fomantic-ui-sass 2.9.0 → 2.9.2

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