@pageboard/html 0.14.19 → 0.14.21

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