@northdata/fomantic-ui 2.8.722 → 2.9.401

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