@ntlab/ntjs-assets 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/assets/js/bootstrap-icons/bootstrap-icons.svg +1 -1
  2. package/assets/js/bootstrap-icons/folder-plus.svg +2 -2
  3. package/assets/js/bootstrap-icons/font/bootstrap-icons.css +1981 -0
  4. package/assets/js/bootstrap-icons/font/bootstrap-icons.json +1955 -0
  5. package/assets/js/bootstrap-icons/font/bootstrap-icons.min.css +5 -0
  6. package/assets/js/bootstrap-icons/font/bootstrap-icons.scss +1993 -0
  7. package/assets/js/bootstrap-icons/font/fonts/bootstrap-icons.woff +0 -0
  8. package/assets/js/bootstrap-icons/font/fonts/bootstrap-icons.woff2 +0 -0
  9. package/assets/js/bootstrap-icons/postcard-heart-fill.svg +1 -1
  10. package/assets/js/bootstrap-icons/trash.svg +2 -2
  11. package/assets/js/jquery/jquery.js +840 -1045
  12. package/assets/js/jquery/jquery.min.js +2 -2
  13. package/assets/js/jquery/jquery.min.map +1 -1
  14. package/assets/js/jquery/jquery.slim.js +834 -1039
  15. package/assets/js/jquery/jquery.slim.min.js +2 -2
  16. package/assets/js/jquery/jquery.slim.min.map +1 -1
  17. package/assets/js/popper.js/cjs/enums.js +1 -1
  18. package/assets/js/popper.js/cjs/popper-base.js +12 -170
  19. package/assets/js/popper.js/cjs/popper-base.js.map +1 -1
  20. package/assets/js/popper.js/cjs/popper-lite.js +14 -184
  21. package/assets/js/popper.js/cjs/popper-lite.js.map +1 -1
  22. package/assets/js/popper.js/cjs/popper.js +14 -197
  23. package/assets/js/popper.js/cjs/popper.js.map +1 -1
  24. package/assets/js/popper.js/esm/createPopper.js +6 -66
  25. package/assets/js/popper.js/esm/modifiers/arrow.js +1 -12
  26. package/assets/js/popper.js/esm/modifiers/computeStyles.js +2 -14
  27. package/assets/js/popper.js/esm/utils/computeAutoPlacement.js +0 -4
  28. package/assets/js/popper.js/esm/utils/userAgent.js +1 -1
  29. package/assets/js/popper.js/umd/enums.js +1 -1
  30. package/assets/js/popper.js/umd/enums.min.js +1 -1
  31. package/assets/js/popper.js/umd/popper-base.js +12 -170
  32. package/assets/js/popper.js/umd/popper-base.js.map +1 -1
  33. package/assets/js/popper.js/umd/popper-base.min.js +2 -2
  34. package/assets/js/popper.js/umd/popper-base.min.js.map +1 -1
  35. package/assets/js/popper.js/umd/popper-lite.js +14 -184
  36. package/assets/js/popper.js/umd/popper-lite.js.map +1 -1
  37. package/assets/js/popper.js/umd/popper-lite.min.js +2 -2
  38. package/assets/js/popper.js/umd/popper-lite.min.js.map +1 -1
  39. package/assets/js/popper.js/umd/popper.js +14 -197
  40. package/assets/js/popper.js/umd/popper.js.map +1 -1
  41. package/assets/js/popper.js/umd/popper.min.js +2 -2
  42. package/assets/js/popper.js/umd/popper.min.js.map +1 -1
  43. package/assets/js/semantic-ui/components/accordion.css +196 -74
  44. package/assets/js/semantic-ui/components/accordion.js +570 -591
  45. package/assets/js/semantic-ui/components/accordion.min.css +4 -4
  46. package/assets/js/semantic-ui/components/accordion.min.js +6 -6
  47. package/assets/js/semantic-ui/components/ad.css +40 -51
  48. package/assets/js/semantic-ui/components/ad.min.css +4 -4
  49. package/assets/js/semantic-ui/components/api.js +1154 -1117
  50. package/assets/js/semantic-ui/components/api.min.js +6 -6
  51. package/assets/js/semantic-ui/components/breadcrumb.css +7 -7
  52. package/assets/js/semantic-ui/components/breadcrumb.min.css +4 -4
  53. package/assets/js/semantic-ui/components/button.css +895 -1227
  54. package/assets/js/semantic-ui/components/button.min.css +4 -4
  55. package/assets/js/semantic-ui/components/calendar.css +60 -33
  56. package/assets/js/semantic-ui/components/calendar.js +1952 -1575
  57. package/assets/js/semantic-ui/components/calendar.min.css +4 -4
  58. package/assets/js/semantic-ui/components/calendar.min.js +6 -6
  59. package/assets/js/semantic-ui/components/card.css +1004 -441
  60. package/assets/js/semantic-ui/components/card.min.css +4 -4
  61. package/assets/js/semantic-ui/components/checkbox.css +275 -303
  62. package/assets/js/semantic-ui/components/checkbox.js +863 -855
  63. package/assets/js/semantic-ui/components/checkbox.min.css +4 -4
  64. package/assets/js/semantic-ui/components/checkbox.min.js +6 -6
  65. package/assets/js/semantic-ui/components/comment.css +45 -63
  66. package/assets/js/semantic-ui/components/comment.min.css +4 -4
  67. package/assets/js/semantic-ui/components/container.css +98 -4
  68. package/assets/js/semantic-ui/components/container.min.css +4 -4
  69. package/assets/js/semantic-ui/components/dimmer.css +95 -196
  70. package/assets/js/semantic-ui/components/dimmer.js +698 -717
  71. package/assets/js/semantic-ui/components/dimmer.min.css +4 -4
  72. package/assets/js/semantic-ui/components/dimmer.min.js +6 -6
  73. package/assets/js/semantic-ui/components/divider.css +75 -93
  74. package/assets/js/semantic-ui/components/divider.min.css +4 -4
  75. package/assets/js/semantic-ui/components/dropdown.css +490 -413
  76. package/assets/js/semantic-ui/components/dropdown.js +4203 -4068
  77. package/assets/js/semantic-ui/components/dropdown.min.css +4 -4
  78. package/assets/js/semantic-ui/components/dropdown.min.js +6 -6
  79. package/assets/js/semantic-ui/components/embed.css +27 -38
  80. package/assets/js/semantic-ui/components/embed.js +647 -673
  81. package/assets/js/semantic-ui/components/embed.min.css +4 -4
  82. package/assets/js/semantic-ui/components/embed.min.js +6 -6
  83. package/assets/js/semantic-ui/components/emoji.css +11156 -9192
  84. package/assets/js/semantic-ui/components/emoji.min.css +3 -3
  85. package/assets/js/semantic-ui/components/feed.css +56 -78
  86. package/assets/js/semantic-ui/components/feed.min.css +4 -4
  87. package/assets/js/semantic-ui/components/flag.css +1037 -929
  88. package/assets/js/semantic-ui/components/flag.min.css +4 -4
  89. package/assets/js/semantic-ui/components/flyout.css +552 -0
  90. package/assets/js/semantic-ui/components/flyout.js +1567 -0
  91. package/assets/js/semantic-ui/components/flyout.min.css +9 -0
  92. package/assets/js/semantic-ui/components/flyout.min.js +11 -0
  93. package/assets/js/semantic-ui/components/form.css +536 -530
  94. package/assets/js/semantic-ui/components/form.js +2037 -1945
  95. package/assets/js/semantic-ui/components/form.min.css +4 -4
  96. package/assets/js/semantic-ui/components/form.min.js +6 -6
  97. package/assets/js/semantic-ui/components/grid.css +218 -345
  98. package/assets/js/semantic-ui/components/grid.min.css +4 -4
  99. package/assets/js/semantic-ui/components/header.css +137 -154
  100. package/assets/js/semantic-ui/components/header.min.css +4 -4
  101. package/assets/js/semantic-ui/components/icon.css +3000 -2750
  102. package/assets/js/semantic-ui/components/icon.min.css +4 -4
  103. package/assets/js/semantic-ui/components/image.css +54 -49
  104. package/assets/js/semantic-ui/components/image.min.css +4 -4
  105. package/assets/js/semantic-ui/components/input.css +1081 -227
  106. package/assets/js/semantic-ui/components/input.min.css +4 -4
  107. package/assets/js/semantic-ui/components/item.css +91 -138
  108. package/assets/js/semantic-ui/components/item.min.css +4 -4
  109. package/assets/js/semantic-ui/components/label.css +470 -481
  110. package/assets/js/semantic-ui/components/label.min.css +4 -4
  111. package/assets/js/semantic-ui/components/list.css +93 -114
  112. package/assets/js/semantic-ui/components/list.min.css +4 -4
  113. package/assets/js/semantic-ui/components/loader.css +452 -536
  114. package/assets/js/semantic-ui/components/loader.min.css +4 -4
  115. package/assets/js/semantic-ui/components/menu.css +408 -510
  116. package/assets/js/semantic-ui/components/menu.min.css +9 -1
  117. package/assets/js/semantic-ui/components/message.css +188 -213
  118. package/assets/js/semantic-ui/components/message.min.css +4 -4
  119. package/assets/js/semantic-ui/components/modal.css +174 -166
  120. package/assets/js/semantic-ui/components/modal.js +1558 -1146
  121. package/assets/js/semantic-ui/components/modal.min.css +4 -4
  122. package/assets/js/semantic-ui/components/modal.min.js +6 -6
  123. package/assets/js/semantic-ui/components/nag.css +183 -41
  124. package/assets/js/semantic-ui/components/nag.js +527 -467
  125. package/assets/js/semantic-ui/components/nag.min.css +4 -4
  126. package/assets/js/semantic-ui/components/nag.min.js +6 -6
  127. package/assets/js/semantic-ui/components/placeholder.css +62 -76
  128. package/assets/js/semantic-ui/components/placeholder.min.css +4 -4
  129. package/assets/js/semantic-ui/components/popup.css +681 -312
  130. package/assets/js/semantic-ui/components/popup.js +1470 -1463
  131. package/assets/js/semantic-ui/components/popup.min.css +4 -4
  132. package/assets/js/semantic-ui/components/popup.min.js +6 -6
  133. package/assets/js/semantic-ui/components/progress.css +149 -217
  134. package/assets/js/semantic-ui/components/progress.js +945 -1002
  135. package/assets/js/semantic-ui/components/progress.min.css +4 -4
  136. package/assets/js/semantic-ui/components/progress.min.js +6 -6
  137. package/assets/js/semantic-ui/components/rail.css +17 -22
  138. package/assets/js/semantic-ui/components/rail.min.css +3 -3
  139. package/assets/js/semantic-ui/components/rating.css +89 -184
  140. package/assets/js/semantic-ui/components/rating.js +509 -521
  141. package/assets/js/semantic-ui/components/rating.min.css +4 -4
  142. package/assets/js/semantic-ui/components/rating.min.js +6 -6
  143. package/assets/js/semantic-ui/components/reset.css +12 -17
  144. package/assets/js/semantic-ui/components/reset.min.css +4 -4
  145. package/assets/js/semantic-ui/components/reveal.css +46 -85
  146. package/assets/js/semantic-ui/components/reveal.min.css +4 -4
  147. package/assets/js/semantic-ui/components/search.css +157 -96
  148. package/assets/js/semantic-ui/components/search.js +1522 -1479
  149. package/assets/js/semantic-ui/components/search.min.css +4 -4
  150. package/assets/js/semantic-ui/components/search.min.js +6 -6
  151. package/assets/js/semantic-ui/components/segment.css +317 -249
  152. package/assets/js/semantic-ui/components/segment.min.css +4 -4
  153. package/assets/js/semantic-ui/components/shape.css +16 -32
  154. package/assets/js/semantic-ui/components/shape.js +763 -812
  155. package/assets/js/semantic-ui/components/shape.min.css +4 -4
  156. package/assets/js/semantic-ui/components/shape.min.js +6 -6
  157. package/assets/js/semantic-ui/components/sidebar.css +128 -216
  158. package/assets/js/semantic-ui/components/sidebar.js +1042 -1003
  159. package/assets/js/semantic-ui/components/sidebar.min.css +4 -4
  160. package/assets/js/semantic-ui/components/sidebar.min.js +6 -6
  161. package/assets/js/semantic-ui/components/site.css +123 -48
  162. package/assets/js/semantic-ui/components/site.js +438 -478
  163. package/assets/js/semantic-ui/components/site.min.css +4 -4
  164. package/assets/js/semantic-ui/components/site.min.js +6 -6
  165. package/assets/js/semantic-ui/components/slider.css +133 -141
  166. package/assets/js/semantic-ui/components/slider.js +1312 -1274
  167. package/assets/js/semantic-ui/components/slider.min.css +9 -1
  168. package/assets/js/semantic-ui/components/slider.min.js +6 -6
  169. package/assets/js/semantic-ui/components/state.js +640 -659
  170. package/assets/js/semantic-ui/components/state.min.js +6 -6
  171. package/assets/js/semantic-ui/components/statistic.css +83 -124
  172. package/assets/js/semantic-ui/components/statistic.min.css +4 -4
  173. package/assets/js/semantic-ui/components/step.css +118 -184
  174. package/assets/js/semantic-ui/components/step.min.css +4 -4
  175. package/assets/js/semantic-ui/components/sticky.css +3 -8
  176. package/assets/js/semantic-ui/components/sticky.js +849 -892
  177. package/assets/js/semantic-ui/components/sticky.min.css +4 -4
  178. package/assets/js/semantic-ui/components/sticky.min.js +6 -6
  179. package/assets/js/semantic-ui/components/tab.css +16 -20
  180. package/assets/js/semantic-ui/components/tab.js +896 -941
  181. package/assets/js/semantic-ui/components/tab.min.css +4 -4
  182. package/assets/js/semantic-ui/components/tab.min.js +6 -6
  183. package/assets/js/semantic-ui/components/table.css +2073 -884
  184. package/assets/js/semantic-ui/components/table.min.css +4 -4
  185. package/assets/js/semantic-ui/components/text.css +51 -30
  186. package/assets/js/semantic-ui/components/text.min.css +4 -4
  187. package/assets/js/semantic-ui/components/toast.css +200 -137
  188. package/assets/js/semantic-ui/components/toast.js +912 -832
  189. package/assets/js/semantic-ui/components/toast.min.css +4 -4
  190. package/assets/js/semantic-ui/components/toast.min.js +6 -6
  191. package/assets/js/semantic-ui/components/transition.css +371 -1282
  192. package/assets/js/semantic-ui/components/transition.js +999 -1074
  193. package/assets/js/semantic-ui/components/transition.min.css +4 -4
  194. package/assets/js/semantic-ui/components/transition.min.js +6 -6
  195. package/assets/js/semantic-ui/components/visibility.js +1215 -1247
  196. package/assets/js/semantic-ui/components/visibility.min.js +6 -6
  197. package/assets/js/semantic-ui/semantic.css +43777 -37429
  198. package/assets/js/semantic-ui/semantic.js +29152 -26694
  199. package/assets/js/semantic-ui/semantic.min.css +6 -399
  200. package/assets/js/semantic-ui/semantic.min.js +6 -6
  201. package/assets/js/semantic-ui/themes/basic/assets/fonts/icons.woff2 +0 -0
  202. package/assets/js/semantic-ui/themes/default/assets/fonts/Lato-Bold.woff +0 -0
  203. package/assets/js/semantic-ui/themes/default/assets/fonts/Lato-Bold.woff2 +0 -0
  204. package/assets/js/semantic-ui/themes/default/assets/fonts/Lato-BoldItalic.woff +0 -0
  205. package/assets/js/semantic-ui/themes/default/assets/fonts/Lato-BoldItalic.woff2 +0 -0
  206. package/assets/js/semantic-ui/themes/default/assets/fonts/Lato-Italic.woff +0 -0
  207. package/assets/js/semantic-ui/themes/default/assets/fonts/Lato-Italic.woff2 +0 -0
  208. package/assets/js/semantic-ui/themes/default/assets/fonts/Lato-Regular.woff +0 -0
  209. package/assets/js/semantic-ui/themes/default/assets/fonts/Lato-Regular.woff2 +0 -0
  210. package/assets/js/semantic-ui/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
  211. package/assets/js/semantic-ui/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
  212. package/assets/js/semantic-ui/themes/default/assets/fonts/LatoLatin-BoldItalic.woff +0 -0
  213. package/assets/js/semantic-ui/themes/default/assets/fonts/LatoLatin-BoldItalic.woff2 +0 -0
  214. package/assets/js/semantic-ui/themes/default/assets/fonts/LatoLatin-Italic.woff +0 -0
  215. package/assets/js/semantic-ui/themes/default/assets/fonts/LatoLatin-Italic.woff2 +0 -0
  216. package/assets/js/semantic-ui/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
  217. package/assets/js/semantic-ui/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
  218. package/assets/js/semantic-ui/themes/default/assets/fonts/brand-icons.woff +0 -0
  219. package/assets/js/semantic-ui/themes/default/assets/fonts/brand-icons.woff2 +0 -0
  220. package/assets/js/semantic-ui/themes/default/assets/fonts/icons.woff +0 -0
  221. package/assets/js/semantic-ui/themes/default/assets/fonts/icons.woff2 +0 -0
  222. package/assets/js/semantic-ui/themes/default/assets/fonts/outline-icons.woff +0 -0
  223. package/assets/js/semantic-ui/themes/default/assets/fonts/outline-icons.woff2 +0 -0
  224. package/assets/js/semantic-ui/themes/famfamfam/assets/images/flags.png +0 -0
  225. package/assets/js/semantic-ui/themes/github/assets/fonts/octicons.woff2 +0 -0
  226. package/assets/js/socket.io/socket.io.esm.min.js +3 -3
  227. package/assets/js/socket.io/socket.io.esm.min.js.map +1 -1
  228. package/assets/js/socket.io/socket.io.js +841 -333
  229. package/assets/js/socket.io/socket.io.js.map +1 -1
  230. package/assets/js/socket.io/socket.io.min.js +3 -3
  231. package/assets/js/socket.io/socket.io.min.js.map +1 -1
  232. package/assets/js/socket.io/socket.io.msgpack.min.js +3 -3
  233. package/assets/js/socket.io/socket.io.msgpack.min.js.map +1 -1
  234. package/cdn.json +19 -4
  235. package/package.json +1 -1
@@ -1,1177 +1,1214 @@
1
1
  /*!
2
- * # Fomantic-UI - API
3
- * http://github.com/fomantic/Fomantic-UI/
2
+ * # Fomantic-UI 2.9.2 - API
3
+ * https://github.com/fomantic/Fomantic-UI/
4
4
  *
5
5
  *
6
6
  * Released under the MIT license
7
- * http://opensource.org/licenses/MIT
7
+ * https://opensource.org/licenses/MIT
8
8
  *
9
9
  */
10
10
 
11
- ;(function ($, window, document, undefined) {
12
-
13
- 'use strict';
14
-
15
- $.isWindow = $.isWindow || function(obj) {
16
- return obj != null && obj === obj.window;
17
- };
18
-
19
- window = (typeof window != 'undefined' && window.Math == Math)
20
- ? window
21
- : (typeof self != 'undefined' && self.Math == Math)
22
- ? self
23
- : Function('return this')()
24
- ;
25
-
26
- $.api = $.fn.api = function(parameters) {
27
-
28
- var
29
- // use window context if none specified
30
- $allModules = $.isFunction(this)
31
- ? $(window)
32
- : $(this),
33
- moduleSelector = $allModules.selector || '',
34
- time = new Date().getTime(),
35
- performance = [],
36
-
37
- query = arguments[0],
38
- methodInvoked = (typeof query == 'string'),
39
- queryArguments = [].slice.call(arguments, 1),
40
-
41
- returnedValue
42
- ;
43
-
44
- $allModules
45
- .each(function() {
46
- var
47
- settings = ( $.isPlainObject(parameters) )
48
- ? $.extend(true, {}, $.fn.api.settings, parameters)
49
- : $.extend({}, $.fn.api.settings),
50
-
51
- // internal aliases
52
- namespace = settings.namespace,
53
- metadata = settings.metadata,
54
- selector = settings.selector,
55
- error = settings.error,
56
- className = settings.className,
57
-
58
- // define namespaces for modules
59
- eventNamespace = '.' + namespace,
60
- moduleNamespace = 'module-' + namespace,
61
-
62
- // element that creates request
63
- $module = $(this),
64
- $form = $module.closest(selector.form),
65
-
66
- // context used for state
67
- $context = (settings.stateContext)
68
- ? $(settings.stateContext)
69
- : $module,
70
-
71
- // request details
72
- ajaxSettings,
73
- requestSettings,
74
- url,
75
- data,
76
- requestStartTime,
77
-
78
- // standard module
79
- element = this,
80
- context = $context[0],
81
- instance = $module.data(moduleNamespace),
82
- module
83
- ;
84
-
85
- module = {
86
-
87
- initialize: function() {
88
- if(!methodInvoked) {
89
- module.bind.events();
90
- }
91
- module.instantiate();
92
- },
11
+ (function ($, window, document) {
12
+ 'use strict';
93
13
 
94
- instantiate: function() {
95
- module.verbose('Storing instance of module', module);
96
- instance = module;
97
- $module
98
- .data(moduleNamespace, instance)
99
- ;
100
- },
14
+ function isWindow(obj) {
15
+ return obj !== null && obj === obj.window;
16
+ }
101
17
 
102
- destroy: function() {
103
- module.verbose('Destroying previous module for', element);
104
- $module
105
- .removeData(moduleNamespace)
106
- .off(eventNamespace)
107
- ;
108
- },
18
+ function isFunction(obj) {
19
+ return typeof obj === 'function' && typeof obj.nodeType !== 'number';
20
+ }
109
21
 
110
- bind: {
111
- events: function() {
112
- var
113
- triggerEvent = module.get.event()
114
- ;
115
- if( triggerEvent ) {
116
- module.verbose('Attaching API events to element', triggerEvent);
117
- $module
118
- .on(triggerEvent + eventNamespace, module.event.trigger)
119
- ;
120
- }
121
- else if(settings.on == 'now') {
122
- module.debug('Querying API endpoint immediately');
123
- module.query();
124
- }
125
- }
126
- },
22
+ window = window !== undefined && window.Math === Math
23
+ ? window
24
+ : globalThis;
127
25
 
128
- decode: {
129
- json: function(response) {
130
- if(response !== undefined && typeof response == 'string') {
131
- try {
132
- response = JSON.parse(response);
133
- }
134
- catch(e) {
135
- // isnt json string
136
- }
137
- }
138
- return response;
139
- }
140
- },
26
+ $.fn.api = function (parameters) {
27
+ var
28
+ // use window context if none specified
29
+ $allModules = isFunction(this)
30
+ ? $(window)
31
+ : $(this),
32
+ moduleSelector = $allModules.selector || '',
33
+ time = Date.now(),
34
+ performance = [],
35
+
36
+ query = arguments[0],
37
+ methodInvoked = typeof query === 'string',
38
+ queryArguments = [].slice.call(arguments, 1),
39
+
40
+ returnedValue
41
+ ;
141
42
 
142
- read: {
143
- cachedResponse: function(url) {
43
+ $allModules.each(function () {
144
44
  var
145
- response
45
+ settings = $.isPlainObject(parameters)
46
+ ? $.extend(true, {}, $.fn.api.settings, parameters)
47
+ : $.extend({}, $.fn.api.settings),
48
+
49
+ // internal aliases
50
+ namespace = settings.namespace,
51
+ metadata = settings.metadata,
52
+ selector = settings.selector,
53
+ error = settings.error,
54
+ className = settings.className,
55
+
56
+ // define namespaces for modules
57
+ eventNamespace = '.' + namespace,
58
+ moduleNamespace = 'module-' + namespace,
59
+
60
+ // element that creates request
61
+ $module = $(this),
62
+ $form = $module.closest(selector.form),
63
+
64
+ // context used for state
65
+ $context = settings.stateContext
66
+ ? ([window, document].indexOf(settings.stateContext) < 0 ? $(document).find(settings.stateContext) : $(settings.stateContext))
67
+ : $module,
68
+
69
+ // request details
70
+ ajaxSettings,
71
+ requestSettings,
72
+ url,
73
+ data,
74
+ requestStartTime,
75
+ originalData,
76
+
77
+ // standard module
78
+ element = this,
79
+ context = $context[0],
80
+ instance = $module.data(moduleNamespace),
81
+ module
146
82
  ;
147
- if(window.Storage === undefined) {
148
- module.error(error.noStorage);
149
- return;
150
- }
151
- response = sessionStorage.getItem(url);
152
- module.debug('Using cached response', url, response);
153
- response = module.decode.json(response);
154
- return response;
155
- }
156
- },
157
- write: {
158
- cachedResponse: function(url, response) {
159
- if(response && response === '') {
160
- module.debug('Response empty, not caching', response);
161
- return;
162
- }
163
- if(window.Storage === undefined) {
164
- module.error(error.noStorage);
165
- return;
166
- }
167
- if( $.isPlainObject(response) ) {
168
- response = JSON.stringify(response);
169
- }
170
- sessionStorage.setItem(url, response);
171
- module.verbose('Storing cached response for url', url, response);
172
- }
173
- },
174
83
 
175
- query: function() {
84
+ module = {
176
85
 
177
- if(module.is.disabled()) {
178
- module.debug('Element is disabled API request aborted');
179
- return;
180
- }
86
+ initialize: function () {
87
+ if (!methodInvoked) {
88
+ originalData = settings.data;
89
+ module.bind.events();
90
+ }
91
+ module.instantiate();
92
+ },
93
+
94
+ instantiate: function () {
95
+ module.verbose('Storing instance of module', module);
96
+ instance = module;
97
+ $module
98
+ .data(moduleNamespace, instance)
99
+ ;
100
+ },
181
101
 
182
- if(module.is.loading()) {
183
- if(settings.interruptRequests) {
184
- module.debug('Interrupting previous request');
185
- module.abort();
186
- }
187
- else {
188
- module.debug('Cancelling request, previous request is still pending');
189
- return;
190
- }
191
- }
192
-
193
- // pass element metadata to url (value, text)
194
- if(settings.defaultData) {
195
- $.extend(true, settings.urlData, module.get.defaultData());
196
- }
197
-
198
- // Add form content
199
- if(settings.serializeForm) {
200
- settings.data = module.add.formData(settings.data);
201
- }
202
-
203
- // call beforesend and get any settings changes
204
- requestSettings = module.get.settings();
205
-
206
- // check if before send cancelled request
207
- if(requestSettings === false) {
208
- module.cancelled = true;
209
- module.error(error.beforeSend);
210
- return;
211
- }
212
- else {
213
- module.cancelled = false;
214
- }
215
-
216
- // get url
217
- url = module.get.templatedURL();
218
-
219
- if(!url && !module.is.mocked()) {
220
- module.error(error.missingURL);
221
- return;
222
- }
223
-
224
- // replace variables
225
- url = module.add.urlData( url );
226
- // missing url parameters
227
- if( !url && !module.is.mocked()) {
228
- return;
229
- }
230
-
231
- requestSettings.url = settings.base + url;
232
-
233
- // look for jQuery ajax parameters in settings
234
- ajaxSettings = $.extend(true, {}, settings, {
235
- type : settings.method || settings.type,
236
- data : data,
237
- url : settings.base + url,
238
- beforeSend : settings.beforeXHR,
239
- success : function() {},
240
- failure : function() {},
241
- complete : function() {}
242
- });
243
-
244
- module.debug('Querying URL', ajaxSettings.url);
245
- module.verbose('Using AJAX settings', ajaxSettings);
246
- if(settings.cache === 'local' && module.read.cachedResponse(url)) {
247
- module.debug('Response returned from local cache');
248
- module.request = module.create.request();
249
- module.request.resolveWith(context, [ module.read.cachedResponse(url) ]);
250
- return;
251
- }
252
-
253
- if( !settings.throttle ) {
254
- module.debug('Sending request', data, ajaxSettings.method);
255
- module.send.request();
256
- }
257
- else {
258
- if(!settings.throttleFirstRequest && !module.timer) {
259
- module.debug('Sending request', data, ajaxSettings.method);
260
- module.send.request();
261
- module.timer = setTimeout(function(){}, settings.throttle);
262
- }
263
- else {
264
- module.debug('Throttling request', settings.throttle);
265
- clearTimeout(module.timer);
266
- module.timer = setTimeout(function() {
267
- if(module.timer) {
268
- delete module.timer;
269
- }
270
- module.debug('Sending throttled request', data, ajaxSettings.method);
271
- module.send.request();
272
- }, settings.throttle);
273
- }
274
- }
102
+ destroy: function () {
103
+ module.verbose('Destroying previous module for', element);
104
+ $module
105
+ .removeData(moduleNamespace)
106
+ .off(eventNamespace)
107
+ ;
108
+ },
109
+
110
+ bind: {
111
+ events: function () {
112
+ var
113
+ triggerEvent = module.get.event()
114
+ ;
115
+ if (triggerEvent) {
116
+ module.verbose('Attaching API events to element', triggerEvent);
117
+ $module
118
+ .on(triggerEvent + eventNamespace, module.event.trigger)
119
+ ;
120
+ } else if (settings.on === 'now') {
121
+ module.debug('Querying API endpoint immediately');
122
+ module.query();
123
+ }
124
+ },
125
+ },
126
+
127
+ decode: {
128
+ json: function (response) {
129
+ if (response !== undefined && typeof response === 'string') {
130
+ try {
131
+ response = JSON.parse(response);
132
+ } catch (e) {
133
+ // isn't json string
134
+ }
135
+ }
136
+
137
+ return response;
138
+ },
139
+ },
140
+
141
+ read: {
142
+ cachedResponse: function (url) {
143
+ var
144
+ response
145
+ ;
146
+ if (window.Storage === undefined) {
147
+ module.error(error.noStorage);
148
+
149
+ return;
150
+ }
151
+ response = sessionStorage.getItem(url + module.get.normalizedData());
152
+ module.debug('Using cached response', url, settings.data, response);
153
+ response = module.decode.json(response);
154
+
155
+ return response;
156
+ },
157
+ },
158
+ write: {
159
+ cachedResponse: function (url, response) {
160
+ if (window.Storage === undefined) {
161
+ module.error(error.noStorage);
162
+
163
+ return;
164
+ }
165
+ if ($.isPlainObject(response)) {
166
+ response = JSON.stringify(response);
167
+ }
168
+ sessionStorage.setItem(url + module.get.normalizedData(), response);
169
+ module.verbose('Storing cached response for url', url, settings.data, response);
170
+ },
171
+ },
172
+
173
+ query: function () {
174
+ if (module.is.disabled()) {
175
+ module.debug('Element is disabled API request aborted');
176
+
177
+ return;
178
+ }
275
179
 
276
- },
180
+ if (module.is.loading()) {
181
+ if (settings.interruptRequests) {
182
+ module.debug('Interrupting previous request');
183
+ module.abort();
184
+ } else {
185
+ module.debug('Cancelling request, previous request is still pending');
277
186
 
278
- should: {
279
- removeError: function() {
280
- return ( settings.hideError === true || (settings.hideError === 'auto' && !module.is.form()) );
281
- }
282
- },
187
+ return;
188
+ }
189
+ }
283
190
 
284
- is: {
285
- disabled: function() {
286
- return ($module.filter(selector.disabled).length > 0);
287
- },
288
- expectingJSON: function() {
289
- return settings.dataType === 'json' || settings.dataType === 'jsonp';
290
- },
291
- form: function() {
292
- return $module.is('form') || $context.is('form');
293
- },
294
- mocked: function() {
295
- return (settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync);
296
- },
297
- input: function() {
298
- return $module.is('input');
299
- },
300
- loading: function() {
301
- return (module.request)
302
- ? (module.request.state() == 'pending')
303
- : false
304
- ;
305
- },
306
- abortedRequest: function(xhr) {
307
- if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) {
308
- module.verbose('XHR request determined to be aborted');
309
- return true;
310
- }
311
- else {
312
- module.verbose('XHR request was not aborted');
313
- return false;
314
- }
315
- },
316
- validResponse: function(response) {
317
- if( (!module.is.expectingJSON()) || !$.isFunction(settings.successTest) ) {
318
- module.verbose('Response is not JSON, skipping validation', settings.successTest, response);
319
- return true;
320
- }
321
- module.debug('Checking JSON returned success', settings.successTest, response);
322
- if( settings.successTest(response) ) {
323
- module.debug('Response passed success test', response);
324
- return true;
325
- }
326
- else {
327
- module.debug('Response failed success test', response);
328
- return false;
329
- }
330
- }
331
- },
191
+ // pass element metadata to url (value, text)
192
+ if (settings.defaultData) {
193
+ $.extend(true, settings.urlData, module.get.defaultData());
194
+ }
332
195
 
333
- was: {
334
- cancelled: function() {
335
- return (module.cancelled || false);
336
- },
337
- succesful: function() {
338
- module.verbose('This behavior will be deleted due to typo. Use "was successful" instead.');
339
- return module.was.successful();
340
- },
341
- successful: function() {
342
- return (module.request && module.request.state() == 'resolved');
343
- },
344
- failure: function() {
345
- return (module.request && module.request.state() == 'rejected');
346
- },
347
- complete: function() {
348
- return (module.request && (module.request.state() == 'resolved' || module.request.state() == 'rejected') );
349
- }
350
- },
196
+ // Add form content
197
+ if (settings.serializeForm) {
198
+ settings.data = module.add.formData(originalData || settings.data);
199
+ }
351
200
 
352
- add: {
353
- urlData: function(url, urlData) {
354
- var
355
- requiredVariables,
356
- optionalVariables
357
- ;
358
- if(url) {
359
- requiredVariables = url.match(settings.regExp.required);
360
- optionalVariables = url.match(settings.regExp.optional);
361
- urlData = urlData || settings.urlData;
362
- if(requiredVariables) {
363
- module.debug('Looking for required URL variables', requiredVariables);
364
- $.each(requiredVariables, function(index, templatedString) {
365
- var
366
- // allow legacy {$var} style
367
- variable = (templatedString.indexOf('$') !== -1)
368
- ? templatedString.substr(2, templatedString.length - 3)
369
- : templatedString.substr(1, templatedString.length - 2),
370
- value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
371
- ? urlData[variable]
372
- : ($module.data(variable) !== undefined)
373
- ? $module.data(variable)
374
- : ($context.data(variable) !== undefined)
375
- ? $context.data(variable)
376
- : urlData[variable]
377
- ;
378
- // remove value
379
- if(value === undefined) {
380
- module.error(error.requiredParameter, variable, url);
381
- url = false;
382
- return false;
383
- }
384
- else {
385
- module.verbose('Found required variable', variable, value);
386
- value = (settings.encodeParameters)
387
- ? module.get.urlEncodedValue(value)
388
- : value
201
+ // call beforesend and get any settings changes
202
+ requestSettings = module.get.settings();
203
+
204
+ // check if before send cancelled request
205
+ if (requestSettings === false) {
206
+ module.cancelled = true;
207
+ module.error(error.beforeSend);
208
+
209
+ return;
210
+ }
211
+
212
+ module.cancelled = false;
213
+
214
+ // get url
215
+ url = module.get.templatedURL();
216
+
217
+ if (!url && !module.is.mocked()) {
218
+ module.error(error.missingURL);
219
+
220
+ return;
221
+ }
222
+
223
+ // replace variables
224
+ url = module.add.urlData(url);
225
+ // missing url parameters
226
+ if (!url && !module.is.mocked()) {
227
+ return;
228
+ }
229
+
230
+ requestSettings.url = settings.base + url;
231
+
232
+ // look for jQuery ajax parameters in settings
233
+ ajaxSettings = $.extend(true, {}, settings, {
234
+ type: settings.method || settings.type,
235
+ data: data,
236
+ url: settings.base + url,
237
+ beforeSend: settings.beforeXHR,
238
+ success: function () {},
239
+ failure: function () {},
240
+ complete: function () {},
241
+ });
242
+
243
+ module.debug('Querying URL', ajaxSettings.url);
244
+ module.verbose('Using AJAX settings', ajaxSettings);
245
+ if (settings.cache === 'local' && module.read.cachedResponse(url)) {
246
+ module.debug('Response returned from local cache');
247
+ module.request = module.create.request();
248
+ module.request.resolveWith(context, [module.read.cachedResponse(url)]);
249
+
250
+ return;
251
+ }
252
+
253
+ if (!settings.throttle) {
254
+ module.debug('Sending request', data, ajaxSettings.method);
255
+ module.send.request();
256
+ } else {
257
+ if (!settings.throttleFirstRequest && !module.timer) {
258
+ module.debug('Sending request', data, ajaxSettings.method);
259
+ module.send.request();
260
+ module.timer = setTimeout(function () {}, settings.throttle);
261
+ } else {
262
+ module.debug('Throttling request', settings.throttle);
263
+ clearTimeout(module.timer);
264
+ module.timer = setTimeout(function () {
265
+ if (module.timer) {
266
+ delete module.timer;
267
+ }
268
+ module.debug('Sending throttled request', data, ajaxSettings.method);
269
+ module.send.request();
270
+ }, settings.throttle);
271
+ }
272
+ }
273
+ },
274
+
275
+ should: {
276
+ removeError: function () {
277
+ return settings.hideError === true || (settings.hideError === 'auto' && !module.is.form());
278
+ },
279
+ },
280
+
281
+ is: {
282
+ disabled: function () {
283
+ return $module.filter(selector.disabled).length > 0;
284
+ },
285
+ expectingJSON: function () {
286
+ return settings.dataType === 'json' || settings.dataType === 'jsonp';
287
+ },
288
+ form: function () {
289
+ return $module.is('form') || $context.is('form');
290
+ },
291
+ mocked: function () {
292
+ return settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync;
293
+ },
294
+ input: function () {
295
+ return $module.is('input');
296
+ },
297
+ loading: function () {
298
+ return module.request
299
+ ? module.request.state() === 'pending'
300
+ : false;
301
+ },
302
+ abortedRequest: function (xhr) {
303
+ if (xhr && xhr.readyState !== undefined && xhr.readyState === 0) {
304
+ module.verbose('XHR request determined to be aborted');
305
+
306
+ return true;
307
+ }
308
+
309
+ module.verbose('XHR request was not aborted');
310
+
311
+ return false;
312
+ },
313
+ validResponse: function (response) {
314
+ if (!module.is.expectingJSON() || !isFunction(settings.successTest)) {
315
+ module.verbose('Response is not JSON, skipping validation', settings.successTest, response);
316
+
317
+ return true;
318
+ }
319
+ module.debug('Checking JSON returned success', settings.successTest, response);
320
+ if (settings.successTest(response)) {
321
+ module.debug('Response passed success test', response);
322
+
323
+ return true;
324
+ }
325
+
326
+ module.debug('Response failed success test', response);
327
+
328
+ return false;
329
+ },
330
+ },
331
+
332
+ was: {
333
+ cancelled: function () {
334
+ return module.cancelled || false;
335
+ },
336
+ successful: function () {
337
+ return module.request && module.request.state() === 'resolved';
338
+ },
339
+ failure: function () {
340
+ return module.request && module.request.state() === 'rejected';
341
+ },
342
+ complete: function () {
343
+ return module.request && (module.request.state() === 'resolved' || module.request.state() === 'rejected');
344
+ },
345
+ },
346
+
347
+ add: {
348
+ urlData: function (url, urlData) {
349
+ var
350
+ requiredVariables,
351
+ optionalVariables
352
+ ;
353
+ if (url) {
354
+ requiredVariables = url.match(settings.regExp.required);
355
+ optionalVariables = url.match(settings.regExp.optional);
356
+ urlData = urlData || settings.urlData;
357
+ if (requiredVariables) {
358
+ module.debug('Looking for required URL variables', requiredVariables);
359
+ $.each(requiredVariables, function (index, templatedString) {
360
+ var
361
+ // allow legacy {$var} style
362
+ variable = templatedString.indexOf('$') !== -1
363
+ ? templatedString.slice(2, -1)
364
+ : templatedString.slice(1, -1),
365
+ value = $.isPlainObject(urlData) && urlData[variable] !== undefined
366
+ ? urlData[variable]
367
+ : ($module.data(variable) !== undefined
368
+ ? $module.data(variable)
369
+ : ($context.data(variable) !== undefined // eslint-disable-line unicorn/no-nested-ternary
370
+ ? $context.data(variable)
371
+ : urlData[variable]))
372
+ ;
373
+ // remove value
374
+ if (value === undefined) {
375
+ module.error(error.requiredParameter, variable, url);
376
+ url = false;
377
+
378
+ return false;
379
+ }
380
+
381
+ module.verbose('Found required variable', variable, value);
382
+ value = settings.encodeParameters
383
+ ? module.get.urlEncodedValue(value)
384
+ : value;
385
+ url = url.replace(templatedString, value);
386
+ });
387
+ }
388
+ if (optionalVariables) {
389
+ module.debug('Looking for optional URL variables', requiredVariables);
390
+ $.each(optionalVariables, function (index, templatedString) {
391
+ var
392
+ // allow legacy {/$var} style
393
+ variable = templatedString.indexOf('$') !== -1
394
+ ? templatedString.slice(3, -1)
395
+ : templatedString.slice(2, -1),
396
+ value = $.isPlainObject(urlData) && urlData[variable] !== undefined
397
+ ? urlData[variable]
398
+ : ($module.data(variable) !== undefined
399
+ ? $module.data(variable)
400
+ : ($context.data(variable) !== undefined // eslint-disable-line unicorn/no-nested-ternary
401
+ ? $context.data(variable)
402
+ : urlData[variable]))
403
+ ;
404
+ // optional replacement
405
+ if (value !== undefined) {
406
+ module.verbose('Optional variable Found', variable, value);
407
+ url = url.replace(templatedString, value);
408
+ } else {
409
+ module.verbose('Optional variable not found', variable);
410
+ // remove preceding slash if set
411
+ url = url.indexOf('/' + templatedString) !== -1
412
+ ? url.replace('/' + templatedString, '')
413
+ : url.replace(templatedString, '');
414
+ }
415
+ });
416
+ }
417
+ }
418
+
419
+ return url;
420
+ },
421
+ formData: function (data) {
422
+ var
423
+ formData = {},
424
+ hasOtherData,
425
+ useFormDataApi = settings.serializeForm === 'formdata'
426
+ ;
427
+ data = data || originalData || settings.data;
428
+ hasOtherData = $.isPlainObject(data);
429
+
430
+ if (useFormDataApi) {
431
+ formData = new FormData($form[0]);
432
+ settings.processData = settings.processData !== undefined ? settings.processData : false;
433
+ settings.contentType = settings.contentType !== undefined ? settings.contentType : false;
434
+ } else {
435
+ var
436
+ formArray = $form.serializeArray(),
437
+ pushes = {},
438
+ pushValues = {},
439
+ build = function (base, key, value) {
440
+ base[key] = value;
441
+
442
+ return base;
443
+ }
444
+ ;
445
+ // add files
446
+ $.each($('input[type="file"]', $form), function (i, tag) {
447
+ $.each($(tag)[0].files, function (j, file) {
448
+ formArray.push({ name: tag.name, value: file });
449
+ });
450
+ });
451
+ $.each(formArray, function (i, el) {
452
+ if (!settings.regExp.validate.test(el.name)) {
453
+ return;
454
+ }
455
+ var
456
+ isCheckbox = $('[name="' + el.name + '"]', $form).attr('type') === 'checkbox',
457
+ floatValue = parseFloat(el.value),
458
+ value = (isCheckbox && el.value === 'on')
459
+ || el.value === 'true'
460
+ || (String(floatValue) === el.value
461
+ ? floatValue
462
+ : (el.value === 'false' ? false : el.value)),
463
+ nameKeys = el.name.match(settings.regExp.key) || [],
464
+ pushKey = el.name.replace(/\[]$/, '')
465
+ ;
466
+ if (!(pushKey in pushes)) {
467
+ pushes[pushKey] = 0;
468
+ pushValues[pushKey] = value;
469
+ } else if (Array.isArray(pushValues[pushKey])) {
470
+ pushValues[pushKey].push(value);
471
+ } else {
472
+ pushValues[pushKey] = [pushValues[pushKey], value];
473
+ }
474
+ if (pushKey.indexOf('[]') === -1) {
475
+ value = pushValues[pushKey];
476
+ }
477
+
478
+ while (nameKeys.length > 0) {
479
+ var k = nameKeys.pop();
480
+
481
+ if (k === '' && !Array.isArray(value)) { // foo[]
482
+ value = build([], pushes[pushKey]++, value);
483
+ } else if (settings.regExp.fixed.test(k)) { // foo[n]
484
+ value = build([], k, value);
485
+ } else if (settings.regExp.named.test(k)) { // foo; foo[bar]
486
+ value = build({}, k, value);
487
+ }
488
+ }
489
+ formData = $.extend(true, formData, value);
490
+ });
491
+ }
492
+
493
+ if (hasOtherData) {
494
+ module.debug('Extending existing data with form data', data, formData);
495
+ if (useFormDataApi) {
496
+ $.each(Object.keys(data), function (i, el) {
497
+ formData.append(el, data[el]);
498
+ });
499
+ data = formData;
500
+ } else {
501
+ data = $.extend(true, {}, data, formData);
502
+ }
503
+ } else {
504
+ module.debug('Adding form data', formData);
505
+ data = formData;
506
+ }
507
+
508
+ return data;
509
+ },
510
+ },
511
+
512
+ send: {
513
+ request: function () {
514
+ module.set.loading();
515
+ module.request = module.create.request();
516
+ if (module.is.mocked()) {
517
+ module.mockedXHR = module.create.mockedXHR();
518
+ } else {
519
+ module.xhr = module.create.xhr();
520
+ }
521
+ settings.onRequest.call(context, module.request, module.xhr);
522
+ },
523
+ },
524
+
525
+ event: {
526
+ trigger: function (event) {
527
+ module.query();
528
+ if (event.type === 'submit' || event.type === 'click') {
529
+ event.preventDefault();
530
+ }
531
+ },
532
+ xhr: {
533
+ always: function () {
534
+ // nothing special
535
+ },
536
+ done: function (response, textStatus, xhr) {
537
+ var
538
+ context = this,
539
+ elapsedTime = Date.now() - requestStartTime,
540
+ timeLeft = settings.loadingDuration - elapsedTime,
541
+ translatedResponse = isFunction(settings.onResponse)
542
+ ? (module.is.expectingJSON() && !settings.rawResponse
543
+ ? settings.onResponse.call(context, $.extend(true, {}, response))
544
+ : settings.onResponse.call(context, response))
545
+ : false
546
+ ;
547
+ timeLeft = timeLeft > 0
548
+ ? timeLeft
549
+ : 0;
550
+ if (translatedResponse) {
551
+ module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response);
552
+ response = translatedResponse;
553
+ }
554
+ if (timeLeft > 0) {
555
+ module.debug('Response completed early delaying state change by', timeLeft);
556
+ }
557
+ setTimeout(function () {
558
+ if (module.is.validResponse(response)) {
559
+ module.request.resolveWith(context, [response, xhr]);
560
+ } else {
561
+ module.request.rejectWith(context, [xhr, 'invalid']);
562
+ }
563
+ }, timeLeft);
564
+ },
565
+ fail: function (xhr, status, httpMessage) {
566
+ var
567
+ context = this,
568
+ elapsedTime = Date.now() - requestStartTime,
569
+ timeLeft = settings.loadingDuration - elapsedTime
570
+ ;
571
+ timeLeft = timeLeft > 0
572
+ ? timeLeft
573
+ : 0;
574
+ if (timeLeft > 0) {
575
+ module.debug('Response completed early delaying state change by', timeLeft);
576
+ }
577
+ setTimeout(function () {
578
+ if (module.is.abortedRequest(xhr)) {
579
+ module.request.rejectWith(context, [xhr, 'aborted', httpMessage]);
580
+ } else {
581
+ module.request.rejectWith(context, [xhr, 'error', status, httpMessage]);
582
+ }
583
+ }, timeLeft);
584
+ },
585
+ },
586
+ request: {
587
+ done: function (response, xhr) {
588
+ module.debug('Successful API Response', response);
589
+ if (settings.cache === 'local' && url) {
590
+ module.write.cachedResponse(url, response);
591
+ module.debug('Saving server response locally', module.cache);
592
+ }
593
+ settings.onSuccess.call(context, response, $module, xhr);
594
+ },
595
+ complete: function (firstParameter, secondParameter) {
596
+ var
597
+ xhr,
598
+ response
599
+ ;
600
+ // have to guess callback parameters based on request success
601
+ if (module.was.successful()) {
602
+ response = firstParameter;
603
+ xhr = secondParameter;
604
+ } else {
605
+ xhr = firstParameter;
606
+ response = module.get.responseFromXHR(xhr);
607
+ }
608
+ module.remove.loading();
609
+ settings.onComplete.call(context, response, $module, xhr);
610
+ },
611
+ fail: function (xhr, status, httpMessage) {
612
+ var
613
+ // pull response from xhr if available
614
+ response = module.get.responseFromXHR(xhr),
615
+ errorMessage = module.get.errorFromRequest(response, status, httpMessage)
616
+ ;
617
+ if (status === 'aborted') {
618
+ module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage);
619
+ settings.onAbort.call(context, status, $module, xhr);
620
+
621
+ return true;
622
+ }
623
+ if (status === 'invalid') {
624
+ module.debug('JSON did not pass success test. A server-side error has most likely occurred', response);
625
+ } else if (status === 'error') {
626
+ if (xhr !== undefined) {
627
+ module.debug('XHR produced a server error', status, httpMessage);
628
+ // make sure we have an error to display to console
629
+ if ((xhr.status < 200 || xhr.status >= 300) && httpMessage !== undefined && httpMessage !== '') {
630
+ module.error(error.statusMessage + httpMessage, ajaxSettings.url);
631
+ }
632
+ settings.onError.call(context, errorMessage, $module, xhr);
633
+ }
634
+ }
635
+
636
+ if (settings.errorDuration && status !== 'aborted') {
637
+ module.debug('Adding error state');
638
+ module.set.error();
639
+ if (module.should.removeError()) {
640
+ setTimeout(module.remove.error, settings.errorDuration);
641
+ }
642
+ }
643
+ module.debug('API Request failed', errorMessage, xhr);
644
+ settings.onFailure.call(context, response, $module, xhr);
645
+ },
646
+ },
647
+ },
648
+
649
+ create: {
650
+
651
+ request: function () {
652
+ // api request promise
653
+ return $.Deferred()
654
+ .always(module.event.request.complete)
655
+ .done(module.event.request.done)
656
+ .fail(module.event.request.fail)
657
+ ;
658
+ },
659
+
660
+ mockedXHR: function () {
661
+ var
662
+ // xhr does not simulate these properties of xhr but must return them
663
+ textStatus = false,
664
+ status = false,
665
+ httpMessage = false,
666
+ responder = settings.mockResponse || settings.response,
667
+ asyncResponder = settings.mockResponseAsync || settings.responseAsync,
668
+ asyncCallback,
669
+ response,
670
+ mockedXHR
671
+ ;
672
+
673
+ mockedXHR = $.Deferred()
674
+ .always(module.event.xhr.complete)
675
+ .done(module.event.xhr.done)
676
+ .fail(module.event.xhr.fail)
677
+ ;
678
+
679
+ if (responder) {
680
+ if (isFunction(responder)) {
681
+ module.debug('Using specified synchronous callback', responder);
682
+ response = responder.call(context, requestSettings);
683
+ } else {
684
+ module.debug('Using settings specified response', responder);
685
+ response = responder;
686
+ }
687
+ // simulating response
688
+ mockedXHR.resolveWith(context, [response, textStatus, { responseText: response }]);
689
+ } else if (isFunction(asyncResponder)) {
690
+ asyncCallback = function (response) {
691
+ module.debug('Async callback returned response', response);
692
+
693
+ if (response) {
694
+ mockedXHR.resolveWith(context, [response, textStatus, { responseText: response }]);
695
+ } else {
696
+ mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]);
697
+ }
698
+ };
699
+ module.debug('Using specified async response callback', asyncResponder);
700
+ asyncResponder.call(context, requestSettings, asyncCallback);
701
+ }
702
+
703
+ return mockedXHR;
704
+ },
705
+
706
+ xhr: function () {
707
+ var
708
+ xhr
709
+ ;
710
+ // ajax request promise
711
+ xhr = $.ajax(ajaxSettings)
712
+ .always(module.event.xhr.always)
713
+ .done(module.event.xhr.done)
714
+ .fail(module.event.xhr.fail)
715
+ ;
716
+ module.verbose('Created server request', xhr, ajaxSettings);
717
+
718
+ return xhr;
719
+ },
720
+ },
721
+
722
+ set: {
723
+ error: function () {
724
+ module.verbose('Adding error state to element', $context);
725
+ $context.addClass(className.error);
726
+ },
727
+ loading: function () {
728
+ module.verbose('Adding loading state to element', $context);
729
+ $context.addClass(className.loading);
730
+ requestStartTime = Date.now();
731
+ },
732
+ },
733
+
734
+ remove: {
735
+ error: function () {
736
+ module.verbose('Removing error state from element', $context);
737
+ $context.removeClass(className.error);
738
+ },
739
+ loading: function () {
740
+ module.verbose('Removing loading state from element', $context);
741
+ $context.removeClass(className.loading);
742
+ },
743
+ },
744
+
745
+ get: {
746
+ normalizedData: function () {
747
+ return typeof settings.data === 'string' ? settings.data : JSON.stringify(settings.data, Object.keys(settings.data).sort());
748
+ },
749
+ responseFromXHR: function (xhr) {
750
+ return $.isPlainObject(xhr)
751
+ ? (module.is.expectingJSON()
752
+ ? module.decode.json(xhr.responseText)
753
+ : xhr.responseText)
754
+ : false;
755
+ },
756
+ errorFromRequest: function (response, status, httpMessage) {
757
+ return $.isPlainObject(response) && response.error !== undefined
758
+ ? response.error // use json error message
759
+ : (settings.error[status] !== undefined // use server error message
760
+ ? settings.error[status]
761
+ : httpMessage);
762
+ },
763
+ request: function () {
764
+ return module.request || false;
765
+ },
766
+ xhr: function () {
767
+ return module.xhr || false;
768
+ },
769
+ settings: function () {
770
+ var
771
+ runSettings
772
+ ;
773
+ runSettings = settings.beforeSend.call($module, settings);
774
+ if (runSettings) {
775
+ if (runSettings.success !== undefined) {
776
+ module.debug('Legacy success callback detected', runSettings);
777
+ module.error(error.legacyParameters, runSettings.success);
778
+ runSettings.onSuccess = runSettings.success;
779
+ }
780
+ if (runSettings.failure !== undefined) {
781
+ module.debug('Legacy failure callback detected', runSettings);
782
+ module.error(error.legacyParameters, runSettings.failure);
783
+ runSettings.onFailure = runSettings.failure;
784
+ }
785
+ if (runSettings.complete !== undefined) {
786
+ module.debug('Legacy complete callback detected', runSettings);
787
+ module.error(error.legacyParameters, runSettings.complete);
788
+ runSettings.onComplete = runSettings.complete;
789
+ }
790
+ }
791
+ if (runSettings === undefined) {
792
+ module.error(error.noReturnedValue);
793
+ }
794
+ if (runSettings === false) {
795
+ return runSettings;
796
+ }
797
+
798
+ return runSettings !== undefined
799
+ ? $.extend(true, {}, runSettings)
800
+ : $.extend(true, {}, settings);
801
+ },
802
+ urlEncodedValue: function (value) {
803
+ var
804
+ decodedValue = window.decodeURIComponent(value),
805
+ encodedValue = window.encodeURIComponent(value),
806
+ alreadyEncoded = decodedValue !== value
807
+ ;
808
+ if (alreadyEncoded) {
809
+ module.debug('URL value is already encoded, avoiding double encoding', value);
810
+
811
+ return value;
812
+ }
813
+ module.verbose('Encoding value using encodeURIComponent', value, encodedValue);
814
+
815
+ return encodedValue;
816
+ },
817
+ defaultData: function () {
818
+ var
819
+ data = {}
820
+ ;
821
+ if (!isWindow(element)) {
822
+ if (module.is.input()) {
823
+ data.value = $module.val();
824
+ } else if (!module.is.form()) {
825
+ data.text = $module.text();
826
+ }
827
+ }
828
+
829
+ return data;
830
+ },
831
+ event: function () {
832
+ if (isWindow(element) || settings.on === 'now') {
833
+ module.debug('API called without element, no events attached');
834
+
835
+ return false;
836
+ }
837
+ if (settings.on === 'auto') {
838
+ if ($module.is('input')) {
839
+ return element.oninput !== undefined
840
+ ? 'input'
841
+ : (element.onpropertychange !== undefined
842
+ ? 'propertychange'
843
+ : 'keyup');
844
+ }
845
+ if ($module.is('form')) {
846
+ return 'submit';
847
+ }
848
+
849
+ return 'click';
850
+ }
851
+
852
+ return settings.on;
853
+ },
854
+ templatedURL: function (action) {
855
+ action = action || settings.action || $module.data(metadata.action) || false;
856
+ url = settings.url || $module.data(metadata.url) || false;
857
+ if (url) {
858
+ module.debug('Using specified url', url);
859
+
860
+ return url;
861
+ }
862
+ if (action) {
863
+ module.debug('Looking up url for action', action, settings.api);
864
+ if (settings.api[action] === undefined && !module.is.mocked()) {
865
+ module.error(error.missingAction, settings.action, settings.api);
866
+
867
+ return;
868
+ }
869
+ url = settings.api[action];
870
+ } else if (module.is.form()) {
871
+ url = $module.attr('action') || $context.attr('action') || false;
872
+ module.debug('No url or action specified, defaulting to form action', url);
873
+ }
874
+
875
+ return url;
876
+ },
877
+ },
878
+
879
+ abort: function () {
880
+ var
881
+ xhr = module.get.xhr()
389
882
  ;
390
- url = url.replace(templatedString, value);
391
- }
392
- });
393
- }
394
- if(optionalVariables) {
395
- module.debug('Looking for optional URL variables', requiredVariables);
396
- $.each(optionalVariables, function(index, templatedString) {
397
- var
398
- // allow legacy {/$var} style
399
- variable = (templatedString.indexOf('$') !== -1)
400
- ? templatedString.substr(3, templatedString.length - 4)
401
- : templatedString.substr(2, templatedString.length - 3),
402
- value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
403
- ? urlData[variable]
404
- : ($module.data(variable) !== undefined)
405
- ? $module.data(variable)
406
- : ($context.data(variable) !== undefined)
407
- ? $context.data(variable)
408
- : urlData[variable]
409
- ;
410
- // optional replacement
411
- if(value !== undefined) {
412
- module.verbose('Optional variable Found', variable, value);
413
- url = url.replace(templatedString, value);
414
- }
415
- else {
416
- module.verbose('Optional variable not found', variable);
417
- // remove preceding slash if set
418
- if(url.indexOf('/' + templatedString) !== -1) {
419
- url = url.replace('/' + templatedString, '');
883
+ if (xhr && xhr.state() !== 'resolved') {
884
+ module.debug('Cancelling API request');
885
+ xhr.abort();
420
886
  }
421
- else {
422
- url = url.replace(templatedString, '');
887
+ },
888
+
889
+ // reset state
890
+ reset: function () {
891
+ module.remove.error();
892
+ module.remove.loading();
893
+ },
894
+
895
+ setting: function (name, value) {
896
+ module.debug('Changing setting', name, value);
897
+ if ($.isPlainObject(name)) {
898
+ $.extend(true, settings, name);
899
+ } else if (value !== undefined) {
900
+ if ($.isPlainObject(settings[name])) {
901
+ $.extend(true, settings[name], value);
902
+ } else {
903
+ settings[name] = value;
904
+ }
905
+ } else {
906
+ return settings[name];
907
+ }
908
+ },
909
+ internal: function (name, value) {
910
+ if ($.isPlainObject(name)) {
911
+ $.extend(true, module, name);
912
+ } else if (value !== undefined) {
913
+ module[name] = value;
914
+ } else {
915
+ return module[name];
916
+ }
917
+ },
918
+ debug: function () {
919
+ if (!settings.silent && settings.debug) {
920
+ if (settings.performance) {
921
+ module.performance.log(arguments);
922
+ } else {
923
+ module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
924
+ module.debug.apply(console, arguments);
925
+ }
926
+ }
927
+ },
928
+ verbose: function () {
929
+ if (!settings.silent && settings.verbose && settings.debug) {
930
+ if (settings.performance) {
931
+ module.performance.log(arguments);
932
+ } else {
933
+ module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
934
+ module.verbose.apply(console, arguments);
935
+ }
936
+ }
937
+ },
938
+ error: function () {
939
+ if (!settings.silent) {
940
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
941
+ module.error.apply(console, arguments);
942
+ }
943
+ },
944
+ performance: {
945
+ log: function (message) {
946
+ var
947
+ currentTime,
948
+ executionTime,
949
+ previousTime
950
+ ;
951
+ if (settings.performance) {
952
+ currentTime = Date.now();
953
+ previousTime = time || currentTime;
954
+ executionTime = currentTime - previousTime;
955
+ time = currentTime;
956
+ performance.push({
957
+ Name: message[0],
958
+ Arguments: [].slice.call(message, 1) || '',
959
+ // 'Element' : element,
960
+ 'Execution Time': executionTime,
961
+ });
962
+ }
963
+ clearTimeout(module.performance.timer);
964
+ module.performance.timer = setTimeout(module.performance.display, 500);
965
+ },
966
+ display: function () {
967
+ var
968
+ title = settings.name + ':',
969
+ totalTime = 0
970
+ ;
971
+ time = false;
972
+ clearTimeout(module.performance.timer);
973
+ $.each(performance, function (index, data) {
974
+ totalTime += data['Execution Time'];
975
+ });
976
+ title += ' ' + totalTime + 'ms';
977
+ if (moduleSelector) {
978
+ title += ' \'' + moduleSelector + '\'';
979
+ }
980
+ if (performance.length > 0) {
981
+ console.groupCollapsed(title);
982
+ if (console.table) {
983
+ console.table(performance);
984
+ } else {
985
+ $.each(performance, function (index, data) {
986
+ console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
987
+ });
988
+ }
989
+ console.groupEnd();
990
+ }
991
+ performance = [];
992
+ },
993
+ },
994
+ invoke: function (query, passedArguments, context) {
995
+ var
996
+ object = instance,
997
+ maxDepth,
998
+ found,
999
+ response
1000
+ ;
1001
+ passedArguments = passedArguments || queryArguments;
1002
+ context = context || element;
1003
+ if (typeof query === 'string' && object !== undefined) {
1004
+ query = query.split(/[ .]/);
1005
+ maxDepth = query.length - 1;
1006
+ $.each(query, function (depth, value) {
1007
+ var camelCaseValue = depth !== maxDepth
1008
+ ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
1009
+ : query
1010
+ ;
1011
+ if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
1012
+ object = object[camelCaseValue];
1013
+ } else if (object[camelCaseValue] !== undefined) {
1014
+ found = object[camelCaseValue];
1015
+
1016
+ return false;
1017
+ } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
1018
+ object = object[value];
1019
+ } else if (object[value] !== undefined) {
1020
+ found = object[value];
1021
+
1022
+ return false;
1023
+ } else {
1024
+ module.error(error.method, query);
1025
+
1026
+ return false;
1027
+ }
1028
+ });
1029
+ }
1030
+ if (isFunction(found)) {
1031
+ response = found.apply(context, passedArguments);
1032
+ } else if (found !== undefined) {
1033
+ response = found;
1034
+ }
1035
+ if (Array.isArray(returnedValue)) {
1036
+ returnedValue.push(response);
1037
+ } else if (returnedValue !== undefined) {
1038
+ returnedValue = [returnedValue, response];
1039
+ } else if (response !== undefined) {
1040
+ returnedValue = response;
423
1041
  }
424
- }
425
- });
426
- }
427
- }
428
- return url;
429
- },
430
- formData: function(data) {
431
- var
432
- canSerialize = ($.fn.serializeObject !== undefined),
433
- formData = (canSerialize)
434
- ? $form.serializeObject()
435
- : $form.serialize(),
436
- hasOtherData
437
- ;
438
- data = data || settings.data;
439
- hasOtherData = $.isPlainObject(data);
440
-
441
- if(hasOtherData) {
442
- if(canSerialize) {
443
- module.debug('Extending existing data with form data', data, formData);
444
- data = $.extend(true, {}, data, formData);
445
- }
446
- else {
447
- module.error(error.missingSerialize);
448
- module.debug('Cant extend data. Replacing data with form data', data, formData);
449
- data = formData;
450
- }
451
- }
452
- else {
453
- module.debug('Adding form data', formData);
454
- data = formData;
455
- }
456
- return data;
457
- }
458
- },
459
1042
 
460
- send: {
461
- request: function() {
462
- module.set.loading();
463
- module.request = module.create.request();
464
- if( module.is.mocked() ) {
465
- module.mockedXHR = module.create.mockedXHR();
466
- }
467
- else {
468
- module.xhr = module.create.xhr();
469
- }
470
- settings.onRequest.call(context, module.request, module.xhr);
471
- }
472
- },
1043
+ return found;
1044
+ },
1045
+ };
473
1046
 
474
- event: {
475
- trigger: function(event) {
476
- module.query();
477
- if(event.type == 'submit' || event.type == 'click') {
478
- event.preventDefault();
479
- }
480
- },
481
- xhr: {
482
- always: function() {
483
- // nothing special
484
- },
485
- done: function(response, textStatus, xhr) {
486
- var
487
- context = this,
488
- elapsedTime = (new Date().getTime() - requestStartTime),
489
- timeLeft = (settings.loadingDuration - elapsedTime),
490
- translatedResponse = ( $.isFunction(settings.onResponse) )
491
- ? module.is.expectingJSON() && !settings.rawResponse
492
- ? settings.onResponse.call(context, $.extend(true, {}, response))
493
- : settings.onResponse.call(context, response)
494
- : false
495
- ;
496
- timeLeft = (timeLeft > 0)
497
- ? timeLeft
498
- : 0
499
- ;
500
- if(translatedResponse) {
501
- module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response);
502
- response = translatedResponse;
503
- }
504
- if(timeLeft > 0) {
505
- module.debug('Response completed early delaying state change by', timeLeft);
506
- }
507
- setTimeout(function() {
508
- if( module.is.validResponse(response) ) {
509
- module.request.resolveWith(context, [response, xhr]);
510
- }
511
- else {
512
- module.request.rejectWith(context, [xhr, 'invalid']);
513
- }
514
- }, timeLeft);
515
- },
516
- fail: function(xhr, status, httpMessage) {
517
- var
518
- context = this,
519
- elapsedTime = (new Date().getTime() - requestStartTime),
520
- timeLeft = (settings.loadingDuration - elapsedTime)
521
- ;
522
- timeLeft = (timeLeft > 0)
523
- ? timeLeft
524
- : 0
525
- ;
526
- if(timeLeft > 0) {
527
- module.debug('Response completed early delaying state change by', timeLeft);
528
- }
529
- setTimeout(function() {
530
- if( module.is.abortedRequest(xhr) ) {
531
- module.request.rejectWith(context, [xhr, 'aborted', httpMessage]);
1047
+ if (methodInvoked) {
1048
+ if (instance === undefined) {
1049
+ module.initialize();
532
1050
  }
533
- else {
534
- module.request.rejectWith(context, [xhr, 'error', status, httpMessage]);
1051
+ module.invoke(query);
1052
+ } else {
1053
+ if (instance !== undefined) {
1054
+ instance.invoke('destroy');
535
1055
  }
536
- }, timeLeft);
1056
+ module.initialize();
537
1057
  }
538
- },
539
- request: {
540
- done: function(response, xhr) {
541
- module.debug('Successful API Response', response);
542
- if(settings.cache === 'local' && url) {
543
- module.write.cachedResponse(url, response);
544
- module.debug('Saving server response locally', module.cache);
545
- }
546
- settings.onSuccess.call(context, response, $module, xhr);
547
- },
548
- complete: function(firstParameter, secondParameter) {
549
- var
550
- xhr,
551
- response
552
- ;
553
- // have to guess callback parameters based on request success
554
- if( module.was.successful() ) {
555
- response = firstParameter;
556
- xhr = secondParameter;
557
- }
558
- else {
559
- xhr = firstParameter;
560
- response = module.get.responseFromXHR(xhr);
561
- }
562
- module.remove.loading();
563
- settings.onComplete.call(context, response, $module, xhr);
564
- },
565
- fail: function(xhr, status, httpMessage) {
566
- var
567
- // pull response from xhr if available
568
- response = module.get.responseFromXHR(xhr),
569
- errorMessage = module.get.errorFromRequest(response, status, httpMessage)
570
- ;
571
- if(status == 'aborted') {
572
- module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage);
573
- settings.onAbort.call(context, status, $module, xhr);
574
- return true;
575
- }
576
- else if(status == 'invalid') {
577
- module.debug('JSON did not pass success test. A server-side error has most likely occurred', response);
578
- }
579
- else if(status == 'error') {
580
- if(xhr !== undefined) {
581
- module.debug('XHR produced a server error', status, httpMessage);
582
- // make sure we have an error to display to console
583
- if( (xhr.status < 200 || xhr.status >= 300) && httpMessage !== undefined && httpMessage !== '') {
584
- module.error(error.statusMessage + httpMessage, ajaxSettings.url);
585
- }
586
- settings.onError.call(context, errorMessage, $module, xhr);
587
- }
588
- }
1058
+ });
589
1059
 
590
- if(settings.errorDuration && status !== 'aborted') {
591
- module.debug('Adding error state');
592
- module.set.error();
593
- if( module.should.removeError() ) {
594
- setTimeout(module.remove.error, settings.errorDuration);
595
- }
596
- }
597
- module.debug('API Request failed', errorMessage, xhr);
598
- settings.onFailure.call(context, response, $module, xhr);
599
- }
600
- }
601
- },
1060
+ return returnedValue !== undefined
1061
+ ? returnedValue
1062
+ : this;
1063
+ };
1064
+ $.api = $.fn.api;
602
1065
 
603
- create: {
1066
+ $.api.settings = {
604
1067
 
605
- request: function() {
606
- // api request promise
607
- return $.Deferred()
608
- .always(module.event.request.complete)
609
- .done(module.event.request.done)
610
- .fail(module.event.request.fail)
611
- ;
612
- },
1068
+ name: 'API',
1069
+ namespace: 'api',
613
1070
 
614
- mockedXHR: function () {
615
- var
616
- // xhr does not simulate these properties of xhr but must return them
617
- textStatus = false,
618
- status = false,
619
- httpMessage = false,
620
- responder = settings.mockResponse || settings.response,
621
- asyncResponder = settings.mockResponseAsync || settings.responseAsync,
622
- asyncCallback,
623
- response,
624
- mockedXHR
625
- ;
1071
+ debug: false,
1072
+ verbose: false,
1073
+ performance: true,
626
1074
 
627
- mockedXHR = $.Deferred()
628
- .always(module.event.xhr.complete)
629
- .done(module.event.xhr.done)
630
- .fail(module.event.xhr.fail)
631
- ;
1075
+ // object containing all templates endpoints
1076
+ api: {},
632
1077
 
633
- if(responder) {
634
- if( $.isFunction(responder) ) {
635
- module.debug('Using specified synchronous callback', responder);
636
- response = responder.call(context, requestSettings);
637
- }
638
- else {
639
- module.debug('Using settings specified response', responder);
640
- response = responder;
641
- }
642
- // simulating response
643
- mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
644
- }
645
- else if( $.isFunction(asyncResponder) ) {
646
- asyncCallback = function(response) {
647
- module.debug('Async callback returned response', response);
1078
+ // whether to cache responses
1079
+ cache: true,
648
1080
 
649
- if(response) {
650
- mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
651
- }
652
- else {
653
- mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]);
654
- }
655
- };
656
- module.debug('Using specified async response callback', asyncResponder);
657
- asyncResponder.call(context, requestSettings, asyncCallback);
658
- }
659
- return mockedXHR;
660
- },
1081
+ // whether new requests should abort previous requests
1082
+ interruptRequests: true,
661
1083
 
662
- xhr: function() {
663
- var
664
- xhr
665
- ;
666
- // ajax request promise
667
- xhr = $.ajax(ajaxSettings)
668
- .always(module.event.xhr.always)
669
- .done(module.event.xhr.done)
670
- .fail(module.event.xhr.fail)
671
- ;
672
- module.verbose('Created server request', xhr, ajaxSettings);
673
- return xhr;
674
- }
675
- },
1084
+ // event binding
1085
+ on: 'auto',
676
1086
 
677
- set: {
678
- error: function() {
679
- module.verbose('Adding error state to element', $context);
680
- $context.addClass(className.error);
681
- },
682
- loading: function() {
683
- module.verbose('Adding loading state to element', $context);
684
- $context.addClass(className.loading);
685
- requestStartTime = new Date().getTime();
686
- }
687
- },
1087
+ // context for applying state classes
1088
+ stateContext: false,
688
1089
 
689
- remove: {
690
- error: function() {
691
- module.verbose('Removing error state from element', $context);
692
- $context.removeClass(className.error);
693
- },
694
- loading: function() {
695
- module.verbose('Removing loading state from element', $context);
696
- $context.removeClass(className.loading);
697
- }
698
- },
1090
+ // duration for loading state
1091
+ loadingDuration: 0,
699
1092
 
700
- get: {
701
- responseFromXHR: function(xhr) {
702
- return $.isPlainObject(xhr)
703
- ? (module.is.expectingJSON())
704
- ? module.decode.json(xhr.responseText)
705
- : xhr.responseText
706
- : false
707
- ;
708
- },
709
- errorFromRequest: function(response, status, httpMessage) {
710
- return ($.isPlainObject(response) && response.error !== undefined)
711
- ? response.error // use json error message
712
- : (settings.error[status] !== undefined) // use server error message
713
- ? settings.error[status]
714
- : httpMessage
715
- ;
716
- },
717
- request: function() {
718
- return module.request || false;
719
- },
720
- xhr: function() {
721
- return module.xhr || false;
722
- },
723
- settings: function() {
724
- var
725
- runSettings
726
- ;
727
- runSettings = settings.beforeSend.call($module, settings);
728
- if(runSettings) {
729
- if(runSettings.success !== undefined) {
730
- module.debug('Legacy success callback detected', runSettings);
731
- module.error(error.legacyParameters, runSettings.success);
732
- runSettings.onSuccess = runSettings.success;
733
- }
734
- if(runSettings.failure !== undefined) {
735
- module.debug('Legacy failure callback detected', runSettings);
736
- module.error(error.legacyParameters, runSettings.failure);
737
- runSettings.onFailure = runSettings.failure;
738
- }
739
- if(runSettings.complete !== undefined) {
740
- module.debug('Legacy complete callback detected', runSettings);
741
- module.error(error.legacyParameters, runSettings.complete);
742
- runSettings.onComplete = runSettings.complete;
743
- }
744
- }
745
- if(runSettings === undefined) {
746
- module.error(error.noReturnedValue);
747
- }
748
- if(runSettings === false) {
749
- return runSettings;
750
- }
751
- return (runSettings !== undefined)
752
- ? $.extend(true, {}, runSettings)
753
- : $.extend(true, {}, settings)
754
- ;
755
- },
756
- urlEncodedValue: function(value) {
757
- var
758
- decodedValue = window.decodeURIComponent(value),
759
- encodedValue = window.encodeURIComponent(value),
760
- alreadyEncoded = (decodedValue !== value)
761
- ;
762
- if(alreadyEncoded) {
763
- module.debug('URL value is already encoded, avoiding double encoding', value);
764
- return value;
765
- }
766
- module.verbose('Encoding value using encodeURIComponent', value, encodedValue);
767
- return encodedValue;
768
- },
769
- defaultData: function() {
770
- var
771
- data = {}
772
- ;
773
- if( !$.isWindow(element) ) {
774
- if( module.is.input() ) {
775
- data.value = $module.val();
776
- }
777
- else if( module.is.form() ) {
778
-
779
- }
780
- else {
781
- data.text = $module.text();
782
- }
783
- }
784
- return data;
785
- },
786
- event: function() {
787
- if( $.isWindow(element) || settings.on == 'now' ) {
788
- module.debug('API called without element, no events attached');
789
- return false;
790
- }
791
- else if(settings.on == 'auto') {
792
- if( $module.is('input') ) {
793
- return (element.oninput !== undefined)
794
- ? 'input'
795
- : (element.onpropertychange !== undefined)
796
- ? 'propertychange'
797
- : 'keyup'
798
- ;
799
- }
800
- else if( $module.is('form') ) {
801
- return 'submit';
802
- }
803
- else {
804
- return 'click';
805
- }
806
- }
807
- else {
808
- return settings.on;
809
- }
810
- },
811
- templatedURL: function(action) {
812
- action = action || $module.data(metadata.action) || settings.action || false;
813
- url = $module.data(metadata.url) || settings.url || false;
814
- if(url) {
815
- module.debug('Using specified url', url);
816
- return url;
817
- }
818
- if(action) {
819
- module.debug('Looking up url for action', action, settings.api);
820
- if(settings.api[action] === undefined && !module.is.mocked()) {
821
- module.error(error.missingAction, settings.action, settings.api);
822
- return;
823
- }
824
- url = settings.api[action];
825
- }
826
- else if( module.is.form() ) {
827
- url = $module.attr('action') || $context.attr('action') || false;
828
- module.debug('No url or action specified, defaulting to form action', url);
829
- }
830
- return url;
831
- }
832
- },
1093
+ // whether to hide errors after a period of time
1094
+ hideError: 'auto',
833
1095
 
834
- abort: function() {
835
- var
836
- xhr = module.get.xhr()
837
- ;
838
- if( xhr && xhr.state() !== 'resolved') {
839
- module.debug('Cancelling API request');
840
- xhr.abort();
841
- }
842
- },
1096
+ // duration for error state
1097
+ errorDuration: 2000,
843
1098
 
844
- // reset state
845
- reset: function() {
846
- module.remove.error();
847
- module.remove.loading();
848
- },
1099
+ // whether parameters should be encoded with encodeURIComponent
1100
+ encodeParameters: true,
849
1101
 
850
- setting: function(name, value) {
851
- module.debug('Changing setting', name, value);
852
- if( $.isPlainObject(name) ) {
853
- $.extend(true, settings, name);
854
- }
855
- else if(value !== undefined) {
856
- if($.isPlainObject(settings[name])) {
857
- $.extend(true, settings[name], value);
858
- }
859
- else {
860
- settings[name] = value;
861
- }
862
- }
863
- else {
864
- return settings[name];
865
- }
866
- },
867
- internal: function(name, value) {
868
- if( $.isPlainObject(name) ) {
869
- $.extend(true, module, name);
870
- }
871
- else if(value !== undefined) {
872
- module[name] = value;
873
- }
874
- else {
875
- return module[name];
876
- }
877
- },
878
- debug: function() {
879
- if(!settings.silent && settings.debug) {
880
- if(settings.performance) {
881
- module.performance.log(arguments);
882
- }
883
- else {
884
- module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
885
- module.debug.apply(console, arguments);
886
- }
887
- }
888
- },
889
- verbose: function() {
890
- if(!settings.silent && settings.verbose && settings.debug) {
891
- if(settings.performance) {
892
- module.performance.log(arguments);
893
- }
894
- else {
895
- module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
896
- module.verbose.apply(console, arguments);
897
- }
898
- }
899
- },
900
- error: function() {
901
- if(!settings.silent) {
902
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
903
- module.error.apply(console, arguments);
904
- }
905
- },
906
- performance: {
907
- log: function(message) {
908
- var
909
- currentTime,
910
- executionTime,
911
- previousTime
912
- ;
913
- if(settings.performance) {
914
- currentTime = new Date().getTime();
915
- previousTime = time || currentTime;
916
- executionTime = currentTime - previousTime;
917
- time = currentTime;
918
- performance.push({
919
- 'Name' : message[0],
920
- 'Arguments' : [].slice.call(message, 1) || '',
921
- //'Element' : element,
922
- 'Execution Time' : executionTime
923
- });
924
- }
925
- clearTimeout(module.performance.timer);
926
- module.performance.timer = setTimeout(module.performance.display, 500);
927
- },
928
- display: function() {
929
- var
930
- title = settings.name + ':',
931
- totalTime = 0
932
- ;
933
- time = false;
934
- clearTimeout(module.performance.timer);
935
- $.each(performance, function(index, data) {
936
- totalTime += data['Execution Time'];
937
- });
938
- title += ' ' + totalTime + 'ms';
939
- if(moduleSelector) {
940
- title += ' \'' + moduleSelector + '\'';
941
- }
942
- if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
943
- console.groupCollapsed(title);
944
- if(console.table) {
945
- console.table(performance);
946
- }
947
- else {
948
- $.each(performance, function(index, data) {
949
- console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
950
- });
951
- }
952
- console.groupEnd();
953
- }
954
- performance = [];
955
- }
956
- },
957
- invoke: function(query, passedArguments, context) {
958
- var
959
- object = instance,
960
- maxDepth,
961
- found,
962
- response
963
- ;
964
- passedArguments = passedArguments || queryArguments;
965
- context = element || context;
966
- if(typeof query == 'string' && object !== undefined) {
967
- query = query.split(/[\. ]/);
968
- maxDepth = query.length - 1;
969
- $.each(query, function(depth, value) {
970
- var camelCaseValue = (depth != maxDepth)
971
- ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
972
- : query
973
- ;
974
- if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
975
- object = object[camelCaseValue];
976
- }
977
- else if( object[camelCaseValue] !== undefined ) {
978
- found = object[camelCaseValue];
979
- return false;
980
- }
981
- else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
982
- object = object[value];
983
- }
984
- else if( object[value] !== undefined ) {
985
- found = object[value];
986
- return false;
987
- }
988
- else {
989
- module.error(error.method, query);
990
- return false;
991
- }
992
- });
993
- }
994
- if ( $.isFunction( found ) ) {
995
- response = found.apply(context, passedArguments);
996
- }
997
- else if(found !== undefined) {
998
- response = found;
999
- }
1000
- if(Array.isArray(returnedValue)) {
1001
- returnedValue.push(response);
1002
- }
1003
- else if(returnedValue !== undefined) {
1004
- returnedValue = [returnedValue, response];
1005
- }
1006
- else if(response !== undefined) {
1007
- returnedValue = response;
1008
- }
1009
- return found;
1010
- }
1011
- };
1012
-
1013
- if(methodInvoked) {
1014
- if(instance === undefined) {
1015
- module.initialize();
1016
- }
1017
- module.invoke(query);
1018
- }
1019
- else {
1020
- if(instance !== undefined) {
1021
- instance.invoke('destroy');
1022
- }
1023
- module.initialize();
1024
- }
1025
- })
1026
- ;
1027
-
1028
- return (returnedValue !== undefined)
1029
- ? returnedValue
1030
- : this
1031
- ;
1032
- };
1033
-
1034
- $.api.settings = {
1035
-
1036
- name : 'API',
1037
- namespace : 'api',
1038
-
1039
- debug : false,
1040
- verbose : false,
1041
- performance : true,
1042
-
1043
- // object containing all templates endpoints
1044
- api : {},
1045
-
1046
- // whether to cache responses
1047
- cache : true,
1048
-
1049
- // whether new requests should abort previous requests
1050
- interruptRequests : true,
1051
-
1052
- // event binding
1053
- on : 'auto',
1054
-
1055
- // context for applying state classes
1056
- stateContext : false,
1057
-
1058
- // duration for loading state
1059
- loadingDuration : 0,
1060
-
1061
- // whether to hide errors after a period of time
1062
- hideError : 'auto',
1063
-
1064
- // duration for error state
1065
- errorDuration : 2000,
1066
-
1067
- // whether parameters should be encoded with encodeURIComponent
1068
- encodeParameters : true,
1069
-
1070
- // API action to use
1071
- action : false,
1072
-
1073
- // templated URL to use
1074
- url : false,
1075
-
1076
- // base URL to apply to all endpoints
1077
- base : '',
1078
-
1079
- // data that will
1080
- urlData : {},
1081
-
1082
- // whether to add default data to url data
1083
- defaultData : true,
1084
-
1085
- // whether to serialize closest form
1086
- serializeForm : false,
1087
-
1088
- // how long to wait before request should occur
1089
- throttle : 0,
1090
-
1091
- // whether to throttle first request or only repeated
1092
- throttleFirstRequest : true,
1093
-
1094
- // standard ajax settings
1095
- method : 'get',
1096
- data : {},
1097
- dataType : 'json',
1098
-
1099
- // mock response
1100
- mockResponse : false,
1101
- mockResponseAsync : false,
1102
-
1103
- // aliases for mock
1104
- response : false,
1105
- responseAsync : false,
1106
-
1107
- // whether onResponse should work with response value without force converting into an object
1108
- rawResponse : false,
1102
+ // API action to use
1103
+ action: false,
1109
1104
 
1110
- // callbacks before request
1111
- beforeSend : function(settings) { return settings; },
1112
- beforeXHR : function(xhr) {},
1113
- onRequest : function(promise, xhr) {},
1105
+ // templated URL to use
1106
+ url: false,
1114
1107
 
1115
- // after request
1116
- onResponse : false, // function(response) { },
1108
+ // base URL to apply to all endpoints
1109
+ base: '',
1117
1110
 
1118
- // response was successful, if JSON passed validation
1119
- onSuccess : function(response, $module) {},
1111
+ // data that will
1112
+ urlData: {},
1120
1113
 
1121
- // request finished without aborting
1122
- onComplete : function(response, $module) {},
1114
+ // whether to add default data to url data
1115
+ defaultData: true,
1123
1116
 
1124
- // failed JSON success test
1125
- onFailure : function(response, $module) {},
1117
+ // whether to serialize closest form
1118
+ // use true to convert complex named keys like a[b][1][c][] into a nested object
1119
+ // use 'formdata' for formdata web api
1120
+ serializeForm: false,
1126
1121
 
1127
- // server error
1128
- onError : function(errorMessage, $module) {},
1122
+ // how long to wait before request should occur
1123
+ throttle: 0,
1129
1124
 
1130
- // request aborted
1131
- onAbort : function(errorMessage, $module) {},
1125
+ // whether to throttle first request or only repeated
1126
+ throttleFirstRequest: true,
1132
1127
 
1133
- successTest : false,
1128
+ // standard ajax settings
1129
+ method: 'get',
1130
+ data: {},
1131
+ dataType: 'json',
1134
1132
 
1135
- // errors
1136
- error : {
1137
- beforeSend : 'The before send function has aborted the request',
1138
- error : 'There was an error with your request',
1139
- exitConditions : 'API Request Aborted. Exit conditions met',
1140
- JSONParse : 'JSON could not be parsed during error handling',
1141
- legacyParameters : 'You are using legacy API success callback names',
1142
- method : 'The method you called is not defined',
1143
- missingAction : 'API action used but no url was defined',
1144
- missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object',
1145
- missingURL : 'No URL specified for api event',
1146
- noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.',
1147
- noStorage : 'Caching responses locally requires session storage',
1148
- parseError : 'There was an error parsing your request',
1149
- requiredParameter : 'Missing a required URL parameter: ',
1150
- statusMessage : 'Server gave an error: ',
1151
- timeout : 'Your request timed out'
1152
- },
1133
+ // mock response
1134
+ mockResponse: false,
1135
+ mockResponseAsync: false,
1153
1136
 
1154
- regExp : {
1155
- required : /\{\$*[A-z0-9]+\}/g,
1156
- optional : /\{\/\$*[A-z0-9]+\}/g,
1157
- },
1137
+ // aliases for mock
1138
+ response: false,
1139
+ responseAsync: false,
1158
1140
 
1159
- className: {
1160
- loading : 'loading',
1161
- error : 'error'
1162
- },
1141
+ // whether onResponse should work with response value without force converting into an object
1142
+ rawResponse: true,
1163
1143
 
1164
- selector: {
1165
- disabled : '.disabled',
1166
- form : 'form'
1167
- },
1144
+ // callbacks before request
1145
+ beforeSend: function (settings) {
1146
+ return settings;
1147
+ },
1148
+ beforeXHR: function (xhr) {},
1149
+ onRequest: function (promise, xhr) {},
1150
+
1151
+ // after request
1152
+ onResponse: false, // function(response) { },
1153
+
1154
+ // response was successful, if JSON passed validation
1155
+ onSuccess: function (response, $module) {},
1156
+
1157
+ // request finished without aborting
1158
+ onComplete: function (response, $module) {},
1159
+
1160
+ // failed JSON success test
1161
+ onFailure: function (response, $module) {},
1162
+
1163
+ // server error
1164
+ onError: function (errorMessage, $module) {},
1165
+
1166
+ // request aborted
1167
+ onAbort: function (errorMessage, $module) {},
1168
+
1169
+ successTest: false,
1170
+
1171
+ // errors
1172
+ error: {
1173
+ beforeSend: 'The before send function has aborted the request',
1174
+ error: 'There was an error with your request',
1175
+ exitConditions: 'API Request Aborted. Exit conditions met',
1176
+ JSONParse: 'JSON could not be parsed during error handling',
1177
+ legacyParameters: 'You are using legacy API success callback names',
1178
+ method: 'The method you called is not defined',
1179
+ missingAction: 'API action used but no url was defined',
1180
+ missingURL: 'No URL specified for api event',
1181
+ noReturnedValue: 'The beforeSend callback must return a settings object, beforeSend ignored.',
1182
+ noStorage: 'Caching responses locally requires session storage',
1183
+ parseError: 'There was an error parsing your request',
1184
+ requiredParameter: 'Missing a required URL parameter: ',
1185
+ statusMessage: 'Server gave an error: ',
1186
+ timeout: 'Your request timed out',
1187
+ },
1168
1188
 
1169
- metadata: {
1170
- action : 'action',
1171
- url : 'url'
1172
- }
1173
- };
1189
+ regExp: {
1190
+ required: /{\$*[\da-z]+}/gi,
1191
+ optional: /{\/\$*[\da-z]+}/gi,
1192
+ validate: /^[_a-z][\w-]*(?:\[[\w-]*])*$/i,
1193
+ key: /[\w-]+|(?=\[])/gi,
1194
+ push: /^$/,
1195
+ fixed: /^\d+$/,
1196
+ named: /^[\w-]+$/i,
1197
+ },
1174
1198
 
1199
+ className: {
1200
+ loading: 'loading',
1201
+ error: 'error',
1202
+ },
1175
1203
 
1204
+ selector: {
1205
+ disabled: '.disabled',
1206
+ form: 'form',
1207
+ },
1176
1208
 
1177
- })( jQuery, window, document );
1209
+ metadata: {
1210
+ action: 'action',
1211
+ url: 'url',
1212
+ },
1213
+ };
1214
+ })(jQuery, window, document);