UNPKG

1.37 MBJavaScriptView Raw
1/*
2 * # Fomantic UI - 2.9.3
3 * https://github.com/fomantic/Fomantic-UI
4 * https://fomantic-ui.com/
5 *
6 * Copyright 2023 Contributors
7 * Released under the MIT license
8 * https://opensource.org/licenses/MIT
9 *
10 */
11/*!
12 * # Fomantic-UI 2.9.3 - Site
13 * https://github.com/fomantic/Fomantic-UI/
14 *
15 *
16 * Released under the MIT license
17 * https://opensource.org/licenses/MIT
18 *
19 */
20
21(function ($, window, document) {
22 'use strict';
23
24 function isFunction(obj) {
25 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
26 }
27
28 window = window !== undefined && window.Math === Math
29 ? window
30 : globalThis;
31
32 $.fn.site = function (parameters) {
33 var
34 time = Date.now(),
35 performance = [],
36
37 query = arguments[0],
38 methodInvoked = typeof query === 'string',
39 queryArguments = [].slice.call(arguments, 1),
40
41 settings = $.isPlainObject(parameters)
42 ? $.extend(true, {}, $.site.settings, parameters)
43 : $.extend({}, $.site.settings),
44
45 namespace = settings.namespace,
46 error = settings.error,
47
48 moduleNamespace = 'module-' + namespace,
49
50 $document = $(document),
51 $module = $document,
52 element = this,
53 instance = $module.data(moduleNamespace),
54
55 module,
56 returnedValue
57 ;
58 module = {
59
60 initialize: function () {
61 module.instantiate();
62 },
63
64 instantiate: function () {
65 module.verbose('Storing instance of site', module);
66 instance = module;
67 $module
68 .data(moduleNamespace, module)
69 ;
70 },
71
72 normalize: function () {
73 // keep the function for backward compatibility
74 // eslint-disable-next-line no-useless-return
75 return;
76 },
77
78 fix: {
79 consoleClear: function () {
80 module.debug('Disabling programmatic console clearing');
81 window.console.clear = function () {};
82 },
83 },
84
85 moduleExists: function (name) {
86 return $.fn[name] !== undefined && $.fn[name].settings !== undefined;
87 },
88
89 enabled: {
90 modules: function (modules) {
91 var
92 enabledModules = []
93 ;
94 modules = modules || settings.modules;
95 $.each(modules, function (index, name) {
96 if (module.moduleExists(name)) {
97 enabledModules.push(name);
98 }
99 });
100
101 return enabledModules;
102 },
103 },
104
105 disabled: {
106 modules: function (modules) {
107 var
108 disabledModules = []
109 ;
110 modules = modules || settings.modules;
111 $.each(modules, function (index, name) {
112 if (!module.moduleExists(name)) {
113 disabledModules.push(name);
114 }
115 });
116
117 return disabledModules;
118 },
119 },
120
121 change: {
122 setting: function (setting, value, modules, modifyExisting) {
123 modules = typeof modules === 'string'
124 ? (modules === 'all'
125 ? settings.modules
126 : [modules])
127 : modules || settings.modules;
128 modifyExisting = modifyExisting !== undefined
129 ? modifyExisting
130 : true;
131 $.each(modules, function (index, name) {
132 var
133 namespace = module.moduleExists(name)
134 ? $.fn[name].settings.namespace || false
135 : true,
136 $existingModules
137 ;
138 if (module.moduleExists(name)) {
139 module.verbose('Changing default setting', setting, value, name);
140 $.fn[name].settings[setting] = value;
141 if (modifyExisting && namespace) {
142 $existingModules = $(':data(module-' + namespace + ')');
143 if ($existingModules.length > 0) {
144 module.verbose('Modifying existing settings', $existingModules);
145 $existingModules[name]('setting', setting, value);
146 }
147 }
148 }
149 });
150 },
151 settings: function (newSettings, modules, modifyExisting) {
152 modules = typeof modules === 'string'
153 ? [modules]
154 : modules || settings.modules;
155 modifyExisting = modifyExisting !== undefined
156 ? modifyExisting
157 : true;
158 $.each(modules, function (index, name) {
159 var
160 $existingModules
161 ;
162 if (module.moduleExists(name)) {
163 module.verbose('Changing default setting', newSettings, name);
164 $.extend(true, $.fn[name].settings, newSettings);
165 if (modifyExisting && namespace) {
166 $existingModules = $(':data(module-' + namespace + ')');
167 if ($existingModules.length > 0) {
168 module.verbose('Modifying existing settings', $existingModules);
169 $existingModules[name]('setting', newSettings);
170 }
171 }
172 }
173 });
174 },
175 },
176
177 enable: {
178 console: function () {
179 module.console(true);
180 },
181 debug: function (modules, modifyExisting) {
182 modules = modules || settings.modules;
183 module.debug('Enabling debug for modules', modules);
184 module.change.setting('debug', true, modules, modifyExisting);
185 },
186 verbose: function (modules, modifyExisting) {
187 modules = modules || settings.modules;
188 module.debug('Enabling verbose debug for modules', modules);
189 module.change.setting('verbose', true, modules, modifyExisting);
190 },
191 },
192 disable: {
193 console: function () {
194 module.console(false);
195 },
196 debug: function (modules, modifyExisting) {
197 modules = modules || settings.modules;
198 module.debug('Disabling debug for modules', modules);
199 module.change.setting('debug', false, modules, modifyExisting);
200 },
201 verbose: function (modules, modifyExisting) {
202 modules = modules || settings.modules;
203 module.debug('Disabling verbose debug for modules', modules);
204 module.change.setting('verbose', false, modules, modifyExisting);
205 },
206 },
207
208 console: function (enable) {
209 if (enable) {
210 if (instance.cache.console === undefined) {
211 module.error(error.console);
212
213 return;
214 }
215 module.debug('Restoring console function');
216 window.console = instance.cache.console;
217 } else {
218 module.debug('Disabling console function');
219 instance.cache.console = window.console;
220 window.console = {
221 clear: function () {},
222 error: function () {},
223 group: function () {},
224 groupCollapsed: function () {},
225 groupEnd: function () {},
226 info: function () {},
227 log: function () {},
228 table: function () {},
229 warn: function () {},
230 };
231 }
232 },
233
234 destroy: function () {
235 module.verbose('Destroying previous site for', $module);
236 $module
237 .removeData(moduleNamespace)
238 ;
239 },
240
241 cache: {},
242
243 setting: function (name, value) {
244 if ($.isPlainObject(name)) {
245 $.extend(true, settings, name);
246 } else if (value !== undefined) {
247 settings[name] = value;
248 } else {
249 return settings[name];
250 }
251 },
252 internal: function (name, value) {
253 if ($.isPlainObject(name)) {
254 $.extend(true, module, name);
255 } else if (value !== undefined) {
256 module[name] = value;
257 } else {
258 return module[name];
259 }
260 },
261 debug: function () {
262 if (settings.debug) {
263 if (settings.performance) {
264 module.performance.log(arguments);
265 } else {
266 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
267 module.debug.apply(console, arguments);
268 }
269 }
270 },
271 verbose: function () {
272 if (settings.verbose && settings.debug) {
273 if (settings.performance) {
274 module.performance.log(arguments);
275 } else {
276 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
277 module.verbose.apply(console, arguments);
278 }
279 }
280 },
281 error: function () {
282 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
283 module.error.apply(console, arguments);
284 },
285 performance: {
286 log: function (message) {
287 var
288 currentTime,
289 executionTime,
290 previousTime
291 ;
292 if (settings.performance) {
293 currentTime = Date.now();
294 previousTime = time || currentTime;
295 executionTime = currentTime - previousTime;
296 time = currentTime;
297 performance.push({
298 Element: element,
299 Name: message[0],
300 Arguments: [].slice.call(message, 1) || '',
301 'Execution Time': executionTime,
302 });
303 }
304 clearTimeout(module.performance.timer);
305 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
306 },
307 display: function () {
308 var
309 title = settings.name + ':',
310 totalTime = 0
311 ;
312 time = false;
313 clearTimeout(module.performance.timer);
314 $.each(performance, function (index, data) {
315 totalTime += data['Execution Time'];
316 });
317 title += ' ' + totalTime + 'ms';
318 if (performance.length > 0) {
319 console.groupCollapsed(title);
320 if (console.table) {
321 console.table(performance);
322 } else {
323 $.each(performance, function (index, data) {
324 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
325 });
326 }
327 console.groupEnd();
328 }
329 performance = [];
330 },
331 },
332 invoke: function (query, passedArguments, context) {
333 var
334 object = instance,
335 maxDepth,
336 found,
337 response
338 ;
339 passedArguments = passedArguments || queryArguments;
340 context = context || element;
341 if (typeof query === 'string' && object !== undefined) {
342 query = query.split(/[ .]/);
343 maxDepth = query.length - 1;
344 $.each(query, function (depth, value) {
345 var camelCaseValue = depth !== maxDepth
346 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
347 : query
348 ;
349 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
350 object = object[camelCaseValue];
351 } else if (object[camelCaseValue] !== undefined) {
352 found = object[camelCaseValue];
353
354 return false;
355 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
356 object = object[value];
357 } else if (object[value] !== undefined) {
358 found = object[value];
359
360 return false;
361 } else {
362 module.error(error.method, query);
363
364 return false;
365 }
366 });
367 }
368 if (isFunction(found)) {
369 response = found.apply(context, passedArguments);
370 } else if (found !== undefined) {
371 response = found;
372 }
373 if (Array.isArray(returnedValue)) {
374 returnedValue.push(response);
375 } else if (returnedValue !== undefined) {
376 returnedValue = [returnedValue, response];
377 } else if (response !== undefined) {
378 returnedValue = response;
379 }
380
381 return found;
382 },
383 };
384
385 if (methodInvoked) {
386 if (instance === undefined) {
387 module.initialize();
388 }
389 module.invoke(query);
390 } else {
391 if (instance !== undefined) {
392 module.destroy();
393 }
394 module.initialize();
395 }
396
397 return returnedValue !== undefined
398 ? returnedValue
399 : this;
400 };
401 $.site = $.fn.site;
402
403 $.site.settings = {
404
405 name: 'Site',
406 namespace: 'site',
407
408 error: {
409 console: 'Console cannot be restored, most likely it was overwritten outside of module',
410 method: 'The method you called is not defined.',
411 },
412
413 debug: false,
414 verbose: false,
415 performance: true,
416
417 modules: [
418 'accordion',
419 'api',
420 'calendar',
421 'checkbox',
422 'dimmer',
423 'dropdown',
424 'embed',
425 'flyout',
426 'form',
427 'modal',
428 'nag',
429 'popup',
430 'progress',
431 'rating',
432 'search',
433 'shape',
434 'sidebar',
435 'slider',
436 'state',
437 'sticky',
438 'tab',
439 'toast',
440 'transition',
441 'visibility',
442 ],
443
444 siteNamespace: 'site',
445 namespaceStub: {
446 cache: {},
447 config: {},
448 sections: {},
449 section: {},
450 utilities: {},
451 },
452
453 };
454
455 // allows for selection of elements with data attributes
456 $.extend($.expr.pseudos, {
457 data: $.expr.createPseudo(function (dataName) {
458 return function (elem) {
459 return !!$.data(elem, dataName);
460 };
461 }),
462 });
463})(jQuery, window, document);
464
465/*!
466 * # Fomantic-UI 2.9.3 - Form Validation
467 * https://github.com/fomantic/Fomantic-UI/
468 *
469 *
470 * Released under the MIT license
471 * https://opensource.org/licenses/MIT
472 *
473 */
474
475(function ($, window, document) {
476 'use strict';
477
478 function isFunction(obj) {
479 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
480 }
481
482 window = window !== undefined && window.Math === Math
483 ? window
484 : globalThis;
485
486 $.fn.form = function (parameters) {
487 var
488 $allModules = $(this),
489 $window = $(window),
490
491 time = Date.now(),
492 performance = [],
493
494 query = arguments[0],
495 methodInvoked = typeof query === 'string',
496 queryArguments = [].slice.call(arguments, 1),
497 returnedValue
498 ;
499 $allModules.each(function () {
500 var
501 $module = $(this),
502 element = this,
503
504 formErrors = [],
505 keyHeldDown = false,
506
507 // set at run-time
508 $field,
509 $group,
510 $message,
511 $prompt,
512 $submit,
513 $clear,
514 $reset,
515
516 settings,
517 validation,
518
519 metadata,
520 selector,
521 className,
522 regExp,
523 error,
524
525 namespace,
526 moduleNamespace,
527 eventNamespace,
528 attachEventsSelector,
529 attachEventsAction,
530
531 submitting = false,
532 dirty = false,
533 history = ['clean', 'clean'],
534
535 instance,
536 module
537 ;
538
539 module = {
540
541 initialize: function () {
542 // settings grabbed at run time
543 module.get.settings();
544 $module.addClass(className.initial);
545 if (methodInvoked) {
546 if (instance === undefined) {
547 module.instantiate();
548 }
549 module.invoke(query);
550 } else {
551 if (instance !== undefined) {
552 instance.invoke('destroy');
553 module.refresh();
554 }
555 module.verbose('Initializing form validation', $module, settings);
556 module.bindEvents();
557 module.set.defaults();
558 if (settings.autoCheckRequired) {
559 module.set.autoCheck();
560 }
561 module.instantiate();
562 }
563 },
564
565 instantiate: function () {
566 module.verbose('Storing instance of module', module);
567 instance = module;
568 $module
569 .data(moduleNamespace, module)
570 ;
571 },
572
573 destroy: function () {
574 module.verbose('Destroying previous module', instance);
575 module.removeEvents();
576 $module
577 .removeData(moduleNamespace)
578 ;
579 },
580
581 refresh: function () {
582 module.verbose('Refreshing selector cache');
583 $field = $module.find(selector.field);
584 $group = $module.find(selector.group);
585 $message = $module.find(selector.message);
586 $prompt = $module.find(selector.prompt);
587
588 $submit = $module.find(selector.submit);
589 $clear = $module.find(selector.clear);
590 $reset = $module.find(selector.reset);
591 },
592
593 refreshEvents: function () {
594 module.removeEvents();
595 module.bindEvents();
596 },
597
598 submit: function (event) {
599 module.verbose('Submitting form', $module);
600 submitting = true;
601 $module.trigger('submit');
602 if (event) {
603 event.preventDefault();
604 }
605 },
606
607 attachEvents: function (selector, action) {
608 if (!action) {
609 action = 'submit';
610 }
611
612 $(selector).on('click' + eventNamespace, function (event) {
613 module[action]();
614 event.preventDefault();
615 });
616
617 attachEventsSelector = selector;
618 attachEventsAction = action;
619 },
620
621 bindEvents: function () {
622 module.verbose('Attaching form events');
623 $module
624 .on('submit' + eventNamespace, module.validate.form)
625 .on('blur' + eventNamespace, selector.field, module.event.field.blur)
626 .on('click' + eventNamespace, selector.submit, module.submit)
627 .on('click' + eventNamespace, selector.reset, module.reset)
628 .on('click' + eventNamespace, selector.clear, module.clear)
629 ;
630 $field.on('invalid' + eventNamespace, module.event.field.invalid);
631 if (settings.keyboardShortcuts) {
632 $module.on('keydown' + eventNamespace, selector.field, module.event.field.keydown);
633 }
634 $field.each(function (index, el) {
635 var
636 $input = $(el),
637 type = $input.prop('type'),
638 inputEvent = module.get.changeEvent(type, $input)
639 ;
640 $input.on(inputEvent + eventNamespace, module.event.field.change);
641 });
642
643 // Dirty events
644 if (settings.preventLeaving) {
645 $window.on('beforeunload' + eventNamespace, module.event.beforeUnload);
646 }
647
648 $field.on('change' + eventNamespace
649 + ' click' + eventNamespace
650 + ' keyup' + eventNamespace
651 + ' keydown' + eventNamespace
652 + ' blur' + eventNamespace, function (e) {
653 module.determine.isDirty();
654 });
655
656 $module.on('dirty' + eventNamespace, function (e) {
657 settings.onDirty.call();
658 });
659
660 $module.on('clean' + eventNamespace, function (e) {
661 settings.onClean.call();
662 });
663 if (attachEventsSelector) {
664 module.attachEvents(attachEventsSelector, attachEventsAction);
665 }
666 },
667
668 clear: function () {
669 $field.each(function (index, el) {
670 var
671 $field = $(el),
672 $element = $field.parent(),
673 $fieldGroup = $field.closest($group),
674 $prompt = $fieldGroup.find(selector.prompt),
675 $calendar = $field.closest(selector.uiCalendar),
676 defaultValue = $field.data(metadata.defaultValue) || '',
677 isCheckbox = $field.is(selector.checkbox),
678 isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
679 isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
680 isErrored = $fieldGroup.hasClass(className.error)
681 ;
682 if (isErrored) {
683 module.verbose('Resetting error on field', $fieldGroup);
684 $fieldGroup.removeClass(className.error);
685 $prompt.remove();
686 }
687 if (isDropdown) {
688 module.verbose('Resetting dropdown value', $element, defaultValue);
689 $element.dropdown('clear', true);
690 } else if (isCheckbox) {
691 $field.prop('checked', false);
692 } else if (isCalendar) {
693 $calendar.calendar('clear');
694 } else {
695 module.verbose('Resetting field value', $field, defaultValue);
696 $field.val('');
697 }
698 });
699 module.remove.states();
700 },
701
702 reset: function () {
703 $field.each(function (index, el) {
704 var
705 $field = $(el),
706 $element = $field.parent(),
707 $fieldGroup = $field.closest($group),
708 $calendar = $field.closest(selector.uiCalendar),
709 $prompt = $fieldGroup.find(selector.prompt),
710 defaultValue = $field.data(metadata.defaultValue),
711 isCheckbox = $field.is(selector.checkbox),
712 isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
713 isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
714 isFile = $field.is(selector.file),
715 isErrored = $fieldGroup.hasClass(className.error)
716 ;
717 if (defaultValue === undefined) {
718 return;
719 }
720 if (isErrored) {
721 module.verbose('Resetting error on field', $fieldGroup);
722 $fieldGroup.removeClass(className.error);
723 $prompt.remove();
724 }
725 if (isDropdown) {
726 module.verbose('Resetting dropdown value', $element, defaultValue);
727 $element.dropdown('restore defaults', true);
728 } else if (isCheckbox) {
729 module.verbose('Resetting checkbox value', $field, defaultValue);
730 $field.prop('checked', defaultValue);
731 } else if (isCalendar) {
732 $calendar.calendar('set date', defaultValue);
733 } else {
734 module.verbose('Resetting field value', $field, defaultValue);
735 $field.val(isFile ? '' : defaultValue);
736 }
737 });
738 module.remove.states();
739 },
740
741 determine: {
742 isValid: function () {
743 var
744 allValid = true
745 ;
746 $field.each(function (index, el) {
747 var $el = $(el),
748 validation = module.get.validation($el) || {},
749 identifier = module.get.identifier(validation, $el)
750 ;
751 if (!module.validate.field(validation, identifier, true)) {
752 allValid = false;
753 }
754 });
755
756 return allValid;
757 },
758 isDirty: function (e) {
759 var formIsDirty = false;
760
761 $field.each(function (index, el) {
762 var
763 $el = $(el),
764 isCheckbox = $el.filter(selector.checkbox).length > 0,
765 isDirty
766 ;
767
768 isDirty = isCheckbox
769 ? module.is.checkboxDirty($el)
770 : module.is.fieldDirty($el);
771
772 $el.data(settings.metadata.isDirty, isDirty);
773
774 formIsDirty = formIsDirty || isDirty;
775 });
776
777 if (formIsDirty) {
778 module.set.dirty();
779 } else {
780 module.set.clean();
781 }
782 },
783 },
784
785 is: {
786 bracketedRule: function (rule) {
787 return rule.type && rule.type.match(settings.regExp.bracket);
788 },
789 // duck type rule test
790 shorthandRules: function (rules) {
791 return typeof rules === 'string' || Array.isArray(rules);
792 },
793 empty: function ($field) {
794 if (!$field || $field.length === 0) {
795 return true;
796 }
797 if ($field.is(selector.checkbox)) {
798 return !$field.is(':checked');
799 }
800
801 return module.is.blank($field);
802 },
803 blank: function ($field) {
804 return String($field.val()).trim() === '';
805 },
806 valid: function (field, showErrors) {
807 var
808 allValid = true
809 ;
810 if (field) {
811 module.verbose('Checking if field is valid', field);
812
813 return module.validate.field(validation[field], field, !!showErrors);
814 }
815
816 module.verbose('Checking if form is valid');
817 $.each(validation, function (fieldName, field) {
818 if (!module.is.valid(fieldName, showErrors)) {
819 allValid = false;
820 }
821 });
822
823 return allValid;
824 },
825 dirty: function () {
826 return dirty;
827 },
828 clean: function () {
829 return !dirty;
830 },
831 fieldDirty: function ($el) {
832 var initialValue = $el.data(metadata.defaultValue);
833 // Explicitly check for undefined/null here as value may be `false`, so ($el.data(dataInitialValue) || '') would not work
834 if (initialValue === undefined || initialValue === null) {
835 initialValue = '';
836 } else if (Array.isArray(initialValue)) {
837 initialValue = initialValue.toString();
838 }
839 var currentValue = $el.val();
840 if (currentValue === undefined || currentValue === null) {
841 currentValue = '';
842 } else if (Array.isArray(currentValue)) {
843 // multiple select values are returned as arrays which are never equal, so do string conversion first
844 currentValue = currentValue.toString();
845 }
846 // Boolean values can be encoded as "true/false" or "True/False" depending on underlying frameworks so we need a case insensitive comparison
847 var boolRegex = /^(true|false)$/i;
848 var isBoolValue = boolRegex.test(initialValue) && boolRegex.test(currentValue);
849 if (isBoolValue) {
850 var regex = new RegExp('^' + initialValue + '$', 'i');
851
852 return !regex.test(currentValue);
853 }
854
855 return currentValue !== initialValue;
856 },
857 checkboxDirty: function ($el) {
858 var initialValue = $el.data(metadata.defaultValue);
859 var currentValue = $el.is(':checked');
860
861 return initialValue !== currentValue;
862 },
863 justDirty: function () {
864 return history[0] === 'dirty';
865 },
866 justClean: function () {
867 return history[0] === 'clean';
868 },
869 },
870
871 removeEvents: function () {
872 $module.off(eventNamespace);
873 $field.off(eventNamespace);
874 $submit.off(eventNamespace);
875 if (settings.preventLeaving) {
876 $window.off(eventNamespace);
877 }
878 if (attachEventsSelector) {
879 $(attachEventsSelector).off(eventNamespace);
880 attachEventsSelector = undefined;
881 }
882 },
883
884 event: {
885 field: {
886 keydown: function (event) {
887 var
888 $field = $(this),
889 key = event.which,
890 isInput = $field.is(selector.input),
891 isCheckbox = $field.is(selector.checkbox),
892 isInDropdown = $field.closest(selector.uiDropdown).length > 0,
893 keyCode = {
894 enter: 13,
895 escape: 27,
896 }
897 ;
898 if (key === keyCode.escape) {
899 module.verbose('Escape key pressed blurring field');
900 $field[0]
901 .blur()
902 ;
903 }
904 if (!event.ctrlKey && key === keyCode.enter && isInput && !isInDropdown && !isCheckbox) {
905 if (!keyHeldDown) {
906 $field.one('keyup' + eventNamespace, module.event.field.keyup);
907 module.submit(event);
908 module.debug('Enter pressed on input submitting form');
909 }
910 keyHeldDown = true;
911 }
912 },
913 keyup: function () {
914 keyHeldDown = false;
915 },
916 invalid: function (event) {
917 event.preventDefault();
918 },
919 blur: function (event) {
920 var
921 $field = $(this),
922 validationRules = module.get.validation($field) || {},
923 identifier = module.get.identifier(validationRules, $field)
924 ;
925 if (settings.on === 'blur' || (!$module.hasClass(className.initial) && settings.revalidate)) {
926 module.debug('Revalidating field', $field, validationRules);
927 module.validate.field(validationRules, identifier);
928 if (!settings.inline) {
929 module.validate.form(false, true);
930 }
931 }
932 },
933 change: function (event) {
934 var
935 $field = $(this),
936 validationRules = module.get.validation($field) || {},
937 identifier = module.get.identifier(validationRules, $field)
938 ;
939 if (settings.on === 'change' || (!$module.hasClass(className.initial) && settings.revalidate)) {
940 clearTimeout(module.timer);
941 module.timer = setTimeout(function () {
942 module.debug('Revalidating field', $field, validationRules);
943 module.validate.field(validationRules, identifier);
944 if (!settings.inline) {
945 module.validate.form(false, true);
946 }
947 }, settings.delay);
948 }
949 },
950 },
951 beforeUnload: function (event) {
952 if (module.is.dirty() && !submitting) {
953 event = event || window.event;
954
955 // For modern browsers
956 if (event) {
957 event.returnValue = settings.text.leavingMessage;
958 }
959
960 // For olders...
961 return settings.text.leavingMessage;
962 }
963 },
964
965 },
966
967 get: {
968 ancillaryValue: function (rule) {
969 if (!rule.type || (!rule.value && !module.is.bracketedRule(rule))) {
970 return false;
971 }
972
973 return rule.value !== undefined
974 ? rule.value
975 : rule.type.match(settings.regExp.bracket)[1] + '';
976 },
977 ruleName: function (rule) {
978 if (module.is.bracketedRule(rule)) {
979 return rule.type.replace(rule.type.match(settings.regExp.bracket)[0], '');
980 }
981
982 return rule.type;
983 },
984 changeEvent: function (type, $input) {
985 return ['file', 'checkbox', 'radio', 'hidden'].indexOf(type) >= 0 || $input.is('select') ? 'change' : 'input';
986 },
987 fieldsFromShorthand: function (fields) {
988 var
989 fullFields = {}
990 ;
991 $.each(fields, function (name, rules) {
992 if (!Array.isArray(rules) && typeof rules === 'object') {
993 fullFields[name] = rules;
994 } else {
995 if (typeof rules === 'string') {
996 rules = [rules];
997 }
998 fullFields[name] = {
999 rules: [],
1000 };
1001 $.each(rules, function (index, rule) {
1002 fullFields[name].rules.push({ type: rule });
1003 });
1004 }
1005 });
1006
1007 return fullFields;
1008 },
1009 identifier: function (validation, $el) {
1010 return validation.identifier || $el.attr('id') || $el.attr('name') || $el.data(metadata.validate);
1011 },
1012 prompt: function (rule, field) {
1013 var
1014 ruleName = module.get.ruleName(rule),
1015 ancillary = module.get.ancillaryValue(rule),
1016 $field = module.get.field(field.identifier),
1017 value = $field.val(),
1018 prompt = isFunction(rule.prompt)
1019 ? rule.prompt(value)
1020 : rule.prompt || settings.prompt[ruleName] || settings.text.unspecifiedRule,
1021 requiresValue = prompt.search('{value}') !== -1,
1022 requiresName = prompt.search('{name}') !== -1,
1023 parts,
1024 suffixPrompt
1025 ;
1026 if (ancillary && ['integer', 'decimal', 'number', 'size'].indexOf(ruleName) >= 0 && ancillary.indexOf('..') >= 0) {
1027 parts = ancillary.split('..', 2);
1028 if (!rule.prompt && ruleName !== 'size') {
1029 suffixPrompt = parts[0] === ''
1030 ? settings.prompt.maxValue.replace(/{ruleValue}/g, '{max}')
1031 : (parts[1] === ''
1032 ? settings.prompt.minValue.replace(/{ruleValue}/g, '{min}')
1033 : settings.prompt.range);
1034 prompt += suffixPrompt.replace(/{name}/g, ' ' + settings.text.and);
1035 }
1036 prompt = prompt.replace(/{min}/g, parts[0]);
1037 prompt = prompt.replace(/{max}/g, parts[1]);
1038 }
1039 if (ancillary && ['match', 'different'].indexOf(ruleName) >= 0) {
1040 prompt = prompt.replace(/{ruleValue}/g, module.get.fieldLabel(ancillary, true));
1041 }
1042 if (requiresValue) {
1043 prompt = prompt.replace(/{value}/g, $field.val());
1044 }
1045 if (requiresName) {
1046 prompt = prompt.replace(/{name}/g, module.get.fieldLabel($field));
1047 }
1048 prompt = prompt.replace(/{identifier}/g, field.identifier);
1049 prompt = prompt.replace(/{ruleValue}/g, ancillary);
1050 if (!rule.prompt) {
1051 module.verbose('Using default validation prompt for type', prompt, ruleName);
1052 }
1053
1054 return prompt;
1055 },
1056 settings: function () {
1057 if ($.isPlainObject(parameters)) {
1058 if (parameters.fields) {
1059 parameters.fields = module.get.fieldsFromShorthand(parameters.fields);
1060 }
1061 settings = $.extend(true, {}, $.fn.form.settings, parameters);
1062 validation = $.extend(true, {}, $.fn.form.settings.defaults, settings.fields);
1063 module.verbose('Extending settings', validation, settings);
1064 } else {
1065 settings = $.extend(true, {}, $.fn.form.settings);
1066 validation = $.extend(true, {}, $.fn.form.settings.defaults);
1067 module.verbose('Using default form validation', validation, settings);
1068 }
1069
1070 // shorthand
1071 namespace = settings.namespace;
1072 metadata = settings.metadata;
1073 selector = settings.selector;
1074 className = settings.className;
1075 regExp = settings.regExp;
1076 error = settings.error;
1077 moduleNamespace = 'module-' + namespace;
1078 eventNamespace = '.' + namespace;
1079
1080 // grab instance
1081 instance = $module.data(moduleNamespace);
1082
1083 // refresh selector cache
1084 (instance || module).refresh();
1085 },
1086 field: function (identifier, strict) {
1087 module.verbose('Finding field with identifier', identifier);
1088 identifier = module.escape.string(identifier);
1089 var t;
1090 t = $field.filter('#' + identifier);
1091 if (t.length > 0) {
1092 return t;
1093 }
1094 t = $field.filter('[name="' + identifier + '"]');
1095 if (t.length > 0) {
1096 return t;
1097 }
1098 t = $field.filter('[name="' + identifier + '[]"]');
1099 if (t.length > 0) {
1100 return t;
1101 }
1102 t = $field.filter('[data-' + metadata.validate + '="' + identifier + '"]');
1103 if (t.length > 0) {
1104 return t;
1105 }
1106 module.error(error.noField.replace('{identifier}', identifier));
1107
1108 return strict ? $() : $('<input/>');
1109 },
1110 fields: function (fields, strict) {
1111 var
1112 $fields = $()
1113 ;
1114 $.each(fields, function (index, name) {
1115 $fields = $fields.add(module.get.field(name, strict));
1116 });
1117
1118 return $fields;
1119 },
1120 fieldLabel: function (identifier, useIdAsFallback) {
1121 var $field = typeof identifier === 'string'
1122 ? module.get.field(identifier)
1123 : identifier,
1124 $label = $field.closest(selector.group).find('label:not(:empty)').eq(0)
1125 ;
1126
1127 return $label.length === 1
1128 ? $label.text()
1129 : $field.prop('placeholder') || (useIdAsFallback ? identifier : settings.text.unspecifiedField);
1130 },
1131 validation: function ($field) {
1132 var
1133 fieldValidation,
1134 identifier
1135 ;
1136 if (!validation) {
1137 return false;
1138 }
1139 $.each(validation, function (fieldName, field) {
1140 identifier = field.identifier || fieldName;
1141 $.each(module.get.field(identifier), function (index, groupField) {
1142 if (groupField == $field[0]) {
1143 field.identifier = identifier;
1144 fieldValidation = field;
1145
1146 return false;
1147 }
1148 });
1149 });
1150
1151 return fieldValidation || false;
1152 },
1153 value: function (field, strict) {
1154 var
1155 fields = [],
1156 results,
1157 resultKeys
1158 ;
1159 fields.push(field);
1160 results = module.get.values.call(element, fields, strict);
1161 resultKeys = Object.keys(results);
1162
1163 return resultKeys.length > 0 ? results[resultKeys[0]] : undefined;
1164 },
1165 values: function (fields, strict) {
1166 var
1167 $fields = Array.isArray(fields) && fields.length > 0
1168 ? module.get.fields(fields, strict)
1169 : $field,
1170 values = {}
1171 ;
1172 $fields.each(function (index, field) {
1173 var
1174 $field = $(field),
1175 $calendar = $field.closest(selector.uiCalendar),
1176 name = $field.prop('name'),
1177 value = $field.val(),
1178 isCheckbox = $field.is(selector.checkbox),
1179 isRadio = $field.is(selector.radio),
1180 isMultiple = name.indexOf('[]') !== -1,
1181 isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
1182 isChecked = isCheckbox
1183 ? $field.is(':checked')
1184 : false
1185 ;
1186 if (name) {
1187 if (isMultiple) {
1188 name = name.replace('[]', '');
1189 if (!values[name]) {
1190 values[name] = [];
1191 }
1192 if (isCheckbox) {
1193 if (isChecked) {
1194 values[name].push(value || true);
1195 } else {
1196 values[name].push(false);
1197 }
1198 } else {
1199 values[name].push(value);
1200 }
1201 } else {
1202 if (isRadio) {
1203 if (values[name] === undefined || values[name] === false) {
1204 values[name] = isChecked
1205 ? value || true
1206 : false;
1207 }
1208 } else if (isCheckbox) {
1209 values[name] = isChecked ? value || true : false;
1210 } else if (isCalendar) {
1211 var date = $calendar.calendar('get date');
1212
1213 if (date !== null) {
1214 switch (settings.dateHandling) {
1215 case 'date': {
1216 values[name] = date;
1217
1218 break;
1219 }
1220 case 'input': {
1221 values[name] = $calendar.calendar('get input date');
1222
1223 break;
1224 }
1225 case 'formatter': {
1226 var type = $calendar.calendar('setting', 'type');
1227
1228 switch (type) {
1229 case 'date': {
1230 values[name] = settings.formatter.date(date);
1231
1232 break;
1233 }
1234 case 'datetime': {
1235 values[name] = settings.formatter.datetime(date);
1236
1237 break;
1238 }
1239 case 'time': {
1240 values[name] = settings.formatter.time(date);
1241
1242 break;
1243 }
1244 case 'month': {
1245 values[name] = settings.formatter.month(date);
1246
1247 break;
1248 }
1249 case 'year': {
1250 values[name] = settings.formatter.year(date);
1251
1252 break;
1253 }
1254 default: {
1255 module.debug('Wrong calendar mode', $calendar, type);
1256 values[name] = '';
1257 }
1258 }
1259
1260 break;
1261 }
1262 }
1263 } else {
1264 values[name] = '';
1265 }
1266 } else {
1267 values[name] = value;
1268 }
1269 }
1270 }
1271 });
1272
1273 return values;
1274 },
1275 dirtyFields: function () {
1276 return $field.filter(function (index, e) {
1277 return $(e).data(metadata.isDirty);
1278 });
1279 },
1280 },
1281
1282 has: {
1283
1284 field: function (identifier) {
1285 module.verbose('Checking for existence of a field with identifier', identifier);
1286
1287 return module.get.field(identifier, true).length > 0;
1288 },
1289
1290 },
1291
1292 can: {
1293 useElement: function (element) {
1294 if ($.fn[element] !== undefined) {
1295 return true;
1296 }
1297 module.error(error.noElement.replace('{element}', element));
1298
1299 return false;
1300 },
1301 },
1302
1303 escape: {
1304 string: function (text) {
1305 text = String(text);
1306
1307 return text.replace(regExp.escape, '\\$&');
1308 },
1309 },
1310
1311 checkErrors: function (errors, internal) {
1312 if (!errors || errors.length === 0) {
1313 if (!internal) {
1314 module.error(settings.error.noErrorMessage);
1315 }
1316
1317 return false;
1318 }
1319 if (!internal) {
1320 errors = typeof errors === 'string'
1321 ? [errors]
1322 : errors;
1323 }
1324
1325 return errors;
1326 },
1327 add: {
1328 // alias
1329 rule: function (name, rules) {
1330 module.add.field(name, rules);
1331 },
1332 field: function (name, rules) {
1333 // Validation should have at least a standard format
1334 if (validation[name] === undefined || validation[name].rules === undefined) {
1335 validation[name] = {
1336 rules: [],
1337 };
1338 }
1339 var
1340 newValidation = {
1341 rules: [],
1342 }
1343 ;
1344 if (module.is.shorthandRules(rules)) {
1345 rules = Array.isArray(rules)
1346 ? rules
1347 : [rules];
1348 $.each(rules, function (_index, rule) {
1349 newValidation.rules.push({ type: rule });
1350 });
1351 } else {
1352 newValidation.rules = rules.rules;
1353 }
1354 // For each new rule, check if there's not already one with the same type
1355 $.each(newValidation.rules, function (_index, rule) {
1356 if ($.grep(validation[name].rules, function (item) {
1357 return item.type === rule.type;
1358 }).length === 0) {
1359 validation[name].rules.push(rule);
1360 }
1361 });
1362 module.debug('Adding rules', newValidation.rules, validation);
1363 module.refreshEvents();
1364 },
1365 fields: function (fields) {
1366 validation = $.extend(true, {}, validation, module.get.fieldsFromShorthand(fields));
1367 module.refreshEvents();
1368 },
1369 prompt: function (identifier, errors, internal) {
1370 errors = module.checkErrors(errors);
1371 if (errors === false) {
1372 return;
1373 }
1374 var
1375 $field = module.get.field(identifier),
1376 $fieldGroup = $field.closest($group),
1377 $prompt = $fieldGroup.children(selector.prompt),
1378 promptExists = $prompt.length > 0,
1379 canTransition = settings.transition && module.can.useElement('transition')
1380 ;
1381 module.verbose('Adding field error state', identifier);
1382 if (!internal) {
1383 $fieldGroup
1384 .addClass(className.error)
1385 ;
1386 }
1387 if (settings.inline) {
1388 if (promptExists) {
1389 if (canTransition) {
1390 if ($prompt.transition('is animating')) {
1391 $prompt.transition('stop all');
1392 }
1393 } else if ($prompt.is(':animated')) {
1394 $prompt.stop(true, true);
1395 }
1396 $prompt = $fieldGroup.children(selector.prompt);
1397 promptExists = $prompt.length > 0;
1398 }
1399 if (!promptExists) {
1400 $prompt = $('<div/>').addClass(className.label);
1401 if (!canTransition) {
1402 $prompt.css('display', 'none');
1403 }
1404 $prompt
1405 .appendTo($fieldGroup)
1406 ;
1407 }
1408 $prompt
1409 .html(settings.templates.prompt(errors))
1410 ;
1411 if (!promptExists) {
1412 if (canTransition) {
1413 module.verbose('Displaying error with css transition', settings.transition);
1414 $prompt.transition(settings.transition + ' in', settings.duration);
1415 } else {
1416 module.verbose('Displaying error with fallback javascript animation');
1417 $prompt
1418 .fadeIn(settings.duration)
1419 ;
1420 }
1421 }
1422 } else {
1423 module.verbose('Inline errors are disabled, no inline error added', identifier);
1424 }
1425 },
1426 errors: function (errors) {
1427 errors = module.checkErrors(errors);
1428 if (errors === false) {
1429 return;
1430 }
1431 module.debug('Adding form error messages', errors);
1432 module.set.error();
1433 var customErrors = [],
1434 tempErrors
1435 ;
1436 if ($.isPlainObject(errors)) {
1437 $.each(Object.keys(errors), function (i, id) {
1438 if (module.checkErrors(errors[id], true) !== false) {
1439 if (settings.inline) {
1440 module.add.prompt(id, errors[id]);
1441 } else {
1442 tempErrors = module.checkErrors(errors[id]);
1443 if (tempErrors !== false) {
1444 $.each(tempErrors, function (index, tempError) {
1445 customErrors.push(settings.prompt.addErrors
1446 .replace(/{name}/g, module.get.fieldLabel(id))
1447 .replace(/{error}/g, tempError));
1448 });
1449 }
1450 }
1451 }
1452 });
1453 } else {
1454 customErrors = errors;
1455 }
1456 if (customErrors.length > 0) {
1457 $message
1458 .html(settings.templates.error(customErrors))
1459 ;
1460 }
1461 },
1462 },
1463
1464 remove: {
1465 errors: function () {
1466 module.debug('Removing form error messages');
1467 $message.empty();
1468 },
1469 states: function () {
1470 $module.removeClass(className.error).removeClass(className.success).addClass(className.initial);
1471 if (!settings.inline) {
1472 module.remove.errors();
1473 }
1474 module.determine.isDirty();
1475 },
1476 rule: function (field, rule) {
1477 var
1478 rules = Array.isArray(rule)
1479 ? rule
1480 : [rule]
1481 ;
1482 if (validation[field] === undefined || !Array.isArray(validation[field].rules)) {
1483 return;
1484 }
1485 if (rule === undefined) {
1486 module.debug('Removed all rules');
1487 if (module.has.field(field)) {
1488 validation[field].rules = [];
1489 } else {
1490 delete validation[field];
1491 }
1492
1493 return;
1494 }
1495 $.each(validation[field].rules, function (index, rule) {
1496 if (rule && rules.indexOf(rule.type) !== -1) {
1497 module.debug('Removed rule', rule.type);
1498 validation[field].rules.splice(index, 1);
1499 }
1500 });
1501 },
1502 field: function (field) {
1503 var
1504 fields = Array.isArray(field)
1505 ? field
1506 : [field]
1507 ;
1508 $.each(fields, function (index, field) {
1509 module.remove.rule(field);
1510 });
1511 module.refreshEvents();
1512 },
1513 // alias
1514 rules: function (field, rules) {
1515 if (Array.isArray(field)) {
1516 $.each(field, function (index, field) {
1517 module.remove.rule(field, rules);
1518 });
1519 } else {
1520 module.remove.rule(field, rules);
1521 }
1522 },
1523 fields: function (fields) {
1524 module.remove.field(fields);
1525 },
1526 prompt: function (identifier) {
1527 var
1528 $field = module.get.field(identifier),
1529 $fieldGroup = $field.closest($group),
1530 $prompt = $fieldGroup.children(selector.prompt)
1531 ;
1532 $fieldGroup
1533 .removeClass(className.error)
1534 ;
1535 if (settings.inline && $prompt.is(':visible')) {
1536 module.verbose('Removing prompt for field', identifier);
1537 if (settings.transition && module.can.useElement('transition')) {
1538 $prompt.transition(settings.transition + ' out', settings.duration, function () {
1539 $prompt.remove();
1540 });
1541 } else {
1542 $prompt
1543 .fadeOut(settings.duration, function () {
1544 $prompt.remove();
1545 })
1546 ;
1547 }
1548 }
1549 },
1550 },
1551
1552 set: {
1553 success: function () {
1554 $module
1555 .removeClass(className.error)
1556 .addClass(className.success)
1557 ;
1558 },
1559 defaults: function () {
1560 $field.each(function (index, el) {
1561 var
1562 $el = $(el),
1563 $parent = $el.parent(),
1564 isCheckbox = $el.filter(selector.checkbox).length > 0,
1565 isDropdown = ($parent.is(selector.uiDropdown) || $el.is(selector.uiDropdown)) && module.can.useElement('dropdown'),
1566 $calendar = $el.closest(selector.uiCalendar),
1567 isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
1568 value = isCheckbox
1569 ? $el.is(':checked')
1570 : $el.val()
1571 ;
1572 if (isDropdown) {
1573 if ($parent.is(selector.uiDropdown)) {
1574 $parent.dropdown('save defaults');
1575 } else {
1576 $el.dropdown('save defaults');
1577 }
1578 } else if (isCalendar) {
1579 $calendar.calendar('refresh');
1580 }
1581 $el.data(metadata.defaultValue, value);
1582 $el.data(metadata.isDirty, false);
1583 });
1584 },
1585 error: function () {
1586 $module
1587 .removeClass(className.success)
1588 .addClass(className.error)
1589 ;
1590 },
1591 value: function (field, value) {
1592 var
1593 fields = {}
1594 ;
1595 fields[field] = value;
1596
1597 return module.set.values.call(element, fields);
1598 },
1599 values: function (fields) {
1600 if ($.isEmptyObject(fields)) {
1601 return;
1602 }
1603 $.each(fields, function (key, value) {
1604 var
1605 $field = module.get.field(key),
1606 $element = $field.parent(),
1607 $calendar = $field.closest(selector.uiCalendar),
1608 isFile = $field.is(selector.file),
1609 isMultiple = Array.isArray(value),
1610 isCheckbox = $element.is(selector.uiCheckbox) && module.can.useElement('checkbox'),
1611 isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
1612 isRadio = $field.is(selector.radio) && isCheckbox,
1613 isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
1614 fieldExists = $field.length > 0,
1615 $multipleField
1616 ;
1617 if (fieldExists) {
1618 if (isMultiple && isCheckbox) {
1619 module.verbose('Selecting multiple', value, $field);
1620 $element.checkbox('uncheck');
1621 $.each(value, function (index, value) {
1622 $multipleField = $field.filter('[value="' + value + '"]');
1623 $element = $multipleField.parent();
1624 if ($multipleField.length > 0) {
1625 $element.checkbox('check');
1626 }
1627 });
1628 } else if (isRadio) {
1629 module.verbose('Selecting radio value', value, $field);
1630 $field.filter('[value="' + value + '"]')
1631 .parent(selector.uiCheckbox)
1632 .checkbox('check')
1633 ;
1634 } else if (isCheckbox) {
1635 module.verbose('Setting checkbox value', value, $element);
1636 if (value === true || value === 1 || value === 'on') {
1637 $element.checkbox('check');
1638 } else {
1639 $element.checkbox('uncheck');
1640 }
1641 if (typeof value === 'string') {
1642 $field.val(value);
1643 }
1644 } else if (isDropdown) {
1645 module.verbose('Setting dropdown value', value, $element);
1646 $element.dropdown('set selected', value);
1647 } else if (isCalendar) {
1648 $calendar.calendar('set date', value);
1649 } else {
1650 module.verbose('Setting field value', value, $field);
1651 $field.val(isFile ? '' : value);
1652 }
1653 }
1654 });
1655 },
1656 dirty: function () {
1657 module.verbose('Setting state dirty');
1658 dirty = true;
1659 history[0] = history[1];
1660 history[1] = 'dirty';
1661
1662 if (module.is.justClean()) {
1663 $module.trigger('dirty');
1664 }
1665 },
1666 clean: function () {
1667 module.verbose('Setting state clean');
1668 dirty = false;
1669 history[0] = history[1];
1670 history[1] = 'clean';
1671
1672 if (module.is.justDirty()) {
1673 $module.trigger('clean');
1674 }
1675 },
1676 asClean: function () {
1677 module.set.defaults();
1678 module.set.clean();
1679 },
1680 asDirty: function () {
1681 module.set.defaults();
1682 module.set.dirty();
1683 },
1684 autoCheck: function () {
1685 module.debug('Enabling auto check on required fields');
1686 if (validation) {
1687 $.each(validation, function (fieldName) {
1688 if (!module.has.field(fieldName)) {
1689 module.verbose('Field not found, removing from validation', fieldName);
1690 module.remove.field(fieldName);
1691 }
1692 });
1693 }
1694 $field.each(function (_index, el) {
1695 var
1696 $el = $(el),
1697 $elGroup = $el.closest($group),
1698 isCheckbox = $el.filter(selector.checkbox).length > 0,
1699 isRequired = $el.prop('required') || $elGroup.hasClass(className.required) || $elGroup.parent().hasClass(className.required),
1700 isDisabled = $el.is(':disabled') || $elGroup.hasClass(className.disabled) || $elGroup.parent().hasClass(className.disabled),
1701 validation = module.get.validation($el),
1702 hasEmptyRule = validation
1703 ? $.grep(validation.rules, function (rule) {
1704 return rule.type === 'empty';
1705 }) !== 0
1706 : false,
1707 identifier = module.get.identifier(validation, $el)
1708 ;
1709 if (isRequired && !isDisabled && !hasEmptyRule && identifier !== undefined) {
1710 if (isCheckbox) {
1711 module.verbose("Adding 'checked' rule on field", identifier);
1712 module.add.rule(identifier, 'checked');
1713 } else {
1714 module.verbose("Adding 'empty' rule on field", identifier);
1715 module.add.rule(identifier, 'empty');
1716 }
1717 }
1718 });
1719 },
1720 optional: function (identifier, bool) {
1721 bool = bool !== false;
1722 $.each(validation, function (fieldName, field) {
1723 if (identifier === fieldName || identifier === field.identifier) {
1724 field.optional = bool;
1725 }
1726 });
1727 },
1728 },
1729
1730 validate: {
1731
1732 form: function (event, ignoreCallbacks) {
1733 var values = module.get.values();
1734
1735 // input keydown event will fire submit repeatedly by browser default
1736 if (keyHeldDown) {
1737 return false;
1738 }
1739 $module.removeClass(className.initial);
1740 // reset errors
1741 formErrors = [];
1742 if (module.determine.isValid()) {
1743 module.debug('Form has no validation errors, submitting');
1744 module.set.success();
1745 if (!settings.inline) {
1746 module.remove.errors();
1747 }
1748 if (ignoreCallbacks !== true) {
1749 return settings.onSuccess.call(element, event, values);
1750 }
1751 } else {
1752 module.debug('Form has errors');
1753 submitting = false;
1754 module.set.error();
1755 if (!settings.inline) {
1756 module.add.errors(formErrors);
1757 }
1758 // prevent ajax submit
1759 if (event && $module.data('moduleApi') !== undefined) {
1760 event.stopImmediatePropagation();
1761 }
1762 if (settings.errorFocus && ignoreCallbacks !== true) {
1763 var
1764 $focusElement,
1765 hasTabIndex = true
1766 ;
1767 if (typeof settings.errorFocus === 'string') {
1768 $focusElement = $(document).find(settings.errorFocus);
1769 hasTabIndex = $focusElement.is('[tabindex]');
1770 // to be able to focus/scroll into non input elements we need a tabindex
1771 if (!hasTabIndex) {
1772 $focusElement.attr('tabindex', -1);
1773 }
1774 } else {
1775 $focusElement = $group.filter('.' + className.error).first().find(selector.field);
1776 }
1777 $focusElement.trigger('focus');
1778 // only remove tabindex if it was dynamically created above
1779 if (!hasTabIndex) {
1780 $focusElement.removeAttr('tabindex');
1781 }
1782 }
1783 if (ignoreCallbacks !== true) {
1784 return settings.onFailure.call(element, formErrors, values);
1785 }
1786 }
1787 },
1788
1789 // takes a validation object and returns whether field passes validation
1790 field: function (field, fieldName, showErrors) {
1791 showErrors = showErrors !== undefined
1792 ? showErrors
1793 : true;
1794 if (typeof field === 'string') {
1795 module.verbose('Validating field', field);
1796 fieldName = field;
1797 field = validation[field];
1798 }
1799 if (!field) {
1800 module.debug('Unable to find field validation. Skipping', fieldName);
1801
1802 return true;
1803 }
1804 var
1805 identifier = field.identifier || fieldName,
1806 $field = module.get.field(identifier),
1807 $dependsField = field.depends
1808 ? module.get.field(field.depends)
1809 : false,
1810 fieldValid = true,
1811 fieldErrors = [],
1812 isDisabled = $field.filter(':not(:disabled)').length === 0,
1813 validationMessage = $field[0].validationMessage,
1814 errorLimit
1815 ;
1816 if (!field.identifier) {
1817 module.debug('Using field name as identifier', identifier);
1818 field.identifier = identifier;
1819 }
1820 if (validationMessage) {
1821 module.debug('Field is natively invalid', identifier);
1822 fieldErrors.push(validationMessage);
1823 fieldValid = false;
1824 if (showErrors) {
1825 $field.closest($group).addClass(className.error);
1826 }
1827 } else if (showErrors) {
1828 $field.closest($group).removeClass(className.error);
1829 }
1830 if (isDisabled) {
1831 module.debug('Field is disabled. Skipping', identifier);
1832 } else if (field.optional && module.is.blank($field)) {
1833 module.debug('Field is optional and blank. Skipping', identifier);
1834 } else if (field.depends && module.is.empty($dependsField)) {
1835 module.debug('Field depends on another value that is not present or empty. Skipping', $dependsField);
1836 } else if (field.rules !== undefined) {
1837 errorLimit = field.errorLimit || settings.errorLimit;
1838 $.each(field.rules, function (index, rule) {
1839 if (module.has.field(identifier) && (!errorLimit || fieldErrors.length < errorLimit)) {
1840 var invalidFields = module.validate.rule(field, rule, true) || [];
1841 if (invalidFields.length > 0) {
1842 module.debug('Field is invalid', identifier, rule.type);
1843 fieldErrors.push(module.get.prompt(rule, field));
1844 fieldValid = false;
1845 if (showErrors) {
1846 $(invalidFields).closest($group).addClass(className.error);
1847 }
1848 }
1849 }
1850 });
1851 }
1852 if (fieldValid) {
1853 if (showErrors) {
1854 module.remove.prompt(identifier);
1855 settings.onValid.call($field);
1856 }
1857 } else {
1858 if (showErrors) {
1859 formErrors = formErrors.concat(fieldErrors);
1860 module.add.prompt(identifier, fieldErrors, true);
1861 settings.onInvalid.call($field, fieldErrors);
1862 }
1863
1864 return false;
1865 }
1866
1867 return true;
1868 },
1869
1870 // takes validation rule and returns whether field passes rule
1871 rule: function (field, rule, internal) {
1872 var
1873 $field = module.get.field(field.identifier),
1874 ancillary = module.get.ancillaryValue(rule),
1875 ruleName = module.get.ruleName(rule),
1876 ruleFunction = settings.rules[ruleName],
1877 invalidFields = [],
1878 isCheckbox = $field.is(selector.checkbox),
1879 isValid = function (field) {
1880 var value = isCheckbox ? $(field).filter(':checked').val() : $(field).val();
1881 // cast to string avoiding encoding special values
1882 value = value === undefined || value === '' || value === null
1883 ? ''
1884 : ((settings.shouldTrim && rule.shouldTrim !== false) || rule.shouldTrim
1885 ? String(value + '').trim()
1886 : String(value + ''));
1887
1888 return ruleFunction.call(field, value, ancillary, module);
1889 }
1890 ;
1891 if (!isFunction(ruleFunction)) {
1892 module.error(error.noRule, ruleName);
1893
1894 return;
1895 }
1896 if (isCheckbox) {
1897 if (!isValid($field)) {
1898 invalidFields = $field;
1899 }
1900 } else {
1901 $.each($field, function (index, field) {
1902 if (!isValid(field)) {
1903 invalidFields.push(field);
1904 }
1905 });
1906 }
1907
1908 return internal ? invalidFields : invalidFields.length === 0;
1909 },
1910 },
1911
1912 setting: function (name, value) {
1913 if ($.isPlainObject(name)) {
1914 $.extend(true, settings, name);
1915 } else if (value !== undefined) {
1916 settings[name] = value;
1917 } else {
1918 return settings[name];
1919 }
1920 },
1921 internal: function (name, value) {
1922 if ($.isPlainObject(name)) {
1923 $.extend(true, module, name);
1924 } else if (value !== undefined) {
1925 module[name] = value;
1926 } else {
1927 return module[name];
1928 }
1929 },
1930 debug: function () {
1931 if (!settings.silent && settings.debug) {
1932 if (settings.performance) {
1933 module.performance.log(arguments);
1934 } else {
1935 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
1936 module.debug.apply(console, arguments);
1937 }
1938 }
1939 },
1940 verbose: function () {
1941 if (!settings.silent && settings.verbose && settings.debug) {
1942 if (settings.performance) {
1943 module.performance.log(arguments);
1944 } else {
1945 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
1946 module.verbose.apply(console, arguments);
1947 }
1948 }
1949 },
1950 error: function () {
1951 if (!settings.silent) {
1952 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
1953 module.error.apply(console, arguments);
1954 }
1955 },
1956 performance: {
1957 log: function (message) {
1958 var
1959 currentTime,
1960 executionTime,
1961 previousTime
1962 ;
1963 if (settings.performance) {
1964 currentTime = Date.now();
1965 previousTime = time || currentTime;
1966 executionTime = currentTime - previousTime;
1967 time = currentTime;
1968 performance.push({
1969 Name: message[0],
1970 Arguments: [].slice.call(message, 1) || '',
1971 Element: element,
1972 'Execution Time': executionTime,
1973 });
1974 }
1975 clearTimeout(module.performance.timer);
1976 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
1977 },
1978 display: function () {
1979 var
1980 title = settings.name + ':',
1981 totalTime = 0
1982 ;
1983 time = false;
1984 clearTimeout(module.performance.timer);
1985 $.each(performance, function (index, data) {
1986 totalTime += data['Execution Time'];
1987 });
1988 title += ' ' + totalTime + 'ms';
1989 if ($allModules.length > 1) {
1990 title += ' (' + $allModules.length + ')';
1991 }
1992 if (performance.length > 0) {
1993 console.groupCollapsed(title);
1994 if (console.table) {
1995 console.table(performance);
1996 } else {
1997 $.each(performance, function (index, data) {
1998 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
1999 });
2000 }
2001 console.groupEnd();
2002 }
2003 performance = [];
2004 },
2005 },
2006 invoke: function (query, passedArguments, context) {
2007 var
2008 object = instance,
2009 maxDepth,
2010 found,
2011 response
2012 ;
2013 passedArguments = passedArguments || queryArguments;
2014 context = context || element;
2015 if (typeof query === 'string' && object !== undefined) {
2016 query = query.split(/[ .]/);
2017 maxDepth = query.length - 1;
2018 $.each(query, function (depth, value) {
2019 var camelCaseValue = depth !== maxDepth
2020 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
2021 : query;
2022 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
2023 object = object[camelCaseValue];
2024 } else if (object[camelCaseValue] !== undefined) {
2025 found = object[camelCaseValue];
2026
2027 return false;
2028 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
2029 object = object[value];
2030 } else if (object[value] !== undefined) {
2031 found = object[value];
2032
2033 return false;
2034 } else {
2035 module.error(error.method, query);
2036
2037 return false;
2038 }
2039 });
2040 }
2041 if (isFunction(found)) {
2042 response = found.apply(context, passedArguments);
2043 } else if (found !== undefined) {
2044 response = found;
2045 }
2046 if (Array.isArray(returnedValue)) {
2047 returnedValue.push(response);
2048 } else if (returnedValue !== undefined) {
2049 returnedValue = [returnedValue, response];
2050 } else if (response !== undefined) {
2051 returnedValue = response;
2052 }
2053
2054 return found;
2055 },
2056 };
2057 module.initialize();
2058 });
2059
2060 return returnedValue !== undefined
2061 ? returnedValue
2062 : this;
2063 };
2064
2065 $.fn.form.settings = {
2066
2067 name: 'Form',
2068 namespace: 'form',
2069
2070 debug: false,
2071 verbose: false,
2072 performance: true,
2073
2074 fields: false,
2075
2076 keyboardShortcuts: true,
2077 on: 'submit',
2078 inline: false,
2079
2080 delay: 200,
2081 revalidate: true,
2082 shouldTrim: true,
2083
2084 transition: 'scale',
2085 duration: 200,
2086
2087 autoCheckRequired: false,
2088 preventLeaving: false,
2089 errorFocus: true,
2090 dateHandling: 'date', // 'date', 'input', 'formatter'
2091 errorLimit: 0,
2092
2093 onValid: function () {},
2094 onInvalid: function () {},
2095 onSuccess: function () {
2096 return true;
2097 },
2098 onFailure: function () {
2099 return false;
2100 },
2101 onDirty: function () {},
2102 onClean: function () {},
2103
2104 metadata: {
2105 defaultValue: 'default',
2106 validate: 'validate',
2107 isDirty: 'isDirty',
2108 },
2109
2110 regExp: {
2111 htmlID: /^[A-Za-z][\w.:-]*$/g,
2112 bracket: /\[(.*)]/i,
2113 decimal: /^\d+\.?\d*$/,
2114 email: /^[\w!#$%&'*+./=?^`{|}~-]+@[\da-z]([\da-z-]*[\da-z])?(\.[\da-z]([\da-z-]*[\da-z])?)*$/i,
2115 escape: /[$()*+,./:=?@[\\\]^{|}-]/g,
2116 flags: /^\/(.*)\/(.*)?/,
2117 integer: /^-?\d+$/,
2118 number: /^-?\d*(\.\d+)?$/,
2119 url: /(https?:\/\/(?:www\.|(?!www))[^\s.]+\.\S{2,}|www\.\S+\.\S{2,})/i,
2120 },
2121
2122 text: {
2123 and: 'and',
2124 unspecifiedRule: 'Please enter a valid value',
2125 unspecifiedField: 'This field',
2126 leavingMessage: 'There are unsaved changes on this page which will be discarded if you continue.',
2127 },
2128
2129 prompt: {
2130 range: '{name} must be in a range from {min} to {max}',
2131 maxValue: '{name} must have a maximum value of {ruleValue}',
2132 minValue: '{name} must have a minimum value of {ruleValue}',
2133 empty: '{name} must have a value',
2134 checked: '{name} must be checked',
2135 email: '{name} must be a valid e-mail',
2136 url: '{name} must be a valid url',
2137 regExp: '{name} is not formatted correctly',
2138 integer: '{name} must be an integer',
2139 decimal: '{name} must be a decimal number',
2140 number: '{name} must be set to a number',
2141 is: '{name} must be "{ruleValue}"',
2142 isExactly: '{name} must be exactly "{ruleValue}"',
2143 not: '{name} cannot be set to "{ruleValue}"',
2144 notExactly: '{name} cannot be set to exactly "{ruleValue}"',
2145 contains: '{name} must contain "{ruleValue}"',
2146 containsExactly: '{name} must contain exactly "{ruleValue}"',
2147 doesntContain: '{name} cannot contain "{ruleValue}"',
2148 doesntContainExactly: '{name} cannot contain exactly "{ruleValue}"',
2149 minLength: '{name} must be at least {ruleValue} characters',
2150 exactLength: '{name} must be exactly {ruleValue} characters',
2151 maxLength: '{name} cannot be longer than {ruleValue} characters',
2152 size: '{name} must have a length between {min} and {max} characters',
2153 match: '{name} must match {ruleValue} field',
2154 different: '{name} must have a different value than {ruleValue} field',
2155 creditCard: '{name} must be a valid credit card number',
2156 minCount: '{name} must have at least {ruleValue} choices',
2157 exactCount: '{name} must have exactly {ruleValue} choices',
2158 maxCount: '{name} must have {ruleValue} or less choices',
2159 addErrors: '{name}: {error}',
2160 },
2161
2162 selector: {
2163 checkbox: 'input[type="checkbox"], input[type="radio"]',
2164 clear: '.clear',
2165 field: 'input:not(.search):not([type="reset"]):not([type="button"]):not([type="submit"]), textarea, select',
2166 file: 'input[type="file"]',
2167 group: '.field',
2168 input: 'input',
2169 message: '.error.message',
2170 prompt: '.prompt.label',
2171 radio: 'input[type="radio"]',
2172 reset: '.reset:not([type="reset"])',
2173 submit: '.submit:not([type="submit"])',
2174 uiCheckbox: '.ui.checkbox',
2175 uiDropdown: '.ui.dropdown',
2176 uiCalendar: '.ui.calendar',
2177 },
2178
2179 className: {
2180 initial: 'initial',
2181 error: 'error',
2182 label: 'ui basic red pointing prompt label',
2183 pressed: 'down',
2184 success: 'success',
2185 required: 'required',
2186 disabled: 'disabled',
2187 },
2188
2189 error: {
2190 method: 'The method you called is not defined.',
2191 noRule: 'There is no rule matching the one you specified',
2192 noField: 'Field identifier {identifier} not found',
2193 noElement: 'This module requires ui {element}',
2194 noErrorMessage: 'No error message provided',
2195 },
2196
2197 templates: {
2198
2199 // template that produces error message
2200 error: function (errors) {
2201 var
2202 html = '<ul class="list">'
2203 ;
2204 $.each(errors, function (index, value) {
2205 html += '<li>' + value + '</li>';
2206 });
2207 html += '</ul>';
2208
2209 return html;
2210 },
2211
2212 // template that produces label content
2213 prompt: function (errors) {
2214 if (errors.length === 1) {
2215 return errors[0];
2216 }
2217 var
2218 html = '<ul class="ui list">'
2219 ;
2220 $.each(errors, function (index, value) {
2221 html += '<li>' + value + '</li>';
2222 });
2223 html += '</ul>';
2224
2225 return html;
2226 },
2227 },
2228
2229 formatter: {
2230 date: function (date) {
2231 return Intl.DateTimeFormat('en-GB').format(date);
2232 },
2233 datetime: function (date) {
2234 return Intl.DateTimeFormat('en-GB', {
2235 year: 'numeric',
2236 month: '2-digit',
2237 day: '2-digit',
2238 hour: '2-digit',
2239 minute: '2-digit',
2240 second: '2-digit',
2241 }).format(date);
2242 },
2243 time: function (date) {
2244 return Intl.DateTimeFormat('en-GB', {
2245 hour: '2-digit',
2246 minute: '2-digit',
2247 second: '2-digit',
2248 }).format(date);
2249 },
2250 month: function (date) {
2251 return Intl.DateTimeFormat('en-GB', {
2252 month: '2-digit',
2253 year: 'numeric',
2254 }).format(date);
2255 },
2256 year: function (date) {
2257 return Intl.DateTimeFormat('en-GB', {
2258 year: 'numeric',
2259 }).format(date);
2260 },
2261 },
2262
2263 rules: {
2264
2265 // is not empty or blank string
2266 empty: function (value) {
2267 return !(value === undefined || value === '' || (Array.isArray(value) && value.length === 0));
2268 },
2269
2270 // checkbox checked
2271 checked: function () {
2272 return $(this).filter(':checked').length > 0;
2273 },
2274
2275 // is most likely an email
2276 email: function (value) {
2277 return $.fn.form.settings.regExp.email.test(value);
2278 },
2279
2280 // value is most likely url
2281 url: function (value) {
2282 return $.fn.form.settings.regExp.url.test(value);
2283 },
2284
2285 // matches specified regExp
2286 regExp: function (value, regExp) {
2287 if (regExp instanceof RegExp) {
2288 return value.match(regExp);
2289 }
2290 var
2291 regExpParts = regExp.match($.fn.form.settings.regExp.flags),
2292 flags
2293 ;
2294 // regular expression specified as /baz/gi (flags)
2295 if (regExpParts) {
2296 regExp = regExpParts.length >= 2
2297 ? regExpParts[1]
2298 : regExp;
2299 flags = regExpParts.length >= 3
2300 ? regExpParts[2]
2301 : '';
2302 }
2303
2304 return value.match(new RegExp(regExp, flags));
2305 },
2306 minValue: function (value, range) {
2307 return $.fn.form.settings.rules.range(value, range + '..', 'number');
2308 },
2309 maxValue: function (value, range) {
2310 return $.fn.form.settings.rules.range(value, '..' + range, 'number');
2311 },
2312 // is valid integer or matches range
2313 integer: function (value, range) {
2314 return $.fn.form.settings.rules.range(value, range, 'integer');
2315 },
2316 range: function (value, range, regExp, testLength) {
2317 if (typeof regExp === 'string') {
2318 regExp = $.fn.form.settings.regExp[regExp];
2319 }
2320 if (!(regExp instanceof RegExp)) {
2321 regExp = $.fn.form.settings.regExp.integer;
2322 }
2323 var
2324 min,
2325 max,
2326 parts
2327 ;
2328 if (!range || ['', '..'].indexOf(range) !== -1) {
2329
2330 // do nothing
2331 } else if (range.indexOf('..') === -1) {
2332 if (regExp.test(range)) {
2333 min = range - 0;
2334 max = min;
2335 }
2336 } else {
2337 parts = range.split('..', 2);
2338 if (regExp.test(parts[0])) {
2339 min = parts[0] - 0;
2340 }
2341 if (regExp.test(parts[1])) {
2342 max = parts[1] - 0;
2343 }
2344 }
2345 if (testLength) {
2346 value = value.length;
2347 }
2348
2349 return (
2350 regExp.test(value)
2351 && (min === undefined || value >= min)
2352 && (max === undefined || value <= max)
2353 );
2354 },
2355
2356 // is valid number (with decimal)
2357 decimal: function (value, range) {
2358 return $.fn.form.settings.rules.range(value, range, 'decimal');
2359 },
2360
2361 // is valid number
2362 number: function (value, range) {
2363 return $.fn.form.settings.rules.range(value, range, 'number');
2364 },
2365
2366 // is value (case insensitive)
2367 is: function (value, text) {
2368 text = typeof text === 'string'
2369 ? text.toLowerCase()
2370 : text;
2371 value = typeof value === 'string'
2372 ? value.toLowerCase()
2373 : value;
2374
2375 return value == text;
2376 },
2377
2378 // is value
2379 isExactly: function (value, text) {
2380 return value == text;
2381 },
2382
2383 // value is not another value (case insensitive)
2384 not: function (value, notValue) {
2385 value = typeof value === 'string'
2386 ? value.toLowerCase()
2387 : value;
2388 notValue = typeof notValue === 'string'
2389 ? notValue.toLowerCase()
2390 : notValue;
2391
2392 return value != notValue;
2393 },
2394
2395 // value is not another value (case sensitive)
2396 notExactly: function (value, notValue) {
2397 return value != notValue;
2398 },
2399
2400 // value contains text (insensitive)
2401 contains: function (value, text) {
2402 // escape regex characters
2403 text = text.replace($.fn.form.settings.regExp.escape, '\\$&');
2404
2405 return value.search(new RegExp(text, 'i')) !== -1;
2406 },
2407
2408 // value contains text (case sensitive)
2409 containsExactly: function (value, text) {
2410 // escape regex characters
2411 text = text.replace($.fn.form.settings.regExp.escape, '\\$&');
2412
2413 return value.search(new RegExp(text)) !== -1;
2414 },
2415
2416 // value contains text (insensitive)
2417 doesntContain: function (value, text) {
2418 // escape regex characters
2419 text = text.replace($.fn.form.settings.regExp.escape, '\\$&');
2420
2421 return value.search(new RegExp(text, 'i')) === -1;
2422 },
2423
2424 // value contains text (case sensitive)
2425 doesntContainExactly: function (value, text) {
2426 // escape regex characters
2427 text = text.replace($.fn.form.settings.regExp.escape, '\\$&');
2428
2429 return value.search(new RegExp(text)) === -1;
2430 },
2431
2432 // is at least string length
2433 minLength: function (value, minLength) {
2434 return $.fn.form.settings.rules.range(value, minLength + '..', 'integer', true);
2435 },
2436
2437 // is exactly length
2438 exactLength: function (value, requiredLength) {
2439 return $.fn.form.settings.rules.range(value, requiredLength + '..' + requiredLength, 'integer', true);
2440 },
2441
2442 // is less than length
2443 maxLength: function (value, maxLength) {
2444 return $.fn.form.settings.rules.range(value, '..' + maxLength, 'integer', true);
2445 },
2446
2447 size: function (value, range) {
2448 return $.fn.form.settings.rules.range(value, range, 'integer', true);
2449 },
2450
2451 // matches another field
2452 match: function (value, identifier, module) {
2453 var matchingValue = module.get.value(identifier, true);
2454
2455 return matchingValue !== undefined
2456 ? value.toString() === matchingValue.toString()
2457 : false;
2458 },
2459
2460 // different than another field
2461 different: function (value, identifier, module) {
2462 var matchingValue = module.get.value(identifier, true);
2463
2464 return matchingValue !== undefined
2465 ? value.toString() !== matchingValue.toString()
2466 : false;
2467 },
2468
2469 creditCard: function (cardNumber, cardTypes) {
2470 var
2471 cards = {
2472 visa: {
2473 pattern: /^4/,
2474 length: [16],
2475 },
2476 amex: {
2477 pattern: /^3[47]/,
2478 length: [15],
2479 },
2480 mastercard: {
2481 pattern: /^5[1-5]/,
2482 length: [16],
2483 },
2484 discover: {
2485 pattern: /^(6011|622(12[6-9]|1[3-9]\d|[2-8]\d{2}|9[01]\d|92[0-5]|64[4-9])|65)/,
2486 length: [16],
2487 },
2488 unionPay: {
2489 pattern: /^(62|88)/,
2490 length: [16, 17, 18, 19],
2491 },
2492 jcb: {
2493 pattern: /^35(2[89]|[3-8]\d)/,
2494 length: [16],
2495 },
2496 maestro: {
2497 pattern: /^(5018|5020|5038|6304|6759|676[1-3])/,
2498 length: [12, 13, 14, 15, 16, 17, 18, 19],
2499 },
2500 dinersClub: {
2501 pattern: /^(30[0-5]|^36)/,
2502 length: [14],
2503 },
2504 laser: {
2505 pattern: /^(6304|670[69]|6771)/,
2506 length: [16, 17, 18, 19],
2507 },
2508 visaElectron: {
2509 pattern: /^(4026|417500|4508|4844|491(3|7))/,
2510 length: [16],
2511 },
2512 },
2513 valid = {},
2514 validCard = false,
2515 requiredTypes = typeof cardTypes === 'string'
2516 ? cardTypes.split(',')
2517 : false,
2518 unionPay,
2519 validation
2520 ;
2521
2522 if (typeof cardNumber !== 'string' || cardNumber.length === 0) {
2523 return;
2524 }
2525
2526 // allow dashes and spaces in card
2527 cardNumber = cardNumber.replace(/[\s-]/g, '');
2528
2529 // verify card types
2530 if (requiredTypes) {
2531 $.each(requiredTypes, function (index, type) {
2532 // verify each card type
2533 validation = cards[type];
2534 if (validation) {
2535 valid = {
2536 length: $.inArray(cardNumber.length, validation.length) !== -1,
2537 pattern: cardNumber.search(validation.pattern) !== -1,
2538 };
2539 if (valid.length > 0 && valid.pattern) {
2540 validCard = true;
2541 }
2542 }
2543 });
2544
2545 if (!validCard) {
2546 return false;
2547 }
2548 }
2549
2550 // skip luhn for UnionPay
2551 unionPay = {
2552 number: $.inArray(cardNumber.length, cards.unionPay.length) !== -1,
2553 pattern: cardNumber.search(cards.unionPay.pattern) !== -1,
2554 };
2555 if (unionPay.number && unionPay.pattern) {
2556 return true;
2557 }
2558
2559 // verify luhn, adapted from <https://gist.github.com/2134376>
2560 var
2561 length = cardNumber.length,
2562 multiple = 0,
2563 producedValue = [
2564 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
2565 [0, 2, 4, 6, 8, 1, 3, 5, 7, 9],
2566 ],
2567 sum = 0
2568 ;
2569 while (length--) {
2570 sum += producedValue[multiple][parseInt(cardNumber.charAt(length), 10)];
2571 multiple ^= 1; // eslint-disable-line no-bitwise
2572 }
2573
2574 return sum % 10 === 0 && sum > 0;
2575 },
2576
2577 minCount: function (value, minCount) {
2578 minCount = Number(minCount);
2579
2580 if (minCount === 0) {
2581 return true;
2582 }
2583 if (minCount === 1) {
2584 return value !== '';
2585 }
2586
2587 return value.split(',').length >= minCount;
2588 },
2589
2590 exactCount: function (value, exactCount) {
2591 exactCount = Number(exactCount);
2592
2593 if (exactCount === 0) {
2594 return value === '';
2595 }
2596 if (exactCount === 1) {
2597 return value !== '' && value.search(',') === -1;
2598 }
2599
2600 return value.split(',').length === exactCount;
2601 },
2602
2603 maxCount: function (value, maxCount) {
2604 maxCount = Number(maxCount);
2605
2606 if (maxCount === 0) {
2607 return false;
2608 }
2609 if (maxCount === 1) {
2610 return value.search(',') === -1;
2611 }
2612
2613 return value.split(',').length <= maxCount;
2614 },
2615 },
2616
2617 };
2618})(jQuery, window, document);
2619
2620/*!
2621 * # Fomantic-UI 2.9.3 - Accordion
2622 * https://github.com/fomantic/Fomantic-UI/
2623 *
2624 *
2625 * Released under the MIT license
2626 * https://opensource.org/licenses/MIT
2627 *
2628 */
2629
2630(function ($, window, document) {
2631 'use strict';
2632
2633 function isFunction(obj) {
2634 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
2635 }
2636
2637 window = window !== undefined && window.Math === Math
2638 ? window
2639 : globalThis;
2640
2641 $.fn.accordion = function (parameters) {
2642 var
2643 $allModules = $(this),
2644
2645 time = Date.now(),
2646 performance = [],
2647
2648 query = arguments[0],
2649 methodInvoked = typeof query === 'string',
2650 queryArguments = [].slice.call(arguments, 1),
2651
2652 returnedValue
2653 ;
2654 $allModules.each(function () {
2655 var
2656 settings = $.isPlainObject(parameters)
2657 ? $.extend(true, {}, $.fn.accordion.settings, parameters)
2658 : $.extend({}, $.fn.accordion.settings),
2659
2660 className = settings.className,
2661 namespace = settings.namespace,
2662 selector = settings.selector,
2663 error = settings.error,
2664
2665 eventNamespace = '.' + namespace,
2666 moduleNamespace = 'module-' + namespace,
2667
2668 $module = $(this),
2669 $title = $module.find(selector.title),
2670 $content = $module.find(selector.content),
2671
2672 element = this,
2673 instance = $module.data(moduleNamespace),
2674 observer,
2675 module
2676 ;
2677
2678 module = {
2679
2680 initialize: function () {
2681 module.debug('Initializing', $module);
2682 module.bind.events();
2683 if (settings.observeChanges) {
2684 module.observeChanges();
2685 }
2686 module.instantiate();
2687 },
2688
2689 instantiate: function () {
2690 instance = module;
2691 $module
2692 .data(moduleNamespace, module)
2693 ;
2694 },
2695
2696 destroy: function () {
2697 module.debug('Destroying previous instance', $module);
2698 $module
2699 .off(eventNamespace)
2700 .removeData(moduleNamespace)
2701 ;
2702 },
2703
2704 refresh: function () {
2705 $title = $module.find(selector.title);
2706 $content = $module.find(selector.content);
2707 },
2708
2709 observeChanges: function () {
2710 if ('MutationObserver' in window) {
2711 observer = new MutationObserver(function (mutations) {
2712 module.debug('DOM tree modified, updating selector cache');
2713 module.refresh();
2714 });
2715 observer.observe(element, {
2716 childList: true,
2717 subtree: true,
2718 });
2719 module.debug('Setting up mutation observer', observer);
2720 }
2721 },
2722
2723 bind: {
2724 events: function () {
2725 module.debug('Binding delegated events');
2726 $module
2727 .on(settings.on + eventNamespace, selector.trigger, module.event.click)
2728 ;
2729 },
2730 },
2731
2732 event: {
2733 click: function (event) {
2734 if ($(event.target).closest(selector.ignore).length === 0) {
2735 module.toggle.call(this);
2736 }
2737 },
2738 },
2739
2740 toggle: function (query) {
2741 var
2742 $activeTitle = query !== undefined
2743 ? (typeof query === 'number'
2744 ? $title.eq(query)
2745 : $(query).closest(selector.title))
2746 : $(this).closest(selector.title),
2747 $activeContent = $activeTitle.next($content),
2748 isAnimating = $activeContent.hasClass(className.animating),
2749 isActive = $activeContent.hasClass(className.active),
2750 isOpen = isActive && !isAnimating,
2751 isOpening = !isActive && isAnimating
2752 ;
2753 module.debug('Toggling visibility of content', $activeTitle);
2754 if (isOpen || isOpening) {
2755 if (settings.collapsible) {
2756 module.close.call($activeTitle);
2757 } else {
2758 module.debug('Cannot close accordion content collapsing is disabled');
2759 }
2760 } else {
2761 module.open.call($activeTitle);
2762 }
2763 },
2764
2765 open: function (query) {
2766 var
2767 $activeTitle = query !== undefined
2768 ? (typeof query === 'number'
2769 ? $title.eq(query)
2770 : $(query).closest(selector.title))
2771 : $(this).closest(selector.title),
2772 $activeContent = $activeTitle.next($content),
2773 isAnimating = $activeContent.hasClass(className.animating),
2774 isActive = $activeContent.hasClass(className.active),
2775 isOpen = isActive || isAnimating
2776 ;
2777 if (isOpen) {
2778 module.debug('Accordion already open, skipping', $activeContent);
2779
2780 return;
2781 }
2782 module.debug('Opening accordion content', $activeTitle);
2783 settings.onOpening.call($activeContent);
2784 settings.onChanging.call($activeContent);
2785 if (settings.exclusive) {
2786 module.closeOthers.call($activeTitle);
2787 }
2788 $activeTitle
2789 .addClass(className.active)
2790 ;
2791 $activeContent
2792 .stop(true, true)
2793 .addClass(className.animating)
2794 ;
2795 if (settings.animateChildren) {
2796 if ($.fn.transition !== undefined) {
2797 $activeContent
2798 .children()
2799 .transition({
2800 animation: 'fade in',
2801 queue: false,
2802 useFailSafe: true,
2803 debug: settings.debug,
2804 verbose: settings.verbose,
2805 silent: settings.silent,
2806 duration: settings.duration,
2807 skipInlineHidden: true,
2808 onComplete: function () {
2809 $activeContent.children().removeClass(className.transition);
2810 },
2811 })
2812 ;
2813 } else {
2814 $activeContent
2815 .children()
2816 .stop(true, true)
2817 .animate({
2818 opacity: 1,
2819 }, settings.duration, module.resetOpacity);
2820 }
2821 }
2822 $activeContent
2823 .slideDown(settings.duration, settings.easing, function () {
2824 $activeContent
2825 .removeClass(className.animating)
2826 .addClass(className.active)
2827 ;
2828 module.reset.display.call(this);
2829 settings.onOpen.call(this);
2830 settings.onChange.call(this);
2831 })
2832 ;
2833 },
2834
2835 close: function (query) {
2836 var
2837 $activeTitle = query !== undefined
2838 ? (typeof query === 'number'
2839 ? $title.eq(query)
2840 : $(query).closest(selector.title))
2841 : $(this).closest(selector.title),
2842 $activeContent = $activeTitle.next($content),
2843 isAnimating = $activeContent.hasClass(className.animating),
2844 isActive = $activeContent.hasClass(className.active),
2845 isOpening = !isActive && isAnimating,
2846 isClosing = isActive && isAnimating
2847 ;
2848 if ((isActive || isOpening) && !isClosing) {
2849 module.debug('Closing accordion content', $activeContent);
2850 settings.onClosing.call($activeContent);
2851 settings.onChanging.call($activeContent);
2852 $activeTitle
2853 .removeClass(className.active)
2854 ;
2855 $activeContent
2856 .stop(true, true)
2857 .addClass(className.animating)
2858 ;
2859 if (settings.animateChildren) {
2860 if ($.fn.transition !== undefined) {
2861 $activeContent
2862 .children()
2863 .transition({
2864 animation: 'fade out',
2865 queue: false,
2866 useFailSafe: true,
2867 debug: settings.debug,
2868 verbose: settings.verbose,
2869 silent: settings.silent,
2870 duration: settings.duration,
2871 skipInlineHidden: true,
2872 })
2873 ;
2874 } else {
2875 $activeContent
2876 .children()
2877 .stop(true, true)
2878 .animate({
2879 opacity: 0,
2880 }, settings.duration, module.resetOpacity);
2881 }
2882 }
2883 $activeContent
2884 .slideUp(settings.duration, settings.easing, function () {
2885 $activeContent
2886 .removeClass(className.animating)
2887 .removeClass(className.active)
2888 ;
2889 module.reset.display.call(this);
2890 settings.onClose.call(this);
2891 settings.onChange.call(this);
2892 })
2893 ;
2894 }
2895 },
2896
2897 closeOthers: function (index) {
2898 var
2899 $activeTitle = index !== undefined
2900 ? $title.eq(index)
2901 : $(this).closest(selector.title),
2902 $parentTitles = $activeTitle.parents(selector.content).prev(selector.title),
2903 $activeAccordion = $activeTitle.closest(selector.accordion),
2904 activeSelector = selector.title + '.' + className.active + ':visible',
2905 activeContent = selector.content + '.' + className.active + ':visible',
2906 $openTitles,
2907 $nestedTitles,
2908 $openContents
2909 ;
2910 if (settings.closeNested) {
2911 $openTitles = $activeAccordion.find(activeSelector).not($parentTitles);
2912 $openContents = $openTitles.next($content);
2913 } else {
2914 $openTitles = $activeAccordion.find(activeSelector).not($parentTitles);
2915 $nestedTitles = $activeAccordion.find(activeContent).find(activeSelector).not($parentTitles);
2916 $openTitles = $openTitles.not($nestedTitles);
2917 $openContents = $openTitles.next($content);
2918 }
2919 if ($openTitles.length > 0) {
2920 module.debug('Exclusive enabled, closing other content', $openTitles);
2921 $openTitles
2922 .removeClass(className.active)
2923 ;
2924 $openContents
2925 .removeClass(className.animating)
2926 .stop(true, true)
2927 ;
2928 if (settings.animateChildren) {
2929 if ($.fn.transition !== undefined) {
2930 $openContents
2931 .children()
2932 .transition({
2933 animation: 'fade out',
2934 useFailSafe: true,
2935 debug: settings.debug,
2936 verbose: settings.verbose,
2937 silent: settings.silent,
2938 duration: settings.duration,
2939 skipInlineHidden: true,
2940 })
2941 ;
2942 } else {
2943 $openContents
2944 .children()
2945 .stop(true, true)
2946 .animate({
2947 opacity: 0,
2948 }, settings.duration, module.resetOpacity);
2949 }
2950 }
2951 $openContents
2952 .slideUp(settings.duration, settings.easing, function () {
2953 $(this).removeClass(className.active);
2954 module.reset.display.call(this);
2955 })
2956 ;
2957 }
2958 },
2959
2960 reset: {
2961
2962 display: function () {
2963 module.verbose('Removing inline display from element', this);
2964 var $element = $(this);
2965 $element.css('display', '');
2966 if ($element.attr('style') === '') {
2967 $element
2968 .attr('style', '')
2969 .removeAttr('style')
2970 ;
2971 }
2972 },
2973
2974 opacity: function () {
2975 module.verbose('Removing inline opacity from element', this);
2976 var $element = $(this);
2977 $element.css('opacity', '');
2978 if ($element.attr('style') === '') {
2979 $element
2980 .attr('style', '')
2981 .removeAttr('style')
2982 ;
2983 }
2984 },
2985
2986 },
2987
2988 setting: function (name, value) {
2989 module.debug('Changing setting', name, value);
2990 if ($.isPlainObject(name)) {
2991 $.extend(true, settings, name);
2992 } else if (value !== undefined) {
2993 if ($.isPlainObject(settings[name])) {
2994 $.extend(true, settings[name], value);
2995 } else {
2996 settings[name] = value;
2997 }
2998 } else {
2999 return settings[name];
3000 }
3001 },
3002 internal: function (name, value) {
3003 module.debug('Changing internal', name, value);
3004 if (value !== undefined) {
3005 if ($.isPlainObject(name)) {
3006 $.extend(true, module, name);
3007 } else {
3008 module[name] = value;
3009 }
3010 } else {
3011 return module[name];
3012 }
3013 },
3014 debug: function () {
3015 if (!settings.silent && settings.debug) {
3016 if (settings.performance) {
3017 module.performance.log(arguments);
3018 } else {
3019 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
3020 module.debug.apply(console, arguments);
3021 }
3022 }
3023 },
3024 verbose: function () {
3025 if (!settings.silent && settings.verbose && settings.debug) {
3026 if (settings.performance) {
3027 module.performance.log(arguments);
3028 } else {
3029 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
3030 module.verbose.apply(console, arguments);
3031 }
3032 }
3033 },
3034 error: function () {
3035 if (!settings.silent) {
3036 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
3037 module.error.apply(console, arguments);
3038 }
3039 },
3040 performance: {
3041 log: function (message) {
3042 var
3043 currentTime,
3044 executionTime,
3045 previousTime
3046 ;
3047 if (settings.performance) {
3048 currentTime = Date.now();
3049 previousTime = time || currentTime;
3050 executionTime = currentTime - previousTime;
3051 time = currentTime;
3052 performance.push({
3053 Name: message[0],
3054 Arguments: [].slice.call(message, 1) || '',
3055 Element: element,
3056 'Execution Time': executionTime,
3057 });
3058 }
3059 clearTimeout(module.performance.timer);
3060 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
3061 },
3062 display: function () {
3063 var
3064 title = settings.name + ':',
3065 totalTime = 0
3066 ;
3067 time = false;
3068 clearTimeout(module.performance.timer);
3069 $.each(performance, function (index, data) {
3070 totalTime += data['Execution Time'];
3071 });
3072 title += ' ' + totalTime + 'ms';
3073 if (performance.length > 0) {
3074 console.groupCollapsed(title);
3075 if (console.table) {
3076 console.table(performance);
3077 } else {
3078 $.each(performance, function (index, data) {
3079 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
3080 });
3081 }
3082 console.groupEnd();
3083 }
3084 performance = [];
3085 },
3086 },
3087 invoke: function (query, passedArguments, context) {
3088 var
3089 object = instance,
3090 maxDepth,
3091 found,
3092 response
3093 ;
3094 passedArguments = passedArguments || queryArguments;
3095 context = context || element;
3096 if (typeof query === 'string' && object !== undefined) {
3097 query = query.split(/[ .]/);
3098 maxDepth = query.length - 1;
3099 $.each(query, function (depth, value) {
3100 var camelCaseValue = depth !== maxDepth
3101 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
3102 : query;
3103 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
3104 object = object[camelCaseValue];
3105 } else if (object[camelCaseValue] !== undefined) {
3106 found = object[camelCaseValue];
3107
3108 return false;
3109 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
3110 object = object[value];
3111 } else if (object[value] !== undefined) {
3112 found = object[value];
3113
3114 return false;
3115 } else {
3116 module.error(error.method, query);
3117
3118 return false;
3119 }
3120 });
3121 }
3122 if (isFunction(found)) {
3123 response = found.apply(context, passedArguments);
3124 } else if (found !== undefined) {
3125 response = found;
3126 }
3127 if (Array.isArray(returnedValue)) {
3128 returnedValue.push(response);
3129 } else if (returnedValue !== undefined) {
3130 returnedValue = [returnedValue, response];
3131 } else if (response !== undefined) {
3132 returnedValue = response;
3133 }
3134
3135 return found;
3136 },
3137 };
3138 if (methodInvoked) {
3139 if (instance === undefined) {
3140 module.initialize();
3141 }
3142 module.invoke(query);
3143 } else {
3144 if (instance !== undefined) {
3145 instance.invoke('destroy');
3146 }
3147 module.initialize();
3148 }
3149 });
3150
3151 return returnedValue !== undefined
3152 ? returnedValue
3153 : this;
3154 };
3155
3156 $.fn.accordion.settings = {
3157
3158 name: 'Accordion',
3159 namespace: 'accordion',
3160
3161 silent: false,
3162 debug: false,
3163 verbose: false,
3164 performance: true,
3165
3166 on: 'click', // event on title that opens accordion
3167
3168 observeChanges: true, // whether accordion should automatically refresh on DOM insertion
3169
3170 exclusive: true, // whether a single accordion content panel should be open at once
3171 collapsible: true, // whether accordion content can be closed
3172 closeNested: false, // whether nested content should be closed when a panel is closed
3173 animateChildren: true, // whether children opacity should be animated
3174
3175 duration: 350, // duration of animation
3176 easing: 'easeOutQuad', // easing equation for animation
3177
3178 onOpening: function () {}, // callback before open animation
3179 onClosing: function () {}, // callback before closing animation
3180 onChanging: function () {}, // callback before closing or opening animation
3181
3182 onOpen: function () {}, // callback after open animation
3183 onClose: function () {}, // callback after closing animation
3184 onChange: function () {}, // callback after closing or opening animation
3185
3186 error: {
3187 method: 'The method you called is not defined',
3188 },
3189
3190 className: {
3191 active: 'active',
3192 animating: 'animating',
3193 transition: 'transition',
3194 },
3195
3196 selector: {
3197 accordion: '.accordion',
3198 title: '.title',
3199 trigger: '.title',
3200 ignore: '.ui.dropdown',
3201 content: '.content',
3202 },
3203
3204 };
3205
3206 // Adds easing
3207 $.extend($.easing, {
3208 easeOutQuad: function (x) {
3209 return 1 - (1 - x) * (1 - x);
3210 },
3211 });
3212})(jQuery, window, document);
3213
3214/*!
3215 * # Fomantic-UI 2.9.3 - Calendar
3216 * https://github.com/fomantic/Fomantic-UI/
3217 *
3218 *
3219 * Released under the MIT license
3220 * https://opensource.org/licenses/MIT
3221 *
3222 */
3223
3224(function ($, window, document) {
3225 'use strict';
3226
3227 function isFunction(obj) {
3228 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
3229 }
3230
3231 window = window !== undefined && window.Math === Math
3232 ? window
3233 : globalThis;
3234
3235 $.fn.calendar = function (parameters) {
3236 var
3237 $allModules = $(this),
3238 $document = $(document),
3239
3240 time = Date.now(),
3241 performance = [],
3242
3243 query = arguments[0],
3244 methodInvoked = typeof query === 'string',
3245 queryArguments = [].slice.call(arguments, 1),
3246 returnedValue,
3247 timeGapTable = {
3248 5: { row: 4, column: 3 },
3249 10: { row: 3, column: 2 },
3250 15: { row: 2, column: 2 },
3251 20: { row: 3, column: 1 },
3252 30: { row: 2, column: 1 },
3253 },
3254 numberText = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']
3255 ;
3256
3257 $allModules.each(function () {
3258 var
3259 settings = $.isPlainObject(parameters)
3260 ? $.extend(true, {}, $.fn.calendar.settings, parameters)
3261 : $.extend({}, $.fn.calendar.settings),
3262
3263 className = settings.className,
3264 namespace = settings.namespace,
3265 selector = settings.selector,
3266 formatter = settings.formatter,
3267 parser = settings.parser,
3268 metadata = settings.metadata,
3269 timeGap = timeGapTable[settings.minTimeGap],
3270 error = settings.error,
3271
3272 eventNamespace = '.' + namespace,
3273 moduleNamespace = 'module-' + namespace,
3274
3275 $module = $(this),
3276 $input = $module.find(selector.input),
3277 $activator = $module.find(selector.activator),
3278
3279 element = this,
3280 instance = $module.data(moduleNamespace),
3281 $container = instance && instance.popupId ? $document.find('#' + instance.popupId) : $module.find(selector.popup),
3282
3283 isTouch,
3284 isTouchDown = false,
3285 isInverted = $module.hasClass(className.inverted),
3286 focusDateUsedForRange = false,
3287 selectionComplete = false,
3288 classObserver,
3289 module
3290 ;
3291
3292 module = {
3293
3294 initialize: function () {
3295 module.debug('Initializing calendar for', element, $module);
3296
3297 isTouch = module.get.isTouch();
3298 module.setup.config();
3299 module.setup.popup();
3300 module.setup.inline();
3301 module.setup.input();
3302 module.setup.date();
3303 module.create.calendar();
3304
3305 module.bind.events();
3306 module.observeChanges();
3307 module.instantiate();
3308 },
3309
3310 instantiate: function () {
3311 module.verbose('Storing instance of calendar');
3312 instance = module;
3313 $module.data(moduleNamespace, instance);
3314 },
3315
3316 destroy: function () {
3317 module.verbose('Destroying previous calendar for', element);
3318 $module.removeData(moduleNamespace);
3319 module.unbind.events();
3320 module.disconnect.classObserver();
3321 },
3322
3323 setup: {
3324 config: function () {
3325 if (module.get.minDate() !== null) {
3326 module.set.minDate($module.data(metadata.minDate));
3327 }
3328 if (module.get.maxDate() !== null) {
3329 module.set.maxDate($module.data(metadata.maxDate));
3330 }
3331 module.setting('type', module.get.type());
3332 module.setting('on', settings.on || 'click');
3333 },
3334 popup: function () {
3335 if (settings.inline) {
3336 return;
3337 }
3338 if ($activator.length === 0) {
3339 $activator = $module.children().first();
3340 if ($activator.length === 0) {
3341 return;
3342 }
3343 }
3344 if ($.fn.popup === undefined) {
3345 module.error(error.popup);
3346
3347 return;
3348 }
3349 if ($container.length === 0) {
3350 if (settings.context) {
3351 module.popupId = namespace + '_popup_' + (Math.random().toString(16) + '000000000').slice(2, 10);
3352 $container = $('<div/>', { id: module.popupId }).addClass(className.popup).appendTo($document.find(settings.context));
3353 } else {
3354 // prepend the popup element to the activator's parent so that it has less chance of messing with
3355 // the styling (eg input action button needs to be the last child to have correct border radius)
3356 var
3357 $activatorParent = $activator.parent(),
3358 domPositionFunction = $activatorParent.closest(selector.append).length > 0 ? 'appendTo' : 'prependTo'
3359 ;
3360 $container = $('<div/>').addClass(className.popup)[domPositionFunction]($activatorParent);
3361 }
3362 }
3363 $container.addClass(className.calendar);
3364 if (isInverted) {
3365 $container.addClass(className.inverted);
3366 }
3367 var onVisible = function () {
3368 module.refreshTooltips();
3369
3370 return settings.onVisible.apply($container, arguments);
3371 };
3372 var onHidden = function () {
3373 module.blur();
3374
3375 return settings.onHidden.apply($container, arguments);
3376 };
3377 if ($input.length === 0) {
3378 // no input, $container has to handle focus/blur
3379 $container.attr('tabindex', '0');
3380 onVisible = function () {
3381 module.refreshTooltips();
3382 module.focus();
3383
3384 return settings.onVisible.apply($container, arguments);
3385 };
3386 }
3387 var onShow = function () {
3388 // reset the focus date onShow
3389 module.set.focusDate(module.get.date());
3390 module.set.mode(module.get.validatedMode(settings.startMode));
3391
3392 return settings.onShow.apply($container, arguments);
3393 };
3394 var on = module.setting('on');
3395 var options = $.extend({}, settings.popupOptions, {
3396 popup: $container,
3397 movePopup: !settings.context,
3398 on: on,
3399 hoverable: on === 'hover',
3400 closable: on === 'click',
3401 onShow: onShow,
3402 onVisible: onVisible,
3403 onHide: settings.onHide,
3404 onHidden: onHidden,
3405 });
3406 module.popup(options);
3407 },
3408 inline: function () {
3409 if ($activator.length > 0 && !settings.inline) {
3410 return;
3411 }
3412 settings.inline = true;
3413 $container = $('<div/>').addClass(className.calendar).appendTo($module);
3414 if ($input.length === 0) {
3415 $container.attr('tabindex', '0');
3416 }
3417 },
3418 input: function () {
3419 if (settings.touchReadonly && $input.length > 0 && isTouch) {
3420 $input.prop('readonly', true);
3421 }
3422 module.check.disabled();
3423 },
3424 date: function () {
3425 var date;
3426 if (settings.initialDate) {
3427 date = parser.date(settings.initialDate, settings);
3428 } else if ($module.data(metadata.date) !== undefined) {
3429 date = parser.date($module.data(metadata.date), settings);
3430 } else if ($input.length > 0) {
3431 date = parser.date($input.val(), settings);
3432 }
3433 module.set.date(date, settings.formatInput, false);
3434 module.set.mode(module.get.mode(), false);
3435 },
3436 },
3437
3438 trigger: {
3439 change: function () {
3440 var
3441 inputElement = $input[0]
3442 ;
3443 if (inputElement) {
3444 var events = document.createEvent('HTMLEvents');
3445 module.verbose('Triggering native change event');
3446 events.initEvent('change', true, false);
3447 inputElement.dispatchEvent(events);
3448 }
3449 },
3450 },
3451
3452 create: {
3453 calendar: function () {
3454 var
3455 i,
3456 r,
3457 c,
3458 p,
3459 row,
3460 cell,
3461 pageGrid
3462 ;
3463
3464 var
3465 mode = module.get.mode(),
3466 today = new Date(),
3467 date = module.get.date(),
3468 focusDate = module.get.focusDate(),
3469 display = module.helper.dateInRange(focusDate || date || parser.date(settings.initialDate, settings) || today)
3470 ;
3471
3472 if (!focusDate) {
3473 focusDate = display;
3474 module.set.focusDate(focusDate, false, false);
3475 }
3476
3477 var
3478 isYear = mode === 'year',
3479 isMonth = mode === 'month',
3480 isDay = mode === 'day',
3481 isHour = mode === 'hour',
3482 isMinute = mode === 'minute',
3483 isTimeOnly = settings.type === 'time'
3484 ;
3485
3486 var multiMonth = Math.max(settings.multiMonth, 1);
3487 var monthOffset = !isDay ? 0 : module.get.monthOffset();
3488
3489 var
3490 minute = display.getMinutes(),
3491 hour = display.getHours(),
3492 day = display.getDate(),
3493 startMonth = display.getMonth() + monthOffset,
3494 year = display.getFullYear()
3495 ;
3496
3497 var columns = isDay
3498 ? (settings.showWeekNumbers ? 8 : 7)
3499 : (isHour ? 4 : timeGap.column);
3500 var rows = isDay || isHour ? 6 : timeGap.row;
3501 var pages = isDay ? multiMonth : 1;
3502
3503 var container = $container;
3504 var tooltipPosition = container.hasClass('left') ? 'right center' : 'left center';
3505 container.empty();
3506 if (pages > 1) {
3507 pageGrid = $('<div/>').addClass(className.grid).appendTo(container);
3508 }
3509
3510 for (p = 0; p < pages; p++) {
3511 if (pages > 1) {
3512 var pageColumn = $('<div/>').addClass(className.column).appendTo(pageGrid);
3513 container = pageColumn;
3514 }
3515
3516 var month = startMonth + p;
3517 var firstMonthDayColumn = (new Date(year, month, 1).getDay() - (settings.firstDayOfWeek % 7) + 7) % 7;
3518 if (!settings.constantHeight && isDay) {
3519 var requiredCells = new Date(year, month + 1, 0).getDate() + firstMonthDayColumn;
3520 rows = Math.ceil(requiredCells / 7);
3521 }
3522
3523 var
3524 yearChange = isYear ? 10 : (isMonth ? 1 : 0),
3525 monthChange = isDay ? 1 : 0,
3526 dayChange = isHour || isMinute ? 1 : 0,
3527 prevNextDay = isHour || isMinute ? day : 1,
3528 prevDate = new Date(year - yearChange, month - monthChange, prevNextDay - dayChange, hour),
3529 nextDate = new Date(year + yearChange, month + monthChange, prevNextDay + dayChange, hour),
3530 prevLast = isYear
3531 ? new Date(Math.ceil(year / 10) * 10 - 9, 0, 0)
3532 : (isMonth
3533 ? new Date(year, 0, 0)
3534 : (isDay // eslint-disable-line unicorn/no-nested-ternary
3535 ? new Date(year, month, 0)
3536 : new Date(year, month, day, -1))),
3537 nextFirst = isYear
3538 ? new Date(Math.ceil(year / 10) * 10 + 1, 0, 1)
3539 : (isMonth
3540 ? new Date(year + 1, 0, 1)
3541 : (isDay // eslint-disable-line unicorn/no-nested-ternary
3542 ? new Date(year, month + 1, 1)
3543 : new Date(year, month, day + 1)))
3544 ;
3545
3546 var tempMode = mode;
3547 if (isDay && settings.showWeekNumbers) {
3548 tempMode += ' andweek';
3549 }
3550 var table = $('<table/>').addClass(className.table).addClass(tempMode).addClass(numberText[columns] + ' column')
3551 .appendTo(container);
3552 if (isInverted) {
3553 table.addClass(className.inverted);
3554 }
3555 var textColumns = columns;
3556 // no header for time-only mode
3557 if (!isTimeOnly) {
3558 var thead = $('<thead/>').appendTo(table);
3559
3560 row = $('<tr/>').appendTo(thead);
3561 cell = $('<th/>').attr('colspan', '' + columns).appendTo(row);
3562
3563 var headerDate = isYear || isMonth
3564 ? new Date(year, 0, 1)
3565 : (isDay
3566 ? new Date(year, month, 1)
3567 : new Date(year, month, day, hour, minute));
3568 var headerText = $('<span/>').addClass(className.link).appendTo(cell);
3569 headerText.text(module.helper.dateFormat(formatter[mode + 'Header'], headerDate));
3570 var newMode = isMonth
3571 ? (settings.disableYear ? 'day' : 'year')
3572 : (isDay
3573 ? (settings.disableMonth ? 'year' : 'month') // eslint-disable-line unicorn/no-nested-ternary
3574 : 'day');
3575 headerText.data(metadata.mode, newMode);
3576
3577 if (p === 0) {
3578 var prev = $('<span/>').addClass(className.prev).appendTo(cell);
3579 prev.data(metadata.focusDate, prevDate);
3580 prev.toggleClass(className.disabledCell, !module.helper.isDateInRange(prevLast, mode));
3581 $('<i/>').addClass(className.prevIcon).appendTo(prev);
3582 }
3583
3584 if (p === pages - 1) {
3585 var next = $('<span/>').addClass(className.next).appendTo(cell);
3586 next.data(metadata.focusDate, nextDate);
3587 next.toggleClass(className.disabledCell, !module.helper.isDateInRange(nextFirst, mode));
3588 $('<i/>').addClass(className.nextIcon).appendTo(next);
3589 }
3590 if (isDay) {
3591 row = $('<tr/>').appendTo(thead);
3592 if (settings.showWeekNumbers) {
3593 cell = $('<th/>').appendTo(row);
3594 cell.text(settings.text.weekNo);
3595 cell.addClass(className.weekCell);
3596 textColumns--;
3597 }
3598 for (i = 0; i < textColumns; i++) {
3599 cell = $('<th/>').appendTo(row);
3600 cell.text(formatter.dayColumnHeader((i + settings.firstDayOfWeek) % 7, settings));
3601 }
3602 }
3603 }
3604
3605 var tbody = $('<tbody/>').appendTo(table);
3606 i = isYear
3607 ? Math.ceil(year / 10) * 10 - 9
3608 : (isDay ? 1 - firstMonthDayColumn : 0);
3609 for (r = 0; r < rows; r++) {
3610 row = $('<tr/>').appendTo(tbody);
3611 if (isDay && settings.showWeekNumbers) {
3612 cell = $('<th/>').appendTo(row);
3613 cell.text(module.get.weekOfYear(year, month, i + 1 - settings.firstDayOfWeek));
3614 cell.addClass(className.weekCell);
3615 }
3616 for (c = 0; c < textColumns; c++, i++) {
3617 var cellDate = isYear
3618 ? new Date(i, month, 1, hour, minute)
3619 : (isMonth
3620 ? new Date(year, i, 1, hour, minute)
3621 : (isDay // eslint-disable-line unicorn/no-nested-ternary
3622 ? new Date(year, month, i, hour, minute)
3623 : (isHour
3624 ? new Date(year, month, day, i)
3625 : new Date(year, month, day, hour, i * settings.minTimeGap))));
3626 var cellText = isYear
3627 ? i
3628 : (isMonth
3629 ? settings.text.monthsShort[i]
3630 : (isDay // eslint-disable-line unicorn/no-nested-ternary
3631 ? cellDate.getDate()
3632 : module.helper.dateFormat(formatter.cellTime, cellDate)));
3633 cell = $('<td/>').addClass(className.cell).appendTo(row);
3634 cell.text(cellText);
3635 cell.data(metadata.date, cellDate);
3636 var adjacent = isDay && cellDate.getMonth() !== ((month + 12) % 12);
3637 var disabled = (!settings.selectAdjacentDays && adjacent) || !module.helper.isDateInRange(cellDate, mode) || settings.isDisabled(cellDate, mode) || module.helper.isDisabled(cellDate, mode) || !module.helper.isEnabled(cellDate, mode);
3638 var eventDate;
3639 if (disabled) {
3640 var disabledDate = module.helper.findDayAsObject(cellDate, mode, settings.disabledDates);
3641 if (disabledDate !== null && disabledDate[metadata.message]) {
3642 cell.attr('data-tooltip', disabledDate[metadata.message]);
3643 cell.attr('data-position', disabledDate[metadata.position] || tooltipPosition);
3644 if (disabledDate[metadata.inverted] || (isInverted && disabledDate[metadata.inverted] === undefined)) {
3645 cell.attr('data-inverted', '');
3646 }
3647 if (disabledDate[metadata.variation]) {
3648 cell.attr('data-variation', disabledDate[metadata.variation]);
3649 }
3650 }
3651 if (mode === 'hour') {
3652 var disabledHour = module.helper.findHourAsObject(cellDate, mode, settings.disabledHours);
3653 if (disabledHour !== null && disabledHour[metadata.message]) {
3654 cell.attr('data-tooltip', disabledHour[metadata.message]);
3655 cell.attr('data-position', disabledHour[metadata.position] || tooltipPosition);
3656 if (disabledHour[metadata.inverted] || (isInverted && disabledHour[metadata.inverted] === undefined)) {
3657 cell.attr('data-inverted', '');
3658 }
3659 if (disabledHour[metadata.variation]) {
3660 cell.attr('data-variation', disabledHour[metadata.variation]);
3661 }
3662 }
3663 }
3664 } else {
3665 eventDate = module.helper.findDayAsObject(cellDate, mode, settings.eventDates);
3666 if (eventDate !== null) {
3667 cell.addClass(eventDate[metadata.class] || settings.eventClass);
3668 if (eventDate[metadata.message]) {
3669 cell.attr('data-tooltip', eventDate[metadata.message]);
3670 cell.attr('data-position', eventDate[metadata.position] || tooltipPosition);
3671 if (eventDate[metadata.inverted] || (isInverted && eventDate[metadata.inverted] === undefined)) {
3672 cell.attr('data-inverted', '');
3673 }
3674 if (eventDate[metadata.variation]) {
3675 cell.attr('data-variation', eventDate[metadata.variation]);
3676 }
3677 }
3678 }
3679 }
3680 var active = module.helper.dateEqual(cellDate, date, mode);
3681 var isToday = module.helper.dateEqual(cellDate, today, mode);
3682 cell.toggleClass(className.adjacentCell, adjacent && !eventDate);
3683 cell.toggleClass(className.disabledCell, disabled);
3684 cell.toggleClass(className.activeCell, active && !(adjacent && disabled));
3685 if (!isHour && !isMinute) {
3686 cell.toggleClass(className.todayCell, !adjacent && isToday);
3687 }
3688
3689 // Allow for external modifications of each cell
3690 var cellOptions = {
3691 mode: mode,
3692 adjacent: adjacent,
3693 disabled: disabled,
3694 active: active,
3695 today: isToday,
3696 };
3697 formatter.cell(cell, cellDate, cellOptions);
3698
3699 if (module.helper.dateEqual(cellDate, focusDate, mode)) {
3700 // ensure that the focus date is exactly equal to the cell date
3701 // so that, if selected, the correct value is set
3702 module.set.focusDate(cellDate, false, false);
3703 }
3704 }
3705 }
3706
3707 if (settings.today) {
3708 var todayRow = $('<tr/>').appendTo(tbody);
3709 var todayButton = $('<td/>').attr('colspan', '' + columns).addClass(className.today).appendTo(todayRow);
3710 todayButton.text(formatter.today(settings));
3711 todayButton.data(metadata.date, today);
3712 }
3713
3714 module.update.focus(false, table);
3715
3716 if (settings.inline) {
3717 module.refreshTooltips();
3718 }
3719 }
3720 },
3721 },
3722
3723 update: {
3724 focus: function (updateRange, container) {
3725 container = container || $container;
3726 var mode = module.get.mode();
3727 var date = module.get.date();
3728 var focusDate = module.get.focusDate();
3729 var startDate = module.get.startDate();
3730 var endDate = module.get.endDate();
3731 var rangeDate = (updateRange ? focusDate : null) || date || (!isTouch ? focusDate : null);
3732
3733 container.find('td').each(function () {
3734 var $cell = $(this);
3735 var cellDate = $cell.data(metadata.date);
3736 if (!cellDate) {
3737 return;
3738 }
3739 var disabled = $cell.hasClass(className.disabledCell);
3740 var active = $cell.hasClass(className.activeCell);
3741 var adjacent = $cell.hasClass(className.adjacentCell);
3742 var focused = module.helper.dateEqual(cellDate, focusDate, mode);
3743 var inRange = !rangeDate
3744 ? false
3745 : (!!startDate && module.helper.isDateInRange(cellDate, mode, startDate, rangeDate))
3746 || (!!endDate && module.helper.isDateInRange(cellDate, mode, rangeDate, endDate));
3747 $cell.toggleClass(className.focusCell, focused && (!isTouch || isTouchDown) && (!adjacent || (settings.selectAdjacentDays && adjacent)) && !disabled);
3748
3749 if (module.helper.isTodayButton($cell)) {
3750 return;
3751 }
3752 $cell.toggleClass(className.rangeCell, inRange && !active && !disabled);
3753 });
3754 },
3755 },
3756
3757 refresh: function () {
3758 module.create.calendar();
3759 },
3760
3761 refreshTooltips: function () {
3762 var winWidth = $(window).width();
3763 $container.find('td[data-position]').each(function () {
3764 var $cell = $(this);
3765 var tooltipWidth = window.getComputedStyle($cell[0], '::after').width.replace(/[^\d.]/g, '');
3766 var tooltipPosition = $cell.attr('data-position');
3767 // use a fallback width of 250 (calendar width) for IE/Edge (which return "auto")
3768 var calcPosition = (winWidth - $cell.width() - (parseInt(tooltipWidth, 10) || 250)) > $cell.offset().left ? 'right' : 'left';
3769 if (tooltipPosition.indexOf(calcPosition) === -1) {
3770 $cell.attr('data-position', tooltipPosition.replace(/(left|right)/, calcPosition));
3771 }
3772 });
3773 },
3774
3775 bind: {
3776 events: function () {
3777 module.debug('Binding events');
3778 $container.on('mousedown' + eventNamespace, module.event.mousedown);
3779 $container.on('touchstart' + eventNamespace, module.event.mousedown);
3780 $container.on('mouseup' + eventNamespace, module.event.mouseup);
3781 $container.on('touchend' + eventNamespace, module.event.mouseup);
3782 $container.on('mouseover' + eventNamespace, module.event.mouseover);
3783 if ($input.length > 0) {
3784 $input.on('input' + eventNamespace, module.event.inputChange);
3785 $input.on('focus' + eventNamespace, module.event.inputFocus);
3786 $input.on('blur' + eventNamespace, module.event.inputBlur);
3787 $input.on('keydown' + eventNamespace, module.event.keydown);
3788 } else {
3789 $container.on('keydown' + eventNamespace, module.event.keydown);
3790 }
3791 },
3792 },
3793
3794 unbind: {
3795 events: function () {
3796 module.debug('Unbinding events');
3797 $container.off(eventNamespace);
3798 if ($input.length > 0) {
3799 $input.off(eventNamespace);
3800 }
3801 },
3802 },
3803
3804 event: {
3805 mouseover: function (event) {
3806 var target = $(event.target);
3807 var date = target.data(metadata.date);
3808 var mousedown = event.buttons === 1;
3809 if (date) {
3810 module.set.focusDate(date, false, true, mousedown);
3811 }
3812 },
3813 mousedown: function (event) {
3814 if ($input.length > 0) {
3815 // prevent the mousedown on the calendar causing the input to lose focus
3816 event.preventDefault();
3817 }
3818 isTouchDown = event.type.indexOf('touch') >= 0;
3819 var target = $(event.target);
3820 var date = target.data(metadata.date);
3821 if (date) {
3822 module.set.focusDate(date, false, true, true);
3823 }
3824 },
3825 mouseup: function (event) {
3826 // ensure input has focus so that it receives keydown events for calendar navigation
3827 module.focus();
3828 event.preventDefault();
3829 event.stopPropagation();
3830 isTouchDown = false;
3831 var target = $(event.target);
3832 if (target.hasClass('disabled')) {
3833 return;
3834 }
3835 var parent = target.parent();
3836 if (parent.data(metadata.date) || parent.data(metadata.focusDate) || parent.data(metadata.mode)) {
3837 // clicked on a child element, switch to parent (used when clicking directly on prev/next <i> icon element)
3838 target = parent;
3839 }
3840 var date = target.data(metadata.date);
3841 var focusDate = target.data(metadata.focusDate);
3842 var mode = target.data(metadata.mode);
3843 if (date && settings.onSelect.call(element, date, module.get.mode()) !== false) {
3844 var forceSet = target.hasClass(className.today);
3845 module.selectDate(date, forceSet);
3846 } else if (focusDate) {
3847 module.set.focusDate(focusDate);
3848 } else if (mode) {
3849 module.set.mode(mode);
3850 }
3851 },
3852 keydown: function (event) {
3853 var keyCode = event.which;
3854 if (keyCode === 9) {
3855 // tab
3856 module.popup('hide');
3857 }
3858
3859 if (module.popup('is visible')) {
3860 var mode = module.get.mode();
3861 switch (keyCode) {
3862 // arrow keys
3863 case 37:
3864 case 38:
3865 case 39:
3866 case 40: {
3867 var bigIncrement = mode === 'day'
3868 ? 7
3869 : (mode === 'hour'
3870 ? 4
3871 : (mode === 'minute' ? timeGap.column : 3)); // eslint-disable-line unicorn/no-nested-ternary
3872 var increment = keyCode === 37
3873 ? -1
3874 : (keyCode === 38
3875 ? -bigIncrement
3876 : (keyCode === 39 ? 1 : bigIncrement)); // eslint-disable-line unicorn/no-nested-ternary
3877 increment *= mode === 'minute' ? settings.minTimeGap : 1;
3878 var focusDate = module.get.focusDate() || module.get.date() || new Date();
3879 var year = focusDate.getFullYear() + (mode === 'year' ? increment : 0);
3880 var month = focusDate.getMonth() + (mode === 'month' ? increment : 0);
3881 var day = focusDate.getDate() + (mode === 'day' ? increment : 0);
3882 var hour = focusDate.getHours() + (mode === 'hour' ? increment : 0);
3883 var minute = focusDate.getMinutes() + (mode === 'minute' ? increment : 0);
3884 var newFocusDate = new Date(year, month, day, hour, minute);
3885 if (settings.type === 'time') {
3886 newFocusDate = module.helper.mergeDateTime(focusDate, newFocusDate);
3887 }
3888 if (module.helper.isDateInRange(newFocusDate, mode)) {
3889 module.set.focusDate(newFocusDate);
3890 }
3891
3892 break;
3893 }
3894 // enter key
3895 case 13: {
3896 var date = module.get.focusDate();
3897 if (date && !settings.isDisabled(date, mode) && !module.helper.isDisabled(date, mode) && module.helper.isEnabled(date, mode)) {
3898 if (settings.onSelect.call(element, date, module.get.mode()) !== false) {
3899 module.selectDate(date);
3900 }
3901 }
3902 // disable form submission:
3903 event.preventDefault();
3904 event.stopPropagation();
3905
3906 break;
3907 }
3908 // escape key
3909 case 27: {
3910 module.popup('hide');
3911 event.stopPropagation();
3912
3913 break;
3914 }
3915 }
3916 }
3917
3918 if (keyCode === 38 || keyCode === 40) {
3919 // arrow-up || arrow-down
3920 event.preventDefault(); // don't scroll
3921 module.popup('show');
3922 }
3923 },
3924 inputChange: function () {
3925 var val = $input.val();
3926 var date = parser.date(val, settings);
3927 module.set.date(date, false);
3928 },
3929 inputFocus: function () {
3930 $container.addClass(className.active);
3931 },
3932 inputBlur: function () {
3933 $container.removeClass(className.active);
3934 if (settings.formatInput) {
3935 var date = module.get.date();
3936 var text = module.helper.dateFormat(formatter[settings.type], date);
3937 $input.val(text);
3938 }
3939 if (selectionComplete) {
3940 module.trigger.change();
3941 selectionComplete = false;
3942 }
3943 },
3944 class: {
3945 mutation: function (mutations) {
3946 mutations.forEach(function (mutation) {
3947 if (mutation.attributeName === 'class') {
3948 module.check.disabled();
3949 }
3950 });
3951 },
3952 },
3953 },
3954
3955 observeChanges: function () {
3956 if ('MutationObserver' in window) {
3957 classObserver = new MutationObserver(module.event.class.mutation);
3958 module.debug('Setting up mutation observer', classObserver);
3959 module.observe.class();
3960 }
3961 },
3962
3963 disconnect: {
3964 classObserver: function () {
3965 if ($input.length > 0 && classObserver) {
3966 classObserver.disconnect();
3967 }
3968 },
3969 },
3970
3971 observe: {
3972 class: function () {
3973 if ($input.length > 0 && classObserver) {
3974 classObserver.observe($module[0], {
3975 attributes: true,
3976 });
3977 }
3978 },
3979 },
3980
3981 is: {
3982 disabled: function () {
3983 return $module.hasClass(className.disabled);
3984 },
3985 },
3986
3987 check: {
3988 disabled: function () {
3989 $input.attr('tabindex', module.is.disabled() ? -1 : 0);
3990 },
3991 },
3992
3993 get: {
3994 weekOfYear: function (weekYear, weekMonth, weekDay) {
3995 // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
3996 var ms1d = 24 * 3600 * 1000,
3997 ms7d = 7 * ms1d,
3998 DC3 = Date.UTC(weekYear, weekMonth, weekDay + 3) / ms1d, // an absolute day number
3999 AWN = Math.floor(DC3 / 7), // an absolute week number
4000 Wyr = new Date(AWN * ms7d).getUTCFullYear()
4001 ;
4002
4003 return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
4004 },
4005 formattedDate: function (format, date) {
4006 return module.helper.dateFormat(format || formatter[settings.type], date || module.get.date());
4007 },
4008 date: function () {
4009 return module.helper.sanitiseDate($module.data(metadata.date)) || null;
4010 },
4011 inputDate: function () {
4012 return $input.val();
4013 },
4014 focusDate: function () {
4015 return $module.data(metadata.focusDate) || null;
4016 },
4017 startDate: function () {
4018 var startModule = module.get.calendarModule(settings.startCalendar);
4019
4020 return (startModule ? startModule.get.date() : $module.data(metadata.startDate)) || null;
4021 },
4022 endDate: function () {
4023 var endModule = module.get.calendarModule(settings.endCalendar);
4024
4025 return (endModule ? endModule.get.date() : $module.data(metadata.endDate)) || null;
4026 },
4027 minDate: function () {
4028 return $module.data(metadata.minDate) || null;
4029 },
4030 maxDate: function () {
4031 return $module.data(metadata.maxDate) || null;
4032 },
4033 monthOffset: function () {
4034 return $module.data(metadata.monthOffset) || settings.monthOffset || 0;
4035 },
4036 mode: function () {
4037 // only returns valid modes for the current settings
4038 var mode = $module.data(metadata.mode) || settings.startMode;
4039
4040 return module.get.validatedMode(mode);
4041 },
4042 validatedMode: function (mode) {
4043 var validModes = module.get.validModes();
4044 if ($.inArray(mode, validModes) >= 0) {
4045 return mode;
4046 }
4047
4048 return settings.type === 'time'
4049 ? 'hour'
4050 : (settings.type === 'month'
4051 ? 'month'
4052 : (settings.type === 'year' ? 'year' : 'day')); // eslint-disable-line unicorn/no-nested-ternary
4053 },
4054 type: function () {
4055 return $module.data(metadata.type) || settings.type;
4056 },
4057 validModes: function () {
4058 var validModes = [];
4059 if (settings.type !== 'time') {
4060 if (!settings.disableYear || settings.type === 'year') {
4061 validModes.push('year');
4062 }
4063 if (!(settings.disableMonth || settings.type === 'year') || settings.type === 'month') {
4064 validModes.push('month');
4065 }
4066 if (settings.type.indexOf('date') >= 0) {
4067 validModes.push('day');
4068 }
4069 }
4070 if (settings.type.indexOf('time') >= 0) {
4071 validModes.push('hour');
4072 if (!settings.disableMinute) {
4073 validModes.push('minute');
4074 }
4075 }
4076
4077 return validModes;
4078 },
4079 isTouch: function () {
4080 try {
4081 document.createEvent('TouchEvent');
4082
4083 return true;
4084 } catch (e) {
4085 return false;
4086 }
4087 },
4088 calendarModule: function (selector) {
4089 if (!selector) {
4090 return null;
4091 }
4092 if (!(selector instanceof $)) {
4093 selector = $document.find(selector).first();
4094 }
4095
4096 // assume range related calendars are using the same namespace
4097 return selector.data(moduleNamespace);
4098 },
4099 },
4100
4101 set: {
4102 date: function (date, updateInput, fireChange) {
4103 updateInput = updateInput !== false;
4104 fireChange = fireChange !== false;
4105 date = module.helper.sanitiseDate(date);
4106 date = module.helper.dateInRange(date);
4107
4108 var mode = module.get.mode();
4109 var text = module.helper.dateFormat(formatter[settings.type], date);
4110
4111 if (fireChange && settings.onBeforeChange.call(element, date, text, mode) === false) {
4112 return false;
4113 }
4114
4115 module.set.focusDate(date);
4116
4117 if (settings.isDisabled(date, mode)) {
4118 return false;
4119 }
4120
4121 var endDate = module.get.endDate();
4122 if (!!endDate && !!date && date > endDate) {
4123 // selected date is greater than end date in range, so clear end date
4124 module.set.endDate();
4125 }
4126 module.set.dataKeyValue(metadata.date, date);
4127
4128 if (updateInput && $input.length > 0) {
4129 $input.val(text);
4130 }
4131
4132 if (fireChange) {
4133 settings.onChange.call(element, date, text, mode);
4134 }
4135 },
4136 startDate: function (date, refreshCalendar) {
4137 date = module.helper.sanitiseDate(date);
4138 var startModule = module.get.calendarModule(settings.startCalendar);
4139 if (startModule) {
4140 startModule.set.date(date);
4141 }
4142 module.set.dataKeyValue(metadata.startDate, date, refreshCalendar);
4143 },
4144 endDate: function (date, refreshCalendar) {
4145 date = module.helper.sanitiseDate(date);
4146 var endModule = module.get.calendarModule(settings.endCalendar);
4147 if (endModule) {
4148 endModule.set.date(date);
4149 }
4150 module.set.dataKeyValue(metadata.endDate, date, refreshCalendar);
4151 },
4152 focusDate: function (date, refreshCalendar, updateFocus, updateRange) {
4153 date = module.helper.sanitiseDate(date);
4154 date = module.helper.dateInRange(date);
4155 var isDay = module.get.mode() === 'day';
4156 var oldFocusDate = module.get.focusDate();
4157 if (isDay && date && oldFocusDate) {
4158 var yearDelta = date.getFullYear() - oldFocusDate.getFullYear();
4159 var monthDelta = yearDelta * 12 + date.getMonth() - oldFocusDate.getMonth();
4160 if (monthDelta) {
4161 var monthOffset = module.get.monthOffset() - monthDelta;
4162 module.set.monthOffset(monthOffset, false);
4163 }
4164 }
4165 var changed = module.set.dataKeyValue(metadata.focusDate, date, !!date && refreshCalendar);
4166 updateFocus = (updateFocus !== false && changed && refreshCalendar === false) || focusDateUsedForRange != updateRange;
4167 focusDateUsedForRange = updateRange;
4168 if (updateFocus) {
4169 module.update.focus(updateRange);
4170 }
4171 },
4172 minDate: function (date) {
4173 date = module.helper.sanitiseDate(date);
4174 if (settings.maxDate !== null && settings.maxDate <= date) {
4175 module.verbose('Unable to set minDate variable bigger that maxDate variable', date, settings.maxDate);
4176 } else {
4177 module.setting('minDate', date);
4178 module.set.dataKeyValue(metadata.minDate, date);
4179 }
4180 },
4181 maxDate: function (date) {
4182 date = module.helper.sanitiseDate(date);
4183 if (settings.minDate !== null && settings.minDate >= date) {
4184 module.verbose('Unable to set maxDate variable lower that minDate variable', date, settings.minDate);
4185 } else {
4186 module.setting('maxDate', date);
4187 module.set.dataKeyValue(metadata.maxDate, date);
4188 }
4189 },
4190 monthOffset: function (monthOffset, refreshCalendar) {
4191 var multiMonth = Math.max(settings.multiMonth, 1);
4192 monthOffset = Math.max(1 - multiMonth, Math.min(0, monthOffset));
4193 module.set.dataKeyValue(metadata.monthOffset, monthOffset, refreshCalendar);
4194 },
4195 mode: function (mode, refreshCalendar) {
4196 module.set.dataKeyValue(metadata.mode, mode, refreshCalendar);
4197 },
4198 dataKeyValue: function (key, value, refreshCalendar) {
4199 var oldValue = $module.data(key);
4200 var equal = oldValue === value || (oldValue <= value && oldValue >= value); // equality test for dates and string objects
4201 if (value) {
4202 $module.data(key, value);
4203 } else {
4204 $module.removeData(key);
4205 }
4206 refreshCalendar = refreshCalendar !== false && !equal;
4207 if (refreshCalendar) {
4208 module.refresh();
4209 }
4210
4211 return !equal;
4212 },
4213 },
4214
4215 selectDate: function (date, forceSet) {
4216 module.verbose('New date selection', date);
4217 var mode = module.get.mode();
4218 var complete = forceSet || mode === 'minute'
4219 || (settings.disableMinute && mode === 'hour')
4220 || (settings.type === 'date' && mode === 'day')
4221 || (settings.type === 'month' && mode === 'month')
4222 || (settings.type === 'year' && mode === 'year');
4223 if (complete) {
4224 var canceled = module.set.date(date) === false;
4225 if (!canceled) {
4226 selectionComplete = true;
4227 if (settings.closable) {
4228 module.popup('hide');
4229 // if this is a range calendar, focus the container or input. This will open the popup from its event listeners.
4230 var endModule = module.get.calendarModule(settings.endCalendar);
4231 if (endModule) {
4232 endModule.refresh();
4233 if (endModule.setting('on') !== 'focus') {
4234 endModule.popup('show');
4235 }
4236 endModule.focus();
4237 }
4238 }
4239 }
4240 } else {
4241 var newMode = mode === 'year'
4242 ? (!settings.disableMonth ? 'month' : 'day')
4243 : (mode === 'month'
4244 ? 'day'
4245 : (mode === 'day' ? 'hour' : 'minute')); // eslint-disable-line unicorn/no-nested-ternary
4246 module.set.mode(newMode);
4247 if (mode === 'hour' || (mode === 'day' && module.get.date())) {
4248 // the user has chosen enough to consider a valid date/time has been chosen
4249 module.set.date(date, true, false);
4250 } else {
4251 module.set.focusDate(date);
4252 }
4253 }
4254 },
4255
4256 changeDate: function (date) {
4257 module.set.date(date);
4258 },
4259
4260 clear: function () {
4261 module.set.date();
4262 },
4263
4264 popup: function () {
4265 return $activator.popup.apply($activator, arguments);
4266 },
4267
4268 focus: function () {
4269 if ($input.length > 0) {
4270 $input.trigger('focus');
4271 } else {
4272 $container.trigger('focus');
4273 }
4274 },
4275 blur: function () {
4276 if ($input.length > 0) {
4277 $input.trigger('blur');
4278 } else {
4279 $container.trigger('blur');
4280 }
4281 },
4282
4283 helper: {
4284 dateFormat: function (format, date) {
4285 if (!(date instanceof Date)) {
4286 return '';
4287 }
4288 if (typeof format === 'function') {
4289 return format.call(module, date, settings);
4290 }
4291
4292 var
4293 D = date.getDate(),
4294 M = date.getMonth(),
4295 Y = date.getFullYear(),
4296 d = date.getDay(),
4297 H = date.getHours(),
4298 m = date.getMinutes(),
4299 s = date.getSeconds(),
4300 w = module.get.weekOfYear(Y, M, D + 1 - settings.firstDayOfWeek),
4301 h = H % 12 || 12,
4302 a = H < 12 ? settings.text.am.toLowerCase() : settings.text.pm.toLowerCase(),
4303 tokens = {
4304 D: D,
4305 DD: ('0' + D).slice(-2),
4306 M: M + 1,
4307 MM: ('0' + (M + 1)).slice(-2),
4308 MMM: settings.text.monthsShort[M],
4309 MMMM: settings.text.months[M],
4310 Y: Y,
4311 YY: String(Y).slice(2),
4312 YYYY: Y,
4313 d: d,
4314 dd: settings.text.dayNamesShort[d].slice(0, 2),
4315 ddd: settings.text.dayNamesShort[d],
4316 dddd: settings.text.dayNames[d],
4317 h: h,
4318 hh: ('0' + h).slice(-2),
4319 H: H,
4320 HH: ('0' + H).slice(-2),
4321 m: m,
4322 mm: ('0' + m).slice(-2),
4323 s: s,
4324 ss: ('0' + s).slice(-2),
4325 a: a,
4326 A: a.toUpperCase(),
4327 S: ['th', 'st', 'nd', 'rd'][(D % 10) > 3 ? 0 : ((D % 100) - (D % 10) === 10 ? 0 : D % 10)],
4328 w: w,
4329 ww: ('0' + w).slice(-2),
4330 }
4331 ;
4332
4333 return format.replace(settings.regExp.token, function (match) {
4334 if (match in tokens) {
4335 return tokens[match];
4336 }
4337
4338 return match.slice(1, -1);
4339 });
4340 },
4341 isDisabled: function (date, mode) {
4342 return (mode === 'day' || mode === 'month' || mode === 'year' || mode === 'hour') && (((mode === 'day' && settings.disabledDaysOfWeek.indexOf(date.getDay()) !== -1) || settings.disabledDates.some(function (d) {
4343 var blocked = false;
4344
4345 if (typeof d === 'string') {
4346 d = module.helper.sanitiseDate(d);
4347 }
4348 if (d instanceof Date) {
4349 blocked = module.helper.dateEqual(date, d, mode);
4350 } else if (d !== null && typeof d === 'object') {
4351 if (d[metadata.year]) {
4352 if (typeof d[metadata.year] === 'number') {
4353 blocked = date.getFullYear() === d[metadata.year];
4354 } else if (Array.isArray(d[metadata.year])) {
4355 blocked = d[metadata.year].indexOf(date.getFullYear()) > -1;
4356 }
4357 } else if (d[metadata.month]) {
4358 if (typeof d[metadata.month] === 'number') {
4359 blocked = date.getMonth() === d[metadata.month];
4360 } else if (Array.isArray(d[metadata.month])) {
4361 blocked = d[metadata.month].indexOf(date.getMonth()) > -1;
4362 } else if (d[metadata.month] instanceof Date) {
4363 var sdate = module.helper.sanitiseDate(d[metadata.month]);
4364
4365 blocked = (date.getMonth() === sdate.getMonth()) && (date.getFullYear() === sdate.getFullYear());
4366 }
4367 } else if (d[metadata.date] && mode === 'day') {
4368 if (d[metadata.date] instanceof Date) {
4369 blocked = module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode);
4370 } else if (Array.isArray(d[metadata.date])) {
4371 blocked = d[metadata.date].some(function (idate) {
4372 return module.helper.dateEqual(date, idate, mode);
4373 });
4374 }
4375 }
4376 }
4377
4378 return blocked;
4379 })) || (mode === 'hour' && settings.disabledHours.some(function (d) {
4380 var blocked = false;
4381
4382 if (typeof d === 'string') {
4383 d = module.helper.sanitiseDate(d);
4384 }
4385 if (d instanceof Date) {
4386 blocked = module.helper.dateEqual(date, d, mode);
4387 } else if (typeof d === 'number') {
4388 blocked = date.getHours() === d;
4389 } else if (d !== null && typeof d === 'object') {
4390 if (d[metadata.date]) {
4391 if (d[metadata.date] instanceof Date) {
4392 blocked = module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]));
4393 } else if (Array.isArray(d[metadata.date])) {
4394 blocked = d[metadata.date].some(function (idate) {
4395 return module.helper.dateEqual(date, idate, mode);
4396 });
4397 }
4398 }
4399
4400 if (d[metadata.days]) {
4401 if (typeof d[metadata.days] === 'number') {
4402 blocked = date.getDay() === d[metadata.days];
4403 } else if (Array.isArray(d[metadata.days])) {
4404 blocked = d[metadata.days].indexOf(date.getDay()) > -1;
4405 }
4406 }
4407
4408 if (d[metadata.hours]) {
4409 if (typeof d[metadata.hours] === 'number') {
4410 blocked = blocked && date.getHours() === d[metadata.hours];
4411 } else if (Array.isArray(d[metadata.hours])) {
4412 blocked = blocked && d[metadata.hours].indexOf(date.getHours()) > -1;
4413 }
4414 }
4415 }
4416
4417 return blocked;
4418 })));
4419 },
4420 isEnabled: function (date, mode) {
4421 if (mode === 'day') {
4422 return settings.enabledDates.length === 0 || settings.enabledDates.some(function (d) {
4423 var enabled = false;
4424
4425 if (typeof d === 'string') {
4426 d = module.helper.sanitiseDate(d);
4427 }
4428 if (d instanceof Date) {
4429 enabled = module.helper.dateEqual(date, d, mode);
4430 } else if (d !== null && typeof d === 'object' && d[metadata.date]) {
4431 enabled = module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode);
4432 }
4433
4434 return enabled;
4435 });
4436 }
4437
4438 return true;
4439 },
4440 findDayAsObject: function (date, mode, dates) {
4441 if (mode === 'day' || mode === 'month' || mode === 'year') {
4442 var d;
4443 for (var i = 0; i < dates.length; i++) {
4444 d = dates[i];
4445 if (typeof d === 'string') {
4446 d = module.helper.sanitiseDate(d);
4447 }
4448 if (d instanceof Date && module.helper.dateEqual(date, d, mode)) {
4449 var dateObject = {};
4450 dateObject[metadata.date] = d;
4451
4452 return dateObject;
4453 }
4454 if (d !== null && typeof d === 'object') {
4455 if (d[metadata.year]) {
4456 if (typeof d[metadata.year] === 'number' && date.getFullYear() === d[metadata.year]) {
4457 return d;
4458 }
4459 if (Array.isArray(d[metadata.year])) {
4460 if (d[metadata.year].indexOf(date.getFullYear()) > -1) {
4461 return d;
4462 }
4463 }
4464 } else if (d[metadata.month]) {
4465 if (typeof d[metadata.month] === 'number' && date.getMonth() === d[metadata.month]) {
4466 return d;
4467 }
4468 if (Array.isArray(d[metadata.month])) {
4469 if (d[metadata.month].indexOf(date.getMonth()) > -1) {
4470 return d;
4471 }
4472 } else if (d[metadata.month] instanceof Date) {
4473 var sdate = module.helper.sanitiseDate(d[metadata.month]);
4474 if ((date.getMonth() === sdate.getMonth()) && (date.getFullYear() === sdate.getFullYear())) {
4475 return d;
4476 }
4477 }
4478 } else if (d[metadata.date] && mode === 'day') {
4479 if (d[metadata.date] instanceof Date && module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode)) {
4480 return d;
4481 }
4482 if (Array.isArray(d[metadata.date])) {
4483 if (d[metadata.date].some(function (idate) {
4484 return module.helper.dateEqual(date, idate, mode);
4485 })) {
4486 return d;
4487 }
4488 }
4489 }
4490 }
4491 }
4492 }
4493
4494 return null;
4495 },
4496 findHourAsObject: function (date, mode, hours) {
4497 if (mode === 'hour') {
4498 var d;
4499 var hourCheck = function (date, d) {
4500 if (d[metadata.hours]) {
4501 if (typeof d[metadata.hours] === 'number' && date.getHours() === d[metadata.hours]) {
4502 return d;
4503 }
4504 if (Array.isArray(d[metadata.hours])) {
4505 if (d[metadata.hours].indexOf(date.getHours()) > -1) {
4506 return d;
4507 }
4508 }
4509 }
4510 };
4511 for (var i = 0; i < hours.length; i++) {
4512 d = hours[i];
4513 if (typeof d === 'number' && date.getHours() === d) {
4514 return null;
4515 }
4516 if (d !== null && typeof d === 'object') {
4517 if (d[metadata.days] && hourCheck(date, d)) {
4518 if (typeof d[metadata.days] === 'number' && date.getDay() === d[metadata.days]) {
4519 return d;
4520 }
4521 if (Array.isArray(d[metadata.days])) {
4522 if (d[metadata.days].indexOf(date.getDay()) > -1) {
4523 return d;
4524 }
4525 }
4526 } else if (d[metadata.date] && hourCheck(date, d)) {
4527 if (d[metadata.date] instanceof Date && module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]))) {
4528 return d;
4529 }
4530 if (Array.isArray(d[metadata.date])) {
4531 if (d[metadata.date].some(function (idate) {
4532 return module.helper.dateEqual(date, idate, mode);
4533 })) {
4534 return d;
4535 }
4536 }
4537 } else if (hourCheck(date, d)) {
4538 return d;
4539 }
4540 }
4541 }
4542 }
4543
4544 return null;
4545 },
4546 sanitiseDate: function (date) {
4547 if (!(date instanceof Date)) {
4548 date = parser.date('' + date, settings);
4549 }
4550 if (!date || isNaN(date.getTime())) {
4551 return null;
4552 }
4553
4554 return date;
4555 },
4556 dateDiff: function (date1, date2, mode) {
4557 if (!mode) {
4558 mode = 'day';
4559 }
4560
4561 var isTimeOnly = settings.type === 'time';
4562 var isYear = mode === 'year';
4563 var isYearOrMonth = isYear || mode === 'month';
4564 var isMinute = mode === 'minute';
4565 var isHourOrMinute = isMinute || mode === 'hour';
4566 // only care about a minute accuracy of settings.minTimeGap
4567 date1 = new Date(
4568 isTimeOnly ? 2000 : date1.getFullYear(),
4569 isTimeOnly ? 0 : (isYear ? 0 : date1.getMonth()),
4570 isTimeOnly ? 1 : (isYearOrMonth ? 1 : date1.getDate()),
4571 !isHourOrMinute ? 0 : date1.getHours(),
4572 !isMinute ? 0 : settings.minTimeGap * Math.floor(date1.getMinutes() / settings.minTimeGap)
4573 );
4574 date2 = new Date(
4575 isTimeOnly ? 2000 : date2.getFullYear(),
4576 isTimeOnly ? 0 : (isYear ? 0 : date2.getMonth()),
4577 isTimeOnly ? 1 : (isYearOrMonth ? 1 : date2.getDate()),
4578 !isHourOrMinute ? 0 : date2.getHours(),
4579 !isMinute ? 0 : settings.minTimeGap * Math.floor(date2.getMinutes() / settings.minTimeGap)
4580 );
4581
4582 return date2.getTime() - date1.getTime();
4583 },
4584 dateEqual: function (date1, date2, mode) {
4585 return !!date1 && !!date2 && module.helper.dateDiff(date1, date2, mode) === 0;
4586 },
4587 isDateInRange: function (date, mode, minDate, maxDate) {
4588 if (!minDate && !maxDate) {
4589 var startDate = module.get.startDate();
4590 minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate;
4591 maxDate = settings.maxDate;
4592 }
4593 minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap));
4594
4595 return !(!date
4596 || (minDate && module.helper.dateDiff(date, minDate, mode) > 0)
4597 || (maxDate && module.helper.dateDiff(maxDate, date, mode) > 0));
4598 },
4599 dateInRange: function (date, minDate, maxDate) {
4600 if (!minDate && !maxDate) {
4601 var startDate = module.get.startDate();
4602 minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate;
4603 maxDate = settings.maxDate;
4604 }
4605 minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap));
4606 var isTimeOnly = settings.type === 'time';
4607
4608 return !date
4609 ? date
4610 : (minDate && module.helper.dateDiff(date, minDate, 'minute') > 0
4611 ? (isTimeOnly ? module.helper.mergeDateTime(date, minDate) : minDate) // eslint-disable-line unicorn/no-nested-ternary
4612 : (maxDate && module.helper.dateDiff(maxDate, date, 'minute') > 0 // eslint-disable-line unicorn/no-nested-ternary
4613 ? (isTimeOnly ? module.helper.mergeDateTime(date, maxDate) : maxDate)
4614 : date));
4615 },
4616 mergeDateTime: function (date, time) {
4617 return !date || !time
4618 ? time
4619 : new Date(date.getFullYear(), date.getMonth(), date.getDate(), time.getHours(), time.getMinutes());
4620 },
4621 isTodayButton: function (element) {
4622 return element.text() === settings.text.today;
4623 },
4624 },
4625
4626 setting: function (name, value) {
4627 module.debug('Changing setting', name, value);
4628 if ($.isPlainObject(name)) {
4629 $.extend(true, settings, name);
4630 } else if (value !== undefined) {
4631 if ($.isPlainObject(settings[name])) {
4632 $.extend(true, settings[name], value);
4633 } else {
4634 settings[name] = value;
4635 }
4636 } else {
4637 return settings[name];
4638 }
4639 },
4640 internal: function (name, value) {
4641 if ($.isPlainObject(name)) {
4642 $.extend(true, module, name);
4643 } else if (value !== undefined) {
4644 module[name] = value;
4645 } else {
4646 return module[name];
4647 }
4648 },
4649 debug: function () {
4650 if (!settings.silent && settings.debug) {
4651 if (settings.performance) {
4652 module.performance.log(arguments);
4653 } else {
4654 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
4655 module.debug.apply(console, arguments);
4656 }
4657 }
4658 },
4659 verbose: function () {
4660 if (!settings.silent && settings.verbose && settings.debug) {
4661 if (settings.performance) {
4662 module.performance.log(arguments);
4663 } else {
4664 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
4665 module.verbose.apply(console, arguments);
4666 }
4667 }
4668 },
4669 error: function () {
4670 if (!settings.silent) {
4671 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
4672 module.error.apply(console, arguments);
4673 }
4674 },
4675 performance: {
4676 log: function (message) {
4677 var
4678 currentTime,
4679 executionTime,
4680 previousTime
4681 ;
4682 if (settings.performance) {
4683 currentTime = Date.now();
4684 previousTime = time || currentTime;
4685 executionTime = currentTime - previousTime;
4686 time = currentTime;
4687 performance.push({
4688 Name: message[0],
4689 Arguments: [].slice.call(message, 1) || '',
4690 Element: element,
4691 'Execution Time': executionTime,
4692 });
4693 }
4694 clearTimeout(module.performance.timer);
4695 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
4696 },
4697 display: function () {
4698 var
4699 title = settings.name + ':',
4700 totalTime = 0
4701 ;
4702 time = false;
4703 clearTimeout(module.performance.timer);
4704 $.each(performance, function (index, data) {
4705 totalTime += data['Execution Time'];
4706 });
4707 title += ' ' + totalTime + 'ms';
4708 if (performance.length > 0) {
4709 console.groupCollapsed(title);
4710 if (console.table) {
4711 console.table(performance);
4712 } else {
4713 $.each(performance, function (index, data) {
4714 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
4715 });
4716 }
4717 console.groupEnd();
4718 }
4719 performance = [];
4720 },
4721 },
4722 invoke: function (query, passedArguments, context) {
4723 var
4724 object = instance,
4725 maxDepth,
4726 found,
4727 response
4728 ;
4729 passedArguments = passedArguments || queryArguments;
4730 context = context || element;
4731 if (typeof query === 'string' && object !== undefined) {
4732 query = query.split(/[ .]/);
4733 maxDepth = query.length - 1;
4734 $.each(query, function (depth, value) {
4735 var camelCaseValue = depth !== maxDepth
4736 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
4737 : query
4738 ;
4739 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
4740 object = object[camelCaseValue];
4741 } else if (object[camelCaseValue] !== undefined) {
4742 found = object[camelCaseValue];
4743
4744 return false;
4745 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
4746 object = object[value];
4747 } else if (object[value] !== undefined) {
4748 found = object[value];
4749
4750 return false;
4751 } else {
4752 module.error(error.method, query);
4753
4754 return false;
4755 }
4756 });
4757 }
4758 if (isFunction(found)) {
4759 response = found.apply(context, passedArguments);
4760 } else if (found !== undefined) {
4761 response = found;
4762 }
4763 if (Array.isArray(returnedValue)) {
4764 returnedValue.push(response);
4765 } else if (returnedValue !== undefined) {
4766 returnedValue = [returnedValue, response];
4767 } else if (response !== undefined) {
4768 returnedValue = response;
4769 }
4770
4771 return found;
4772 },
4773 };
4774
4775 if (methodInvoked) {
4776 if (instance === undefined) {
4777 module.initialize();
4778 }
4779 module.invoke(query);
4780 } else {
4781 if (instance !== undefined) {
4782 instance.invoke('destroy');
4783 }
4784 module.initialize();
4785 }
4786 });
4787
4788 return returnedValue !== undefined
4789 ? returnedValue
4790 : this;
4791 };
4792
4793 $.fn.calendar.settings = {
4794
4795 name: 'Calendar',
4796 namespace: 'calendar',
4797
4798 silent: false,
4799 debug: false,
4800 verbose: false,
4801 performance: true,
4802
4803 context: false,
4804
4805 type: 'datetime', // picker type, can be 'datetime', 'date', 'time', 'month', or 'year'
4806 firstDayOfWeek: 0, // day for first day column (0 = Sunday)
4807 constantHeight: true, // add rows to shorter months to keep day calendar height consistent (6 rows)
4808 today: false, // show a 'today/now' button at the bottom of the calendar
4809 closable: true, // close the popup after selecting a date/time
4810 monthFirst: true, // month before day when parsing date from text
4811 touchReadonly: true, // set input to readonly on touch devices
4812 inline: false, // create the calendar inline instead of inside a popup
4813 on: null, // when to show the popup (defaults to 'focus' for input, 'click' for others)
4814 initialDate: null, // date to display initially when no date is selected (null = now)
4815 startMode: false, // display mode to start in, can be 'year', 'month', 'day', 'hour', 'minute' (false = 'day')
4816 minDate: null, // minimum date/time that can be selected, dates/times before are disabled
4817 maxDate: null, // maximum date/time that can be selected, dates/times after are disabled
4818 disableYear: false, // disable year selection mode
4819 disableMonth: false, // disable month selection mode
4820 disableMinute: false, // disable minute selection mode
4821 formatInput: true, // format the input text upon input blur and module creation
4822 startCalendar: null, // jquery object or selector for another calendar that represents the start date of a date range
4823 endCalendar: null, // jquery object or selector for another calendar that represents the end date of a date range
4824 multiMonth: 1, // show multiple months when in 'day' mode
4825 monthOffset: 0, // position current month by offset when multimonth > 1
4826 minTimeGap: 5,
4827 showWeekNumbers: false, // show Number of Week at the very first column of a dayView
4828 disabledHours: [], // specific hour(s) which won't be selectable and contain additional information.
4829 disabledDates: [], // specific day(s) which won't be selectable and contain additional information.
4830 disabledDaysOfWeek: [], // day(s) which won't be selectable(s) (0 = Sunday)
4831 enabledDates: [], // specific day(s) which will be selectable, all other days will be disabled
4832 eventDates: [], // specific day(s) which will be shown in a different color and using tooltips
4833 centuryBreak: 60, // starting short year until 99 where it will be assumed to belong to the last century
4834 currentCentury: 2000, // century to be added to 2-digit years (00 to {centuryBreak}-1)
4835 selectAdjacentDays: false, // The calendar can show dates from adjacent month. These adjacent month dates can also be made selectable.
4836 // popup options ('popup', 'on', 'hoverable', and show/hide callbacks are overridden)
4837 popupOptions: {
4838 position: 'bottom left',
4839 lastResort: 'bottom left',
4840 prefer: 'opposite',
4841 observeChanges: false,
4842 hideOnScroll: false,
4843 },
4844
4845 text: {
4846 days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
4847 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
4848 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
4849 months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
4850 monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
4851 today: 'Today',
4852 now: 'Now',
4853 am: 'AM',
4854 pm: 'PM',
4855 weekNo: 'Week',
4856 },
4857
4858 formatter: {
4859 yearHeader: function (date, settings) {
4860 var decadeYear = Math.ceil(date.getFullYear() / 10) * 10;
4861
4862 return (decadeYear - 9) + ' - ' + (decadeYear + 2);
4863 },
4864 monthHeader: 'YYYY',
4865 dayHeader: 'MMMM YYYY',
4866 hourHeader: 'MMMM D, YYYY',
4867 minuteHeader: 'MMMM D, YYYY',
4868 dayColumnHeader: function (day, settings) {
4869 return settings.text.days[day];
4870 },
4871 datetime: 'MMMM D, YYYY h:mm A',
4872 date: 'MMMM D, YYYY',
4873 time: 'h:mm A',
4874 cellTime: 'h:mm A',
4875 month: 'MMMM YYYY',
4876 year: 'YYYY',
4877 today: function (settings) {
4878 return settings.type === 'date' ? settings.text.today : settings.text.now;
4879 },
4880 cell: function (cell, date, cellOptions) {},
4881 },
4882
4883 parser: {
4884 date: function (text, settings) {
4885 if (text instanceof Date) {
4886 return text;
4887 }
4888 if (!text) {
4889 return null;
4890 }
4891 text = String(text).trim().replace(/([./:-])\s+/g, '$1').replace(/\s+([./:-])/g, '$1')
4892 .replace(/\s+/g, ' ');
4893 if (text.length === 0) {
4894 return null;
4895 }
4896 if (/^\d{4}(?:[./-]\d{1,2}){2}$/.test(text)) {
4897 text = text.replace(/[./-]/g, '/') + ' 00:00:00';
4898 }
4899 // Reverse date and month in some cases
4900 text = settings.monthFirst || !/^\d{1,2}[./-]/.test(text) ? text : text.replace(/[./-]/g, '/').replace(/(\d+)\/(\d+)/, '$2/$1');
4901 var textDate = new Date(text);
4902 var numberOnly = text.match(/^\d+$/) !== null;
4903 if (!numberOnly && !isNaN(textDate.getDate())) {
4904 return textDate;
4905 }
4906 text = text.toLowerCase();
4907
4908 var
4909 i,
4910 j,
4911 k
4912 ;
4913 var
4914 minute = -1,
4915 hour = -1,
4916 day = -1,
4917 month = -1,
4918 year = -1
4919 ;
4920 var isAm;
4921
4922 var isTimeOnly = settings.type === 'time';
4923 var isDateOnly = settings.type.indexOf('time') < 0;
4924
4925 var
4926 words = text.split(settings.regExp.dateWords),
4927 word
4928 ;
4929 var
4930 numbers = text.split(settings.regExp.dateNumbers),
4931 number
4932 ;
4933
4934 var parts;
4935 var monthString;
4936
4937 if (!isDateOnly) {
4938 // am/pm
4939 isAm = $.inArray(settings.text.am.toLowerCase(), words) >= 0
4940 ? true
4941 : ($.inArray(settings.text.pm.toLowerCase(), words) >= 0 ? false : undefined);
4942
4943 // time with ':'
4944 for (i = 0; i < numbers.length; i++) {
4945 number = numbers[i];
4946 if (number.indexOf(':') >= 0) {
4947 if (hour < 0 || minute < 0) {
4948 parts = number.split(':');
4949 for (k = 0; k < Math.min(2, parts.length); k++) {
4950 j = parseInt(parts[k], 10);
4951 if (isNaN(j)) {
4952 j = 0;
4953 }
4954 if (k === 0) {
4955 hour = j % 24;
4956 } else {
4957 minute = j % 60;
4958 }
4959 }
4960 }
4961 numbers.splice(i, 1);
4962 }
4963 }
4964 }
4965
4966 if (!isTimeOnly) {
4967 // textual month
4968 for (i = 0; i < words.length; i++) {
4969 word = words[i];
4970 if (word.length <= 0) {
4971 continue;
4972 }
4973 for (j = 0; j < settings.text.months.length; j++) {
4974 monthString = settings.text.months[j];
4975 monthString = monthString.slice(0, word.length).toLowerCase();
4976 if (monthString === word) {
4977 month = j + 1;
4978
4979 break;
4980 }
4981 }
4982 if (month >= 0) {
4983 break;
4984 }
4985 }
4986
4987 // year > settings.centuryBreak
4988 for (i = 0; i < numbers.length; i++) {
4989 j = parseInt(numbers[i], 10);
4990 if (isNaN(j)) {
4991 continue;
4992 }
4993 if (j >= settings.centuryBreak && i === numbers.length - 1) {
4994 if (j <= 99) {
4995 j += settings.currentCentury - 100;
4996 }
4997 year = j;
4998 numbers.splice(i, 1);
4999
5000 break;
5001 }
5002 }
5003
5004 // numeric month
5005 if (month < 0) {
5006 for (i = 0; i < numbers.length; i++) {
5007 k = i > 1 || settings.monthFirst
5008 ? i
5009 : (i === 1 ? 0 : 1);
5010 j = parseInt(numbers[k], 10);
5011 if (isNaN(j)) {
5012 continue;
5013 }
5014 if (j >= 1 && j <= 12) {
5015 month = j;
5016 numbers.splice(k, 1);
5017
5018 break;
5019 }
5020 }
5021 }
5022
5023 // day
5024 for (i = 0; i < numbers.length; i++) {
5025 j = parseInt(numbers[i], 10);
5026 if (isNaN(j)) {
5027 continue;
5028 }
5029 if (j >= 1 && j <= 31) {
5030 day = j;
5031 numbers.splice(i, 1);
5032
5033 break;
5034 }
5035 }
5036
5037 // year <= settings.centuryBreak
5038 if (year < 0) {
5039 for (i = numbers.length - 1; i >= 0; i--) {
5040 j = parseInt(numbers[i], 10);
5041 if (isNaN(j)) {
5042 continue;
5043 }
5044 if (j <= 99) {
5045 j += settings.currentCentury;
5046 }
5047 year = j;
5048 numbers.splice(i, 1);
5049
5050 break;
5051 }
5052 }
5053 }
5054
5055 if (!isDateOnly) {
5056 // hour
5057 if (hour < 0) {
5058 for (i = 0; i < numbers.length; i++) {
5059 j = parseInt(numbers[i], 10);
5060 if (isNaN(j)) {
5061 continue;
5062 }
5063 if (j >= 0 && j <= 23) {
5064 hour = j;
5065 numbers.splice(i, 1);
5066
5067 break;
5068 }
5069 }
5070 }
5071
5072 // minute
5073 if (minute < 0) {
5074 for (i = 0; i < numbers.length; i++) {
5075 j = parseInt(numbers[i], 10);
5076 if (isNaN(j)) {
5077 continue;
5078 }
5079 if (j >= 0 && j <= 59) {
5080 minute = j;
5081 numbers.splice(i, 1);
5082
5083 break;
5084 }
5085 }
5086 }
5087 }
5088
5089 if (minute < 0 && hour < 0 && day < 0 && month < 0 && year < 0) {
5090 return null;
5091 }
5092
5093 if (minute < 0) {
5094 minute = 0;
5095 }
5096 if (hour < 0) {
5097 hour = 0;
5098 }
5099 if (day < 0) {
5100 day = 1;
5101 }
5102 if (month < 0) {
5103 month = 1;
5104 }
5105 if (year < 0) {
5106 year = new Date().getFullYear();
5107 }
5108
5109 if (isAm !== undefined) {
5110 if (isAm) {
5111 if (hour === 12) {
5112 hour = 0;
5113 }
5114 } else if (hour < 12) {
5115 hour += 12;
5116 }
5117 }
5118
5119 var date = new Date(year, month - 1, day, hour, minute);
5120 if (date.getMonth() !== month - 1 || date.getFullYear() !== year) {
5121 // month or year don't match up, switch to last day of the month
5122 date = new Date(year, month, 0, hour, minute);
5123 }
5124
5125 return isNaN(date.getTime()) ? null : date;
5126 },
5127 },
5128
5129 // callback before date is changed, return false to cancel the change
5130 onBeforeChange: function (date, text, mode) {
5131 return true;
5132 },
5133
5134 // callback when date changes
5135 onChange: function (date, text, mode) {},
5136
5137 // callback before show animation, return false to prevent show
5138 onShow: function () {},
5139
5140 // callback after show animation
5141 onVisible: function () {},
5142
5143 // callback before hide animation, return false to prevent hide
5144 onHide: function () {},
5145
5146 // callback after hide animation
5147 onHidden: function () {},
5148
5149 // callback before item is selected, return false to prevent selection
5150 onSelect: function (date, mode) {},
5151
5152 // is the given date disabled?
5153 isDisabled: function (date, mode) {
5154 return false;
5155 },
5156
5157 selector: {
5158 popup: '.ui.popup',
5159 input: 'input',
5160 activator: 'input',
5161 append: '.inline.field,.inline.fields',
5162 },
5163
5164 regExp: {
5165 dateWords: /[^A-Za-z\u00C0-\u024F]+/g,
5166 dateNumbers: /[^\d:]+/g,
5167 token: /d{1,4}|D{1,2}|M{1,4}|YY(?:YY)?|([Hhmsw])\1?|[ASYa]|"[^"]*"|'[^']*'/g,
5168 },
5169
5170 error: {
5171 popup: 'UI Popup, a required component is not included in this page',
5172 method: 'The method you called is not defined.',
5173 },
5174
5175 className: {
5176 calendar: 'calendar',
5177 active: 'active',
5178 popup: 'ui popup',
5179 grid: 'ui equal width grid',
5180 column: 'column',
5181 table: 'ui celled center aligned unstackable table',
5182 inverted: 'inverted',
5183 prev: 'prev link',
5184 next: 'next link',
5185 prevIcon: 'chevron left icon',
5186 nextIcon: 'chevron right icon',
5187 link: 'link',
5188 cell: 'link',
5189 disabledCell: 'disabled',
5190 weekCell: 'disabled',
5191 adjacentCell: 'adjacent',
5192 activeCell: 'active',
5193 rangeCell: 'range',
5194 focusCell: 'focus',
5195 todayCell: 'today',
5196 today: 'today link',
5197 disabled: 'disabled',
5198 },
5199
5200 metadata: {
5201 date: 'date',
5202 focusDate: 'focusDate',
5203 startDate: 'startDate',
5204 endDate: 'endDate',
5205 minDate: 'minDate',
5206 maxDate: 'maxDate',
5207 mode: 'mode',
5208 type: 'type',
5209 monthOffset: 'monthOffset',
5210 message: 'message',
5211 class: 'class',
5212 inverted: 'inverted',
5213 variation: 'variation',
5214 position: 'position',
5215 month: 'month',
5216 year: 'year',
5217 hours: 'hours',
5218 days: 'days',
5219 },
5220
5221 eventClass: 'blue',
5222 };
5223})(jQuery, window, document);
5224
5225/*!
5226 * # Fomantic-UI 2.9.3 - Checkbox
5227 * https://github.com/fomantic/Fomantic-UI/
5228 *
5229 *
5230 * Released under the MIT license
5231 * https://opensource.org/licenses/MIT
5232 *
5233 */
5234
5235(function ($, window, document) {
5236 'use strict';
5237
5238 function isFunction(obj) {
5239 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
5240 }
5241
5242 window = window !== undefined && window.Math === Math
5243 ? window
5244 : globalThis;
5245
5246 $.fn.checkbox = function (parameters) {
5247 var
5248 $allModules = $(this),
5249
5250 time = Date.now(),
5251 performance = [],
5252
5253 query = arguments[0],
5254 methodInvoked = typeof query === 'string',
5255 queryArguments = [].slice.call(arguments, 1),
5256 returnedValue
5257 ;
5258
5259 $allModules.each(function () {
5260 var
5261 settings = $.extend(true, {}, $.fn.checkbox.settings, parameters),
5262
5263 className = settings.className,
5264 namespace = settings.namespace,
5265 selector = settings.selector,
5266 error = settings.error,
5267
5268 eventNamespace = '.' + namespace,
5269 moduleNamespace = 'module-' + namespace,
5270
5271 $module = $(this),
5272 $label = $(this).children(selector.label),
5273 $input = $(this).children(selector.input),
5274 input = $input[0],
5275
5276 initialLoad = false,
5277 shortcutPressed = false,
5278 instance = $module.data(moduleNamespace),
5279
5280 observer,
5281 element = this,
5282 module
5283 ;
5284
5285 module = {
5286
5287 initialize: function () {
5288 module.verbose('Initializing checkbox', settings);
5289
5290 module.create.label();
5291 module.bind.events();
5292
5293 module.set.tabbable();
5294 module.hide.input();
5295
5296 module.observeChanges();
5297 module.instantiate();
5298 module.setup();
5299 },
5300
5301 instantiate: function () {
5302 module.verbose('Storing instance of module', module);
5303 instance = module;
5304 $module
5305 .data(moduleNamespace, module)
5306 ;
5307 },
5308
5309 destroy: function () {
5310 module.verbose('Destroying module');
5311 module.unbind.events();
5312 module.show.input();
5313 $module.removeData(moduleNamespace);
5314 },
5315
5316 fix: {
5317 reference: function () {
5318 if ($module.is(selector.input)) {
5319 module.debug('Behavior called on <input> adjusting invoked element');
5320 $module = $module.closest(selector.checkbox);
5321 module.refresh();
5322 }
5323 },
5324 },
5325
5326 setup: function () {
5327 module.set.initialLoad();
5328 if (module.is.indeterminate()) {
5329 module.debug('Initial value is indeterminate');
5330 module.indeterminate();
5331 } else if (module.is.checked()) {
5332 module.debug('Initial value is checked');
5333 module.check();
5334 } else {
5335 module.debug('Initial value is unchecked');
5336 module.uncheck();
5337 }
5338 module.remove.initialLoad();
5339 },
5340
5341 refresh: function () {
5342 $label = $module.children(selector.label);
5343 $input = $module.children(selector.input);
5344 input = $input[0];
5345 },
5346
5347 hide: {
5348 input: function () {
5349 module.verbose('Modifying <input> z-index to be unselectable');
5350 $input.addClass(className.hidden);
5351 },
5352 },
5353 show: {
5354 input: function () {
5355 module.verbose('Modifying <input> z-index to be selectable');
5356 $input.removeClass(className.hidden);
5357 },
5358 },
5359
5360 observeChanges: function () {
5361 if ('MutationObserver' in window) {
5362 observer = new MutationObserver(function (mutations) {
5363 module.debug('DOM tree modified, updating selector cache');
5364 module.refresh();
5365 });
5366 observer.observe(element, {
5367 childList: true,
5368 subtree: true,
5369 });
5370 module.debug('Setting up mutation observer', observer);
5371 }
5372 },
5373
5374 attachEvents: function (selector, event) {
5375 var
5376 $element = $(selector)
5377 ;
5378 event = isFunction(module[event])
5379 ? module[event]
5380 : module.toggle;
5381 if ($element.length > 0) {
5382 module.debug('Attaching checkbox events to element', selector, event);
5383 $element
5384 .on('click' + eventNamespace, event)
5385 ;
5386 } else {
5387 module.error(error.notFound);
5388 }
5389 },
5390
5391 preventDefaultOnInputTarget: function () {
5392 if (event !== undefined && event !== null && $(event.target).is(selector.input)) {
5393 module.verbose('Preventing default check action after manual check action');
5394 event.preventDefault();
5395 }
5396 },
5397
5398 event: {
5399 change: function (event) {
5400 if (!module.should.ignoreCallbacks()) {
5401 settings.onChange.call(input);
5402 }
5403 },
5404 click: function (event) {
5405 var
5406 $target = $(event.target)
5407 ;
5408 if ($target.is(selector.input)) {
5409 module.verbose('Using default check action on initialized checkbox');
5410
5411 return;
5412 }
5413 if ($target.is(selector.link)) {
5414 module.debug('Clicking link inside checkbox, skipping toggle');
5415
5416 return;
5417 }
5418 module.toggle();
5419 $input.trigger('focus');
5420 event.preventDefault();
5421 },
5422 keydown: function (event) {
5423 var
5424 key = event.which,
5425 keyCode = {
5426 enter: 13,
5427 space: 32,
5428 escape: 27,
5429 left: 37,
5430 up: 38,
5431 right: 39,
5432 down: 40,
5433 }
5434 ;
5435
5436 var
5437 r = module.get.radios(),
5438 rIndex = r.index($module),
5439 rLen = r.length,
5440 checkIndex = false
5441 ;
5442
5443 if (key === keyCode.left || key === keyCode.up) {
5444 checkIndex = (rIndex === 0 ? rLen : rIndex) - 1;
5445 } else if (key === keyCode.right || key === keyCode.down) {
5446 checkIndex = rIndex === rLen - 1 ? 0 : rIndex + 1;
5447 }
5448
5449 if (!module.should.ignoreCallbacks() && checkIndex !== false) {
5450 if (settings.beforeUnchecked.apply(input) === false) {
5451 module.verbose('Option not allowed to be unchecked, cancelling key navigation');
5452
5453 return false;
5454 }
5455 if (settings.beforeChecked.apply($(r[checkIndex]).children(selector.input)[0]) === false) {
5456 module.verbose('Next option should not allow check, cancelling key navigation');
5457
5458 return false;
5459 }
5460 }
5461
5462 shortcutPressed = false;
5463 if (key === keyCode.escape) {
5464 module.verbose('Escape key pressed blurring field');
5465 $input.trigger('blur');
5466 shortcutPressed = true;
5467 event.stopPropagation();
5468 } else if (!module.can.change()) {
5469 shortcutPressed = true;
5470 } else if (!event.ctrlKey) {
5471 if (key === keyCode.space || (key === keyCode.enter && settings.enableEnterKey)) {
5472 module.verbose('Enter/space key pressed, toggling checkbox');
5473 module.toggle();
5474 shortcutPressed = true;
5475 } else if ($module.is('.toggle, .slider') && !module.is.radio()) {
5476 if (key === keyCode.left && module.is.checked()) {
5477 module.uncheck();
5478 shortcutPressed = true;
5479 } else if (key === keyCode.right && module.is.unchecked()) {
5480 module.check();
5481 shortcutPressed = true;
5482 }
5483 }
5484 }
5485 },
5486 keyup: function (event) {
5487 if (shortcutPressed) {
5488 event.preventDefault();
5489 }
5490 },
5491 },
5492
5493 check: function () {
5494 if (!module.should.allowCheck()) {
5495 return;
5496 }
5497 module.debug('Checking checkbox', $input);
5498 module.set.checked();
5499 if (!module.should.ignoreCallbacks()) {
5500 settings.onChecked.call(input);
5501 module.trigger.change();
5502 }
5503 module.preventDefaultOnInputTarget();
5504 },
5505
5506 uncheck: function () {
5507 if (!module.should.allowUncheck()) {
5508 return;
5509 }
5510 module.debug('Unchecking checkbox');
5511 module.set.unchecked();
5512 if (!module.should.ignoreCallbacks()) {
5513 settings.onUnchecked.call(input);
5514 module.trigger.change();
5515 }
5516 module.preventDefaultOnInputTarget();
5517 },
5518
5519 indeterminate: function () {
5520 if (module.should.allowIndeterminate()) {
5521 module.debug('Checkbox is already indeterminate');
5522
5523 return;
5524 }
5525 module.debug('Making checkbox indeterminate');
5526 module.set.indeterminate();
5527 if (!module.should.ignoreCallbacks()) {
5528 settings.onIndeterminate.call(input);
5529 module.trigger.change();
5530 }
5531 },
5532
5533 determinate: function () {
5534 if (module.should.allowDeterminate()) {
5535 module.debug('Checkbox is already determinate');
5536
5537 return;
5538 }
5539 module.debug('Making checkbox determinate');
5540 module.set.determinate();
5541 if (!module.should.ignoreCallbacks()) {
5542 settings.onDeterminate.call(input);
5543 module.trigger.change();
5544 }
5545 },
5546
5547 enable: function () {
5548 if (module.is.enabled()) {
5549 module.debug('Checkbox is already enabled');
5550
5551 return;
5552 }
5553 module.debug('Enabling checkbox');
5554 module.set.enabled();
5555 if (!module.should.ignoreCallbacks()) {
5556 settings.onEnable.call(input);
5557 // preserve legacy callbacks
5558 settings.onEnabled.call(input);
5559 }
5560 },
5561
5562 disable: function () {
5563 if (module.is.disabled()) {
5564 module.debug('Checkbox is already disabled');
5565
5566 return;
5567 }
5568 module.debug('Disabling checkbox');
5569 module.set.disabled();
5570 if (!module.should.ignoreCallbacks()) {
5571 settings.onDisable.call(input);
5572 // preserve legacy callbacks
5573 settings.onDisabled.call(input);
5574 }
5575 },
5576
5577 get: {
5578 radios: function () {
5579 var
5580 name = module.get.name()
5581 ;
5582
5583 return $('input[name="' + name + '"]').closest(selector.checkbox);
5584 },
5585 otherRadios: function () {
5586 return module.get.radios().not($module);
5587 },
5588 name: function () {
5589 return $input.attr('name');
5590 },
5591 },
5592
5593 is: {
5594 initialLoad: function () {
5595 return initialLoad;
5596 },
5597 radio: function () {
5598 return $input.hasClass(className.radio) || $input.attr('type') === 'radio';
5599 },
5600 indeterminate: function () {
5601 return $input.prop('indeterminate') !== undefined && $input.prop('indeterminate');
5602 },
5603 checked: function () {
5604 return $input.prop('checked') !== undefined && $input.prop('checked');
5605 },
5606 disabled: function () {
5607 return $input.prop('disabled') !== undefined && $input.prop('disabled');
5608 },
5609 enabled: function () {
5610 return !module.is.disabled();
5611 },
5612 determinate: function () {
5613 return !module.is.indeterminate();
5614 },
5615 unchecked: function () {
5616 return !module.is.checked();
5617 },
5618 },
5619
5620 should: {
5621 allowCheck: function () {
5622 if (module.is.determinate() && module.is.checked() && !module.is.initialLoad()) {
5623 module.debug('Should not allow check, checkbox is already checked');
5624
5625 return false;
5626 }
5627 if (!module.should.ignoreCallbacks() && settings.beforeChecked.apply(input) === false) {
5628 module.debug('Should not allow check, beforeChecked cancelled');
5629
5630 return false;
5631 }
5632
5633 return true;
5634 },
5635 allowUncheck: function () {
5636 if (module.is.determinate() && module.is.unchecked() && !module.is.initialLoad()) {
5637 module.debug('Should not allow uncheck, checkbox is already unchecked');
5638
5639 return false;
5640 }
5641 if (!module.should.ignoreCallbacks() && settings.beforeUnchecked.apply(input) === false) {
5642 module.debug('Should not allow uncheck, beforeUnchecked cancelled');
5643
5644 return false;
5645 }
5646
5647 return true;
5648 },
5649 allowIndeterminate: function () {
5650 if (module.is.indeterminate() && !module.is.initialLoad()) {
5651 module.debug('Should not allow indeterminate, checkbox is already indeterminate');
5652
5653 return false;
5654 }
5655 if (!module.should.ignoreCallbacks() && settings.beforeIndeterminate.apply(input) === false) {
5656 module.debug('Should not allow indeterminate, beforeIndeterminate cancelled');
5657
5658 return false;
5659 }
5660
5661 return true;
5662 },
5663 allowDeterminate: function () {
5664 if (module.is.determinate() && !module.is.initialLoad()) {
5665 module.debug('Should not allow determinate, checkbox is already determinate');
5666
5667 return false;
5668 }
5669 if (!module.should.ignoreCallbacks() && settings.beforeDeterminate.apply(input) === false) {
5670 module.debug('Should not allow determinate, beforeDeterminate cancelled');
5671
5672 return false;
5673 }
5674
5675 return true;
5676 },
5677 ignoreCallbacks: function () {
5678 return initialLoad && !settings.fireOnInit;
5679 },
5680 },
5681
5682 can: {
5683 change: function () {
5684 return !($module.hasClass(className.disabled) || $module.hasClass(className.readOnly) || $input.prop('disabled') || $input.prop('readonly'));
5685 },
5686 uncheck: function () {
5687 return typeof settings.uncheckable === 'boolean'
5688 ? settings.uncheckable
5689 : !module.is.radio();
5690 },
5691 },
5692
5693 set: {
5694 initialLoad: function () {
5695 initialLoad = true;
5696 },
5697 checked: function () {
5698 module.verbose('Setting class to checked');
5699 $module
5700 .removeClass(className.indeterminate)
5701 .addClass(className.checked)
5702 ;
5703 if (module.is.radio()) {
5704 module.uncheckOthers();
5705 }
5706 if (!module.is.indeterminate() && module.is.checked()) {
5707 module.debug('Input is already checked, skipping input property change');
5708
5709 return;
5710 }
5711 module.verbose('Setting state to checked', input);
5712 $input
5713 .prop('indeterminate', false)
5714 .prop('checked', true)
5715 ;
5716 },
5717 unchecked: function () {
5718 module.verbose('Removing checked class');
5719 $module
5720 .removeClass(className.indeterminate)
5721 .removeClass(className.checked)
5722 ;
5723 if (!module.is.indeterminate() && module.is.unchecked()) {
5724 module.debug('Input is already unchecked');
5725
5726 return;
5727 }
5728 module.debug('Setting state to unchecked');
5729 $input
5730 .prop('indeterminate', false)
5731 .prop('checked', false)
5732 ;
5733 },
5734 indeterminate: function () {
5735 module.verbose('Setting class to indeterminate');
5736 $module
5737 .addClass(className.indeterminate)
5738 ;
5739 if (module.is.indeterminate()) {
5740 module.debug('Input is already indeterminate, skipping input property change');
5741
5742 return;
5743 }
5744 module.debug('Setting state to indeterminate');
5745 $input
5746 .prop('indeterminate', true)
5747 ;
5748 },
5749 determinate: function () {
5750 module.verbose('Removing indeterminate class');
5751 $module
5752 .removeClass(className.indeterminate)
5753 ;
5754 if (module.is.determinate()) {
5755 module.debug('Input is already determinate, skipping input property change');
5756
5757 return;
5758 }
5759 module.debug('Setting state to determinate');
5760 $input
5761 .prop('indeterminate', false)
5762 ;
5763 },
5764 disabled: function () {
5765 module.verbose('Setting class to disabled');
5766 $module
5767 .addClass(className.disabled)
5768 ;
5769 if (module.is.disabled()) {
5770 module.debug('Input is already disabled, skipping input property change');
5771
5772 return;
5773 }
5774 module.debug('Setting state to disabled');
5775 $input
5776 .prop('disabled', 'disabled')
5777 ;
5778 },
5779 enabled: function () {
5780 module.verbose('Removing disabled class');
5781 $module.removeClass(className.disabled);
5782 if (module.is.enabled()) {
5783 module.debug('Input is already enabled, skipping input property change');
5784
5785 return;
5786 }
5787 module.debug('Setting state to enabled');
5788 $input
5789 .prop('disabled', false)
5790 ;
5791 },
5792 tabbable: function () {
5793 module.verbose('Adding tabindex to checkbox');
5794 if ($input.attr('tabindex') === undefined) {
5795 $input.attr('tabindex', 0);
5796 }
5797 },
5798 },
5799
5800 remove: {
5801 initialLoad: function () {
5802 initialLoad = false;
5803 },
5804 },
5805
5806 trigger: {
5807 change: function () {
5808 var
5809 inputElement = $input[0]
5810 ;
5811 if (inputElement) {
5812 var events = document.createEvent('HTMLEvents');
5813 module.verbose('Triggering native change event');
5814 events.initEvent('change', true, false);
5815 inputElement.dispatchEvent(events);
5816 }
5817 },
5818 },
5819
5820 create: {
5821 label: function () {
5822 if ($input.prevAll(selector.label).length > 0) {
5823 $input.prev(selector.label).detach().insertAfter($input);
5824 module.debug('Moving existing label', $label);
5825 } else if (!module.has.label()) {
5826 $label = $('<label>').insertAfter($input);
5827 module.debug('Creating label', $label);
5828 }
5829 },
5830 },
5831
5832 has: {
5833 label: function () {
5834 return $label.length > 0;
5835 },
5836 },
5837
5838 bind: {
5839 events: function () {
5840 module.verbose('Attaching checkbox events');
5841 $module
5842 .on('click' + eventNamespace, module.event.click)
5843 .on('change' + eventNamespace, module.event.change)
5844 .on('keydown' + eventNamespace, selector.input, module.event.keydown)
5845 .on('keyup' + eventNamespace, selector.input, module.event.keyup)
5846 ;
5847 },
5848 },
5849
5850 unbind: {
5851 events: function () {
5852 module.debug('Removing events');
5853 $module
5854 .off(eventNamespace)
5855 ;
5856 },
5857 },
5858
5859 uncheckOthers: function () {
5860 var
5861 $radios = module.get.otherRadios()
5862 ;
5863 module.debug('Unchecking other radios', $radios);
5864 $radios.removeClass(className.checked);
5865 },
5866
5867 toggle: function () {
5868 if (!module.can.change()) {
5869 if (!module.is.radio()) {
5870 module.debug('Checkbox is read-only or disabled, ignoring toggle');
5871 }
5872
5873 return;
5874 }
5875 if (module.is.indeterminate() || module.is.unchecked()) {
5876 module.debug('Currently unchecked');
5877 module.check();
5878 } else if (module.is.checked() && module.can.uncheck()) {
5879 module.debug('Currently checked');
5880 module.uncheck();
5881 }
5882 },
5883 setting: function (name, value) {
5884 module.debug('Changing setting', name, value);
5885 if ($.isPlainObject(name)) {
5886 $.extend(true, settings, name);
5887 } else if (value !== undefined) {
5888 if ($.isPlainObject(settings[name])) {
5889 $.extend(true, settings[name], value);
5890 } else {
5891 settings[name] = value;
5892 }
5893 } else {
5894 return settings[name];
5895 }
5896 },
5897 internal: function (name, value) {
5898 if ($.isPlainObject(name)) {
5899 $.extend(true, module, name);
5900 } else if (value !== undefined) {
5901 module[name] = value;
5902 } else {
5903 return module[name];
5904 }
5905 },
5906 debug: function () {
5907 if (!settings.silent && settings.debug) {
5908 if (settings.performance) {
5909 module.performance.log(arguments);
5910 } else {
5911 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
5912 module.debug.apply(console, arguments);
5913 }
5914 }
5915 },
5916 verbose: function () {
5917 if (!settings.silent && settings.verbose && settings.debug) {
5918 if (settings.performance) {
5919 module.performance.log(arguments);
5920 } else {
5921 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
5922 module.verbose.apply(console, arguments);
5923 }
5924 }
5925 },
5926 error: function () {
5927 if (!settings.silent) {
5928 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
5929 module.error.apply(console, arguments);
5930 }
5931 },
5932 performance: {
5933 log: function (message) {
5934 var
5935 currentTime,
5936 executionTime,
5937 previousTime
5938 ;
5939 if (settings.performance) {
5940 currentTime = Date.now();
5941 previousTime = time || currentTime;
5942 executionTime = currentTime - previousTime;
5943 time = currentTime;
5944 performance.push({
5945 Name: message[0],
5946 Arguments: [].slice.call(message, 1) || '',
5947 Element: element,
5948 'Execution Time': executionTime,
5949 });
5950 }
5951 clearTimeout(module.performance.timer);
5952 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
5953 },
5954 display: function () {
5955 var
5956 title = settings.name + ':',
5957 totalTime = 0
5958 ;
5959 time = false;
5960 clearTimeout(module.performance.timer);
5961 $.each(performance, function (index, data) {
5962 totalTime += data['Execution Time'];
5963 });
5964 title += ' ' + totalTime + 'ms';
5965 if (performance.length > 0) {
5966 console.groupCollapsed(title);
5967 if (console.table) {
5968 console.table(performance);
5969 } else {
5970 $.each(performance, function (index, data) {
5971 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
5972 });
5973 }
5974 console.groupEnd();
5975 }
5976 performance = [];
5977 },
5978 },
5979 invoke: function (query, passedArguments, context) {
5980 var
5981 object = instance,
5982 maxDepth,
5983 found,
5984 response
5985 ;
5986 passedArguments = passedArguments || queryArguments;
5987 context = context || element;
5988 if (typeof query === 'string' && object !== undefined) {
5989 query = query.split(/[ .]/);
5990 maxDepth = query.length - 1;
5991 $.each(query, function (depth, value) {
5992 var camelCaseValue = depth !== maxDepth
5993 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
5994 : query
5995 ;
5996 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
5997 object = object[camelCaseValue];
5998 } else if (object[camelCaseValue] !== undefined) {
5999 found = object[camelCaseValue];
6000
6001 return false;
6002 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
6003 object = object[value];
6004 } else if (object[value] !== undefined) {
6005 found = object[value];
6006
6007 return false;
6008 } else {
6009 module.error(error.method, query);
6010
6011 return false;
6012 }
6013 });
6014 }
6015 if (isFunction(found)) {
6016 response = found.apply(context, passedArguments);
6017 } else if (found !== undefined) {
6018 response = found;
6019 }
6020 if (Array.isArray(returnedValue)) {
6021 returnedValue.push(response);
6022 } else if (returnedValue !== undefined) {
6023 returnedValue = [returnedValue, response];
6024 } else if (response !== undefined) {
6025 returnedValue = response;
6026 }
6027
6028 return found;
6029 },
6030 };
6031
6032 if (methodInvoked) {
6033 if (instance === undefined) {
6034 module.initialize();
6035 }
6036 module.invoke(query);
6037 } else {
6038 if (instance !== undefined) {
6039 instance.invoke('destroy');
6040 }
6041 module.initialize();
6042 }
6043 });
6044
6045 return returnedValue !== undefined
6046 ? returnedValue
6047 : this;
6048 };
6049
6050 $.fn.checkbox.settings = {
6051
6052 name: 'Checkbox',
6053 namespace: 'checkbox',
6054
6055 silent: false,
6056 debug: false,
6057 verbose: false,
6058 performance: true,
6059
6060 // delegated event context
6061 uncheckable: 'auto',
6062 fireOnInit: false,
6063 enableEnterKey: true,
6064
6065 onChange: function () {},
6066
6067 beforeChecked: function () {},
6068 beforeUnchecked: function () {},
6069 beforeDeterminate: function () {},
6070 beforeIndeterminate: function () {},
6071
6072 onChecked: function () {},
6073 onUnchecked: function () {},
6074
6075 onDeterminate: function () {},
6076 onIndeterminate: function () {},
6077
6078 onEnable: function () {},
6079 onDisable: function () {},
6080
6081 // preserve misspelled callbacks (will be removed in 3.0)
6082 onEnabled: function () {},
6083 onDisabled: function () {},
6084
6085 className: {
6086 checked: 'checked',
6087 indeterminate: 'indeterminate',
6088 disabled: 'disabled',
6089 hidden: 'hidden',
6090 radio: 'radio',
6091 readOnly: 'read-only',
6092 },
6093
6094 error: {
6095 method: 'The method you called is not defined',
6096 },
6097
6098 selector: {
6099 checkbox: '.ui.checkbox',
6100 label: 'label',
6101 input: 'input[type="checkbox"], input[type="radio"]',
6102 link: 'a[href]',
6103 },
6104
6105 };
6106})(jQuery, window, document);
6107
6108/*!
6109 * # Fomantic-UI 2.9.3 - Dimmer
6110 * https://github.com/fomantic/Fomantic-UI/
6111 *
6112 *
6113 * Released under the MIT license
6114 * https://opensource.org/licenses/MIT
6115 *
6116 */
6117
6118(function ($, window, document) {
6119 'use strict';
6120
6121 function isFunction(obj) {
6122 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
6123 }
6124
6125 window = window !== undefined && window.Math === Math
6126 ? window
6127 : globalThis;
6128
6129 $.fn.dimmer = function (parameters) {
6130 var
6131 $allModules = $(this),
6132
6133 time = Date.now(),
6134 performance = [],
6135
6136 query = arguments[0],
6137 methodInvoked = typeof query === 'string',
6138 queryArguments = [].slice.call(arguments, 1),
6139
6140 returnedValue
6141 ;
6142
6143 $allModules.each(function () {
6144 var
6145 settings = $.isPlainObject(parameters)
6146 ? $.extend(true, {}, $.fn.dimmer.settings, parameters)
6147 : $.extend({}, $.fn.dimmer.settings),
6148
6149 selector = settings.selector,
6150 namespace = settings.namespace,
6151 className = settings.className,
6152 error = settings.error,
6153
6154 eventNamespace = '.' + namespace,
6155 moduleNamespace = 'module-' + namespace,
6156
6157 clickEvent = 'ontouchstart' in document.documentElement
6158 ? 'touchstart'
6159 : 'click',
6160
6161 $module = $(this),
6162 $dimmer,
6163 $dimmable,
6164
6165 element = this,
6166 instance = $module.data(moduleNamespace),
6167 module
6168 ;
6169
6170 module = {
6171
6172 preinitialize: function () {
6173 if (module.is.dimmer()) {
6174 $dimmable = $module.parent();
6175 $dimmer = $module;
6176 } else {
6177 $dimmable = $module;
6178 if (module.has.dimmer()) {
6179 $dimmer = settings.dimmerName
6180 ? $dimmable.find(selector.dimmer).filter('.' + settings.dimmerName)
6181 : $dimmable.find(selector.dimmer);
6182 } else {
6183 $dimmer = module.create();
6184 }
6185 }
6186 },
6187
6188 initialize: function () {
6189 module.debug('Initializing dimmer', settings);
6190
6191 module.bind.events();
6192 module.set.dimmable();
6193 module.instantiate();
6194 },
6195
6196 instantiate: function () {
6197 module.verbose('Storing instance of module', module);
6198 instance = module;
6199 $module
6200 .data(moduleNamespace, instance)
6201 ;
6202 },
6203
6204 destroy: function () {
6205 module.verbose('Destroying previous module', $dimmer);
6206 module.unbind.events();
6207 module.remove.variation();
6208 $dimmable
6209 .off(eventNamespace)
6210 ;
6211 },
6212
6213 bind: {
6214 events: function () {
6215 if (settings.on === 'hover') {
6216 $dimmable
6217 .on('mouseenter' + eventNamespace, module.show)
6218 .on('mouseleave' + eventNamespace, module.hide)
6219 ;
6220 } else if (settings.on === 'click') {
6221 $dimmable
6222 .on(clickEvent + eventNamespace, module.toggle)
6223 ;
6224 }
6225 if (module.is.page()) {
6226 module.debug('Setting as a page dimmer', $dimmable);
6227 module.set.pageDimmer();
6228 }
6229
6230 if (module.is.closable()) {
6231 module.verbose('Adding dimmer close event', $dimmer);
6232 $dimmable
6233 .on(clickEvent + eventNamespace, selector.dimmer, module.event.click)
6234 ;
6235 }
6236 },
6237 },
6238
6239 unbind: {
6240 events: function () {
6241 $module
6242 .removeData(moduleNamespace)
6243 ;
6244 $dimmable
6245 .off(eventNamespace)
6246 ;
6247 },
6248 },
6249
6250 event: {
6251 click: function (event) {
6252 module.verbose('Determining if event occurred on dimmer', event);
6253 if ($dimmer.find(event.target).length === 0 || $(event.target).is(selector.content)) {
6254 module.hide();
6255 event.stopImmediatePropagation();
6256 }
6257 },
6258 },
6259
6260 addContent: function (element) {
6261 var
6262 $content = $(element)
6263 ;
6264 module.debug('Add content to dimmer', $content);
6265 if ($content.parent()[0] !== $dimmer[0]) {
6266 $content.detach().appendTo($dimmer);
6267 }
6268 },
6269
6270 create: function () {
6271 var
6272 $element = $(settings.template.dimmer(settings))
6273 ;
6274 if (settings.dimmerName) {
6275 module.debug('Creating named dimmer', settings.dimmerName);
6276 $element.addClass(settings.dimmerName);
6277 }
6278 $element
6279 .appendTo($dimmable)
6280 ;
6281
6282 return $element;
6283 },
6284
6285 show: function (callback) {
6286 callback = isFunction(callback)
6287 ? callback
6288 : function () {};
6289 if ((!module.is.dimmed() || module.is.animating()) && module.is.enabled()) {
6290 if (settings.onShow.call(element) === false) {
6291 module.verbose('Show callback returned false cancelling dimmer show');
6292
6293 return;
6294 }
6295 module.debug('Showing dimmer', $dimmer, settings);
6296 module.set.variation();
6297 module.animate.show(callback);
6298 settings.onChange.call(element);
6299 } else {
6300 module.debug('Dimmer is already shown or disabled');
6301 }
6302 },
6303
6304 hide: function (callback) {
6305 callback = isFunction(callback)
6306 ? callback
6307 : function () {};
6308 if (module.is.dimmed() || module.is.animating()) {
6309 if (settings.onHide.call(element) === false) {
6310 module.verbose('Hide callback returned false cancelling dimmer hide');
6311
6312 return;
6313 }
6314 module.debug('Hiding dimmer', $dimmer);
6315 module.animate.hide(callback);
6316 settings.onChange.call(element);
6317 } else {
6318 module.debug('Dimmer is not visible');
6319 }
6320 },
6321
6322 toggle: function () {
6323 module.verbose('Toggling dimmer visibility', $dimmer);
6324 if (!module.is.dimmed()) {
6325 module.show();
6326 } else {
6327 if (module.is.closable()) {
6328 module.hide();
6329 }
6330 }
6331 },
6332
6333 animate: {
6334 show: function (callback) {
6335 callback = isFunction(callback)
6336 ? callback
6337 : function () {};
6338 if (settings.useCSS && $.fn.transition !== undefined) {
6339 if (settings.useFlex) {
6340 module.debug('Using flex dimmer');
6341 module.remove.legacy();
6342 } else {
6343 module.debug('Using legacy non-flex dimmer');
6344 module.set.legacy();
6345 }
6346 if (settings.opacity !== 'auto') {
6347 module.set.opacity();
6348 }
6349 $dimmer
6350 .transition({
6351 debug: settings.debug,
6352 verbose: settings.verbose,
6353 silent: settings.silent,
6354 displayType: settings.useFlex
6355 ? 'flex'
6356 : 'block',
6357 animation: (settings.transition.showMethod || settings.transition) + ' in',
6358 queue: false,
6359 duration: module.get.duration(),
6360 useFailSafe: true,
6361 onStart: function () {
6362 module.set.dimmed();
6363 },
6364 onComplete: function () {
6365 module.set.active();
6366 settings.onVisible.call($dimmer);
6367 callback();
6368 },
6369 })
6370 ;
6371 } else {
6372 module.verbose('Showing dimmer animation with javascript');
6373 module.set.dimmed();
6374 if (settings.opacity === 'auto') {
6375 settings.opacity = 0.8;
6376 }
6377 $dimmer
6378 .stop()
6379 .css({
6380 opacity: 0,
6381 width: '100%',
6382 height: '100%',
6383 })
6384 .fadeTo(module.get.duration(), settings.opacity, function () {
6385 $dimmer.removeAttr('style');
6386 module.set.active();
6387 settings.onVisible.call($dimmer);
6388 callback();
6389 })
6390 ;
6391 }
6392 },
6393 hide: function (callback) {
6394 callback = isFunction(callback)
6395 ? callback
6396 : function () {};
6397 if (settings.useCSS && $.fn.transition !== undefined) {
6398 module.verbose('Hiding dimmer with css');
6399 $dimmer
6400 .transition({
6401 debug: settings.debug,
6402 verbose: settings.verbose,
6403 silent: settings.silent,
6404 displayType: settings.useFlex
6405 ? 'flex'
6406 : 'block',
6407 animation: (settings.transition.hideMethod || settings.transition) + ' out',
6408 queue: false,
6409 duration: module.get.duration(),
6410 useFailSafe: true,
6411 onComplete: function () {
6412 module.remove.dimmed();
6413 module.remove.variation();
6414 module.remove.active();
6415 settings.onHidden.call($dimmer);
6416 callback();
6417 },
6418 })
6419 ;
6420 } else {
6421 module.verbose('Hiding dimmer with javascript');
6422 $dimmer
6423 .stop()
6424 .fadeOut(module.get.duration(), function () {
6425 module.remove.dimmed();
6426 module.remove.active();
6427 $dimmer.removeAttr('style');
6428 settings.onHidden.call($dimmer);
6429 callback();
6430 })
6431 ;
6432 }
6433 },
6434 },
6435
6436 get: {
6437 dimmer: function () {
6438 return $dimmer;
6439 },
6440 duration: function () {
6441 if (module.is.active()) {
6442 return settings.transition.hideDuration || settings.duration.hide || settings.duration;
6443 }
6444
6445 return settings.transition.showDuration || settings.duration.show || settings.duration;
6446 },
6447 },
6448
6449 has: {
6450 dimmer: function () {
6451 if (settings.dimmerName) {
6452 return $module.find(selector.dimmer).filter('.' + settings.dimmerName).length > 0;
6453 }
6454
6455 return $module.find(selector.dimmer).length > 0;
6456 },
6457 },
6458
6459 is: {
6460 active: function () {
6461 return $dimmer.hasClass(className.active);
6462 },
6463 animating: function () {
6464 return $dimmer.is(':animated') || $dimmer.hasClass(className.animating);
6465 },
6466 closable: function () {
6467 if (settings.closable === 'auto') {
6468 return settings.on !== 'hover';
6469 }
6470
6471 return settings.closable;
6472 },
6473 dimmer: function () {
6474 return $module.hasClass(className.dimmer);
6475 },
6476 dimmable: function () {
6477 return $module.hasClass(className.dimmable);
6478 },
6479 dimmed: function () {
6480 return $dimmable.hasClass(className.dimmed);
6481 },
6482 disabled: function () {
6483 return $dimmable.hasClass(className.disabled);
6484 },
6485 enabled: function () {
6486 return !module.is.disabled();
6487 },
6488 page: function () {
6489 return $dimmable.is('body');
6490 },
6491 pageDimmer: function () {
6492 return $dimmer.hasClass(className.pageDimmer);
6493 },
6494 },
6495
6496 can: {
6497 show: function () {
6498 return !$dimmer.hasClass(className.disabled);
6499 },
6500 },
6501
6502 set: {
6503 opacity: function (opacity) {
6504 var
6505 color = $dimmer.css('background-color'),
6506 colorArray = color.split(','),
6507 isRGB = colorArray && colorArray.length >= 3
6508 ;
6509 opacity = settings.opacity === 0 ? 0 : settings.opacity || opacity;
6510 if (isRGB) {
6511 colorArray[2] = colorArray[2].replace(')', '');
6512 colorArray[3] = opacity + ')';
6513 color = colorArray.join(',');
6514 } else {
6515 color = 'rgba(0, 0, 0, ' + opacity + ')';
6516 }
6517 module.debug('Setting opacity to', opacity);
6518 $dimmer.css('background-color', color);
6519 },
6520 legacy: function () {
6521 $dimmer.addClass(className.legacy);
6522 },
6523 active: function () {
6524 $dimmer.addClass(className.active);
6525 },
6526 dimmable: function () {
6527 $dimmable.addClass(className.dimmable);
6528 },
6529 dimmed: function () {
6530 $dimmable.addClass(className.dimmed);
6531 },
6532 pageDimmer: function () {
6533 $dimmer.addClass(className.pageDimmer);
6534 },
6535 disabled: function () {
6536 $dimmer.addClass(className.disabled);
6537 },
6538 variation: function (variation) {
6539 variation = variation || settings.variation;
6540 if (variation) {
6541 $dimmer.addClass(variation);
6542 }
6543 },
6544 },
6545
6546 remove: {
6547 active: function () {
6548 $dimmer
6549 .removeClass(className.active)
6550 ;
6551 },
6552 legacy: function () {
6553 $dimmer.removeClass(className.legacy);
6554 },
6555 dimmed: function () {
6556 $dimmable.removeClass(className.dimmed);
6557 },
6558 disabled: function () {
6559 $dimmer.removeClass(className.disabled);
6560 },
6561 variation: function (variation) {
6562 variation = variation || settings.variation;
6563 if (variation) {
6564 $dimmer.removeClass(variation);
6565 }
6566 },
6567 },
6568
6569 setting: function (name, value) {
6570 module.debug('Changing setting', name, value);
6571 if ($.isPlainObject(name)) {
6572 $.extend(true, settings, name);
6573 } else if (value !== undefined) {
6574 if ($.isPlainObject(settings[name])) {
6575 $.extend(true, settings[name], value);
6576 } else {
6577 settings[name] = value;
6578 }
6579 } else {
6580 return settings[name];
6581 }
6582 },
6583 internal: function (name, value) {
6584 if ($.isPlainObject(name)) {
6585 $.extend(true, module, name);
6586 } else if (value !== undefined) {
6587 module[name] = value;
6588 } else {
6589 return module[name];
6590 }
6591 },
6592 debug: function () {
6593 if (!settings.silent && settings.debug) {
6594 if (settings.performance) {
6595 module.performance.log(arguments);
6596 } else {
6597 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
6598 module.debug.apply(console, arguments);
6599 }
6600 }
6601 },
6602 verbose: function () {
6603 if (!settings.silent && settings.verbose && settings.debug) {
6604 if (settings.performance) {
6605 module.performance.log(arguments);
6606 } else {
6607 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
6608 module.verbose.apply(console, arguments);
6609 }
6610 }
6611 },
6612 error: function () {
6613 if (!settings.silent) {
6614 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
6615 module.error.apply(console, arguments);
6616 }
6617 },
6618 performance: {
6619 log: function (message) {
6620 var
6621 currentTime,
6622 executionTime,
6623 previousTime
6624 ;
6625 if (settings.performance) {
6626 currentTime = Date.now();
6627 previousTime = time || currentTime;
6628 executionTime = currentTime - previousTime;
6629 time = currentTime;
6630 performance.push({
6631 Name: message[0],
6632 Arguments: [].slice.call(message, 1) || '',
6633 Element: element,
6634 'Execution Time': executionTime,
6635 });
6636 }
6637 clearTimeout(module.performance.timer);
6638 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
6639 },
6640 display: function () {
6641 var
6642 title = settings.name + ':',
6643 totalTime = 0
6644 ;
6645 time = false;
6646 clearTimeout(module.performance.timer);
6647 $.each(performance, function (index, data) {
6648 totalTime += data['Execution Time'];
6649 });
6650 title += ' ' + totalTime + 'ms';
6651 if ($allModules.length > 1) {
6652 title += ' (' + $allModules.length + ')';
6653 }
6654 if (performance.length > 0) {
6655 console.groupCollapsed(title);
6656 if (console.table) {
6657 console.table(performance);
6658 } else {
6659 $.each(performance, function (index, data) {
6660 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
6661 });
6662 }
6663 console.groupEnd();
6664 }
6665 performance = [];
6666 },
6667 },
6668 invoke: function (query, passedArguments, context) {
6669 var
6670 object = instance,
6671 maxDepth,
6672 found,
6673 response
6674 ;
6675 passedArguments = passedArguments || queryArguments;
6676 context = context || element;
6677 if (typeof query === 'string' && object !== undefined) {
6678 query = query.split(/[ .]/);
6679 maxDepth = query.length - 1;
6680 $.each(query, function (depth, value) {
6681 var camelCaseValue = depth !== maxDepth
6682 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
6683 : query
6684 ;
6685 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
6686 object = object[camelCaseValue];
6687 } else if (object[camelCaseValue] !== undefined) {
6688 found = object[camelCaseValue];
6689
6690 return false;
6691 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
6692 object = object[value];
6693 } else if (object[value] !== undefined) {
6694 found = object[value];
6695
6696 return false;
6697 } else {
6698 module.error(error.method, query);
6699
6700 return false;
6701 }
6702 });
6703 }
6704 if (isFunction(found)) {
6705 response = found.apply(context, passedArguments);
6706 } else if (found !== undefined) {
6707 response = found;
6708 }
6709 if (Array.isArray(returnedValue)) {
6710 returnedValue.push(response);
6711 } else if (returnedValue !== undefined) {
6712 returnedValue = [returnedValue, response];
6713 } else if (response !== undefined) {
6714 returnedValue = response;
6715 }
6716
6717 return found;
6718 },
6719 };
6720
6721 module.preinitialize();
6722
6723 if (methodInvoked) {
6724 if (instance === undefined) {
6725 module.initialize();
6726 }
6727 module.invoke(query);
6728 } else {
6729 if (instance !== undefined) {
6730 instance.invoke('destroy');
6731 }
6732 module.initialize();
6733 }
6734 });
6735
6736 return returnedValue !== undefined
6737 ? returnedValue
6738 : this;
6739 };
6740
6741 $.fn.dimmer.settings = {
6742
6743 name: 'Dimmer',
6744 namespace: 'dimmer',
6745
6746 silent: false,
6747 debug: false,
6748 verbose: false,
6749 performance: true,
6750
6751 // whether should use flex layout
6752 useFlex: true,
6753
6754 // name to distinguish between multiple dimmers in context
6755 dimmerName: false,
6756
6757 // whether to add a variation type
6758 variation: false,
6759
6760 // whether to bind close events
6761 closable: 'auto',
6762
6763 // whether to use css animations
6764 useCSS: true,
6765
6766 // css animation to use
6767 transition: 'fade',
6768
6769 // event to bind to
6770 on: false,
6771
6772 // overriding opacity value
6773 opacity: 'auto',
6774
6775 // transition durations
6776 duration: {
6777 show: 500,
6778 hide: 500,
6779 },
6780 // whether the dynamically created dimmer should have a loader
6781 displayLoader: false,
6782 loaderText: false,
6783 loaderVariation: '',
6784
6785 onChange: function () {},
6786 onShow: function () {},
6787 onHide: function () {},
6788 onVisible: function () {},
6789 onHidden: function () {},
6790
6791 error: {
6792 method: 'The method you called is not defined.',
6793 },
6794
6795 className: {
6796 active: 'active',
6797 animating: 'animating',
6798 dimmable: 'dimmable',
6799 dimmed: 'dimmed',
6800 dimmer: 'dimmer',
6801 disabled: 'disabled',
6802 hide: 'hide',
6803 legacy: 'legacy',
6804 pageDimmer: 'page',
6805 show: 'show',
6806 loader: 'ui loader',
6807 },
6808
6809 selector: {
6810 dimmer: '> .ui.dimmer',
6811 content: '.ui.dimmer > .content, .ui.dimmer > .content > .center',
6812 },
6813
6814 template: {
6815 dimmer: function (settings) {
6816 var
6817 d = $('<div/>').addClass('ui dimmer'),
6818 l
6819 ;
6820 if (settings.displayLoader) {
6821 l = $('<div/>')
6822 .addClass(settings.className.loader)
6823 .addClass(settings.loaderVariation)
6824 ;
6825 if (settings.loaderText) {
6826 l.text(settings.loaderText);
6827 l.addClass('text');
6828 }
6829 d.append(l);
6830 }
6831
6832 return d;
6833 },
6834 },
6835
6836 };
6837})(jQuery, window, document);
6838
6839/*!
6840 * # Fomantic-UI 2.9.3 - Dropdown
6841 * https://github.com/fomantic/Fomantic-UI/
6842 *
6843 *
6844 * Released under the MIT license
6845 * https://opensource.org/licenses/MIT
6846 *
6847 */
6848
6849(function ($, window, document) {
6850 'use strict';
6851
6852 function isFunction(obj) {
6853 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
6854 }
6855
6856 window = window !== undefined && window.Math === Math
6857 ? window
6858 : globalThis;
6859
6860 $.fn.dropdown = function (parameters) {
6861 var
6862 $allModules = $(this),
6863 $document = $(document),
6864
6865 time = Date.now(),
6866 performance = [],
6867
6868 query = arguments[0],
6869 methodInvoked = typeof query === 'string',
6870 queryArguments = [].slice.call(arguments, 1),
6871 contextCheck = function (context, win) {
6872 var $context;
6873 if ([window, document].indexOf(context) >= 0) {
6874 $context = $(context);
6875 } else {
6876 $context = $(win.document).find(context);
6877 if ($context.length === 0) {
6878 $context = win.frameElement ? contextCheck(context, win.parent) : window;
6879 }
6880 }
6881
6882 return $context;
6883 },
6884 returnedValue
6885 ;
6886
6887 $allModules.each(function (elementIndex) {
6888 var
6889 settings = $.isPlainObject(parameters)
6890 ? $.extend(true, {}, $.fn.dropdown.settings, parameters)
6891 : $.extend({}, $.fn.dropdown.settings),
6892
6893 className = settings.className,
6894 message = settings.message,
6895 fields = settings.fields,
6896 keys = settings.keys,
6897 metadata = settings.metadata,
6898 namespace = settings.namespace,
6899 regExp = settings.regExp,
6900 selector = settings.selector,
6901 error = settings.error,
6902 templates = settings.templates,
6903
6904 eventNamespace = '.' + namespace,
6905 moduleNamespace = 'module-' + namespace,
6906
6907 $module = $(this),
6908 $context = contextCheck(settings.context, window),
6909 $text = $module.find(selector.text),
6910 $search = $module.find(selector.search),
6911 $sizer = $module.find(selector.sizer),
6912 $input = $module.find(selector.input),
6913 $icon = $module.find(selector.icon),
6914 $clear = $module.find(selector.clearIcon),
6915
6916 $combo = $module.prev().find(selector.text).length > 0
6917 ? $module.prev().find(selector.text)
6918 : $module.prev(),
6919
6920 $menu = $module.children(selector.menu),
6921 $item = $menu.find(selector.item),
6922 $divider = settings.hideDividers
6923 ? $item.parent().children(selector.divider)
6924 : $(),
6925
6926 activated = false,
6927 itemActivated = false,
6928 internalChange = false,
6929 iconClicked = false,
6930 element = this,
6931 focused = false,
6932 instance = $module.data(moduleNamespace),
6933
6934 selectActionActive,
6935 initialLoad,
6936 pageLostFocus,
6937 willRefocus,
6938 elementNamespace,
6939 id,
6940 selectObserver,
6941 menuObserver,
6942 classObserver,
6943 module,
6944 tempDisableApiCache = false
6945 ;
6946
6947 module = {
6948
6949 initialize: function () {
6950 module.debug('Initializing dropdown', settings);
6951
6952 if (module.is.alreadySetup()) {
6953 module.setup.reference();
6954 } else {
6955 if (settings.ignoreDiacritics && !String.prototype.normalize) {
6956 settings.ignoreDiacritics = false;
6957 module.error(error.noNormalize, element);
6958 }
6959
6960 module.create.id();
6961 module.setup.layout();
6962
6963 if (settings.values) {
6964 module.set.initialLoad();
6965 module.change.values(settings.values);
6966 module.remove.initialLoad();
6967 }
6968
6969 module.refreshData();
6970
6971 module.save.defaults();
6972 module.restore.selected();
6973
6974 module.bind.events();
6975
6976 module.observeChanges();
6977 module.instantiate();
6978 }
6979 },
6980
6981 instantiate: function () {
6982 module.verbose('Storing instance of dropdown', module);
6983 instance = module;
6984 $module
6985 .data(moduleNamespace, module)
6986 ;
6987 },
6988
6989 destroy: function () {
6990 module.verbose('Destroying previous dropdown', $module);
6991 module.remove.tabbable();
6992 module.remove.active();
6993 $menu.transition('stop all');
6994 $menu.removeClass(className.visible).addClass(className.hidden);
6995 $module
6996 .off(eventNamespace)
6997 .removeData(moduleNamespace)
6998 ;
6999 $menu
7000 .off(eventNamespace)
7001 ;
7002 $document
7003 .off(elementNamespace)
7004 ;
7005 module.disconnect.menuObserver();
7006 module.disconnect.selectObserver();
7007 module.disconnect.classObserver();
7008 },
7009
7010 observeChanges: function () {
7011 if ('MutationObserver' in window) {
7012 selectObserver = new MutationObserver(module.event.select.mutation);
7013 menuObserver = new MutationObserver(module.event.menu.mutation);
7014 classObserver = new MutationObserver(module.event.class.mutation);
7015 module.debug('Setting up mutation observer', selectObserver, menuObserver, classObserver);
7016 module.observe.select();
7017 module.observe.menu();
7018 module.observe.class();
7019 }
7020 },
7021
7022 disconnect: {
7023 menuObserver: function () {
7024 if (menuObserver) {
7025 menuObserver.disconnect();
7026 }
7027 },
7028 selectObserver: function () {
7029 if (selectObserver) {
7030 selectObserver.disconnect();
7031 }
7032 },
7033 classObserver: function () {
7034 if (classObserver) {
7035 classObserver.disconnect();
7036 }
7037 },
7038 },
7039 observe: {
7040 select: function () {
7041 if (module.has.input() && selectObserver) {
7042 selectObserver.observe($module[0], {
7043 attributes: true,
7044 childList: true,
7045 subtree: true,
7046 });
7047 }
7048 },
7049 menu: function () {
7050 if (module.has.menu() && menuObserver) {
7051 menuObserver.observe($menu[0], {
7052 childList: true,
7053 subtree: true,
7054 });
7055 }
7056 },
7057 class: function () {
7058 if (module.has.search() && classObserver) {
7059 classObserver.observe($module[0], {
7060 attributes: true,
7061 });
7062 }
7063 },
7064 },
7065
7066 create: {
7067 id: function () {
7068 id = (Math.random().toString(16) + '000000000').slice(2, 10);
7069 elementNamespace = '.' + id;
7070 module.verbose('Creating unique id for element', id);
7071 },
7072 userChoice: function (values) {
7073 var
7074 $userChoices,
7075 $userChoice,
7076 html
7077 ;
7078 values = values || module.get.userValues();
7079 if (!values) {
7080 return false;
7081 }
7082 values = Array.isArray(values)
7083 ? values
7084 : [values];
7085 $.each(values, function (index, value) {
7086 if (module.get.item(value) === false) {
7087 html = settings.templates.addition(module.add.variables(message.addResult, value));
7088 $userChoice = $('<div />')
7089 .html(html)
7090 .attr('data-' + metadata.value, value)
7091 .attr('data-' + metadata.text, value)
7092 .addClass(className.addition)
7093 .addClass(className.item)
7094 ;
7095 if (settings.hideAdditions) {
7096 $userChoice.addClass(className.hidden);
7097 }
7098 $userChoices = $userChoices === undefined
7099 ? $userChoice
7100 : $userChoices.add($userChoice);
7101 module.verbose('Creating user choices for value', value, $userChoice);
7102 }
7103 });
7104
7105 return $userChoices;
7106 },
7107 userLabels: function (value) {
7108 var
7109 userValues = module.get.userValues()
7110 ;
7111 if (userValues) {
7112 module.debug('Adding user labels', userValues);
7113 $.each(userValues, function (index, value) {
7114 module.verbose('Adding custom user value');
7115 module.add.label(value, value);
7116 });
7117 }
7118 },
7119 menu: function () {
7120 $menu = $('<div />')
7121 .addClass(className.menu)
7122 .appendTo($module)
7123 ;
7124 },
7125 sizer: function () {
7126 $sizer = $('<span />')
7127 .addClass(className.sizer)
7128 .insertAfter($search)
7129 ;
7130 },
7131 },
7132
7133 search: function (query) {
7134 query = query !== undefined
7135 ? query
7136 : module.get.query();
7137 module.verbose('Searching for query', query);
7138 if (settings.fireOnInit === false && module.is.initialLoad()) {
7139 module.verbose('Skipping callback on initial load', settings.onSearch);
7140 } else if (module.has.minCharacters(query) && settings.onSearch.call(element, query) !== false) {
7141 module.filter(query);
7142 } else {
7143 module.hide(null, true);
7144 }
7145 },
7146
7147 select: {
7148 firstUnfiltered: function () {
7149 module.verbose('Selecting first non-filtered element');
7150 module.remove.selectedItem();
7151 $item
7152 .not(selector.unselectable)
7153 .not(selector.addition + selector.hidden)
7154 .eq(0)
7155 .addClass(className.selected)
7156 ;
7157 },
7158 nextAvailable: function ($selected) {
7159 $selected = $selected.eq(0);
7160 var
7161 $nextAvailable = $selected.nextAll(selector.item).not(selector.unselectable).eq(0),
7162 $prevAvailable = $selected.prevAll(selector.item).not(selector.unselectable).eq(0),
7163 hasNext = $nextAvailable.length > 0
7164 ;
7165 if (hasNext) {
7166 module.verbose('Moving selection to', $nextAvailable);
7167 $nextAvailable.addClass(className.selected);
7168 } else {
7169 module.verbose('Moving selection to', $prevAvailable);
7170 $prevAvailable.addClass(className.selected);
7171 }
7172 },
7173 },
7174
7175 setup: {
7176 api: function () {
7177 var
7178 apiSettings = {
7179 debug: settings.debug,
7180 urlData: {
7181 value: module.get.value(),
7182 query: module.get.query(),
7183 },
7184 on: false,
7185 }
7186 ;
7187 module.verbose('First request, initializing API');
7188 $module
7189 .api(apiSettings)
7190 ;
7191 },
7192 layout: function () {
7193 if ($module.is('select')) {
7194 module.setup.select();
7195 module.setup.returnedObject();
7196 }
7197 if (!module.has.menu()) {
7198 module.create.menu();
7199 }
7200 if (module.is.clearable() && !module.has.clearItem()) {
7201 module.verbose('Adding clear icon');
7202 $clear = $('<i />')
7203 .addClass('remove icon')
7204 .insertAfter($icon)
7205 ;
7206 }
7207 if (module.is.search() && !module.has.search()) {
7208 module.verbose('Adding search input');
7209 var
7210 labelNode = $module.prev('label')
7211 ;
7212 $search = $('<input />')
7213 .addClass(className.search)
7214 .prop('autocomplete', module.is.chrome() ? 'fomantic-search' : 'off')
7215 ;
7216 if (labelNode.length > 0) {
7217 if (!labelNode.attr('id')) {
7218 labelNode.attr('id', '_' + module.get.id() + '_formLabel');
7219 }
7220 $search.attr('aria-labelledby', labelNode.attr('id'));
7221 }
7222 $search.insertBefore($text);
7223 }
7224 if (module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
7225 module.create.sizer();
7226 }
7227 if (settings.allowTab) {
7228 module.set.tabbable();
7229 }
7230 },
7231 select: function () {
7232 var
7233 selectValues = module.get.selectValues()
7234 ;
7235 module.debug('Dropdown initialized on a select', selectValues);
7236 if ($module.is('select')) {
7237 $input = $module;
7238 }
7239 // see if select is placed correctly already
7240 if ($input.parent(selector.dropdown).length > 0) {
7241 module.debug('UI dropdown already exists. Creating dropdown menu only');
7242 $module = $input.closest(selector.dropdown);
7243 if (!module.has.menu()) {
7244 module.create.menu();
7245 }
7246 $menu = $module.children(selector.menu);
7247 module.setup.menu(selectValues);
7248 } else {
7249 module.debug('Creating entire dropdown from select');
7250 $module = $('<div />')
7251 .attr('class', $input.attr('class'))
7252 .addClass(className.selection)
7253 .addClass(className.dropdown)
7254 .html(templates.dropdown(selectValues, fields, settings.preserveHTML, settings.className))
7255 .insertBefore($input)
7256 ;
7257 if ($input.hasClass(className.multiple) && $input.prop('multiple') === false) {
7258 module.error(error.missingMultiple);
7259 $input.prop('multiple', true);
7260 }
7261 if ($input.is('[multiple]')) {
7262 module.set.multiple();
7263 }
7264 if ($input.prop('disabled')) {
7265 module.debug('Disabling dropdown');
7266 $module.addClass(className.disabled);
7267 }
7268 if ($input.is('[required]')) {
7269 settings.forceSelection = true;
7270 }
7271 if (!settings.allowTab) {
7272 $input.removeAttr('tabindex');
7273 }
7274 $input
7275 .prop('required', false)
7276 .removeAttr('class')
7277 .detach()
7278 .prependTo($module)
7279 ;
7280 }
7281 module.refresh();
7282 },
7283 menu: function (values) {
7284 $menu.html(templates.menu(values, fields, settings.preserveHTML, settings.className));
7285 $item = $menu.find(selector.item);
7286 $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
7287 },
7288 reference: function () {
7289 module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
7290 // replace module reference
7291 $module = $module.parent(selector.dropdown);
7292 instance = $module.data(moduleNamespace);
7293 element = $module[0];
7294 module.refresh();
7295 module.setup.returnedObject();
7296 },
7297 returnedObject: function () {
7298 var
7299 $firstModules = $allModules.slice(0, elementIndex),
7300 $lastModules = $allModules.slice(elementIndex + 1)
7301 ;
7302 // adjust all modules to use correct reference
7303 $allModules = $firstModules.add($module).add($lastModules);
7304 },
7305 },
7306
7307 refresh: function () {
7308 module.refreshSelectors();
7309 module.refreshData();
7310 },
7311
7312 refreshItems: function () {
7313 $item = $menu.find(selector.item);
7314 $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
7315 },
7316
7317 refreshSelectors: function () {
7318 module.verbose('Refreshing selector cache');
7319 $text = $module.find(selector.text);
7320 $search = $module.find(selector.search);
7321 $input = $module.find(selector.input);
7322 $icon = $module.find(selector.icon);
7323 $combo = $module.prev().find(selector.text).length > 0
7324 ? $module.prev().find(selector.text)
7325 : $module.prev();
7326 $menu = $module.children(selector.menu);
7327 $item = $menu.find(selector.item);
7328 $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
7329 },
7330
7331 refreshData: function () {
7332 module.verbose('Refreshing cached metadata');
7333 $item
7334 .removeData(metadata.text)
7335 .removeData(metadata.value)
7336 ;
7337 },
7338
7339 clearData: function () {
7340 module.verbose('Clearing metadata');
7341 $item
7342 .removeData(metadata.text)
7343 .removeData(metadata.value)
7344 ;
7345 $module
7346 .removeData(metadata.defaultText)
7347 .removeData(metadata.defaultValue)
7348 .removeData(metadata.placeholderText)
7349 ;
7350 },
7351
7352 clearItems: function () {
7353 $menu.empty();
7354 module.refreshItems();
7355 },
7356
7357 toggle: function () {
7358 module.verbose('Toggling menu visibility');
7359 if (!module.is.active()) {
7360 module.show();
7361 } else {
7362 module.hide();
7363 }
7364 },
7365
7366 show: function (callback, preventFocus) {
7367 callback = isFunction(callback)
7368 ? callback
7369 : function () {};
7370 if ((focused || iconClicked) && module.is.remote() && module.is.noApiCache() && !module.has.maxSelections()) {
7371 module.clearItems();
7372 }
7373 if (!module.can.show() && module.is.remote()) {
7374 module.debug('No API results retrieved, searching before show');
7375 module.queryRemote(module.get.query(), module.show, [callback, preventFocus]);
7376 }
7377 if (module.can.show() && !module.is.active()) {
7378 module.debug('Showing dropdown');
7379 if (module.has.message() && !(module.has.maxSelections() || module.has.allResultsFiltered())) {
7380 module.remove.message();
7381 }
7382 if (module.is.allFiltered()) {
7383 return true;
7384 }
7385 if (settings.onShow.call(element) !== false) {
7386 module.remove.empty();
7387 module.animate.show(function () {
7388 module.bind.intent();
7389 if (module.has.search() && !preventFocus) {
7390 module.focusSearch();
7391 }
7392 module.set.visible();
7393 callback.call(element);
7394 });
7395 }
7396 }
7397 },
7398
7399 hide: function (callback, preventBlur) {
7400 callback = isFunction(callback)
7401 ? callback
7402 : function () {};
7403 if (module.is.active() && !module.is.animatingOutward()) {
7404 module.debug('Hiding dropdown');
7405 if (settings.onHide.call(element) !== false) {
7406 module.animate.hide(function () {
7407 module.remove.visible();
7408 // hiding search focus
7409 if (module.is.focusedOnSearch() && preventBlur !== true) {
7410 $search.trigger('blur');
7411 }
7412 callback.call(element);
7413 });
7414 // Hide submenus explicitly. On some browsers (esp. mobile), they will not automatically receive a
7415 // mouseleave event
7416 var $subMenu = $module.find(selector.menu);
7417 if ($subMenu.length > 0) {
7418 module.verbose('Hiding sub-menu', $subMenu);
7419 $subMenu.each(function () {
7420 var $sub = $(this);
7421 if (!module.is.animating($sub)) {
7422 module.animate.hide(false, $sub);
7423 }
7424 });
7425 }
7426 }
7427 } else {
7428 module.unbind.intent();
7429 }
7430 iconClicked = false;
7431 focused = false;
7432 },
7433
7434 hideOthers: function () {
7435 module.verbose('Finding other dropdowns to hide');
7436 $allModules
7437 .not($module)
7438 .has(selector.menu + '.' + className.visible)
7439 .dropdown('hide')
7440 ;
7441 },
7442
7443 hideMenu: function () {
7444 module.verbose('Hiding menu instantaneously');
7445 module.remove.active();
7446 module.remove.visible();
7447 $menu.transition('destroy').transition('hide');
7448 },
7449
7450 hideSubMenus: function () {
7451 var
7452 $subMenus = $menu.children(selector.item).find(selector.menu)
7453 ;
7454 module.verbose('Hiding sub menus', $subMenus);
7455 $subMenus.transition('hide');
7456 },
7457
7458 bind: {
7459 events: function () {
7460 module.bind.keyboardEvents();
7461 module.bind.inputEvents();
7462 module.bind.mouseEvents();
7463 },
7464 keyboardEvents: function () {
7465 module.verbose('Binding keyboard events');
7466 $module
7467 .on('keydown' + eventNamespace, module.event.keydown)
7468 ;
7469 if (module.has.search()) {
7470 $module
7471 .on(module.get.inputEvent() + eventNamespace, selector.search, module.event.input)
7472 ;
7473 }
7474 if (module.is.multiple()) {
7475 $document
7476 .on('keydown' + elementNamespace, module.event.document.keydown)
7477 ;
7478 }
7479 },
7480 inputEvents: function () {
7481 module.verbose('Binding input change events');
7482 $module
7483 .on('change' + eventNamespace, selector.input, module.event.change)
7484 ;
7485 if (module.is.multiple() && module.is.searchSelection()) {
7486 $module
7487 .on('paste' + eventNamespace, selector.search, module.event.paste)
7488 ;
7489 }
7490 },
7491 mouseEvents: function () {
7492 module.verbose('Binding mouse events');
7493 if (module.is.multiple()) {
7494 $module
7495 .on('click' + eventNamespace, selector.label, module.event.label.click)
7496 .on('click' + eventNamespace, selector.remove, module.event.remove.click)
7497 ;
7498 }
7499 if (module.is.searchSelection()) {
7500 $module
7501 .on('mousedown' + eventNamespace, module.event.mousedown)
7502 .on('mouseup' + eventNamespace, module.event.mouseup)
7503 .on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
7504 .on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
7505 .on('click' + eventNamespace, selector.icon, module.event.icon.click)
7506 .on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
7507 .on('focus' + eventNamespace, selector.search, module.event.search.focus)
7508 .on('click' + eventNamespace, selector.search, module.event.search.focus)
7509 .on('blur' + eventNamespace, selector.search, module.event.search.blur)
7510 .on('click' + eventNamespace, selector.text, module.event.text.focus)
7511 ;
7512 if (module.is.multiple()) {
7513 $module
7514 .on('click' + eventNamespace, module.event.click)
7515 .on('click' + eventNamespace, module.event.search.focus)
7516 ;
7517 }
7518 } else {
7519 if (settings.on === 'click') {
7520 $module
7521 .on('click' + eventNamespace, selector.icon, module.event.icon.click)
7522 .on('click' + eventNamespace, module.event.test.toggle)
7523 ;
7524 } else if (settings.on === 'hover') {
7525 $module
7526 .on('mouseenter' + eventNamespace, module.delay.show)
7527 .on('mouseleave' + eventNamespace, module.delay.hide)
7528 .on('touchstart' + eventNamespace, module.event.test.toggle)
7529 .on('touchstart' + eventNamespace, selector.icon, module.event.icon.click)
7530 ;
7531 } else {
7532 $module
7533 .on(settings.on + eventNamespace, module.toggle)
7534 ;
7535 }
7536 $module
7537 .on('mousedown' + eventNamespace, module.event.mousedown)
7538 .on('mouseup' + eventNamespace, module.event.mouseup)
7539 .on('focus' + eventNamespace, module.event.focus)
7540 .on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
7541 ;
7542 if (module.has.menuSearch()) {
7543 $module
7544 .on('blur' + eventNamespace, selector.search, module.event.search.blur)
7545 ;
7546 } else {
7547 $module
7548 .on('blur' + eventNamespace, module.event.blur)
7549 ;
7550 }
7551 }
7552 $menu
7553 .on('mouseenter' + eventNamespace, selector.item, module.event.item.mouseenter)
7554 .on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
7555 .on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
7556 .on('click' + eventNamespace, selector.item, module.event.item.click)
7557 ;
7558 },
7559 intent: function () {
7560 module.verbose('Binding hide intent event to document');
7561 $document
7562 .on('click' + elementNamespace, module.event.test.hide)
7563 ;
7564 },
7565 },
7566
7567 unbind: {
7568 intent: function () {
7569 module.verbose('Removing hide intent event from document');
7570 $document
7571 .off('click' + elementNamespace)
7572 ;
7573 },
7574 },
7575
7576 filter: function (query) {
7577 var
7578 searchTerm = query !== undefined
7579 ? query
7580 : module.get.query(),
7581 afterFiltered = function () {
7582 if (module.is.multiple()) {
7583 module.filterActive();
7584 }
7585 if (query || (!query && module.get.activeItem().length === 0)) {
7586 module.select.firstUnfiltered();
7587 }
7588 if (module.has.allResultsFiltered()) {
7589 if (settings.onNoResults.call(element, searchTerm)) {
7590 if (settings.allowAdditions) {
7591 if (settings.hideAdditions) {
7592 module.verbose('User addition with no menu, setting empty style');
7593 module.set.empty();
7594 module.hideMenu();
7595 }
7596 } else {
7597 module.verbose('All items filtered, showing message', searchTerm);
7598 module.add.message(message.noResults);
7599 }
7600 } else {
7601 module.verbose('All items filtered, hiding dropdown', searchTerm);
7602 module.set.empty();
7603 module.hideMenu();
7604 }
7605 } else {
7606 module.remove.empty();
7607 module.remove.message();
7608 }
7609 if (settings.allowAdditions) {
7610 module.add.userSuggestion(module.escape.htmlEntities(query));
7611 }
7612 if (module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() && !module.is.empty()) {
7613 module.show();
7614 }
7615 }
7616 ;
7617 if (settings.useLabels && module.has.maxSelections()) {
7618 module.show();
7619
7620 return;
7621 }
7622 if (settings.apiSettings) {
7623 if (module.can.useAPI()) {
7624 module.queryRemote(searchTerm, function () {
7625 if (settings.filterRemoteData) {
7626 module.filterItems(searchTerm);
7627 }
7628 var preSelected = $input.val();
7629 if (!Array.isArray(preSelected)) {
7630 preSelected = preSelected && preSelected !== '' ? preSelected.split(settings.delimiter) : [];
7631 }
7632 if (module.is.multiple()) {
7633 $.each(preSelected, function (index, value) {
7634 $item.filter('[data-value="' + value + '"]')
7635 .addClass(className.filtered)
7636 ;
7637 });
7638 }
7639 module.focusSearch(true);
7640 afterFiltered();
7641 });
7642 } else {
7643 module.error(error.noAPI);
7644 }
7645 } else {
7646 module.filterItems(searchTerm);
7647 afterFiltered();
7648 }
7649 },
7650
7651 queryRemote: function (query, callback, callbackParameters) {
7652 if (!Array.isArray(callbackParameters)) {
7653 callbackParameters = [callbackParameters];
7654 }
7655 var
7656 apiSettings = {
7657 errorDuration: false,
7658 cache: 'local',
7659 throttle: settings.throttle,
7660 urlData: {
7661 query: query,
7662 },
7663 },
7664 apiCallbacks = {
7665 onError: function (errorMessage, $module, xhr) {
7666 module.add.message(message.serverError);
7667 iconClicked = false;
7668 focused = false;
7669 callback.apply(null, callbackParameters);
7670 if (typeof settings.apiSettings.onError === 'function') {
7671 settings.apiSettings.onError.call(this, errorMessage, $module, xhr);
7672 }
7673 },
7674 onFailure: function (response, $module, xhr) {
7675 module.add.message(message.serverError);
7676 iconClicked = false;
7677 focused = false;
7678 callback.apply(null, callbackParameters);
7679 if (typeof settings.apiSettings.onFailure === 'function') {
7680 settings.apiSettings.onFailure.call(this, response, $module, xhr);
7681 }
7682 },
7683 onSuccess: function (response, $module, xhr) {
7684 var
7685 values = response[fields.remoteValues]
7686 ;
7687 if (!Array.isArray(values)) {
7688 values = [];
7689 }
7690 module.remove.message();
7691 var menuConfig = {};
7692 menuConfig[fields.values] = values;
7693 module.setup.menu(menuConfig);
7694
7695 if (values.length === 0 && !settings.allowAdditions) {
7696 module.add.message(message.noResults);
7697 } else {
7698 var value = module.is.multiple() ? module.get.values() : module.get.value();
7699 if (value !== '') {
7700 module.verbose('Value(s) present after click icon, select value(s) in items');
7701 module.set.selected(value, null, true, true);
7702 }
7703 }
7704 iconClicked = false;
7705 focused = false;
7706 callback.apply(null, callbackParameters);
7707 if (typeof settings.apiSettings.onSuccess === 'function') {
7708 settings.apiSettings.onSuccess.call(this, response, $module, xhr);
7709 }
7710 },
7711 }
7712 ;
7713 if (!$module.api('get request')) {
7714 module.setup.api();
7715 }
7716 apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings, apiCallbacks, tempDisableApiCache ? { cache: false } : {});
7717 $module
7718 .api('setting', apiSettings)
7719 .api('query')
7720 ;
7721 tempDisableApiCache = false;
7722 },
7723
7724 filterItems: function (query) {
7725 var
7726 searchTerm = module.remove.diacritics(
7727 query !== undefined
7728 ? query
7729 : module.get.query()
7730 ),
7731 results = null,
7732 escapedTerm = module.escape.string(searchTerm),
7733 regExpFlags = (settings.ignoreSearchCase ? 'i' : '') + 'gm',
7734 beginsWithRegExp = new RegExp('^' + escapedTerm, regExpFlags)
7735 ;
7736 // avoid loop if we're matching nothing
7737 if (module.has.query()) {
7738 results = [];
7739
7740 module.verbose('Searching for matching values', searchTerm);
7741 $item
7742 .each(function () {
7743 var
7744 $choice = $(this),
7745 text,
7746 value
7747 ;
7748 if ($choice.hasClass(className.unfilterable)) {
7749 results.push(this);
7750
7751 return true;
7752 }
7753 if (settings.match === 'both' || settings.match === 'text') {
7754 text = module.remove.diacritics(String(module.get.choiceText($choice, false)));
7755 if (text.search(beginsWithRegExp) !== -1
7756 || (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text))
7757 || (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text))
7758 ) {
7759 results.push(this);
7760
7761 return true;
7762 }
7763 }
7764 if (settings.match === 'both' || settings.match === 'value') {
7765 value = module.remove.diacritics(String(module.get.choiceValue($choice, text)));
7766 if (value.search(beginsWithRegExp) !== -1
7767 || (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value))
7768 || (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value))
7769 ) {
7770 results.push(this);
7771
7772 return true;
7773 }
7774 }
7775 })
7776 ;
7777 }
7778 module.debug('Showing only matched items', searchTerm);
7779 module.remove.filteredItem();
7780 if (results) {
7781 $item
7782 .not(results)
7783 .addClass(className.filtered)
7784 ;
7785 }
7786
7787 if (!module.has.query()) {
7788 $divider
7789 .removeClass(className.hidden)
7790 ;
7791 } else if (settings.hideDividers === true) {
7792 $divider
7793 .addClass(className.hidden)
7794 ;
7795 } else if (settings.hideDividers === 'empty') {
7796 $divider
7797 .removeClass(className.hidden)
7798 .filter(function () {
7799 // First find the last divider in this divider group
7800 // Dividers which are direct siblings are considered a group
7801 var $lastDivider = $(this).nextUntil(selector.item);
7802
7803 return ($lastDivider.length > 0 ? $lastDivider : $(this))
7804 // Count all non-filtered items until the next divider (or end of the dropdown)
7805 .nextUntil(selector.divider)
7806 .filter(selector.item + ':not(.' + className.filtered + ')')
7807 // Hide divider if no items are found
7808 .length === 0;
7809 })
7810 .addClass(className.hidden)
7811 ;
7812 }
7813 },
7814
7815 fuzzySearch: function (query, term) {
7816 var
7817 termLength = term.length,
7818 queryLength = query.length
7819 ;
7820 query = settings.ignoreSearchCase ? query.toLowerCase() : query;
7821 term = settings.ignoreSearchCase ? term.toLowerCase() : term;
7822 if (queryLength > termLength) {
7823 return false;
7824 }
7825 if (queryLength === termLength) {
7826 return query === term;
7827 }
7828 for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
7829 var
7830 continueSearch = false,
7831 queryCharacter = query.charCodeAt(characterIndex)
7832 ;
7833 while (nextCharacterIndex < termLength) {
7834 if (term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
7835 continueSearch = true;
7836
7837 break;
7838 }
7839 }
7840
7841 if (!continueSearch) {
7842 return false;
7843 }
7844 }
7845
7846 return true;
7847 },
7848 exactSearch: function (query, term) {
7849 query = settings.ignoreSearchCase ? query.toLowerCase() : query;
7850 term = settings.ignoreSearchCase ? term.toLowerCase() : term;
7851
7852 return term.indexOf(query) > -1;
7853 },
7854 filterActive: function () {
7855 if (settings.useLabels) {
7856 $item.filter('.' + className.active)
7857 .addClass(className.filtered)
7858 ;
7859 }
7860 },
7861
7862 focusSearch: function (skipHandler) {
7863 if (module.has.search() && !module.is.focusedOnSearch()) {
7864 if (skipHandler) {
7865 $module.off('focus' + eventNamespace, selector.search);
7866 $search.trigger('focus');
7867 $module.on('focus' + eventNamespace, selector.search, module.event.search.focus);
7868 } else {
7869 $search.trigger('focus');
7870 }
7871 }
7872 },
7873
7874 blurSearch: function () {
7875 if (module.has.search()) {
7876 $search.trigger('blur');
7877 }
7878 },
7879
7880 forceSelection: function () {
7881 var
7882 $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
7883 $activeItem = $item.not(className.filtered).filter('.' + className.active).eq(0),
7884 $selectedItem = $currentlySelected.length > 0
7885 ? $currentlySelected
7886 : $activeItem,
7887 hasSelected = $selectedItem.length > 0
7888 ;
7889 if (settings.allowAdditions || (hasSelected && !module.is.multiple())) {
7890 module.debug('Forcing partial selection to selected item', $selectedItem);
7891 module.event.item.click.call($selectedItem, {}, true);
7892 } else {
7893 module.remove.searchTerm();
7894 }
7895 },
7896
7897 change: {
7898 values: function (values) {
7899 if (!settings.allowAdditions) {
7900 module.clear();
7901 }
7902 module.debug('Creating dropdown with specified values', values);
7903 var menuConfig = {};
7904 menuConfig[fields.values] = values;
7905 module.setup.menu(menuConfig);
7906 $.each(values, function (index, item) {
7907 if (item.selected === true) {
7908 module.debug('Setting initial selection to', item[fields.value]);
7909 module.set.selected(item[fields.value]);
7910 if (!module.is.multiple()) {
7911 return false;
7912 }
7913 }
7914 });
7915
7916 if (module.has.selectInput()) {
7917 module.disconnect.selectObserver();
7918 $input.html('');
7919 $input.append('<option disabled selected value></option>');
7920 $.each(values, function (index, item) {
7921 var
7922 value = settings.templates.deQuote(item[fields.value]),
7923 name = settings.templates.escape(
7924 item[fields.name] || '',
7925 settings.preserveHTML
7926 )
7927 ;
7928 $input.append('<option value="' + value + '"' + (item.selected === true ? ' selected' : '') + '>' + name + '</option>');
7929 });
7930 module.observe.select();
7931 }
7932 },
7933 },
7934
7935 event: {
7936 paste: function (event) {
7937 var
7938 pasteValue = (event.originalEvent.clipboardData || window.clipboardData).getData('text'),
7939 tokens = pasteValue.split(settings.delimiter),
7940 notFoundTokens = []
7941 ;
7942 tokens.forEach(function (value) {
7943 if (module.set.selected(module.escape.htmlEntities(value.trim()), null, false, true) === false) {
7944 notFoundTokens.push(value.trim());
7945 }
7946 });
7947 event.preventDefault();
7948 if (notFoundTokens.length > 0) {
7949 var searchEl = $search[0],
7950 startPos = searchEl.selectionStart,
7951 endPos = searchEl.selectionEnd,
7952 orgText = searchEl.value,
7953 pasteText = notFoundTokens.join(settings.delimiter),
7954 newEndPos = startPos + pasteText.length
7955 ;
7956 $search.val(orgText.slice(0, startPos) + pasteText + orgText.slice(endPos));
7957 searchEl.selectionStart = newEndPos;
7958 searchEl.selectionEnd = newEndPos;
7959 module.event.input(event);
7960 }
7961 },
7962 change: function () {
7963 if (!internalChange) {
7964 module.debug('Input changed, updating selection');
7965 module.set.selected();
7966 }
7967 },
7968 focus: function () {
7969 if (settings.showOnFocus && !activated && module.is.hidden() && !pageLostFocus) {
7970 focused = true;
7971 module.show();
7972 }
7973 },
7974 blur: function (event) {
7975 pageLostFocus = document.activeElement === this;
7976 if (!activated && !pageLostFocus) {
7977 module.remove.activeLabel();
7978 module.hide();
7979 }
7980 },
7981 mousedown: function () {
7982 if (module.is.searchSelection(true)) {
7983 // prevent menu hiding on immediate re-focus
7984 willRefocus = true;
7985 } else {
7986 // prevents focus callback from occurring on mousedown
7987 activated = true;
7988 }
7989 },
7990 mouseup: function () {
7991 if (module.is.searchSelection(true)) {
7992 // prevent menu hiding on immediate re-focus
7993 willRefocus = false;
7994 } else {
7995 activated = false;
7996 }
7997 },
7998 click: function (event) {
7999 var
8000 $target = $(event.target)
8001 ;
8002 // focus search
8003 if ($target.is($module)) {
8004 if (!module.is.focusedOnSearch()) {
8005 module.focusSearch();
8006 } else {
8007 module.show();
8008 }
8009 }
8010 },
8011 search: {
8012 focus: function (event) {
8013 activated = true;
8014 if (module.is.multiple()) {
8015 module.remove.activeLabel();
8016 }
8017 if (!focused && !module.is.active() && (settings.showOnFocus || (event.type !== 'focus' && event.type !== 'focusin')) && event.type !== 'touchstart') {
8018 focused = true;
8019 module.search();
8020 }
8021 },
8022 blur: function (event) {
8023 pageLostFocus = document.activeElement === this;
8024 if (module.is.searchSelection(true) && !willRefocus) {
8025 if (!itemActivated && !pageLostFocus) {
8026 if (settings.forceSelection) {
8027 module.forceSelection();
8028 } else if (!settings.allowAdditions) {
8029 module.remove.searchTerm();
8030 }
8031 module.hide();
8032 }
8033 }
8034 willRefocus = false;
8035 },
8036 },
8037 clearIcon: {
8038 click: function (event) {
8039 module.clear();
8040 if (module.is.searchSelection()) {
8041 module.remove.searchTerm();
8042 }
8043 module.hide();
8044 event.stopPropagation();
8045 },
8046 },
8047 icon: {
8048 click: function (event) {
8049 iconClicked = true;
8050 if (module.has.search()) {
8051 if (!module.is.active()) {
8052 if (settings.showOnFocus) {
8053 module.focusSearch();
8054 } else {
8055 module.toggle();
8056 }
8057 } else {
8058 module.blurSearch();
8059 }
8060 } else {
8061 module.toggle();
8062 }
8063 event.stopPropagation();
8064 },
8065 },
8066 text: {
8067 focus: function (event) {
8068 activated = true;
8069 module.focusSearch();
8070 },
8071 },
8072 input: function (event) {
8073 if (module.is.multiple() || module.is.searchSelection()) {
8074 module.set.filtered();
8075 }
8076 clearTimeout(module.timer);
8077 module.timer = setTimeout(function () { module.search(); }, settings.delay.search);
8078 },
8079 label: {
8080 click: function (event) {
8081 var
8082 $label = $(this),
8083 $labels = $module.find(selector.label),
8084 $activeLabels = $labels.filter('.' + className.active),
8085 $nextActive = $label.nextAll('.' + className.active),
8086 $prevActive = $label.prevAll('.' + className.active),
8087 $range = $nextActive.length > 0
8088 ? $label.nextUntil($nextActive).add($activeLabels).add($label)
8089 : $label.prevUntil($prevActive).add($activeLabels).add($label)
8090 ;
8091 if (event.shiftKey) {
8092 $activeLabels.removeClass(className.active);
8093 $range.addClass(className.active);
8094 } else if (event.ctrlKey) {
8095 $label.toggleClass(className.active);
8096 } else {
8097 $activeLabels.removeClass(className.active);
8098 $label.addClass(className.active);
8099 }
8100 settings.onLabelSelect.apply(this, $labels.filter('.' + className.active));
8101 event.stopPropagation();
8102 },
8103 },
8104 remove: {
8105 click: function (event) {
8106 var
8107 $label = $(this).parent()
8108 ;
8109 if ($label.hasClass(className.active)) {
8110 // remove all selected labels
8111 module.remove.activeLabels();
8112 } else {
8113 // remove this label only
8114 module.remove.activeLabels($label);
8115 }
8116 event.stopPropagation();
8117 },
8118 },
8119 test: {
8120 toggle: function (event) {
8121 var
8122 toggleBehavior = module.is.multiple()
8123 ? module.show
8124 : module.toggle
8125 ;
8126 if (module.is.bubbledLabelClick(event) || module.is.bubbledIconClick(event)) {
8127 return;
8128 }
8129 if (!module.is.multiple() || (module.is.multiple() && !module.is.active())) {
8130 focused = true;
8131 }
8132 if (module.determine.eventOnElement(event, toggleBehavior) && event.type !== 'touchstart') {
8133 // do not preventDefault of touchstart; so emulated mouseenter is triggered on first touch and not later
8134 // (when selecting an item). The double-showing of the dropdown through both events does not hurt.
8135 event.preventDefault();
8136 }
8137 },
8138 hide: function (event) {
8139 if (module.determine.eventInModule(event, module.hide)) {
8140 if (element.id && $(event.target).attr('for') === element.id) {
8141 event.preventDefault();
8142 }
8143 }
8144 },
8145 },
8146 class: {
8147 mutation: function (mutations) {
8148 mutations.forEach(function (mutation) {
8149 if (mutation.attributeName === 'class') {
8150 module.check.disabled();
8151 }
8152 });
8153 },
8154 },
8155 select: {
8156 mutation: function (mutations) {
8157 if (module.is.selectMutation(mutations)) {
8158 module.debug('<select> modified, recreating menu');
8159 module.disconnect.selectObserver();
8160 module.refresh();
8161 module.setup.select();
8162 module.set.selected();
8163 module.observe.select();
8164 }
8165 },
8166 },
8167 menu: {
8168 mutation: function (mutations) {
8169 var
8170 mutation = mutations[0],
8171 $addedNode = mutation.addedNodes
8172 ? $(mutation.addedNodes[0])
8173 : $(false),
8174 $removedNode = mutation.removedNodes
8175 ? $(mutation.removedNodes[0])
8176 : $(false),
8177 $changedNodes = $addedNode.add($removedNode),
8178 isUserAddition = $changedNodes.is(selector.addition) || $changedNodes.closest(selector.addition).length > 0,
8179 isMessage = $changedNodes.is(selector.message) || $changedNodes.closest(selector.message).length > 0
8180 ;
8181 if (isUserAddition || isMessage) {
8182 module.debug('Updating item selector cache');
8183 module.refreshItems();
8184 } else {
8185 module.debug('Menu modified, updating selector cache');
8186 module.refresh();
8187 }
8188 },
8189 mousedown: function () {
8190 itemActivated = true;
8191 },
8192 mouseup: function () {
8193 itemActivated = false;
8194 },
8195 },
8196 item: {
8197 mouseenter: function (event) {
8198 var
8199 $target = $(event.target),
8200 $item = $(this),
8201 $subMenu = $item.children(selector.menu),
8202 $otherMenus = $item.siblings(selector.item).children(selector.menu),
8203 hasSubMenu = $subMenu.length > 0,
8204 isBubbledEvent = $subMenu.find($target).length > 0
8205 ;
8206 if (!isBubbledEvent && hasSubMenu) {
8207 clearTimeout(module.itemTimer);
8208 module.itemTimer = setTimeout(function () {
8209 module.verbose('Showing sub-menu', $subMenu);
8210 $.each($otherMenus, function () {
8211 module.animate.hide(false, $(this));
8212 });
8213 module.animate.show(false, $subMenu);
8214 }, settings.delay.show);
8215 event.preventDefault();
8216 }
8217 },
8218 mouseleave: function (event) {
8219 var
8220 $subMenu = $(this).find(selector.menu)
8221 ;
8222 if ($subMenu.length > 0) {
8223 clearTimeout(module.itemTimer);
8224 module.itemTimer = setTimeout(function () {
8225 module.verbose('Hiding sub-menu', $subMenu);
8226 $subMenu.each(function () {
8227 module.animate.hide(false, $(this));
8228 });
8229 }, settings.delay.hide);
8230 }
8231 },
8232 click: function (event, skipRefocus) {
8233 var
8234 $choice = $(this),
8235 $target = event
8236 ? $(event.target || '')
8237 : $(''),
8238 $subMenu = $choice.find(selector.menu),
8239 text = module.get.choiceText($choice),
8240 value = module.get.choiceValue($choice, text),
8241 hasSubMenu = $subMenu.length > 0,
8242 isBubbledEvent = $subMenu.find($target).length > 0
8243 ;
8244 // prevents IE11 bug where menu receives focus even though `tabindex=-1`
8245 if (document.activeElement.tagName.toLowerCase() !== 'input') {
8246 $(document.activeElement).trigger('blur');
8247 }
8248 if (!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
8249 if (module.is.searchSelection()) {
8250 if (settings.allowAdditions) {
8251 module.remove.userAddition();
8252 }
8253 if (!settings.keepSearchTerm) {
8254 module.remove.filteredItem();
8255 module.remove.searchTerm();
8256 }
8257 if (!module.is.visible() && $target.length > 0) {
8258 module.show();
8259 }
8260 if (!module.is.focusedOnSearch() && skipRefocus !== true) {
8261 module.focusSearch(true);
8262 }
8263 }
8264 if (!settings.useLabels) {
8265 module.remove.filteredItem();
8266 module.set.scrollPosition($choice);
8267 }
8268 module.determine.selectAction.call(this, text, value);
8269 }
8270 },
8271 },
8272
8273 document: {
8274 // label selection should occur even when element has no focus
8275 keydown: function (event) {
8276 var
8277 pressedKey = event.which,
8278 isShortcutKey = module.is.inObject(pressedKey, keys)
8279 ;
8280 if (isShortcutKey) {
8281 var
8282 $label = $module.find(selector.label),
8283 $activeLabel = $label.filter('.' + className.active),
8284 activeValue = $activeLabel.data(metadata.value),
8285 labelIndex = $label.index($activeLabel),
8286 labelCount = $label.length,
8287 hasActiveLabel = $activeLabel.length > 0,
8288 hasMultipleActive = $activeLabel.length > 1,
8289 isFirstLabel = labelIndex === 0,
8290 isLastLabel = labelIndex + 1 === labelCount,
8291 isSearch = module.is.searchSelection(),
8292 isFocusedOnSearch = module.is.focusedOnSearch(),
8293 isFocused = module.is.focused(),
8294 caretAtStart = isFocusedOnSearch && module.get.caretPosition(false) === 0,
8295 isSelectedSearch = caretAtStart && module.get.caretPosition(true) !== 0
8296 ;
8297 if (isSearch && !hasActiveLabel && !isFocusedOnSearch) {
8298 return;
8299 }
8300
8301 switch (pressedKey) {
8302 case keys.leftArrow: {
8303 // activate previous label
8304 if ((isFocused || caretAtStart) && !hasActiveLabel) {
8305 module.verbose('Selecting previous label');
8306 $label.last().addClass(className.active);
8307 } else if (hasActiveLabel) {
8308 if (!event.shiftKey) {
8309 module.verbose('Selecting previous label');
8310 $label.removeClass(className.active);
8311 } else {
8312 module.verbose('Adding previous label to selection');
8313 }
8314 if (isFirstLabel && !hasMultipleActive) {
8315 $activeLabel.addClass(className.active);
8316 } else {
8317 $activeLabel.prev(selector.siblingLabel)
8318 .addClass(className.active)
8319 .end()
8320 ;
8321 }
8322 event.preventDefault();
8323 }
8324
8325 break;
8326 }
8327 case keys.rightArrow: {
8328 // activate first label
8329 if (isFocused && !hasActiveLabel) {
8330 $label.first().addClass(className.active);
8331 }
8332 // activate next label
8333 if (hasActiveLabel) {
8334 if (!event.shiftKey) {
8335 module.verbose('Selecting next label');
8336 $label.removeClass(className.active);
8337 } else {
8338 module.verbose('Adding next label to selection');
8339 }
8340 if (isLastLabel) {
8341 if (isSearch) {
8342 if (!isFocusedOnSearch) {
8343 module.focusSearch();
8344 } else {
8345 $label.removeClass(className.active);
8346 }
8347 } else if (hasMultipleActive) {
8348 $activeLabel.next(selector.siblingLabel).addClass(className.active);
8349 } else {
8350 $activeLabel.addClass(className.active);
8351 }
8352 } else {
8353 $activeLabel.next(selector.siblingLabel).addClass(className.active);
8354 }
8355 event.preventDefault();
8356 }
8357
8358 break;
8359 }
8360 case keys.deleteKey:
8361 case keys.backspace: {
8362 if (hasActiveLabel) {
8363 module.verbose('Removing active labels');
8364 if (isLastLabel) {
8365 if (isSearch && !isFocusedOnSearch) {
8366 module.focusSearch();
8367 }
8368 }
8369 $activeLabel.last().next(selector.siblingLabel).addClass(className.active);
8370 module.remove.activeLabels($activeLabel);
8371 if (!module.is.visible()) {
8372 module.show();
8373 }
8374 event.preventDefault();
8375 } else if (caretAtStart && !isSelectedSearch && !hasActiveLabel && pressedKey === keys.backspace) {
8376 module.verbose('Removing last label on input backspace');
8377 $activeLabel = $label.last().addClass(className.active);
8378 module.remove.activeLabels($activeLabel);
8379 if (!module.is.visible()) {
8380 module.show();
8381 }
8382 }
8383
8384 break;
8385 }
8386 default: {
8387 $activeLabel.removeClass(className.active);
8388 }
8389 }
8390 }
8391 },
8392 },
8393
8394 keydown: function (event) {
8395 var
8396 pressedKey = event.which,
8397 isShortcutKey = module.is.inObject(pressedKey, keys) || event.key === settings.delimiter
8398 ;
8399 if (isShortcutKey) {
8400 var
8401 $currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
8402 $activeItem = $menu.children('.' + className.active).eq(0),
8403 $selectedItem = $currentlySelected.length > 0
8404 ? $currentlySelected
8405 : $activeItem,
8406 $visibleItems = $selectedItem.length > 0
8407 ? $selectedItem.siblings(':not(.' + className.filtered + ')').addBack()
8408 : $menu.children(':not(.' + className.filtered + ')'),
8409 $subMenu = $selectedItem.children(selector.menu),
8410 $parentMenu = $selectedItem.closest(selector.menu),
8411 inVisibleMenu = $parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0,
8412 hasSubMenu = $subMenu.length > 0,
8413 hasSelectedItem = $selectedItem.length > 0,
8414 selectedIsSelectable = $selectedItem.not(selector.unselectable).length > 0,
8415 delimiterPressed = event.key === settings.delimiter && module.is.multiple(),
8416 isAdditionWithoutMenu = settings.allowAdditions && (pressedKey === keys.enter || delimiterPressed),
8417 $nextItem,
8418 isSubMenuItem
8419 ;
8420 // allow selection with menu closed
8421 if (isAdditionWithoutMenu) {
8422 if (selectedIsSelectable && settings.hideAdditions) {
8423 module.verbose('Selecting item from keyboard shortcut', $selectedItem);
8424 module.event.item.click.call($selectedItem, event);
8425 }
8426 if (module.is.searchSelection()) {
8427 module.remove.searchTerm();
8428 }
8429 if (module.is.multiple()) {
8430 event.preventDefault();
8431 }
8432 }
8433
8434 // visible menu keyboard shortcuts
8435 if (module.is.visible()) {
8436 // enter (select or open sub-menu)
8437 if (pressedKey === keys.enter || delimiterPressed) {
8438 if (pressedKey === keys.enter && hasSelectedItem && hasSubMenu && !settings.allowCategorySelection) {
8439 module.verbose('Pressed enter on unselectable category, opening sub menu');
8440 pressedKey = keys.rightArrow;
8441 } else if (selectedIsSelectable) {
8442 module.verbose('Selecting item from keyboard shortcut', $selectedItem);
8443 module.event.item.click.call($selectedItem, event);
8444 if (module.is.searchSelection()) {
8445 if (!settings.keepSearchTerm) {
8446 module.remove.searchTerm();
8447 }
8448 if (module.is.multiple()) {
8449 $search.trigger('focus');
8450 }
8451 }
8452 }
8453 event.preventDefault();
8454 }
8455
8456 // sub-menu actions
8457 if (hasSelectedItem) {
8458 if (pressedKey === keys.leftArrow) {
8459 isSubMenuItem = $parentMenu[0] !== $menu[0];
8460
8461 if (isSubMenuItem) {
8462 module.verbose('Left key pressed, closing sub-menu');
8463 module.animate.hide(false, $parentMenu);
8464 $selectedItem
8465 .removeClass(className.selected)
8466 ;
8467 $parentMenu
8468 .closest(selector.item)
8469 .addClass(className.selected)
8470 ;
8471 event.preventDefault();
8472 }
8473 }
8474
8475 // right arrow (show sub-menu)
8476 if (pressedKey === keys.rightArrow) {
8477 if (hasSubMenu) {
8478 module.verbose('Right key pressed, opening sub-menu');
8479 module.animate.show(false, $subMenu);
8480 $selectedItem
8481 .removeClass(className.selected)
8482 ;
8483 $subMenu
8484 .find(selector.item).eq(0)
8485 .addClass(className.selected)
8486 ;
8487 event.preventDefault();
8488 }
8489 }
8490 }
8491
8492 // up arrow (traverse menu up)
8493 if (pressedKey === keys.upArrow) {
8494 $nextItem = hasSelectedItem && inVisibleMenu
8495 ? $selectedItem.prevAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
8496 : $item.eq(0);
8497 if ($visibleItems.index($nextItem) < 0) {
8498 module.verbose('Up key pressed but reached top of current menu');
8499 event.preventDefault();
8500
8501 return;
8502 }
8503
8504 module.verbose('Up key pressed, changing active item');
8505 $selectedItem
8506 .removeClass(className.selected)
8507 ;
8508 $nextItem
8509 .addClass(className.selected)
8510 ;
8511 module.set.scrollPosition($nextItem);
8512 if (settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
8513 module.set.selectedItem($nextItem);
8514 }
8515
8516 event.preventDefault();
8517 }
8518
8519 // down arrow (traverse menu down)
8520 if (pressedKey === keys.downArrow) {
8521 $nextItem = hasSelectedItem && inVisibleMenu
8522 ? $selectedItem.nextAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
8523 : $item.eq(0);
8524 if ($nextItem.length === 0) {
8525 module.verbose('Down key pressed but reached bottom of current menu');
8526 event.preventDefault();
8527
8528 return;
8529 }
8530
8531 module.verbose('Down key pressed, changing active item');
8532 $item
8533 .removeClass(className.selected)
8534 ;
8535 $nextItem
8536 .addClass(className.selected)
8537 ;
8538 module.set.scrollPosition($nextItem);
8539 if (settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
8540 module.set.selectedItem($nextItem);
8541 }
8542
8543 event.preventDefault();
8544 }
8545
8546 // page down (show next page)
8547 if (pressedKey === keys.pageUp) {
8548 module.scrollPage('up');
8549 event.preventDefault();
8550 }
8551 if (pressedKey === keys.pageDown) {
8552 module.scrollPage('down');
8553 event.preventDefault();
8554 }
8555
8556 // escape (close menu)
8557 if (pressedKey === keys.escape) {
8558 module.verbose('Escape key pressed, closing dropdown');
8559 module.hide();
8560 event.stopPropagation();
8561 }
8562 } else {
8563 // delimiter key
8564 if (pressedKey === keys.enter || delimiterPressed) {
8565 event.preventDefault();
8566 }
8567 // down arrow (open menu)
8568 if (pressedKey === keys.downArrow && !module.is.visible()) {
8569 module.verbose('Down key pressed, showing dropdown');
8570 module.show();
8571 event.preventDefault();
8572 }
8573 }
8574 } else {
8575 if (!module.has.search()) {
8576 module.set.selectedLetter(String.fromCharCode(pressedKey));
8577 }
8578 }
8579 },
8580 },
8581
8582 trigger: {
8583 change: function () {
8584 var
8585 inputElement = $input[0]
8586 ;
8587 if (inputElement) {
8588 var events = document.createEvent('HTMLEvents');
8589 module.verbose('Triggering native change event');
8590 events.initEvent('change', true, false);
8591 inputElement.dispatchEvent(events);
8592 }
8593 },
8594 },
8595
8596 determine: {
8597 selectAction: function (text, value) {
8598 selectActionActive = true;
8599 module.verbose('Determining action', settings.action);
8600 if (isFunction(module.action[settings.action])) {
8601 module.verbose('Triggering preset action', settings.action, text, value);
8602 module.action[settings.action].call(element, text, value, this);
8603 } else if (isFunction(settings.action)) {
8604 module.verbose('Triggering user action', settings.action, text, value);
8605 settings.action.call(element, text, value, this);
8606 } else {
8607 module.error(error.action, settings.action);
8608 }
8609 selectActionActive = false;
8610 },
8611 eventInModule: function (event, callback) {
8612 var
8613 $target = $(event.target),
8614 inDocument = $target.closest(document.documentElement).length > 0,
8615 inModule = $target.closest($module).length > 0
8616 ;
8617 callback = isFunction(callback)
8618 ? callback
8619 : function () {};
8620 if (inDocument && !inModule) {
8621 module.verbose('Triggering event', callback);
8622 callback();
8623
8624 return true;
8625 }
8626
8627 module.verbose('Event occurred in dropdown, canceling callback');
8628
8629 return false;
8630 },
8631 eventOnElement: function (event, callback) {
8632 var
8633 $target = $(event.target),
8634 $label = $target.closest(selector.siblingLabel),
8635 inVisibleDOM = document.body.contains(event.target),
8636 notOnLabel = $module.find($label).length === 0 || !(module.is.multiple() && settings.useLabels),
8637 notInMenu = $target.closest($menu).length === 0
8638 ;
8639 callback = isFunction(callback)
8640 ? callback
8641 : function () {};
8642 if (inVisibleDOM && notOnLabel && notInMenu) {
8643 module.verbose('Triggering event', callback);
8644 callback();
8645
8646 return true;
8647 }
8648
8649 module.verbose('Event occurred in dropdown menu, canceling callback');
8650
8651 return false;
8652 },
8653 },
8654
8655 action: {
8656
8657 nothing: function () {},
8658
8659 activate: function (text, value, element) {
8660 value = value !== undefined
8661 ? value
8662 : text;
8663 if (module.can.activate($(element))) {
8664 module.set.selected(value, $(element), false, settings.keepSearchTerm);
8665 if (!module.is.multiple() && !(!settings.collapseOnActionable && $(element).hasClass(className.actionable))) {
8666 module.hideAndClear();
8667 }
8668 }
8669 },
8670
8671 select: function (text, value, element) {
8672 value = value !== undefined
8673 ? value
8674 : text;
8675 if (module.can.activate($(element))) {
8676 module.set.value(value, text, $(element));
8677 if (!module.is.multiple() && !(!settings.collapseOnActionable && $(element).hasClass(className.actionable))) {
8678 module.hideAndClear();
8679 }
8680 }
8681 },
8682
8683 combo: function (text, value, element) {
8684 value = value !== undefined
8685 ? value
8686 : text;
8687 module.set.selected(value, $(element));
8688 module.hideAndClear();
8689 },
8690
8691 hide: function (text, value, element) {
8692 module.set.value(value, text, $(element));
8693 module.hideAndClear();
8694 },
8695
8696 },
8697
8698 get: {
8699 id: function () {
8700 return id;
8701 },
8702 defaultText: function () {
8703 return $module.data(metadata.defaultText);
8704 },
8705 defaultValue: function () {
8706 return $module.data(metadata.defaultValue);
8707 },
8708 placeholderText: function () {
8709 if (settings.placeholder !== 'auto' && typeof settings.placeholder === 'string') {
8710 return settings.placeholder;
8711 }
8712
8713 return $module.data(metadata.placeholderText) || '';
8714 },
8715 text: function () {
8716 return settings.preserveHTML ? $text.html() : $text.text();
8717 },
8718 query: function () {
8719 return String($search.val()).trim();
8720 },
8721 searchWidth: function (value) {
8722 value = value !== undefined
8723 ? value
8724 : $search.val();
8725 $sizer.text(value);
8726
8727 // prevent rounding issues
8728 return Math.ceil($sizer.width() + (module.is.edge() ? 3 : 1));
8729 },
8730 selectionCount: function () {
8731 var
8732 values = module.get.values(),
8733 count
8734 ;
8735 count = module.is.multiple()
8736 ? (Array.isArray(values) ? values.length : 0)
8737 : (module.get.value() !== '' ? 1 : 0);
8738
8739 return count;
8740 },
8741 transition: function ($subMenu) {
8742 return settings.transition === 'auto'
8743 ? (module.is.upward($subMenu) ? 'slide up' : 'slide down')
8744 : settings.transition;
8745 },
8746 userValues: function () {
8747 var
8748 values = module.get.values(true)
8749 ;
8750 if (!values) {
8751 return false;
8752 }
8753 values = Array.isArray(values)
8754 ? values
8755 : [values];
8756
8757 return $.grep(values, function (value) {
8758 return module.get.item(value) === false;
8759 });
8760 },
8761 uniqueArray: function (array) {
8762 return $.grep(array, function (value, index) {
8763 return $.inArray(value, array) === index;
8764 });
8765 },
8766 caretPosition: function (returnEndPos) {
8767 var
8768 input = $search[0],
8769 range,
8770 rangeLength
8771 ;
8772 if (returnEndPos && 'selectionEnd' in input) {
8773 return input.selectionEnd;
8774 }
8775 if (!returnEndPos && 'selectionStart' in input) {
8776 return input.selectionStart;
8777 }
8778 if (document.selection) {
8779 input.focus();
8780 range = document.selection.createRange();
8781 rangeLength = range.text.length;
8782 if (returnEndPos) {
8783 return rangeLength;
8784 }
8785 range.moveStart('character', -input.value.length);
8786
8787 return range.text.length - rangeLength;
8788 }
8789 },
8790 value: function () {
8791 var
8792 value = $input.length > 0
8793 ? $input.val()
8794 : $module.data(metadata.value),
8795 isEmptyMultiselect = Array.isArray(value) && value.length === 1 && value[0] === ''
8796 ;
8797
8798 // prevents placeholder element from being selected when multiple
8799 return value === undefined || isEmptyMultiselect
8800 ? ''
8801 : value;
8802 },
8803 values: function (raw) {
8804 var
8805 value = module.get.value()
8806 ;
8807 if (value === '') {
8808 return '';
8809 }
8810
8811 return !module.has.selectInput() && module.is.multiple()
8812 ? (typeof value === 'string' // delimited string
8813 ? (raw
8814 ? value
8815 : module.escape.htmlEntities(value)).split(settings.delimiter)
8816 : '')
8817 : value;
8818 },
8819 remoteValues: function () {
8820 var
8821 values = module.get.values(),
8822 remoteValues = false
8823 ;
8824 if (values) {
8825 if (typeof values === 'string') {
8826 values = [values];
8827 }
8828 $.each(values, function (index, value) {
8829 var
8830 name = module.read.remoteData(value)
8831 ;
8832 module.verbose('Restoring value from session data', name, value);
8833 if (name) {
8834 if (!remoteValues) {
8835 remoteValues = {};
8836 }
8837 remoteValues[value] = name;
8838 }
8839 });
8840 }
8841
8842 return remoteValues;
8843 },
8844 choiceText: function ($choice, preserveHTML) {
8845 preserveHTML = preserveHTML !== undefined
8846 ? preserveHTML
8847 : settings.preserveHTML;
8848 if ($choice) {
8849 if ($choice.find(selector.menu).length > 0) {
8850 module.verbose('Retrieving text of element with sub-menu');
8851 $choice = $choice.clone();
8852 $choice.find(selector.menu).remove();
8853 $choice.find(selector.menuIcon).remove();
8854 }
8855
8856 return $choice.data(metadata.text) !== undefined
8857 ? $choice.data(metadata.text)
8858 : (preserveHTML
8859 ? $choice.html() && $choice.html().trim()
8860 : $choice.text() && $choice.text().trim());
8861 }
8862 },
8863 choiceValue: function ($choice, choiceText) {
8864 choiceText = choiceText || module.get.choiceText($choice);
8865 if (!$choice) {
8866 return false;
8867 }
8868
8869 return $choice.data(metadata.value) !== undefined
8870 ? String($choice.data(metadata.value))
8871 : (typeof choiceText === 'string'
8872 ? String(
8873 settings.ignoreSearchCase
8874 ? choiceText.toLowerCase()
8875 : choiceText
8876 ).trim()
8877 : String(choiceText));
8878 },
8879 inputEvent: function () {
8880 var
8881 input = $search[0]
8882 ;
8883 if (input) {
8884 return input.oninput !== undefined
8885 ? 'input'
8886 : (input.onpropertychange !== undefined
8887 ? 'propertychange'
8888 : 'keyup');
8889 }
8890
8891 return false;
8892 },
8893 selectValues: function () {
8894 var
8895 select = {},
8896 oldGroup = [],
8897 values = []
8898 ;
8899 $module
8900 .find('option')
8901 .each(function () {
8902 var
8903 $option = $(this),
8904 name = $option.html(),
8905 disabled = $option.attr('disabled'),
8906 value = $option.attr('value') !== undefined
8907 ? $option.attr('value')
8908 : name,
8909 text = $option.data(metadata.text) !== undefined
8910 ? $option.data(metadata.text)
8911 : name,
8912 group = $option.parent('optgroup')
8913 ;
8914 if (settings.placeholder === 'auto' && value === '') {
8915 select.placeholder = name;
8916 } else {
8917 if (group.length !== oldGroup.length || group[0] !== oldGroup[0]) {
8918 values.push({
8919 type: 'header',
8920 divider: settings.headerDivider,
8921 name: group.attr('label') || '',
8922 });
8923 oldGroup = group;
8924 }
8925 values.push({
8926 name: name,
8927 value: value,
8928 text: module.escape.htmlEntities(text, true),
8929 disabled: disabled,
8930 });
8931 }
8932 })
8933 ;
8934 if (settings.placeholder && settings.placeholder !== 'auto') {
8935 module.debug('Setting placeholder value to', settings.placeholder);
8936 select.placeholder = settings.placeholder;
8937 }
8938 if (settings.sortSelect) {
8939 if (settings.sortSelect === true) {
8940 values.sort(function (a, b) {
8941 return a.name.localeCompare(b.name);
8942 });
8943 } else if (settings.sortSelect === 'natural') {
8944 values.sort(function (a, b) {
8945 return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
8946 });
8947 } else if (isFunction(settings.sortSelect)) {
8948 values.sort(settings.sortSelect);
8949 }
8950 select[fields.values] = values;
8951 module.debug('Retrieved and sorted values from select', select);
8952 } else {
8953 select[fields.values] = values;
8954 module.debug('Retrieved values from select', select);
8955 }
8956
8957 return select;
8958 },
8959 activeItem: function () {
8960 return $item.filter('.' + className.active);
8961 },
8962 selectedItem: function () {
8963 var
8964 $selectedItem = $item.not(selector.unselectable).filter('.' + className.selected)
8965 ;
8966
8967 return $selectedItem.length > 0
8968 ? $selectedItem
8969 : $item.eq(0);
8970 },
8971 itemWithAdditions: function (value) {
8972 var
8973 $items = module.get.item(value),
8974 $userItems = module.create.userChoice(value),
8975 hasUserItems = $userItems && $userItems.length > 0
8976 ;
8977 if (hasUserItems) {
8978 $items = $items.length > 0
8979 ? $items.add($userItems)
8980 : $userItems;
8981 }
8982
8983 return $items;
8984 },
8985 item: function (value, strict) {
8986 var
8987 $selectedItem = false,
8988 shouldSearch,
8989 isMultiple
8990 ;
8991 value = value !== undefined
8992 ? value
8993 : (module.get.values() !== undefined
8994 ? module.get.values()
8995 : module.get.text());
8996 isMultiple = module.is.multiple() && Array.isArray(value);
8997 shouldSearch = isMultiple
8998 ? value.length > 0
8999 : value !== undefined && value !== null;
9000 strict = value === '' || value === false || value === true
9001 ? true
9002 : strict || false;
9003 if (shouldSearch) {
9004 $item
9005 .each(function () {
9006 var
9007 $choice = $(this),
9008 optionText = module.get.choiceText($choice),
9009 optionValue = module.get.choiceValue($choice, optionText)
9010 ;
9011 // safe early exit
9012 if (optionValue === null || optionValue === undefined) {
9013 return;
9014 }
9015 if (isMultiple) {
9016 if ($.inArray(module.escape.htmlEntities(String(optionValue)), value.map(String).map(module.escape.htmlEntities)) !== -1) {
9017 $selectedItem = $selectedItem
9018 ? $selectedItem.add($choice)
9019 : $choice;
9020 }
9021 } else if (strict) {
9022 module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
9023 if (optionValue === value) {
9024 $selectedItem = $choice;
9025
9026 return true;
9027 }
9028 } else {
9029 if (settings.ignoreCase) {
9030 optionValue = optionValue.toLowerCase();
9031 value = value.toLowerCase();
9032 }
9033 if (module.escape.htmlEntities(String(optionValue)) === module.escape.htmlEntities(String(value))) {
9034 module.verbose('Found select item by value', optionValue, value);
9035 $selectedItem = $choice;
9036
9037 return true;
9038 }
9039 }
9040 })
9041 ;
9042 }
9043
9044 return $selectedItem;
9045 },
9046 displayType: function () {
9047 return $module.hasClass('column') ? 'flex' : settings.displayType;
9048 },
9049 },
9050
9051 check: {
9052 maxSelections: function (selectionCount) {
9053 if (settings.maxSelections) {
9054 selectionCount = selectionCount !== undefined
9055 ? selectionCount
9056 : module.get.selectionCount();
9057 if (selectionCount >= settings.maxSelections) {
9058 module.debug('Maximum selection count reached');
9059 if (settings.useLabels) {
9060 $item.addClass(className.filtered);
9061 module.add.message(message.maxSelections);
9062 }
9063
9064 return true;
9065 }
9066
9067 module.verbose('No longer at maximum selection count');
9068 module.remove.message();
9069 module.remove.filteredItem();
9070 if (module.is.searchSelection()) {
9071 module.filterItems();
9072 }
9073
9074 return false;
9075 }
9076
9077 return false;
9078 },
9079 disabled: function () {
9080 $search.attr('tabindex', module.is.disabled() ? -1 : 0);
9081 },
9082 },
9083
9084 restore: {
9085 defaults: function (preventChangeTrigger) {
9086 module.clear(preventChangeTrigger);
9087 module.restore.defaultText();
9088 module.restore.defaultValue();
9089 },
9090 defaultText: function () {
9091 var
9092 defaultText = module.get.defaultText(),
9093 placeholderText = module.get.placeholderText
9094 ;
9095 if (defaultText === placeholderText) {
9096 module.debug('Restoring default placeholder text', defaultText);
9097 module.set.placeholderText(defaultText);
9098 } else {
9099 module.debug('Restoring default text', defaultText);
9100 module.set.text(defaultText);
9101 }
9102 },
9103 placeholderText: function () {
9104 module.set.placeholderText();
9105 },
9106 defaultValue: function () {
9107 var
9108 defaultValue = module.get.defaultValue()
9109 ;
9110 if (defaultValue !== undefined) {
9111 module.debug('Restoring default value', defaultValue);
9112 if (defaultValue !== '') {
9113 module.set.value(defaultValue);
9114 module.set.selected();
9115 } else {
9116 module.remove.activeItem();
9117 module.remove.selectedItem();
9118 }
9119 }
9120 },
9121 labels: function () {
9122 if (settings.allowAdditions) {
9123 if (!settings.useLabels) {
9124 module.error(error.labels);
9125 settings.useLabels = true;
9126 }
9127 module.debug('Restoring selected values');
9128 module.create.userLabels();
9129 }
9130 module.check.maxSelections();
9131 },
9132 selected: function () {
9133 module.restore.values();
9134 if (module.is.multiple()) {
9135 module.debug('Restoring previously selected values and labels');
9136 module.restore.labels();
9137 } else {
9138 module.debug('Restoring previously selected values');
9139 }
9140 },
9141 values: function () {
9142 // prevents callbacks from occurring on initial load
9143 module.set.initialLoad();
9144 if (settings.apiSettings && settings.saveRemoteData && module.get.remoteValues()) {
9145 module.restore.remoteValues();
9146 } else {
9147 module.set.selected();
9148 }
9149 var value = module.get.value();
9150 if (value && value !== '' && !(Array.isArray(value) && value.length === 0)) {
9151 $input.removeClass(className.noselection);
9152 } else {
9153 $input.addClass(className.noselection);
9154 }
9155 module.remove.initialLoad();
9156 },
9157 remoteValues: function () {
9158 var
9159 values = module.get.remoteValues()
9160 ;
9161 module.debug('Recreating selected from session data', values);
9162 if (values) {
9163 if (module.is.single()) {
9164 $.each(values, function (value, name) {
9165 module.set.text(name);
9166 });
9167 } else if (settings.useLabels) {
9168 $.each(values, function (value, name) {
9169 module.add.label(value, name);
9170 });
9171 }
9172 }
9173 },
9174 },
9175
9176 read: {
9177 remoteData: function (value) {
9178 var
9179 name
9180 ;
9181 if (window.Storage === undefined) {
9182 module.error(error.noStorage);
9183
9184 return;
9185 }
9186 name = sessionStorage.getItem(value + elementNamespace);
9187
9188 return name !== undefined
9189 ? name
9190 : false;
9191 },
9192 },
9193
9194 save: {
9195 defaults: function () {
9196 module.save.defaultText();
9197 module.save.placeholderText();
9198 module.save.defaultValue();
9199 },
9200 defaultValue: function () {
9201 var
9202 value = module.get.value()
9203 ;
9204 module.verbose('Saving default value as', value);
9205 $module.data(metadata.defaultValue, value);
9206 },
9207 defaultText: function () {
9208 var
9209 text = module.get.text()
9210 ;
9211 module.verbose('Saving default text as', text);
9212 $module.data(metadata.defaultText, text);
9213 },
9214 placeholderText: function () {
9215 var
9216 text
9217 ;
9218 if (settings.placeholder !== false && $text.hasClass(className.placeholder)) {
9219 text = module.get.text();
9220 module.verbose('Saving placeholder text as', text);
9221 $module.data(metadata.placeholderText, text);
9222 }
9223 },
9224 remoteData: function (name, value) {
9225 if (window.Storage === undefined) {
9226 module.error(error.noStorage);
9227
9228 return;
9229 }
9230 module.verbose('Saving remote data to session storage', value, name);
9231 sessionStorage.setItem(value + elementNamespace, name);
9232 },
9233 },
9234
9235 clear: function (preventChangeTrigger) {
9236 if (module.is.multiple() && settings.useLabels) {
9237 module.remove.labels($module.find(selector.label), preventChangeTrigger);
9238 } else {
9239 module.remove.activeItem();
9240 module.remove.selectedItem();
9241 module.remove.filteredItem();
9242 }
9243 module.set.placeholderText();
9244 module.clearValue(preventChangeTrigger);
9245 },
9246
9247 clearValue: function (preventChangeTrigger) {
9248 module.set.value('', null, null, preventChangeTrigger);
9249 },
9250
9251 clearCache: function () {
9252 module.debug('Clearing API cache once');
9253 tempDisableApiCache = true;
9254 },
9255
9256 scrollPage: function (direction, $selectedItem) {
9257 var
9258 $currentItem = $selectedItem || module.get.selectedItem(),
9259 $menu = $currentItem.closest(selector.menu),
9260 menuHeight = $menu.outerHeight(),
9261 currentScroll = $menu.scrollTop(),
9262 itemHeight = $item.eq(0).outerHeight(),
9263 itemsPerPage = Math.floor(menuHeight / itemHeight),
9264 newScroll = direction === 'up'
9265 ? currentScroll - (itemHeight * itemsPerPage)
9266 : currentScroll + (itemHeight * itemsPerPage),
9267 $selectableItem = $item.not(selector.unselectable),
9268 isWithinRange,
9269 $nextSelectedItem,
9270 elementIndex
9271 ;
9272 elementIndex = direction === 'up'
9273 ? $selectableItem.index($currentItem) - itemsPerPage
9274 : $selectableItem.index($currentItem) + itemsPerPage;
9275 isWithinRange = direction === 'up'
9276 ? elementIndex >= 0
9277 : elementIndex < $selectableItem.length;
9278 $nextSelectedItem = isWithinRange
9279 ? $selectableItem.eq(elementIndex)
9280 : (direction === 'up'
9281 ? $selectableItem.first()
9282 : $selectableItem.last());
9283 if ($nextSelectedItem.length > 0) {
9284 module.debug('Scrolling page', direction, $nextSelectedItem);
9285 $currentItem
9286 .removeClass(className.selected)
9287 ;
9288 $nextSelectedItem
9289 .addClass(className.selected)
9290 ;
9291 if (settings.selectOnKeydown && module.is.single() && !$nextSelectedItem.hasClass(className.actionable)) {
9292 module.set.selectedItem($nextSelectedItem);
9293 }
9294 $menu
9295 .scrollTop(newScroll)
9296 ;
9297 }
9298 },
9299
9300 set: {
9301 filtered: function () {
9302 var
9303 isMultiple = module.is.multiple(),
9304 isSearch = module.is.searchSelection(),
9305 isSearchMultiple = isMultiple && isSearch,
9306 searchValue = isSearch
9307 ? module.get.query()
9308 : '',
9309 hasSearchValue = typeof searchValue === 'string' && searchValue.length > 0,
9310 searchWidth = module.get.searchWidth(),
9311 valueIsSet = searchValue !== ''
9312 ;
9313 if (isMultiple && hasSearchValue) {
9314 module.verbose('Adjusting input width', searchWidth);
9315 $search.css('width', searchWidth + 'px');
9316 }
9317 if (hasSearchValue || (isSearchMultiple && valueIsSet)) {
9318 module.verbose('Hiding placeholder text');
9319 $text.addClass(className.filtered);
9320 } else if (!isMultiple || (isSearchMultiple && !valueIsSet)) {
9321 module.verbose('Showing placeholder text');
9322 $text.removeClass(className.filtered);
9323 }
9324 },
9325 empty: function () {
9326 $module.addClass(className.empty);
9327 },
9328 loading: function () {
9329 $module.addClass(className.loading);
9330 },
9331 placeholderText: function (text) {
9332 text = text || module.get.placeholderText();
9333 module.debug('Setting placeholder text', text);
9334 module.set.text(text);
9335 $text.addClass(className.placeholder);
9336 },
9337 tabbable: function () {
9338 if (module.is.searchSelection()) {
9339 module.debug('Added tabindex to searchable dropdown');
9340 $search
9341 .val('')
9342 ;
9343 module.check.disabled();
9344 $menu
9345 .attr('tabindex', -1)
9346 ;
9347 } else {
9348 module.debug('Added tabindex to dropdown');
9349 if ($module.attr('tabindex') === undefined) {
9350 $module
9351 .attr('tabindex', $input.attr('tabindex') || 0)
9352 ;
9353 $menu
9354 .attr('tabindex', -1)
9355 ;
9356 }
9357 }
9358 $input.removeAttr('tabindex');
9359 },
9360 initialLoad: function () {
9361 module.verbose('Setting initial load');
9362 initialLoad = true;
9363 },
9364 activeItem: function ($item) {
9365 if (settings.allowAdditions && $item.filter(selector.addition).length > 0) {
9366 $item.addClass(className.filtered);
9367 } else {
9368 $item.addClass(className.active);
9369 }
9370 },
9371 partialSearch: function (text) {
9372 var
9373 length = module.get.query().length
9374 ;
9375 $search.val(text.slice(0, length));
9376 },
9377 scrollPosition: function ($item, forceScroll) {
9378 var
9379 edgeTolerance = 5,
9380 $menu,
9381 hasActive,
9382 offset,
9383 itemOffset,
9384 menuOffset,
9385 menuScroll,
9386 menuHeight,
9387 abovePage,
9388 belowPage
9389 ;
9390
9391 $item = $item || module.get.selectedItem();
9392 $menu = $item.closest(selector.menu);
9393 hasActive = $item && $item.length > 0;
9394 forceScroll = forceScroll !== undefined
9395 ? forceScroll
9396 : false;
9397 if (module.get.activeItem().length === 0) {
9398 forceScroll = false;
9399 }
9400 if ($item && $menu.length > 0 && hasActive) {
9401 itemOffset = $item.position().top;
9402
9403 $menu.addClass(className.loading);
9404 menuScroll = $menu.scrollTop();
9405 menuOffset = $menu.offset().top;
9406 itemOffset = $item.offset().top;
9407 offset = menuScroll - menuOffset + itemOffset;
9408 if (!forceScroll) {
9409 menuHeight = $menu.height();
9410 belowPage = menuScroll + menuHeight < (offset + edgeTolerance);
9411 abovePage = (offset - edgeTolerance) < menuScroll;
9412 }
9413 module.debug('Scrolling to active item', offset);
9414 if (forceScroll || abovePage || belowPage) {
9415 $menu.scrollTop(offset);
9416 }
9417 $menu.removeClass(className.loading);
9418 }
9419 },
9420 text: function (text, isNotPlaceholder) {
9421 if (settings.action === 'combo') {
9422 module.debug('Changing combo button text', text, $combo);
9423 if (settings.preserveHTML) {
9424 $combo.html(text);
9425 } else {
9426 $combo.text(text);
9427 }
9428 } else if (settings.action === 'activate') {
9429 if (text !== module.get.placeholderText() || isNotPlaceholder) {
9430 $text.removeClass(className.placeholder);
9431 }
9432 module.debug('Changing text', text, $text);
9433 $text
9434 .removeClass(className.filtered)
9435 ;
9436 if (settings.preserveHTML) {
9437 $text.html(text);
9438 } else {
9439 $text.text(text);
9440 }
9441 }
9442 },
9443 selectedItem: function ($item) {
9444 var
9445 value = module.get.choiceValue($item),
9446 searchText = module.get.choiceText($item, false),
9447 text = module.get.choiceText($item)
9448 ;
9449 module.debug('Setting user selection to item', $item);
9450 module.remove.activeItem();
9451 module.set.partialSearch(searchText);
9452 module.set.activeItem($item);
9453 module.set.selected(value, $item);
9454 module.set.text(text);
9455 },
9456 selectedLetter: function (letter) {
9457 var
9458 $selectedItem = $item.filter('.' + className.selected),
9459 alreadySelectedLetter = $selectedItem.length > 0 && module.has.firstLetter($selectedItem, letter),
9460 $nextValue = false,
9461 $nextItem
9462 ;
9463 // check next of same letter
9464 if (alreadySelectedLetter) {
9465 $nextItem = $selectedItem.nextAll($item).eq(0);
9466 if (module.has.firstLetter($nextItem, letter)) {
9467 $nextValue = $nextItem;
9468 }
9469 }
9470 // check all values
9471 if (!$nextValue) {
9472 $item
9473 .each(function () {
9474 if (module.has.firstLetter($(this), letter)) {
9475 $nextValue = $(this);
9476
9477 return false;
9478 }
9479 })
9480 ;
9481 }
9482 // set next value
9483 if ($nextValue) {
9484 module.verbose('Scrolling to next value with letter', letter);
9485 module.set.scrollPosition($nextValue);
9486 $selectedItem.removeClass(className.selected);
9487 $nextValue.addClass(className.selected);
9488 if (settings.selectOnKeydown && module.is.single() && !$nextItem.hasClass(className.actionable)) {
9489 module.set.selectedItem($nextValue);
9490 }
9491 }
9492 },
9493 direction: function ($menu) {
9494 if (settings.direction === 'auto') {
9495 // reset position, remove upward if it's base menu
9496 if (!$menu) {
9497 module.remove.upward();
9498 } else if (module.is.upward($menu)) {
9499 // we need make sure when make assertion openDownward for $menu, $menu does not have upward class
9500 module.remove.upward($menu);
9501 }
9502
9503 if (module.can.openDownward($menu)) {
9504 module.remove.upward($menu);
9505 } else {
9506 module.set.upward($menu);
9507 }
9508 if (!module.is.leftward($menu) && !module.can.openRightward($menu)) {
9509 module.set.leftward($menu);
9510 }
9511 } else if (settings.direction === 'upward') {
9512 module.set.upward($menu);
9513 }
9514 },
9515 upward: function ($currentMenu) {
9516 var $element = $currentMenu || $module;
9517 $element.addClass(className.upward);
9518 },
9519 leftward: function ($currentMenu) {
9520 var $element = $currentMenu || $menu;
9521 $element.addClass(className.leftward);
9522 },
9523 value: function (value, text, $selected, preventChangeTrigger) {
9524 if (typeof text === 'boolean') {
9525 preventChangeTrigger = text;
9526 $selected = undefined;
9527 text = undefined;
9528 }
9529 if (value !== undefined && value !== '' && !(Array.isArray(value) && value.length === 0)) {
9530 $input.removeClass(className.noselection);
9531 } else {
9532 $input.addClass(className.noselection);
9533 }
9534 var
9535 escapedValue = module.escape.value(value),
9536 hasInput = $input.length > 0,
9537 currentValue = module.get.values(),
9538 stringValue = value !== undefined
9539 ? String(value)
9540 : value
9541 ;
9542 if (hasInput) {
9543 if (!settings.allowReselection && stringValue == currentValue) {
9544 module.verbose('Skipping value update already same value', value, currentValue);
9545 if (!module.is.initialLoad()) {
9546 return;
9547 }
9548 }
9549
9550 if (module.is.single() && module.has.selectInput() && module.can.extendSelect()) {
9551 module.debug('Adding user option', value);
9552 module.add.optionValue(value);
9553 }
9554 module.debug('Updating input value', escapedValue, currentValue);
9555 internalChange = true;
9556 $input
9557 .val(escapedValue)
9558 ;
9559 if (settings.fireOnInit === false && module.is.initialLoad()) {
9560 module.debug('Input native change event ignored on initial load');
9561 } else if (preventChangeTrigger !== true) {
9562 module.trigger.change();
9563 }
9564 internalChange = false;
9565 } else {
9566 module.verbose('Storing value in metadata', escapedValue, $input);
9567 if (escapedValue !== currentValue) {
9568 $module.data(metadata.value, stringValue);
9569 }
9570 }
9571 if (settings.fireOnInit === false && module.is.initialLoad()) {
9572 module.verbose('No callback on initial load', settings.onChange);
9573 } else if (preventChangeTrigger !== true) {
9574 settings.onChange.call(element, value, text, $selected);
9575 }
9576 },
9577 active: function () {
9578 $module
9579 .addClass(className.active)
9580 ;
9581 },
9582 multiple: function () {
9583 $module.addClass(className.multiple);
9584 },
9585 visible: function () {
9586 $module.addClass(className.visible);
9587 },
9588 exactly: function (value, $selectedItem, preventChangeTrigger) {
9589 if (typeof $selectedItem === 'boolean') {
9590 preventChangeTrigger = $selectedItem;
9591 $selectedItem = undefined;
9592 }
9593 module.debug('Setting selected to exact values');
9594 module.clear();
9595 module.set.selected(value, $selectedItem, preventChangeTrigger);
9596 },
9597 selected: function (value, $selectedItem, preventChangeTrigger, keepSearchTerm) {
9598 if (typeof $selectedItem === 'boolean') {
9599 keepSearchTerm = preventChangeTrigger;
9600 preventChangeTrigger = $selectedItem;
9601 $selectedItem = undefined;
9602 }
9603 var
9604 isMultiple = module.is.multiple()
9605 ;
9606 $selectedItem = settings.allowAdditions
9607 ? $selectedItem || module.get.itemWithAdditions(value)
9608 : $selectedItem || module.get.item(value);
9609 if (!$selectedItem) {
9610 return false;
9611 }
9612 module.debug('Setting selected menu item to', $selectedItem);
9613 if (module.is.multiple() && !keepSearchTerm) {
9614 module.remove.searchWidth();
9615 }
9616 if (module.is.single()) {
9617 module.remove.activeItem();
9618 module.remove.selectedItem();
9619 } else if (settings.useLabels) {
9620 module.remove.selectedItem();
9621 }
9622 // select each item
9623 $selectedItem
9624 .each(function () {
9625 var
9626 $selected = $(this),
9627 selectedText = module.get.choiceText($selected),
9628 selectedValue = module.get.choiceValue($selected, selectedText),
9629
9630 isFiltered = $selected.hasClass(className.filtered),
9631 isActive = $selected.hasClass(className.active),
9632 isActionable = $selected.hasClass(className.actionable),
9633 isUserValue = $selected.hasClass(className.addition),
9634 shouldAnimate = isMultiple && $selectedItem && $selectedItem.length === 1
9635 ;
9636 if (isActionable) {
9637 if ((!isMultiple || (!isActive || isUserValue)) && settings.apiSettings && settings.saveRemoteData) {
9638 module.save.remoteData(selectedText, selectedValue);
9639 }
9640 settings.onActionable.call(element, selectedValue, selectedText, $selected);
9641 } else if (isMultiple) {
9642 if (!isActive || isUserValue) {
9643 if (settings.apiSettings && settings.saveRemoteData) {
9644 module.save.remoteData(selectedText, selectedValue);
9645 }
9646 if (settings.useLabels) {
9647 module.add.value(selectedValue, selectedText, $selected, preventChangeTrigger);
9648 module.add.label(selectedValue, selectedText, shouldAnimate);
9649 module.set.activeItem($selected);
9650 module.filterActive();
9651 module.select.nextAvailable($selectedItem);
9652 } else {
9653 module.add.value(selectedValue, selectedText, $selected, preventChangeTrigger);
9654 module.set.text(module.add.variables(message.count));
9655 module.set.activeItem($selected);
9656 }
9657 } else if (!isFiltered && (settings.useLabels || selectActionActive)) {
9658 module.debug('Selected active value, removing label');
9659 module.remove.selected(selectedValue);
9660 }
9661 } else {
9662 if (settings.apiSettings && settings.saveRemoteData) {
9663 module.save.remoteData(selectedText, selectedValue);
9664 }
9665 if (!keepSearchTerm && !$selected.hasClass(className.actionable)) {
9666 module.set.text(selectedText, true);
9667 }
9668 module.set.value(selectedValue, selectedText, $selected, preventChangeTrigger);
9669 $selected
9670 .addClass(className.active)
9671 .addClass(className.selected)
9672 ;
9673 }
9674 })
9675 ;
9676 if (!keepSearchTerm) {
9677 module.remove.searchTerm();
9678 }
9679 if (module.is.allFiltered()) {
9680 module.set.empty();
9681 module.hideMenu();
9682 }
9683 },
9684 },
9685
9686 add: {
9687 label: function (value, text, shouldAnimate) {
9688 var
9689 $next = module.is.searchSelection()
9690 ? $search
9691 : $text,
9692 escapedValue = module.escape.value(value),
9693 $label
9694 ;
9695 if (settings.ignoreCase) {
9696 escapedValue = escapedValue.toLowerCase();
9697 }
9698 $label = $('<a />')
9699 .addClass(className.label)
9700 .attr('data-' + metadata.value, escapedValue)
9701 .html(templates.label(escapedValue, text, settings.preserveHTML, settings.className))
9702 ;
9703 $label = settings.onLabelCreate.call($label, escapedValue, text);
9704
9705 if (module.has.label(value)) {
9706 module.debug('User selection already exists, skipping', escapedValue);
9707
9708 return;
9709 }
9710 if (settings.label.variation) {
9711 $label.addClass(settings.label.variation);
9712 }
9713 if (shouldAnimate === true && settings.label.transition) {
9714 module.debug('Animating in label', $label);
9715 $label
9716 .addClass(className.hidden)
9717 .insertBefore($next)
9718 .transition({
9719 animation: settings.label.transition,
9720 debug: settings.debug,
9721 verbose: settings.verbose,
9722 silent: settings.silent,
9723 duration: settings.label.duration,
9724 })
9725 ;
9726 } else {
9727 module.debug('Adding selection label', $label);
9728 $label
9729 .insertBefore($next)
9730 ;
9731 }
9732 },
9733 message: function (message) {
9734 var
9735 $message = $menu.children(selector.message),
9736 html = settings.templates.message(module.add.variables(message))
9737 ;
9738 if ($message.length > 0) {
9739 $message
9740 .html(html)
9741 ;
9742 } else {
9743 $('<div/>')
9744 .html(html)
9745 .addClass(className.message)
9746 .appendTo($menu)
9747 ;
9748 }
9749 },
9750 optionValue: function (value) {
9751 var
9752 escapedValue = module.escape.value(value),
9753 $option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
9754 hasOption = $option.length > 0
9755 ;
9756 if (hasOption) {
9757 return;
9758 }
9759 // temporarily disconnect observer
9760 module.disconnect.selectObserver();
9761 if (module.is.single()) {
9762 module.verbose('Removing previous user addition');
9763 $input.find('option.' + className.addition).remove();
9764 }
9765 $('<option/>')
9766 .prop('value', escapedValue)
9767 .addClass(className.addition)
9768 .text(value)
9769 .appendTo($input)
9770 ;
9771 module.verbose('Adding user addition as an <option>', value);
9772 module.observe.select();
9773 },
9774 userSuggestion: function (value) {
9775 var
9776 $addition = $menu.children(selector.addition),
9777 $existingItem = module.get.item(value),
9778 alreadyHasValue = $existingItem && $existingItem.not(selector.addition).length > 0,
9779 hasUserSuggestion = $addition.length > 0,
9780 html
9781 ;
9782 if (settings.useLabels && module.has.maxSelections()) {
9783 return;
9784 }
9785 if (value === '' || alreadyHasValue) {
9786 $addition.remove();
9787
9788 return;
9789 }
9790 if (hasUserSuggestion) {
9791 $addition
9792 .data(metadata.value, value)
9793 .data(metadata.text, value)
9794 .attr('data-' + metadata.value, value)
9795 .attr('data-' + metadata.text, value)
9796 .removeClass(className.filtered)
9797 ;
9798 if (!settings.hideAdditions) {
9799 html = settings.templates.addition(module.add.variables(message.addResult, value));
9800 $addition
9801 .html(html)
9802 ;
9803 }
9804 module.verbose('Replacing user suggestion with new value', $addition);
9805 } else {
9806 $addition = module.create.userChoice(value);
9807 $addition
9808 .prependTo($menu)
9809 ;
9810 module.verbose('Adding item choice to menu corresponding with user choice addition', $addition);
9811 }
9812 if (!settings.hideAdditions || module.is.allFiltered()) {
9813 $addition
9814 .addClass(className.selected)
9815 .siblings()
9816 .removeClass(className.selected)
9817 ;
9818 }
9819 module.refreshItems();
9820 },
9821 variables: function (message, term) {
9822 var
9823 hasCount = message.search('{count}') !== -1,
9824 hasMaxCount = message.search('{maxCount}') !== -1,
9825 hasTerm = message.search('{term}') !== -1,
9826 query
9827 ;
9828 module.verbose('Adding templated variables to message', message);
9829 if (hasCount) {
9830 message = message.replace('{count}', module.get.selectionCount());
9831 }
9832 if (hasMaxCount) {
9833 message = message.replace('{maxCount}', settings.maxSelections);
9834 }
9835 if (hasTerm) {
9836 query = term || module.get.query();
9837 message = message.replace('{term}', query);
9838 }
9839
9840 return message;
9841 },
9842 value: function (addedValue, addedText, $selectedItem, preventChangeTrigger) {
9843 if (typeof addedText === 'boolean') {
9844 preventChangeTrigger = addedText;
9845 $selectedItem = undefined;
9846 addedText = undefined;
9847 }
9848 var
9849 currentValue = module.get.values(true),
9850 newValue
9851 ;
9852 if (module.has.value(addedValue)) {
9853 module.debug('Value already selected');
9854
9855 return;
9856 }
9857 if (addedValue === '') {
9858 module.debug('Cannot select blank values from multiselect');
9859
9860 return;
9861 }
9862 // extend current array
9863 if (Array.isArray(currentValue)) {
9864 newValue = $selectedItem && $selectedItem.hasClass(className.actionable) ? currentValue : currentValue.concat([addedValue]);
9865 newValue = module.get.uniqueArray(newValue);
9866 } else {
9867 newValue = [addedValue];
9868 }
9869 // add values
9870 if (module.has.selectInput()) {
9871 if (module.can.extendSelect()) {
9872 module.debug('Adding value to select', addedValue, newValue, $input);
9873 module.add.optionValue(addedValue);
9874 }
9875 } else {
9876 newValue = newValue.join(settings.delimiter);
9877 module.debug('Setting hidden input to delimited value', newValue, $input);
9878 }
9879
9880 if (settings.fireOnInit === false && module.is.initialLoad()) {
9881 module.verbose('Skipping onadd callback on initial load', settings.onAdd);
9882 } else {
9883 settings.onAdd.call(element, addedValue, addedText, $selectedItem);
9884 }
9885 module.set.value(newValue, addedText, $selectedItem, preventChangeTrigger);
9886 module.check.maxSelections();
9887 },
9888 },
9889
9890 remove: {
9891 active: function () {
9892 $module.removeClass(className.active);
9893 },
9894 activeLabel: function () {
9895 $module.find(selector.label).removeClass(className.active);
9896 },
9897 empty: function () {
9898 $module.removeClass(className.empty);
9899 },
9900 loading: function () {
9901 $module.removeClass(className.loading);
9902 },
9903 initialLoad: function () {
9904 initialLoad = false;
9905 },
9906 upward: function ($currentMenu) {
9907 var $element = $currentMenu || $module;
9908 $element.removeClass(className.upward);
9909 },
9910 leftward: function ($currentMenu) {
9911 var $element = $currentMenu || $menu;
9912 $element.removeClass(className.leftward);
9913 },
9914 visible: function () {
9915 $module.removeClass(className.visible);
9916 },
9917 activeItem: function () {
9918 $item.removeClass(className.active);
9919 },
9920 filteredItem: function () {
9921 if (settings.useLabels && module.has.maxSelections()) {
9922 return;
9923 }
9924 if (settings.useLabels && module.is.multiple()) {
9925 $item.not('.' + className.active).removeClass(className.filtered);
9926 } else {
9927 $item.removeClass(className.filtered);
9928 }
9929 if (settings.hideDividers) {
9930 $divider.removeClass(className.hidden);
9931 }
9932 module.remove.empty();
9933 },
9934 optionValue: function (value) {
9935 var
9936 escapedValue = module.escape.value(value),
9937 $option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
9938 hasOption = $option.length > 0
9939 ;
9940 if (!hasOption || !$option.hasClass(className.addition)) {
9941 return;
9942 }
9943 // temporarily disconnect observer
9944 module.disconnect.selectObserver();
9945 $option.remove();
9946 module.verbose('Removing user addition as an <option>', escapedValue);
9947 module.observe.select();
9948 },
9949 message: function () {
9950 $menu.children(selector.message).remove();
9951 },
9952 searchWidth: function () {
9953 $search.css('width', '');
9954 },
9955 searchTerm: function () {
9956 module.verbose('Cleared search term');
9957 $search.val('');
9958 module.set.filtered();
9959 },
9960 userAddition: function () {
9961 $item.filter(selector.addition).remove();
9962 },
9963 selected: function (value, $selectedItem, preventChangeTrigger) {
9964 $selectedItem = settings.allowAdditions
9965 ? $selectedItem || module.get.itemWithAdditions(value)
9966 : $selectedItem || module.get.item(value);
9967
9968 if (!$selectedItem) {
9969 return false;
9970 }
9971
9972 $selectedItem
9973 .each(function () {
9974 var
9975 $selected = $(this),
9976 selectedText = module.get.choiceText($selected),
9977 selectedValue = module.get.choiceValue($selected, selectedText)
9978 ;
9979 if (module.is.multiple()) {
9980 if (settings.useLabels) {
9981 module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
9982 module.remove.label(selectedValue);
9983 } else {
9984 module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
9985 if (module.get.selectionCount() === 0) {
9986 module.set.placeholderText();
9987 } else {
9988 module.set.text(module.add.variables(message.count));
9989 }
9990 }
9991 } else {
9992 module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
9993 }
9994 $selected
9995 .removeClass(className.filtered)
9996 .removeClass(className.active)
9997 ;
9998 if (settings.useLabels) {
9999 $selected.removeClass(className.selected);
10000 }
10001 })
10002 ;
10003 },
10004 selectedItem: function () {
10005 $item.removeClass(className.selected);
10006 },
10007 value: function (removedValue, removedText, $removedItem, preventChangeTrigger) {
10008 var
10009 values = module.get.values(true),
10010 newValue
10011 ;
10012 if (module.has.selectInput()) {
10013 module.verbose('Input is <select> removing selected option', removedValue);
10014 newValue = module.remove.arrayValue(removedValue, values);
10015 module.remove.optionValue(removedValue);
10016 } else {
10017 module.verbose('Removing from delimited values', removedValue);
10018 newValue = module.remove.arrayValue(removedValue, values);
10019 newValue = newValue.join(settings.delimiter);
10020 }
10021 if (settings.fireOnInit === false && module.is.initialLoad()) {
10022 module.verbose('No callback on initial load', settings.onRemove);
10023 } else {
10024 settings.onRemove.call(element, removedValue, removedText, $removedItem);
10025 }
10026 module.set.value(newValue, removedText, $removedItem, preventChangeTrigger);
10027 module.check.maxSelections();
10028 },
10029 arrayValue: function (removedValue, values) {
10030 if (!Array.isArray(values)) {
10031 values = [values];
10032 }
10033 values = $.grep(values, function (value) {
10034 return removedValue != value;
10035 });
10036 module.verbose('Removed value from delimited string', removedValue, values);
10037
10038 return values;
10039 },
10040 label: function (value, shouldAnimate) {
10041 var
10042 escapedValue = module.escape.value(value),
10043 $labels = $module.find(selector.label),
10044 $removedLabel = $labels.filter('[data-' + metadata.value + '="' + module.escape.string(settings.ignoreCase ? escapedValue.toLowerCase() : escapedValue) + '"]')
10045 ;
10046 module.verbose('Removing label', $removedLabel);
10047 $removedLabel.remove();
10048 },
10049 activeLabels: function ($activeLabels) {
10050 $activeLabels = $activeLabels || $module.find(selector.label).filter('.' + className.active);
10051 module.verbose('Removing active label selections', $activeLabels);
10052 module.remove.labels($activeLabels);
10053 },
10054 labels: function ($labels, preventChangeTrigger) {
10055 $labels = $labels || $module.find(selector.label);
10056 module.verbose('Removing labels', $labels);
10057 $labels
10058 .each(function () {
10059 var
10060 $label = $(this),
10061 value = $label.data(metadata.value),
10062 stringValue = value !== undefined
10063 ? String(value)
10064 : value,
10065 isUserValue = module.is.userValue(stringValue)
10066 ;
10067 if (settings.onLabelRemove.call($label, value) === false) {
10068 module.debug('Label remove callback cancelled removal');
10069
10070 return;
10071 }
10072 module.remove.message();
10073 if (isUserValue) {
10074 module.remove.value(stringValue, stringValue, module.get.item(stringValue), preventChangeTrigger);
10075 module.remove.label(stringValue);
10076 } else {
10077 // selected will also remove label
10078 module.remove.selected(stringValue, false, preventChangeTrigger);
10079 }
10080 })
10081 ;
10082 },
10083 tabbable: function () {
10084 if (module.is.searchSelection()) {
10085 module.debug('Searchable dropdown initialized');
10086 $search
10087 .removeAttr('tabindex')
10088 ;
10089 $menu
10090 .removeAttr('tabindex')
10091 ;
10092 } else {
10093 module.debug('Simple selection dropdown initialized');
10094 $module
10095 .removeAttr('tabindex')
10096 ;
10097 $menu
10098 .removeAttr('tabindex')
10099 ;
10100 }
10101 },
10102 diacritics: function (text) {
10103 return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036F]/g, '') : text;
10104 },
10105 },
10106
10107 has: {
10108 menuSearch: function () {
10109 return module.has.search() && $search.closest($menu).length > 0;
10110 },
10111 clearItem: function () {
10112 return $clear.length > 0;
10113 },
10114 search: function () {
10115 return $search.length > 0;
10116 },
10117 sizer: function () {
10118 return $sizer.length > 0;
10119 },
10120 selectInput: function () {
10121 return $input.is('select');
10122 },
10123 minCharacters: function (searchTerm) {
10124 if (settings.minCharacters && !iconClicked) {
10125 searchTerm = searchTerm !== undefined
10126 ? String(searchTerm)
10127 : String(module.get.query());
10128
10129 return searchTerm.length >= settings.minCharacters;
10130 }
10131 iconClicked = false;
10132
10133 return true;
10134 },
10135 firstLetter: function ($item, letter) {
10136 var
10137 text,
10138 firstLetter
10139 ;
10140 if (!$item || $item.length === 0 || typeof letter !== 'string') {
10141 return false;
10142 }
10143 text = module.get.choiceText($item, false);
10144 letter = letter.toLowerCase();
10145 firstLetter = String(text).charAt(0).toLowerCase();
10146
10147 return letter == firstLetter;
10148 },
10149 input: function () {
10150 return $input.length > 0;
10151 },
10152 items: function () {
10153 return $item.length > 0;
10154 },
10155 menu: function () {
10156 return $menu.length > 0;
10157 },
10158 subMenu: function ($currentMenu) {
10159 return ($currentMenu || $menu).find(selector.menu).length > 0;
10160 },
10161 message: function () {
10162 return $menu.children(selector.message).length > 0;
10163 },
10164 label: function (value) {
10165 var
10166 escapedValue = module.escape.value(value),
10167 $labels = $module.find(selector.label)
10168 ;
10169 if (settings.ignoreCase) {
10170 escapedValue = escapedValue.toLowerCase();
10171 }
10172
10173 return $labels.filter('[data-' + metadata.value + '="' + module.escape.string(escapedValue) + '"]').length > 0;
10174 },
10175 maxSelections: function () {
10176 return settings.maxSelections && module.get.selectionCount() >= settings.maxSelections;
10177 },
10178 allResultsFiltered: function () {
10179 var
10180 $normalResults = $item.not(selector.addition)
10181 ;
10182
10183 return $normalResults.filter(selector.unselectable).length === $normalResults.length;
10184 },
10185 userSuggestion: function () {
10186 return $menu.children(selector.addition).length > 0;
10187 },
10188 query: function () {
10189 return module.get.query() !== '';
10190 },
10191 value: function (value) {
10192 return settings.ignoreCase
10193 ? module.has.valueIgnoringCase(value)
10194 : module.has.valueMatchingCase(value);
10195 },
10196 valueMatchingCase: function (value) {
10197 var
10198 values = module.get.values(true),
10199 hasValue = Array.isArray(values)
10200 ? values && ($.inArray(value, values) !== -1)
10201 : values == value
10202 ;
10203
10204 return !!hasValue;
10205 },
10206 valueIgnoringCase: function (value) {
10207 var
10208 values = module.get.values(true),
10209 hasValue = false
10210 ;
10211 if (!Array.isArray(values)) {
10212 values = [values];
10213 }
10214 $.each(values, function (index, existingValue) {
10215 if (String(value).toLowerCase() === String(existingValue).toLowerCase()) {
10216 hasValue = true;
10217
10218 return false;
10219 }
10220 });
10221
10222 return hasValue;
10223 },
10224 },
10225
10226 is: {
10227 active: function () {
10228 return $module.hasClass(className.active);
10229 },
10230 animatingInward: function () {
10231 return $menu.transition('is inward');
10232 },
10233 animatingOutward: function () {
10234 return $menu.transition('is outward');
10235 },
10236 bubbledLabelClick: function (event) {
10237 return $(event.target).is('select, input') && $module.closest('label').length > 0;
10238 },
10239 bubbledIconClick: function (event) {
10240 return $(event.target).closest($icon).length > 0;
10241 },
10242 edge: function () {
10243 return !!window.chrome && !!window.StyleMedia;
10244 },
10245 empty: function () {
10246 return $module.hasClass(className.empty);
10247 },
10248 chrome: function () {
10249 return !!window.chrome && !window.StyleMedia;
10250 },
10251 alreadySetup: function () {
10252 return $module.is('select') && $module.parent(selector.dropdown).data(moduleNamespace) !== undefined && $module.prev().length === 0;
10253 },
10254 animating: function ($subMenu) {
10255 return $subMenu
10256 ? $subMenu.transition && $subMenu.transition('is animating')
10257 : $menu.transition && $menu.transition('is animating');
10258 },
10259 leftward: function ($subMenu) {
10260 var $selectedMenu = $subMenu || $menu;
10261
10262 return $selectedMenu.hasClass(className.leftward);
10263 },
10264 clearable: function () {
10265 return $module.hasClass(className.clearable) || settings.clearable;
10266 },
10267 disabled: function () {
10268 return $module.hasClass(className.disabled);
10269 },
10270 focused: function () {
10271 return document.activeElement === $module[0];
10272 },
10273 focusedOnSearch: function () {
10274 return document.activeElement === $search[0];
10275 },
10276 allFiltered: function () {
10277 return (module.is.multiple() || module.has.search()) && !(!settings.hideAdditions && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered();
10278 },
10279 hidden: function ($subMenu) {
10280 return !module.is.visible($subMenu);
10281 },
10282 initialLoad: function () {
10283 return initialLoad;
10284 },
10285 inObject: function (needle, object) {
10286 var
10287 found = false
10288 ;
10289 $.each(object, function (index, property) {
10290 if (property == needle) {
10291 found = true;
10292
10293 return true;
10294 }
10295 });
10296
10297 return found;
10298 },
10299 multiple: function () {
10300 return $module.hasClass(className.multiple);
10301 },
10302 remote: function () {
10303 return settings.apiSettings && module.can.useAPI();
10304 },
10305 noApiCache: function () {
10306 return tempDisableApiCache || (settings.apiSettings && !settings.apiSettings.cache);
10307 },
10308 single: function () {
10309 return !module.is.multiple();
10310 },
10311 selectMutation: function (mutations) {
10312 var
10313 selectChanged = false
10314 ;
10315 $.each(mutations, function (index, mutation) {
10316 if ($(mutation.target).is('option, optgroup') || $(mutation.addedNodes).is('select') || ($(mutation.target).is('select') && mutation.type !== 'attributes')) {
10317 selectChanged = true;
10318
10319 return false;
10320 }
10321 });
10322
10323 return selectChanged;
10324 },
10325 search: function () {
10326 return $module.hasClass(className.search);
10327 },
10328 searchSelection: function (deep) {
10329 return module.has.search() && (deep ? $search.parents(selector.dropdown) : $search.parent(selector.dropdown)).length === 1;
10330 },
10331 selection: function () {
10332 return $module.hasClass(className.selection);
10333 },
10334 userValue: function (value) {
10335 return $.inArray(value, module.get.userValues()) !== -1;
10336 },
10337 upward: function ($menu) {
10338 var $element = $menu || $module;
10339
10340 return $element.hasClass(className.upward);
10341 },
10342 visible: function ($subMenu) {
10343 return $subMenu
10344 ? $subMenu.hasClass(className.visible)
10345 : $menu.hasClass(className.visible);
10346 },
10347 verticallyScrollableContext: function () {
10348 var
10349 overflowY = $context[0] !== window
10350 ? $context.css('overflow-y')
10351 : false
10352 ;
10353
10354 return overflowY === 'auto' || overflowY === 'scroll';
10355 },
10356 horizontallyScrollableContext: function () {
10357 var
10358 overflowX = $context[0] !== window
10359 ? $context.css('overflow-X')
10360 : false
10361 ;
10362
10363 return overflowX === 'auto' || overflowX === 'scroll';
10364 },
10365 },
10366
10367 can: {
10368 activate: function ($item) {
10369 return (
10370 settings.useLabels
10371 || !module.has.maxSelections()
10372 || (module.has.maxSelections() && $item.hasClass(className.active))
10373 );
10374 },
10375 openDownward: function ($subMenu) {
10376 var
10377 $currentMenu = $subMenu || $menu,
10378 canOpenDownward,
10379 onScreen,
10380 calculations
10381 ;
10382 $currentMenu
10383 .addClass(className.loading)
10384 ;
10385 calculations = {
10386 context: {
10387 offset: $context[0] === window
10388 ? { top: 0, left: 0 }
10389 : $context.offset(),
10390 scrollTop: $context.scrollTop(),
10391 height: $context.outerHeight(),
10392 },
10393 menu: {
10394 offset: $currentMenu.offset(),
10395 height: $currentMenu.outerHeight(),
10396 },
10397 };
10398 if (module.is.verticallyScrollableContext()) {
10399 calculations.menu.offset.top += calculations.context.scrollTop;
10400 }
10401 if (module.has.subMenu($currentMenu)) {
10402 calculations.menu.height += $currentMenu.find(selector.menu).first().outerHeight();
10403 }
10404 onScreen = {
10405 above: calculations.context.scrollTop <= calculations.menu.offset.top - calculations.context.offset.top - calculations.menu.height,
10406 below: (calculations.context.scrollTop + calculations.context.height) >= calculations.menu.offset.top - calculations.context.offset.top + calculations.menu.height,
10407 };
10408 if (onScreen.below) {
10409 module.verbose('Dropdown can fit in context downward', onScreen);
10410 canOpenDownward = true;
10411 } else if (!onScreen.below && !onScreen.above) {
10412 module.verbose('Dropdown cannot fit in either direction, favoring downward', onScreen);
10413 canOpenDownward = true;
10414 } else {
10415 module.verbose('Dropdown cannot fit below, opening upward', onScreen);
10416 canOpenDownward = false;
10417 }
10418 $currentMenu.removeClass(className.loading);
10419
10420 return canOpenDownward;
10421 },
10422 openRightward: function ($subMenu) {
10423 var
10424 $currentMenu = $subMenu || $menu,
10425 canOpenRightward = true,
10426 isOffscreenRight = false,
10427 calculations
10428 ;
10429 $currentMenu
10430 .addClass(className.loading)
10431 ;
10432 calculations = {
10433 context: {
10434 offset: $context[0] === window
10435 ? { top: 0, left: 0 }
10436 : $context.offset(),
10437 scrollLeft: $context.scrollLeft(),
10438 width: $context.outerWidth(),
10439 },
10440 menu: {
10441 offset: $currentMenu.offset(),
10442 width: $currentMenu.outerWidth(),
10443 },
10444 };
10445 if (module.is.horizontallyScrollableContext()) {
10446 calculations.menu.offset.left += calculations.context.scrollLeft;
10447 }
10448 isOffscreenRight = calculations.menu.offset.left - calculations.context.offset.left + calculations.menu.width >= calculations.context.scrollLeft + calculations.context.width;
10449 if (isOffscreenRight) {
10450 module.verbose('Dropdown cannot fit in context rightward', isOffscreenRight);
10451 canOpenRightward = false;
10452 }
10453 $currentMenu.removeClass(className.loading);
10454
10455 return canOpenRightward;
10456 },
10457 extendSelect: function () {
10458 return settings.allowAdditions || settings.apiSettings;
10459 },
10460 show: function () {
10461 return !module.is.disabled() && (module.has.items() || module.has.message());
10462 },
10463 useAPI: function () {
10464 return $.fn.api !== undefined;
10465 },
10466 useElement: function (element) {
10467 if ($.fn[element] !== undefined) {
10468 return true;
10469 }
10470 module.error(error.noElement.replace('{element}', element));
10471
10472 return false;
10473 },
10474 },
10475
10476 animate: {
10477 show: function (callback, $subMenu) {
10478 var
10479 $currentMenu = $subMenu || $menu,
10480 start = $subMenu
10481 ? function () {}
10482 : function () {
10483 module.hideSubMenus();
10484 module.hideOthers();
10485 module.set.active();
10486 },
10487 transition
10488 ;
10489 callback = isFunction(callback)
10490 ? callback
10491 : function () {};
10492 module.verbose('Doing menu show animation', $currentMenu);
10493 module.set.direction($subMenu);
10494 transition = settings.transition.showMethod || module.get.transition($subMenu);
10495 if (module.is.selection()) {
10496 module.set.scrollPosition(module.get.selectedItem(), true);
10497 }
10498 if (module.is.hidden($currentMenu) || module.is.animating($currentMenu)) {
10499 if (transition === 'none') {
10500 start();
10501 $currentMenu.transition({
10502 displayType: module.get.displayType(),
10503 }).transition('show');
10504 callback.call(element);
10505 } else if (module.can.useElement('transition')) {
10506 $currentMenu
10507 .transition({
10508 animation: transition + ' in',
10509 debug: settings.debug,
10510 verbose: settings.verbose,
10511 silent: settings.silent,
10512 duration: settings.transition.showDuration || settings.duration,
10513 queue: true,
10514 onStart: start,
10515 displayType: module.get.displayType(),
10516 onComplete: function () {
10517 callback.call(element);
10518 },
10519 })
10520 ;
10521 }
10522 }
10523 },
10524 hide: function (callback, $subMenu) {
10525 var
10526 $currentMenu = $subMenu || $menu,
10527 start = $subMenu
10528 ? function () {}
10529 : function () {
10530 module.unbind.intent();
10531 module.remove.active();
10532 },
10533 transition = settings.transition.hideMethod || module.get.transition($subMenu)
10534 ;
10535 callback = isFunction(callback)
10536 ? callback
10537 : function () {};
10538 if (module.is.visible($currentMenu) || module.is.animating($currentMenu)) {
10539 module.verbose('Doing menu hide animation', $currentMenu);
10540
10541 if (transition === 'none') {
10542 start();
10543 $currentMenu.transition({
10544 displayType: module.get.displayType(),
10545 }).transition('hide');
10546 callback.call(element);
10547 } else if ($.fn.transition !== undefined) {
10548 $currentMenu
10549 .transition({
10550 animation: transition + ' out',
10551 duration: settings.transition.hideDuration || settings.duration,
10552 debug: settings.debug,
10553 verbose: settings.verbose,
10554 silent: settings.silent,
10555 queue: false,
10556 onStart: start,
10557 displayType: module.get.displayType(),
10558 onComplete: function () {
10559 callback.call(element);
10560 },
10561 })
10562 ;
10563 } else {
10564 module.error(error.transition);
10565 }
10566 }
10567 },
10568 },
10569
10570 hideAndClear: function () {
10571 module.remove.searchTerm();
10572 if (module.has.maxSelections()) {
10573 return;
10574 }
10575 if (module.has.search()) {
10576 module.hide(function () {
10577 module.remove.filteredItem();
10578 });
10579 } else {
10580 module.hide();
10581 }
10582 },
10583
10584 delay: {
10585 show: function () {
10586 module.verbose('Delaying show event to ensure user intent');
10587 clearTimeout(module.timer);
10588 module.timer = setTimeout(function () { module.show(); }, settings.delay.show);
10589 },
10590 hide: function () {
10591 module.verbose('Delaying hide event to ensure user intent');
10592 clearTimeout(module.timer);
10593 module.timer = setTimeout(function () { module.hide(); }, settings.delay.hide);
10594 },
10595 },
10596
10597 escape: {
10598 value: function (value) {
10599 var
10600 multipleValues = Array.isArray(value),
10601 stringValue = typeof value === 'string',
10602 isUnparsable = !stringValue && !multipleValues,
10603 hasQuotes = stringValue && value.search(regExp.quote) !== -1,
10604 values = []
10605 ;
10606 if (isUnparsable || !hasQuotes) {
10607 return value;
10608 }
10609 module.debug('Encoding quote values for use in select', value);
10610 if (multipleValues) {
10611 $.each(value, function (index, value) {
10612 values.push(value.replace(regExp.quote, '&quot;'));
10613 });
10614
10615 return values;
10616 }
10617
10618 return value.replace(regExp.quote, '&quot;');
10619 },
10620 string: function (text) {
10621 text = String(text);
10622
10623 return text.replace(regExp.escape, '\\$&');
10624 },
10625 htmlEntities: function (string, forceAmpersand) {
10626 var
10627 badChars = /["'<>`]/g,
10628 shouldEscape = /["&'<>`]/,
10629 escape = {
10630 '<': '&lt;',
10631 '>': '&gt;',
10632 '"': '&quot;',
10633 "'": '&#x27;',
10634 '`': '&#x60;',
10635 },
10636 escapedChar = function (chr) {
10637 return escape[chr];
10638 }
10639 ;
10640 if (shouldEscape.test(string)) {
10641 string = string.replace(forceAmpersand ? /&/g : /&(?![\d#a-z]{1,12};)/gi, '&amp;');
10642
10643 return string.replace(badChars, escapedChar);
10644 }
10645
10646 return string;
10647 },
10648 },
10649
10650 setting: function (name, value) {
10651 module.debug('Changing setting', name, value);
10652 if ($.isPlainObject(name)) {
10653 $.extend(true, settings, name);
10654 } else if (value !== undefined) {
10655 if ($.isPlainObject(settings[name])) {
10656 $.extend(true, settings[name], value);
10657 } else {
10658 settings[name] = value;
10659 }
10660 } else {
10661 return settings[name];
10662 }
10663 },
10664 internal: function (name, value) {
10665 if ($.isPlainObject(name)) {
10666 $.extend(true, module, name);
10667 } else if (value !== undefined) {
10668 module[name] = value;
10669 } else {
10670 return module[name];
10671 }
10672 },
10673 debug: function () {
10674 if (!settings.silent && settings.debug) {
10675 if (settings.performance) {
10676 module.performance.log(arguments);
10677 } else {
10678 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
10679 module.debug.apply(console, arguments);
10680 }
10681 }
10682 },
10683 verbose: function () {
10684 if (!settings.silent && settings.verbose && settings.debug) {
10685 if (settings.performance) {
10686 module.performance.log(arguments);
10687 } else {
10688 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
10689 module.verbose.apply(console, arguments);
10690 }
10691 }
10692 },
10693 error: function () {
10694 if (!settings.silent) {
10695 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
10696 module.error.apply(console, arguments);
10697 }
10698 },
10699 performance: {
10700 log: function (message) {
10701 var
10702 currentTime,
10703 executionTime,
10704 previousTime
10705 ;
10706 if (settings.performance) {
10707 currentTime = Date.now();
10708 previousTime = time || currentTime;
10709 executionTime = currentTime - previousTime;
10710 time = currentTime;
10711 performance.push({
10712 Name: message[0],
10713 Arguments: [].slice.call(message, 1) || '',
10714 Element: element,
10715 'Execution Time': executionTime,
10716 });
10717 }
10718 clearTimeout(module.performance.timer);
10719 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
10720 },
10721 display: function () {
10722 var
10723 title = settings.name + ':',
10724 totalTime = 0
10725 ;
10726 time = false;
10727 clearTimeout(module.performance.timer);
10728 $.each(performance, function (index, data) {
10729 totalTime += data['Execution Time'];
10730 });
10731 title += ' ' + totalTime + 'ms';
10732 if (performance.length > 0) {
10733 console.groupCollapsed(title);
10734 if (console.table) {
10735 console.table(performance);
10736 } else {
10737 $.each(performance, function (index, data) {
10738 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
10739 });
10740 }
10741 console.groupEnd();
10742 }
10743 performance = [];
10744 },
10745 },
10746 invoke: function (query, passedArguments, context) {
10747 var
10748 object = instance,
10749 maxDepth,
10750 found,
10751 response
10752 ;
10753 passedArguments = passedArguments || queryArguments;
10754 context = context || element;
10755 if (typeof query === 'string' && object !== undefined) {
10756 query = query.split(/[ .]/);
10757 maxDepth = query.length - 1;
10758 $.each(query, function (depth, value) {
10759 var camelCaseValue = depth !== maxDepth
10760 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
10761 : query
10762 ;
10763 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
10764 object = object[camelCaseValue];
10765 } else if (object[camelCaseValue] !== undefined) {
10766 found = object[camelCaseValue];
10767
10768 return false;
10769 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
10770 object = object[value];
10771 } else if (object[value] !== undefined) {
10772 found = object[value];
10773
10774 return false;
10775 } else {
10776 module.error(error.method, query);
10777
10778 return false;
10779 }
10780 });
10781 }
10782 if (isFunction(found)) {
10783 response = found.apply(context, passedArguments);
10784 } else if (found !== undefined) {
10785 response = found;
10786 }
10787 if (Array.isArray(returnedValue)) {
10788 returnedValue.push(response);
10789 } else if (returnedValue !== undefined) {
10790 returnedValue = [returnedValue, response];
10791 } else if (response !== undefined) {
10792 returnedValue = response;
10793 }
10794
10795 return found;
10796 },
10797 };
10798
10799 if (methodInvoked) {
10800 if (instance === undefined) {
10801 module.initialize();
10802 }
10803 module.invoke(query);
10804 } else {
10805 if (instance !== undefined) {
10806 instance.invoke('destroy');
10807 }
10808 module.initialize();
10809 }
10810 });
10811
10812 return returnedValue !== undefined
10813 ? returnedValue
10814 : $allModules;
10815 };
10816
10817 $.fn.dropdown.settings = {
10818
10819 silent: false,
10820 debug: false,
10821 verbose: false,
10822 performance: true,
10823
10824 on: 'click', // what event should show menu action on item selection
10825 action: 'activate', // action on item selection (nothing, activate, select, combo, hide, function(){})
10826
10827 values: false, // specify values to use for dropdown
10828
10829 clearable: false, // whether the value of the dropdown can be cleared
10830
10831 apiSettings: false,
10832 selectOnKeydown: true, // Whether selection should occur automatically when keyboard shortcuts used
10833 minCharacters: 0, // Minimum characters required to trigger API call
10834
10835 filterRemoteData: false, // Whether API results should be filtered after being returned for query term
10836 saveRemoteData: true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
10837
10838 throttle: 200, // How long to wait after last user input to search remotely
10839
10840 context: window, // Context to use when determining if on screen
10841 direction: 'auto', // Whether dropdown should always open in one direction
10842 keepOnScreen: true, // Whether dropdown should check whether it is on screen before showing
10843
10844 match: 'both', // what to match against with search selection (both, text, or label)
10845 fullTextSearch: 'exact', // search anywhere in value (set to 'exact' to require exact matches)
10846 ignoreDiacritics: false, // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
10847 hideDividers: false, // Whether to hide any divider elements (specified in selector.divider) that are sibling to any items when searched (set to true will hide all dividers, set to 'empty' will hide them when they are not followed by a visible item)
10848
10849 placeholder: 'auto', // whether to convert blank <select> values to placeholder text
10850 preserveHTML: true, // preserve html when selecting value
10851 sortSelect: false, // sort selection on init
10852
10853 forceSelection: false, // force a choice on blur with search selection
10854
10855 allowAdditions: false, // whether multiple select should allow user added values
10856 keepSearchTerm: false, // whether the search value should be kept and menu stays filtered on item selection
10857 ignoreCase: false, // whether to consider case sensitivity when creating labels
10858 ignoreSearchCase: true, // whether to consider case sensitivity when filtering items
10859 hideAdditions: true, // whether or not to hide special message prompting a user they can enter a value
10860
10861 maxSelections: false, // When set to a number limits the number of selections to this count
10862 useLabels: true, // whether multiple select should filter currently active selections from choices
10863 delimiter: ',', // when multiselect uses normal <input> the values will be delimited with this character
10864
10865 showOnFocus: false, // show menu on focus
10866 allowReselection: false, // whether current value should trigger callbacks when reselected
10867 allowTab: true, // add tabindex to element
10868 allowCategorySelection: false, // allow elements with sub-menus to be selected
10869
10870 fireOnInit: false, // Whether callbacks should fire when initializing dropdown values
10871
10872 transition: 'auto', // auto transition will slide down or up based on direction
10873 duration: 200, // duration of transition
10874 displayType: false, // displayType of transition
10875
10876 headerDivider: true, // whether option headers should have an additional divider line underneath when converted from <select> <optgroup>
10877
10878 collapseOnActionable: true, // whether the dropdown should collapse upon selection of an actionable item
10879
10880 // label settings on multi-select
10881 label: {
10882 transition: 'scale',
10883 duration: 200,
10884 variation: false,
10885 },
10886
10887 // delay before event
10888 delay: {
10889 hide: 300,
10890 show: 200,
10891 search: 20,
10892 },
10893
10894 /* Callbacks */
10895 onChange: function (value, text, $selected) {},
10896 onAdd: function (value, text, $selected) {},
10897 onRemove: function (value, text, $selected) {},
10898 onActionable: function (value, text, $selected) {},
10899 onSearch: function (searchTerm) {},
10900
10901 onLabelSelect: function ($selectedLabels) {},
10902 onLabelCreate: function (value, text) {
10903 return $(this);
10904 },
10905 onLabelRemove: function (value) {
10906 return true;
10907 },
10908 onNoResults: function (searchTerm) {
10909 return true;
10910 },
10911 onShow: function () {},
10912 onHide: function () {},
10913
10914 /* Component */
10915 name: 'Dropdown',
10916 namespace: 'dropdown',
10917
10918 message: {
10919 addResult: 'Add <b>{term}</b>',
10920 count: '{count} selected',
10921 maxSelections: 'Max {maxCount} selections',
10922 noResults: 'No results found.',
10923 serverError: 'There was an error contacting the server',
10924 },
10925
10926 error: {
10927 action: 'You called a dropdown action that was not defined',
10928 alreadySetup: 'Once a select has been initialized behaviors must be called on the created ui dropdown',
10929 labels: 'Allowing user additions currently requires the use of labels.',
10930 missingMultiple: '<select> requires multiple property to be set to correctly preserve multiple values',
10931 method: 'The method you called is not defined.',
10932 noAPI: 'The API module is required to load resources remotely',
10933 noStorage: 'Saving remote data requires session storage',
10934 noElement: 'This module requires ui {element}',
10935 noNormalize: '"ignoreDiacritics" setting will be ignored. Browser does not support String().normalize(). You may consider including <https://cdn.jsdelivr.net/npm/unorm@1.4.1/lib/unorm.min.js> as a polyfill.',
10936 },
10937
10938 regExp: {
10939 escape: /[\s#$()*+,.:=?@[\\\]^{|}-]/g,
10940 quote: /"/g,
10941 },
10942
10943 metadata: {
10944 defaultText: 'defaultText',
10945 defaultValue: 'defaultValue',
10946 placeholderText: 'placeholder',
10947 text: 'text',
10948 value: 'value',
10949 },
10950
10951 // property names for remote query
10952 fields: {
10953 remoteValues: 'results', // grouping for api results
10954 values: 'values', // grouping for all dropdown values
10955 disabled: 'disabled', // whether value should be disabled
10956 name: 'name', // displayed dropdown text
10957 description: 'description', // displayed dropdown description
10958 descriptionVertical: 'descriptionVertical', // whether description should be vertical
10959 value: 'value', // actual dropdown value
10960 text: 'text', // displayed text when selected
10961 type: 'type', // type of dropdown element
10962 image: 'image', // optional image path
10963 imageClass: 'imageClass', // optional individual class for image
10964 icon: 'icon', // optional icon name
10965 iconClass: 'iconClass', // optional individual class for icon (for example to use flag instead)
10966 class: 'class', // optional individual class for item/header
10967 divider: 'divider', // optional divider append for group headers
10968 actionable: 'actionable', // optional actionable item
10969 },
10970
10971 keys: {
10972 backspace: 8,
10973 deleteKey: 46,
10974 enter: 13,
10975 escape: 27,
10976 pageUp: 33,
10977 pageDown: 34,
10978 leftArrow: 37,
10979 upArrow: 38,
10980 rightArrow: 39,
10981 downArrow: 40,
10982 },
10983
10984 selector: {
10985 addition: '.addition',
10986 divider: '.divider, .header',
10987 dropdown: '.ui.dropdown',
10988 hidden: '.hidden',
10989 icon: '> .dropdown.icon',
10990 input: '> input[type="hidden"], > select',
10991 item: '.item',
10992 label: '> .label',
10993 remove: '> .label > .delete.icon',
10994 siblingLabel: '.label',
10995 menu: '.menu',
10996 message: '.message',
10997 menuIcon: '.dropdown.icon',
10998 search: 'input.search, .menu > .search > input, .menu input.search',
10999 sizer: '> span.sizer',
11000 text: '> .text:not(.icon)',
11001 unselectable: '.disabled, .filtered',
11002 clearIcon: '> .remove.icon',
11003 },
11004
11005 className: {
11006 active: 'active',
11007 addition: 'addition',
11008 animating: 'animating',
11009 description: 'description',
11010 descriptionVertical: 'vertical',
11011 disabled: 'disabled',
11012 empty: 'empty',
11013 dropdown: 'ui dropdown',
11014 filtered: 'filtered',
11015 hidden: 'hidden transition',
11016 icon: 'icon',
11017 image: 'image',
11018 item: 'item',
11019 label: 'ui label',
11020 loading: 'loading',
11021 menu: 'menu',
11022 message: 'message',
11023 multiple: 'multiple',
11024 placeholder: 'default',
11025 sizer: 'sizer',
11026 search: 'search',
11027 selected: 'selected',
11028 selection: 'selection',
11029 text: 'text',
11030 upward: 'upward',
11031 leftward: 'left',
11032 visible: 'visible',
11033 clearable: 'clearable',
11034 noselection: 'noselection',
11035 delete: 'delete',
11036 header: 'header',
11037 divider: 'divider',
11038 groupIcon: '',
11039 unfilterable: 'unfilterable',
11040 actionable: 'actionable',
11041 },
11042
11043 };
11044
11045 /* Templates */
11046 $.fn.dropdown.settings.templates = {
11047 deQuote: function (string, encode) {
11048 return String(string).replace(/"/g, encode ? '&quot;' : '');
11049 },
11050 escape: function (string, preserveHTML) {
11051 if (preserveHTML) {
11052 return string;
11053 }
11054 var
11055 badChars = /["'<>`]/g,
11056 shouldEscape = /["&'<>`]/,
11057 escape = {
11058 '<': '&lt;',
11059 '>': '&gt;',
11060 '"': '&quot;',
11061 "'": '&#x27;',
11062 '`': '&#x60;',
11063 },
11064 escapedChar = function (chr) {
11065 return escape[chr];
11066 }
11067 ;
11068 if (shouldEscape.test(string)) {
11069 string = string.replace(/&(?![\d#a-z]{1,12};)/gi, '&amp;');
11070
11071 return string.replace(badChars, escapedChar);
11072 }
11073
11074 return string;
11075 },
11076 // generates dropdown from select values
11077 dropdown: function (select, fields, preserveHTML, className) {
11078 var
11079 placeholder = select.placeholder || false,
11080 html = '',
11081 escape = $.fn.dropdown.settings.templates.escape,
11082 deQuote = $.fn.dropdown.settings.templates.deQuote
11083 ;
11084 html += '<i class="dropdown icon"></i>';
11085 html += placeholder
11086 ? '<div class="default text">' + escape(placeholder, preserveHTML) + '</div>'
11087 : '<div class="text"></div>';
11088 html += '<div class="' + deQuote(className.menu) + '">';
11089 html += $.fn.dropdown.settings.templates.menu(select, fields, preserveHTML, className);
11090 html += '</div>';
11091
11092 return html;
11093 },
11094
11095 // generates just menu from select
11096 menu: function (response, fields, preserveHTML, className) {
11097 var
11098 values = response[fields.values] || [],
11099 html = '',
11100 escape = $.fn.dropdown.settings.templates.escape,
11101 deQuote = $.fn.dropdown.settings.templates.deQuote
11102 ;
11103 $.each(values, function (index, option) {
11104 var
11105 itemType = option[fields.type] || 'item',
11106 isMenu = itemType.indexOf('menu') !== -1
11107 ;
11108
11109 if (itemType === 'item' || isMenu) {
11110 var
11111 maybeText = option[fields.text]
11112 ? ' data-text="' + deQuote(option[fields.text], true) + '"'
11113 : '',
11114 maybeActionable = option[fields.actionable]
11115 ? className.actionable + ' '
11116 : '',
11117 maybeDisabled = option[fields.disabled]
11118 ? className.disabled + ' '
11119 : '',
11120 maybeDescriptionVertical = option[fields.descriptionVertical]
11121 ? className.descriptionVertical + ' '
11122 : '',
11123 hasDescription = escape(option[fields.description] || '', preserveHTML) !== ''
11124 ;
11125 html += '<div class="' + deQuote(maybeActionable + maybeDisabled + maybeDescriptionVertical + (option[fields.class] || className.item)) + '" data-value="' + deQuote(option[fields.value], true) + '"' + maybeText + '>';
11126 if (isMenu) {
11127 html += '<i class="' + (itemType.indexOf('left') !== -1 ? 'left' : '') + ' dropdown icon"></i>';
11128 }
11129 if (option[fields.image]) {
11130 html += '<img class="' + deQuote(option[fields.imageClass] || className.image) + '" src="' + deQuote(option[fields.image]) + '">';
11131 }
11132 if (option[fields.icon]) {
11133 html += '<i class="' + deQuote(option[fields.icon] + ' ' + (option[fields.iconClass] || className.icon)) + '"></i>';
11134 }
11135 if (hasDescription) {
11136 html += '<span class="' + deQuote(className.description) + '">' + escape(option[fields.description] || '', preserveHTML) + '</span>';
11137 html += !isMenu ? '<span class="' + deQuote(className.text) + '">' : '';
11138 }
11139 if (isMenu) {
11140 html += '<span class="' + deQuote(className.text) + '">';
11141 }
11142 html += escape(option[fields.name] || '', preserveHTML);
11143 if (isMenu) {
11144 html += '</span>';
11145 html += '<div class="' + deQuote(itemType) + '">';
11146 html += $.fn.dropdown.settings.templates.menu(option, fields, preserveHTML, className);
11147 html += '</div>';
11148 } else if (hasDescription) {
11149 html += '</span>';
11150 }
11151 html += '</div>';
11152 } else if (itemType === 'header') {
11153 var
11154 groupName = escape(option[fields.name] || '', preserveHTML),
11155 groupIcon = deQuote(option[fields.icon] || className.groupIcon)
11156 ;
11157 if (groupName !== '' || groupIcon !== '') {
11158 html += '<div class="' + deQuote(option[fields.class] || className.header) + '">';
11159 if (groupIcon !== '') {
11160 html += '<i class="' + deQuote(groupIcon + ' ' + (option[fields.iconClass] || className.icon)) + '"></i>';
11161 }
11162 html += groupName;
11163 html += '</div>';
11164 }
11165 if (option[fields.divider]) {
11166 html += '<div class="' + deQuote(className.divider) + '"></div>';
11167 }
11168 }
11169 });
11170
11171 return html;
11172 },
11173
11174 // generates label for multiselect
11175 label: function (value, text, preserveHTML, className) {
11176 var
11177 escape = $.fn.dropdown.settings.templates.escape,
11178 deQuote = $.fn.dropdown.settings.templates.deQuote
11179 ;
11180
11181 return escape(text, preserveHTML) + '<i class="' + deQuote(className.delete) + ' icon"></i>';
11182 },
11183
11184 // generates messages like "No results"
11185 message: function (message) {
11186 return message;
11187 },
11188
11189 // generates user addition to selection menu
11190 addition: function (choice) {
11191 return choice;
11192 },
11193
11194 };
11195})(jQuery, window, document);
11196
11197/*!
11198 * # Fomantic-UI 2.9.3 - Embed
11199 * https://github.com/fomantic/Fomantic-UI/
11200 *
11201 *
11202 * Released under the MIT license
11203 * https://opensource.org/licenses/MIT
11204 *
11205 */
11206
11207(function ($, window, document) {
11208 'use strict';
11209
11210 function isFunction(obj) {
11211 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
11212 }
11213
11214 window = window !== undefined && window.Math === Math
11215 ? window
11216 : globalThis;
11217
11218 $.fn.embed = function (parameters) {
11219 var
11220 $allModules = $(this),
11221
11222 time = Date.now(),
11223 performance = [],
11224
11225 query = arguments[0],
11226 methodInvoked = typeof query === 'string',
11227 queryArguments = [].slice.call(arguments, 1),
11228
11229 returnedValue
11230 ;
11231
11232 $allModules.each(function () {
11233 var
11234 settings = $.isPlainObject(parameters)
11235 ? $.extend(true, {}, $.fn.embed.settings, parameters)
11236 : $.extend({}, $.fn.embed.settings),
11237
11238 selector = settings.selector,
11239 className = settings.className,
11240 sources = settings.sources,
11241 error = settings.error,
11242 metadata = settings.metadata,
11243 namespace = settings.namespace,
11244 templates = settings.templates,
11245
11246 eventNamespace = '.' + namespace,
11247 moduleNamespace = 'module-' + namespace,
11248
11249 $module = $(this),
11250 $placeholder = $module.find(selector.placeholder),
11251 $icon = $module.find(selector.icon),
11252 $embed = $module.find(selector.embed),
11253
11254 element = this,
11255 instance = $module.data(moduleNamespace),
11256 module
11257 ;
11258
11259 module = {
11260
11261 initialize: function () {
11262 module.debug('Initializing embed');
11263 module.determine.autoplay();
11264 module.create();
11265 module.bind.events();
11266 module.instantiate();
11267 },
11268
11269 instantiate: function () {
11270 module.verbose('Storing instance of module', module);
11271 instance = module;
11272 $module
11273 .data(moduleNamespace, module)
11274 ;
11275 },
11276
11277 destroy: function () {
11278 module.verbose('Destroying previous instance of embed');
11279 module.reset();
11280 $module
11281 .removeData(moduleNamespace)
11282 .off(eventNamespace)
11283 ;
11284 },
11285
11286 refresh: function () {
11287 module.verbose('Refreshing selector cache');
11288 $placeholder = $module.find(selector.placeholder);
11289 $icon = $module.find(selector.icon);
11290 $embed = $module.find(selector.embed);
11291 },
11292
11293 bind: {
11294 events: function () {
11295 if (module.has.placeholder()) {
11296 module.debug('Adding placeholder events');
11297 $module
11298 .on('click' + eventNamespace, selector.placeholder, module.createAndShow)
11299 .on('click' + eventNamespace, selector.icon, module.createAndShow)
11300 ;
11301 }
11302 },
11303 },
11304
11305 create: function () {
11306 var
11307 placeholder = module.get.placeholder()
11308 ;
11309 if (placeholder) {
11310 module.createPlaceholder();
11311 } else {
11312 module.createAndShow();
11313 }
11314 },
11315
11316 createPlaceholder: function (placeholder) {
11317 var
11318 icon = module.get.icon()
11319 ;
11320 placeholder = placeholder || module.get.placeholder();
11321 $module.html(templates.placeholder(placeholder, icon));
11322 module.debug('Creating placeholder for embed', placeholder, icon);
11323 },
11324
11325 createEmbed: function (url) {
11326 module.refresh();
11327 url = url || module.get.url();
11328 $embed = $('<div/>')
11329 .addClass(className.embed)
11330 .html(module.generate.embed(url))
11331 .appendTo($module)
11332 ;
11333 settings.onCreate.call(element, url);
11334 module.debug('Creating embed object', $embed);
11335 },
11336
11337 changeEmbed: function (url) {
11338 $embed
11339 .html(module.generate.embed(url))
11340 ;
11341 },
11342
11343 createAndShow: function () {
11344 module.createEmbed();
11345 module.show();
11346 },
11347
11348 // sets new embed
11349 change: function (source, id, url) {
11350 module.debug('Changing video to ', source, id, url);
11351 $module
11352 .data(metadata.source, source)
11353 .data(metadata.id, id)
11354 ;
11355 if (url) {
11356 $module.data(metadata.url, url);
11357 } else {
11358 $module.removeData(metadata.url);
11359 }
11360 if (module.has.embed()) {
11361 module.changeEmbed();
11362 } else {
11363 module.create();
11364 }
11365 },
11366
11367 // clears embed
11368 reset: function () {
11369 module.debug('Clearing embed and showing placeholder');
11370 module.remove.data();
11371 module.remove.active();
11372 module.remove.embed();
11373 module.showPlaceholder();
11374 settings.onReset.call(element);
11375 },
11376
11377 // shows current embed
11378 show: function () {
11379 module.debug('Showing embed');
11380 module.set.active();
11381 settings.onDisplay.call(element);
11382 },
11383
11384 hide: function () {
11385 module.debug('Hiding embed');
11386 module.showPlaceholder();
11387 },
11388
11389 showPlaceholder: function () {
11390 module.debug('Showing placeholder image');
11391 module.remove.active();
11392 settings.onPlaceholderDisplay.call(element);
11393 },
11394
11395 get: {
11396 id: function () {
11397 return settings.id || $module.data(metadata.id);
11398 },
11399 placeholder: function () {
11400 return settings.placeholder || $module.data(metadata.placeholder);
11401 },
11402 icon: function () {
11403 return settings.icon || ($module.data(metadata.icon) !== undefined
11404 ? $module.data(metadata.icon)
11405 : module.determine.icon());
11406 },
11407 source: function (url) {
11408 return settings.source || ($module.data(metadata.source) !== undefined
11409 ? $module.data(metadata.source)
11410 : module.determine.source());
11411 },
11412 type: function () {
11413 var source = module.get.source();
11414
11415 return sources[source] !== undefined
11416 ? sources[source].type
11417 : false;
11418 },
11419 url: function () {
11420 return settings.url || ($module.data(metadata.url) !== undefined
11421 ? $module.data(metadata.url)
11422 : module.determine.url());
11423 },
11424 },
11425
11426 determine: {
11427 autoplay: function () {
11428 if (module.should.autoplay()) {
11429 settings.autoplay = true;
11430 }
11431 },
11432 source: function (url) {
11433 var
11434 matchedSource = false
11435 ;
11436 url = url || module.get.url();
11437 if (url) {
11438 $.each(sources, function (name, source) {
11439 if (url.search(source.domain) !== -1) {
11440 matchedSource = name;
11441
11442 return false;
11443 }
11444 });
11445 }
11446
11447 return matchedSource;
11448 },
11449 icon: function () {
11450 var
11451 source = module.get.source()
11452 ;
11453
11454 return sources[source] !== undefined
11455 ? sources[source].icon
11456 : false;
11457 },
11458 url: function () {
11459 var
11460 id = settings.id || $module.data(metadata.id),
11461 source = settings.source || $module.data(metadata.source),
11462 url
11463 ;
11464 url = sources[source] !== undefined
11465 ? sources[source].url.replace('{id}', id)
11466 : false;
11467 if (url) {
11468 $module.data(metadata.url, url);
11469 }
11470
11471 return url;
11472 },
11473 },
11474
11475 set: {
11476 active: function () {
11477 $module.addClass(className.active);
11478 },
11479 },
11480
11481 remove: {
11482 data: function () {
11483 $module
11484 .removeData(metadata.id)
11485 .removeData(metadata.icon)
11486 .removeData(metadata.placeholder)
11487 .removeData(metadata.source)
11488 .removeData(metadata.url)
11489 ;
11490 },
11491 active: function () {
11492 $module.removeClass(className.active);
11493 },
11494 embed: function () {
11495 $embed.empty();
11496 },
11497 },
11498
11499 encode: {
11500 parameters: function (parameters) {
11501 var
11502 urlString = [],
11503 index
11504 ;
11505 for (index in parameters) {
11506 urlString.push(encodeURIComponent(index) + '=' + encodeURIComponent(parameters[index]));
11507 }
11508
11509 return urlString.join('&amp;');
11510 },
11511 },
11512
11513 generate: {
11514 embed: function (url) {
11515 module.debug('Generating embed html');
11516 var
11517 source = module.get.source(),
11518 html,
11519 parameters
11520 ;
11521 url = module.get.url(url);
11522 if (url) {
11523 parameters = module.generate.parameters(source);
11524 html = templates.iframe(url, parameters);
11525 } else {
11526 module.error(error.noURL, $module);
11527 }
11528
11529 return html;
11530 },
11531 parameters: function (source, extraParameters) {
11532 var
11533 parameters = sources[source] && sources[source].parameters !== undefined
11534 ? sources[source].parameters(settings)
11535 : {}
11536 ;
11537 extraParameters = extraParameters || settings.parameters;
11538 if (extraParameters) {
11539 parameters = $.extend({}, parameters, extraParameters);
11540 }
11541 parameters = settings.onEmbed(parameters);
11542
11543 return module.encode.parameters(parameters);
11544 },
11545 },
11546
11547 has: {
11548 embed: function () {
11549 return $embed.length > 0;
11550 },
11551 placeholder: function () {
11552 return settings.placeholder || $module.data(metadata.placeholder);
11553 },
11554 },
11555
11556 should: {
11557 autoplay: function () {
11558 return settings.autoplay === 'auto'
11559 ? settings.placeholder || $module.data(metadata.placeholder) !== undefined
11560 : settings.autoplay;
11561 },
11562 },
11563
11564 is: {
11565 video: function () {
11566 return module.get.type() === 'video';
11567 },
11568 },
11569
11570 setting: function (name, value) {
11571 module.debug('Changing setting', name, value);
11572 if ($.isPlainObject(name)) {
11573 $.extend(true, settings, name);
11574 } else if (value !== undefined) {
11575 if ($.isPlainObject(settings[name])) {
11576 $.extend(true, settings[name], value);
11577 } else {
11578 settings[name] = value;
11579 }
11580 } else {
11581 return settings[name];
11582 }
11583 },
11584 internal: function (name, value) {
11585 if ($.isPlainObject(name)) {
11586 $.extend(true, module, name);
11587 } else if (value !== undefined) {
11588 module[name] = value;
11589 } else {
11590 return module[name];
11591 }
11592 },
11593 debug: function () {
11594 if (!settings.silent && settings.debug) {
11595 if (settings.performance) {
11596 module.performance.log(arguments);
11597 } else {
11598 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
11599 module.debug.apply(console, arguments);
11600 }
11601 }
11602 },
11603 verbose: function () {
11604 if (!settings.silent && settings.verbose && settings.debug) {
11605 if (settings.performance) {
11606 module.performance.log(arguments);
11607 } else {
11608 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
11609 module.verbose.apply(console, arguments);
11610 }
11611 }
11612 },
11613 error: function () {
11614 if (!settings.silent) {
11615 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
11616 module.error.apply(console, arguments);
11617 }
11618 },
11619 performance: {
11620 log: function (message) {
11621 var
11622 currentTime,
11623 executionTime,
11624 previousTime
11625 ;
11626 if (settings.performance) {
11627 currentTime = Date.now();
11628 previousTime = time || currentTime;
11629 executionTime = currentTime - previousTime;
11630 time = currentTime;
11631 performance.push({
11632 Name: message[0],
11633 Arguments: [].slice.call(message, 1) || '',
11634 Element: element,
11635 'Execution Time': executionTime,
11636 });
11637 }
11638 clearTimeout(module.performance.timer);
11639 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
11640 },
11641 display: function () {
11642 var
11643 title = settings.name + ':',
11644 totalTime = 0
11645 ;
11646 time = false;
11647 clearTimeout(module.performance.timer);
11648 $.each(performance, function (index, data) {
11649 totalTime += data['Execution Time'];
11650 });
11651 title += ' ' + totalTime + 'ms';
11652 if ($allModules.length > 1) {
11653 title += ' (' + $allModules.length + ')';
11654 }
11655 if (performance.length > 0) {
11656 console.groupCollapsed(title);
11657 if (console.table) {
11658 console.table(performance);
11659 } else {
11660 $.each(performance, function (index, data) {
11661 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
11662 });
11663 }
11664 console.groupEnd();
11665 }
11666 performance = [];
11667 },
11668 },
11669 invoke: function (query, passedArguments, context) {
11670 var
11671 object = instance,
11672 maxDepth,
11673 found,
11674 response
11675 ;
11676 passedArguments = passedArguments || queryArguments;
11677 context = context || element;
11678 if (typeof query === 'string' && object !== undefined) {
11679 query = query.split(/[ .]/);
11680 maxDepth = query.length - 1;
11681 $.each(query, function (depth, value) {
11682 var camelCaseValue = depth !== maxDepth
11683 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
11684 : query
11685 ;
11686 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
11687 object = object[camelCaseValue];
11688 } else if (object[camelCaseValue] !== undefined) {
11689 found = object[camelCaseValue];
11690
11691 return false;
11692 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
11693 object = object[value];
11694 } else if (object[value] !== undefined) {
11695 found = object[value];
11696
11697 return false;
11698 } else {
11699 module.error(error.method, query);
11700
11701 return false;
11702 }
11703 });
11704 }
11705 if (isFunction(found)) {
11706 response = found.apply(context, passedArguments);
11707 } else if (found !== undefined) {
11708 response = found;
11709 }
11710 if (Array.isArray(returnedValue)) {
11711 returnedValue.push(response);
11712 } else if (returnedValue !== undefined) {
11713 returnedValue = [returnedValue, response];
11714 } else if (response !== undefined) {
11715 returnedValue = response;
11716 }
11717
11718 return found;
11719 },
11720 };
11721
11722 if (methodInvoked) {
11723 if (instance === undefined) {
11724 module.initialize();
11725 }
11726 module.invoke(query);
11727 } else {
11728 if (instance !== undefined) {
11729 instance.invoke('destroy');
11730 }
11731 module.initialize();
11732 }
11733 });
11734
11735 return returnedValue !== undefined
11736 ? returnedValue
11737 : this;
11738 };
11739
11740 $.fn.embed.settings = {
11741
11742 name: 'Embed',
11743 namespace: 'embed',
11744
11745 silent: false,
11746 debug: false,
11747 verbose: false,
11748 performance: true,
11749
11750 icon: false,
11751 source: false,
11752 url: false,
11753 id: false,
11754
11755 // standard video settings
11756 autoplay: 'auto',
11757 color: '#444',
11758 hd: true,
11759 brandedUI: false,
11760
11761 // additional parameters to include with the embed
11762 parameters: false,
11763
11764 onDisplay: function () {},
11765 onPlaceholderDisplay: function () {},
11766 onReset: function () {},
11767 onCreate: function (url) {},
11768 onEmbed: function (parameters) {
11769 return parameters;
11770 },
11771
11772 metadata: {
11773 id: 'id',
11774 icon: 'icon',
11775 placeholder: 'placeholder',
11776 source: 'source',
11777 url: 'url',
11778 },
11779
11780 error: {
11781 noURL: 'No URL specified',
11782 method: 'The method you called is not defined',
11783 },
11784
11785 className: {
11786 active: 'active',
11787 embed: 'embed',
11788 },
11789
11790 selector: {
11791 embed: '.embed',
11792 placeholder: '.placeholder',
11793 icon: '.icon',
11794 },
11795
11796 sources: {
11797 youtube: {
11798 name: 'youtube',
11799 type: 'video',
11800 icon: 'video play',
11801 domain: 'youtube.com',
11802 url: '//www.youtube.com/embed/{id}',
11803 parameters: function (settings) {
11804 return {
11805 autohide: !settings.brandedUI,
11806 autoplay: settings.autoplay,
11807 color: settings.color || undefined,
11808 hq: settings.hd,
11809 jsapi: settings.api,
11810 modestbranding: !settings.brandedUI,
11811 };
11812 },
11813 },
11814 vimeo: {
11815 name: 'vimeo',
11816 type: 'video',
11817 icon: 'video play',
11818 domain: 'vimeo.com',
11819 url: '//player.vimeo.com/video/{id}',
11820 parameters: function (settings) {
11821 return {
11822 api: settings.api,
11823 autoplay: settings.autoplay,
11824 byline: settings.brandedUI,
11825 color: settings.color || undefined,
11826 portrait: settings.brandedUI,
11827 title: settings.brandedUI,
11828 };
11829 },
11830 },
11831 },
11832
11833 templates: {
11834 deQuote: function (string, encode) {
11835 return String(string).replace(/"/g, encode ? '&quot;' : '');
11836 },
11837 iframe: function (url, parameters) {
11838 var
11839 src = url,
11840 deQuote = $.fn.embed.settings.templates.deQuote
11841 ;
11842 if (parameters) {
11843 src += '?' + parameters;
11844 }
11845
11846 return ''
11847 + '<iframe src="' + deQuote(src) + '"'
11848 + ' width="100%" height="100%"'
11849 + ' msallowFullScreen allowFullScreen></iframe>';
11850 },
11851 placeholder: function (image, icon) {
11852 var
11853 html = '',
11854 deQuote = $.fn.embed.settings.templates.deQuote
11855 ;
11856 if (icon) {
11857 html += '<i class="' + deQuote(icon) + ' icon"></i>';
11858 }
11859 if (image) {
11860 html += '<img class="placeholder" src="' + deQuote(image) + '">';
11861 }
11862
11863 return html;
11864 },
11865 },
11866
11867 // NOT YET IMPLEMENTED
11868 api: false,
11869 onPause: function () {},
11870 onPlay: function () {},
11871 onStop: function () {},
11872
11873 };
11874})(jQuery, window, document);
11875
11876/*!
11877 * # Fomantic-UI 2.9.3 - Flyout
11878 * https://github.com/fomantic/Fomantic-UI/
11879 *
11880 *
11881 * Released under the MIT license
11882 * https://opensource.org/licenses/MIT
11883 *
11884 */
11885
11886(function ($, window, document) {
11887 'use strict';
11888
11889 function isFunction(obj) {
11890 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
11891 }
11892
11893 window = window !== undefined && window.Math === Math
11894 ? window
11895 : globalThis;
11896
11897 $.fn.flyout = function (parameters) {
11898 var
11899 $allModules = $(this),
11900 $window = $(window),
11901 $document = $(document),
11902 $html = $('html'),
11903 $head = $('head'),
11904 $body = $('body'),
11905
11906 time = Date.now(),
11907 performance = [],
11908
11909 query = arguments[0],
11910 methodInvoked = typeof query === 'string',
11911 queryArguments = [].slice.call(arguments, 1),
11912 contextCheck = function (context, win) {
11913 var $context;
11914 if ([window, document].indexOf(context) >= 0) {
11915 $context = $body;
11916 } else {
11917 $context = $(win.document).find(context);
11918 if ($context.length === 0) {
11919 $context = win.frameElement ? contextCheck(context, win.parent) : $body;
11920 }
11921 }
11922
11923 return $context;
11924 },
11925 returnedValue
11926 ;
11927
11928 $allModules.each(function () {
11929 var
11930 settings = $.isPlainObject(parameters)
11931 ? $.extend(true, {}, $.fn.flyout.settings, parameters)
11932 : $.extend({}, $.fn.flyout.settings),
11933
11934 selector = settings.selector,
11935 className = settings.className,
11936 namespace = settings.namespace,
11937 fields = settings.fields,
11938 regExp = settings.regExp,
11939 error = settings.error,
11940
11941 eventNamespace = '.' + namespace,
11942 moduleNamespace = 'module-' + namespace,
11943
11944 $module = $(this),
11945 $context = contextCheck(settings.context, window),
11946 $closeIcon = $module.find(selector.close),
11947 $inputs,
11948 $focusedElement,
11949
11950 $flyouts = $module.children(selector.flyout),
11951 $pusher = $context.children(selector.pusher),
11952 $style,
11953
11954 isFlyoutComponent = $module.hasClass('flyout'),
11955
11956 element = this,
11957 instance = isFlyoutComponent ? $module.data(moduleNamespace) : undefined,
11958
11959 ignoreRepeatedEvents = false,
11960 isBody = $context[0] === $body[0],
11961 initialBodyMargin = '',
11962 tempBodyMargin = '',
11963 hadScrollbar = false,
11964 windowRefocused = false,
11965
11966 elementNamespace,
11967 id,
11968 observer,
11969 observeAttributes = false,
11970 currentScroll,
11971
11972 module
11973 ;
11974
11975 module = {
11976
11977 initialize: function () {
11978 module.debug('Initializing flyout', parameters);
11979
11980 module.create.id();
11981 if (!isFlyoutComponent) {
11982 module.create.flyout();
11983 if (!isFunction(settings.onHidden)) {
11984 settings.onHidden = function () {
11985 module.destroy();
11986 $module.remove();
11987 };
11988 }
11989 if (!settings.autoShow) {
11990 settings.autoShow = true;
11991 }
11992 }
11993 $module.addClass(settings.class);
11994 if (settings.title !== '') {
11995 $module.find(selector.header).html(module.helpers.escape(settings.title, settings.preserveHTML)).addClass(settings.classTitle);
11996 }
11997 if (settings.content !== '') {
11998 $module.find(selector.content).html(module.helpers.escape(settings.content, settings.preserveHTML)).addClass(settings.classContent);
11999 }
12000 if (module.has.configActions()) {
12001 var $actions = $module.find(selector.actions).addClass(settings.classActions);
12002 if ($actions.length === 0) {
12003 $actions = $('<div/>', { class: className.actions + ' ' + (settings.classActions || '') }).appendTo($module);
12004 } else {
12005 $actions.empty();
12006 }
12007 settings.actions.forEach(function (el) {
12008 var
12009 icon = el[fields.icon]
12010 ? '<i ' + (el[fields.text] ? 'aria-hidden="true"' : '') + ' class="' + module.helpers.deQuote(el[fields.icon]) + ' icon"></i>'
12011 : '',
12012 text = module.helpers.escape(el[fields.text] || '', settings.preserveHTML),
12013 cls = module.helpers.deQuote(el[fields.class] || ''),
12014 click = el[fields.click] && isFunction(el[fields.click])
12015 ? el[fields.click]
12016 : function () {}
12017 ;
12018 $actions.append($('<button/>', {
12019 html: icon + text,
12020 'aria-label': (el[fields.text] || el[fields.icon] || '').replace(/<[^>]+(>|$)/g, ''),
12021 class: className.button + ' ' + cls,
12022 on: {
12023 click: function () {
12024 if (click.call(element, $module) === false) {
12025 return;
12026 }
12027 module.hide();
12028 },
12029 },
12030 }));
12031 });
12032 }
12033
12034 // avoids locking rendering if initialized in onReady
12035 if (settings.delaySetup) {
12036 requestAnimationFrame(module.setup.layout);
12037 } else {
12038 module.setup.layout();
12039 }
12040
12041 requestAnimationFrame(function () {
12042 module.setup.cache();
12043 });
12044
12045 if (module.get.direction() === 'left' || module.get.direction() === 'right') {
12046 module.setup.heights();
12047 module.bind.resize();
12048 }
12049 module.bind.events();
12050 module.observeChanges();
12051 module.instantiate();
12052
12053 if (settings.autoShow) {
12054 module.show();
12055 }
12056 },
12057
12058 instantiate: function () {
12059 module.verbose('Storing instance of module', module);
12060 instance = module;
12061 $module
12062 .data(moduleNamespace, instance)
12063 ;
12064 },
12065
12066 create: {
12067 flyout: function () {
12068 module.verbose('Programmaticaly create flyout', $context);
12069 $module = $('<div/>', { class: className.flyout, role: 'dialog', 'aria-modal': settings.dimPage });
12070 if (settings.closeIcon) {
12071 $closeIcon = $('<i/>', {
12072 class: className.close,
12073 role: 'button',
12074 tabindex: 0,
12075 'aria-label': settings.text.close,
12076 });
12077 $module.append($closeIcon);
12078 }
12079 if (settings.title !== '') {
12080 var titleId = '_' + module.get.id() + 'title';
12081 $module.attr('aria-labelledby', titleId);
12082 $('<div/>', { class: className.header, id: titleId }).appendTo($module);
12083 }
12084 if (settings.content !== '') {
12085 var descId = '_' + module.get.id() + 'desc';
12086 $module.attr('aria-describedby', descId);
12087 $('<div/>', { class: className.content, id: descId }).appendTo($module);
12088 }
12089 if (module.has.configActions()) {
12090 $('<div/>', { class: className.actions }).appendTo($module);
12091 }
12092 $module.prependTo($context);
12093 element = $module[0];
12094 },
12095 id: function () {
12096 id = (Math.random().toString(16) + '000000000').slice(2, 10);
12097 elementNamespace = '.' + id;
12098 module.verbose('Creating unique id for element', id);
12099 },
12100 },
12101
12102 destroy: function () {
12103 if (observer) {
12104 observer.disconnect();
12105 }
12106 module.verbose('Destroying previous module for', $module);
12107 $module
12108 .off(eventNamespace)
12109 .removeData(moduleNamespace)
12110 ;
12111 $closeIcon.off(elementNamespace);
12112 if ($inputs) {
12113 $inputs.off(elementNamespace);
12114 }
12115 // bound by uuid
12116 $context.off(elementNamespace);
12117 $window.off(elementNamespace);
12118 $document.off(elementNamespace);
12119 },
12120
12121 event: {
12122 keyboard: function (event) {
12123 var
12124 keyCode = event.which
12125 ;
12126 if (keyCode === settings.keys.escape) {
12127 if (settings.closable) {
12128 module.debug('Escape key pressed hiding flyout');
12129 module.hide();
12130 } else {
12131 module.debug('Escape key pressed, but closable is set to false');
12132 }
12133 event.preventDefault();
12134 }
12135 },
12136 resize: function () {
12137 module.setup.heights();
12138 },
12139 focus: function () {
12140 windowRefocused = true;
12141 },
12142 click: function (event) {
12143 if (windowRefocused && document.activeElement !== event.target && module.is.visible() && settings.autofocus && settings.dimPage && $(document.activeElement).closest(selector.flyout).length === 0) {
12144 requestAnimationFrame(module.set.autofocus);
12145 }
12146 windowRefocused = false;
12147 },
12148 clickaway: function (event) {
12149 if (settings.closable) {
12150 var
12151 clickedInPusher = $pusher.find(event.target).length > 0 || $pusher.is(event.target),
12152 clickedContext = $context.is(event.target)
12153 ;
12154 if (clickedInPusher) {
12155 module.verbose('User clicked on dimmed page');
12156 module.hide();
12157 }
12158 if (clickedContext) {
12159 module.verbose('User clicked on dimmable context (scaled out page)');
12160 module.hide();
12161 }
12162 }
12163 },
12164 close: function (event) {
12165 module.hide();
12166 },
12167 closeKeyUp: function (event) {
12168 var
12169 keyCode = event.which
12170 ;
12171 if (keyCode === settings.keys.enter || keyCode === settings.keys.space) {
12172 module.hide();
12173 }
12174 },
12175 inputKeyDown: {
12176 first: function (event) {
12177 var
12178 keyCode = event.which
12179 ;
12180 if (keyCode === settings.keys.tab && event.shiftKey) {
12181 $inputs.last().trigger('focus');
12182 event.preventDefault();
12183 }
12184 },
12185 last: function (event) {
12186 var
12187 keyCode = event.which
12188 ;
12189 if (keyCode === settings.keys.tab && !event.shiftKey) {
12190 $inputs.first().trigger('focus');
12191 event.preventDefault();
12192 }
12193 },
12194 },
12195 approve: function (event) {
12196 if (ignoreRepeatedEvents || settings.onApprove.call(module.element, $(this)) === false) {
12197 module.verbose('Approve callback returned false cancelling close');
12198
12199 return;
12200 }
12201 ignoreRepeatedEvents = true;
12202 module.hide(function () {
12203 ignoreRepeatedEvents = false;
12204 });
12205 },
12206 deny: function (event) {
12207 if (ignoreRepeatedEvents || settings.onDeny.call(module.element, $(this)) === false) {
12208 module.verbose('Deny callback returned false cancelling close');
12209
12210 return;
12211 }
12212 ignoreRepeatedEvents = true;
12213 module.hide(function () {
12214 ignoreRepeatedEvents = false;
12215 });
12216 },
12217 touch: function (event) {
12218 // event.stopPropagation();
12219 },
12220 containScroll: function (event) {
12221 if (element.scrollTop <= 0) {
12222 element.scrollTop = 1;
12223 }
12224 if ((element.scrollTop + element.offsetHeight) >= element.scrollHeight) {
12225 element.scrollTop = element.scrollHeight - element.offsetHeight - 1;
12226 }
12227 },
12228 scroll: function (event) {
12229 if ($(event.target).closest(selector.flyout).length === 0) {
12230 event.preventDefault();
12231 }
12232 },
12233 },
12234
12235 bind: {
12236 resize: function () {
12237 module.verbose('Adding resize event to window', $window);
12238 $window.on('resize' + elementNamespace, module.event.resize);
12239 },
12240 events: function () {
12241 module.verbose('Attaching events');
12242 $module
12243 .on('click' + eventNamespace, selector.close, module.event.close)
12244 .on('click' + eventNamespace, selector.approve, module.event.approve)
12245 .on('click' + eventNamespace, selector.deny, module.event.deny)
12246 ;
12247 $closeIcon
12248 .on('keyup' + elementNamespace, module.event.closeKeyUp)
12249 ;
12250 $window
12251 .on('focus' + elementNamespace, module.event.focus)
12252 ;
12253 $context
12254 .on('click' + elementNamespace, module.event.click)
12255 ;
12256 },
12257 clickaway: function () {
12258 module.verbose('Adding clickaway events to context', $context);
12259 $context
12260 .on('click' + elementNamespace, module.event.clickaway)
12261 .on('touchend' + elementNamespace, module.event.clickaway)
12262 ;
12263 },
12264 scrollLock: function () {
12265 if (settings.scrollLock) {
12266 module.debug('Disabling page scroll');
12267 hadScrollbar = module.has.scrollbar();
12268 if (hadScrollbar) {
12269 module.save.bodyMargin();
12270 module.set.bodyMargin();
12271 }
12272 $context.addClass(className.locked);
12273 }
12274 module.verbose('Adding events to contain flyout scroll');
12275 $document
12276 .on('touchmove' + elementNamespace, module.event.touch)
12277 ;
12278 $module
12279 .on('scroll' + eventNamespace, module.event.containScroll)
12280 ;
12281 },
12282 },
12283 unbind: {
12284 clickaway: function () {
12285 module.verbose('Removing clickaway events from context', $context);
12286 $context.off(elementNamespace);
12287 },
12288 scrollLock: function () {
12289 module.verbose('Removing scroll lock from page');
12290 if (hadScrollbar) {
12291 module.restore.bodyMargin();
12292 }
12293 $context.removeClass(className.locked);
12294 $document.off(elementNamespace);
12295 $module.off('scroll' + eventNamespace);
12296 },
12297 },
12298
12299 add: {
12300 inlineCSS: function () {
12301 var
12302 width = module.cache.width || $module.outerWidth(),
12303 height = module.cache.height || $module.outerHeight(),
12304 isRTL = module.is.rtl(),
12305 direction = module.get.direction(),
12306 distance = {
12307 left: width,
12308 right: -width,
12309 top: height,
12310 bottom: -height,
12311 },
12312 style
12313 ;
12314
12315 if (isRTL) {
12316 module.verbose('RTL detected, flipping widths');
12317 distance.left = -width;
12318 distance.right = width;
12319 }
12320
12321 style = '<style>';
12322
12323 if (direction === 'left' || direction === 'right') {
12324 module.debug('Adding CSS rules for animation distance', width);
12325 style += ''
12326 + ' .ui.visible.' + direction + '.flyout ~ .fixed,'
12327 + ' .ui.visible.' + direction + '.flyout ~ .pusher {'
12328 + ' transform: translate3d(' + distance[direction] + 'px, 0, 0);'
12329 + ' }';
12330 } else if (direction === 'top' || direction === 'bottom') {
12331 style += ''
12332 + ' .ui.visible.' + direction + '.flyout ~ .fixed,'
12333 + ' .ui.visible.' + direction + '.flyout ~ .pusher {'
12334 + ' transform: translate3d(0, ' + distance[direction] + 'px, 0);'
12335 + ' }';
12336 }
12337
12338 /* IE is only browser not to create context with transforms */
12339 /* https://www.w3.org/Bugs/Public/show_bug.cgi?id=16328 */
12340 if (module.is.ie()) {
12341 if (direction === 'left' || direction === 'right') {
12342 module.debug('Adding CSS rules for animation distance', width);
12343 style += ''
12344 + ' body.pushable > .ui.visible.' + direction + '.flyout ~ .pusher::after {'
12345 + ' transform: translate3d(' + distance[direction] + 'px, 0, 0);'
12346 + ' }';
12347 } else if (direction === 'top' || direction === 'bottom') {
12348 style += ''
12349 + ' body.pushable > .ui.visible.' + direction + '.flyout ~ .pusher::after {'
12350 + ' transform: translate3d(0, ' + distance[direction] + 'px, 0);'
12351 + ' }';
12352 }
12353 /* opposite sides visible forces content overlay */
12354 style += ''
12355 + ' body.pushable > .ui.visible.left.flyout ~ .ui.visible.right.flyout ~ .pusher::after,'
12356 + ' body.pushable > .ui.visible.right.flyout ~ .ui.visible.left.flyout ~ .pusher::after {'
12357 + ' transform: translate3d(0, 0, 0);'
12358 + ' }';
12359 }
12360 style += '</style>';
12361 $style = $(style)
12362 .appendTo($head)
12363 ;
12364 module.debug('Adding sizing css to head', $style);
12365 },
12366 keyboardShortcuts: function () {
12367 module.verbose('Adding keyboard shortcuts');
12368 $document
12369 .on('keydown' + eventNamespace, module.event.keyboard)
12370 ;
12371 },
12372 },
12373 observeChanges: function () {
12374 if ('MutationObserver' in window) {
12375 observer = new MutationObserver(function (mutations) {
12376 var collectNodes = function (parent) {
12377 var nodes = [];
12378 for (var c = 0, cl = parent.length; c < cl; c++) {
12379 Array.prototype.push.apply(nodes, collectNodes(parent[c].childNodes));
12380 nodes.push(parent[c]);
12381 }
12382
12383 return nodes;
12384 },
12385 shouldRefreshInputs = false,
12386 ignoreAutofocus = true
12387 ;
12388 mutations.every(function (mutation) {
12389 if (mutation.type === 'attributes') {
12390 if (observeAttributes && (mutation.attributeName === 'disabled' || $(mutation.target).find(':input').addBack(':input').filter(':visible').length > 0)) {
12391 shouldRefreshInputs = true;
12392 }
12393 } else {
12394 // mutationobserver only provides the parent nodes
12395 // so let's collect all childs as well to find nested inputs
12396 var $addedInputs = $(collectNodes(mutation.addedNodes)).filter('a[href], [tabindex], :input:enabled').filter(':visible'),
12397 $removedInputs = $(collectNodes(mutation.removedNodes)).filter('a[href], [tabindex], :input');
12398 if ($addedInputs.length > 0 || $removedInputs.length > 0) {
12399 shouldRefreshInputs = true;
12400 if ($addedInputs.filter(':input').length > 0 || $removedInputs.filter(':input').length > 0) {
12401 ignoreAutofocus = false;
12402 }
12403 }
12404 }
12405
12406 return !shouldRefreshInputs;
12407 });
12408
12409 if (shouldRefreshInputs) {
12410 module.refreshInputs(ignoreAutofocus);
12411 }
12412 });
12413 observer.observe(element, {
12414 attributeFilter: ['class', 'disabled'],
12415 attributes: true,
12416 childList: true,
12417 subtree: true,
12418 });
12419 module.debug('Setting up mutation observer', observer);
12420 }
12421 },
12422 refresh: function () {
12423 module.verbose('Refreshing selector cache');
12424 $context = contextCheck(settings.context, window);
12425 module.refreshFlyouts();
12426 $pusher = $context.children(selector.pusher);
12427 module.clear.cache();
12428 },
12429
12430 refreshFlyouts: function () {
12431 module.verbose('Refreshing other flyouts');
12432 $flyouts = $context.children(selector.flyout);
12433 },
12434
12435 refreshInputs: function (ignoreAutofocus) {
12436 if ($inputs) {
12437 $inputs
12438 .off('keydown' + elementNamespace)
12439 ;
12440 }
12441 if (!settings.dimPage) {
12442 return;
12443 }
12444 $inputs = $module.find('a[href], [tabindex], :input:enabled').filter(':visible').filter(function () {
12445 return $(this).closest('.disabled').length === 0;
12446 });
12447 if ($inputs.filter(':input').length === 0) {
12448 $inputs = $module.add($inputs);
12449 $module.attr('tabindex', -1);
12450 } else {
12451 $module.removeAttr('tabindex');
12452 }
12453 $inputs.first()
12454 .on('keydown' + elementNamespace, module.event.inputKeyDown.first)
12455 ;
12456 $inputs.last()
12457 .on('keydown' + elementNamespace, module.event.inputKeyDown.last)
12458 ;
12459 if (!ignoreAutofocus && settings.autofocus && $inputs.filter(':focus').length === 0) {
12460 module.set.autofocus();
12461 }
12462 },
12463
12464 setup: {
12465 cache: function () {
12466 module.cache = {
12467 width: $module.outerWidth(),
12468 height: $module.outerHeight(),
12469 };
12470 },
12471 layout: function () {
12472 if ($context.children(selector.pusher).length === 0) {
12473 module.debug('Adding wrapper element for flyout');
12474 module.error(error.pusher);
12475 $pusher = $('<div class="pusher" />');
12476 $context
12477 .children()
12478 .not(selector.omitted)
12479 .not($flyouts)
12480 .wrapAll($pusher)
12481 ;
12482 module.refresh();
12483 }
12484 if ($module.nextAll(selector.pusher).length === 0 || $module.nextAll(selector.pusher)[0] !== $pusher[0]) {
12485 module.debug('Moved flyout to correct parent element');
12486 module.error(error.movedFlyout, element);
12487 $module.detach().prependTo($context);
12488 module.refresh();
12489 }
12490 if (module.is.mobile()) {
12491 $module.addClass(className.fullscreen);
12492 }
12493 module.clear.cache();
12494 module.set.pushable();
12495 module.set.direction();
12496 },
12497 heights: function () {
12498 module.debug('Setting up heights', $module);
12499 var
12500 $header = $module.children(selector.header),
12501 $content = $module.children(selector.content),
12502 $actions = $module.children(selector.actions),
12503 newContentHeight = ($context.height() || 0) - ($header.outerHeight() || 0) - ($actions.outerHeight() || 0)
12504 ;
12505 if (newContentHeight > 0) {
12506 $content.css('min-height', String(newContentHeight) + 'px');
12507 }
12508 },
12509 },
12510
12511 attachEvents: function (selector, event) {
12512 var
12513 $toggle = $(selector)
12514 ;
12515 event = isFunction(module[event])
12516 ? module[event]
12517 : module.toggle;
12518 if ($toggle.length > 0) {
12519 module.debug('Attaching flyout events to element', selector, event);
12520 $toggle
12521 .on('click' + eventNamespace, event)
12522 ;
12523 } else {
12524 module.error(error.notFound, selector);
12525 }
12526 },
12527
12528 show: function (callback) {
12529 callback = isFunction(callback)
12530 ? callback
12531 : function () {};
12532 if (module.is.hidden()) {
12533 if (settings.onShow.call(element) === false) {
12534 module.verbose('Show callback returned false cancelling show');
12535
12536 return;
12537 }
12538 module.refresh();
12539 if (module.othersActive()) {
12540 module.debug('Other flyouts currently visible');
12541 if (settings.exclusive) {
12542 module.hideOthers();
12543 } else {
12544 ignoreRepeatedEvents = false;
12545 }
12546 }
12547 module.set.dimmerStyles();
12548 module.set.observeAttributes(false);
12549 module.pushPage(function () {
12550 callback.call(element);
12551 settings.onVisible.call(element);
12552 if (settings.keyboardShortcuts) {
12553 module.add.keyboardShortcuts();
12554 }
12555 module.save.focus();
12556 module.refreshInputs();
12557 requestAnimationFrame(module.set.observeAttributes);
12558 });
12559 settings.onChange.call(element);
12560 } else {
12561 module.debug('Flyout is already visible');
12562 }
12563 },
12564
12565 hide: function (callback) {
12566 callback = isFunction(callback)
12567 ? callback
12568 : function () {};
12569 if (settings.onHide.call(element, $(this)) === false) {
12570 module.verbose('Hide callback returned false cancelling hide');
12571 ignoreRepeatedEvents = false;
12572
12573 return false;
12574 }
12575 if (module.is.visible() || module.is.animating()) {
12576 module.debug('Hiding flyout', callback);
12577 module.refreshFlyouts();
12578 module.set.observeAttributes(false);
12579 module.pullPage(function () {
12580 callback.call(element);
12581 if (isFunction(settings.onHidden)) {
12582 settings.onHidden.call(element);
12583 }
12584 module.restore.focus();
12585 });
12586 settings.onChange.call(element);
12587 }
12588 },
12589
12590 othersAnimating: function () {
12591 return $flyouts.not($module).filter('.' + className.animating).length > 0;
12592 },
12593 othersVisible: function () {
12594 return $flyouts.not($module).filter('.' + className.visible).length > 0;
12595 },
12596 othersActive: function () {
12597 return module.othersVisible() || module.othersAnimating();
12598 },
12599
12600 hideOthers: function (callback) {
12601 var
12602 $otherFlyouts = $flyouts.not($module).filter('.' + className.visible),
12603 flyoutCount = $otherFlyouts.length,
12604 callbackCount = 0
12605 ;
12606 callback = callback || function () {};
12607 $otherFlyouts
12608 .flyout('hide', function () {
12609 callbackCount++;
12610 if (callbackCount === flyoutCount) {
12611 callback();
12612 }
12613 })
12614 ;
12615 },
12616
12617 toggle: function () {
12618 module.verbose('Determining toggled direction');
12619 if (module.is.hidden()) {
12620 module.show();
12621 } else {
12622 module.hide();
12623 }
12624 },
12625
12626 pushPage: function (callback) {
12627 var
12628 animate,
12629 dim,
12630 transitionEnd
12631 ;
12632 callback = isFunction(callback)
12633 ? callback
12634 : function () {};
12635 module.set.overlay();
12636 if (settings.returnScroll) {
12637 currentScroll = (isBody ? $window : $context).scrollTop();
12638 }
12639 module.bind.scrollLock();
12640 animate = function () {
12641 module.bind.clickaway();
12642 module.add.inlineCSS();
12643 module.set.animating();
12644 module.set.visible();
12645 };
12646 dim = function () {
12647 module.set.dimmed();
12648 };
12649 transitionEnd = function (event) {
12650 if (event.target === $module[0]) {
12651 $module.off('transitionend' + elementNamespace, transitionEnd);
12652 module.remove.animating();
12653 callback.call(element);
12654 }
12655 };
12656 $module.off('transitionend' + elementNamespace);
12657 $module.on('transitionend' + elementNamespace, transitionEnd);
12658 requestAnimationFrame(animate);
12659 if (settings.dimPage && !module.othersVisible()) {
12660 requestAnimationFrame(dim);
12661 }
12662 },
12663
12664 pullPage: function (callback) {
12665 var
12666 animate,
12667 transitionEnd
12668 ;
12669 callback = isFunction(callback)
12670 ? callback
12671 : function () {};
12672 module.verbose('Removing context push state', module.get.direction());
12673
12674 module.unbind.clickaway();
12675 if (!module.othersActive()) {
12676 module.unbind.scrollLock();
12677 if (settings.keyboardShortcuts) {
12678 module.remove.keyboardShortcuts();
12679 }
12680 }
12681
12682 animate = function () {
12683 module.set.overlay();
12684 module.set.animating();
12685 if (settings.dimPage && !module.othersVisible()) {
12686 module.set.closing();
12687 }
12688 module.remove.visible();
12689 };
12690 transitionEnd = function (event) {
12691 if (event.target === $module[0]) {
12692 $module.off('transitionend' + elementNamespace, transitionEnd);
12693 module.remove.animating();
12694 module.remove.closing();
12695 module.remove.overlay();
12696 module.remove.inlineCSS();
12697 if (settings.returnScroll) {
12698 module.scrollBack();
12699 }
12700 if (settings.dimPage && !module.othersVisible()) {
12701 $pusher.removeClass(className.dimmed);
12702 }
12703 callback.call(element);
12704 }
12705 };
12706 $module.off('transitionend' + elementNamespace);
12707 $module.on('transitionend' + elementNamespace, transitionEnd);
12708 requestAnimationFrame(animate);
12709 },
12710
12711 scrollToTop: function () {
12712 module.verbose('Scrolling to top of page to avoid animation issues');
12713 $module.scrollTop(0);
12714 (isBody ? $window : $context)[0].scrollTo(0, 0);
12715 },
12716
12717 scrollBack: function () {
12718 module.verbose('Scrolling back to original page position');
12719 (isBody ? $window : $context)[0].scrollTo(0, currentScroll);
12720 },
12721
12722 clear: {
12723 cache: function () {
12724 module.verbose('Clearing cached dimensions');
12725 module.cache = {};
12726 },
12727 },
12728
12729 set: {
12730 observeAttributes: function (state) {
12731 observeAttributes = state !== false;
12732 },
12733 autofocus: function () {
12734 var
12735 $autofocus = $inputs.filter('[autofocus]'),
12736 $rawInputs = $inputs.filter(':input'),
12737 $input = ($autofocus.length > 0
12738 ? $autofocus
12739 : ($rawInputs.length > 0
12740 ? $rawInputs
12741 : $module)
12742 ).first()
12743 ;
12744 $input.trigger('focus');
12745 },
12746 dimmerStyles: function () {
12747 if (settings.blurring) {
12748 $pusher.addClass(className.blurring);
12749 } else {
12750 $pusher.removeClass(className.blurring);
12751 }
12752 },
12753 bodyMargin: function () {
12754 var position = module.can.leftBodyScrollbar() ? 'left' : 'right';
12755 $context.css((isBody ? 'margin-' : 'padding-') + position, tempBodyMargin + 'px');
12756 $context.find(selector.bodyFixed.replace('right', position)).each(function () {
12757 var
12758 el = $(this),
12759 attribute = el.css('position') === 'fixed' ? 'padding-' + position : position
12760 ;
12761 el.css(attribute, 'calc(' + el.css(attribute) + ' + ' + tempBodyMargin + 'px)');
12762 });
12763 },
12764
12765 // container
12766 pushed: function () {
12767 $context.addClass(className.pushed);
12768 },
12769 pushable: function () {
12770 $context.addClass(className.pushable);
12771 },
12772
12773 // pusher
12774 dimmed: function () {
12775 $pusher.addClass(className.dimmed);
12776 },
12777
12778 // flyout
12779 active: function () {
12780 $module.addClass(className.active);
12781 },
12782 animating: function () {
12783 $module.addClass(className.animating);
12784 },
12785 closing: function () {
12786 $pusher.addClass(className.closing);
12787 },
12788 direction: function (direction) {
12789 direction = direction || module.get.direction();
12790 $module.addClass(className[direction]);
12791 },
12792 visible: function () {
12793 $module.addClass(className.visible);
12794 },
12795 overlay: function () {
12796 $module.addClass(className.overlay);
12797 },
12798 },
12799 remove: {
12800
12801 inlineCSS: function () {
12802 module.debug('Removing inline css styles', $style);
12803 if ($style && $style.length > 0) {
12804 $style.remove();
12805 }
12806 },
12807 keyboardShortcuts: function () {
12808 module.verbose('Removing keyboard shortcuts');
12809 $document
12810 .off('keydown' + eventNamespace)
12811 ;
12812 },
12813
12814 // context
12815 pushed: function () {
12816 $context.removeClass(className.pushed);
12817 },
12818 pushable: function () {
12819 $context.removeClass(className.pushable);
12820 },
12821
12822 // flyout
12823 active: function () {
12824 $module.removeClass(className.active);
12825 },
12826 animating: function () {
12827 $module.removeClass(className.animating);
12828 },
12829 closing: function () {
12830 $pusher.removeClass(className.closing);
12831 },
12832 direction: function (direction) {
12833 direction = direction || module.get.direction();
12834 $module.removeClass(className[direction]);
12835 },
12836 visible: function () {
12837 $module.removeClass(className.visible);
12838 },
12839 overlay: function () {
12840 $module.removeClass(className.overlay);
12841 },
12842 },
12843
12844 get: {
12845 direction: function () {
12846 if ($module.hasClass(className.top)) {
12847 return className.top;
12848 }
12849 if ($module.hasClass(className.right)) {
12850 return className.right;
12851 }
12852 if ($module.hasClass(className.bottom)) {
12853 return className.bottom;
12854 }
12855
12856 return className.left;
12857 },
12858 id: function () {
12859 return id;
12860 },
12861 element: function () {
12862 return $module;
12863 },
12864 settings: function () {
12865 return settings;
12866 },
12867 },
12868
12869 can: {
12870 leftBodyScrollbar: function () {
12871 if (module.cache.leftBodyScrollbar === undefined) {
12872 module.cache.leftBodyScrollbar = module.is.rtl() && ((module.is.iframe && !module.is.firefox()) || module.is.safari() || module.is.edge() || module.is.ie());
12873 }
12874
12875 return module.cache.leftBodyScrollbar;
12876 },
12877 },
12878
12879 save: {
12880 focus: function () {
12881 var
12882 $activeElement = $(document.activeElement),
12883 inCurrentFlyout = $activeElement.closest($module).length > 0
12884 ;
12885 if (!inCurrentFlyout) {
12886 $focusedElement = $(document.activeElement).trigger('blur');
12887 }
12888 },
12889 bodyMargin: function () {
12890 initialBodyMargin = $context.css((isBody ? 'margin-' : 'padding-') + (module.can.leftBodyScrollbar() ? 'left' : 'right'));
12891 var
12892 bodyMarginRightPixel = parseInt(initialBodyMargin.replace(/[^\d.]/g, ''), 10),
12893 bodyScrollbarWidth = isBody ? window.innerWidth - document.documentElement.clientWidth : $context[0].offsetWidth - $context[0].clientWidth
12894 ;
12895 tempBodyMargin = bodyMarginRightPixel + bodyScrollbarWidth;
12896 },
12897 },
12898
12899 is: {
12900 safari: function () {
12901 if (module.cache.isSafari === undefined) {
12902 module.cache.isSafari = /constructor/i.test(window.HTMLElement) || !!window.ApplePaySession;
12903 }
12904
12905 return module.cache.isSafari;
12906 },
12907 edge: function () {
12908 if (module.cache.isEdge === undefined) {
12909 module.cache.isEdge = !!window.setImmediate && !module.is.ie();
12910 }
12911
12912 return module.cache.isEdge;
12913 },
12914 firefox: function () {
12915 if (module.cache.isFirefox === undefined) {
12916 module.cache.isFirefox = !!window.InstallTrigger;
12917 }
12918
12919 return module.cache.isFirefox;
12920 },
12921 iframe: function () {
12922 return !(self === top);
12923 },
12924 ie: function () {
12925 if (module.cache.isIE === undefined) {
12926 var
12927 isIE11 = !window.ActiveXObject && 'ActiveXObject' in window,
12928 isIE = 'ActiveXObject' in window
12929 ;
12930 module.cache.isIE = isIE11 || isIE;
12931 }
12932
12933 return module.cache.isIE;
12934 },
12935 mobile: function () {
12936 var
12937 userAgent = navigator.userAgent,
12938 isMobile = userAgent.match(regExp.mobile)
12939 ;
12940 if (isMobile) {
12941 module.verbose('Browser was found to be mobile', userAgent);
12942
12943 return true;
12944 }
12945
12946 module.verbose('Browser is not mobile, using regular transition', userAgent);
12947
12948 return false;
12949 },
12950 hidden: function () {
12951 return !module.is.visible();
12952 },
12953 visible: function () {
12954 return $module.hasClass(className.visible);
12955 },
12956 animating: function () {
12957 return $context.hasClass(className.animating);
12958 },
12959 rtl: function () {
12960 if (module.cache.isRTL === undefined) {
12961 module.cache.isRTL = $module.attr('dir') === 'rtl' || $module.css('direction') === 'rtl' || $body.attr('dir') === 'rtl' || $body.css('direction') === 'rtl' || $context.attr('dir') === 'rtl' || $context.css('direction') === 'rtl';
12962 }
12963
12964 return module.cache.isRTL;
12965 },
12966 },
12967
12968 has: {
12969 configActions: function () {
12970 return Array.isArray(settings.actions) && settings.actions.length > 0;
12971 },
12972 scrollbar: function () {
12973 return isBody || $context.css('overflow-y') !== 'hidden';
12974 },
12975 },
12976
12977 restore: {
12978 focus: function () {
12979 if ($focusedElement && $focusedElement.length > 0 && settings.restoreFocus) {
12980 $focusedElement.trigger('focus');
12981 }
12982 },
12983 bodyMargin: function () {
12984 var position = module.can.leftBodyScrollbar() ? 'left' : 'right';
12985 $context.css((isBody ? 'margin-' : 'padding-') + position, initialBodyMargin);
12986 $context.find(selector.bodyFixed.replace('right', position)).each(function () {
12987 var
12988 el = $(this),
12989 attribute = el.css('position') === 'fixed' ? 'padding-' + position : position
12990 ;
12991 el.css(attribute, '');
12992 });
12993 },
12994 },
12995
12996 helpers: {
12997 deQuote: function (string) {
12998 return String(string).replace(/"/g, '');
12999 },
13000 escape: function (string, preserveHTML) {
13001 if (preserveHTML) {
13002 return string;
13003 }
13004 var
13005 badChars = /["'<>`]/g,
13006 shouldEscape = /["&'<>`]/,
13007 escape = {
13008 '<': '&lt;',
13009 '>': '&gt;',
13010 '"': '&quot;',
13011 "'": '&#x27;',
13012 '`': '&#x60;',
13013 },
13014 escapedChar = function (chr) {
13015 return escape[chr];
13016 }
13017 ;
13018 if (shouldEscape.test(string)) {
13019 string = string.replace(/&(?![\d#a-z]{1,12};)/gi, '&amp;');
13020
13021 return string.replace(badChars, escapedChar);
13022 }
13023
13024 return string;
13025 },
13026 },
13027
13028 setting: function (name, value) {
13029 module.debug('Changing setting', name, value);
13030 if ($.isPlainObject(name)) {
13031 $.extend(true, settings, name);
13032 } else if (value !== undefined) {
13033 if ($.isPlainObject(settings[name])) {
13034 $.extend(true, settings[name], value);
13035 } else {
13036 settings[name] = value;
13037 }
13038 } else {
13039 return settings[name];
13040 }
13041 },
13042 internal: function (name, value) {
13043 if ($.isPlainObject(name)) {
13044 $.extend(true, module, name);
13045 } else if (value !== undefined) {
13046 module[name] = value;
13047 } else {
13048 return module[name];
13049 }
13050 },
13051 debug: function () {
13052 if (!settings.silent && settings.debug) {
13053 if (settings.performance) {
13054 module.performance.log(arguments);
13055 } else {
13056 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
13057 module.debug.apply(console, arguments);
13058 }
13059 }
13060 },
13061 verbose: function () {
13062 if (!settings.silent && settings.verbose && settings.debug) {
13063 if (settings.performance) {
13064 module.performance.log(arguments);
13065 } else {
13066 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
13067 module.verbose.apply(console, arguments);
13068 }
13069 }
13070 },
13071 error: function () {
13072 if (!settings.silent) {
13073 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
13074 module.error.apply(console, arguments);
13075 }
13076 },
13077 performance: {
13078 log: function (message) {
13079 var
13080 currentTime,
13081 executionTime,
13082 previousTime
13083 ;
13084 if (settings.performance) {
13085 currentTime = Date.now();
13086 previousTime = time || currentTime;
13087 executionTime = currentTime - previousTime;
13088 time = currentTime;
13089 performance.push({
13090 Name: message[0],
13091 Arguments: [].slice.call(message, 1) || '',
13092 Element: element,
13093 'Execution Time': executionTime,
13094 });
13095 }
13096 clearTimeout(module.performance.timer);
13097 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
13098 },
13099 display: function () {
13100 var
13101 title = settings.name + ':',
13102 totalTime = 0
13103 ;
13104 time = false;
13105 clearTimeout(module.performance.timer);
13106 $.each(performance, function (index, data) {
13107 totalTime += data['Execution Time'];
13108 });
13109 title += ' ' + totalTime + 'ms';
13110 if (performance.length > 0) {
13111 console.groupCollapsed(title);
13112 if (console.table) {
13113 console.table(performance);
13114 } else {
13115 $.each(performance, function (index, data) {
13116 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
13117 });
13118 }
13119 console.groupEnd();
13120 }
13121 performance = [];
13122 },
13123 },
13124 invoke: function (query, passedArguments, context) {
13125 var
13126 object = instance,
13127 maxDepth,
13128 found,
13129 response
13130 ;
13131 passedArguments = passedArguments || queryArguments;
13132 context = element || context;
13133 if (typeof query === 'string' && object !== undefined) {
13134 query = query.split(/[ .]/);
13135 maxDepth = query.length - 1;
13136 $.each(query, function (depth, value) {
13137 var camelCaseValue = depth !== maxDepth
13138 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
13139 : query
13140 ;
13141 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
13142 object = object[camelCaseValue];
13143 } else if (object[camelCaseValue] !== undefined) {
13144 found = object[camelCaseValue];
13145
13146 return false;
13147 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
13148 object = object[value];
13149 } else if (object[value] !== undefined) {
13150 found = object[value];
13151
13152 return false;
13153 } else {
13154 module.error(error.method, query);
13155
13156 return false;
13157 }
13158 });
13159 }
13160 if (isFunction(found)) {
13161 response = found.apply(context, passedArguments);
13162 } else if (found !== undefined) {
13163 response = found;
13164 }
13165 if (Array.isArray(returnedValue)) {
13166 returnedValue.push(response);
13167 } else if (returnedValue !== undefined) {
13168 returnedValue = [returnedValue, response];
13169 } else if (response !== undefined) {
13170 returnedValue = response;
13171 }
13172
13173 return found;
13174 },
13175 };
13176
13177 if (methodInvoked) {
13178 if (instance === undefined) {
13179 if (isFunction(settings.templates[query])) {
13180 settings.autoShow = true;
13181 settings.className.flyout = settings.className.template;
13182 settings = $.extend(true, {}, settings, settings.templates[query].apply(module, queryArguments));
13183
13184 // reassign shortcuts
13185 className = settings.className;
13186 namespace = settings.namespace;
13187 fields = settings.fields;
13188 error = settings.error;
13189 }
13190 module.initialize();
13191 }
13192 if (!isFunction(settings.templates[query])) {
13193 module.invoke(query);
13194 }
13195 } else {
13196 if (instance !== undefined) {
13197 instance.invoke('destroy');
13198 }
13199 module.initialize();
13200 returnedValue = $module;
13201 }
13202 });
13203
13204 return returnedValue !== undefined
13205 ? returnedValue
13206 : this;
13207 };
13208 $.flyout = $.fn.flyout;
13209
13210 $.fn.flyout.settings = {
13211
13212 name: 'Flyout',
13213 namespace: 'flyout',
13214
13215 silent: false,
13216 debug: false,
13217 verbose: false,
13218 performance: true,
13219
13220 context: 'body',
13221 exclusive: false,
13222 closable: true,
13223 autofocus: true,
13224 restoreFocus: true,
13225 dimPage: true,
13226 scrollLock: false,
13227 returnScroll: false,
13228 delaySetup: false,
13229 autoShow: false,
13230
13231 keyboardShortcuts: true,
13232
13233 // dynamic content
13234 title: '',
13235 content: '',
13236 class: '',
13237 classTitle: '',
13238 classContent: '',
13239 classActions: '',
13240 closeIcon: false,
13241 actions: false,
13242 preserveHTML: true,
13243
13244 fields: {
13245 class: 'class',
13246 text: 'text',
13247 icon: 'icon',
13248 click: 'click',
13249 },
13250
13251 onChange: function () {},
13252 onShow: function () {},
13253 onHide: function () {
13254 return true;
13255 },
13256
13257 onHidden: false,
13258 onVisible: function () {},
13259
13260 onApprove: function () {},
13261 onDeny: function () {},
13262
13263 keys: {
13264 space: 32,
13265 enter: 13,
13266 escape: 27,
13267 tab: 9,
13268 },
13269
13270 className: {
13271 flyout: 'ui flyout',
13272 close: 'close icon',
13273 header: 'ui header',
13274 content: 'content',
13275 actions: 'actions',
13276 active: 'active',
13277 animating: 'animating',
13278 blurring: 'blurring',
13279 closing: 'closing',
13280 dimmed: 'dimmed',
13281 locked: 'locked',
13282 pushable: 'pushable',
13283 pushed: 'pushed',
13284 right: 'right',
13285 top: 'top',
13286 left: 'left',
13287 bottom: 'bottom',
13288 visible: 'visible',
13289 overlay: 'overlay',
13290 fullscreen: 'fullscreen',
13291 template: 'ui flyout',
13292 button: 'ui button',
13293 ok: 'positive',
13294 cancel: 'negative',
13295 prompt: 'ui fluid input',
13296 },
13297
13298 selector: {
13299 bodyFixed: '> .ui.fixed.menu, > .ui.right.toast-container, > .ui.right.sidebar, > .ui.right.flyout, > .ui.fixed.nag, > .ui.fixed.nag > .close',
13300 fixed: '.fixed',
13301 omitted: 'script, link, style, .ui.modal, .ui.dimmer, .ui.nag, .ui.fixed',
13302 pusher: '.pusher',
13303 flyout: '.ui.flyout',
13304 header: '.ui.header',
13305 content: '.content',
13306 actions: '.actions',
13307 close: '.close',
13308 approve: '.actions .positive, .actions .approve, .actions .ok',
13309 deny: '.actions .negative, .actions .deny, .actions .cancel',
13310 },
13311
13312 regExp: {
13313 mobile: /Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune/g,
13314 },
13315
13316 error: {
13317 method: 'The method you called is not defined.',
13318 pusher: 'Had to add pusher element. For optimal performance make sure body content is inside a pusher element',
13319 movedFlyout: 'Had to move flyout. For optimal performance make sure flyout and pusher are direct children of your body tag',
13320 notFound: 'There were no elements that matched the specified selector',
13321 },
13322
13323 text: {
13324 ok: 'Ok',
13325 cancel: 'Cancel',
13326 close: 'Close',
13327 },
13328 };
13329
13330 $.fn.flyout.settings.templates = {
13331 getArguments: function (args) {
13332 var queryArguments = [].slice.call(args);
13333 if ($.isPlainObject(queryArguments[0])) {
13334 return $.extend({
13335 handler: function () {},
13336 content: '',
13337 title: '',
13338 }, queryArguments[0]);
13339 }
13340 if (!isFunction(queryArguments[queryArguments.length - 1])) {
13341 queryArguments.push(function () {});
13342 }
13343
13344 return {
13345 handler: queryArguments.pop(),
13346 content: queryArguments.pop() || '',
13347 title: queryArguments.pop() || '',
13348 };
13349 },
13350 alert: function () {
13351 var
13352 settings = this.get.settings(),
13353 args = settings.templates.getArguments(arguments)
13354 ;
13355
13356 return {
13357 title: args.title,
13358 content: args.content,
13359 actions: [{
13360 text: settings.text.ok,
13361 class: settings.className.ok,
13362 click: args.handler,
13363 }],
13364 };
13365 },
13366 confirm: function () {
13367 var
13368 settings = this.get.settings(),
13369 args = settings.templates.getArguments(arguments)
13370 ;
13371
13372 return {
13373 title: args.title,
13374 content: args.content,
13375 actions: [{
13376 text: settings.text.ok,
13377 class: settings.className.ok,
13378 click: function () {
13379 args.handler(true);
13380 },
13381 }, {
13382 text: settings.text.cancel,
13383 class: settings.className.cancel,
13384 click: function () {
13385 args.handler(false);
13386 },
13387 }],
13388 };
13389 },
13390 prompt: function () {
13391 var
13392 $this = this,
13393 settings = this.get.settings(),
13394 args = settings.templates.getArguments(arguments),
13395 input = $($.parseHTML(args.content)).filter('.ui.input')
13396 ;
13397 if (input.length === 0) {
13398 args.content += '<p><div class="' + settings.className.prompt + '"><input placeholder="' + this.helpers.deQuote(args.placeholder || '') + '" type="text" value="' + this.helpers.deQuote(args.defaultValue || '') + '"></div></p>';
13399 }
13400
13401 return {
13402 title: args.title,
13403 content: args.content,
13404 actions: [{
13405 text: settings.text.ok,
13406 class: settings.className.ok,
13407 click: function () {
13408 var
13409 settings = $this.get.settings(),
13410 inputField = $this.get.element().find(settings.selector.prompt)[0]
13411 ;
13412 args.handler($(inputField).val());
13413 },
13414 }, {
13415 text: settings.text.cancel,
13416 class: settings.className.cancel,
13417 click: function () {
13418 args.handler(null);
13419 },
13420 }],
13421 };
13422 },
13423 };
13424})(jQuery, window, document);
13425
13426/*!
13427 * # Fomantic-UI 2.9.3 - Modal
13428 * https://github.com/fomantic/Fomantic-UI/
13429 *
13430 *
13431 * Released under the MIT license
13432 * https://opensource.org/licenses/MIT
13433 *
13434 */
13435
13436(function ($, window, document) {
13437 'use strict';
13438
13439 function isFunction(obj) {
13440 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
13441 }
13442
13443 window = window !== undefined && window.Math === Math
13444 ? window
13445 : globalThis;
13446
13447 $.fn.modal = function (parameters) {
13448 var
13449 $allModules = $(this),
13450 $window = $(window),
13451 $document = $(document),
13452 $body = $('body'),
13453
13454 time = Date.now(),
13455 performance = [],
13456
13457 query = arguments[0],
13458 methodInvoked = typeof query === 'string',
13459 queryArguments = [].slice.call(arguments, 1),
13460 contextCheck = function (context, win) {
13461 var $context;
13462 if ([window, document].indexOf(context) >= 0) {
13463 $context = $body;
13464 } else {
13465 $context = $(win.document).find(context);
13466 if ($context.length === 0) {
13467 $context = win.frameElement ? contextCheck(context, win.parent) : $body;
13468 }
13469 }
13470
13471 return $context;
13472 },
13473 returnedValue
13474 ;
13475
13476 $allModules.each(function () {
13477 var
13478 settings = $.isPlainObject(parameters)
13479 ? $.extend(true, {}, $.fn.modal.settings, parameters)
13480 : $.extend({}, $.fn.modal.settings),
13481
13482 selector = settings.selector,
13483 className = settings.className,
13484 namespace = settings.namespace,
13485 fields = settings.fields,
13486 error = settings.error,
13487
13488 eventNamespace = '.' + namespace,
13489 moduleNamespace = 'module-' + namespace,
13490
13491 $module = $(this),
13492 $context = contextCheck(settings.context, window),
13493 isBody = $context[0] === $body[0],
13494 $closeIcon = $module.find(selector.closeIcon),
13495 $inputs,
13496
13497 $allModals,
13498 $otherModals,
13499 $focusedElement,
13500 $dimmable,
13501 $dimmer,
13502
13503 isModalComponent = $module.hasClass('modal'),
13504
13505 element = this,
13506 instance = isModalComponent ? $module.data(moduleNamespace) : undefined,
13507
13508 ignoreRepeatedEvents = false,
13509
13510 initialMouseDownInModal,
13511 initialMouseDownInScrollbar,
13512 initialBodyMargin = '',
13513 tempBodyMargin = '',
13514 keepScrollingClass = false,
13515 hadScrollbar = false,
13516 windowRefocused = false,
13517
13518 elementEventNamespace,
13519 id,
13520 observer,
13521 observeAttributes = false,
13522 module
13523 ;
13524 module = {
13525
13526 initialize: function () {
13527 module.create.id();
13528 if (!isModalComponent) {
13529 module.create.modal();
13530 if (!isFunction(settings.onHidden)) {
13531 settings.onHidden = function () {
13532 module.destroy();
13533 $module.remove();
13534 };
13535 }
13536 }
13537 $module.addClass(settings.class);
13538 if (settings.title !== '') {
13539 $module.find(selector.title).html(module.helpers.escape(settings.title, settings.preserveHTML)).addClass(settings.classTitle);
13540 }
13541 if (settings.content !== '') {
13542 $module.find(selector.content).html(module.helpers.escape(settings.content, settings.preserveHTML)).addClass(settings.classContent);
13543 }
13544 if (module.has.configActions()) {
13545 var $actions = $module.find(selector.actions).addClass(settings.classActions);
13546 if ($actions.length === 0) {
13547 $actions = $('<div/>', { class: className.actions + ' ' + (settings.classActions || '') }).appendTo($module);
13548 } else {
13549 $actions.empty();
13550 }
13551 settings.actions.forEach(function (el) {
13552 var
13553 icon = el[fields.icon]
13554 ? '<i ' + (el[fields.text] ? 'aria-hidden="true"' : '') + ' class="' + module.helpers.deQuote(el[fields.icon]) + ' icon"></i>'
13555 : '',
13556 text = module.helpers.escape(el[fields.text] || '', settings.preserveHTML),
13557 cls = module.helpers.deQuote(el[fields.class] || ''),
13558 click = el[fields.click] && isFunction(el[fields.click])
13559 ? el[fields.click]
13560 : function () {}
13561 ;
13562 $actions.append($('<button/>', {
13563 html: icon + text,
13564 'aria-label': (el[fields.text] || el[fields.icon] || '').replace(/<[^>]+(>|$)/g, ''),
13565 class: className.button + ' ' + cls,
13566 on: {
13567 click: function () {
13568 var button = $(this);
13569 if (button.is(selector.approve) || button.is(selector.deny) || click.call(element, $module) === false) {
13570 return;
13571 }
13572 module.hide();
13573 },
13574 },
13575 }));
13576 });
13577 }
13578 module.cache = {};
13579 module.verbose('Initializing dimmer', $context);
13580
13581 module.create.dimmer();
13582
13583 if (settings.allowMultiple) {
13584 module.create.innerDimmer();
13585 }
13586 if (!settings.centered) {
13587 $module.addClass('top aligned');
13588 }
13589 module.refreshModals();
13590 module.bind.events();
13591 module.observeChanges();
13592 module.instantiate();
13593 if (settings.autoShow) {
13594 module.show();
13595 }
13596 },
13597
13598 instantiate: function () {
13599 module.verbose('Storing instance of modal');
13600 instance = module;
13601 $module
13602 .data(moduleNamespace, instance)
13603 ;
13604 },
13605
13606 create: {
13607 modal: function () {
13608 $module = $('<div/>', { class: className.modal, role: 'dialog', 'aria-modal': true });
13609 if (settings.closeIcon) {
13610 $closeIcon = $('<i/>', {
13611 class: className.close,
13612 role: 'button',
13613 tabindex: 0,
13614 'aria-label': settings.text.close,
13615 });
13616 $module.append($closeIcon);
13617 }
13618 if (settings.title !== '') {
13619 var titleId = '_' + module.get.id() + 'title';
13620 $module.attr('aria-labelledby', titleId);
13621 $('<div/>', { class: className.title, id: titleId }).appendTo($module);
13622 }
13623 if (settings.content !== '') {
13624 var descId = '_' + module.get.id() + 'desc';
13625 $module.attr('aria-describedby', descId);
13626 $('<div/>', { class: className.content, id: descId }).appendTo($module);
13627 }
13628 if (module.has.configActions()) {
13629 $('<div/>', { class: className.actions }).appendTo($module);
13630 }
13631 $context.append($module);
13632 element = $module[0];
13633 },
13634 dimmer: function () {
13635 var
13636 defaultSettings = {
13637 debug: settings.debug,
13638 dimmerName: 'modals',
13639 },
13640 dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
13641 ;
13642 if ($.fn.dimmer === undefined) {
13643 module.error(error.dimmer);
13644
13645 return;
13646 }
13647 module.debug('Creating dimmer');
13648 $dimmable = $context.dimmer(dimmerSettings);
13649 keepScrollingClass = module.is.scrolling();
13650 if (settings.detachable) {
13651 module.verbose('Modal is detachable, moving content into dimmer');
13652 $dimmable.dimmer('add content', $module);
13653 } else {
13654 module.set.undetached();
13655 }
13656 $dimmer = $dimmable.dimmer('get dimmer');
13657 },
13658 id: function () {
13659 id = (Math.random().toString(16) + '000000000').slice(2, 10);
13660 elementEventNamespace = '.' + id;
13661 module.verbose('Creating unique id for element', id);
13662 },
13663 innerDimmer: function () {
13664 if ($module.find(selector.dimmer).length === 0) {
13665 $('<div/>', { class: className.innerDimmer }).prependTo($module);
13666 }
13667 },
13668 },
13669
13670 destroy: function () {
13671 if (observer) {
13672 observer.disconnect();
13673 }
13674 module.verbose('Destroying previous modal');
13675 $module
13676 .removeData(moduleNamespace)
13677 .off(eventNamespace)
13678 ;
13679 $window.off(elementEventNamespace);
13680 $context.off(elementEventNamespace);
13681 $dimmer.off(elementEventNamespace);
13682 $closeIcon.off(elementEventNamespace);
13683 if ($inputs) {
13684 $inputs.off(elementEventNamespace);
13685 }
13686 $context.dimmer('destroy');
13687 },
13688
13689 observeChanges: function () {
13690 if ('MutationObserver' in window) {
13691 observer = new MutationObserver(function (mutations) {
13692 var collectNodes = function (parent) {
13693 var nodes = [];
13694 for (var c = 0, cl = parent.length; c < cl; c++) {
13695 Array.prototype.push.apply(nodes, collectNodes(parent[c].childNodes));
13696 nodes.push(parent[c]);
13697 }
13698
13699 return nodes;
13700 },
13701 shouldRefresh = false,
13702 shouldRefreshInputs = false,
13703 ignoreAutofocus = true
13704 ;
13705 mutations.every(function (mutation) {
13706 if (mutation.type === 'attributes') {
13707 if (observeAttributes && (mutation.attributeName === 'disabled' || $(mutation.target).find(':input').addBack(':input').filter(':visible').length > 0)) {
13708 shouldRefreshInputs = true;
13709 }
13710 } else {
13711 shouldRefresh = true;
13712 // mutationobserver only provides the parent nodes
13713 // so let's collect all childs as well to find nested inputs
13714 var $addedInputs = $(collectNodes(mutation.addedNodes)).filter('a[href], [tabindex], :input:enabled').filter(':visible'),
13715 $removedInputs = $(collectNodes(mutation.removedNodes)).filter('a[href], [tabindex], :input');
13716 if ($addedInputs.length > 0 || $removedInputs.length > 0) {
13717 shouldRefreshInputs = true;
13718 if ($addedInputs.filter(':input').length > 0 || $removedInputs.filter(':input').length > 0) {
13719 ignoreAutofocus = false;
13720 }
13721 }
13722 }
13723
13724 return !shouldRefreshInputs;
13725 });
13726
13727 if (shouldRefresh && settings.observeChanges) {
13728 module.debug('DOM tree modified, refreshing');
13729 module.refresh();
13730 }
13731 if (shouldRefreshInputs) {
13732 module.refreshInputs(ignoreAutofocus);
13733 }
13734 });
13735 observer.observe(element, {
13736 attributeFilter: ['class', 'disabled'],
13737 attributes: true,
13738 childList: true,
13739 subtree: true,
13740 });
13741 module.debug('Setting up mutation observer', observer);
13742 }
13743 },
13744
13745 refresh: function () {
13746 module.remove.scrolling();
13747 module.cacheSizes();
13748 if (!module.can.useFlex()) {
13749 module.set.modalOffset();
13750 }
13751 module.set.screenHeight();
13752 module.set.type();
13753 },
13754
13755 refreshModals: function () {
13756 $otherModals = $module.siblings(selector.modal);
13757 $allModals = $otherModals.add($module);
13758 },
13759
13760 refreshInputs: function (ignoreAutofocus) {
13761 if ($inputs) {
13762 $inputs
13763 .off('keydown' + elementEventNamespace)
13764 ;
13765 }
13766 $inputs = $module.find('a[href], [tabindex], :input:enabled').filter(':visible').filter(function () {
13767 return $(this).closest('.disabled').length === 0;
13768 });
13769 if ($inputs.filter(':input').length === 0) {
13770 $inputs = $module.add($inputs);
13771 $module.attr('tabindex', -1);
13772 } else {
13773 $module.removeAttr('tabindex');
13774 }
13775 $inputs.first()
13776 .on('keydown' + elementEventNamespace, module.event.inputKeyDown.first)
13777 ;
13778 $inputs.last()
13779 .on('keydown' + elementEventNamespace, module.event.inputKeyDown.last)
13780 ;
13781 if (!ignoreAutofocus && settings.autofocus && $inputs.filter(':focus').length === 0) {
13782 module.set.autofocus();
13783 }
13784 },
13785
13786 attachEvents: function (selector, event) {
13787 var
13788 $toggle = $(selector)
13789 ;
13790 event = isFunction(module[event])
13791 ? module[event]
13792 : module.toggle;
13793 if ($toggle.length > 0) {
13794 module.debug('Attaching modal events to element', selector, event);
13795 $toggle
13796 .off(eventNamespace)
13797 .on('click' + eventNamespace, event)
13798 ;
13799 } else {
13800 module.error(error.notFound, selector);
13801 }
13802 },
13803
13804 bind: {
13805 events: function () {
13806 module.verbose('Attaching events');
13807 $module
13808 .on('click' + eventNamespace, selector.close, module.event.close)
13809 .on('click' + eventNamespace, selector.approve, module.event.approve)
13810 .on('click' + eventNamespace, selector.deny, module.event.deny)
13811 ;
13812 $closeIcon
13813 .on('keyup' + elementEventNamespace, module.event.closeKeyUp)
13814 ;
13815 $window
13816 .on('resize' + elementEventNamespace, module.event.resize)
13817 .on('focus' + elementEventNamespace, module.event.focus)
13818 ;
13819 $context
13820 .on('click' + elementEventNamespace, module.event.click)
13821 ;
13822 },
13823 scrollLock: function () {
13824 // touch events default to passive, due to changes in chrome to optimize mobile perf
13825 $dimmable[0].addEventListener('touchmove', module.event.preventScroll, { passive: false });
13826 },
13827 },
13828
13829 unbind: {
13830 scrollLock: function () {
13831 $dimmable[0].removeEventListener('touchmove', module.event.preventScroll, { passive: false });
13832 },
13833 },
13834
13835 get: {
13836 id: function () {
13837 return id;
13838 },
13839 element: function () {
13840 return $module;
13841 },
13842 settings: function () {
13843 return settings;
13844 },
13845 },
13846
13847 event: {
13848 approve: function () {
13849 if (ignoreRepeatedEvents || settings.onApprove.call(element, $(this)) === false) {
13850 module.verbose('Approve callback returned false cancelling hide');
13851
13852 return;
13853 }
13854 ignoreRepeatedEvents = true;
13855 module.hide(function () {
13856 ignoreRepeatedEvents = false;
13857 });
13858 },
13859 preventScroll: function (event) {
13860 if (event.target.className.indexOf('dimmer') !== -1) {
13861 event.preventDefault();
13862 }
13863 },
13864 deny: function () {
13865 if (ignoreRepeatedEvents || settings.onDeny.call(element, $(this)) === false) {
13866 module.verbose('Deny callback returned false cancelling hide');
13867
13868 return;
13869 }
13870 ignoreRepeatedEvents = true;
13871 module.hide(function () {
13872 ignoreRepeatedEvents = false;
13873 });
13874 },
13875 close: function () {
13876 module.hide();
13877 },
13878 closeKeyUp: function (event) {
13879 var
13880 keyCode = event.which
13881 ;
13882 if ((keyCode === settings.keys.enter || keyCode === settings.keys.space) && $module.hasClass(className.front)) {
13883 module.hide();
13884 }
13885 },
13886 inputKeyDown: {
13887 first: function (event) {
13888 var
13889 keyCode = event.which
13890 ;
13891 if (keyCode === settings.keys.tab && event.shiftKey) {
13892 $inputs.last().trigger('focus');
13893 event.preventDefault();
13894 }
13895 },
13896 last: function (event) {
13897 var
13898 keyCode = event.which
13899 ;
13900 if (keyCode === settings.keys.tab && !event.shiftKey) {
13901 $inputs.first().trigger('focus');
13902 event.preventDefault();
13903 }
13904 },
13905 },
13906 mousedown: function (event) {
13907 var
13908 $target = $(event.target),
13909 isRtl = module.is.rtl()
13910 ;
13911 initialMouseDownInModal = $target.closest(selector.modal).length > 0;
13912 if (initialMouseDownInModal) {
13913 module.verbose('Mouse down event registered inside the modal');
13914 }
13915 initialMouseDownInScrollbar = module.is.scrolling() && ((!isRtl && $window.outerWidth() - settings.scrollbarWidth <= event.clientX) || (isRtl && settings.scrollbarWidth >= event.clientX));
13916 if (initialMouseDownInScrollbar) {
13917 module.verbose('Mouse down event registered inside the scrollbar');
13918 }
13919 },
13920 mouseup: function (event) {
13921 if (!settings.closable) {
13922 module.verbose('Dimmer clicked but closable setting is disabled');
13923
13924 return;
13925 }
13926 if (initialMouseDownInModal) {
13927 module.debug('Dimmer clicked but mouse down was initially registered inside the modal');
13928
13929 return;
13930 }
13931 if (initialMouseDownInScrollbar) {
13932 module.debug('Dimmer clicked but mouse down was initially registered inside the scrollbar');
13933
13934 return;
13935 }
13936 var
13937 $target = $(event.target),
13938 isInModal = $target.closest(selector.modal).length > 0,
13939 isInDOM = $.contains(document.documentElement, event.target)
13940 ;
13941 if (!isInModal && isInDOM && module.is.active() && $module.hasClass(className.front)) {
13942 module.debug('Dimmer clicked, hiding all modals');
13943 if (settings.allowMultiple) {
13944 if (!module.hideAll()) {
13945 return;
13946 }
13947 } else if (!module.hide()) {
13948 return;
13949 }
13950 module.remove.clickaway();
13951 }
13952 },
13953 debounce: function (method, delay) {
13954 clearTimeout(module.timer);
13955 module.timer = setTimeout(function () { method(); }, delay);
13956 },
13957 keyboard: function (event) {
13958 var
13959 keyCode = event.which
13960 ;
13961 if (keyCode === settings.keys.escape) {
13962 if (settings.closable) {
13963 module.debug('Escape key pressed hiding modal');
13964 if ($module.hasClass(className.front)) {
13965 module.hide();
13966 }
13967 } else {
13968 module.debug('Escape key pressed, but closable is set to false');
13969 }
13970 event.preventDefault();
13971 }
13972 },
13973 resize: function () {
13974 if ($dimmable.dimmer('is active') && (module.is.animating() || module.is.active())) {
13975 requestAnimationFrame(module.refresh);
13976 }
13977 },
13978 focus: function () {
13979 windowRefocused = true;
13980 },
13981 click: function (event) {
13982 if (windowRefocused && document.activeElement !== event.target && $dimmable.dimmer('is active') && module.is.active() && settings.autofocus && $(document.activeElement).closest(selector.modal).length === 0) {
13983 requestAnimationFrame(module.set.autofocus);
13984 }
13985 windowRefocused = false;
13986 },
13987 },
13988
13989 toggle: function () {
13990 if (module.is.active() || module.is.animating()) {
13991 module.hide();
13992 } else {
13993 module.show();
13994 }
13995 },
13996
13997 show: function (callback) {
13998 callback = isFunction(callback)
13999 ? callback
14000 : function () {};
14001 module.refreshModals();
14002 module.set.dimmerSettings();
14003 module.set.dimmerStyles();
14004
14005 module.showModal(callback);
14006 },
14007
14008 hide: function (callback) {
14009 callback = isFunction(callback)
14010 ? callback
14011 : function () {};
14012 module.refreshModals();
14013
14014 return module.hideModal(callback);
14015 },
14016
14017 showModal: function (callback) {
14018 callback = isFunction(callback)
14019 ? callback
14020 : function () {};
14021 if (module.is.animating() || !module.is.active()) {
14022 if (settings.onShow.call(element) === false) {
14023 module.verbose('Show callback returned false cancelling show');
14024
14025 return;
14026 }
14027 hadScrollbar = module.has.scrollbar();
14028 module.showDimmer();
14029 module.cacheSizes();
14030 if (hadScrollbar) {
14031 module.set.bodyMargin();
14032 }
14033 if (module.can.useFlex()) {
14034 module.remove.legacy();
14035 } else {
14036 module.set.legacy();
14037 module.set.modalOffset();
14038 module.debug('Using non-flex legacy modal positioning.');
14039 }
14040 module.set.screenHeight();
14041 module.set.type();
14042 module.set.clickaway();
14043
14044 if (!settings.allowMultiple && module.others.active()) {
14045 module.hideOthers(module.showModal);
14046 } else {
14047 ignoreRepeatedEvents = false;
14048 if (settings.allowMultiple) {
14049 if (module.others.active()) {
14050 $otherModals.filter('.' + className.active).find(selector.dimmer).removeClass('out').addClass('transition fade in active');
14051 }
14052
14053 if (settings.detachable) {
14054 $module.detach().appendTo($dimmer);
14055 }
14056 }
14057 if (settings.transition && $.fn.transition !== undefined) {
14058 module.debug('Showing modal with css animations');
14059 module.set.observeAttributes(false);
14060 $module
14061 .transition({
14062 debug: settings.debug,
14063 verbose: settings.verbose,
14064 silent: settings.silent,
14065 animation: (settings.transition.showMethod || settings.transition) + ' in',
14066 queue: settings.queue,
14067 duration: settings.transition.showDuration || settings.duration,
14068 useFailSafe: true,
14069 onComplete: function () {
14070 settings.onVisible.apply(element);
14071 if (settings.keyboardShortcuts) {
14072 module.add.keyboardShortcuts();
14073 }
14074 module.save.focus();
14075 module.set.active();
14076 module.refreshInputs();
14077 requestAnimationFrame(module.set.observeAttributes);
14078 callback();
14079 },
14080 })
14081 ;
14082 } else {
14083 module.error(error.noTransition);
14084 }
14085 }
14086 } else {
14087 module.debug('Modal is already visible');
14088 }
14089 },
14090
14091 hideModal: function (callback, keepDimmed, hideOthersToo) {
14092 var
14093 $previousModal = $otherModals.filter('.' + className.active).last()
14094 ;
14095 callback = isFunction(callback)
14096 ? callback
14097 : function () {};
14098 if (settings.onHide.call(element, $(this)) === false) {
14099 module.verbose('Hide callback returned false cancelling hide');
14100 ignoreRepeatedEvents = false;
14101
14102 return false;
14103 }
14104
14105 if (module.is.animating() || module.is.active()) {
14106 module.debug('Hiding modal');
14107 if (settings.transition && $.fn.transition !== undefined) {
14108 module.remove.active();
14109 module.set.observeAttributes(false);
14110 $module
14111 .transition({
14112 debug: settings.debug,
14113 verbose: settings.verbose,
14114 silent: settings.silent,
14115 animation: (settings.transition.hideMethod || settings.transition) + ' out',
14116 queue: settings.queue,
14117 duration: settings.transition.hideDuration || settings.duration,
14118 useFailSafe: true,
14119 onStart: function () {
14120 if (!module.others.active() && !module.others.animating() && !keepDimmed) {
14121 module.hideDimmer();
14122 } else if (settings.allowMultiple) {
14123 (hideOthersToo ? $allModals : $previousModal).find(selector.dimmer).removeClass('in').addClass('out');
14124 }
14125 if (settings.keyboardShortcuts && !module.others.active()) {
14126 module.remove.keyboardShortcuts();
14127 }
14128 },
14129 onComplete: function () {
14130 module.unbind.scrollLock();
14131 module.remove.active();
14132 if (settings.allowMultiple) {
14133 $previousModal.addClass(className.front);
14134 $module.removeClass(className.front);
14135
14136 (hideOthersToo ? $allModals : $previousModal).find(selector.dimmer).removeClass('active');
14137 }
14138 if (isFunction(settings.onHidden)) {
14139 settings.onHidden.call(element);
14140 }
14141 module.remove.dimmerStyles();
14142 module.restore.focus();
14143 callback();
14144 },
14145 })
14146 ;
14147 } else {
14148 module.error(error.noTransition);
14149 }
14150 }
14151 },
14152
14153 showDimmer: function () {
14154 if ($dimmable.dimmer('is animating') || !$dimmable.dimmer('is active')) {
14155 if (hadScrollbar) {
14156 if (!isBody) {
14157 $dimmer.css('top', $dimmable.scrollTop());
14158 }
14159 module.save.bodyMargin();
14160 }
14161 module.debug('Showing dimmer');
14162 $dimmable.dimmer('show');
14163 } else {
14164 module.debug('Dimmer already visible');
14165 }
14166 },
14167
14168 hideDimmer: function () {
14169 if ($dimmable.dimmer('is animating') || $dimmable.dimmer('is active')) {
14170 module.unbind.scrollLock();
14171 $dimmable.dimmer('hide', function () {
14172 if (hadScrollbar) {
14173 module.restore.bodyMargin();
14174 }
14175 module.remove.clickaway();
14176 module.remove.screenHeight();
14177 });
14178 } else {
14179 module.debug('Dimmer is not visible cannot hide');
14180 }
14181 },
14182
14183 hideAll: function (callback) {
14184 var
14185 $visibleModals = $allModals.filter('.' + className.active + ', .' + className.animating)
14186 ;
14187 callback = isFunction(callback)
14188 ? callback
14189 : function () {};
14190 if ($visibleModals.length > 0) {
14191 module.debug('Hiding all visible modals');
14192 var hideOk = true;
14193 // check in reverse order trying to hide most top displayed modal first
14194 $($visibleModals.get().reverse()).each(function (index, element) {
14195 if (hideOk) {
14196 hideOk = $(element).modal('hide modal', callback, false, true);
14197 }
14198 });
14199 if (hideOk) {
14200 module.hideDimmer();
14201 }
14202
14203 return hideOk;
14204 }
14205 },
14206
14207 hideOthers: function (callback) {
14208 var
14209 $visibleModals = $otherModals.filter('.' + className.active + ', .' + className.animating)
14210 ;
14211 callback = isFunction(callback)
14212 ? callback
14213 : function () {};
14214 if ($visibleModals.length > 0) {
14215 module.debug('Hiding other modals', $otherModals);
14216 $visibleModals
14217 .modal('hide modal', callback, true)
14218 ;
14219 }
14220 },
14221
14222 others: {
14223 active: function () {
14224 return $otherModals.filter('.' + className.active).length > 0;
14225 },
14226 animating: function () {
14227 return $otherModals.filter('.' + className.animating).length > 0;
14228 },
14229 },
14230
14231 add: {
14232 keyboardShortcuts: function () {
14233 module.verbose('Adding keyboard shortcuts');
14234 $document
14235 .on('keydown' + eventNamespace, module.event.keyboard)
14236 ;
14237 },
14238 },
14239
14240 save: {
14241 focus: function () {
14242 var
14243 $activeElement = $(document.activeElement),
14244 inCurrentModal = $activeElement.closest($module).length > 0
14245 ;
14246 if (!inCurrentModal) {
14247 $focusedElement = $(document.activeElement).trigger('blur');
14248 }
14249 },
14250 bodyMargin: function () {
14251 initialBodyMargin = $context.css((isBody ? 'margin-' : 'padding-') + (module.can.leftBodyScrollbar() ? 'left' : 'right'));
14252 var
14253 bodyMarginRightPixel = parseInt(initialBodyMargin.replace(/[^\d.]/g, ''), 10),
14254 bodyScrollbarWidth = isBody ? window.innerWidth - document.documentElement.clientWidth : $context[0].offsetWidth - $context[0].clientWidth
14255 ;
14256 tempBodyMargin = bodyMarginRightPixel + bodyScrollbarWidth;
14257 },
14258 },
14259
14260 restore: {
14261 focus: function () {
14262 if ($focusedElement && $focusedElement.length > 0 && settings.restoreFocus) {
14263 $focusedElement.trigger('focus');
14264 }
14265 },
14266 bodyMargin: function () {
14267 var position = module.can.leftBodyScrollbar() ? 'left' : 'right';
14268 $context.css((isBody ? 'margin-' : 'padding-') + position, initialBodyMargin);
14269 $context.find(selector.bodyFixed.replace('right', position)).each(function () {
14270 var
14271 el = $(this),
14272 attribute = el.css('position') === 'fixed' ? 'padding-' + position : position
14273 ;
14274 el.css(attribute, '');
14275 });
14276 },
14277 },
14278
14279 remove: {
14280 active: function () {
14281 $module.removeClass(className.active);
14282 },
14283 legacy: function () {
14284 $module.removeClass(className.legacy);
14285 },
14286 clickaway: function () {
14287 if (!settings.detachable) {
14288 $module
14289 .off('mousedown' + elementEventNamespace)
14290 ;
14291 }
14292 $dimmer
14293 .off('mousedown' + elementEventNamespace)
14294 ;
14295 $dimmer
14296 .off('mouseup' + elementEventNamespace)
14297 ;
14298 },
14299 dimmerStyles: function () {
14300 $dimmer.removeClass(className.inverted);
14301 $dimmable.removeClass(className.blurring);
14302 },
14303 bodyStyle: function () {
14304 if ($context.attr('style') === '') {
14305 module.verbose('Removing style attribute');
14306 $context.removeAttr('style');
14307 }
14308 },
14309 screenHeight: function () {
14310 module.debug('Removing page height');
14311 $context
14312 .css('height', '')
14313 ;
14314 module.remove.bodyStyle();
14315 },
14316 keyboardShortcuts: function () {
14317 module.verbose('Removing keyboard shortcuts');
14318 $document
14319 .off('keydown' + eventNamespace)
14320 ;
14321 },
14322 scrolling: function () {
14323 if (!keepScrollingClass) {
14324 $dimmable.removeClass(className.scrolling);
14325 }
14326 $module.removeClass(className.scrolling);
14327 },
14328 },
14329
14330 cacheSizes: function () {
14331 $module.addClass(className.loading);
14332 var
14333 scrollHeight = $module.prop('scrollHeight'),
14334 modalWidth = $module.outerWidth(),
14335 modalHeight = $module.outerHeight()
14336 ;
14337 if (module.cache.pageHeight === undefined || modalHeight !== 0) {
14338 $.extend(module.cache, {
14339 pageHeight: $document.outerHeight(),
14340 width: modalWidth,
14341 height: modalHeight + settings.offset,
14342 scrollHeight: scrollHeight + settings.offset,
14343 contextHeight: isBody
14344 ? $window.height()
14345 : $dimmable.height(),
14346 });
14347 module.cache.topOffset = -(module.cache.height / 2);
14348 }
14349 $module.removeClass(className.loading);
14350 module.debug('Caching modal and container sizes', module.cache);
14351 },
14352 helpers: {
14353 deQuote: function (string) {
14354 return String(string).replace(/"/g, '');
14355 },
14356 escape: function (string, preserveHTML) {
14357 if (preserveHTML) {
14358 return string;
14359 }
14360 var
14361 badChars = /["'<>`]/g,
14362 shouldEscape = /["&'<>`]/,
14363 escape = {
14364 '<': '&lt;',
14365 '>': '&gt;',
14366 '"': '&quot;',
14367 "'": '&#x27;',
14368 '`': '&#x60;',
14369 },
14370 escapedChar = function (chr) {
14371 return escape[chr];
14372 }
14373 ;
14374 if (shouldEscape.test(string)) {
14375 string = string.replace(/&(?![\d#a-z]{1,12};)/gi, '&amp;');
14376
14377 return string.replace(badChars, escapedChar);
14378 }
14379
14380 return string;
14381 },
14382 },
14383 can: {
14384 leftBodyScrollbar: function () {
14385 if (module.cache.leftBodyScrollbar === undefined) {
14386 module.cache.leftBodyScrollbar = module.is.rtl() && ((module.is.iframe && !module.is.firefox()) || module.is.safari() || module.is.edge() || module.is.ie());
14387 }
14388
14389 return module.cache.leftBodyScrollbar;
14390 },
14391 useFlex: function () {
14392 if (settings.useFlex === 'auto') {
14393 return settings.detachable && !module.is.ie();
14394 }
14395 if (settings.useFlex && module.is.ie()) {
14396 module.debug('useFlex true is not supported in IE');
14397 } else if (settings.useFlex && !settings.detachable) {
14398 module.debug('useFlex true in combination with detachable false is not supported');
14399 }
14400
14401 return settings.useFlex;
14402 },
14403 fit: function () {
14404 var
14405 contextHeight = module.cache.contextHeight,
14406 verticalCenter = module.cache.contextHeight / 2,
14407 topOffset = module.cache.topOffset,
14408 scrollHeight = module.cache.scrollHeight,
14409 height = module.cache.height,
14410 paddingHeight = settings.padding,
14411 startPosition = verticalCenter + topOffset
14412 ;
14413
14414 return scrollHeight > height
14415 ? startPosition + scrollHeight + paddingHeight < contextHeight
14416 : height + (paddingHeight * 2) < contextHeight;
14417 },
14418 },
14419 has: {
14420 configActions: function () {
14421 return Array.isArray(settings.actions) && settings.actions.length > 0;
14422 },
14423 scrollbar: function () {
14424 return isBody || $context.css('overflow-y') !== 'hidden';
14425 },
14426 },
14427 is: {
14428 active: function () {
14429 return $module.hasClass(className.active);
14430 },
14431 ie: function () {
14432 if (module.cache.isIE === undefined) {
14433 var
14434 isIE11 = !window.ActiveXObject && 'ActiveXObject' in window,
14435 isIE = 'ActiveXObject' in window
14436 ;
14437 module.cache.isIE = isIE11 || isIE;
14438 }
14439
14440 return module.cache.isIE;
14441 },
14442 animating: function () {
14443 return $module.transition('is animating');
14444 },
14445 scrolling: function () {
14446 return $dimmable.hasClass(className.scrolling);
14447 },
14448 modernBrowser: function () {
14449 // appName for IE11 reports 'Netscape' can no longer use
14450 return !(window.ActiveXObject || 'ActiveXObject' in window);
14451 },
14452 rtl: function () {
14453 if (module.cache.isRTL === undefined) {
14454 module.cache.isRTL = $module.attr('dir') === 'rtl' || $module.css('direction') === 'rtl' || $body.attr('dir') === 'rtl' || $body.css('direction') === 'rtl' || $context.attr('dir') === 'rtl' || $context.css('direction') === 'rtl';
14455 }
14456
14457 return module.cache.isRTL;
14458 },
14459 safari: function () {
14460 if (module.cache.isSafari === undefined) {
14461 module.cache.isSafari = /constructor/i.test(window.HTMLElement) || !!window.ApplePaySession;
14462 }
14463
14464 return module.cache.isSafari;
14465 },
14466 edge: function () {
14467 if (module.cache.isEdge === undefined) {
14468 module.cache.isEdge = !!window.setImmediate && !module.is.ie();
14469 }
14470
14471 return module.cache.isEdge;
14472 },
14473 firefox: function () {
14474 if (module.cache.isFirefox === undefined) {
14475 module.cache.isFirefox = !!window.InstallTrigger;
14476 }
14477
14478 return module.cache.isFirefox;
14479 },
14480 iframe: function () {
14481 return !(self === top);
14482 },
14483 },
14484
14485 set: {
14486 observeAttributes: function (state) {
14487 observeAttributes = state !== false;
14488 },
14489 autofocus: function () {
14490 var
14491 $autofocus = $inputs.filter('[autofocus]'),
14492 $rawInputs = $inputs.filter(':input'),
14493 $input = ($autofocus.length > 0
14494 ? $autofocus
14495 : ($rawInputs.length > 0
14496 ? $rawInputs
14497 : $module)
14498 ).first()
14499 ;
14500 $input.trigger('focus');
14501 },
14502 bodyMargin: function () {
14503 var position = module.can.leftBodyScrollbar() ? 'left' : 'right';
14504 if (settings.detachable || module.can.fit()) {
14505 $context.css((isBody ? 'margin-' : 'padding-') + position, tempBodyMargin + 'px');
14506 }
14507 $context.find(selector.bodyFixed.replace('right', position)).each(function () {
14508 var
14509 el = $(this),
14510 attribute = el.css('position') === 'fixed' ? 'padding-' + position : position
14511 ;
14512 el.css(attribute, 'calc(' + el.css(attribute) + ' + ' + tempBodyMargin + 'px)');
14513 });
14514 },
14515 clickaway: function () {
14516 if (!settings.detachable) {
14517 $module
14518 .on('mousedown' + elementEventNamespace, module.event.mousedown)
14519 ;
14520 }
14521 $dimmer
14522 .on('mousedown' + elementEventNamespace, module.event.mousedown)
14523 ;
14524 $dimmer
14525 .on('mouseup' + elementEventNamespace, module.event.mouseup)
14526 ;
14527 },
14528 dimmerSettings: function () {
14529 if ($.fn.dimmer === undefined) {
14530 module.error(error.dimmer);
14531
14532 return;
14533 }
14534 var
14535 defaultSettings = {
14536 debug: settings.debug,
14537 dimmerName: 'modals',
14538 closable: 'auto',
14539 useFlex: module.can.useFlex(),
14540 duration: {
14541 show: settings.transition.showDuration || settings.duration,
14542 hide: settings.transition.hideDuration || settings.duration,
14543 },
14544 },
14545 dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
14546 ;
14547 if (settings.inverted) {
14548 dimmerSettings.variation = dimmerSettings.variation !== undefined
14549 ? dimmerSettings.variation + ' inverted'
14550 : 'inverted';
14551 }
14552 $context.dimmer('setting', dimmerSettings);
14553 },
14554 dimmerStyles: function () {
14555 if (settings.inverted) {
14556 $dimmer.addClass(className.inverted);
14557 } else {
14558 $dimmer.removeClass(className.inverted);
14559 }
14560 if (settings.blurring) {
14561 $dimmable.addClass(className.blurring);
14562 } else {
14563 $dimmable.removeClass(className.blurring);
14564 }
14565 },
14566 modalOffset: function () {
14567 if (!settings.detachable) {
14568 var canFit = module.can.fit();
14569 $module
14570 .css({
14571 top: !$module.hasClass('aligned') && canFit
14572 ? $document.scrollTop() + (module.cache.contextHeight - module.cache.height) / 2
14573 : (!canFit || $module.hasClass('top')
14574 ? $document.scrollTop() + settings.padding
14575 : $document.scrollTop() + (module.cache.contextHeight - module.cache.height - settings.padding)),
14576 marginLeft: -(module.cache.width / 2),
14577 })
14578 ;
14579 } else {
14580 $module
14581 .css({
14582 marginTop: !$module.hasClass('aligned') && module.can.fit()
14583 ? -(module.cache.height / 2)
14584 : settings.padding / 2,
14585 marginLeft: -(module.cache.width / 2),
14586 })
14587 ;
14588 }
14589 module.verbose('Setting modal offset for legacy mode');
14590 },
14591 screenHeight: function () {
14592 if (module.can.fit()) {
14593 $context.css('height', '');
14594 } else if (!$module.hasClass('bottom')) {
14595 module.debug('Modal is taller than page content, resizing page height');
14596 $context
14597 .css('height', module.cache.height + (settings.padding * 2) + 'px')
14598 ;
14599 }
14600 },
14601 active: function () {
14602 $module.addClass(className.active + ' ' + className.front);
14603 $otherModals.filter('.' + className.active).removeClass(className.front);
14604 },
14605 scrolling: function () {
14606 $dimmable.addClass(className.scrolling);
14607 $module.addClass(className.scrolling);
14608 module.unbind.scrollLock();
14609 },
14610 legacy: function () {
14611 $module.addClass(className.legacy);
14612 },
14613 type: function () {
14614 if (module.can.fit()) {
14615 module.verbose('Modal fits on screen');
14616 if (!module.others.active() && !module.others.animating()) {
14617 module.remove.scrolling();
14618 module.bind.scrollLock();
14619 }
14620 } else if (!$module.hasClass('bottom')) {
14621 module.verbose('Modal cannot fit on screen setting to scrolling');
14622 module.set.scrolling();
14623 } else {
14624 module.verbose('Bottom aligned modal not fitting on screen is unsupported for scrolling');
14625 }
14626 },
14627 undetached: function () {
14628 $dimmable.addClass(className.undetached);
14629 },
14630 },
14631
14632 setting: function (name, value) {
14633 module.debug('Changing setting', name, value);
14634 if ($.isPlainObject(name)) {
14635 $.extend(true, settings, name);
14636 } else if (value !== undefined) {
14637 if ($.isPlainObject(settings[name])) {
14638 $.extend(true, settings[name], value);
14639 } else {
14640 settings[name] = value;
14641 }
14642 } else {
14643 return settings[name];
14644 }
14645 },
14646 internal: function (name, value) {
14647 if ($.isPlainObject(name)) {
14648 $.extend(true, module, name);
14649 } else if (value !== undefined) {
14650 module[name] = value;
14651 } else {
14652 return module[name];
14653 }
14654 },
14655 debug: function () {
14656 if (!settings.silent && settings.debug) {
14657 if (settings.performance) {
14658 module.performance.log(arguments);
14659 } else {
14660 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
14661 module.debug.apply(console, arguments);
14662 }
14663 }
14664 },
14665 verbose: function () {
14666 if (!settings.silent && settings.verbose && settings.debug) {
14667 if (settings.performance) {
14668 module.performance.log(arguments);
14669 } else {
14670 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
14671 module.verbose.apply(console, arguments);
14672 }
14673 }
14674 },
14675 error: function () {
14676 if (!settings.silent) {
14677 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
14678 module.error.apply(console, arguments);
14679 }
14680 },
14681 performance: {
14682 log: function (message) {
14683 var
14684 currentTime,
14685 executionTime,
14686 previousTime
14687 ;
14688 if (settings.performance) {
14689 currentTime = Date.now();
14690 previousTime = time || currentTime;
14691 executionTime = currentTime - previousTime;
14692 time = currentTime;
14693 performance.push({
14694 Name: message[0],
14695 Arguments: [].slice.call(message, 1) || '',
14696 Element: element,
14697 'Execution Time': executionTime,
14698 });
14699 }
14700 clearTimeout(module.performance.timer);
14701 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
14702 },
14703 display: function () {
14704 var
14705 title = settings.name + ':',
14706 totalTime = 0
14707 ;
14708 time = false;
14709 clearTimeout(module.performance.timer);
14710 $.each(performance, function (index, data) {
14711 totalTime += data['Execution Time'];
14712 });
14713 title += ' ' + totalTime + 'ms';
14714 if (performance.length > 0) {
14715 console.groupCollapsed(title);
14716 if (console.table) {
14717 console.table(performance);
14718 } else {
14719 $.each(performance, function (index, data) {
14720 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
14721 });
14722 }
14723 console.groupEnd();
14724 }
14725 performance = [];
14726 },
14727 },
14728 invoke: function (query, passedArguments, context) {
14729 var
14730 object = instance,
14731 maxDepth,
14732 found,
14733 response
14734 ;
14735 passedArguments = passedArguments || queryArguments;
14736 context = context || element;
14737 if (typeof query === 'string' && object !== undefined) {
14738 query = query.split(/[ .]/);
14739 maxDepth = query.length - 1;
14740 $.each(query, function (depth, value) {
14741 var camelCaseValue = depth !== maxDepth
14742 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
14743 : query;
14744 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
14745 object = object[camelCaseValue];
14746 } else if (object[camelCaseValue] !== undefined) {
14747 found = object[camelCaseValue];
14748
14749 return false;
14750 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
14751 object = object[value];
14752 } else if (object[value] !== undefined) {
14753 found = object[value];
14754
14755 return false;
14756 } else {
14757 module.error(error.method, query);
14758
14759 return false;
14760 }
14761 });
14762 }
14763 if (isFunction(found)) {
14764 response = found.apply(context, passedArguments);
14765 } else if (found !== undefined) {
14766 response = found;
14767 }
14768 if (Array.isArray(returnedValue)) {
14769 returnedValue.push(response);
14770 } else if (returnedValue !== undefined) {
14771 returnedValue = [returnedValue, response];
14772 } else if (response !== undefined) {
14773 returnedValue = response;
14774 }
14775
14776 return found;
14777 },
14778 };
14779
14780 if (methodInvoked) {
14781 if (instance === undefined) {
14782 if (isFunction(settings.templates[query])) {
14783 settings.autoShow = true;
14784 settings.className.modal = settings.className.template;
14785 settings = $.extend(true, {}, settings, settings.templates[query].apply(module, queryArguments));
14786
14787 // reassign shortcuts
14788 className = settings.className;
14789 namespace = settings.namespace;
14790 fields = settings.fields;
14791 error = settings.error;
14792 }
14793 module.initialize();
14794 }
14795 if (!isFunction(settings.templates[query])) {
14796 module.invoke(query);
14797 }
14798 } else {
14799 if (instance !== undefined) {
14800 instance.invoke('destroy');
14801 }
14802 module.initialize();
14803 returnedValue = $module;
14804 }
14805 });
14806
14807 return returnedValue !== undefined
14808 ? returnedValue
14809 : this;
14810 };
14811 $.modal = $.fn.modal;
14812
14813 $.fn.modal.settings = {
14814
14815 name: 'Modal',
14816 namespace: 'modal',
14817
14818 useFlex: 'auto',
14819 offset: 0,
14820
14821 silent: false,
14822 debug: false,
14823 verbose: false,
14824 performance: true,
14825
14826 observeChanges: false,
14827
14828 allowMultiple: false,
14829 detachable: true,
14830 closable: true,
14831 autofocus: true,
14832 restoreFocus: true,
14833 autoShow: false,
14834
14835 inverted: false,
14836 blurring: false,
14837
14838 centered: true,
14839
14840 dimmerSettings: {
14841 closable: false,
14842 useCSS: true,
14843 },
14844
14845 // whether to use keyboard shortcuts
14846 keyboardShortcuts: true,
14847
14848 context: 'body',
14849
14850 queue: false,
14851 duration: 500,
14852 transition: 'scale',
14853
14854 // padding with edge of page
14855 padding: 50,
14856 scrollbarWidth: 10,
14857
14858 // dynamic content
14859 title: '',
14860 content: '',
14861 class: '',
14862 classTitle: '',
14863 classContent: '',
14864 classActions: '',
14865 closeIcon: false,
14866 actions: false,
14867 preserveHTML: true,
14868
14869 fields: {
14870 class: 'class',
14871 text: 'text',
14872 icon: 'icon',
14873 click: 'click',
14874 },
14875
14876 // called before show animation
14877 onShow: function () {},
14878
14879 // called after show animation
14880 onVisible: function () {},
14881
14882 // called before hide animation
14883 onHide: function () {
14884 return true;
14885 },
14886
14887 // called after hide animation
14888 onHidden: false,
14889
14890 // called after approve selector match
14891 onApprove: function () {
14892 return true;
14893 },
14894
14895 // called after deny selector match
14896 onDeny: function () {
14897 return true;
14898 },
14899
14900 keys: {
14901 space: 32,
14902 enter: 13,
14903 escape: 27,
14904 tab: 9,
14905 },
14906
14907 selector: {
14908 title: '> .header',
14909 content: '> .content',
14910 actions: '> .actions',
14911 close: '> .close',
14912 closeIcon: '> .close',
14913 approve: '.actions .positive, .actions .approve, .actions .ok',
14914 deny: '.actions .negative, .actions .deny, .actions .cancel',
14915 modal: '.ui.modal',
14916 dimmer: '> .ui.dimmer',
14917 bodyFixed: '> .ui.fixed.menu, > .ui.right.toast-container, > .ui.right.sidebar, > .ui.fixed.nag, > .ui.fixed.nag > .close',
14918 prompt: '.ui.input > input',
14919 },
14920 error: {
14921 dimmer: 'UI Dimmer, a required component is not included in this page',
14922 method: 'The method you called is not defined.',
14923 notFound: 'The element you specified could not be found',
14924 },
14925 className: {
14926 active: 'active',
14927 animating: 'animating',
14928 blurring: 'blurring',
14929 inverted: 'inverted',
14930 legacy: 'legacy',
14931 loading: 'loading',
14932 scrolling: 'scrolling',
14933 undetached: 'undetached',
14934 front: 'front',
14935 close: 'close icon',
14936 button: 'ui button',
14937 modal: 'ui modal',
14938 title: 'header',
14939 content: 'content',
14940 actions: 'actions',
14941 template: 'ui tiny modal',
14942 ok: 'positive',
14943 cancel: 'negative',
14944 prompt: 'ui fluid input',
14945 innerDimmer: 'ui inverted dimmer',
14946 },
14947 text: {
14948 ok: 'Ok',
14949 cancel: 'Cancel',
14950 close: 'Close',
14951 },
14952 };
14953
14954 $.fn.modal.settings.templates = {
14955 getArguments: function (args) {
14956 var queryArguments = [].slice.call(args);
14957 if ($.isPlainObject(queryArguments[0])) {
14958 return $.extend({
14959 handler: function () {},
14960 content: '',
14961 title: '',
14962 }, queryArguments[0]);
14963 }
14964 if (!isFunction(queryArguments[queryArguments.length - 1])) {
14965 queryArguments.push(function () {});
14966 }
14967
14968 return {
14969 handler: queryArguments.pop(),
14970 content: queryArguments.pop() || '',
14971 title: queryArguments.pop() || '',
14972 };
14973 },
14974 alert: function () {
14975 var
14976 settings = this.get.settings(),
14977 args = settings.templates.getArguments(arguments),
14978 approveFn = args.handler
14979 ;
14980
14981 return {
14982 title: args.title,
14983 content: args.content,
14984 onApprove: approveFn,
14985 actions: [{
14986 text: settings.text.ok,
14987 class: settings.className.ok,
14988 click: approveFn,
14989 }],
14990 };
14991 },
14992 confirm: function () {
14993 var
14994 settings = this.get.settings(),
14995 args = settings.templates.getArguments(arguments),
14996 approveFn = function () {
14997 args.handler(true);
14998 },
14999 denyFn = function () {
15000 args.handler(false);
15001 }
15002 ;
15003
15004 return {
15005 title: args.title,
15006 content: args.content,
15007 onApprove: approveFn,
15008 onDeny: denyFn,
15009 actions: [{
15010 text: settings.text.ok,
15011 class: settings.className.ok,
15012 click: approveFn,
15013 }, {
15014 text: settings.text.cancel,
15015 class: settings.className.cancel,
15016 click: denyFn,
15017 }],
15018 };
15019 },
15020 prompt: function () {
15021 var
15022 $this = this,
15023 settings = this.get.settings(),
15024 args = settings.templates.getArguments(arguments),
15025 input = $($.parseHTML(args.content)).filter('.ui.input'),
15026 approveFn = function () {
15027 var
15028 settings = $this.get.settings(),
15029 inputField = $this.get.element().find(settings.selector.prompt)[0]
15030 ;
15031 args.handler($(inputField).val());
15032 },
15033 denyFn = function () {
15034 args.handler(null);
15035 }
15036 ;
15037 if (input.length === 0) {
15038 args.content += '<p><div class="' + this.helpers.deQuote(settings.className.prompt) + '"><input placeholder="' + this.helpers.deQuote(args.placeholder || '') + '" type="text" value="' + this.helpers.deQuote(args.defaultValue || '') + '"></div></p>';
15039 }
15040
15041 return {
15042 title: args.title,
15043 content: args.content,
15044 onApprove: approveFn,
15045 onDeny: denyFn,
15046 actions: [{
15047 text: settings.text.ok,
15048 class: settings.className.ok,
15049 click: approveFn,
15050 }, {
15051 text: settings.text.cancel,
15052 class: settings.className.cancel,
15053 click: denyFn,
15054 }],
15055 };
15056 },
15057 };
15058})(jQuery, window, document);
15059
15060/*!
15061 * # Fomantic-UI 2.9.3 - Nag
15062 * https://github.com/fomantic/Fomantic-UI/
15063 *
15064 *
15065 * Released under the MIT license
15066 * https://opensource.org/licenses/MIT
15067 *
15068 */
15069
15070(function ($, window, document) {
15071 'use strict';
15072
15073 function isFunction(obj) {
15074 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
15075 }
15076
15077 window = window !== undefined && window.Math === Math
15078 ? window
15079 : globalThis;
15080
15081 $.fn.nag = function (parameters) {
15082 var
15083 $allModules = $(this),
15084 $body = $('body'),
15085
15086 time = Date.now(),
15087 performance = [],
15088
15089 query = arguments[0],
15090 methodInvoked = typeof query === 'string',
15091 queryArguments = [].slice.call(arguments, 1),
15092 contextCheck = function (context, win) {
15093 var $context;
15094 if ([window, document].indexOf(context) >= 0) {
15095 $context = $(context);
15096 } else {
15097 $context = $(win.document).find(context);
15098 if ($context.length === 0) {
15099 $context = win.frameElement ? contextCheck(context, win.parent) : $body;
15100 }
15101 }
15102
15103 return $context;
15104 },
15105 returnedValue
15106 ;
15107 $allModules.each(function () {
15108 var
15109 settings = $.isPlainObject(parameters)
15110 ? $.extend(true, {}, $.fn.nag.settings, parameters)
15111 : $.extend({}, $.fn.nag.settings),
15112
15113 selector = settings.selector,
15114 error = settings.error,
15115 namespace = settings.namespace,
15116
15117 eventNamespace = '.' + namespace,
15118 moduleNamespace = namespace + '-module',
15119
15120 $module = $(this),
15121
15122 $context = settings.context ? contextCheck(settings.context, window) : $body,
15123
15124 element = this,
15125 instance = $module.data(moduleNamespace),
15126 storage,
15127 module
15128 ;
15129 module = {
15130
15131 initialize: function () {
15132 module.verbose('Initializing element');
15133 if (typeof settings.value !== 'string') {
15134 settings.value = JSON.stringify(settings.value);
15135 }
15136 storage = module.get.storage();
15137 $module
15138 .on('click' + eventNamespace, selector.close, module.dismiss)
15139 .data(moduleNamespace, module)
15140 ;
15141
15142 if (settings.detachable && $module.parent()[0] !== $context[0]) {
15143 $module
15144 .detach()
15145 .prependTo($context)
15146 ;
15147 }
15148
15149 if (settings.displayTime > 0) {
15150 setTimeout(function () { module.hide(); }, settings.displayTime);
15151 }
15152 module.show();
15153 },
15154
15155 destroy: function () {
15156 module.verbose('Destroying instance');
15157 $module
15158 .removeData(moduleNamespace)
15159 .off(eventNamespace)
15160 ;
15161 },
15162
15163 show: function () {
15164 if (module.should.show() && !$module.is(':visible')) {
15165 if (settings.onShow.call(element) === false) {
15166 module.debug('onShow callback returned false, cancelling nag animation');
15167
15168 return false;
15169 }
15170 module.debug('Showing nag', settings.animation.show);
15171 if (settings.animation.show === 'fade') {
15172 $module
15173 .fadeIn(settings.duration, settings.easing, settings.onVisible)
15174 ;
15175 } else {
15176 $module
15177 .slideDown(settings.duration, settings.easing, settings.onVisible)
15178 ;
15179 }
15180 }
15181 },
15182
15183 hide: function () {
15184 if (settings.onHide.call(element) === false) {
15185 module.debug('onHide callback returned false, cancelling nag animation');
15186
15187 return false;
15188 }
15189 module.debug('Hiding nag', settings.animation.hide);
15190 if (settings.animation.hide === 'fade') {
15191 $module
15192 .fadeOut(settings.duration, settings.easing, settings.onHidden)
15193 ;
15194 } else {
15195 $module
15196 .slideUp(settings.duration, settings.easing, settings.onHidden)
15197 ;
15198 }
15199 },
15200
15201 dismiss: function (event) {
15202 if (module.hide() !== false && settings.storageMethod) {
15203 module.debug('Dismissing nag', settings.storageMethod, settings.key, settings.value, settings.expires);
15204 module.storage.set(settings.key, settings.value);
15205 }
15206 event.stopImmediatePropagation();
15207 event.preventDefault();
15208 },
15209
15210 should: {
15211 show: function () {
15212 if (settings.persist) {
15213 module.debug('Persistent nag is set, can show nag');
15214
15215 return true;
15216 }
15217 if (module.storage.get(settings.key) != settings.value.toString()) {
15218 module.debug('Stored value is not set, can show nag', module.storage.get(settings.key));
15219
15220 return true;
15221 }
15222 module.debug('Stored value is set, cannot show nag', module.storage.get(settings.key));
15223
15224 return false;
15225 },
15226 },
15227
15228 get: {
15229 expirationDate: function (expires) {
15230 if (typeof expires === 'number') {
15231 expires = new Date(Date.now() + expires * 864e5);
15232 }
15233 if (expires instanceof Date && expires.getTime()) {
15234 return expires.toUTCString();
15235 }
15236
15237 module.error(error.expiresFormat);
15238 },
15239 storage: function () {
15240 if (settings.storageMethod === 'localstorage' && window.localStorage !== undefined) {
15241 module.debug('Using local storage');
15242
15243 return window.localStorage;
15244 }
15245 if (settings.storageMethod === 'sessionstorage' && window.sessionStorage !== undefined) {
15246 module.debug('Using session storage');
15247
15248 return window.sessionStorage;
15249 }
15250 if ('cookie' in document) {
15251 module.debug('Using cookie');
15252
15253 return {
15254 setItem: function (key, value, options) {
15255 // RFC6265 compliant encoding
15256 key = encodeURIComponent(key)
15257 .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
15258 .replace(/[()]/g, escape)
15259 ;
15260 value = encodeURIComponent(value)
15261 .replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[B-D])/g, decodeURIComponent)
15262 ;
15263
15264 var cookieOptions = '';
15265 for (var option in options) {
15266 if (Object.prototype.hasOwnProperty.call(options, option)) {
15267 cookieOptions += '; ' + option;
15268 if (typeof options[option] === 'string') {
15269 cookieOptions += '=' + options[option].split(';')[0];
15270 }
15271 }
15272 }
15273 document.cookie = key + '=' + value + cookieOptions;
15274 },
15275 getItem: function (key) {
15276 var cookies = document.cookie.split('; ');
15277 for (var i = 0, il = cookies.length; i < il; i++) {
15278 var
15279 parts = cookies[i].split('='),
15280 foundKey = parts[0].replace(/(%[\da-f]{2})+/gi, decodeURIComponent)
15281 ;
15282 if (key === foundKey) {
15283 return parts[1] || '';
15284 }
15285 }
15286 },
15287 removeItem: function (key, options) {
15288 storage.setItem(key, '', options);
15289 },
15290 };
15291 }
15292
15293 module.error(error.noStorage);
15294 },
15295 storageOptions: function () {
15296 var
15297 options = {}
15298 ;
15299 if (settings.expires) {
15300 options.expires = module.get.expirationDate(settings.expires);
15301 }
15302 if (settings.domain) {
15303 options.domain = settings.domain;
15304 }
15305 if (settings.path) {
15306 options.path = settings.path;
15307 }
15308 if (settings.secure) {
15309 options.secure = settings.secure;
15310 }
15311 if (settings.samesite) {
15312 options.samesite = settings.samesite;
15313 }
15314
15315 return options;
15316 },
15317 },
15318
15319 clear: function () {
15320 module.storage.remove(settings.key);
15321 },
15322
15323 storage: {
15324 set: function (key, value) {
15325 var
15326 options = module.get.storageOptions()
15327 ;
15328 if (storage === window.localStorage && options.expires) {
15329 module.debug('Storing expiration value in localStorage', key, options.expires);
15330 storage.setItem(key + settings.expirationKey, options.expires);
15331 }
15332 module.debug('Value stored', key, value);
15333 try {
15334 storage.setItem(key, value, options);
15335 } catch (e) {
15336 module.error(error.setItem, e);
15337 }
15338 },
15339 get: function (key) {
15340 var
15341 storedValue
15342 ;
15343 storedValue = storage.getItem(key);
15344 if (storage === window.localStorage) {
15345 var expiration = storage.getItem(key + settings.expirationKey);
15346 if (expiration !== null && expiration !== undefined && new Date(expiration) < new Date()) {
15347 module.debug('Value in localStorage has expired. Deleting key', key);
15348 module.storage.remove(key);
15349 storedValue = null;
15350 }
15351 }
15352 if (storedValue === 'undefined' || storedValue === 'null' || storedValue === undefined || storedValue === null) {
15353 storedValue = undefined;
15354 }
15355
15356 return storedValue;
15357 },
15358 remove: function (key) {
15359 var
15360 options = module.get.storageOptions()
15361 ;
15362 options.expires = module.get.expirationDate(-1);
15363 if (storage === window.localStorage) {
15364 storage.removeItem(key + settings.expirationKey);
15365 }
15366 storage.removeItem(key, options);
15367 },
15368 },
15369
15370 setting: function (name, value) {
15371 module.debug('Changing setting', name, value);
15372 if ($.isPlainObject(name)) {
15373 $.extend(true, settings, name);
15374 } else if (value !== undefined) {
15375 if ($.isPlainObject(settings[name])) {
15376 $.extend(true, settings[name], value);
15377 } else {
15378 settings[name] = value;
15379 }
15380 } else {
15381 return settings[name];
15382 }
15383 },
15384 internal: function (name, value) {
15385 if ($.isPlainObject(name)) {
15386 $.extend(true, module, name);
15387 } else if (value !== undefined) {
15388 module[name] = value;
15389 } else {
15390 return module[name];
15391 }
15392 },
15393 debug: function () {
15394 if (!settings.silent && settings.debug) {
15395 if (settings.performance) {
15396 module.performance.log(arguments);
15397 } else {
15398 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
15399 module.debug.apply(console, arguments);
15400 }
15401 }
15402 },
15403 verbose: function () {
15404 if (!settings.silent && settings.verbose && settings.debug) {
15405 if (settings.performance) {
15406 module.performance.log(arguments);
15407 } else {
15408 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
15409 module.verbose.apply(console, arguments);
15410 }
15411 }
15412 },
15413 error: function () {
15414 if (!settings.silent) {
15415 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
15416 module.error.apply(console, arguments);
15417 }
15418 },
15419 performance: {
15420 log: function (message) {
15421 var
15422 currentTime,
15423 executionTime,
15424 previousTime
15425 ;
15426 if (settings.performance) {
15427 currentTime = Date.now();
15428 previousTime = time || currentTime;
15429 executionTime = currentTime - previousTime;
15430 time = currentTime;
15431 performance.push({
15432 Name: message[0],
15433 Arguments: [].slice.call(message, 1) || '',
15434 Element: element,
15435 'Execution Time': executionTime,
15436 });
15437 }
15438 clearTimeout(module.performance.timer);
15439 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
15440 },
15441 display: function () {
15442 var
15443 title = settings.name + ':',
15444 totalTime = 0
15445 ;
15446 time = false;
15447 clearTimeout(module.performance.timer);
15448 $.each(performance, function (index, data) {
15449 totalTime += data['Execution Time'];
15450 });
15451 title += ' ' + totalTime + 'ms';
15452 if (performance.length > 0) {
15453 console.groupCollapsed(title);
15454 if (console.table) {
15455 console.table(performance);
15456 } else {
15457 $.each(performance, function (index, data) {
15458 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
15459 });
15460 }
15461 console.groupEnd();
15462 }
15463 performance = [];
15464 },
15465 },
15466 invoke: function (query, passedArguments, context) {
15467 var
15468 object = instance,
15469 maxDepth,
15470 found,
15471 response
15472 ;
15473 passedArguments = passedArguments || queryArguments;
15474 context = context || element;
15475 if (typeof query === 'string' && object !== undefined) {
15476 query = query.split(/[ .]/);
15477 maxDepth = query.length - 1;
15478 $.each(query, function (depth, value) {
15479 var camelCaseValue = depth !== maxDepth
15480 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
15481 : query
15482 ;
15483 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
15484 object = object[camelCaseValue];
15485 } else if (object[camelCaseValue] !== undefined) {
15486 found = object[camelCaseValue];
15487
15488 return false;
15489 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
15490 object = object[value];
15491 } else if (object[value] !== undefined) {
15492 found = object[value];
15493
15494 return false;
15495 } else {
15496 module.error(error.method, query);
15497
15498 return false;
15499 }
15500 });
15501 }
15502 if (isFunction(found)) {
15503 response = found.apply(context, passedArguments);
15504 } else if (found !== undefined) {
15505 response = found;
15506 }
15507 if (Array.isArray(returnedValue)) {
15508 returnedValue.push(response);
15509 } else if (returnedValue !== undefined) {
15510 returnedValue = [returnedValue, response];
15511 } else if (response !== undefined) {
15512 returnedValue = response;
15513 }
15514
15515 return found;
15516 },
15517 };
15518
15519 if (methodInvoked) {
15520 if (instance === undefined) {
15521 module.initialize();
15522 }
15523 module.invoke(query);
15524 } else {
15525 if (instance !== undefined) {
15526 instance.invoke('destroy');
15527 }
15528 module.initialize();
15529 }
15530 });
15531
15532 return returnedValue !== undefined
15533 ? returnedValue
15534 : this;
15535 };
15536
15537 $.fn.nag.settings = {
15538
15539 name: 'Nag',
15540
15541 silent: false,
15542 debug: false,
15543 verbose: false,
15544 performance: true,
15545
15546 namespace: 'Nag',
15547
15548 // allows cookie to be overridden
15549 persist: false,
15550
15551 // set to zero to require manually dismissal, otherwise hides on its own
15552 displayTime: 0,
15553
15554 animation: {
15555 show: 'slide',
15556 hide: 'slide',
15557 },
15558
15559 context: false,
15560 detachable: false,
15561
15562 expires: 30,
15563
15564 // cookie storage only options
15565 domain: false,
15566 path: '/',
15567 secure: false,
15568 samesite: false,
15569
15570 // type of storage to use
15571 storageMethod: 'cookie',
15572
15573 // value to store in dismissed localstorage/cookie
15574 key: 'nag',
15575 value: 'dismiss',
15576
15577 // Key suffix to support expiration in localstorage
15578 expirationKey: 'ExpirationDate',
15579
15580 error: {
15581 noStorage: 'Unsupported storage method',
15582 method: 'The method you called is not defined.',
15583 setItem: 'Unexpected error while setting value',
15584 expiresFormat: '"expires" must be a number of days or a Date Object',
15585 },
15586
15587 className: {
15588 bottom: 'bottom',
15589 fixed: 'fixed',
15590 },
15591
15592 selector: {
15593 close: '> .close.icon',
15594 },
15595
15596 duration: 500,
15597 easing: 'easeOutQuad',
15598
15599 // callback before show animation, return false to prevent show
15600 onShow: function () {},
15601
15602 // called after show animation
15603 onVisible: function () {},
15604
15605 // callback before hide animation, return false to prevent hide
15606 onHide: function () {},
15607
15608 // callback after hide animation
15609 onHidden: function () {},
15610
15611 };
15612
15613 // Adds easing
15614 $.extend($.easing, {
15615 easeOutQuad: function (x) {
15616 return 1 - (1 - x) * (1 - x);
15617 },
15618 });
15619})(jQuery, window, document);
15620
15621/*!
15622 * # Fomantic-UI 2.9.3 - Popup
15623 * https://github.com/fomantic/Fomantic-UI/
15624 *
15625 *
15626 * Released under the MIT license
15627 * https://opensource.org/licenses/MIT
15628 *
15629 */
15630
15631(function ($, window, document) {
15632 'use strict';
15633
15634 function isFunction(obj) {
15635 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
15636 }
15637
15638 window = window !== undefined && window.Math === Math
15639 ? window
15640 : globalThis;
15641
15642 $.fn.popup = function (parameters) {
15643 var
15644 $allModules = $(this),
15645 $document = $(document),
15646 $window = $(window),
15647 $body = $('body'),
15648
15649 clickEvent = 'ontouchstart' in document.documentElement
15650 ? 'touchstart'
15651 : 'click',
15652
15653 time = Date.now(),
15654 performance = [],
15655
15656 query = arguments[0],
15657 methodInvoked = typeof query === 'string',
15658 queryArguments = [].slice.call(arguments, 1),
15659 contextCheck = function (context, win) {
15660 var $context;
15661 if ([window, document].indexOf(context) >= 0) {
15662 $context = $(context);
15663 } else {
15664 $context = $(win.document).find(context);
15665 if ($context.length === 0) {
15666 $context = win.frameElement ? contextCheck(context, win.parent) : $body;
15667 }
15668 }
15669
15670 return $context;
15671 },
15672
15673 returnedValue
15674 ;
15675 $allModules.each(function () {
15676 var
15677 settings = $.isPlainObject(parameters)
15678 ? $.extend(true, {}, $.fn.popup.settings, parameters)
15679 : $.extend({}, $.fn.popup.settings),
15680
15681 selector = settings.selector,
15682 className = settings.className,
15683 error = settings.error,
15684 metadata = settings.metadata,
15685 namespace = settings.namespace,
15686
15687 eventNamespace = '.' + settings.namespace,
15688 moduleNamespace = 'module-' + namespace,
15689
15690 $module = $(this),
15691 $context = contextCheck(settings.context, window),
15692 $scrollContext = contextCheck(settings.scrollContext, window),
15693 $boundary = contextCheck(settings.boundary, window),
15694 $target = settings.target ? contextCheck(settings.target, window) : $module,
15695
15696 $popup,
15697 $offsetParent,
15698
15699 searchDepth = 0,
15700 triedPositions = false,
15701 openedWithTouch = false,
15702
15703 element = this,
15704 instance = $module.data(moduleNamespace),
15705
15706 documentObserver,
15707 elementNamespace,
15708 id,
15709 module
15710 ;
15711
15712 module = {
15713
15714 // binds events
15715 initialize: function () {
15716 module.debug('Initializing', $module);
15717 module.createID();
15718 module.bind.events();
15719 if (!module.exists() && settings.preserve) {
15720 module.create();
15721 }
15722 if (settings.observeChanges) {
15723 module.observeChanges();
15724 }
15725 module.instantiate();
15726 },
15727
15728 instantiate: function () {
15729 module.verbose('Storing instance', module);
15730 instance = module;
15731 $module
15732 .data(moduleNamespace, instance)
15733 ;
15734 },
15735
15736 observeChanges: function () {
15737 if ('MutationObserver' in window) {
15738 documentObserver = new MutationObserver(module.event.documentChanged);
15739 documentObserver.observe(document, {
15740 childList: true,
15741 subtree: true,
15742 });
15743 module.debug('Setting up mutation observer', documentObserver);
15744 }
15745 },
15746
15747 refresh: function () {
15748 if (settings.popup) {
15749 $popup = $document.find(settings.popup).eq(0);
15750 } else {
15751 if (settings.inline) {
15752 $popup = $target.nextAll(selector.popup).eq(0);
15753 settings.popup = $popup;
15754 }
15755 }
15756 if (settings.popup) {
15757 module.set.invisible();
15758 $offsetParent = module.get.offsetParent();
15759 module.remove.invisible();
15760 if (settings.movePopup && module.has.popup() && module.get.offsetParent($popup)[0] !== $offsetParent[0]) {
15761 module.debug('Moving popup to the same offset parent as target');
15762 $popup
15763 .detach()
15764 .appendTo($offsetParent)
15765 ;
15766 }
15767 } else {
15768 $offsetParent = settings.inline
15769 ? module.get.offsetParent($target)
15770 : (module.has.popup()
15771 ? module.get.offsetParent($popup)
15772 : $body);
15773 }
15774 if ($offsetParent.is('html') && $offsetParent[0] !== $body[0]) {
15775 module.debug('Setting page as offset parent');
15776 $offsetParent = $body;
15777 }
15778 if (module.get.variation()) {
15779 module.set.variation();
15780 }
15781 },
15782
15783 reposition: function () {
15784 module.refresh();
15785 module.set.position();
15786 },
15787
15788 destroy: function () {
15789 module.debug('Destroying previous module');
15790 if (documentObserver) {
15791 documentObserver.disconnect();
15792 }
15793 // remove element only if was created dynamically
15794 if ($popup && !settings.preserve) {
15795 module.removePopup();
15796 }
15797 // clear all timeouts
15798 clearTimeout(module.hideTimer);
15799 clearTimeout(module.showTimer);
15800 // remove events
15801 module.unbind.close();
15802 module.unbind.events();
15803 $module
15804 .removeData(moduleNamespace)
15805 ;
15806 },
15807
15808 event: {
15809 start: function (event) {
15810 var
15811 delay = $.isPlainObject(settings.delay)
15812 ? settings.delay.show
15813 : settings.delay
15814 ;
15815 clearTimeout(module.hideTimer);
15816 if (!openedWithTouch || (openedWithTouch && settings.addTouchEvents)) {
15817 module.showTimer = setTimeout(function () { module.show(); }, delay);
15818 }
15819 },
15820 end: function () {
15821 var
15822 delay = $.isPlainObject(settings.delay)
15823 ? settings.delay.hide
15824 : settings.delay
15825 ;
15826 clearTimeout(module.showTimer);
15827 module.hideTimer = setTimeout(function () { module.hide(); }, delay);
15828 },
15829 touchstart: function (event) {
15830 openedWithTouch = true;
15831 if (settings.addTouchEvents) {
15832 module.show();
15833 }
15834 },
15835 resize: function () {
15836 if (module.is.visible()) {
15837 module.set.position();
15838 }
15839 },
15840 documentChanged: function (mutations) {
15841 [].forEach.call(mutations, function (mutation) {
15842 if (mutation.removedNodes) {
15843 [].forEach.call(mutation.removedNodes, function (node) {
15844 if (node === element || $(node).find(element).length > 0) {
15845 module.debug('Element removed from DOM, tearing down events');
15846 module.destroy();
15847 }
15848 });
15849 }
15850 });
15851 },
15852 hideGracefully: function (event) {
15853 var
15854 $target = $(event.target),
15855 isInDOM = $.contains(document.documentElement, event.target),
15856 inPopup = $target.closest(selector.popup).length > 0
15857 ;
15858 // don't close on clicks inside popup
15859 if (event && !inPopup && isInDOM) {
15860 module.debug('Click occurred outside popup hiding popup');
15861 module.hide();
15862 } else {
15863 module.debug('Click was inside popup, keeping popup open');
15864 }
15865 },
15866 },
15867
15868 // generates popup html from metadata
15869 create: function () {
15870 var
15871 targetSibling = $target.next(selector.popup),
15872 contentFallback = !settings.popup && targetSibling.length === 0 ? $module.attr('title') : false,
15873 html = module.get.html(),
15874 title = module.get.title(),
15875 content = module.get.content(contentFallback)
15876 ;
15877
15878 if (html || content || title) {
15879 module.debug('Creating pop-up html');
15880 if (!html) {
15881 html = settings.templates.popup({
15882 title: title,
15883 content: content,
15884 });
15885 }
15886 $popup = $('<div/>')
15887 .addClass(className.popup)
15888 .data(metadata.activator, $module)
15889 .html(html)
15890 ;
15891 if (settings.inline) {
15892 module.verbose('Inserting popup element inline', $popup);
15893 $popup
15894 .insertAfter($module)
15895 ;
15896 } else {
15897 module.verbose('Appending popup element to body', $popup);
15898 $popup
15899 .appendTo($context)
15900 ;
15901 }
15902 module.refresh();
15903 module.set.variation();
15904
15905 if (settings.hoverable) {
15906 module.bind.popup();
15907 }
15908 settings.onCreate.call($popup, element);
15909 } else if (settings.popup) {
15910 $document.find(settings.popup).data(metadata.activator, $module);
15911 module.verbose('Used popup specified in settings');
15912 module.refresh();
15913 if (settings.hoverable) {
15914 module.bind.popup();
15915 }
15916 } else if (targetSibling.length > 0) {
15917 module.verbose('Pre-existing popup found');
15918 settings.inline = true;
15919 settings.popup = targetSibling.data(metadata.activator, $module);
15920 module.refresh();
15921 if (settings.hoverable) {
15922 module.bind.popup();
15923 }
15924 } else {
15925 module.debug('No content specified skipping display', element);
15926 }
15927 },
15928
15929 createID: function () {
15930 id = (Math.random().toString(16) + '000000000').slice(2, 10);
15931 elementNamespace = '.' + id;
15932 module.verbose('Creating unique id for element', id);
15933 },
15934
15935 // determines popup state
15936 toggle: function () {
15937 module.debug('Toggling pop-up');
15938 if (module.is.hidden()) {
15939 module.debug('Popup is hidden, showing pop-up');
15940 module.unbind.close();
15941 module.show();
15942 } else {
15943 module.debug('Popup is visible, hiding pop-up');
15944 module.hide();
15945 }
15946 },
15947
15948 show: function (callback) {
15949 callback = callback || function () {};
15950 module.debug('Showing pop-up', settings.transition);
15951 if (module.is.hidden() && !(module.is.active() && module.is.dropdown())) {
15952 if (!module.exists()) {
15953 module.create();
15954 }
15955 if (settings.onShow.call($popup, element) === false) {
15956 module.debug('onShow callback returned false, cancelling popup animation');
15957
15958 return;
15959 }
15960 if (!settings.preserve && !settings.popup) {
15961 module.refresh();
15962 }
15963 if ($popup && module.set.position()) {
15964 module.save.conditions();
15965 if (settings.exclusive) {
15966 module.hideAll();
15967 }
15968 module.animate.show(callback);
15969 }
15970 }
15971 },
15972
15973 hide: function (callback) {
15974 callback = callback || function () {};
15975 if (module.is.visible() || module.is.animating()) {
15976 if (settings.onHide.call($popup, element) === false) {
15977 module.debug('onHide callback returned false, cancelling popup animation');
15978
15979 return;
15980 }
15981 module.remove.visible();
15982 module.unbind.close();
15983 module.restore.conditions();
15984 module.animate.hide(callback);
15985 }
15986 },
15987
15988 hideAll: function () {
15989 $document.find(selector.popup)
15990 .filter('.' + className.popupVisible)
15991 .each(function () {
15992 $(this)
15993 .data(metadata.activator)
15994 .popup('hide')
15995 ;
15996 })
15997 ;
15998 },
15999 exists: function () {
16000 if (!$popup) {
16001 return false;
16002 }
16003 if (settings.inline || settings.popup) {
16004 return module.has.popup();
16005 }
16006
16007 return $popup.closest($context).length > 0;
16008 },
16009
16010 removePopup: function () {
16011 if (module.has.popup() && !settings.popup) {
16012 module.debug('Removing popup', $popup);
16013 $popup.remove();
16014 $popup = undefined;
16015 settings.onRemove.call($popup, element);
16016 }
16017 },
16018
16019 save: {
16020 conditions: function () {
16021 module.cache = {
16022 title: $module.attr('title'),
16023 };
16024 if (module.cache.title) {
16025 $module.removeAttr('title');
16026 }
16027 module.verbose('Saving original attributes', module.cache.title);
16028 },
16029 },
16030 restore: {
16031 conditions: function () {
16032 if (module.cache && module.cache.title) {
16033 $module.attr('title', module.cache.title);
16034 module.verbose('Restoring original attributes', module.cache.title);
16035 }
16036
16037 return true;
16038 },
16039 },
16040 supports: {
16041 svg: function () {
16042 return typeof SVGGraphicsElement !== 'undefined';
16043 },
16044 },
16045 animate: {
16046 show: function (callback) {
16047 callback = isFunction(callback) ? callback : function () {};
16048 if (settings.transition && module.can.useElement('transition')) {
16049 module.set.visible();
16050 $popup
16051 .transition({
16052 animation: (settings.transition.showMethod || settings.transition) + ' in',
16053 queue: false,
16054 debug: settings.debug,
16055 verbose: settings.verbose,
16056 silent: settings.silent,
16057 duration: settings.transition.showDuration || settings.duration,
16058 onComplete: function () {
16059 module.bind.close();
16060 callback.call($popup, element);
16061 settings.onVisible.call($popup, element);
16062 },
16063 })
16064 ;
16065 }
16066 },
16067 hide: function (callback) {
16068 callback = isFunction(callback) ? callback : function () {};
16069 module.debug('Hiding pop-up');
16070 if (settings.transition && $.fn.transition !== undefined) {
16071 $popup
16072 .transition({
16073 animation: (settings.transition.hideMethod || settings.transition) + ' out',
16074 queue: false,
16075 duration: settings.transition.hideDuration || settings.duration,
16076 debug: settings.debug,
16077 verbose: settings.verbose,
16078 silent: settings.silent,
16079 onComplete: function () {
16080 module.reset();
16081 callback.call($popup, element);
16082 settings.onHidden.call($popup, element);
16083 },
16084 })
16085 ;
16086 } else {
16087 module.error(error.noTransition);
16088 }
16089 },
16090 },
16091
16092 change: {
16093 content: function (html) {
16094 $popup.html(html);
16095 },
16096 },
16097
16098 get: {
16099 html: function () {
16100 $module.removeData(metadata.html);
16101
16102 return $module.data(metadata.html) || settings.html;
16103 },
16104 title: function () {
16105 $module.removeData(metadata.title);
16106
16107 return $module.data(metadata.title) || settings.title;
16108 },
16109 content: function (fallback) {
16110 $module.removeData(metadata.content);
16111
16112 return $module.data(metadata.content) || settings.content || fallback;
16113 },
16114 variation: function () {
16115 $module.removeData(metadata.variation);
16116
16117 return $module.data(metadata.variation) || settings.variation;
16118 },
16119 popup: function () {
16120 return $popup;
16121 },
16122 popupOffset: function () {
16123 return $popup.offset();
16124 },
16125 calculations: function () {
16126 var
16127 $popupOffsetParent = module.get.offsetParent($popup),
16128 targetElement = $target[0],
16129 isWindowEl = $boundary[0] === window,
16130 targetOffset = $target.offset(),
16131 parentOffset = settings.inline || (settings.popup && settings.movePopup)
16132 ? $target.offsetParent().offset()
16133 : { top: 0, left: 0 },
16134 screenPosition = isWindowEl
16135 ? { top: 0, left: 0 }
16136 : $boundary.offset(),
16137 calculations = {},
16138 scroll = isWindowEl
16139 ? { top: $window.scrollTop(), left: $window.scrollLeft() }
16140 : { top: 0, left: 0 },
16141 screen
16142 ;
16143 calculations = {
16144 // element which is launching popup
16145 target: {
16146 element: $target[0],
16147 width: $target.outerWidth(),
16148 height: $target.outerHeight(),
16149 top: targetOffset.top - parentOffset.top,
16150 left: targetOffset.left - parentOffset.left,
16151 margin: {},
16152 },
16153 // popup itself
16154 popup: {
16155 width: $popup.outerWidth(),
16156 height: $popup.outerHeight(),
16157 },
16158 // offset container (or 3d context)
16159 parent: {
16160 width: $offsetParent.outerWidth(),
16161 height: $offsetParent.outerHeight(),
16162 },
16163 // screen boundaries
16164 screen: {
16165 top: screenPosition.top,
16166 left: screenPosition.left,
16167 scroll: {
16168 top: scroll.top,
16169 left: scroll.left,
16170 },
16171 width: $boundary.width(),
16172 height: $boundary.height(),
16173 },
16174 };
16175
16176 // if popup offset context is not same as target, then adjust calculations
16177 if ($popupOffsetParent[0] !== $offsetParent[0]) {
16178 var
16179 popupOffset = $popupOffsetParent.offset()
16180 ;
16181 calculations.target.top -= popupOffset.top;
16182 calculations.target.left -= popupOffset.left;
16183 calculations.parent.width = $popupOffsetParent.outerWidth();
16184 calculations.parent.height = $popupOffsetParent.outerHeight();
16185 }
16186
16187 // add in container calcs if fluid
16188 if (settings.setFluidWidth && module.is.fluid()) {
16189 calculations.container = {
16190 width: $popup.parent().outerWidth(),
16191 };
16192 calculations.popup.width = calculations.container.width;
16193 }
16194
16195 // add in margins if inline
16196 calculations.target.margin.top = settings.inline
16197 ? parseInt(window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10)
16198 : 0;
16199 calculations.target.margin.left = settings.inline
16200 ? (module.is.rtl()
16201 ? parseInt(window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10)
16202 : parseInt(window.getComputedStyle(targetElement).getPropertyValue('margin-left'), 10))
16203 : 0;
16204 // calculate screen boundaries
16205 screen = calculations.screen;
16206 calculations.boundary = {
16207 top: screen.top + screen.scroll.top,
16208 bottom: screen.top + screen.scroll.top + screen.height,
16209 left: screen.left + screen.scroll.left,
16210 right: screen.left + screen.scroll.left + screen.width,
16211 };
16212
16213 return calculations;
16214 },
16215 id: function () {
16216 return id;
16217 },
16218 startEvent: function () {
16219 if (settings.on === 'hover') {
16220 return 'mouseenter';
16221 }
16222 if (settings.on === 'focus') {
16223 return 'focus';
16224 }
16225
16226 return false;
16227 },
16228 scrollEvent: function () {
16229 return 'scroll';
16230 },
16231 endEvent: function () {
16232 if (settings.on === 'hover') {
16233 return 'mouseleave';
16234 }
16235 if (settings.on === 'focus') {
16236 return 'blur';
16237 }
16238
16239 return false;
16240 },
16241 distanceFromBoundary: function (offset, calculations) {
16242 var
16243 distanceFromBoundary = {},
16244 popup,
16245 boundary
16246 ;
16247 calculations = calculations || module.get.calculations();
16248
16249 // shorthand
16250 popup = calculations.popup;
16251 boundary = calculations.boundary;
16252
16253 if (offset) {
16254 distanceFromBoundary = {
16255 top: offset.top - boundary.top,
16256 left: offset.left - boundary.left,
16257 right: boundary.right - (offset.left + popup.width),
16258 bottom: boundary.bottom - (offset.top + popup.height),
16259 };
16260 module.verbose('Distance from boundaries determined', offset, distanceFromBoundary);
16261 }
16262
16263 return distanceFromBoundary;
16264 },
16265 offsetParent: function ($element) {
16266 var
16267 element = $element !== undefined
16268 ? $element[0]
16269 : $target[0],
16270 parentNode = element.parentNode,
16271 $node = $(parentNode)
16272 ;
16273 if (parentNode) {
16274 var
16275 is2D = $node.css('transform') === 'none',
16276 isStatic = $node.css('position') === 'static',
16277 isBody = $node.is('body')
16278 ;
16279 while (parentNode && !isBody && isStatic && is2D) {
16280 parentNode = parentNode.parentNode;
16281 $node = $(parentNode);
16282 is2D = $node.css('transform') === 'none';
16283 isStatic = $node.css('position') === 'static';
16284 isBody = $node.is('body');
16285 }
16286 }
16287
16288 return $node && $node.length > 0
16289 ? $node
16290 : $();
16291 },
16292 positions: function () {
16293 return {
16294 'top left': false,
16295 'top center': false,
16296 'top right': false,
16297 'bottom left': false,
16298 'bottom center': false,
16299 'bottom right': false,
16300 'left center': false,
16301 'right center': false,
16302 };
16303 },
16304 nextPosition: function (position) {
16305 var
16306 positions = position.split(' '),
16307 verticalPosition = positions[0],
16308 horizontalPosition = positions[1],
16309 opposite = {
16310 top: 'bottom',
16311 bottom: 'top',
16312 left: 'right',
16313 right: 'left',
16314 },
16315 adjacent = {
16316 left: 'center',
16317 center: 'right',
16318 right: 'left',
16319 },
16320 backup = {
16321 'top left': 'top center',
16322 'top center': 'top right',
16323 'top right': 'right center',
16324 'right center': 'bottom right',
16325 'bottom right': 'bottom center',
16326 'bottom center': 'bottom left',
16327 'bottom left': 'left center',
16328 'left center': 'top left',
16329 },
16330 adjacentsAvailable = verticalPosition === 'top' || verticalPosition === 'bottom',
16331 oppositeTried = false,
16332 adjacentTried = false,
16333 nextPosition = false
16334 ;
16335 if (!triedPositions) {
16336 module.verbose('All available positions available');
16337 triedPositions = module.get.positions();
16338 }
16339
16340 module.debug('Recording last position tried', position);
16341 triedPositions[position] = true;
16342
16343 if (settings.prefer === 'opposite') {
16344 nextPosition = [opposite[verticalPosition], horizontalPosition];
16345 nextPosition = nextPosition.join(' ');
16346 oppositeTried = triedPositions[nextPosition] === true;
16347 module.debug('Trying opposite strategy', nextPosition);
16348 }
16349 if ((settings.prefer === 'adjacent') && adjacentsAvailable) {
16350 nextPosition = [verticalPosition, adjacent[horizontalPosition]];
16351 nextPosition = nextPosition.join(' ');
16352 adjacentTried = triedPositions[nextPosition] === true;
16353 module.debug('Trying adjacent strategy', nextPosition);
16354 }
16355 if (adjacentTried || oppositeTried) {
16356 module.debug('Using backup position', nextPosition);
16357 nextPosition = backup[position];
16358 }
16359
16360 return nextPosition;
16361 },
16362 },
16363
16364 set: {
16365 position: function (position, calculations) {
16366 // exit conditions
16367 if ($target.length === 0 || $popup.length === 0) {
16368 module.error(error.notFound);
16369
16370 return;
16371 }
16372 var
16373 offset,
16374 distanceAway,
16375 target,
16376 popup,
16377 parent,
16378 positioning,
16379 popupOffset,
16380 distanceFromBoundary
16381 ;
16382
16383 calculations = calculations || module.get.calculations();
16384 position = position || $module.data(metadata.position) || settings.position;
16385
16386 offset = $module.data(metadata.offset) || settings.offset;
16387 distanceAway = settings.distanceAway;
16388
16389 // shorthand
16390 target = calculations.target;
16391 popup = calculations.popup;
16392 parent = calculations.parent;
16393
16394 if (module.should.centerArrow(calculations)) {
16395 module.verbose('Adjusting offset to center arrow on small target element');
16396 if (position === 'top left' || position === 'bottom left') {
16397 offset += target.width / 2;
16398 offset -= settings.arrowPixelsFromEdge;
16399 }
16400 if (position === 'top right' || position === 'bottom right') {
16401 offset -= target.width / 2;
16402 offset += settings.arrowPixelsFromEdge;
16403 }
16404 }
16405
16406 if (target.width === 0 && target.height === 0 && !module.is.svg(target.element)) {
16407 module.debug('Popup target is hidden, no action taken');
16408
16409 return false;
16410 }
16411
16412 if (settings.inline) {
16413 module.debug('Adding margin to calculation', target.margin);
16414 if (position === 'left center' || position === 'right center') {
16415 offset += target.margin.top;
16416 distanceAway += -target.margin.left;
16417 } else if (position === 'top left' || position === 'top center' || position === 'top right') {
16418 offset += target.margin.left;
16419 distanceAway -= target.margin.top;
16420 } else {
16421 offset += target.margin.left;
16422 distanceAway += target.margin.top;
16423 }
16424 }
16425
16426 module.debug('Determining popup position from calculations', position, calculations);
16427
16428 if (module.is.rtl()) {
16429 position = position.replace(/left|right/g, function (match) {
16430 return match === 'left'
16431 ? 'right'
16432 : 'left';
16433 });
16434 module.debug('RTL: Popup position updated', position);
16435 }
16436
16437 // if last attempt use specified last resort position
16438 if (searchDepth === settings.maxSearchDepth && typeof settings.lastResort === 'string') {
16439 position = settings.lastResort;
16440 }
16441
16442 switch (position) {
16443 case 'top left': {
16444 positioning = {
16445 top: 'auto',
16446 bottom: parent.height - target.top + distanceAway,
16447 left: target.left + offset,
16448 right: 'auto',
16449 };
16450
16451 break;
16452 }
16453 case 'top center': {
16454 positioning = {
16455 bottom: parent.height - target.top + distanceAway,
16456 left: target.left + (target.width / 2) - (popup.width / 2) + offset,
16457 top: 'auto',
16458 right: 'auto',
16459 };
16460
16461 break;
16462 }
16463 case 'top right': {
16464 positioning = {
16465 bottom: parent.height - target.top + distanceAway,
16466 right: parent.width - target.left - target.width - offset,
16467 top: 'auto',
16468 left: 'auto',
16469 };
16470
16471 break;
16472 }
16473 case 'left center': {
16474 positioning = {
16475 top: target.top + (target.height / 2) - (popup.height / 2) + offset,
16476 right: parent.width - target.left + distanceAway,
16477 left: 'auto',
16478 bottom: 'auto',
16479 };
16480
16481 break;
16482 }
16483 case 'right center': {
16484 positioning = {
16485 top: target.top + (target.height / 2) - (popup.height / 2) + offset,
16486 left: target.left + target.width + distanceAway,
16487 bottom: 'auto',
16488 right: 'auto',
16489 };
16490
16491 break;
16492 }
16493 case 'bottom left': {
16494 positioning = {
16495 top: target.top + target.height + distanceAway,
16496 left: target.left + offset,
16497 bottom: 'auto',
16498 right: 'auto',
16499 };
16500
16501 break;
16502 }
16503 case 'bottom center': {
16504 positioning = {
16505 top: target.top + target.height + distanceAway,
16506 left: target.left + (target.width / 2) - (popup.width / 2) + offset,
16507 bottom: 'auto',
16508 right: 'auto',
16509 };
16510
16511 break;
16512 }
16513 case 'bottom right': {
16514 positioning = {
16515 top: target.top + target.height + distanceAway,
16516 right: parent.width - target.left - target.width - offset,
16517 left: 'auto',
16518 bottom: 'auto',
16519 };
16520
16521 break;
16522 }
16523 }
16524 if (positioning === undefined) {
16525 module.error(error.invalidPosition, position);
16526 }
16527
16528 module.debug('Calculated popup positioning values', positioning);
16529
16530 // tentatively place on stage
16531 $popup
16532 .css(positioning)
16533 .removeClass(className.position)
16534 .addClass(position)
16535 ;
16536 module.set.invisible();
16537
16538 popupOffset = module.get.popupOffset();
16539
16540 // see if any boundaries are surpassed with this tentative position
16541 distanceFromBoundary = module.get.distanceFromBoundary(popupOffset, calculations);
16542
16543 if (!settings.forcePosition && module.is.offstage(distanceFromBoundary, position)) {
16544 module.debug('Position is outside viewport', position);
16545 if (searchDepth < settings.maxSearchDepth) {
16546 searchDepth++;
16547 position = module.get.nextPosition(position);
16548 module.debug('Trying new position', position);
16549
16550 return $popup
16551 ? module.set.position(position, calculations)
16552 : false;
16553 }
16554 if (settings.lastResort) {
16555 module.debug('No position found, showing with last position');
16556 } else {
16557 module.debug('Popup could not find a position to display', $popup);
16558 module.error(error.cannotPlace, element);
16559 module.remove.attempts();
16560 module.remove.invisible();
16561 module.reset();
16562 settings.onUnplaceable.call($popup, element);
16563
16564 return false;
16565 }
16566 }
16567 module.debug('Position is on stage', position);
16568 module.remove.attempts();
16569 module.remove.invisible();
16570 if (settings.setFluidWidth && module.is.fluid()) {
16571 module.set.fluidWidth(calculations);
16572 }
16573
16574 return true;
16575 },
16576
16577 fluidWidth: function (calculations) {
16578 calculations = calculations || module.get.calculations();
16579 module.debug('Automatically setting element width to parent width', calculations.parent.width);
16580 $popup.css('width', calculations.container.width);
16581 },
16582
16583 loading: function () {
16584 $popup.addClass(className.loading);
16585 },
16586
16587 invisible: function () {
16588 $popup.addClass(className.invisible);
16589 },
16590
16591 variation: function (variation) {
16592 variation = variation || module.get.variation();
16593 if (variation && module.has.popup()) {
16594 module.verbose('Adding variation to popup', variation);
16595 $popup.addClass(variation);
16596 }
16597 },
16598
16599 visible: function () {
16600 $module.addClass(className.visible);
16601 },
16602 },
16603
16604 remove: {
16605 loading: function () {
16606 $popup.removeClass(className.loading);
16607 },
16608 invisible: function () {
16609 $popup.removeClass(className.invisible);
16610 },
16611 variation: function (variation) {
16612 variation = variation || module.get.variation();
16613 if (variation) {
16614 module.verbose('Removing variation', variation);
16615 $popup.removeClass(variation);
16616 }
16617 },
16618 visible: function () {
16619 $module.removeClass(className.visible);
16620 },
16621 attempts: function () {
16622 module.verbose('Resetting all searched positions');
16623 searchDepth = 0;
16624 triedPositions = false;
16625 },
16626 },
16627
16628 bind: {
16629 events: function () {
16630 module.debug('Binding popup events to module');
16631 if (settings.on === 'click') {
16632 $module
16633 .on(clickEvent + eventNamespace, module.toggle)
16634 ;
16635 }
16636 if (settings.on === 'hover') {
16637 $module
16638 .on('touchstart' + eventNamespace, module.event.touchstart)
16639 ;
16640 }
16641 if (module.get.startEvent()) {
16642 $module
16643 .on(module.get.startEvent() + eventNamespace, module.event.start)
16644 .on(module.get.endEvent() + eventNamespace, module.event.end)
16645 ;
16646 }
16647 if (settings.target) {
16648 module.debug('Target set to element', $target);
16649 }
16650 $window.on('resize' + elementNamespace, module.event.resize);
16651 },
16652 popup: function () {
16653 module.verbose('Allowing hover events on popup to prevent closing');
16654 if ($popup && module.has.popup()) {
16655 $popup
16656 .on('mouseenter' + eventNamespace, module.event.start)
16657 .on('mouseleave' + eventNamespace, module.event.end)
16658 ;
16659 }
16660 },
16661 close: function () {
16662 if (settings.hideOnScroll === true || (settings.hideOnScroll === 'auto' && settings.on !== 'click')) {
16663 module.bind.closeOnScroll();
16664 }
16665 if (module.is.closable()) {
16666 module.bind.clickaway();
16667 } else if (settings.on === 'hover' && openedWithTouch) {
16668 module.bind.touchClose();
16669 }
16670 },
16671 closeOnScroll: function () {
16672 module.verbose('Binding scroll close event to document');
16673 $scrollContext
16674 .one(module.get.scrollEvent() + elementNamespace, module.event.hideGracefully)
16675 ;
16676 },
16677 touchClose: function () {
16678 module.verbose('Binding popup touchclose event to document');
16679 $document
16680 .on('touchstart' + elementNamespace, function (event) {
16681 module.verbose('Touched away from popup');
16682 module.event.hideGracefully.call(element, event);
16683 })
16684 ;
16685 },
16686 clickaway: function () {
16687 module.verbose('Binding popup close event to document');
16688 $document
16689 .on(clickEvent + elementNamespace, function (event) {
16690 module.verbose('Clicked away from popup');
16691 module.event.hideGracefully.call(element, event);
16692 })
16693 ;
16694 },
16695 },
16696
16697 unbind: {
16698 events: function () {
16699 $window
16700 .off(elementNamespace)
16701 ;
16702 $module
16703 .off(eventNamespace)
16704 ;
16705 },
16706 close: function () {
16707 $document
16708 .off(elementNamespace)
16709 ;
16710 $scrollContext
16711 .off(elementNamespace)
16712 ;
16713 },
16714 },
16715
16716 can: {
16717 useElement: function (element) {
16718 if ($.fn[element] !== undefined) {
16719 return true;
16720 }
16721 module.error(error.noElement.replace('{element}', element));
16722
16723 return false;
16724 },
16725 },
16726
16727 has: {
16728 popup: function () {
16729 return $popup && $popup.length > 0;
16730 },
16731 },
16732
16733 should: {
16734 centerArrow: function (calculations) {
16735 return !module.is.basic() && calculations.target.width <= (settings.arrowPixelsFromEdge * 2);
16736 },
16737 },
16738
16739 is: {
16740 closable: function () {
16741 if (settings.closable === 'auto') {
16742 return settings.on !== 'hover';
16743 }
16744
16745 return settings.closable;
16746 },
16747 offstage: function (distanceFromBoundary, position) {
16748 var
16749 offstage = []
16750 ;
16751 // return boundaries that have been surpassed
16752 $.each(distanceFromBoundary, function (direction, distance) {
16753 if (distance < -settings.jitter) {
16754 module.debug('Position exceeds allowable distance from edge', direction, distance, position);
16755 offstage.push(direction);
16756 }
16757 });
16758
16759 return offstage.length > 0;
16760 },
16761 svg: function (element) {
16762 return module.supports.svg() && (element instanceof SVGGraphicsElement);
16763 },
16764 basic: function () {
16765 return $module.hasClass(className.basic);
16766 },
16767 active: function () {
16768 return $module.hasClass(className.active);
16769 },
16770 animating: function () {
16771 return $popup !== undefined && $popup.hasClass(className.animating);
16772 },
16773 fluid: function () {
16774 return $popup !== undefined && $popup.hasClass(className.fluid);
16775 },
16776 visible: function () {
16777 return $popup !== undefined && $popup.hasClass(className.popupVisible);
16778 },
16779 dropdown: function () {
16780 return $module.hasClass(className.dropdown);
16781 },
16782 hidden: function () {
16783 return !module.is.visible();
16784 },
16785 rtl: function () {
16786 return $module.attr('dir') === 'rtl' || $module.css('direction') === 'rtl' || $body.attr('dir') === 'rtl' || $body.css('direction') === 'rtl' || $context.attr('dir') === 'rtl' || $context.css('direction') === 'rtl';
16787 },
16788 },
16789
16790 reset: function () {
16791 module.remove.visible();
16792 if (settings.preserve) {
16793 if ($.fn.transition !== undefined) {
16794 $popup
16795 .transition('remove transition')
16796 ;
16797 }
16798 } else {
16799 module.removePopup();
16800 }
16801 },
16802
16803 setting: function (name, value) {
16804 if ($.isPlainObject(name)) {
16805 $.extend(true, settings, name);
16806 } else if (value !== undefined) {
16807 settings[name] = value;
16808 } else {
16809 return settings[name];
16810 }
16811 },
16812 internal: function (name, value) {
16813 if ($.isPlainObject(name)) {
16814 $.extend(true, module, name);
16815 } else if (value !== undefined) {
16816 module[name] = value;
16817 } else {
16818 return module[name];
16819 }
16820 },
16821 debug: function () {
16822 if (!settings.silent && settings.debug) {
16823 if (settings.performance) {
16824 module.performance.log(arguments);
16825 } else {
16826 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
16827 module.debug.apply(console, arguments);
16828 }
16829 }
16830 },
16831 verbose: function () {
16832 if (!settings.silent && settings.verbose && settings.debug) {
16833 if (settings.performance) {
16834 module.performance.log(arguments);
16835 } else {
16836 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
16837 module.verbose.apply(console, arguments);
16838 }
16839 }
16840 },
16841 error: function () {
16842 if (!settings.silent) {
16843 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
16844 module.error.apply(console, arguments);
16845 }
16846 },
16847 performance: {
16848 log: function (message) {
16849 var
16850 currentTime,
16851 executionTime,
16852 previousTime
16853 ;
16854 if (settings.performance) {
16855 currentTime = Date.now();
16856 previousTime = time || currentTime;
16857 executionTime = currentTime - previousTime;
16858 time = currentTime;
16859 performance.push({
16860 Name: message[0],
16861 Arguments: [].slice.call(message, 1) || '',
16862 Element: element,
16863 'Execution Time': executionTime,
16864 });
16865 }
16866 clearTimeout(module.performance.timer);
16867 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
16868 },
16869 display: function () {
16870 var
16871 title = settings.name + ':',
16872 totalTime = 0
16873 ;
16874 time = false;
16875 clearTimeout(module.performance.timer);
16876 $.each(performance, function (index, data) {
16877 totalTime += data['Execution Time'];
16878 });
16879 title += ' ' + totalTime + 'ms';
16880 if (performance.length > 0) {
16881 console.groupCollapsed(title);
16882 if (console.table) {
16883 console.table(performance);
16884 } else {
16885 $.each(performance, function (index, data) {
16886 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
16887 });
16888 }
16889 console.groupEnd();
16890 }
16891 performance = [];
16892 },
16893 },
16894 invoke: function (query, passedArguments, context) {
16895 var
16896 object = instance,
16897 maxDepth,
16898 found,
16899 response
16900 ;
16901 passedArguments = passedArguments || queryArguments;
16902 context = context || element;
16903 if (typeof query === 'string' && object !== undefined) {
16904 query = query.split(/[ .]/);
16905 maxDepth = query.length - 1;
16906 $.each(query, function (depth, value) {
16907 var camelCaseValue = depth !== maxDepth
16908 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
16909 : query
16910 ;
16911 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
16912 object = object[camelCaseValue];
16913 } else if (object[camelCaseValue] !== undefined) {
16914 found = object[camelCaseValue];
16915
16916 return false;
16917 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
16918 object = object[value];
16919 } else if (object[value] !== undefined) {
16920 found = object[value];
16921
16922 return false;
16923 } else {
16924 module.error(error.method, query);
16925
16926 return false;
16927 }
16928 });
16929 }
16930 if (isFunction(found)) {
16931 response = found.apply(context, passedArguments);
16932 } else if (found !== undefined) {
16933 response = found;
16934 }
16935 if (Array.isArray(returnedValue)) {
16936 returnedValue.push(response);
16937 } else if (returnedValue !== undefined) {
16938 returnedValue = [returnedValue, response];
16939 } else if (response !== undefined) {
16940 returnedValue = response;
16941 }
16942
16943 return found;
16944 },
16945 };
16946
16947 if (methodInvoked) {
16948 if (instance === undefined) {
16949 module.initialize();
16950 }
16951 module.invoke(query);
16952 } else {
16953 if (instance !== undefined) {
16954 instance.invoke('destroy');
16955 }
16956 module.initialize();
16957 }
16958 });
16959
16960 return returnedValue !== undefined
16961 ? returnedValue
16962 : this;
16963 };
16964
16965 $.fn.popup.settings = {
16966
16967 name: 'Popup',
16968
16969 // module settings
16970 silent: false,
16971 debug: false,
16972 verbose: false,
16973 performance: true,
16974 namespace: 'popup',
16975
16976 // whether it should use dom mutation observers
16977 observeChanges: true,
16978
16979 // callback only when element added to dom
16980 onCreate: function () {},
16981
16982 // callback before element removed from dom
16983 onRemove: function () {},
16984
16985 // callback before show animation
16986 onShow: function () {},
16987
16988 // callback after show animation
16989 onVisible: function () {},
16990
16991 // callback before hide animation
16992 onHide: function () {},
16993
16994 // callback when popup cannot be positioned in visible screen
16995 onUnplaceable: function () {},
16996
16997 // callback after hide animation
16998 onHidden: function () {},
16999
17000 // when to show popup
17001 on: 'hover',
17002
17003 // element to use to determine if popup is out of boundary
17004 boundary: window,
17005
17006 // whether to add touchstart events when using hover
17007 addTouchEvents: true,
17008
17009 // default position relative to element
17010 position: 'top left',
17011
17012 // if given position should be used regardless if popup fits
17013 forcePosition: false,
17014
17015 // name of variation to use
17016 variation: '',
17017
17018 // whether popup should be moved to context
17019 movePopup: true,
17020
17021 // element which popup should be relative to
17022 target: false,
17023
17024 // jq selector or element that should be used as popup
17025 popup: false,
17026
17027 // popup should remain inline next to activator
17028 inline: false,
17029
17030 // popup should be removed from page on hide
17031 preserve: false,
17032
17033 // popup should not close when being hovered on
17034 hoverable: false,
17035
17036 // explicitly set content
17037 content: false,
17038
17039 // explicitly set html
17040 html: false,
17041
17042 // explicitly set title
17043 title: false,
17044
17045 // whether automatically close on clickaway when on click
17046 closable: true,
17047
17048 // automatically hide on scroll
17049 hideOnScroll: 'auto',
17050
17051 // hide other popups on show
17052 exclusive: false,
17053
17054 // context to attach popups
17055 context: 'body',
17056
17057 // context for binding scroll events
17058 scrollContext: window,
17059
17060 // position to prefer when calculating new position
17061 prefer: 'opposite',
17062
17063 // specify position to appear even if it doesn't fit
17064 lastResort: false,
17065
17066 // number of pixels from edge of popup to pointing arrow center (used from centering)
17067 arrowPixelsFromEdge: 20,
17068
17069 // delay used to prevent accidental refiring of animations due to user error
17070 delay: {
17071 show: 50,
17072 hide: 70,
17073 },
17074
17075 // whether fluid variation should assign width explicitly
17076 setFluidWidth: true,
17077
17078 // transition settings
17079 duration: 200,
17080 transition: 'scale',
17081
17082 // distance away from activating element in px
17083 distanceAway: 0,
17084
17085 // number of pixels an element is allowed to be "offstage" for a position to be chosen (allows for rounding)
17086 jitter: 2,
17087
17088 // offset on aligning axis from calculated position
17089 offset: 0,
17090
17091 // maximum times to look for a position before failing (9 positions total)
17092 maxSearchDepth: 15,
17093
17094 error: {
17095 invalidPosition: 'The position you specified is not a valid position',
17096 cannotPlace: 'Popup does not fit within the boundaries of the viewport',
17097 method: 'The method you called is not defined.',
17098 noElement: 'This module requires ui {element}',
17099 notFound: 'The target or popup you specified does not exist on the page',
17100 },
17101
17102 metadata: {
17103 activator: 'activator',
17104 content: 'content',
17105 html: 'html',
17106 offset: 'offset',
17107 position: 'position',
17108 title: 'title',
17109 variation: 'variation',
17110 },
17111
17112 className: {
17113 active: 'active',
17114 basic: 'basic',
17115 animating: 'animating',
17116 dropdown: 'dropdown',
17117 invisible: 'invisible',
17118 fluid: 'fluid',
17119 loading: 'loading',
17120 popup: 'ui popup',
17121 position: 'top left center bottom right',
17122 visible: 'visible',
17123 popupVisible: 'visible',
17124 },
17125
17126 selector: {
17127 popup: '.ui.popup',
17128 },
17129
17130 templates: {
17131 escape: function (string) {
17132 var
17133 badChars = /["'<>`]/g,
17134 shouldEscape = /["&'<>`]/,
17135 escape = {
17136 '<': '&lt;',
17137 '>': '&gt;',
17138 '"': '&quot;',
17139 "'": '&#x27;',
17140 '`': '&#x60;',
17141 },
17142 escapedChar = function (chr) {
17143 return escape[chr];
17144 }
17145 ;
17146 if (shouldEscape.test(string)) {
17147 string = string.replace(/&(?![\d#a-z]{1,12};)/gi, '&amp;');
17148
17149 return string.replace(badChars, escapedChar);
17150 }
17151
17152 return string;
17153 },
17154 popup: function (text) {
17155 var
17156 html = '',
17157 escape = $.fn.popup.settings.templates.escape
17158 ;
17159 if (text !== undefined) {
17160 if (text.title) {
17161 text.title = escape(text.title);
17162 html += '<div class="header">' + text.title + '</div>';
17163 }
17164 if (text.content) {
17165 text.content = escape(text.content);
17166 html += '<div class="content">' + text.content + '</div>';
17167 }
17168 }
17169
17170 return html;
17171 },
17172 },
17173
17174 };
17175})(jQuery, window, document);
17176
17177/*!
17178 * # Fomantic-UI 2.9.3 - Progress
17179 * https://github.com/fomantic/Fomantic-UI/
17180 *
17181 *
17182 * Released under the MIT license
17183 * https://opensource.org/licenses/MIT
17184 *
17185 */
17186
17187(function ($, window, document) {
17188 'use strict';
17189
17190 function isFunction(obj) {
17191 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
17192 }
17193
17194 window = window !== undefined && window.Math === Math
17195 ? window
17196 : globalThis;
17197
17198 $.fn.progress = function (parameters) {
17199 var
17200 $allModules = $(this),
17201
17202 time = Date.now(),
17203 performance = [],
17204
17205 query = arguments[0],
17206 methodInvoked = typeof query === 'string',
17207 queryArguments = [].slice.call(arguments, 1),
17208
17209 returnedValue
17210 ;
17211
17212 $allModules.each(function () {
17213 var
17214 settings = $.isPlainObject(parameters)
17215 ? $.extend(true, {}, $.fn.progress.settings, parameters)
17216 : $.extend({}, $.fn.progress.settings),
17217
17218 className = settings.className,
17219 metadata = settings.metadata,
17220 namespace = settings.namespace,
17221 selector = settings.selector,
17222 error = settings.error,
17223
17224 eventNamespace = '.' + namespace,
17225 moduleNamespace = 'module-' + namespace,
17226
17227 $module = $(this),
17228 $bars = $(this).find(selector.bar),
17229 $progresses = $(this).find(selector.progress),
17230 $label = $(this).find(selector.label),
17231
17232 element = this,
17233 instance = $module.data(moduleNamespace),
17234
17235 animating = false,
17236 module
17237 ;
17238 module = {
17239 helper: {
17240 sum: function (nums) {
17241 return Array.isArray(nums) ? nums.reduce(function (left, right) {
17242 return left + Number(right);
17243 }, 0) : 0;
17244 },
17245 /**
17246 * Derive precision for multiple progress with total and values.
17247 *
17248 * This helper dervices a precision that is sufficiently large to show minimum value of multiple progress.
17249 *
17250 * Example1
17251 * - total: 1122
17252 * - values: [325, 111, 74, 612]
17253 * - min ratio: 74/1122 = 0.0659...
17254 * - required precision: 100
17255 *
17256 * Example2
17257 * - total: 10541
17258 * - values: [3235, 1111, 74, 6121]
17259 * - min ratio: 74/10541 = 0.0070...
17260 * - required precision: 1000
17261 *
17262 * @param min A minimum value within multiple values
17263 * @param total A total amount of multiple values
17264 * @returns {number} A precision. Could be 1, 10, 100, ... 1e+10.
17265 */
17266 derivePrecision: function (min, total) {
17267 var precisionPower = 0;
17268 var precision = 1;
17269 var ratio = min / total;
17270 while (precisionPower < 10) {
17271 ratio *= precision;
17272 if (ratio > 1) {
17273 break;
17274 }
17275 precision = Math.pow(10, precisionPower++);
17276 }
17277
17278 return precision;
17279 },
17280 forceArray: function (element) {
17281 return Array.isArray(element)
17282 ? element
17283 : (!isNaN(element)
17284 ? [element]
17285 : (typeof element === 'string' ? element.split(',') : [])); // eslint-disable-line unicorn/no-nested-ternary
17286 },
17287 },
17288
17289 initialize: function () {
17290 module.set.duration();
17291 module.debug(element);
17292
17293 module.read.metadata();
17294 module.read.settings();
17295
17296 module.instantiate();
17297 },
17298
17299 instantiate: function () {
17300 module.verbose('Storing instance of progress', module);
17301 instance = module;
17302 $module
17303 .data(moduleNamespace, module)
17304 ;
17305 },
17306 destroy: function () {
17307 module.verbose('Destroying previous progress for', $module);
17308 clearInterval(instance.interval);
17309 module.remove.state();
17310 $module.removeData(moduleNamespace);
17311 instance = undefined;
17312 },
17313
17314 reset: function () {
17315 module.remove.nextValue();
17316 module.update.progress(0);
17317 },
17318
17319 complete: function (keepState) {
17320 if (module.percent === undefined || module.percent < 100) {
17321 module.remove.progressPoll();
17322 if (keepState !== true) {
17323 module.set.percent(100);
17324 }
17325 }
17326 },
17327
17328 read: {
17329 metadata: function () {
17330 var
17331 data = {
17332 percent: module.helper.forceArray($module.data(metadata.percent)),
17333 total: $module.data(metadata.total),
17334 value: module.helper.forceArray($module.data(metadata.value)),
17335 }
17336 ;
17337 if (data.total !== undefined) {
17338 module.debug('Total value set from metadata', data.total);
17339 module.set.total(data.total);
17340 }
17341 if (data.value.length > 0) {
17342 module.debug('Current value set from metadata', data.value);
17343 module.set.value(data.value);
17344 module.set.progress(data.value);
17345 }
17346 if (data.percent.length > 0) {
17347 module.debug('Current percent value set from metadata', data.percent);
17348 module.set.percent(data.percent);
17349 }
17350 },
17351 settings: function () {
17352 if (settings.total !== false) {
17353 module.debug('Current total set in settings', settings.total);
17354 module.set.total(settings.total);
17355 }
17356 if (settings.value !== false) {
17357 module.debug('Current value set in settings', settings.value);
17358 module.set.value(settings.value);
17359 module.set.progress(module.value);
17360 }
17361 if (settings.percent !== false) {
17362 module.debug('Current percent set in settings', settings.percent);
17363 module.set.percent(settings.percent);
17364 }
17365 },
17366 },
17367
17368 bind: {
17369 transitionEnd: function (callback) {
17370 $bars
17371 .one('transitionend' + eventNamespace, function (event) {
17372 clearTimeout(module.failSafeTimer);
17373 callback.call(this, event);
17374 })
17375 ;
17376 module.failSafeTimer = setTimeout(function () {
17377 $bars.triggerHandler('transitionend');
17378 }, settings.duration + settings.failSafeDelay);
17379 module.verbose('Adding fail safe timer', module.timer);
17380 },
17381 },
17382
17383 increment: function (incrementValue) {
17384 var
17385 startValue,
17386 newValue
17387 ;
17388 if (module.has.total()) {
17389 startValue = module.get.value();
17390 incrementValue = incrementValue || 1;
17391 } else {
17392 startValue = module.get.percent();
17393 incrementValue = incrementValue || module.get.randomValue();
17394 }
17395 newValue = startValue + incrementValue;
17396 module.debug('Incrementing percentage by', startValue, newValue, incrementValue);
17397 newValue = module.get.normalizedValue(newValue);
17398 module.set.progress(newValue);
17399 },
17400 decrement: function (decrementValue) {
17401 var
17402 total = module.get.total(),
17403 startValue,
17404 newValue
17405 ;
17406 if (total) {
17407 startValue = module.get.value();
17408 decrementValue = decrementValue || 1;
17409 newValue = startValue - decrementValue;
17410 module.debug('Decrementing value by', decrementValue, startValue);
17411 } else {
17412 startValue = module.get.percent();
17413 decrementValue = decrementValue || module.get.randomValue();
17414 newValue = startValue - decrementValue;
17415 module.debug('Decrementing percentage by', decrementValue, startValue);
17416 }
17417 newValue = module.get.normalizedValue(newValue);
17418 module.set.progress(newValue);
17419 },
17420
17421 has: {
17422 progressPoll: function () {
17423 return module.progressPoll;
17424 },
17425 total: function () {
17426 return module.get.total() !== false;
17427 },
17428 },
17429
17430 get: {
17431 text: function (templateText, index) {
17432 if (!index) {
17433 index = 0;
17434 }
17435
17436 var
17437 value = module.get.value(index),
17438 total = module.get.total(),
17439 percent = animating
17440 ? module.get.displayPercent(index)
17441 : module.get.percent(index),
17442 left = total !== false
17443 ? Math.max(0, total - value)
17444 : 100 - percent
17445 ;
17446 templateText = templateText || '';
17447 templateText = templateText
17448 .replace('{value}', value)
17449 .replace('{total}', total || 0)
17450 .replace('{left}', left)
17451 .replace('{percent}', percent)
17452 .replace('{bar}', settings.text.bars[index] || '')
17453 ;
17454 module.verbose('Adding variables to progress bar text', templateText);
17455
17456 return templateText;
17457 },
17458
17459 normalizedValue: function (value) {
17460 if (value < 0) {
17461 module.debug('Value cannot decrement below 0');
17462
17463 return 0;
17464 }
17465 if (module.has.total()) {
17466 if (value > module.total) {
17467 module.debug('Value cannot increment above total', module.total);
17468
17469 return module.total;
17470 }
17471 } else if (value > 100) {
17472 module.debug('Value cannot increment above 100 percent');
17473
17474 return 100;
17475 }
17476
17477 return value;
17478 },
17479
17480 updateInterval: function () {
17481 if (settings.updateInterval === 'auto') {
17482 return settings.duration;
17483 }
17484
17485 return settings.updateInterval;
17486 },
17487
17488 randomValue: function () {
17489 module.debug('Generating random increment percentage');
17490
17491 return Math.floor((Math.random() * settings.random.max) + settings.random.min);
17492 },
17493
17494 numericValue: function (value) {
17495 return typeof value === 'string'
17496 ? (value.replace(/[^\d.]/g, '') !== ''
17497 ? +value.replace(/[^\d.]/g, '')
17498 : false)
17499 : value;
17500 },
17501
17502 // gets current displayed percentage (if animating values this is the intermediary value)
17503 displayPercent: function (index) {
17504 var
17505 $bar = $($bars[index]),
17506 barWidth = $bar.width(),
17507 totalWidth = $module.width(),
17508 minDisplay = parseInt($bar.css('min-width'), 10),
17509 displayPercent = barWidth > minDisplay
17510 ? (barWidth / totalWidth) * 100
17511 : module.percent
17512 ;
17513
17514 return settings.precision > 0
17515 ? Math.round(displayPercent * (10 * settings.precision)) / (10 * settings.precision)
17516 : Math.round(displayPercent);
17517 },
17518
17519 percent: function (index) {
17520 return (module.percent && module.percent[index || 0]) || 0;
17521 },
17522 value: function (index) {
17523 return module.nextValue || (module.value && module.value[index || 0]) || 0;
17524 },
17525 total: function () {
17526 return module.total !== undefined ? module.total : false;
17527 },
17528 },
17529
17530 create: {
17531 progressPoll: function () {
17532 module.progressPoll = setTimeout(function () {
17533 module.update.toNextValue();
17534 module.remove.progressPoll();
17535 }, module.get.updateInterval());
17536 },
17537 },
17538
17539 is: {
17540 complete: function () {
17541 return module.is.success() || module.is.warning() || module.is.error();
17542 },
17543 success: function () {
17544 return $module.hasClass(className.success);
17545 },
17546 warning: function () {
17547 return $module.hasClass(className.warning);
17548 },
17549 error: function () {
17550 return $module.hasClass(className.error);
17551 },
17552 active: function () {
17553 return $module.hasClass(className.active);
17554 },
17555 visible: function () {
17556 return $module.is(':visible');
17557 },
17558 },
17559
17560 remove: {
17561 progressPoll: function () {
17562 module.verbose('Removing progress poll timer');
17563 if (module.progressPoll) {
17564 clearTimeout(module.progressPoll);
17565 delete module.progressPoll;
17566 }
17567 },
17568 nextValue: function () {
17569 module.verbose('Removing progress value stored for next update');
17570 delete module.nextValue;
17571 },
17572 state: function () {
17573 module.verbose('Removing stored state');
17574 delete module.total;
17575 delete module.percent;
17576 delete module.value;
17577 },
17578 active: function () {
17579 module.verbose('Removing active state');
17580 $module.removeClass(className.active);
17581 },
17582 success: function () {
17583 module.verbose('Removing success state');
17584 $module.removeClass(className.success);
17585 },
17586 warning: function () {
17587 module.verbose('Removing warning state');
17588 $module.removeClass(className.warning);
17589 },
17590 error: function () {
17591 module.verbose('Removing error state');
17592 $module.removeClass(className.error);
17593 },
17594 },
17595
17596 set: {
17597 barWidth: function (values) {
17598 module.debug('set bar width with ', values);
17599 values = module.helper.forceArray(values);
17600 var firstNonZeroIndex = -1;
17601 var lastNonZeroIndex = -1;
17602 var valuesSum = module.helper.sum(values);
17603 var barCounts = $bars.length;
17604 var isMultiple = barCounts > 1;
17605 var percents = values.map(function (value, index) {
17606 var allZero = index === barCounts - 1 && valuesSum === 0;
17607 var $bar = $($bars[index]);
17608 if (value === 0 && isMultiple && !allZero) {
17609 $bar.css('display', 'none');
17610 } else {
17611 if (isMultiple && allZero) {
17612 $bar.css('background', 'transparent');
17613 }
17614 if (firstNonZeroIndex === -1) {
17615 firstNonZeroIndex = index;
17616 }
17617 lastNonZeroIndex = index;
17618 $bar.css({
17619 display: 'block',
17620 width: value + '%',
17621 });
17622 }
17623
17624 return parseFloat(value);
17625 });
17626 values.forEach(function (_, index) {
17627 var $bar = $($bars[index]);
17628 $bar.css({
17629 borderTopLeftRadius: index === firstNonZeroIndex ? '' : '0',
17630 borderBottomLeftRadius: index === firstNonZeroIndex ? '' : '0',
17631 borderTopRightRadius: index === lastNonZeroIndex ? '' : '0',
17632 borderBottomRightRadius: index === lastNonZeroIndex ? '' : '0',
17633 });
17634 });
17635 $module
17636 .attr('data-percent', percents)
17637 ;
17638 },
17639 duration: function (duration) {
17640 duration = duration || settings.duration;
17641 duration = typeof duration === 'number'
17642 ? duration + 'ms'
17643 : duration;
17644 module.verbose('Setting progress bar transition duration', duration);
17645 $bars
17646 .css({
17647 'transition-duration': duration,
17648 })
17649 ;
17650 },
17651 percent: function (percents) {
17652 percents = module.helper.forceArray(percents).map(function (percent) {
17653 percent = typeof percent === 'string'
17654 ? +percent.replace('%', '')
17655 : percent;
17656
17657 return settings.limitValues
17658 ? Math.max(0, Math.min(100, percent))
17659 : percent;
17660 });
17661 var hasTotal = module.has.total();
17662 var totalPercent = module.helper.sum(percents);
17663 var isMultipleValues = percents.length > 1 && hasTotal;
17664 var sumTotal = module.helper.sum(module.helper.forceArray(module.value));
17665 if (isMultipleValues && sumTotal > module.total) {
17666 // Sum values instead of pecents to avoid precision issues when summing floats
17667 module.error(error.sumExceedsTotal, sumTotal, module.total);
17668 } else if (!isMultipleValues && totalPercent > 100) {
17669 // Sum before rounding since sum of rounded may have error though sum of actual is fine
17670 module.error(error.tooHigh, totalPercent);
17671 } else if (totalPercent < 0) {
17672 module.error(error.tooLow, totalPercent);
17673 } else {
17674 var autoPrecision = settings.precision > 0
17675 ? settings.precision
17676 : (isMultipleValues
17677 ? module.helper.derivePrecision(Math.min.apply(null, module.value), module.total)
17678 : 0);
17679
17680 // round display percentage
17681 var roundedPercents = percents.map(function (percent) {
17682 return autoPrecision > 0
17683 ? Math.round(percent * (10 * autoPrecision)) / (10 * autoPrecision)
17684 : Math.round(percent)
17685 ;
17686 });
17687 module.percent = roundedPercents;
17688 if (hasTotal) {
17689 module.value = percents.map(function (percent) {
17690 return autoPrecision > 0
17691 ? Math.round((percent / 100) * module.total * (10 * autoPrecision)) / (10 * autoPrecision)
17692 : Math.round((percent / 100) * module.total * 10) / 10;
17693 });
17694 }
17695 module.set.barWidth(percents);
17696 module.set.labelInterval();
17697 }
17698 settings.onChange.call(element, percents, module.value, module.total);
17699 },
17700 labelInterval: function () {
17701 var
17702 animationCallback = function () {
17703 module.verbose('Bar finished animating, removing continuous label updates');
17704 clearInterval(module.interval);
17705 animating = false;
17706 module.set.labels();
17707 }
17708 ;
17709 clearInterval(module.interval);
17710 module.bind.transitionEnd(animationCallback);
17711 animating = true;
17712 module.interval = setInterval(function () {
17713 var
17714 isInDOM = $.contains(document.documentElement, element)
17715 ;
17716 if (!isInDOM) {
17717 clearInterval(module.interval);
17718 animating = false;
17719 }
17720 module.set.labels();
17721 }, settings.framerate);
17722 },
17723 labels: function () {
17724 module.verbose('Setting both bar progress and outer label text');
17725 module.set.barLabel();
17726 module.set.state();
17727 },
17728 label: function (text) {
17729 if (text) {
17730 text = module.get.text(text);
17731 module.verbose('Setting label to text', text);
17732 $label.text(text);
17733 }
17734 },
17735 state: function (percent) {
17736 percent = percent !== undefined
17737 ? percent
17738 : module.helper.sum(module.percent);
17739 if (percent === 100) {
17740 if (settings.autoSuccess && $bars.length === 1 && !(module.is.warning() || module.is.error() || module.is.success())) {
17741 module.set.success();
17742 module.debug('Automatically triggering success at 100%');
17743 } else {
17744 module.verbose('Reached 100% removing active state');
17745 module.remove.active();
17746 module.remove.progressPoll();
17747 }
17748 } else if (percent > 0) {
17749 module.verbose('Adjusting active progress bar label', percent);
17750 module.set.active();
17751 } else {
17752 module.remove.active();
17753 module.remove.warning();
17754 module.remove.error();
17755 module.remove.success();
17756 module.set.label(settings.text.active);
17757 }
17758 },
17759 barLabel: function (text) {
17760 $progresses.each(function (index, element) {
17761 var $progress = $(element);
17762 if (text !== undefined) {
17763 $progress.text(module.get.text(text, index));
17764 } else if (settings.label === 'ratio' && module.has.total()) {
17765 module.verbose('Adding ratio to bar label');
17766 $progress.text(module.get.text(settings.text.ratio, index));
17767 } else if (settings.label === 'percent') {
17768 module.verbose('Adding percentage to bar label');
17769 $progress.text(module.get.text(settings.text.percent, index));
17770 }
17771 });
17772 },
17773 active: function (text) {
17774 text = text || settings.text.active;
17775 module.debug('Setting active state');
17776 if (settings.showActivity && !module.is.active()) {
17777 $module.addClass(className.active);
17778 }
17779 module.remove.warning();
17780 module.remove.error();
17781 module.remove.success();
17782 text = settings.onLabelUpdate('active', text, module.value, module.total);
17783 if (text) {
17784 module.set.label(text);
17785 }
17786 module.bind.transitionEnd(function () {
17787 settings.onActive.call(element, module.value, module.total);
17788 });
17789 },
17790 success: function (text, keepState) {
17791 text = text || settings.text.success || settings.text.active;
17792 module.debug('Setting success state');
17793 $module.addClass(className.success);
17794 module.remove.active();
17795 module.remove.warning();
17796 module.remove.error();
17797 module.complete(keepState);
17798 if (settings.text.success) {
17799 text = settings.onLabelUpdate('success', text, module.value, module.total);
17800 module.set.label(text);
17801 } else {
17802 text = settings.onLabelUpdate('active', text, module.value, module.total);
17803 module.set.label(text);
17804 }
17805 module.bind.transitionEnd(function () {
17806 settings.onSuccess.call(element, module.total);
17807 });
17808 },
17809 warning: function (text, keepState) {
17810 text = text || settings.text.warning;
17811 module.debug('Setting warning state');
17812 $module.addClass(className.warning);
17813 module.remove.active();
17814 module.remove.success();
17815 module.remove.error();
17816 module.complete(keepState);
17817 text = settings.onLabelUpdate('warning', text, module.value, module.total);
17818 if (text) {
17819 module.set.label(text);
17820 }
17821 module.bind.transitionEnd(function () {
17822 settings.onWarning.call(element, module.value, module.total);
17823 });
17824 },
17825 error: function (text, keepState) {
17826 text = text || settings.text.error;
17827 module.debug('Setting error state');
17828 $module.addClass(className.error);
17829 module.remove.active();
17830 module.remove.success();
17831 module.remove.warning();
17832 module.complete(keepState);
17833 text = settings.onLabelUpdate('error', text, module.value, module.total);
17834 if (text) {
17835 module.set.label(text);
17836 }
17837 module.bind.transitionEnd(function () {
17838 settings.onError.call(element, module.value, module.total);
17839 });
17840 },
17841 total: function (totalValue) {
17842 module.total = totalValue;
17843 },
17844 value: function (value) {
17845 module.value = module.helper.forceArray(value);
17846 },
17847 progress: function (value) {
17848 if (!module.has.progressPoll()) {
17849 module.debug('First update in progress update interval, immediately updating', value);
17850 module.update.progress(value);
17851 module.create.progressPoll();
17852 } else {
17853 module.debug('Updated within interval, setting next update to use new value', value);
17854 module.set.nextValue(value);
17855 }
17856 },
17857 nextValue: function (value) {
17858 module.nextValue = value;
17859 },
17860 },
17861
17862 update: {
17863 toNextValue: function () {
17864 var
17865 nextValue = module.nextValue
17866 ;
17867 if (nextValue) {
17868 module.debug('Update interval complete using last updated value', nextValue);
17869 module.update.progress(nextValue);
17870 module.remove.nextValue();
17871 }
17872 },
17873 progress: function (values) {
17874 var hasTotal = module.has.total();
17875 if (hasTotal) {
17876 module.set.value(values);
17877 }
17878 var percentCompletes = module.helper.forceArray(values).map(function (value) {
17879 var
17880 percentComplete
17881 ;
17882 value = module.get.numericValue(value);
17883 if (value === false) {
17884 module.error(error.nonNumeric, value);
17885 }
17886 value = module.get.normalizedValue(value);
17887 if (hasTotal) {
17888 percentComplete = module.total > 0 ? (value / module.total) * 100 : 100;
17889 module.debug('Calculating percent complete from total', percentComplete);
17890 } else {
17891 percentComplete = value;
17892 module.debug('Setting value to exact percentage value', percentComplete);
17893 }
17894
17895 return percentComplete;
17896 });
17897 module.set.percent(percentCompletes);
17898 },
17899 },
17900
17901 setting: function (name, value) {
17902 module.debug('Changing setting', name, value);
17903 if ($.isPlainObject(name)) {
17904 $.extend(true, settings, name);
17905 } else if (value !== undefined) {
17906 if ($.isPlainObject(settings[name])) {
17907 $.extend(true, settings[name], value);
17908 } else {
17909 settings[name] = value;
17910 }
17911 } else {
17912 return settings[name];
17913 }
17914 },
17915 internal: function (name, value) {
17916 if ($.isPlainObject(name)) {
17917 $.extend(true, module, name);
17918 } else if (value !== undefined) {
17919 module[name] = value;
17920 } else {
17921 return module[name];
17922 }
17923 },
17924 debug: function () {
17925 if (!settings.silent && settings.debug) {
17926 if (settings.performance) {
17927 module.performance.log(arguments);
17928 } else {
17929 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
17930 module.debug.apply(console, arguments);
17931 }
17932 }
17933 },
17934 verbose: function () {
17935 if (!settings.silent && settings.verbose && settings.debug) {
17936 if (settings.performance) {
17937 module.performance.log(arguments);
17938 } else {
17939 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
17940 module.verbose.apply(console, arguments);
17941 }
17942 }
17943 },
17944 error: function () {
17945 if (!settings.silent) {
17946 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
17947 module.error.apply(console, arguments);
17948 }
17949 },
17950 performance: {
17951 log: function (message) {
17952 var
17953 currentTime,
17954 executionTime,
17955 previousTime
17956 ;
17957 if (settings.performance) {
17958 currentTime = Date.now();
17959 previousTime = time || currentTime;
17960 executionTime = currentTime - previousTime;
17961 time = currentTime;
17962 performance.push({
17963 Name: message[0],
17964 Arguments: [].slice.call(message, 1) || '',
17965 Element: element,
17966 'Execution Time': executionTime,
17967 });
17968 }
17969 clearTimeout(module.performance.timer);
17970 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
17971 },
17972 display: function () {
17973 var
17974 title = settings.name + ':',
17975 totalTime = 0
17976 ;
17977 time = false;
17978 clearTimeout(module.performance.timer);
17979 $.each(performance, function (index, data) {
17980 totalTime += data['Execution Time'];
17981 });
17982 title += ' ' + totalTime + 'ms';
17983 if (performance.length > 0) {
17984 console.groupCollapsed(title);
17985 if (console.table) {
17986 console.table(performance);
17987 } else {
17988 $.each(performance, function (index, data) {
17989 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
17990 });
17991 }
17992 console.groupEnd();
17993 }
17994 performance = [];
17995 },
17996 },
17997 invoke: function (query, passedArguments, context) {
17998 var
17999 object = instance,
18000 maxDepth,
18001 found,
18002 response
18003 ;
18004 passedArguments = passedArguments || queryArguments;
18005 context = context || element;
18006 if (typeof query === 'string' && object !== undefined) {
18007 query = query.split(/[ .]/);
18008 maxDepth = query.length - 1;
18009 $.each(query, function (depth, value) {
18010 var camelCaseValue = depth !== maxDepth
18011 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
18012 : query
18013 ;
18014 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
18015 object = object[camelCaseValue];
18016 } else if (object[camelCaseValue] !== undefined) {
18017 found = object[camelCaseValue];
18018
18019 return false;
18020 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
18021 object = object[value];
18022 } else if (object[value] !== undefined) {
18023 found = object[value];
18024
18025 return false;
18026 } else {
18027 module.error(error.method, query);
18028
18029 return false;
18030 }
18031 });
18032 }
18033 if (isFunction(found)) {
18034 response = found.apply(context, passedArguments);
18035 } else if (found !== undefined) {
18036 response = found;
18037 }
18038 if (Array.isArray(returnedValue)) {
18039 returnedValue.push(response);
18040 } else if (returnedValue !== undefined) {
18041 returnedValue = [returnedValue, response];
18042 } else if (response !== undefined) {
18043 returnedValue = response;
18044 }
18045
18046 return found;
18047 },
18048 };
18049
18050 if (methodInvoked) {
18051 if (instance === undefined) {
18052 module.initialize();
18053 }
18054 module.invoke(query);
18055 } else {
18056 if (instance !== undefined) {
18057 instance.invoke('destroy');
18058 }
18059 module.initialize();
18060 }
18061 });
18062
18063 return returnedValue !== undefined
18064 ? returnedValue
18065 : this;
18066 };
18067
18068 $.fn.progress.settings = {
18069
18070 name: 'Progress',
18071 namespace: 'progress',
18072
18073 silent: false,
18074 debug: false,
18075 verbose: false,
18076 performance: true,
18077
18078 random: {
18079 min: 2,
18080 max: 5,
18081 },
18082
18083 duration: 300,
18084
18085 updateInterval: 'auto',
18086
18087 autoSuccess: true,
18088 showActivity: true,
18089 limitValues: true,
18090
18091 label: 'percent',
18092 precision: 0,
18093 framerate: 1000 / 30, /// 30 fps
18094
18095 percent: false,
18096 total: false,
18097 value: false,
18098
18099 // delay in ms for fail safe animation callback
18100 failSafeDelay: 100,
18101
18102 onLabelUpdate: function (state, text, value, total) {
18103 return text;
18104 },
18105 onChange: function (percent, value, total) {},
18106 onSuccess: function (total) {},
18107 onActive: function (value, total) {},
18108 onError: function (value, total) {},
18109 onWarning: function (value, total) {},
18110
18111 error: {
18112 method: 'The method you called is not defined.',
18113 nonNumeric: 'Progress value is non numeric',
18114 tooHigh: 'Value specified is above 100%',
18115 tooLow: 'Value specified is below 0%',
18116 sumExceedsTotal: 'Sum of multiple values exceed total',
18117 },
18118
18119 regExp: {
18120 variable: /{\$*[\da-z]+}/gi,
18121 },
18122
18123 metadata: {
18124 percent: 'percent',
18125 total: 'total',
18126 value: 'value',
18127 },
18128
18129 selector: {
18130 bar: '> .bar',
18131 label: '> .label',
18132 progress: '.bar > .progress',
18133 },
18134
18135 text: {
18136 active: false,
18137 error: false,
18138 success: false,
18139 warning: false,
18140 percent: '{percent}%',
18141 ratio: '{value} of {total}',
18142 bars: [''],
18143 },
18144
18145 className: {
18146 active: 'active',
18147 error: 'error',
18148 success: 'success',
18149 warning: 'warning',
18150 },
18151
18152 };
18153})(jQuery, window, document);
18154
18155/*!
18156 * # Fomantic-UI 2.9.3 - Slider
18157 * https://github.com/fomantic/Fomantic-UI/
18158 *
18159 *
18160 * Released under the MIT license
18161 * https://opensource.org/licenses/MIT
18162 *
18163 */
18164
18165(function ($, window, document) {
18166 'use strict';
18167
18168 function isFunction(obj) {
18169 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
18170 }
18171
18172 window = window !== undefined && window.Math === Math
18173 ? window
18174 : globalThis;
18175
18176 $.fn.slider = function (parameters) {
18177 var
18178 $allModules = $(this),
18179 $document = $(document),
18180 $window = $(window),
18181
18182 time = Date.now(),
18183 performance = [],
18184
18185 query = arguments[0],
18186 methodInvoked = typeof query === 'string',
18187 queryArguments = [].slice.call(arguments, 1),
18188
18189 alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
18190
18191 SINGLE_STEP = 1,
18192 BIG_STEP = 2,
18193 NO_STEP = 0,
18194 SINGLE_BACKSTEP = -1,
18195 BIG_BACKSTEP = -2,
18196
18197 // Used to manage document bound events.
18198 // Use this so that we can distinguish between which document events are bound to which range.
18199 currentRange = 0,
18200
18201 returnedValue
18202 ;
18203
18204 $allModules.each(function () {
18205 var
18206 settings = $.isPlainObject(parameters)
18207 ? $.extend(true, {}, $.fn.slider.settings, parameters)
18208 : $.extend({}, $.fn.slider.settings),
18209
18210 className = settings.className,
18211 metadata = settings.metadata,
18212 namespace = settings.namespace,
18213 error = settings.error,
18214 keys = settings.keys,
18215 interpretLabel = settings.interpretLabel,
18216
18217 isHover = false,
18218 eventNamespace = '.' + namespace,
18219 moduleNamespace = 'module-' + namespace,
18220
18221 $module = $(this),
18222 $currThumb,
18223 touchIdentifier,
18224 $thumb,
18225 $secondThumb,
18226 $track,
18227 $trackFill,
18228 $labels,
18229
18230 element = this,
18231 instance = $module.data(moduleNamespace),
18232
18233 documentEventID,
18234
18235 value,
18236 position,
18237 secondPos,
18238 offset,
18239 precision,
18240 gapRatio = 1,
18241 previousValue,
18242
18243 initialPosition,
18244 initialLoad,
18245 module
18246 ;
18247
18248 module = {
18249
18250 initialize: function () {
18251 module.debug('Initializing slider', settings);
18252 initialLoad = true;
18253
18254 currentRange += 1;
18255 documentEventID = currentRange;
18256
18257 module.setup.layout();
18258 module.setup.labels();
18259
18260 module.bind.events();
18261
18262 module.read.metadata();
18263 module.read.settings();
18264
18265 initialLoad = false;
18266 module.instantiate();
18267 },
18268
18269 instantiate: function () {
18270 module.verbose('Storing instance of slider', module);
18271 instance = module;
18272 $module
18273 .data(moduleNamespace, module)
18274 ;
18275 },
18276
18277 destroy: function () {
18278 module.verbose('Destroying previous slider for', $module);
18279 clearInterval(instance.interval);
18280 module.unbind.events();
18281 module.unbind.slidingEvents();
18282 $module.removeData(moduleNamespace);
18283 instance = undefined;
18284 },
18285
18286 setup: {
18287 layout: function () {
18288 if ($module.attr('tabindex') === undefined) {
18289 $module.attr('tabindex', 0);
18290 }
18291 if ($module.find('.inner').length === 0) {
18292 $module.append('<div class="inner">'
18293 + '<div class="track"></div>'
18294 + '<div class="track-fill"></div>'
18295 + '<div class="thumb"></div>'
18296 + '</div>');
18297 }
18298 precision = module.get.precision();
18299 $thumb = $module.find('.thumb:not(.second)');
18300 if (settings.showThumbTooltip) {
18301 $thumb
18302 .attr('data-position', settings.tooltipConfig.position)
18303 .attr('data-variation', settings.tooltipConfig.variation)
18304 ;
18305 }
18306 $currThumb = $thumb;
18307 if (module.is.range()) {
18308 if ($module.find('.thumb.second').length === 0) {
18309 $module.find('.inner').append('<div class="thumb second"></div>');
18310 }
18311 $secondThumb = $module.find('.thumb.second');
18312 if (settings.showThumbTooltip) {
18313 $secondThumb
18314 .attr('data-position', settings.tooltipConfig.position)
18315 .attr('data-variation', settings.tooltipConfig.variation)
18316 ;
18317 }
18318 }
18319 $track = $module.find('.track');
18320 $trackFill = $module.find('.track-fill');
18321 offset = $thumb.width() / 2;
18322 },
18323 labels: function () {
18324 if (module.is.labeled()) {
18325 $labels = $module.find('.labels:not(.auto)');
18326 if ($labels.length > 0) {
18327 module.setup.customLabel();
18328 } else {
18329 module.setup.autoLabel();
18330 }
18331
18332 if (settings.showLabelTicks) {
18333 $module.addClass(className.ticked);
18334 }
18335 }
18336 },
18337 customLabel: function () {
18338 var
18339 $children = $labels.find('.label'),
18340 numChildren = $children.length,
18341 min = module.get.min(),
18342 max = module.get.max(),
18343 ratio
18344 ;
18345 $children.each(function (index) {
18346 var
18347 $child = $(this),
18348 attrValue = $child.attr('data-value')
18349 ;
18350 if (attrValue) {
18351 attrValue = attrValue > max
18352 ? max
18353 : (attrValue < min ? min : attrValue);
18354 ratio = (attrValue - min) / (max - min);
18355 } else {
18356 ratio = (index + 1) / (numChildren + 1);
18357 }
18358 module.update.labelPosition(ratio, $(this));
18359 });
18360 },
18361 autoLabel: function () {
18362 $labels = $module.find('.labels');
18363 if ($labels.length > 0) {
18364 $labels.empty();
18365 } else {
18366 $labels = $module.append('<ul class="auto labels"></ul>').find('.labels');
18367 }
18368 for (var i = 0, len = module.get.numLabels(); i <= len; i++) {
18369 var
18370 labelText = module.get.label(i),
18371 showLabel = settings.restrictedLabels.length === 0 || settings.restrictedLabels.indexOf(labelText) >= 0,
18372 $label = labelText !== '' && (showLabel || settings.showLabelTicks === 'always')
18373 ? (!(i % module.get.gapRatio())
18374 ? $('<li class="label">' + (showLabel ? labelText : '') + '</li>')
18375 : $('<li class="halftick label"></li>'))
18376 : null,
18377 ratio = i / len
18378 ;
18379 if ($label) {
18380 module.update.labelPosition(ratio, $label);
18381 $labels.append($label);
18382 }
18383 }
18384 },
18385 },
18386
18387 bind: {
18388 events: function () {
18389 module.bind.globalKeyboardEvents();
18390 module.bind.keyboardEvents();
18391 module.bind.mouseEvents();
18392 if (settings.autoAdjustLabels) {
18393 module.bind.windowEvents();
18394 }
18395 },
18396 keyboardEvents: function () {
18397 module.verbose('Binding keyboard events');
18398 $module.on('keydown' + eventNamespace, module.event.keydown);
18399 },
18400 globalKeyboardEvents: function () {
18401 $document.on('keydown' + eventNamespace + documentEventID, module.event.activateFocus);
18402 },
18403 mouseEvents: function () {
18404 module.verbose('Binding mouse and touch events');
18405 $module.find('.track, .thumb, .inner').on('mousedown' + eventNamespace, function (event) {
18406 event.stopImmediatePropagation();
18407 event.preventDefault();
18408 module.event.down(event);
18409 });
18410 $module.on('mousedown' + eventNamespace, module.event.down);
18411 $module.on('mouseenter' + eventNamespace, function (event) {
18412 isHover = true;
18413 });
18414 $module.on('mouseleave' + eventNamespace, function (event) {
18415 isHover = false;
18416 });
18417 // All touch events are invoked on the element where the touch *started*. Thus, we can bind them all
18418 // on the thumb(s) and don't need to worry about interference with other components, i.e. no dynamic binding
18419 // and unbinding required.
18420 $module.find('.thumb')
18421 .on('touchstart' + eventNamespace, module.event.touchDown)
18422 .on('touchmove' + eventNamespace, module.event.move)
18423 .on('touchend' + eventNamespace, module.event.up)
18424 .on('touchcancel' + eventNamespace, module.event.touchCancel)
18425 ;
18426 },
18427 slidingEvents: function () {
18428 // these don't need the identifier because we only ever want one of them to be registered with document
18429 module.verbose('Binding page wide events while handle is being draged');
18430 $document.on('mousemove' + eventNamespace, module.event.move);
18431 $document.on('mouseup' + eventNamespace, module.event.up);
18432 },
18433 windowEvents: function () {
18434 $window.on('resize' + eventNamespace, module.event.resize);
18435 },
18436 },
18437
18438 unbind: {
18439 events: function () {
18440 $module.find('.track, .thumb, .inner').off('mousedown' + eventNamespace);
18441 $module.off('mousedown' + eventNamespace);
18442 $module.off('mouseenter' + eventNamespace);
18443 $module.off('mouseleave' + eventNamespace);
18444 $module.find('.thumb')
18445 .off('touchstart' + eventNamespace)
18446 .off('touchmove' + eventNamespace)
18447 .off('touchend' + eventNamespace)
18448 .off('touchcancel' + eventNamespace)
18449 ;
18450 $module.off('keydown' + eventNamespace);
18451 $module.off('focusout' + eventNamespace);
18452 $document.off('keydown' + eventNamespace + documentEventID, module.event.activateFocus);
18453 $window.off('resize' + eventNamespace);
18454 },
18455 slidingEvents: function () {
18456 $document.off('mousemove' + eventNamespace);
18457 $document.off('mouseup' + eventNamespace);
18458 },
18459 },
18460
18461 event: {
18462 down: function (event) {
18463 event.preventDefault();
18464 if (module.is.range()) {
18465 var
18466 eventPos = module.determine.eventPos(event),
18467 newPos = module.determine.pos(eventPos)
18468 ;
18469 // Special handling if range mode and both thumbs have the same value
18470 if (settings.preventCrossover && module.is.range() && module.thumbVal === module.secondThumbVal) {
18471 initialPosition = newPos;
18472 $currThumb = undefined;
18473 } else {
18474 $currThumb = module.determine.closestThumb(newPos);
18475 }
18476 if (previousValue === undefined) {
18477 previousValue = module.get.currentThumbValue();
18478 }
18479 } else if (previousValue === undefined) {
18480 previousValue = module.get.value();
18481 }
18482
18483 if (!module.is.disabled()) {
18484 module.bind.slidingEvents();
18485 }
18486 },
18487 touchDown: function (event) {
18488 event.preventDefault(); // disable mouse emulation and touch-scrolling
18489 event.stopImmediatePropagation();
18490 if (touchIdentifier !== undefined) {
18491 // ignore multiple touches on the same slider --
18492 // we cannot handle changing both thumbs at once due to shared state
18493 return;
18494 }
18495 $currThumb = $(event.target);
18496 var touchEvent = event.touches ? event : event.originalEvent;
18497 touchIdentifier = touchEvent.targetTouches[0].identifier;
18498 if (previousValue === undefined) {
18499 previousValue = module.get.currentThumbValue();
18500 }
18501 },
18502 move: function (event) {
18503 if (event.type === 'mousemove') {
18504 event.preventDefault(); // prevent text selection etc.
18505 }
18506 if (module.is.disabled()) {
18507 // touch events are always bound, so we need to prevent touch-sliding on disabled sliders here
18508 return;
18509 }
18510 var value = module.determine.valueFromEvent(event);
18511 if (event.type === 'mousemove' && $currThumb === undefined) {
18512 var
18513 eventPos = module.determine.eventPos(event),
18514 newPos = module.determine.pos(eventPos)
18515 ;
18516 $currThumb = initialPosition > newPos ? $thumb : $secondThumb;
18517 }
18518 if (module.is.range() && (settings.minRange || settings.maxRange)) {
18519 var currentRangeDiff = module.get.currentRangeDiff(value),
18520 isSecondThumb = $currThumb.hasClass('second')
18521 ;
18522 if ((settings.minRange && currentRangeDiff < settings.minRange)
18523 || (settings.maxRange && currentRangeDiff > settings.maxRange)
18524 || (settings.preventCrossover && !isSecondThumb && value > module.secondThumbVal)
18525 || (settings.preventCrossover && isSecondThumb && value < module.thumbVal)
18526 ) {
18527 return;
18528 }
18529 }
18530 if (module.get.step() === 0 || module.is.smooth()) {
18531 var
18532 thumbVal = module.thumbVal,
18533 secondThumbVal = module.secondThumbVal,
18534 thumbSmoothVal = module.determine.smoothValueFromEvent(event)
18535 ;
18536 if (!$currThumb.hasClass('second')) {
18537 if (settings.preventCrossover && module.is.range()) {
18538 value = Math.min(secondThumbVal, value);
18539 thumbSmoothVal = Math.min(secondThumbVal, thumbSmoothVal);
18540 }
18541 thumbVal = value;
18542 } else {
18543 if (settings.preventCrossover && module.is.range()) {
18544 value = Math.max(thumbVal, value);
18545 thumbSmoothVal = Math.max(thumbVal, thumbSmoothVal);
18546 }
18547 secondThumbVal = value;
18548 }
18549 value = Math.abs(thumbVal - (secondThumbVal || 0));
18550 module.update.position(thumbSmoothVal);
18551 settings.onMove.call(element, value, thumbVal, secondThumbVal);
18552 } else {
18553 module.update.value(value, function (value, thumbVal, secondThumbVal) {
18554 settings.onMove.call(element, value, thumbVal, secondThumbVal);
18555 });
18556 }
18557 },
18558 up: function (event) {
18559 event.preventDefault();
18560 if (module.is.disabled()) {
18561 // touch events are always bound, so we need to prevent touch-sliding on disabled sliders here
18562 return;
18563 }
18564 var value = module.determine.valueFromEvent(event);
18565 if (module.is.range() && (settings.minRange || settings.maxRange)) {
18566 if ($currThumb === undefined) {
18567 $currThumb = value <= module.get.currentThumbValue() ? $thumb : $secondThumb;
18568 }
18569 var currentRangeDiff = module.get.currentRangeDiff(value);
18570 if (settings.minRange && currentRangeDiff < settings.minRange) {
18571 value = module.get.edgeValue(value, settings.minRange);
18572 } else if (settings.maxRange && currentRangeDiff > settings.maxRange) {
18573 value = module.get.edgeValue(value, settings.maxRange);
18574 }
18575 }
18576 module.set.value(value);
18577 module.unbind.slidingEvents();
18578 touchIdentifier = undefined;
18579 if (previousValue !== undefined) {
18580 previousValue = undefined;
18581 }
18582 },
18583 touchCancel: function (event) {
18584 event.preventDefault();
18585 touchIdentifier = undefined;
18586 if (previousValue !== undefined) {
18587 module.update.value(previousValue);
18588 previousValue = undefined;
18589 }
18590 },
18591 keydown: function (event, first) {
18592 if (module.is.disabled()) {
18593 return;
18594 }
18595 if (settings.preventCrossover && module.is.range() && module.thumbVal === module.secondThumbVal) {
18596 $currThumb = undefined;
18597 }
18598 if (module.is.focused()) {
18599 $document.trigger(event);
18600 }
18601 if (first || module.is.focused()) {
18602 var step = module.determine.keyMovement(event);
18603 if (step !== NO_STEP) {
18604 event.preventDefault();
18605 switch (step) {
18606 case SINGLE_STEP: {
18607 module.takeStep();
18608
18609 break;
18610 }
18611 case BIG_STEP: {
18612 module.takeStep(module.get.multiplier());
18613
18614 break;
18615 }
18616 case SINGLE_BACKSTEP: {
18617 module.backStep();
18618
18619 break;
18620 }
18621 case BIG_BACKSTEP: {
18622 module.backStep(module.get.multiplier());
18623
18624 break;
18625 }
18626 }
18627 }
18628 }
18629 },
18630 activateFocus: function (event) {
18631 if (!module.is.disabled() && !module.is.focused() && module.is.hover() && module.determine.keyMovement(event) !== NO_STEP) {
18632 event.preventDefault();
18633 module.event.keydown(event, true);
18634 $module.trigger('focus');
18635 }
18636 },
18637 resize: function (_event) {
18638 // To avoid a useless performance cost, we only call the label refresh when its necessary
18639 if (gapRatio !== module.get.gapRatio()) {
18640 module.setup.labels();
18641 gapRatio = module.get.gapRatio();
18642 }
18643 },
18644 },
18645
18646 resync: function () {
18647 module.verbose('Resyncing thumb position based on value');
18648 if (module.is.range()) {
18649 module.update.position(module.secondThumbVal, $secondThumb);
18650 }
18651 module.update.position(module.thumbVal, $thumb);
18652 module.setup.labels();
18653 },
18654 takeStep: function (multiplier) {
18655 if (!multiplier) {
18656 multiplier = 1;
18657 }
18658 var
18659 step = module.get.step(),
18660 currValue = module.get.currentThumbValue()
18661 ;
18662 module.verbose('Taking a step');
18663 if (step > 0) {
18664 module.set.value(currValue + step * multiplier);
18665 } else if (step === 0) {
18666 var
18667 precision = module.get.precision(),
18668 newValue = currValue + (multiplier / precision)
18669 ;
18670 module.set.value(Math.round(newValue * precision) / precision);
18671 }
18672 },
18673
18674 backStep: function (multiplier) {
18675 if (!multiplier) {
18676 multiplier = 1;
18677 }
18678 var
18679 step = module.get.step(),
18680 currValue = module.get.currentThumbValue()
18681 ;
18682 module.verbose('Going back a step');
18683 if (step > 0) {
18684 module.set.value(currValue - step * multiplier);
18685 } else if (step === 0) {
18686 var
18687 precision = module.get.precision(),
18688 newValue = currValue - (multiplier / precision)
18689 ;
18690 module.set.value(Math.round(newValue * precision) / precision);
18691 }
18692 },
18693
18694 is: {
18695 range: function () {
18696 var isRange = $module.hasClass(className.range);
18697 if (!isRange && (settings.minRange || settings.maxRange)) {
18698 $module.addClass(className.range);
18699 isRange = true;
18700 }
18701
18702 return isRange;
18703 },
18704 hover: function () {
18705 return isHover;
18706 },
18707 focused: function () {
18708 return $module.is(':focus');
18709 },
18710 disabled: function () {
18711 return $module.hasClass(className.disabled);
18712 },
18713 labeled: function () {
18714 var isLabeled = $module.hasClass(className.labeled);
18715 if (!isLabeled && (settings.restrictedLabels.length > 0 || settings.showLabelTicks !== false)) {
18716 $module.addClass(className.labeled);
18717 isLabeled = true;
18718 }
18719
18720 return isLabeled;
18721 },
18722 reversed: function () {
18723 return $module.hasClass(className.reversed);
18724 },
18725 vertical: function () {
18726 return $module.hasClass(className.vertical);
18727 },
18728 smooth: function () {
18729 return settings.smooth || $module.hasClass(className.smooth);
18730 },
18731 },
18732
18733 get: {
18734 currentRangeDiff: function (value) {
18735 var currentRangeDiff;
18736 if ($currThumb.hasClass('second')) {
18737 currentRangeDiff = module.thumbVal < value
18738 ? value - module.thumbVal
18739 : module.thumbVal - value;
18740 } else {
18741 currentRangeDiff = module.secondThumbVal > value
18742 ? module.secondThumbVal - value
18743 : value - module.secondThumbVal;
18744 }
18745
18746 return currentRangeDiff;
18747 },
18748 edgeValue: function (value, edgeValue) {
18749 if ($currThumb.hasClass('second')) {
18750 value = module.thumbVal < value
18751 ? module.thumbVal + edgeValue
18752 : module.thumbVal - edgeValue;
18753 } else {
18754 value = module.secondThumbVal < value
18755 ? module.secondThumbVal + edgeValue
18756 : module.secondThumbVal - edgeValue;
18757 }
18758
18759 return value;
18760 },
18761 trackOffset: function () {
18762 if (module.is.vertical()) {
18763 return $track.offset().top;
18764 }
18765
18766 return $track.offset().left;
18767 },
18768 trackLength: function () {
18769 if (module.is.vertical()) {
18770 return $track.height();
18771 }
18772
18773 return $track.width();
18774 },
18775 trackLeft: function () {
18776 if (module.is.vertical()) {
18777 return $track.position().top;
18778 }
18779
18780 return $track.position().left;
18781 },
18782 trackStartPos: function () {
18783 return module.is.reversed() ? module.get.trackLeft() + module.get.trackLength() : module.get.trackLeft();
18784 },
18785 trackEndPos: function () {
18786 return module.is.reversed() ? module.get.trackLeft() : module.get.trackLeft() + module.get.trackLength();
18787 },
18788 trackStartMargin: function () {
18789 var margin;
18790 if (module.is.vertical()) {
18791 margin = module.is.reversed() ? $module.css('padding-bottom') : $module.css('padding-top');
18792 } else {
18793 margin = module.is.reversed() ? $module.css('padding-right') : $module.css('padding-left');
18794 }
18795
18796 return margin || '0px';
18797 },
18798 trackEndMargin: function () {
18799 var margin;
18800 if (module.is.vertical()) {
18801 margin = module.is.reversed() ? $module.css('padding-top') : $module.css('padding-bottom');
18802 } else {
18803 margin = module.is.reversed() ? $module.css('padding-left') : $module.css('padding-right');
18804 }
18805
18806 return margin || '0px';
18807 },
18808 precision: function () {
18809 var
18810 decimalPlaces,
18811 step = module.get.step()
18812 ;
18813 if (step !== 0) {
18814 var split = String(step).split('.');
18815 decimalPlaces = split.length === 2 ? split[1].length : 0;
18816 } else {
18817 decimalPlaces = settings.decimalPlaces;
18818 }
18819 var precision = Math.pow(10, decimalPlaces);
18820 module.debug('Precision determined', precision);
18821
18822 return precision;
18823 },
18824 min: function () {
18825 return settings.min;
18826 },
18827 max: function () {
18828 var
18829 step = module.get.step(),
18830 min = module.get.min(),
18831 precision = module.get.precision(),
18832 quotient = step === 0 ? 0 : Math.floor(Math.round(((settings.max - min) / step) * precision) / precision),
18833 remainder = step === 0 ? 0 : (settings.max - min) % step
18834 ;
18835
18836 return remainder === 0 ? settings.max : min + quotient * step;
18837 },
18838 step: function () {
18839 return settings.step;
18840 },
18841 numLabels: function () {
18842 var step = module.get.step(),
18843 precision = module.get.precision(),
18844 value = Math.round(((module.get.max() - module.get.min()) / (step === 0 ? 1 : step)) * precision) / precision;
18845 module.debug('Determined that there should be ' + value + ' labels');
18846
18847 return value;
18848 },
18849 labelType: function () {
18850 return settings.labelType;
18851 },
18852 label: function (value) {
18853 if (interpretLabel) {
18854 return interpretLabel(value);
18855 }
18856
18857 switch (settings.labelType) {
18858 case settings.labelTypes.number: {
18859 var step = module.get.step();
18860
18861 return Math.round(((value * (step === 0 ? 1 : step)) + module.get.min()) * precision) / precision;
18862 }
18863 case settings.labelTypes.letter: {
18864 return alphabet[value % 26];
18865 }
18866 default: {
18867 return value;
18868 }
18869 }
18870 },
18871 value: function () {
18872 return value;
18873 },
18874 currentThumbValue: function () {
18875 return $currThumb !== undefined && $currThumb.hasClass('second') ? module.secondThumbVal : module.thumbVal;
18876 },
18877 thumbValue: function (which) {
18878 switch (which) {
18879 case 'second': {
18880 if (module.is.range()) {
18881 return module.secondThumbVal;
18882 }
18883
18884 module.error(error.notrange);
18885
18886 break;
18887 }
18888 default: {
18889 return module.thumbVal;
18890 }
18891 }
18892 },
18893 multiplier: function () {
18894 return settings.pageMultiplier;
18895 },
18896 thumbPosition: function (which) {
18897 switch (which) {
18898 case 'second': {
18899 if (module.is.range()) {
18900 return secondPos;
18901 }
18902
18903 module.error(error.notrange);
18904
18905 break;
18906 }
18907 default: {
18908 return position;
18909 }
18910 }
18911 },
18912 gapRatio: function () {
18913 var gapRatio = 1;
18914
18915 if (settings.autoAdjustLabels) {
18916 var
18917 numLabels = module.get.numLabels(),
18918 trackLength = module.get.trackLength(),
18919 gapCounter = 1
18920 ;
18921
18922 // While the distance between two labels is too short,
18923 // we divide the number of labels at each iteration
18924 // and apply only if the modulo of the operation is an odd number.
18925 if (trackLength > 0) {
18926 while ((trackLength / numLabels) * gapCounter < settings.labelDistance) {
18927 if (!(numLabels % gapCounter)) {
18928 gapRatio = gapCounter;
18929 }
18930 gapCounter += 1;
18931 }
18932 }
18933 }
18934
18935 return gapRatio;
18936 },
18937 },
18938
18939 determine: {
18940 pos: function (pagePos) {
18941 return module.is.reversed()
18942 ? module.get.trackStartPos() - pagePos + module.get.trackOffset()
18943 : pagePos - module.get.trackOffset() - module.get.trackStartPos();
18944 },
18945 closestThumb: function (eventPos) {
18946 var
18947 thumbPos = parseFloat(module.determine.thumbPos($thumb)),
18948 thumbDelta = Math.abs(eventPos - thumbPos),
18949 secondThumbPos = parseFloat(module.determine.thumbPos($secondThumb)),
18950 secondThumbDelta = Math.abs(eventPos - secondThumbPos)
18951 ;
18952 if (thumbDelta === secondThumbDelta && module.get.thumbValue() === module.get.min()) {
18953 return $secondThumb;
18954 }
18955
18956 return thumbDelta <= secondThumbDelta ? $thumb : $secondThumb;
18957 },
18958 closestThumbPos: function (eventPos) {
18959 var
18960 thumbPos = parseFloat(module.determine.thumbPos($thumb)),
18961 thumbDelta = Math.abs(eventPos - thumbPos),
18962 secondThumbPos = parseFloat(module.determine.thumbPos($secondThumb)),
18963 secondThumbDelta = Math.abs(eventPos - secondThumbPos)
18964 ;
18965
18966 return thumbDelta <= secondThumbDelta ? thumbPos : secondThumbPos;
18967 },
18968 thumbPos: function ($element) {
18969 return module.is.vertical()
18970 ? (module.is.reversed() ? $element.css('bottom') : $element.css('top'))
18971 : (module.is.reversed() ? $element.css('right') : $element.css('left'))
18972 ;
18973 },
18974 positionFromValue: function (val) {
18975 var
18976 min = module.get.min(),
18977 max = module.get.max(),
18978 value = val > max
18979 ? max
18980 : (val < min ? min : val),
18981 trackLength = module.get.trackLength(),
18982 ratio = (value - min) / (max - min),
18983 position = Math.round(ratio * trackLength)
18984 ;
18985 module.verbose('Determined position: ' + position + ' from value: ' + value);
18986
18987 return position;
18988 },
18989 positionFromRatio: function (ratio) {
18990 var
18991 trackLength = module.get.trackLength(),
18992 step = module.get.step(),
18993 position = Math.round(ratio * trackLength),
18994 adjustedPos = step === 0 ? position : Math.round(position / step) * step
18995 ;
18996 module.verbose('Determined position: ' + position + ' from ratio: ' + ratio);
18997
18998 return adjustedPos;
18999 },
19000 valueFromEvent: function (event) {
19001 var
19002 eventPos = module.determine.eventPos(event),
19003 newPos = module.determine.pos(eventPos),
19004 value
19005 ;
19006 if (eventPos < module.get.trackOffset()) {
19007 value = module.is.reversed() ? module.get.max() : module.get.min();
19008 } else if (eventPos > module.get.trackOffset() + module.get.trackLength()) {
19009 value = module.is.reversed() ? module.get.min() : module.get.max();
19010 } else {
19011 value = module.determine.value(newPos);
19012 }
19013
19014 return value;
19015 },
19016 smoothValueFromEvent: function (event) {
19017 var
19018 min = module.get.min(),
19019 max = module.get.max(),
19020 trackLength = module.get.trackLength(),
19021 eventPos = module.determine.eventPos(event),
19022 newPos = eventPos - module.get.trackOffset(),
19023 ratio,
19024 value
19025 ;
19026 newPos = newPos < 0
19027 ? 0
19028 : (newPos > trackLength ? trackLength : newPos);
19029 ratio = newPos / trackLength;
19030 if (module.is.reversed()) {
19031 ratio = 1 - ratio;
19032 }
19033 value = ratio * (max - min) + min;
19034
19035 return value;
19036 },
19037 eventPos: function (event) {
19038 if (event.type === 'touchmove' || event.type === 'touchend') {
19039 var
19040 touchEvent = event.touches ? event : event.originalEvent,
19041 touch = touchEvent.changedTouches[0]; // fall back to first touch if correct touch not found
19042 for (var i = 0; i < touchEvent.touches.length; i++) {
19043 if (touchEvent.touches[i].identifier === touchIdentifier) {
19044 touch = touchEvent.touches[i];
19045
19046 break;
19047 }
19048 }
19049 var
19050 touchY = touch.pageY,
19051 touchX = touch.pageX
19052 ;
19053
19054 return module.is.vertical() ? touchY : touchX;
19055 }
19056 var
19057 clickY = event.pageY || event.originalEvent.pageY,
19058 clickX = event.pageX || event.originalEvent.pageX
19059 ;
19060
19061 return module.is.vertical() ? clickY : clickX;
19062 },
19063 value: function (position) {
19064 var
19065 startPos = module.is.reversed() ? module.get.trackEndPos() : module.get.trackStartPos(),
19066 endPos = module.is.reversed() ? module.get.trackStartPos() : module.get.trackEndPos(),
19067 ratio = (position - startPos) / (endPos - startPos),
19068 range = module.get.max() - module.get.min(),
19069 step = module.get.step(),
19070 value = ratio * range,
19071 difference = step === 0 ? value : Math.round(value / step) * step
19072 ;
19073 module.verbose('Determined value based upon position: ' + position + ' as: ' + value);
19074 if (value !== difference) {
19075 module.verbose('Rounding value to closest step: ' + difference);
19076 }
19077 // Use precision to avoid ugly Javascript floating point rounding issues
19078 // (like 35 * .01 = 0.35000000000000003)
19079 module.verbose('Cutting off additional decimal places');
19080
19081 return Math.round((difference + module.get.min()) * precision) / precision;
19082 },
19083 keyMovement: function (event) {
19084 var
19085 key = event.which,
19086 downArrow = module.is.vertical()
19087 ? (module.is.reversed() ? keys.downArrow : keys.upArrow)
19088 : keys.downArrow,
19089 upArrow = module.is.vertical()
19090 ? (module.is.reversed() ? keys.upArrow : keys.downArrow)
19091 : keys.upArrow,
19092 leftArrow = !module.is.vertical()
19093 ? (module.is.reversed() ? keys.rightArrow : keys.leftArrow)
19094 : keys.leftArrow,
19095 rightArrow = !module.is.vertical()
19096 ? (module.is.reversed() ? keys.leftArrow : keys.rightArrow)
19097 : keys.rightArrow
19098 ;
19099 if (key === downArrow || key === leftArrow) {
19100 return SINGLE_BACKSTEP;
19101 }
19102 if (key === upArrow || key === rightArrow) {
19103 return SINGLE_STEP;
19104 }
19105 if (key === keys.pageDown) {
19106 return BIG_BACKSTEP;
19107 }
19108 if (key === keys.pageUp) {
19109 return BIG_STEP;
19110 }
19111
19112 return NO_STEP;
19113 },
19114 },
19115
19116 handleNewValuePosition: function (val) {
19117 var
19118 min = module.get.min(),
19119 max = module.get.max(),
19120 newPos
19121 ;
19122 if (val <= min) {
19123 val = min;
19124 } else if (val >= max) {
19125 val = max;
19126 }
19127 newPos = module.determine.positionFromValue(val);
19128
19129 return newPos;
19130 },
19131
19132 set: {
19133 value: function (newValue, fireChange) {
19134 fireChange = fireChange !== false;
19135 var toReset = previousValue === undefined;
19136 previousValue = previousValue === undefined ? module.get.value() : previousValue;
19137 module.update.value(newValue, function (value, thumbVal, secondThumbVal) {
19138 if ((!initialLoad || settings.fireOnInit) && fireChange) {
19139 if (newValue !== previousValue) {
19140 settings.onChange.call(element, value, thumbVal, secondThumbVal);
19141 }
19142 settings.onMove.call(element, value, thumbVal, secondThumbVal);
19143 }
19144 if (toReset) {
19145 previousValue = undefined;
19146 }
19147 });
19148 },
19149 rangeValue: function (first, second, fireChange) {
19150 fireChange = fireChange !== false;
19151 if (module.is.range()) {
19152 var
19153 min = module.get.min(),
19154 max = module.get.max(),
19155 toReset = previousValue === undefined
19156 ;
19157 previousValue = previousValue === undefined ? module.get.value() : previousValue;
19158 if (first <= min) {
19159 first = min;
19160 } else if (first >= max) {
19161 first = max;
19162 }
19163 if (second <= min) {
19164 second = min;
19165 } else if (second >= max) {
19166 second = max;
19167 }
19168 module.thumbVal = first;
19169 module.secondThumbVal = second;
19170 value = Math.abs(module.thumbVal - module.secondThumbVal);
19171 module.update.position(module.thumbVal, $thumb);
19172 module.update.position(module.secondThumbVal, $secondThumb);
19173 if ((!initialLoad || settings.fireOnInit) && fireChange) {
19174 if (value !== previousValue) {
19175 settings.onChange.call(element, value, module.thumbVal, module.secondThumbVal);
19176 }
19177 settings.onMove.call(element, value, module.thumbVal, module.secondThumbVal);
19178 }
19179 if (toReset) {
19180 previousValue = undefined;
19181 }
19182 } else {
19183 module.error(error.notrange);
19184 }
19185 },
19186 position: function (position, which) {
19187 var thumbVal = module.determine.value(position);
19188 if (which === 'second') {
19189 module.secondThumbVal = thumbVal;
19190 module.update.position(thumbVal, $secondThumb);
19191 } else {
19192 module.thumbVal = thumbVal;
19193 module.update.position(thumbVal, $thumb);
19194 }
19195 value = Math.abs(module.thumbVal - (module.secondThumbVal || 0));
19196 module.set.value(value);
19197 },
19198 },
19199
19200 update: {
19201 value: function (newValue, callback) {
19202 var
19203 min = module.get.min(),
19204 max = module.get.max()
19205 ;
19206 if (newValue <= min) {
19207 newValue = min;
19208 } else if (newValue >= max) {
19209 newValue = max;
19210 }
19211 if (!module.is.range()) {
19212 value = newValue;
19213 module.thumbVal = value;
19214 } else {
19215 if ($currThumb === undefined) {
19216 $currThumb = newValue <= module.get.currentThumbValue() ? $thumb : $secondThumb;
19217 }
19218 if (!$currThumb.hasClass('second')) {
19219 if (settings.preventCrossover && module.is.range()) {
19220 newValue = Math.min(module.secondThumbVal - (settings.minRange || 0), newValue);
19221 }
19222 module.thumbVal = newValue;
19223 } else {
19224 if (settings.preventCrossover && module.is.range()) {
19225 newValue = Math.max(module.thumbVal + (settings.minRange || 0), newValue);
19226 }
19227 module.secondThumbVal = newValue;
19228 }
19229 value = Math.abs(module.thumbVal - module.secondThumbVal);
19230 }
19231 module.update.position(newValue);
19232 module.debug('Setting slider value to ' + value);
19233 if (typeof callback === 'function') {
19234 callback(value, module.thumbVal, module.secondThumbVal);
19235 }
19236 },
19237 position: function (newValue, $element) {
19238 var
19239 newPos = module.handleNewValuePosition(newValue),
19240 $targetThumb = $element || $currThumb,
19241 thumbVal = module.thumbVal || module.get.min(),
19242 secondThumbVal = module.secondThumbVal || module.get.min()
19243 ;
19244 if (settings.showThumbTooltip) {
19245 var precision = module.get.precision();
19246 $targetThumb.attr('data-tooltip', Math.round(newValue * precision) / precision);
19247 }
19248 if (module.is.range()) {
19249 if (!$targetThumb.hasClass('second')) {
19250 position = newPos;
19251 thumbVal = newValue;
19252 } else {
19253 secondPos = newPos;
19254 secondThumbVal = newValue;
19255 }
19256 } else {
19257 position = newPos;
19258 thumbVal = newValue;
19259 }
19260 var
19261 trackPosValue,
19262 thumbPosValue,
19263 min = module.get.min(),
19264 max = module.get.max(),
19265 thumbPosPercent = 100 * ((newValue - min) / (max - min)),
19266 trackStartPosPercent = 100 * ((Math.min(thumbVal, secondThumbVal) - min) / (max - min)),
19267 trackEndPosPercent = 100 * (1 - (Math.max(thumbVal, secondThumbVal) - min) / (max - min))
19268 ;
19269 if (module.is.vertical()) {
19270 if (module.is.reversed()) {
19271 thumbPosValue = { bottom: 'calc(' + thumbPosPercent + '% - ' + offset + 'px)', top: 'auto' };
19272 trackPosValue = { bottom: trackStartPosPercent + '%', top: trackEndPosPercent + '%' };
19273 } else {
19274 thumbPosValue = { top: 'calc(' + thumbPosPercent + '% - ' + offset + 'px)', bottom: 'auto' };
19275 trackPosValue = { top: trackStartPosPercent + '%', bottom: trackEndPosPercent + '%' };
19276 }
19277 } else {
19278 if (module.is.reversed()) {
19279 thumbPosValue = { right: 'calc(' + thumbPosPercent + '% - ' + offset + 'px)', left: 'auto' };
19280 trackPosValue = { right: trackStartPosPercent + '%', left: trackEndPosPercent + '%' };
19281 } else {
19282 thumbPosValue = { left: 'calc(' + thumbPosPercent + '% - ' + offset + 'px)', right: 'auto' };
19283 trackPosValue = { left: trackStartPosPercent + '%', right: trackEndPosPercent + '%' };
19284 }
19285 }
19286 $targetThumb.css(thumbPosValue);
19287 $trackFill.css(trackPosValue);
19288 module.debug('Setting slider position to ' + newPos);
19289 },
19290 labelPosition: function (ratio, $label) {
19291 var
19292 startMargin = module.get.trackStartMargin(),
19293 endMargin = module.get.trackEndMargin(),
19294 posDir = module.is.vertical()
19295 ? (module.is.reversed() ? 'bottom' : 'top')
19296 : (module.is.reversed() ? 'right' : 'left'),
19297 startMarginMod = module.is.reversed() && !module.is.vertical()
19298 ? ' - '
19299 : ' + '
19300 ;
19301 var position = '(100% - ' + startMargin + ' - ' + endMargin + ') * ' + ratio;
19302 $label.css(posDir, 'calc(' + position + startMarginMod + startMargin + ')');
19303 },
19304 },
19305
19306 goto: {
19307 max: function () {
19308 module.set.value(module.get.max());
19309 },
19310 min: function () {
19311 module.set.value(module.get.min());
19312 },
19313 },
19314
19315 read: {
19316 metadata: function () {
19317 var
19318 data = {
19319 thumbVal: $module.data(metadata.thumbVal),
19320 secondThumbVal: $module.data(metadata.secondThumbVal),
19321 }
19322 ;
19323 if (data.thumbVal) {
19324 if (module.is.range() && data.secondThumbVal) {
19325 module.debug('Current value set from metadata', data.thumbVal, data.secondThumbVal);
19326 module.set.rangeValue(data.thumbVal, data.secondThumbVal);
19327 } else {
19328 module.debug('Current value set from metadata', data.thumbVal);
19329 module.set.value(data.thumbVal);
19330 }
19331 }
19332 },
19333 settings: function () {
19334 if (settings.start !== false) {
19335 if (module.is.range()) {
19336 var rangeDiff = settings.end - settings.start;
19337 if (rangeDiff < 0
19338 || (settings.minRange && rangeDiff < settings.minRange)
19339 || (settings.maxRange && rangeDiff > settings.maxRange)
19340 || (settings.minRange && settings.maxRange && settings.minRange > settings.maxRange)
19341 ) {
19342 module.error(error.invalidRanges, settings.start, settings.end, settings.minRange, settings.maxRange);
19343 }
19344 module.debug('Start position set from settings', settings.start, settings.end);
19345 module.set.rangeValue(settings.start, settings.end);
19346 } else {
19347 module.debug('Start position set from settings', settings.start);
19348 module.set.value(settings.start);
19349 }
19350 }
19351 },
19352 },
19353
19354 setting: function (name, value) {
19355 module.debug('Changing setting', name, value);
19356 if ($.isPlainObject(name)) {
19357 $.extend(true, settings, name);
19358 } else if (value !== undefined) {
19359 if ($.isPlainObject(settings[name])) {
19360 $.extend(true, settings[name], value);
19361 } else {
19362 settings[name] = value;
19363 }
19364 } else {
19365 return settings[name];
19366 }
19367 },
19368 internal: function (name, value) {
19369 if ($.isPlainObject(name)) {
19370 $.extend(true, module, name);
19371 } else if (value !== undefined) {
19372 module[name] = value;
19373 } else {
19374 return module[name];
19375 }
19376 },
19377 debug: function () {
19378 if (!settings.silent && settings.debug) {
19379 if (settings.performance) {
19380 module.performance.log(arguments);
19381 } else {
19382 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
19383 module.debug.apply(console, arguments);
19384 }
19385 }
19386 },
19387 verbose: function () {
19388 if (!settings.silent && settings.verbose && settings.debug) {
19389 if (settings.performance) {
19390 module.performance.log(arguments);
19391 } else {
19392 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
19393 module.verbose.apply(console, arguments);
19394 }
19395 }
19396 },
19397 error: function () {
19398 if (!settings.silent) {
19399 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
19400 module.error.apply(console, arguments);
19401 }
19402 },
19403
19404 performance: {
19405 log: function (message) {
19406 var
19407 currentTime,
19408 executionTime,
19409 previousTime
19410 ;
19411 if (settings.performance) {
19412 currentTime = Date.now();
19413 previousTime = time || currentTime;
19414 executionTime = currentTime - previousTime;
19415 time = currentTime;
19416 performance.push({
19417 Name: message[0],
19418 Arguments: [].slice.call(message, 1) || '',
19419 Element: element,
19420 'Execution Time': executionTime,
19421 });
19422 }
19423 clearTimeout(module.performance.timer);
19424 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
19425 },
19426 display: function () {
19427 var
19428 title = settings.name + ':',
19429 totalTime = 0
19430 ;
19431 time = false;
19432 clearTimeout(module.performance.timer);
19433 $.each(performance, function (index, data) {
19434 totalTime += data['Execution Time'];
19435 });
19436 title += ' ' + totalTime + 'ms';
19437 if (performance.length > 0) {
19438 console.groupCollapsed(title);
19439 if (console.table) {
19440 console.table(performance);
19441 } else {
19442 $.each(performance, function (index, data) {
19443 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
19444 });
19445 }
19446 console.groupEnd();
19447 }
19448 performance = [];
19449 },
19450 },
19451
19452 invoke: function (query, passedArguments, context) {
19453 var
19454 object = instance,
19455 maxDepth,
19456 found,
19457 response
19458 ;
19459 passedArguments = passedArguments || queryArguments;
19460 context = context || element;
19461 if (typeof query === 'string' && object !== undefined) {
19462 query = query.split(/[ .]/);
19463 maxDepth = query.length - 1;
19464 $.each(query, function (depth, value) {
19465 var camelCaseValue = depth !== maxDepth
19466 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
19467 : query
19468 ;
19469 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
19470 object = object[camelCaseValue];
19471 } else if (object[camelCaseValue] !== undefined) {
19472 found = object[camelCaseValue];
19473
19474 return false;
19475 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
19476 object = object[value];
19477 } else if (object[value] !== undefined) {
19478 found = object[value];
19479
19480 return false;
19481 } else {
19482 module.error(error.method, query);
19483
19484 return false;
19485 }
19486 });
19487 }
19488 if (isFunction(found)) {
19489 response = found.apply(context, passedArguments);
19490 } else if (found !== undefined) {
19491 response = found;
19492 }
19493 if (Array.isArray(returnedValue)) {
19494 returnedValue.push(response);
19495 } else if (returnedValue !== undefined) {
19496 returnedValue = [returnedValue, response];
19497 } else if (response !== undefined) {
19498 returnedValue = response;
19499 }
19500
19501 return found;
19502 },
19503 };
19504
19505 if (methodInvoked) {
19506 if (instance === undefined) {
19507 module.initialize();
19508 }
19509 module.invoke(query);
19510 } else {
19511 if (instance !== undefined) {
19512 instance.invoke('destroy');
19513 }
19514 module.initialize();
19515 }
19516 });
19517
19518 return returnedValue !== undefined
19519 ? returnedValue
19520 : this;
19521 };
19522
19523 $.fn.slider.settings = {
19524
19525 silent: false,
19526 debug: false,
19527 verbose: false,
19528 performance: true,
19529
19530 name: 'Slider',
19531 namespace: 'slider',
19532
19533 error: {
19534 method: 'The method you called is not defined.',
19535 notrange: 'This slider is not a range slider',
19536 invalidRanges: 'Invalid range settings (start/end/minRange/maxRange)',
19537 },
19538
19539 metadata: {
19540 thumbVal: 'thumbVal',
19541 secondThumbVal: 'secondThumbVal',
19542 },
19543
19544 min: 0,
19545 max: 20,
19546 step: 1,
19547 start: 0,
19548 end: 20,
19549 minRange: false,
19550 maxRange: false,
19551 labelType: 'number',
19552 showLabelTicks: false,
19553 smooth: false,
19554 autoAdjustLabels: true,
19555 labelDistance: 100,
19556 preventCrossover: true,
19557 fireOnInit: false,
19558 interpretLabel: false,
19559
19560 // the decimal place to round to if step is undefined
19561 decimalPlaces: 2,
19562
19563 // page up/down multiplier. How many more times the steps to take on page up/down press
19564 pageMultiplier: 2,
19565
19566 selector: {},
19567
19568 className: {
19569 reversed: 'reversed',
19570 disabled: 'disabled',
19571 labeled: 'labeled',
19572 ticked: 'ticked',
19573 vertical: 'vertical',
19574 range: 'range',
19575 smooth: 'smooth',
19576 },
19577
19578 keys: {
19579 pageUp: 33,
19580 pageDown: 34,
19581 leftArrow: 37,
19582 upArrow: 38,
19583 rightArrow: 39,
19584 downArrow: 40,
19585 },
19586
19587 restrictedLabels: [],
19588 showThumbTooltip: false,
19589 tooltipConfig: {
19590 position: 'top center',
19591 variation: 'tiny black',
19592 },
19593
19594 labelTypes: {
19595 number: 'number',
19596 letter: 'letter',
19597 },
19598
19599 onChange: function (value, thumbVal, secondThumbVal) {},
19600 onMove: function (value, thumbVal, secondThumbVal) {},
19601 };
19602})(jQuery, window, document);
19603
19604/*!
19605 * # Fomantic-UI 2.9.3 - Rating
19606 * https://github.com/fomantic/Fomantic-UI/
19607 *
19608 *
19609 * Released under the MIT license
19610 * https://opensource.org/licenses/MIT
19611 *
19612 */
19613
19614(function ($, window, document) {
19615 'use strict';
19616
19617 function isFunction(obj) {
19618 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
19619 }
19620
19621 window = window !== undefined && window.Math === Math
19622 ? window
19623 : globalThis;
19624
19625 $.fn.rating = function (parameters) {
19626 var
19627 $allModules = $(this),
19628
19629 time = Date.now(),
19630 performance = [],
19631
19632 query = arguments[0],
19633 methodInvoked = typeof query === 'string',
19634 queryArguments = [].slice.call(arguments, 1),
19635 returnedValue
19636 ;
19637 $allModules.each(function () {
19638 var
19639 settings = $.isPlainObject(parameters)
19640 ? $.extend(true, {}, $.fn.rating.settings, parameters)
19641 : $.extend({}, $.fn.rating.settings),
19642
19643 namespace = settings.namespace,
19644 className = settings.className,
19645 error = settings.error,
19646 metadata = settings.metadata,
19647 selector = settings.selector,
19648 cssVars = settings.cssVars,
19649
19650 eventNamespace = '.' + namespace,
19651 moduleNamespace = 'module-' + namespace,
19652
19653 element = this,
19654 instance = $(this).data(moduleNamespace),
19655
19656 $module = $(this),
19657 $icon = $module.find(selector.icon),
19658
19659 initialLoad,
19660 module
19661 ;
19662
19663 module = {
19664
19665 initialize: function () {
19666 module.verbose('Initializing rating module', settings);
19667
19668 if ($icon.length === 0) {
19669 module.setup.layout();
19670 }
19671
19672 if (settings.interactive && !module.is.disabled()) {
19673 module.enable();
19674 } else {
19675 module.disable();
19676 }
19677 module.set.initialLoad();
19678 module.set.rating(module.get.initialRating());
19679 module.remove.initialLoad();
19680 module.instantiate();
19681 },
19682
19683 instantiate: function () {
19684 module.verbose('Instantiating module', settings);
19685 instance = module;
19686 $module
19687 .data(moduleNamespace, module)
19688 ;
19689 },
19690
19691 destroy: function () {
19692 module.verbose('Destroying previous instance', instance);
19693 module.remove.events();
19694 $module
19695 .removeData(moduleNamespace)
19696 ;
19697 },
19698
19699 refresh: function () {
19700 $icon = $module.find(selector.icon);
19701 },
19702
19703 setup: {
19704 layout: function () {
19705 var
19706 maxRating = module.get.maxRating(),
19707 icon = module.get.icon(),
19708 html = $.fn.rating.settings.templates.icon(maxRating, icon)
19709 ;
19710 module.debug('Generating icon html dynamically');
19711 $module
19712 .html(html)
19713 ;
19714 module.refresh();
19715 },
19716 },
19717
19718 event: {
19719 mouseenter: function () {
19720 var
19721 $activeIcon = $(this)
19722 ;
19723 $activeIcon
19724 .nextAll()
19725 .removeClass(className.selected)
19726 ;
19727 $module
19728 .addClass(className.selected)
19729 ;
19730 $activeIcon
19731 .addClass(className.selected)
19732 .prevAll()
19733 .addClass(className.selected)
19734 ;
19735 },
19736 mouseleave: function () {
19737 $module
19738 .removeClass(className.selected)
19739 ;
19740 $icon
19741 .removeClass(className.selected)
19742 ;
19743 },
19744 click: function () {
19745 var
19746 $activeIcon = $(this),
19747 currentRating = module.get.rating(),
19748 rating = $icon.index($activeIcon) + 1,
19749 canClear = settings.clearable === 'auto'
19750 ? $icon.length === 1
19751 : settings.clearable
19752 ;
19753 if (canClear && currentRating === rating) {
19754 module.clearRating();
19755 } else {
19756 module.set.rating(rating);
19757 }
19758 },
19759 },
19760
19761 clearRating: function () {
19762 module.debug('Clearing current rating');
19763 module.set.rating(0);
19764 },
19765
19766 bind: {
19767 events: function () {
19768 module.verbose('Binding events');
19769 $module
19770 .on('mouseenter' + eventNamespace, selector.icon, module.event.mouseenter)
19771 .on('mouseleave' + eventNamespace, selector.icon, module.event.mouseleave)
19772 .on('click' + eventNamespace, selector.icon, module.event.click)
19773 ;
19774 },
19775 },
19776
19777 remove: {
19778 events: function () {
19779 module.verbose('Removing events');
19780 $module
19781 .off(eventNamespace)
19782 ;
19783 },
19784 initialLoad: function () {
19785 initialLoad = false;
19786 },
19787 },
19788
19789 enable: function () {
19790 module.debug('Setting rating to interactive mode');
19791 module.bind.events();
19792 $module
19793 .removeClass(className.disabled)
19794 ;
19795 },
19796
19797 disable: function () {
19798 module.debug('Setting rating to read-only mode');
19799 module.remove.events();
19800 $module
19801 .addClass(className.disabled)
19802 ;
19803 },
19804
19805 is: {
19806 initialLoad: function () {
19807 return initialLoad;
19808 },
19809 disabled: function () {
19810 return $module.hasClass(className.disabled);
19811 },
19812 },
19813
19814 get: {
19815 icon: function () {
19816 var icon = $module.data(metadata.icon);
19817 if (icon) {
19818 $module.removeData(metadata.icon);
19819 }
19820
19821 return icon || settings.icon;
19822 },
19823 initialRating: function () {
19824 if ($module.data(metadata.rating) !== undefined) {
19825 $module.removeData(metadata.rating);
19826
19827 return $module.data(metadata.rating);
19828 }
19829
19830 return settings.initialRating;
19831 },
19832 maxRating: function () {
19833 if ($module.data(metadata.maxRating) !== undefined) {
19834 $module.removeData(metadata.maxRating);
19835
19836 return $module.data(metadata.maxRating);
19837 }
19838
19839 return settings.maxRating;
19840 },
19841 rating: function () {
19842 var
19843 currentRating = $icon.filter('.' + className.active).length
19844 ;
19845 module.verbose('Current rating retrieved', currentRating);
19846
19847 return currentRating;
19848 },
19849 },
19850
19851 set: {
19852 rating: function (rating) {
19853 var
19854 ratingIndex = Math.floor(
19855 rating - 1 >= 0
19856 ? rating - 1
19857 : 0
19858 ),
19859 $activeIcon = $icon.eq(ratingIndex),
19860 $partialActiveIcon = rating <= 1
19861 ? $activeIcon
19862 : $activeIcon.next(),
19863 filledPercentage = (rating % 1) * 100
19864 ;
19865 $module
19866 .removeClass(className.selected)
19867 ;
19868 $icon
19869 .removeClass(className.selected)
19870 .removeClass(className.active)
19871 .removeClass(className.partiallyActive)
19872 ;
19873 if (rating > 0) {
19874 module.verbose('Setting current rating to', rating);
19875 $activeIcon
19876 .prevAll()
19877 .addBack()
19878 .addClass(className.active)
19879 ;
19880 if ($activeIcon.next() && rating % 1 !== 0) {
19881 $partialActiveIcon
19882 .addClass(className.partiallyActive)
19883 .addClass(className.active)
19884 ;
19885 $partialActiveIcon
19886 .css(cssVars.filledCustomPropName, filledPercentage + '%')
19887 ;
19888 if ($partialActiveIcon.css('backgroundColor') === 'transparent') {
19889 $partialActiveIcon
19890 .removeClass(className.partiallyActive)
19891 .removeClass(className.active)
19892 ;
19893 }
19894 }
19895 }
19896 if (!module.is.initialLoad()) {
19897 settings.onRate.call(element, rating);
19898 }
19899 },
19900 initialLoad: function () {
19901 initialLoad = true;
19902 },
19903 },
19904
19905 setting: function (name, value) {
19906 module.debug('Changing setting', name, value);
19907 if ($.isPlainObject(name)) {
19908 $.extend(true, settings, name);
19909 } else if (value !== undefined) {
19910 if ($.isPlainObject(settings[name])) {
19911 $.extend(true, settings[name], value);
19912 } else {
19913 settings[name] = value;
19914 }
19915 } else {
19916 return settings[name];
19917 }
19918 },
19919 internal: function (name, value) {
19920 if ($.isPlainObject(name)) {
19921 $.extend(true, module, name);
19922 } else if (value !== undefined) {
19923 module[name] = value;
19924 } else {
19925 return module[name];
19926 }
19927 },
19928 debug: function () {
19929 if (!settings.silent && settings.debug) {
19930 if (settings.performance) {
19931 module.performance.log(arguments);
19932 } else {
19933 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
19934 module.debug.apply(console, arguments);
19935 }
19936 }
19937 },
19938 verbose: function () {
19939 if (!settings.silent && settings.verbose && settings.debug) {
19940 if (settings.performance) {
19941 module.performance.log(arguments);
19942 } else {
19943 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
19944 module.verbose.apply(console, arguments);
19945 }
19946 }
19947 },
19948 error: function () {
19949 if (!settings.silent) {
19950 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
19951 module.error.apply(console, arguments);
19952 }
19953 },
19954 performance: {
19955 log: function (message) {
19956 var
19957 currentTime,
19958 executionTime,
19959 previousTime
19960 ;
19961 if (settings.performance) {
19962 currentTime = Date.now();
19963 previousTime = time || currentTime;
19964 executionTime = currentTime - previousTime;
19965 time = currentTime;
19966 performance.push({
19967 Name: message[0],
19968 Arguments: [].slice.call(message, 1) || '',
19969 Element: element,
19970 'Execution Time': executionTime,
19971 });
19972 }
19973 clearTimeout(module.performance.timer);
19974 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
19975 },
19976 display: function () {
19977 var
19978 title = settings.name + ':',
19979 totalTime = 0
19980 ;
19981 time = false;
19982 clearTimeout(module.performance.timer);
19983 $.each(performance, function (index, data) {
19984 totalTime += data['Execution Time'];
19985 });
19986 title += ' ' + totalTime + 'ms';
19987 if ($allModules.length > 1) {
19988 title += ' (' + $allModules.length + ')';
19989 }
19990 if (performance.length > 0) {
19991 console.groupCollapsed(title);
19992 if (console.table) {
19993 console.table(performance);
19994 } else {
19995 $.each(performance, function (index, data) {
19996 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
19997 });
19998 }
19999 console.groupEnd();
20000 }
20001 performance = [];
20002 },
20003 },
20004 invoke: function (query, passedArguments, context) {
20005 var
20006 object = instance,
20007 maxDepth,
20008 found,
20009 response
20010 ;
20011 passedArguments = passedArguments || queryArguments;
20012 context = context || element;
20013 if (typeof query === 'string' && object !== undefined) {
20014 query = query.split(/[ .]/);
20015 maxDepth = query.length - 1;
20016 $.each(query, function (depth, value) {
20017 var camelCaseValue = depth !== maxDepth
20018 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
20019 : query
20020 ;
20021 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
20022 object = object[camelCaseValue];
20023 } else if (object[camelCaseValue] !== undefined) {
20024 found = object[camelCaseValue];
20025
20026 return false;
20027 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
20028 object = object[value];
20029 } else if (object[value] !== undefined) {
20030 found = object[value];
20031
20032 return false;
20033 } else {
20034 module.error(error.method, query);
20035
20036 return false;
20037 }
20038 });
20039 }
20040 if (isFunction(found)) {
20041 response = found.apply(context, passedArguments);
20042 } else if (found !== undefined) {
20043 response = found;
20044 }
20045 if (Array.isArray(returnedValue)) {
20046 returnedValue.push(response);
20047 } else if (returnedValue !== undefined) {
20048 returnedValue = [returnedValue, response];
20049 } else if (response !== undefined) {
20050 returnedValue = response;
20051 }
20052
20053 return found;
20054 },
20055 };
20056 if (methodInvoked) {
20057 if (instance === undefined) {
20058 module.initialize();
20059 }
20060 module.invoke(query);
20061 } else {
20062 if (instance !== undefined) {
20063 instance.invoke('destroy');
20064 }
20065 module.initialize();
20066 }
20067 });
20068
20069 return returnedValue !== undefined
20070 ? returnedValue
20071 : this;
20072 };
20073
20074 $.fn.rating.settings = {
20075
20076 name: 'Rating',
20077 namespace: 'rating',
20078
20079 icon: 'star',
20080
20081 silent: false,
20082 debug: false,
20083 verbose: false,
20084 performance: true,
20085
20086 initialRating: 0,
20087 interactive: true,
20088 maxRating: 4,
20089 clearable: 'auto',
20090
20091 fireOnInit: false,
20092
20093 onRate: function (rating) {},
20094
20095 error: {
20096 method: 'The method you called is not defined',
20097 },
20098
20099 metadata: {
20100 rating: 'rating',
20101 maxRating: 'maxRating',
20102 icon: 'icon',
20103 },
20104
20105 className: {
20106 active: 'active',
20107 disabled: 'disabled',
20108 selected: 'selected',
20109 loading: 'loading',
20110 partiallyActive: 'partial',
20111 },
20112
20113 cssVars: {
20114 filledCustomPropName: '--full',
20115 },
20116
20117 selector: {
20118 icon: '.icon',
20119 },
20120
20121 templates: {
20122 deQuote: function (string, encode) {
20123 return String(string).replace(/"/g, encode ? '&quot;' : '');
20124 },
20125 icon: function (maxRating, iconClass) {
20126 var
20127 icon = 1,
20128 html = '',
20129 deQuote = $.fn.rating.settings.templates.deQuote
20130 ;
20131 while (icon <= maxRating) {
20132 html += '<i class="' + deQuote(iconClass) + ' icon"></i>';
20133 icon++;
20134 }
20135
20136 return html;
20137 },
20138 },
20139
20140 };
20141})(jQuery, window, document);
20142
20143/*!
20144 * # Fomantic-UI 2.9.3 - Search
20145 * https://github.com/fomantic/Fomantic-UI/
20146 *
20147 *
20148 * Released under the MIT license
20149 * https://opensource.org/licenses/MIT
20150 *
20151 */
20152
20153(function ($, window, document) {
20154 'use strict';
20155
20156 function isFunction(obj) {
20157 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
20158 }
20159
20160 window = window !== undefined && window.Math === Math
20161 ? window
20162 : globalThis;
20163
20164 $.fn.search = function (parameters) {
20165 var
20166 $allModules = $(this),
20167
20168 time = Date.now(),
20169 performance = [],
20170
20171 query = arguments[0],
20172 methodInvoked = typeof query === 'string',
20173 queryArguments = [].slice.call(arguments, 1),
20174 returnedValue
20175 ;
20176 $allModules.each(function () {
20177 var
20178 settings = $.isPlainObject(parameters)
20179 ? $.extend(true, {}, $.fn.search.settings, parameters)
20180 : $.extend({}, $.fn.search.settings),
20181
20182 className = settings.className,
20183 metadata = settings.metadata,
20184 regExp = settings.regExp,
20185 fields = settings.fields,
20186 selector = settings.selector,
20187 error = settings.error,
20188 namespace = settings.namespace,
20189
20190 eventNamespace = '.' + namespace,
20191 moduleNamespace = namespace + '-module',
20192
20193 $module = $(this),
20194 $prompt = $module.find(selector.prompt),
20195 $searchButton = $module.find(selector.searchButton),
20196 $results = $module.find(selector.results),
20197 $result = $module.find(selector.result),
20198 $category = $module.find(selector.category),
20199
20200 element = this,
20201 instance = $module.data(moduleNamespace),
20202
20203 disabledBubbled = false,
20204 resultsDismissed = false,
20205
20206 module
20207 ;
20208
20209 module = {
20210
20211 initialize: function () {
20212 module.verbose('Initializing module');
20213 module.get.settings();
20214 module.determine.searchFields();
20215 module.bind.events();
20216 module.set.type();
20217 module.create.results();
20218 module.instantiate();
20219 },
20220 instantiate: function () {
20221 module.verbose('Storing instance of module', module);
20222 instance = module;
20223 $module
20224 .data(moduleNamespace, module)
20225 ;
20226 },
20227 destroy: function () {
20228 module.verbose('Destroying instance');
20229 $module
20230 .off(eventNamespace)
20231 .removeData(moduleNamespace)
20232 ;
20233 },
20234
20235 refresh: function () {
20236 module.debug('Refreshing selector cache');
20237 $prompt = $module.find(selector.prompt);
20238 $searchButton = $module.find(selector.searchButton);
20239 $category = $module.find(selector.category);
20240 $results = $module.find(selector.results);
20241 $result = $module.find(selector.result);
20242 },
20243
20244 refreshResults: function () {
20245 $results = $module.find(selector.results);
20246 $result = $module.find(selector.result);
20247 },
20248
20249 bind: {
20250 events: function () {
20251 module.verbose('Binding events to search');
20252 if (settings.automatic) {
20253 $module
20254 .on(module.get.inputEvent() + eventNamespace, selector.prompt, module.event.input)
20255 ;
20256 $prompt
20257 .attr('autocomplete', module.is.chrome() ? 'fomantic-search' : 'off')
20258 ;
20259 }
20260 $module
20261 // prompt
20262 .on('focus' + eventNamespace, selector.prompt, module.event.focus)
20263 .on('blur' + eventNamespace, selector.prompt, module.event.blur)
20264 .on('keydown' + eventNamespace, selector.prompt, module.handleKeyboard)
20265 // search button
20266 .on('click' + eventNamespace, selector.searchButton, module.query)
20267 // results
20268 .on('mousedown' + eventNamespace, selector.results, module.event.result.mousedown)
20269 .on('mouseup' + eventNamespace, selector.results, module.event.result.mouseup)
20270 .on('click' + eventNamespace, selector.result, module.event.result.click)
20271 ;
20272 },
20273 },
20274
20275 determine: {
20276 searchFields: function () {
20277 // this makes sure $.extend does not add specified search fields to default fields
20278 // this is the only setting which should not extend defaults
20279 if (parameters && parameters.searchFields !== undefined) {
20280 settings.searchFields = parameters.searchFields;
20281 }
20282 },
20283 },
20284
20285 event: {
20286 input: function () {
20287 if (settings.searchDelay) {
20288 clearTimeout(module.timer);
20289 module.timer = setTimeout(function () {
20290 if (module.is.focused()) {
20291 module.query();
20292 }
20293 }, settings.searchDelay);
20294 } else {
20295 module.query();
20296 }
20297 },
20298 focus: function () {
20299 module.set.focus();
20300 if (settings.searchOnFocus && module.has.minimumCharacters()) {
20301 module.query(function () {
20302 if (module.can.show()) {
20303 module.showResults();
20304 }
20305 });
20306 }
20307 },
20308 blur: function (event) {
20309 var
20310 pageLostFocus = document.activeElement === this,
20311 callback = function () {
20312 module.cancel.query();
20313 module.remove.focus();
20314 module.timer = setTimeout(function () { module.hideResults(); }, settings.hideDelay);
20315 }
20316 ;
20317 if (pageLostFocus) {
20318 return;
20319 }
20320 resultsDismissed = false;
20321 if (module.resultsClicked) {
20322 module.debug('Determining if user action caused search to close');
20323 $module
20324 .one('click.close' + eventNamespace, selector.results, function (event) {
20325 if (module.is.inMessage(event) || disabledBubbled) {
20326 $prompt.trigger('focus');
20327
20328 return;
20329 }
20330 disabledBubbled = false;
20331 if (!module.is.animating() && !module.is.hidden()) {
20332 callback();
20333 }
20334 })
20335 ;
20336 } else {
20337 module.debug('Input blurred without user action, closing results');
20338 callback();
20339 }
20340 },
20341 result: {
20342 mousedown: function () {
20343 module.resultsClicked = true;
20344 },
20345 mouseup: function () {
20346 module.resultsClicked = false;
20347 },
20348 click: function (event) {
20349 module.debug('Search result selected');
20350 var
20351 $result = $(this),
20352 $title = $result.find(selector.title).eq(0),
20353 $link = $result.is('a[href]')
20354 ? $result
20355 : $result.find('a[href]').eq(0),
20356 href = $link.attr('href') || false,
20357 target = $link.attr('target') || false,
20358 // title is used for result lookup
20359 value = $title.length > 0
20360 ? $title.text()
20361 : false,
20362 results = module.get.results(),
20363 result = $result.data(metadata.result) || module.get.result(value, results)
20364 ;
20365 var oldValue = module.get.value();
20366 if (isFunction(settings.onSelect)) {
20367 if (settings.onSelect.call(element, result, results) === false) {
20368 module.debug('Custom onSelect callback cancelled default select action');
20369 disabledBubbled = true;
20370
20371 return;
20372 }
20373 }
20374 module.hideResults();
20375 if (value && module.get.value() === oldValue) {
20376 module.set.value(value);
20377 }
20378 if (href) {
20379 event.preventDefault();
20380 module.verbose('Opening search link found in result', $link);
20381 if (target === '_blank' || event.ctrlKey) {
20382 window.open(href);
20383 } else {
20384 window.location.href = href;
20385 }
20386 }
20387 },
20388 },
20389 },
20390 ensureVisible: function ($el) {
20391 var
20392 elTop,
20393 elBottom,
20394 resultsScrollTop,
20395 resultsHeight
20396 ;
20397 if ($el.length === 0) {
20398 return;
20399 }
20400 elTop = $el.position().top;
20401 elBottom = elTop + $el.outerHeight(true);
20402
20403 resultsScrollTop = $results.scrollTop();
20404 resultsHeight = $results.height();
20405
20406 if (elTop < 0) {
20407 $results.scrollTop(resultsScrollTop + elTop);
20408 } else if (resultsHeight < elBottom) {
20409 $results.scrollTop(resultsScrollTop + (elBottom - resultsHeight));
20410 }
20411 },
20412 handleKeyboard: function (event) {
20413 var
20414 // force selector refresh
20415 $result = $module.find(selector.result),
20416 $category = $module.find(selector.category),
20417 $activeResult = $result.filter('.' + className.active),
20418 currentIndex = $result.index($activeResult),
20419 resultSize = $result.length,
20420 hasActiveResult = $activeResult.length > 0,
20421
20422 keyCode = event.which,
20423 keys = {
20424 backspace: 8,
20425 enter: 13,
20426 escape: 27,
20427 upArrow: 38,
20428 downArrow: 40,
20429 },
20430 newIndex
20431 ;
20432 // search shortcuts
20433 if (keyCode === keys.escape) {
20434 if (!module.is.visible()) {
20435 module.verbose('Escape key pressed, blurring search field');
20436 $prompt.trigger('blur');
20437 } else {
20438 module.hideResults();
20439 }
20440 event.stopPropagation();
20441 resultsDismissed = true;
20442 }
20443 if (module.is.visible()) {
20444 if (keyCode === keys.enter) {
20445 module.verbose('Enter key pressed, selecting active result');
20446 if ($result.filter('.' + className.active).length > 0) {
20447 module.event.result.click.call($result.filter('.' + className.active), event);
20448 event.preventDefault();
20449
20450 return false;
20451 }
20452 } else if (keyCode === keys.upArrow && hasActiveResult) {
20453 module.verbose('Up key pressed, changing active result');
20454 newIndex = currentIndex - 1 < 0
20455 ? currentIndex
20456 : currentIndex - 1;
20457 $category
20458 .removeClass(className.active)
20459 ;
20460 $result
20461 .removeClass(className.active)
20462 .eq(newIndex)
20463 .addClass(className.active)
20464 .closest($category)
20465 .addClass(className.active)
20466 ;
20467 module.ensureVisible($result.eq(newIndex));
20468 event.preventDefault();
20469 } else if (keyCode === keys.downArrow) {
20470 module.verbose('Down key pressed, changing active result');
20471 newIndex = currentIndex + 1 >= resultSize
20472 ? currentIndex
20473 : currentIndex + 1;
20474 $category
20475 .removeClass(className.active)
20476 ;
20477 $result
20478 .removeClass(className.active)
20479 .eq(newIndex)
20480 .addClass(className.active)
20481 .closest($category)
20482 .addClass(className.active)
20483 ;
20484 module.ensureVisible($result.eq(newIndex));
20485 event.preventDefault();
20486 }
20487 } else {
20488 // query shortcuts
20489 if (keyCode === keys.enter) {
20490 module.verbose('Enter key pressed, executing query');
20491 module.query();
20492 module.set.buttonPressed();
20493 $prompt.one('keyup', module.remove.buttonFocus);
20494 }
20495 }
20496 },
20497
20498 setup: {
20499 api: function (searchTerm, callback) {
20500 var
20501 apiSettings = {
20502 debug: settings.debug,
20503 on: false,
20504 cache: settings.cache,
20505 action: 'search',
20506 urlData: {
20507 query: searchTerm,
20508 },
20509 },
20510 apiCallbacks = {
20511 onSuccess: function (response, $module, xhr) {
20512 module.parse.response.call(element, response, searchTerm);
20513 callback();
20514 if (settings.apiSettings && typeof settings.apiSettings.onSuccess === 'function') {
20515 settings.apiSettings.onSuccess.call(this, response, $module, xhr);
20516 }
20517 },
20518 onFailure: function (response, $module, xhr) {
20519 module.displayMessage(error.serverError);
20520 callback();
20521 if (settings.apiSettings && typeof settings.apiSettings.onFailure === 'function') {
20522 settings.apiSettings.onFailure.call(this, response, $module, xhr);
20523 }
20524 },
20525 onAbort: function (status, $module, xhr) {
20526 if (settings.apiSettings && typeof settings.apiSettings.onAbort === 'function') {
20527 settings.apiSettings.onAbort.call(this, status, $module, xhr);
20528 }
20529 },
20530 onError: function (errorMessage, $module, xhr) {
20531 module.error();
20532 if (settings.apiSettings && typeof settings.apiSettings.onError === 'function') {
20533 settings.apiSettings.onError.call(this, errorMessage, $module, xhr);
20534 }
20535 },
20536 }
20537 ;
20538 $.extend(true, apiSettings, settings.apiSettings, apiCallbacks);
20539 module.verbose('Setting up API request', apiSettings);
20540 $module.api(apiSettings);
20541 },
20542 },
20543
20544 can: {
20545 useAPI: function () {
20546 return $.fn.api !== undefined;
20547 },
20548 show: function () {
20549 return module.is.focused() && !module.is.visible() && !module.is.empty();
20550 },
20551 transition: function () {
20552 return settings.transition && $.fn.transition !== undefined;
20553 },
20554 },
20555
20556 is: {
20557 animating: function () {
20558 return $results.hasClass(className.animating);
20559 },
20560 chrome: function () {
20561 return !!window.chrome && !window.StyleMedia;
20562 },
20563 hidden: function () {
20564 return $results.hasClass(className.hidden);
20565 },
20566 inMessage: function (event) {
20567 if (!event.target) {
20568 return;
20569 }
20570 var
20571 $target = $(event.target),
20572 isInDOM = $.contains(document.documentElement, event.target)
20573 ;
20574
20575 return isInDOM && $target.closest(selector.message).length > 0;
20576 },
20577 empty: function () {
20578 return $results.html() === '';
20579 },
20580 visible: function () {
20581 return $results.filter(':visible').length > 0;
20582 },
20583 focused: function () {
20584 return $prompt.filter(':focus').length > 0;
20585 },
20586 },
20587
20588 get: {
20589 settings: function () {
20590 if ($.isPlainObject(parameters) && parameters.searchFullText) {
20591 settings.fullTextSearch = parameters.searchFullText;
20592 module.error(settings.error.oldSearchSyntax, element);
20593 }
20594 if (settings.ignoreDiacritics && !String.prototype.normalize) {
20595 settings.ignoreDiacritics = false;
20596 module.error(error.noNormalize, element);
20597 }
20598 },
20599 inputEvent: function () {
20600 var
20601 prompt = $prompt[0],
20602 inputEvent = prompt !== undefined && prompt.oninput !== undefined
20603 ? 'input'
20604 : (prompt !== undefined && prompt.onpropertychange !== undefined
20605 ? 'propertychange'
20606 : 'keyup')
20607 ;
20608
20609 return inputEvent;
20610 },
20611 value: function () {
20612 return $prompt.val();
20613 },
20614 results: function () {
20615 return $module.data(metadata.results);
20616 },
20617 result: function (value, results) {
20618 var
20619 result = false
20620 ;
20621 value = value !== undefined
20622 ? value
20623 : module.get.value();
20624 results = results !== undefined
20625 ? results
20626 : module.get.results();
20627 if (settings.type === 'category') {
20628 module.debug('Finding result that matches', value);
20629 $.each(results, function (index, category) {
20630 if (Array.isArray(category.results)) {
20631 result = module.search.object(value, category.results)[0];
20632 // don't continue searching if a result is found
20633 if (result) {
20634 return false;
20635 }
20636 }
20637 });
20638 } else {
20639 module.debug('Finding result in results object', value);
20640 result = module.search.object(value, results)[0];
20641 }
20642
20643 return result || false;
20644 },
20645 },
20646
20647 select: {
20648 firstResult: function () {
20649 module.verbose('Selecting first result');
20650 $result.first().addClass(className.active);
20651 },
20652 },
20653
20654 set: {
20655 focus: function () {
20656 $module.addClass(className.focus);
20657 },
20658 loading: function () {
20659 $module.addClass(className.loading);
20660 },
20661 value: function (value) {
20662 module.verbose('Setting search input value', value);
20663 $prompt
20664 .val(value)
20665 ;
20666 },
20667 type: function (type) {
20668 type = type || settings.type;
20669 if (className[type]) {
20670 $module.addClass(className[type]);
20671 }
20672 },
20673 buttonPressed: function () {
20674 $searchButton.addClass(className.pressed);
20675 },
20676 },
20677
20678 remove: {
20679 loading: function () {
20680 $module.removeClass(className.loading);
20681 },
20682 focus: function () {
20683 $module.removeClass(className.focus);
20684 },
20685 buttonPressed: function () {
20686 $searchButton.removeClass(className.pressed);
20687 },
20688 diacritics: function (text) {
20689 return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036F]/g, '') : text;
20690 },
20691 },
20692
20693 query: function (callback) {
20694 callback = isFunction(callback)
20695 ? callback
20696 : function () {};
20697 var
20698 searchTerm = module.get.value(),
20699 cache = module.read.cache(searchTerm)
20700 ;
20701 callback = callback || function () {};
20702 if (module.has.minimumCharacters()) {
20703 if (cache) {
20704 module.debug('Reading result from cache', searchTerm);
20705 module.save.results(cache.results);
20706 settings.onResults.call(element, cache.results, true);
20707 module.addResults(cache.html);
20708 module.inject.id(cache.results);
20709 callback();
20710 } else {
20711 module.debug('Querying for', searchTerm);
20712 if ($.isPlainObject(settings.source) || Array.isArray(settings.source)) {
20713 module.search.local(searchTerm);
20714 callback();
20715 } else if (module.can.useAPI()) {
20716 module.search.remote(searchTerm, callback);
20717 } else {
20718 module.error(error.source);
20719 callback();
20720 }
20721 }
20722 settings.onSearchQuery.call(element, searchTerm);
20723 } else {
20724 module.hideResults();
20725 }
20726 },
20727
20728 search: {
20729 local: function (searchTerm) {
20730 var
20731 results = module.search.object(searchTerm, settings.source),
20732 searchHTML
20733 ;
20734 module.set.loading();
20735 module.save.results(results);
20736 module.debug('Returned full local search results', results);
20737 if (settings.maxResults > 0) {
20738 module.debug('Using specified max results', results);
20739 results = results.slice(0, settings.maxResults);
20740 }
20741 if (settings.type === 'category') {
20742 results = module.create.categoryResults(results);
20743 }
20744 searchHTML = module.generateResults({
20745 results: results,
20746 });
20747 module.remove.loading();
20748 module.addResults(searchHTML);
20749 module.inject.id(results);
20750 module.write.cache(searchTerm, {
20751 html: searchHTML,
20752 results: results,
20753 });
20754 },
20755 remote: function (searchTerm, callback) {
20756 callback = isFunction(callback)
20757 ? callback
20758 : function () {};
20759 if ($module.api('is loading')) {
20760 $module.api('abort');
20761 }
20762 module.setup.api(searchTerm, callback);
20763 $module
20764 .api('query')
20765 ;
20766 },
20767 object: function (searchTerm, source, searchFields) {
20768 searchTerm = module.remove.diacritics(String(searchTerm));
20769 var
20770 results = [],
20771 exactResults = [],
20772 fuzzyResults = [],
20773 searchExp = searchTerm.replace(regExp.escape, '\\$&'),
20774 matchRegExp = new RegExp(regExp.beginsWith + searchExp, 'i'),
20775
20776 // avoid duplicates when pushing results
20777 addResult = function (array, result) {
20778 var
20779 notResult = $.inArray(result, results) === -1,
20780 notFuzzyResult = $.inArray(result, fuzzyResults) === -1,
20781 notExactResults = $.inArray(result, exactResults) === -1
20782 ;
20783 if (notResult && notFuzzyResult && notExactResults) {
20784 array.push(result);
20785 }
20786 }
20787 ;
20788 source = source || settings.source;
20789 searchFields = searchFields !== undefined
20790 ? searchFields
20791 : settings.searchFields;
20792
20793 // search fields should be array to loop correctly
20794 if (!Array.isArray(searchFields)) {
20795 searchFields = [searchFields];
20796 }
20797
20798 // exit conditions if no source
20799 if (source === undefined || source === false) {
20800 module.error(error.source);
20801
20802 return [];
20803 }
20804 // iterate through search fields looking for matches
20805 var lastSearchFieldIndex = searchFields.length - 1;
20806 $.each(source, function (label, content) {
20807 var concatenatedContent = [];
20808 $.each(searchFields, function (index, field) {
20809 var
20810 fieldExists = (typeof content[field] === 'string') || (typeof content[field] === 'number')
20811 ;
20812 if (fieldExists) {
20813 var text;
20814 text = typeof content[field] === 'string'
20815 ? module.remove.diacritics(content[field])
20816 : content[field].toString();
20817 if (settings.fullTextSearch === 'all') {
20818 concatenatedContent.push(text);
20819 if (index < lastSearchFieldIndex) {
20820 return true;
20821 }
20822 text = concatenatedContent.join(' ');
20823 }
20824 if (settings.fullTextSearch !== 'all' && text.search(matchRegExp) !== -1) {
20825 // content starts with value (first in results)
20826 addResult(results, content);
20827 } else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
20828 addResult(exactResults, content);
20829 } else if (settings.fullTextSearch === 'some' && module.wordSearch(searchTerm, text)) {
20830 addResult(exactResults, content);
20831 } else if (settings.fullTextSearch === 'all' && module.wordSearch(searchTerm, text, true)) {
20832 addResult(exactResults, content);
20833 } else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
20834 // content fuzzy matches (last in results)
20835 addResult(fuzzyResults, content);
20836 }
20837 }
20838 });
20839 });
20840 $.merge(exactResults, fuzzyResults);
20841 $.merge(results, exactResults);
20842
20843 return results;
20844 },
20845 },
20846 exactSearch: function (query, term) {
20847 query = query.toLowerCase();
20848 term = term.toLowerCase();
20849
20850 return term.indexOf(query) > -1;
20851 },
20852 wordSearch: function (query, term, matchAll) {
20853 var allWords = query.split(/\s+/),
20854 w,
20855 wL = allWords.length,
20856 found = false
20857 ;
20858 for (w = 0; w < wL; w++) {
20859 found = module.exactSearch(allWords[w], term);
20860 if ((!found && matchAll) || (found && !matchAll)) {
20861 break;
20862 }
20863 }
20864
20865 return found;
20866 },
20867 fuzzySearch: function (query, term) {
20868 var
20869 termLength = term.length,
20870 queryLength = query.length
20871 ;
20872 if (typeof query !== 'string') {
20873 return false;
20874 }
20875 query = query.toLowerCase();
20876 term = term.toLowerCase();
20877 if (queryLength > termLength) {
20878 return false;
20879 }
20880 if (queryLength === termLength) {
20881 return query === term;
20882 }
20883 for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
20884 var
20885 continueSearch = false,
20886 queryCharacter = query.charCodeAt(characterIndex)
20887 ;
20888 while (nextCharacterIndex < termLength) {
20889 if (term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
20890 continueSearch = true;
20891
20892 break;
20893 }
20894 }
20895
20896 if (!continueSearch) {
20897 return false;
20898 }
20899 }
20900
20901 return true;
20902 },
20903
20904 parse: {
20905 response: function (response, searchTerm) {
20906 if (Array.isArray(response)) {
20907 var o = {};
20908 o[fields.results] = response;
20909 response = o;
20910 }
20911 var
20912 searchHTML = module.generateResults(response)
20913 ;
20914 module.verbose('Parsing server response', response);
20915 if (response !== undefined) {
20916 if (searchTerm !== undefined && response[fields.results] !== undefined) {
20917 module.addResults(searchHTML);
20918 module.inject.id(response[fields.results]);
20919 module.write.cache(searchTerm, {
20920 html: searchHTML,
20921 results: response[fields.results],
20922 });
20923 module.save.results(response[fields.results]);
20924 }
20925 }
20926 },
20927 },
20928
20929 cancel: {
20930 query: function () {
20931 if (module.can.useAPI()) {
20932 $module.api('abort');
20933 }
20934 },
20935 },
20936
20937 has: {
20938 minimumCharacters: function () {
20939 var
20940 searchTerm = module.get.value(),
20941 numCharacters = searchTerm.length
20942 ;
20943
20944 return numCharacters >= settings.minCharacters;
20945 },
20946 results: function () {
20947 if ($results.length === 0) {
20948 return false;
20949 }
20950 var
20951 html = $results.html()
20952 ;
20953
20954 return html !== '';
20955 },
20956 },
20957
20958 clear: {
20959 cache: function (value) {
20960 var
20961 cache = $module.data(metadata.cache)
20962 ;
20963 if (!value) {
20964 module.debug('Clearing cache', value);
20965 $module.removeData(metadata.cache);
20966 } else if (value && cache && cache[value]) {
20967 module.debug('Removing value from cache', value);
20968 delete cache[value];
20969 $module.data(metadata.cache, cache);
20970 }
20971 },
20972 },
20973
20974 read: {
20975 cache: function (name) {
20976 var
20977 cache = $module.data(metadata.cache)
20978 ;
20979 if (settings.cache) {
20980 module.verbose('Checking cache for generated html for query', name);
20981
20982 return (typeof cache === 'object') && (cache[name] !== undefined)
20983 ? cache[name]
20984 : false;
20985 }
20986
20987 return false;
20988 },
20989 },
20990
20991 create: {
20992 categoryResults: function (results) {
20993 var
20994 categoryResults = {}
20995 ;
20996 $.each(results, function (index, result) {
20997 if (!result.category) {
20998 return;
20999 }
21000 if (categoryResults[result.category] === undefined) {
21001 module.verbose('Creating new category of results', result.category);
21002 categoryResults[result.category] = {
21003 name: result.category,
21004 results: [result],
21005 };
21006 } else {
21007 categoryResults[result.category].results.push(result);
21008 }
21009 });
21010
21011 return categoryResults;
21012 },
21013 id: function (resultIndex, categoryIndex) {
21014 var
21015 resultID = resultIndex + 1, // not zero indexed
21016 letterID,
21017 id
21018 ;
21019 if (categoryIndex !== undefined) {
21020 // start char code for "A"
21021 letterID = String.fromCharCode(97 + categoryIndex);
21022 id = letterID + resultID;
21023 module.verbose('Creating category result id', id);
21024 } else {
21025 id = resultID;
21026 module.verbose('Creating result id', id);
21027 }
21028
21029 return id;
21030 },
21031 results: function () {
21032 if ($results.length === 0) {
21033 $results = $('<div />')
21034 .addClass(className.results)
21035 .appendTo($module)
21036 ;
21037 }
21038 },
21039 },
21040
21041 inject: {
21042 result: function (result, resultIndex, categoryIndex) {
21043 module.verbose('Injecting result into results');
21044 var
21045 $selectedResult = categoryIndex !== undefined
21046 ? $results
21047 .children().eq(categoryIndex)
21048 .children(selector.results)
21049 .first()
21050 .children(selector.result)
21051 .eq(resultIndex)
21052 : $results
21053 .children(selector.result).eq(resultIndex)
21054 ;
21055 module.verbose('Injecting results metadata', $selectedResult);
21056 $selectedResult
21057 .data(metadata.result, result)
21058 ;
21059 },
21060 id: function (results) {
21061 module.debug('Injecting unique ids into results');
21062 var
21063 // since results may be object, we must use counters
21064 categoryIndex = 0,
21065 resultIndex = 0
21066 ;
21067 if (settings.type === 'category') {
21068 // iterate through each category result
21069 $.each(results, function (index, category) {
21070 if (category.results.length > 0) {
21071 resultIndex = 0;
21072 $.each(category.results, function (index, result) {
21073 if (result.id === undefined) {
21074 result.id = module.create.id(resultIndex, categoryIndex);
21075 }
21076 module.inject.result(result, resultIndex, categoryIndex);
21077 resultIndex++;
21078 });
21079 categoryIndex++;
21080 }
21081 });
21082 } else {
21083 // top level
21084 $.each(results, function (index, result) {
21085 if (result.id === undefined) {
21086 result.id = module.create.id(resultIndex);
21087 }
21088 module.inject.result(result, resultIndex);
21089 resultIndex++;
21090 });
21091 }
21092
21093 return results;
21094 },
21095 },
21096
21097 save: {
21098 results: function (results) {
21099 module.verbose('Saving current search results to metadata', results);
21100 $module.data(metadata.results, results);
21101 },
21102 },
21103
21104 write: {
21105 cache: function (name, value) {
21106 var
21107 cache = $module.data(metadata.cache) !== undefined
21108 ? $module.data(metadata.cache)
21109 : {}
21110 ;
21111 if (settings.cache) {
21112 module.verbose('Writing generated html to cache', name, value);
21113 cache[name] = value;
21114 $module
21115 .data(metadata.cache, cache)
21116 ;
21117 }
21118 },
21119 },
21120
21121 addResults: function (html) {
21122 if (isFunction(settings.onResultsAdd)) {
21123 if (settings.onResultsAdd.call($results, html) === false) {
21124 module.debug('onResultsAdd callback cancelled default action');
21125
21126 return false;
21127 }
21128 }
21129 if (html) {
21130 $results
21131 .html(html)
21132 ;
21133 module.refreshResults();
21134 if (settings.selectFirstResult) {
21135 module.select.firstResult();
21136 }
21137 module.showResults();
21138 } else {
21139 module.hideResults(function () {
21140 $results.empty();
21141 });
21142 }
21143 },
21144
21145 showResults: function (callback) {
21146 callback = isFunction(callback)
21147 ? callback
21148 : function () {};
21149 if (resultsDismissed) {
21150 return;
21151 }
21152 if (!module.is.visible() && module.has.results()) {
21153 if (module.can.transition()) {
21154 module.debug('Showing results with css animations');
21155 $results
21156 .transition({
21157 animation: settings.transition + ' in',
21158 debug: settings.debug,
21159 verbose: settings.verbose,
21160 silent: settings.silent,
21161 duration: settings.duration,
21162 onShow: function () {
21163 var $firstResult = $module.find(selector.result).eq(0);
21164 module.ensureVisible($firstResult);
21165 },
21166 onComplete: function () {
21167 callback();
21168 },
21169 queue: true,
21170 })
21171 ;
21172 } else {
21173 module.debug('Showing results with javascript');
21174 $results
21175 .stop()
21176 .fadeIn(settings.duration, settings.easing)
21177 ;
21178 }
21179 settings.onResultsOpen.call($results);
21180 }
21181 },
21182 hideResults: function (callback) {
21183 callback = isFunction(callback)
21184 ? callback
21185 : function () {};
21186 if (module.is.visible()) {
21187 if (module.can.transition()) {
21188 module.debug('Hiding results with css animations');
21189 $results
21190 .transition({
21191 animation: settings.transition + ' out',
21192 debug: settings.debug,
21193 verbose: settings.verbose,
21194 silent: settings.silent,
21195 duration: settings.duration,
21196 onComplete: function () {
21197 callback();
21198 },
21199 queue: true,
21200 })
21201 ;
21202 } else {
21203 module.debug('Hiding results with javascript');
21204 $results
21205 .stop()
21206 .fadeOut(settings.duration, settings.easing)
21207 ;
21208 }
21209 settings.onResultsClose.call($results);
21210 }
21211 },
21212
21213 generateResults: function (response) {
21214 module.debug('Generating html from response', response);
21215 var
21216 template = settings.templates[settings.type],
21217 isProperObject = $.isPlainObject(response[fields.results]) && !$.isEmptyObject(response[fields.results]),
21218 isProperArray = Array.isArray(response[fields.results]) && response[fields.results].length > 0,
21219 html = ''
21220 ;
21221 if (isProperObject || isProperArray) {
21222 if (settings.maxResults > 0) {
21223 if (isProperObject) {
21224 if (settings.type === 'standard') {
21225 module.error(error.maxResults);
21226 }
21227 } else {
21228 response[fields.results] = response[fields.results].slice(0, settings.maxResults);
21229 }
21230 }
21231 if (isFunction(template)) {
21232 html = template(response, fields, settings.preserveHTML);
21233 } else {
21234 module.error(error.noTemplate, false);
21235 }
21236 } else if (settings.showNoResults) {
21237 html = module.displayMessage(error.noResults, 'empty', error.noResultsHeader);
21238 }
21239 settings.onResults.call(element, response);
21240
21241 return html;
21242 },
21243
21244 displayMessage: function (text, type, header) {
21245 type = type || 'standard';
21246 module.debug('Displaying message', text, type, header);
21247 module.addResults(settings.templates.message(text, type, header));
21248
21249 return settings.templates.message(text, type, header);
21250 },
21251
21252 setting: function (name, value) {
21253 if ($.isPlainObject(name)) {
21254 $.extend(true, settings, name);
21255 } else if (value !== undefined) {
21256 settings[name] = value;
21257 } else {
21258 return settings[name];
21259 }
21260 },
21261 internal: function (name, value) {
21262 if ($.isPlainObject(name)) {
21263 $.extend(true, module, name);
21264 } else if (value !== undefined) {
21265 module[name] = value;
21266 } else {
21267 return module[name];
21268 }
21269 },
21270 debug: function () {
21271 if (!settings.silent && settings.debug) {
21272 if (settings.performance) {
21273 module.performance.log(arguments);
21274 } else {
21275 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
21276 module.debug.apply(console, arguments);
21277 }
21278 }
21279 },
21280 verbose: function () {
21281 if (!settings.silent && settings.verbose && settings.debug) {
21282 if (settings.performance) {
21283 module.performance.log(arguments);
21284 } else {
21285 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
21286 module.verbose.apply(console, arguments);
21287 }
21288 }
21289 },
21290 error: function () {
21291 if (!settings.silent) {
21292 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
21293 module.error.apply(console, arguments);
21294 }
21295 },
21296 performance: {
21297 log: function (message) {
21298 var
21299 currentTime,
21300 executionTime,
21301 previousTime
21302 ;
21303 if (settings.performance) {
21304 currentTime = Date.now();
21305 previousTime = time || currentTime;
21306 executionTime = currentTime - previousTime;
21307 time = currentTime;
21308 performance.push({
21309 Name: message[0],
21310 Arguments: [].slice.call(message, 1) || '',
21311 Element: element,
21312 'Execution Time': executionTime,
21313 });
21314 }
21315 clearTimeout(module.performance.timer);
21316 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
21317 },
21318 display: function () {
21319 var
21320 title = settings.name + ':',
21321 totalTime = 0
21322 ;
21323 time = false;
21324 clearTimeout(module.performance.timer);
21325 $.each(performance, function (index, data) {
21326 totalTime += data['Execution Time'];
21327 });
21328 title += ' ' + totalTime + 'ms';
21329 if ($allModules.length > 1) {
21330 title += ' (' + $allModules.length + ')';
21331 }
21332 if (performance.length > 0) {
21333 console.groupCollapsed(title);
21334 if (console.table) {
21335 console.table(performance);
21336 } else {
21337 $.each(performance, function (index, data) {
21338 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
21339 });
21340 }
21341 console.groupEnd();
21342 }
21343 performance = [];
21344 },
21345 },
21346 invoke: function (query, passedArguments, context) {
21347 var
21348 object = instance,
21349 maxDepth,
21350 found,
21351 response
21352 ;
21353 passedArguments = passedArguments || queryArguments;
21354 context = context || element;
21355 if (typeof query === 'string' && object !== undefined) {
21356 query = query.split(/[ .]/);
21357 maxDepth = query.length - 1;
21358 $.each(query, function (depth, value) {
21359 var camelCaseValue = depth !== maxDepth
21360 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
21361 : query
21362 ;
21363 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
21364 object = object[camelCaseValue];
21365 } else if (object[camelCaseValue] !== undefined) {
21366 found = object[camelCaseValue];
21367
21368 return false;
21369 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
21370 object = object[value];
21371 } else if (object[value] !== undefined) {
21372 found = object[value];
21373
21374 return false;
21375 } else {
21376 module.error(error.method, query);
21377
21378 return false;
21379 }
21380 });
21381 }
21382 if (isFunction(found)) {
21383 response = found.apply(context, passedArguments);
21384 } else if (found !== undefined) {
21385 response = found;
21386 }
21387 if (Array.isArray(returnedValue)) {
21388 returnedValue.push(response);
21389 } else if (returnedValue !== undefined) {
21390 returnedValue = [returnedValue, response];
21391 } else if (response !== undefined) {
21392 returnedValue = response;
21393 }
21394
21395 return found;
21396 },
21397 };
21398 if (methodInvoked) {
21399 if (instance === undefined) {
21400 module.initialize();
21401 }
21402 module.invoke(query);
21403 } else {
21404 if (instance !== undefined) {
21405 instance.invoke('destroy');
21406 }
21407 module.initialize();
21408 }
21409 });
21410
21411 return returnedValue !== undefined
21412 ? returnedValue
21413 : this;
21414 };
21415
21416 $.fn.search.settings = {
21417
21418 name: 'Search',
21419 namespace: 'search',
21420
21421 silent: false,
21422 debug: false,
21423 verbose: false,
21424 performance: true,
21425
21426 // template to use (specified in settings.templates)
21427 type: 'standard',
21428
21429 // minimum characters required to search
21430 minCharacters: 1,
21431
21432 // whether to select first result after searching automatically
21433 selectFirstResult: false,
21434
21435 // API config
21436 apiSettings: false,
21437
21438 // object to search
21439 source: false,
21440
21441 // Whether search should query current term on focus
21442 searchOnFocus: true,
21443
21444 // fields to search
21445 searchFields: [
21446 'id',
21447 'title',
21448 'description',
21449 ],
21450
21451 // field to display in standard results template
21452 displayField: '',
21453
21454 // search anywhere in value (set to 'exact' to require exact matches
21455 fullTextSearch: 'exact',
21456
21457 // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
21458 ignoreDiacritics: false,
21459
21460 // whether to add events to prompt automatically
21461 automatic: true,
21462
21463 // delay before hiding menu after blur
21464 hideDelay: 0,
21465
21466 // delay before searching
21467 searchDelay: 200,
21468
21469 // maximum results returned from search
21470 maxResults: 7,
21471
21472 // whether to store lookups in local cache
21473 cache: true,
21474
21475 // whether no results errors should be shown
21476 showNoResults: true,
21477
21478 // preserve possible html of resultset values
21479 preserveHTML: true,
21480
21481 // transition settings
21482 transition: 'scale',
21483 duration: 200,
21484 easing: 'easeOutExpo',
21485
21486 // callbacks
21487 onSelect: false,
21488 onResultsAdd: false,
21489
21490 onSearchQuery: function (query) {},
21491 onResults: function (response, fromCache) {},
21492
21493 onResultsOpen: function () {},
21494 onResultsClose: function () {},
21495
21496 className: {
21497 animating: 'animating',
21498 active: 'active',
21499 category: 'category',
21500 empty: 'empty',
21501 focus: 'focus',
21502 hidden: 'hidden',
21503 loading: 'loading',
21504 results: 'results',
21505 pressed: 'down',
21506 },
21507
21508 error: {
21509 source: 'Cannot search. No source used, and Fomantic API module was not included',
21510 noResultsHeader: 'No Results',
21511 noResults: 'Your search returned no results',
21512 noTemplate: 'A valid template name was not specified.',
21513 oldSearchSyntax: 'searchFullText setting has been renamed fullTextSearch for consistency, please adjust your settings.',
21514 serverError: 'There was an issue querying the server.',
21515 maxResults: 'Results must be an array to use maxResults setting',
21516 method: 'The method you called is not defined.',
21517 noNormalize: '"ignoreDiacritics" setting will be ignored. Browser does not support String().normalize(). You may consider including <https://cdn.jsdelivr.net/npm/unorm@1.4.1/lib/unorm.min.js> as a polyfill.',
21518 },
21519
21520 metadata: {
21521 cache: 'cache',
21522 results: 'results',
21523 result: 'result',
21524 },
21525
21526 regExp: {
21527 escape: /[$()*+./?[\\\]^{|}-]/g,
21528 beginsWith: '(?:\\s|^)',
21529 },
21530
21531 // maps api response attributes to internal representation
21532 fields: {
21533 categories: 'results', // array of categories (category view)
21534 categoryName: 'name', // name of category (category view)
21535 categoryResults: 'results', // array of results (category view)
21536 description: 'description', // result description
21537 image: 'image', // result image
21538 price: 'price', // result price
21539 results: 'results', // array of results (standard)
21540 title: 'title', // result title
21541 url: 'url', // result url
21542 action: 'action', // "view more" object name
21543 actionText: 'text', // "view more" text
21544 actionURL: 'url', // "view more" url
21545 },
21546
21547 selector: {
21548 prompt: '.prompt',
21549 searchButton: '.search.button',
21550 results: '.results',
21551 message: '.results > .message',
21552 category: '.category',
21553 result: '.result',
21554 title: '.title, .name',
21555 },
21556
21557 templates: {
21558 escape: function (string, preserveHTML) {
21559 if (preserveHTML) {
21560 return string;
21561 }
21562 var
21563 badChars = /["'<>`]/g,
21564 shouldEscape = /["&'<>`]/,
21565 escape = {
21566 '<': '&lt;',
21567 '>': '&gt;',
21568 '"': '&quot;',
21569 "'": '&#x27;',
21570 '`': '&#x60;',
21571 },
21572 escapedChar = function (chr) {
21573 return escape[chr];
21574 };
21575 if (shouldEscape.test(string)) {
21576 string = string.replace(/&(?![\d#a-z]{1,12};)/gi, '&amp;');
21577
21578 return string.replace(badChars, escapedChar);
21579 }
21580
21581 return string;
21582 },
21583 message: function (message, type, header) {
21584 var
21585 html = ''
21586 ;
21587 if (message !== undefined && type !== undefined) {
21588 html += ''
21589 + '<div class="message ' + type + '">';
21590 if (header) {
21591 html += ''
21592 + '<div class="header">' + header + '</div>';
21593 }
21594 html += ' <div class="description">' + message + '</div>';
21595 html += '</div>';
21596 }
21597
21598 return html;
21599 },
21600 category: function (response, fields, preserveHTML) {
21601 var
21602 html = '',
21603 escape = $.fn.search.settings.templates.escape
21604 ;
21605 if (response[fields.categoryResults] !== undefined) {
21606 // each category
21607 $.each(response[fields.categoryResults], function (index, category) {
21608 if (category[fields.results] !== undefined && category.results.length > 0) {
21609 html += '<div class="category">';
21610
21611 if (category[fields.categoryName] !== undefined) {
21612 html += '<div class="name">' + escape(category[fields.categoryName], preserveHTML) + '</div>';
21613 }
21614
21615 // each item inside category
21616 html += '<div class="results">';
21617 $.each(category.results, function (index, result) {
21618 html += result[fields.url]
21619 ? '<a class="result" href="' + result[fields.url].replace(/"/g, '') + '">'
21620 : '<a class="result">';
21621 if (result[fields.image] !== undefined) {
21622 html += ''
21623 + '<div class="image">'
21624 + ' <img src="' + result[fields.image].replace(/"/g, '') + '">'
21625 + '</div>';
21626 }
21627 html += '<div class="content">';
21628 if (result[fields.price] !== undefined) {
21629 html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
21630 }
21631 if (result[fields.title] !== undefined) {
21632 html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
21633 }
21634 if (result[fields.description] !== undefined) {
21635 html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
21636 }
21637 html += ''
21638 + '</div>';
21639 html += '</a>';
21640 });
21641 html += '</div>';
21642 html += ''
21643 + '</div>';
21644 }
21645 });
21646 if (response[fields.action]) {
21647 html += fields.actionURL === false
21648 ? ''
21649 + '<div class="action">'
21650 + escape(response[fields.action][fields.actionText], preserveHTML)
21651 + '</div>'
21652 : ''
21653 + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g, '') + '" class="action">'
21654 + escape(response[fields.action][fields.actionText], preserveHTML)
21655 + '</a>';
21656 }
21657
21658 return html;
21659 }
21660
21661 return false;
21662 },
21663 standard: function (response, fields, preserveHTML) {
21664 var
21665 html = '',
21666 escape = $.fn.search.settings.templates.escape
21667 ;
21668 if (response[fields.results] !== undefined) {
21669 // each result
21670 $.each(response[fields.results], function (index, result) {
21671 html += result[fields.url]
21672 ? '<a class="result" href="' + result[fields.url].replace(/"/g, '') + '">'
21673 : '<a class="result">';
21674 if (result[fields.image] !== undefined) {
21675 html += ''
21676 + '<div class="image">'
21677 + ' <img src="' + result[fields.image].replace(/"/g, '') + '">'
21678 + '</div>';
21679 }
21680 html += '<div class="content">';
21681 if (result[fields.price] !== undefined) {
21682 html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
21683 }
21684 if (result[fields.title] !== undefined) {
21685 html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
21686 }
21687 if (result[fields.description] !== undefined) {
21688 html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
21689 }
21690 html += ''
21691 + '</div>';
21692 html += '</a>';
21693 });
21694 if (response[fields.action]) {
21695 html += fields.actionURL === false
21696 ? ''
21697 + '<div class="action">'
21698 + escape(response[fields.action][fields.actionText], preserveHTML)
21699 + '</div>'
21700 : ''
21701 + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g, '') + '" class="action">'
21702 + escape(response[fields.action][fields.actionText], preserveHTML)
21703 + '</a>';
21704 }
21705
21706 return html;
21707 }
21708
21709 return false;
21710 },
21711 },
21712 };
21713
21714 $.extend($.easing, {
21715 easeOutExpo: function (x) {
21716 return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
21717 },
21718 });
21719})(jQuery, window, document);
21720
21721/*!
21722 * # Fomantic-UI 2.9.3 - Shape
21723 * https://github.com/fomantic/Fomantic-UI/
21724 *
21725 *
21726 * Released under the MIT license
21727 * https://opensource.org/licenses/MIT
21728 *
21729 */
21730
21731(function ($, window, document) {
21732 'use strict';
21733
21734 function isFunction(obj) {
21735 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
21736 }
21737
21738 window = window !== undefined && window.Math === Math
21739 ? window
21740 : globalThis;
21741
21742 $.fn.shape = function (parameters) {
21743 var
21744 $allModules = $(this),
21745
21746 time = Date.now(),
21747 performance = [],
21748
21749 query = arguments[0],
21750 methodInvoked = typeof query === 'string',
21751 queryArguments = [].slice.call(arguments, 1),
21752
21753 returnedValue
21754 ;
21755
21756 $allModules.each(function () {
21757 var
21758 settings = $.isPlainObject(parameters)
21759 ? $.extend(true, {}, $.fn.shape.settings, parameters)
21760 : $.extend({}, $.fn.shape.settings),
21761
21762 // internal aliases
21763 namespace = settings.namespace,
21764 selector = settings.selector,
21765 error = settings.error,
21766 className = settings.className,
21767
21768 // define namespaces for modules
21769 eventNamespace = '.' + namespace,
21770 moduleNamespace = 'module-' + namespace,
21771
21772 // selector cache
21773 $module = $(this),
21774 $sides = $module.find('>' + selector.sides),
21775 $side = $sides.find('>' + selector.side),
21776
21777 // private variables
21778 nextIndex = false,
21779 $activeSide,
21780 $nextSide,
21781
21782 // standard module
21783 element = this,
21784 instance = $module.data(moduleNamespace),
21785 module
21786 ;
21787
21788 module = {
21789
21790 initialize: function () {
21791 module.verbose('Initializing module for', element);
21792 module.set.defaultSide();
21793 module.instantiate();
21794 },
21795
21796 instantiate: function () {
21797 module.verbose('Storing instance of module', module);
21798 instance = module;
21799 $module
21800 .data(moduleNamespace, instance)
21801 ;
21802 },
21803
21804 destroy: function () {
21805 module.verbose('Destroying previous module for', element);
21806 $module
21807 .removeData(moduleNamespace)
21808 .off(eventNamespace)
21809 ;
21810 },
21811
21812 refresh: function () {
21813 module.verbose('Refreshing selector cache for', element);
21814 $module = $(element);
21815 $sides = $(this).find(selector.sides);
21816 $side = $(this).find(selector.side);
21817 },
21818
21819 repaint: function () {
21820 module.verbose('Forcing repaint event');
21821 var
21822 shape = $sides[0] || document.createElement('div'),
21823 fakeAssignment = shape.offsetWidth
21824 ;
21825 },
21826
21827 animate: function (propertyObject, callback) {
21828 module.verbose('Animating box with properties', propertyObject);
21829 callback = callback || function (event) {
21830 module.verbose('Executing animation callback');
21831 if (event !== undefined) {
21832 event.stopPropagation();
21833 }
21834 module.reset();
21835 module.set.active();
21836 };
21837 settings.onBeforeChange.call($nextSide[0]);
21838 module.verbose('Starting CSS animation');
21839 $module
21840 .addClass(className.animating)
21841 ;
21842 $sides
21843 .css(propertyObject)
21844 .one('transitionend', callback)
21845 ;
21846 module.set.duration(settings.duration);
21847 requestAnimationFrame(function () {
21848 $module
21849 .addClass(className.animating)
21850 ;
21851 $activeSide
21852 .addClass(className.hidden)
21853 ;
21854 });
21855 },
21856
21857 queue: function (method) {
21858 module.debug('Queueing animation of', method);
21859 $sides
21860 .one('transitionend', function () {
21861 module.debug('Executing queued animation');
21862 setTimeout(function () {
21863 $module.shape(method);
21864 }, 0);
21865 })
21866 ;
21867 },
21868
21869 reset: function () {
21870 module.verbose('Animating states reset');
21871 $module
21872 .removeClass(className.animating)
21873 .attr('style', '')
21874 .removeAttr('style')
21875 ;
21876 // removeAttr style does not consistently work in safari
21877 $sides
21878 .attr('style', '')
21879 .removeAttr('style')
21880 ;
21881 $side
21882 .attr('style', '')
21883 .removeAttr('style')
21884 .removeClass(className.hidden)
21885 ;
21886 $nextSide
21887 .removeClass(className.animating)
21888 .attr('style', '')
21889 .removeAttr('style')
21890 ;
21891 },
21892
21893 is: {
21894 complete: function () {
21895 return $side.filter('.' + className.active)[0] === $nextSide[0];
21896 },
21897 animating: function () {
21898 return $module.hasClass(className.animating);
21899 },
21900 hidden: function () {
21901 return $module.closest(':hidden').length > 0;
21902 },
21903 },
21904
21905 set: {
21906
21907 defaultSide: function () {
21908 $activeSide = $side.filter('.' + settings.className.active);
21909 $nextSide = $activeSide.next(selector.side).length > 0
21910 ? $activeSide.next(selector.side)
21911 : $side.first();
21912 nextIndex = false;
21913 module.verbose('Active side set to', $activeSide);
21914 module.verbose('Next side set to', $nextSide);
21915 },
21916
21917 duration: function (duration) {
21918 duration = duration || settings.duration;
21919 duration = typeof duration === 'number'
21920 ? duration + 'ms'
21921 : duration;
21922 module.verbose('Setting animation duration', duration);
21923 if (settings.duration || settings.duration === 0) {
21924 $sides.add($side)
21925 .css({
21926 'transition-duration': duration,
21927 })
21928 ;
21929 }
21930 },
21931
21932 currentStageSize: function () {
21933 var
21934 $activeSide = $side.filter('.' + settings.className.active),
21935 width = $activeSide.outerWidth(true),
21936 height = $activeSide.outerHeight(true)
21937 ;
21938 $module
21939 .css({
21940 width: width,
21941 height: height,
21942 })
21943 ;
21944 },
21945
21946 stageSize: function () {
21947 var
21948 $clone = $module.clone().addClass(className.loading),
21949 $side = $clone.find('>' + selector.sides + '>' + selector.side),
21950 $activeSide = $side.filter('.' + settings.className.active),
21951 $nextSide = nextIndex
21952 ? $side.eq(nextIndex)
21953 : ($activeSide.next(selector.side).length > 0
21954 ? $activeSide.next(selector.side)
21955 : $side.first()),
21956 newWidth = settings.width === 'next'
21957 ? $nextSide.outerWidth(true)
21958 : (settings.width === 'initial'
21959 ? $module.width()
21960 : settings.width),
21961 newHeight = settings.height === 'next'
21962 ? $nextSide.outerHeight(true)
21963 : (settings.height === 'initial'
21964 ? $module.height()
21965 : settings.height)
21966 ;
21967 $activeSide.removeClass(className.active);
21968 $nextSide.addClass(className.active);
21969 $clone.insertAfter($module);
21970 $clone.remove();
21971 if (settings.width !== 'auto') {
21972 $module.css('width', newWidth + settings.jitter);
21973 module.verbose('Specifying width during animation', newWidth);
21974 }
21975 if (settings.height !== 'auto') {
21976 $module.css('height', newHeight + settings.jitter);
21977 module.verbose('Specifying height during animation', newHeight);
21978 }
21979 },
21980
21981 nextSide: function (selector) {
21982 nextIndex = selector;
21983 $nextSide = $side.filter(selector);
21984 nextIndex = $side.index($nextSide);
21985 if ($nextSide.length === 0) {
21986 module.set.defaultSide();
21987 module.error(error.side);
21988 }
21989 module.verbose('Next side manually set to', $nextSide);
21990 },
21991
21992 active: function () {
21993 module.verbose('Setting new side to active', $nextSide);
21994 $side
21995 .removeClass(className.active)
21996 ;
21997 $nextSide
21998 .addClass(className.active)
21999 ;
22000 settings.onChange.call($nextSide[0]);
22001 module.set.defaultSide();
22002 },
22003 },
22004
22005 flip: {
22006 to: function (type, stage) {
22007 if (module.is.hidden()) {
22008 module.debug('Module not visible', $nextSide);
22009
22010 return;
22011 }
22012 if (module.is.complete() && !module.is.animating() && !settings.allowRepeats) {
22013 module.debug('Side already visible', $nextSide);
22014
22015 return;
22016 }
22017 var
22018 transform = module.get.transform[type]()
22019 ;
22020 if (!module.is.animating()) {
22021 module.debug('Flipping ' + type, $nextSide);
22022 module.set.stageSize();
22023 module.stage[stage]();
22024 module.animate(transform);
22025 } else {
22026 module.queue('flip ' + type);
22027 }
22028 },
22029
22030 up: function () {
22031 module.flip.to('up', 'above');
22032 },
22033
22034 down: function () {
22035 module.flip.to('down', 'below');
22036 },
22037
22038 left: function () {
22039 module.flip.to('left', 'left');
22040 },
22041
22042 right: function () {
22043 module.flip.to('right', 'right');
22044 },
22045
22046 over: function () {
22047 module.flip.to('over', 'behind');
22048 },
22049
22050 back: function () {
22051 module.flip.to('back', 'behind');
22052 },
22053
22054 },
22055
22056 get: {
22057
22058 transform: {
22059 up: function () {
22060 var
22061 translateZ = $activeSide.outerHeight(true) / 2,
22062 translateY = $nextSide.outerHeight(true) - translateZ
22063 ;
22064
22065 return {
22066 transform: 'translateY(' + translateY + 'px) translateZ(-' + translateZ + 'px) rotateX(-90deg)',
22067 };
22068 },
22069
22070 down: function () {
22071 var
22072 translate = {
22073 z: $activeSide.outerHeight(true) / 2,
22074 }
22075 ;
22076
22077 return {
22078 transform: 'translateY(-' + translate.z + 'px) translateZ(-' + translate.z + 'px) rotateX(90deg)',
22079 };
22080 },
22081
22082 left: function () {
22083 var
22084 translateZ = $activeSide.outerWidth(true) / 2,
22085 translateX = $nextSide.outerWidth(true) - translateZ
22086 ;
22087
22088 return {
22089 transform: 'translateX(' + translateX + 'px) translateZ(-' + translateZ + 'px) rotateY(90deg)',
22090 };
22091 },
22092
22093 right: function () {
22094 var
22095 translate = {
22096 z: $activeSide.outerWidth(true) / 2,
22097 }
22098 ;
22099
22100 return {
22101 transform: 'translateX(-' + translate.z + 'px) translateZ(-' + translate.z + 'px) rotateY(-90deg)',
22102 };
22103 },
22104
22105 over: function () {
22106 var
22107 translate = {
22108 x: -(($activeSide.outerWidth(true) - $nextSide.outerWidth(true)) / 2),
22109 }
22110 ;
22111
22112 return {
22113 transform: 'translateX(' + translate.x + 'px) rotateY(180deg)',
22114 };
22115 },
22116
22117 back: function () {
22118 var
22119 translate = {
22120 x: -(($activeSide.outerWidth(true) - $nextSide.outerWidth(true)) / 2),
22121 }
22122 ;
22123
22124 return {
22125 transform: 'translateX(' + translate.x + 'px) rotateY(-180deg)',
22126 };
22127 },
22128 },
22129
22130 nextSide: function () {
22131 return $activeSide.next(selector.side).length > 0
22132 ? $activeSide.next(selector.side)
22133 : $side.first();
22134 },
22135
22136 },
22137
22138 stage: {
22139
22140 above: function () {
22141 var
22142 box = {
22143 origin: ($activeSide.outerHeight(true) - $nextSide.outerHeight(true)) / 2,
22144 depth: {
22145 active: $nextSide.outerHeight(true) / 2,
22146 next: $activeSide.outerHeight(true) / 2,
22147 },
22148 }
22149 ;
22150 module.verbose('Setting the initial animation position as above', $nextSide, box);
22151 $activeSide
22152 .css({
22153 transform: 'rotateX(0deg)',
22154 })
22155 ;
22156 $nextSide
22157 .addClass(className.animating)
22158 .css({
22159 top: box.origin + 'px',
22160 transform: 'rotateX(90deg) translateZ(' + box.depth.next + 'px) translateY(-' + box.depth.active + 'px)',
22161 })
22162 ;
22163 },
22164
22165 below: function () {
22166 var
22167 box = {
22168 origin: ($activeSide.outerHeight(true) - $nextSide.outerHeight(true)) / 2,
22169 depth: {
22170 active: $nextSide.outerHeight(true) / 2,
22171 next: $activeSide.outerHeight(true) / 2,
22172 },
22173 }
22174 ;
22175 module.verbose('Setting the initial animation position as below', $nextSide, box);
22176 $activeSide
22177 .css({
22178 transform: 'rotateX(0deg)',
22179 })
22180 ;
22181 $nextSide
22182 .addClass(className.animating)
22183 .css({
22184 top: box.origin + 'px',
22185 transform: 'rotateX(-90deg) translateZ(' + box.depth.next + 'px) translateY(' + box.depth.active + 'px)',
22186 })
22187 ;
22188 },
22189
22190 left: function () {
22191 var
22192 height = {
22193 active: $activeSide.outerWidth(true),
22194 next: $nextSide.outerWidth(true),
22195 },
22196 box = {
22197 origin: (height.active - height.next) / 2,
22198 depth: {
22199 active: height.next / 2,
22200 next: height.active / 2,
22201 },
22202 }
22203 ;
22204 module.verbose('Setting the initial animation position as left', $nextSide, box);
22205 $activeSide
22206 .css({
22207 transform: 'rotateY(0deg)',
22208 })
22209 ;
22210 $nextSide
22211 .addClass(className.animating)
22212 .css({
22213 left: box.origin + 'px',
22214 transform: 'rotateY(-90deg) translateZ(' + box.depth.next + 'px) translateX(-' + box.depth.active + 'px)',
22215 })
22216 ;
22217 },
22218
22219 right: function () {
22220 var
22221 height = {
22222 active: $activeSide.outerWidth(true),
22223 next: $nextSide.outerWidth(true),
22224 },
22225 box = {
22226 origin: (height.active - height.next) / 2,
22227 depth: {
22228 active: height.next / 2,
22229 next: height.active / 2,
22230 },
22231 }
22232 ;
22233 module.verbose('Setting the initial animation position as right', $nextSide, box);
22234 $activeSide
22235 .css({
22236 transform: 'rotateY(0deg)',
22237 })
22238 ;
22239 $nextSide
22240 .addClass(className.animating)
22241 .css({
22242 left: box.origin + 'px',
22243 transform: 'rotateY(90deg) translateZ(' + box.depth.next + 'px) translateX(' + box.depth.active + 'px)',
22244 })
22245 ;
22246 },
22247
22248 behind: function () {
22249 var
22250 height = {
22251 active: $activeSide.outerWidth(true),
22252 next: $nextSide.outerWidth(true),
22253 },
22254 box = {
22255 origin: (height.active - height.next) / 2,
22256 depth: {
22257 active: height.next / 2,
22258 next: height.active / 2,
22259 },
22260 }
22261 ;
22262 module.verbose('Setting the initial animation position as behind', $nextSide, box);
22263 $activeSide
22264 .css({
22265 transform: 'rotateY(0deg)',
22266 })
22267 ;
22268 $nextSide
22269 .addClass(className.animating)
22270 .css({
22271 left: box.origin + 'px',
22272 transform: 'rotateY(-180deg)',
22273 })
22274 ;
22275 },
22276 },
22277 setting: function (name, value) {
22278 module.debug('Changing setting', name, value);
22279 if ($.isPlainObject(name)) {
22280 $.extend(true, settings, name);
22281 } else if (value !== undefined) {
22282 if ($.isPlainObject(settings[name])) {
22283 $.extend(true, settings[name], value);
22284 } else {
22285 settings[name] = value;
22286 }
22287 } else {
22288 return settings[name];
22289 }
22290 },
22291 internal: function (name, value) {
22292 if ($.isPlainObject(name)) {
22293 $.extend(true, module, name);
22294 } else if (value !== undefined) {
22295 module[name] = value;
22296 } else {
22297 return module[name];
22298 }
22299 },
22300 debug: function () {
22301 if (!settings.silent && settings.debug) {
22302 if (settings.performance) {
22303 module.performance.log(arguments);
22304 } else {
22305 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
22306 module.debug.apply(console, arguments);
22307 }
22308 }
22309 },
22310 verbose: function () {
22311 if (!settings.silent && settings.verbose && settings.debug) {
22312 if (settings.performance) {
22313 module.performance.log(arguments);
22314 } else {
22315 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
22316 module.verbose.apply(console, arguments);
22317 }
22318 }
22319 },
22320 error: function () {
22321 if (!settings.silent) {
22322 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
22323 module.error.apply(console, arguments);
22324 }
22325 },
22326 performance: {
22327 log: function (message) {
22328 var
22329 currentTime,
22330 executionTime,
22331 previousTime
22332 ;
22333 if (settings.performance) {
22334 currentTime = Date.now();
22335 previousTime = time || currentTime;
22336 executionTime = currentTime - previousTime;
22337 time = currentTime;
22338 performance.push({
22339 Name: message[0],
22340 Arguments: [].slice.call(message, 1) || '',
22341 Element: element,
22342 'Execution Time': executionTime,
22343 });
22344 }
22345 clearTimeout(module.performance.timer);
22346 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
22347 },
22348 display: function () {
22349 var
22350 title = settings.name + ':',
22351 totalTime = 0
22352 ;
22353 time = false;
22354 clearTimeout(module.performance.timer);
22355 $.each(performance, function (index, data) {
22356 totalTime += data['Execution Time'];
22357 });
22358 title += ' ' + totalTime + 'ms';
22359 if ($allModules.length > 1) {
22360 title += ' (' + $allModules.length + ')';
22361 }
22362 if (performance.length > 0) {
22363 console.groupCollapsed(title);
22364 if (console.table) {
22365 console.table(performance);
22366 } else {
22367 $.each(performance, function (index, data) {
22368 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
22369 });
22370 }
22371 console.groupEnd();
22372 }
22373 performance = [];
22374 },
22375 },
22376 invoke: function (query, passedArguments, context) {
22377 var
22378 object = instance,
22379 maxDepth,
22380 found,
22381 response
22382 ;
22383 passedArguments = passedArguments || queryArguments;
22384 context = context || element;
22385 if (typeof query === 'string' && object !== undefined) {
22386 query = query.split(/[ .]/);
22387 maxDepth = query.length - 1;
22388 $.each(query, function (depth, value) {
22389 var camelCaseValue = depth !== maxDepth
22390 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
22391 : query
22392 ;
22393 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
22394 object = object[camelCaseValue];
22395 } else if (object[camelCaseValue] !== undefined) {
22396 found = object[camelCaseValue];
22397
22398 return false;
22399 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
22400 object = object[value];
22401 } else if (object[value] !== undefined) {
22402 found = object[value];
22403
22404 return false;
22405 } else {
22406 module.error(error.method, query);
22407
22408 return false;
22409 }
22410 });
22411 }
22412 if (isFunction(found)) {
22413 response = found.apply(context, passedArguments);
22414 } else if (found !== undefined) {
22415 response = found;
22416 }
22417 if (Array.isArray(returnedValue)) {
22418 returnedValue.push(response);
22419 } else if (returnedValue !== undefined) {
22420 returnedValue = [returnedValue, response];
22421 } else if (response !== undefined) {
22422 returnedValue = response;
22423 }
22424
22425 return found;
22426 },
22427 };
22428
22429 if (methodInvoked) {
22430 if (instance === undefined) {
22431 module.initialize();
22432 }
22433 var $inputs = $module.find('input');
22434 if ($inputs.length > 0) {
22435 $inputs.trigger('blur');
22436 setTimeout(function () {
22437 module.invoke(query);
22438 }, 150);
22439 } else {
22440 module.invoke(query);
22441 }
22442 } else {
22443 if (instance !== undefined) {
22444 instance.invoke('destroy');
22445 }
22446 module.initialize();
22447 }
22448 });
22449
22450 return returnedValue !== undefined
22451 ? returnedValue
22452 : this;
22453 };
22454
22455 $.fn.shape.settings = {
22456
22457 // module info
22458 name: 'Shape',
22459
22460 // hide all debug content
22461 silent: false,
22462
22463 // debug content outputted to console
22464 debug: false,
22465
22466 // verbose debug output
22467 verbose: false,
22468
22469 // fudge factor in pixels when swapping from 2d to 3d (can be useful to correct rounding errors)
22470 jitter: 0,
22471
22472 // performance data output
22473 performance: true,
22474
22475 // event namespace
22476 namespace: 'shape',
22477
22478 // width during animation, can be set to 'auto', initial', 'next' or pixel amount
22479 width: 'initial',
22480
22481 // height during animation, can be set to 'auto', 'initial', 'next' or pixel amount
22482 height: 'initial',
22483
22484 // callback occurs on side change
22485 onBeforeChange: function () {},
22486 onChange: function () {},
22487
22488 // allow animation to same side
22489 allowRepeats: false,
22490
22491 // animation duration
22492 duration: false,
22493
22494 // possible errors
22495 error: {
22496 side: 'You tried to switch to a side that does not exist.',
22497 method: 'The method you called is not defined',
22498 },
22499
22500 // classnames used
22501 className: {
22502 animating: 'animating',
22503 hidden: 'hidden',
22504 loading: 'loading',
22505 active: 'active',
22506 },
22507
22508 // selectors used
22509 selector: {
22510 sides: '.sides',
22511 side: '.side',
22512 },
22513
22514 };
22515})(jQuery, window, document);
22516
22517/*!
22518 * # Fomantic-UI 2.9.3 - Sidebar
22519 * https://github.com/fomantic/Fomantic-UI/
22520 *
22521 *
22522 * Released under the MIT license
22523 * https://opensource.org/licenses/MIT
22524 *
22525 */
22526
22527(function ($, window, document) {
22528 'use strict';
22529
22530 function isFunction(obj) {
22531 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
22532 }
22533
22534 window = window !== undefined && window.Math === Math
22535 ? window
22536 : globalThis;
22537
22538 $.fn.sidebar = function (parameters) {
22539 var
22540 $allModules = $(this),
22541 $window = $(window),
22542 $document = $(document),
22543 $body = $('body'),
22544 $html = $('html'),
22545 $head = $('head'),
22546
22547 time = Date.now(),
22548 performance = [],
22549
22550 query = arguments[0],
22551 methodInvoked = typeof query === 'string',
22552 queryArguments = [].slice.call(arguments, 1),
22553 contextCheck = function (context, win) {
22554 var $context;
22555 if ([window, document].indexOf(context) >= 0) {
22556 $context = $body;
22557 } else {
22558 $context = $(win.document).find(context);
22559 if ($context.length === 0) {
22560 $context = win.frameElement ? contextCheck(context, win.parent) : $body;
22561 }
22562 }
22563
22564 return $context;
22565 },
22566 returnedValue;
22567
22568 $allModules.each(function () {
22569 var
22570 settings = $.isPlainObject(parameters)
22571 ? $.extend(true, {}, $.fn.sidebar.settings, parameters)
22572 : $.extend({}, $.fn.sidebar.settings),
22573
22574 selector = settings.selector,
22575 className = settings.className,
22576 namespace = settings.namespace,
22577 regExp = settings.regExp,
22578 error = settings.error,
22579
22580 eventNamespace = '.' + namespace,
22581 moduleNamespace = 'module-' + namespace,
22582
22583 $module = $(this),
22584 $context = contextCheck(settings.context, window),
22585 isBody = $context[0] === $body[0],
22586
22587 $sidebars = $module.children(selector.sidebar),
22588 $fixed = $context.children(selector.fixed),
22589 $pusher = $context.children(selector.pusher),
22590 $style,
22591
22592 element = this,
22593 instance = $module.data(moduleNamespace),
22594
22595 elementNamespace,
22596 id,
22597 currentScroll,
22598 initialBodyMargin = '',
22599 tempBodyMargin = '',
22600 hadScrollbar = false,
22601
22602 module
22603 ;
22604
22605 module = {
22606
22607 initialize: function () {
22608 module.debug('Initializing sidebar', parameters);
22609
22610 module.create.id();
22611
22612 // avoids locking rendering if initialized in onReady
22613 if (settings.delaySetup) {
22614 requestAnimationFrame(module.setup.layout);
22615 } else {
22616 module.setup.layout();
22617 }
22618
22619 requestAnimationFrame(function () {
22620 module.setup.cache();
22621 });
22622
22623 module.instantiate();
22624 },
22625
22626 instantiate: function () {
22627 module.verbose('Storing instance of module', module);
22628 instance = module;
22629 $module
22630 .data(moduleNamespace, module)
22631 ;
22632 },
22633
22634 create: {
22635 id: function () {
22636 id = (Math.random().toString(16) + '000000000').slice(2, 10);
22637 elementNamespace = '.' + id;
22638 module.verbose('Creating unique id for element', id);
22639 },
22640 },
22641
22642 destroy: function () {
22643 module.verbose('Destroying previous module for', $module);
22644 $module
22645 .off(eventNamespace)
22646 .removeData(moduleNamespace)
22647 ;
22648 // bound by uuid
22649 $context.off(elementNamespace);
22650 $window.off(elementNamespace);
22651 $document.off(elementNamespace);
22652 },
22653
22654 event: {
22655 clickaway: function (event) {
22656 if (settings.closable) {
22657 var
22658 clickedInPusher = $pusher.find(event.target).length > 0 || $pusher.is(event.target),
22659 clickedContext = $context.is(event.target)
22660 ;
22661 if (clickedInPusher) {
22662 module.verbose('User clicked on dimmed page');
22663 module.hide();
22664 }
22665 if (clickedContext) {
22666 module.verbose('User clicked on dimmable context (scaled out page)');
22667 module.hide();
22668 }
22669 }
22670 },
22671 touch: function (event) {
22672 // event.stopPropagation();
22673 },
22674 containScroll: function (event) {
22675 if (element.scrollTop <= 0) {
22676 element.scrollTop = 1;
22677 }
22678 if ((element.scrollTop + element.offsetHeight) >= element.scrollHeight) {
22679 element.scrollTop = element.scrollHeight - element.offsetHeight - 1;
22680 }
22681 },
22682 scroll: function (event) {
22683 if ($(event.target).closest(selector.sidebar).length === 0) {
22684 event.preventDefault();
22685 }
22686 },
22687 },
22688
22689 bind: {
22690 clickaway: function () {
22691 module.verbose('Adding clickaway events to context', $context);
22692 $context
22693 .on('click' + elementNamespace, module.event.clickaway)
22694 .on('touchend' + elementNamespace, module.event.clickaway)
22695 ;
22696 },
22697 scrollLock: function () {
22698 if (settings.scrollLock) {
22699 module.debug('Disabling page scroll');
22700 hadScrollbar = module.has.scrollbar();
22701 if (hadScrollbar) {
22702 module.save.bodyMargin();
22703 module.set.bodyMargin();
22704 }
22705 $context.addClass(className.locked);
22706 }
22707 module.verbose('Adding events to contain sidebar scroll');
22708 $document
22709 .on('touchmove' + elementNamespace, module.event.touch)
22710 ;
22711 $module
22712 .on('scroll' + eventNamespace, module.event.containScroll)
22713 ;
22714 },
22715 },
22716 unbind: {
22717 clickaway: function () {
22718 module.verbose('Removing clickaway events from context', $context);
22719 $context.off(elementNamespace);
22720 },
22721 scrollLock: function () {
22722 module.verbose('Removing scroll lock from page');
22723 if (hadScrollbar) {
22724 module.restore.bodyMargin();
22725 }
22726 $context.removeClass(className.locked);
22727 $document.off(elementNamespace);
22728 $module.off('scroll' + eventNamespace);
22729 },
22730 },
22731
22732 add: {
22733 inlineCSS: function () {
22734 var
22735 width = module.cache.width || $module.outerWidth(),
22736 height = module.cache.height || $module.outerHeight(),
22737 isRTL = module.is.rtl(),
22738 direction = module.get.direction(),
22739 distance = {
22740 left: width,
22741 right: -width,
22742 top: height,
22743 bottom: -height,
22744 },
22745 style
22746 ;
22747
22748 if (isRTL) {
22749 module.verbose('RTL detected, flipping widths');
22750 distance.left = -width;
22751 distance.right = width;
22752 }
22753
22754 style = '<style>';
22755
22756 if (direction === 'left' || direction === 'right') {
22757 module.debug('Adding CSS rules for animation distance', width);
22758 style += ''
22759 + ' .ui.visible.' + direction + '.sidebar ~ .fixed,'
22760 + ' .ui.visible.' + direction + '.sidebar ~ .pusher {'
22761 + ' transform: translate3d(' + distance[direction] + 'px, 0, 0);'
22762 + ' }';
22763 } else if (direction === 'top' || direction === 'bottom') {
22764 style += ''
22765 + ' .ui.visible.' + direction + '.sidebar ~ .fixed,'
22766 + ' .ui.visible.' + direction + '.sidebar ~ .pusher {'
22767 + ' transform: translate3d(0, ' + distance[direction] + 'px, 0);'
22768 + ' }';
22769 }
22770
22771 /* IE is only browser not to create context with transforms */
22772 /* https://www.w3.org/Bugs/Public/show_bug.cgi?id=16328 */
22773 if (module.is.ie()) {
22774 if (direction === 'left' || direction === 'right') {
22775 module.debug('Adding CSS rules for animation distance', width);
22776 style += ''
22777 + ' body.pushable > .ui.visible.' + direction + '.sidebar ~ .pusher::after {'
22778 + ' transform: translate3d(' + distance[direction] + 'px, 0, 0);'
22779 + ' }';
22780 } else if (direction === 'top' || direction === 'bottom') {
22781 style += ''
22782 + ' body.pushable > .ui.visible.' + direction + '.sidebar ~ .pusher::after {'
22783 + ' transform: translate3d(0, ' + distance[direction] + 'px, 0);'
22784 + ' }';
22785 }
22786 /* opposite sides visible forces content overlay */
22787 style += ''
22788 + ' body.pushable > .ui.visible.left.sidebar ~ .ui.visible.right.sidebar ~ .pusher::after,'
22789 + ' body.pushable > .ui.visible.right.sidebar ~ .ui.visible.left.sidebar ~ .pusher::after {'
22790 + ' transform: translate3d(0, 0, 0);'
22791 + ' }';
22792 }
22793 style += '</style>';
22794 $style = $(style)
22795 .appendTo($head)
22796 ;
22797 module.debug('Adding sizing css to head', $style);
22798 },
22799 },
22800
22801 refresh: function () {
22802 module.verbose('Refreshing selector cache');
22803 $context = contextCheck(settings.context, window);
22804 module.refreshSidebars();
22805 $pusher = $context.children(selector.pusher);
22806 $fixed = $context.children(selector.fixed);
22807 module.clear.cache();
22808 },
22809
22810 refreshSidebars: function () {
22811 module.verbose('Refreshing other sidebars');
22812 $sidebars = $context.children(selector.sidebar);
22813 },
22814
22815 repaint: function () {
22816 module.verbose('Forcing repaint event');
22817 element.style.display = 'none';
22818 var ignored = element.offsetHeight;
22819 element.scrollTop = element.scrollTop; // eslint-disable-line no-self-assign
22820 element.style.display = '';
22821 },
22822
22823 setup: {
22824 cache: function () {
22825 module.cache = {
22826 width: $module.outerWidth(),
22827 height: $module.outerHeight(),
22828 };
22829 },
22830 layout: function () {
22831 if ($context.children(selector.pusher).length === 0) {
22832 module.debug('Adding wrapper element for sidebar');
22833 module.error(error.pusher);
22834 $pusher = $('<div class="pusher" />');
22835 $context
22836 .children()
22837 .not(selector.omitted)
22838 .not($sidebars)
22839 .wrapAll($pusher)
22840 ;
22841 module.refresh();
22842 }
22843 if ($module.nextAll(selector.pusher).length === 0 || $module.nextAll(selector.pusher)[0] !== $pusher[0]) {
22844 module.debug('Moved sidebar to correct parent element');
22845 module.error(error.movedSidebar, element);
22846 $module.detach().prependTo($context);
22847 module.refresh();
22848 }
22849 module.clear.cache();
22850 module.set.pushable();
22851 module.set.direction();
22852 },
22853 },
22854
22855 attachEvents: function (selector, event) {
22856 var
22857 $toggle = $(selector)
22858 ;
22859 event = isFunction(module[event])
22860 ? module[event]
22861 : module.toggle;
22862 if ($toggle.length > 0) {
22863 module.debug('Attaching sidebar events to element', selector, event);
22864 $toggle
22865 .on('click' + eventNamespace, event)
22866 ;
22867 } else {
22868 module.error(error.notFound, selector);
22869 }
22870 },
22871 can: {
22872 leftBodyScrollbar: function () {
22873 if (module.cache.leftBodyScrollbar === undefined) {
22874 module.cache.leftBodyScrollbar = module.is.rtl() && ((module.is.iframe && !module.is.firefox()) || module.is.safari() || module.is.edge() || module.is.ie());
22875 }
22876
22877 return module.cache.leftBodyScrollbar;
22878 },
22879 },
22880 save: {
22881 bodyMargin: function () {
22882 initialBodyMargin = $context.css((isBody ? 'margin-' : 'padding-') + (module.can.leftBodyScrollbar() ? 'left' : 'right'));
22883 var
22884 bodyMarginRightPixel = parseInt(initialBodyMargin.replace(/[^\d.]/g, ''), 10),
22885 bodyScrollbarWidth = isBody ? window.innerWidth - document.documentElement.clientWidth : $context[0].offsetWidth - $context[0].clientWidth
22886 ;
22887 tempBodyMargin = bodyMarginRightPixel + bodyScrollbarWidth;
22888 },
22889 },
22890 show: function (callback) {
22891 callback = isFunction(callback)
22892 ? callback
22893 : function () {};
22894 if (module.is.hidden()) {
22895 if (settings.onShow.call(element) === false) {
22896 module.verbose('Show callback returned false cancelling show');
22897
22898 return;
22899 }
22900 if (settings.overlay) {
22901 module.error(error.overlay);
22902 settings.transition = 'overlay';
22903 }
22904 module.refresh();
22905 if (module.othersActive()) {
22906 module.debug('Other sidebars currently visible');
22907 if (settings.exclusive) {
22908 // if not overlay queue animation after hide
22909 if (settings.transition !== 'overlay') {
22910 module.hideOthers(module.show);
22911
22912 return;
22913 }
22914
22915 module.hideOthers();
22916 } else {
22917 settings.transition = 'overlay';
22918 }
22919 }
22920 module.set.dimmerStyles();
22921 module.pushPage(function () {
22922 callback.call(element);
22923 settings.onVisible.call(element);
22924 });
22925 settings.onChange.call(element);
22926 } else {
22927 module.debug('Sidebar is already visible');
22928 }
22929 },
22930
22931 hide: function (callback) {
22932 callback = isFunction(callback)
22933 ? callback
22934 : function () {};
22935 if ((module.is.visible() || module.is.animating()) && settings.onHide.call(element) !== false) {
22936 module.debug('Hiding sidebar', callback);
22937 module.refreshSidebars();
22938 module.pullPage(function () {
22939 callback.call(element);
22940 settings.onHidden.call(element);
22941 });
22942 settings.onChange.call(element);
22943 }
22944 },
22945
22946 othersAnimating: function () {
22947 return $sidebars.not($module).filter('.' + className.animating).length > 0;
22948 },
22949 othersVisible: function () {
22950 return $sidebars.not($module).filter('.' + className.visible).length > 0;
22951 },
22952 othersActive: function () {
22953 return module.othersVisible() || module.othersAnimating();
22954 },
22955
22956 hideOthers: function (callback) {
22957 var
22958 $otherSidebars = $sidebars.not($module).filter('.' + className.visible),
22959 sidebarCount = $otherSidebars.length,
22960 callbackCount = 0
22961 ;
22962 callback = callback || function () {};
22963 $otherSidebars
22964 .sidebar('hide', function () {
22965 callbackCount++;
22966 if (callbackCount === sidebarCount) {
22967 callback();
22968 }
22969 })
22970 ;
22971 },
22972
22973 toggle: function () {
22974 module.verbose('Determining toggled direction');
22975 if (module.is.hidden()) {
22976 module.show();
22977 } else {
22978 module.hide();
22979 }
22980 },
22981
22982 pushPage: function (callback) {
22983 var
22984 transition = module.get.transition(),
22985 $transition = transition === 'overlay' || module.othersActive()
22986 ? $module
22987 : $pusher,
22988 animate,
22989 dim,
22990 transitionEnd
22991 ;
22992 callback = isFunction(callback)
22993 ? callback
22994 : function () {};
22995 if (settings.returnScroll) {
22996 currentScroll = (isBody ? $window : $context).scrollTop();
22997 }
22998 if (settings.transition === 'scale down') {
22999 module.scrollToTop();
23000 }
23001 module.bind.scrollLock();
23002 module.set.transition(transition);
23003 module.repaint();
23004 animate = function () {
23005 module.bind.clickaway();
23006 module.add.inlineCSS();
23007 module.set.animating();
23008 module.set.visible();
23009 };
23010 dim = function () {
23011 module.set.dimmed();
23012 };
23013 transitionEnd = function (event) {
23014 if (event.target === $transition[0]) {
23015 $transition.off('transitionend' + elementNamespace, transitionEnd);
23016 module.remove.animating();
23017 callback.call(element);
23018 }
23019 };
23020 $transition.off('transitionend' + elementNamespace);
23021 $transition.on('transitionend' + elementNamespace, transitionEnd);
23022 requestAnimationFrame(animate);
23023 if (settings.dimPage && !module.othersVisible()) {
23024 requestAnimationFrame(dim);
23025 }
23026 },
23027
23028 pullPage: function (callback) {
23029 var
23030 transition = module.get.transition(),
23031 $transition = transition === 'overlay' || module.othersActive()
23032 ? $module
23033 : $pusher,
23034 animate,
23035 transitionEnd
23036 ;
23037 callback = isFunction(callback)
23038 ? callback
23039 : function () {};
23040 module.verbose('Removing context push state', module.get.direction());
23041
23042 module.unbind.clickaway();
23043 module.unbind.scrollLock();
23044
23045 animate = function () {
23046 module.set.transition(transition);
23047 module.set.animating();
23048 if (settings.dimPage && !module.othersVisible()) {
23049 module.set.closing();
23050 }
23051 module.remove.visible();
23052 };
23053 transitionEnd = function (event) {
23054 if (event.target === $transition[0]) {
23055 $transition.off('transitionend' + elementNamespace, transitionEnd);
23056 module.remove.animating();
23057 module.remove.closing();
23058 module.remove.transition();
23059 module.remove.inlineCSS();
23060 if (transition === 'scale down' || settings.returnScroll) {
23061 module.scrollBack();
23062 }
23063 if (settings.dimPage && !module.othersVisible()) {
23064 $pusher.removeClass(className.dimmed);
23065 }
23066 callback.call(element);
23067 }
23068 };
23069 $transition.off('transitionend' + elementNamespace);
23070 $transition.on('transitionend' + elementNamespace, transitionEnd);
23071 requestAnimationFrame(animate);
23072 },
23073
23074 scrollToTop: function () {
23075 module.verbose('Scrolling to top of page to avoid animation issues');
23076 $module.scrollTop(0);
23077 (isBody ? $window : $context)[0].scrollTo(0, 0);
23078 },
23079
23080 scrollBack: function () {
23081 module.verbose('Scrolling back to original page position');
23082 (isBody ? $window : $context)[0].scrollTo(0, currentScroll);
23083 },
23084
23085 clear: {
23086 cache: function () {
23087 module.verbose('Clearing cached dimensions');
23088 module.cache = {};
23089 },
23090 },
23091
23092 set: {
23093 bodyMargin: function () {
23094 var position = module.can.leftBodyScrollbar() ? 'left' : 'right';
23095 $context.css((isBody ? 'margin-' : 'padding-') + position, tempBodyMargin + 'px');
23096 $context.find(selector.bodyFixed.replace('right', position)).each(function () {
23097 var
23098 el = $(this),
23099 attribute = el.css('position') === 'fixed' ? 'padding-' + position : position
23100 ;
23101 el.css(attribute, 'calc(' + el.css(attribute) + ' + ' + tempBodyMargin + 'px)');
23102 });
23103 },
23104 dimmerStyles: function () {
23105 if (settings.blurring) {
23106 $pusher.addClass(className.blurring);
23107 } else {
23108 $pusher.removeClass(className.blurring);
23109 }
23110 },
23111
23112 // container
23113 pushed: function () {
23114 $context.addClass(className.pushed);
23115 },
23116 pushable: function () {
23117 $context.addClass(className.pushable);
23118 },
23119
23120 // pusher
23121 dimmed: function () {
23122 $pusher.addClass(className.dimmed);
23123 },
23124
23125 // sidebar
23126 active: function () {
23127 $module.addClass(className.active);
23128 },
23129 animating: function () {
23130 $module.addClass(className.animating);
23131 },
23132 closing: function () {
23133 $pusher.addClass(className.closing);
23134 },
23135 transition: function (transition) {
23136 transition = transition || module.get.transition();
23137 $module.addClass(transition);
23138 },
23139 direction: function (direction) {
23140 direction = direction || module.get.direction();
23141 $module.addClass(className[direction]);
23142 },
23143 visible: function () {
23144 $module.addClass(className.visible);
23145 },
23146 overlay: function () {
23147 $module.addClass(className.overlay);
23148 },
23149 },
23150 remove: {
23151
23152 inlineCSS: function () {
23153 module.debug('Removing inline css styles', $style);
23154 if ($style && $style.length > 0) {
23155 $style.remove();
23156 }
23157 },
23158
23159 // context
23160 pushed: function () {
23161 $context.removeClass(className.pushed);
23162 },
23163 pushable: function () {
23164 $context.removeClass(className.pushable);
23165 },
23166
23167 // sidebar
23168 active: function () {
23169 $module.removeClass(className.active);
23170 },
23171 animating: function () {
23172 $module.removeClass(className.animating);
23173 },
23174 closing: function () {
23175 $pusher.removeClass(className.closing);
23176 },
23177 transition: function (transition) {
23178 transition = transition || module.get.transition();
23179 $module.removeClass(transition);
23180 },
23181 direction: function (direction) {
23182 direction = direction || module.get.direction();
23183 $module.removeClass(className[direction]);
23184 },
23185 visible: function () {
23186 $module.removeClass(className.visible);
23187 },
23188 overlay: function () {
23189 $module.removeClass(className.overlay);
23190 },
23191 },
23192 restore: {
23193 bodyMargin: function () {
23194 var position = module.can.leftBodyScrollbar() ? 'left' : 'right';
23195 $context.css((isBody ? 'margin-' : 'padding-') + position, initialBodyMargin);
23196 $context.find(selector.bodyFixed.replace('right', position)).each(function () {
23197 var
23198 el = $(this),
23199 attribute = el.css('position') === 'fixed' ? 'padding-' + position : position
23200 ;
23201 el.css(attribute, '');
23202 });
23203 },
23204 },
23205 get: {
23206 direction: function () {
23207 if ($module.hasClass(className.top)) {
23208 return className.top;
23209 }
23210 if ($module.hasClass(className.right)) {
23211 return className.right;
23212 }
23213 if ($module.hasClass(className.bottom)) {
23214 return className.bottom;
23215 }
23216
23217 return className.left;
23218 },
23219 transition: function () {
23220 var
23221 direction = module.get.direction(),
23222 transition
23223 ;
23224 transition = module.is.mobile()
23225 ? (settings.mobileTransition === 'auto'
23226 ? settings.defaultTransition.mobile[direction]
23227 : settings.mobileTransition)
23228 : (settings.transition === 'auto'
23229 ? settings.defaultTransition.computer[direction]
23230 : settings.transition);
23231 module.verbose('Determined transition', transition);
23232
23233 return transition;
23234 },
23235 },
23236 has: {
23237 scrollbar: function () {
23238 return isBody || $context.css('overflow-y') !== 'hidden';
23239 },
23240 },
23241 is: {
23242 safari: function () {
23243 if (module.cache.isSafari === undefined) {
23244 module.cache.isSafari = /constructor/i.test(window.HTMLElement) || !!window.ApplePaySession;
23245 }
23246
23247 return module.cache.isSafari;
23248 },
23249 edge: function () {
23250 if (module.cache.isEdge === undefined) {
23251 module.cache.isEdge = !!window.setImmediate && !module.is.ie();
23252 }
23253
23254 return module.cache.isEdge;
23255 },
23256 firefox: function () {
23257 if (module.cache.isFirefox === undefined) {
23258 module.cache.isFirefox = !!window.InstallTrigger;
23259 }
23260
23261 return module.cache.isFirefox;
23262 },
23263 iframe: function () {
23264 return !(self === top);
23265 },
23266 ie: function () {
23267 if (module.cache.isIE === undefined) {
23268 var
23269 isIE11 = !window.ActiveXObject && 'ActiveXObject' in window,
23270 isIE = 'ActiveXObject' in window
23271 ;
23272 module.cache.isIE = isIE11 || isIE;
23273 }
23274
23275 return module.cache.isIE;
23276 },
23277
23278 mobile: function () {
23279 var
23280 userAgent = navigator.userAgent,
23281 isMobile = userAgent.match(regExp.mobile)
23282 ;
23283 if (isMobile) {
23284 module.verbose('Browser was found to be mobile', userAgent);
23285
23286 return true;
23287 }
23288
23289 module.verbose('Browser is not mobile, using regular transition', userAgent);
23290
23291 return false;
23292 },
23293 hidden: function () {
23294 return !module.is.visible();
23295 },
23296 visible: function () {
23297 return $module.hasClass(className.visible);
23298 },
23299 // alias
23300 open: function () {
23301 return module.is.visible();
23302 },
23303 closed: function () {
23304 return module.is.hidden();
23305 },
23306 vertical: function () {
23307 return $module.hasClass(className.top);
23308 },
23309 animating: function () {
23310 return $context.hasClass(className.animating);
23311 },
23312 rtl: function () {
23313 if (module.cache.isRTL === undefined) {
23314 module.cache.isRTL = $module.attr('dir') === 'rtl' || $module.css('direction') === 'rtl' || $body.attr('dir') === 'rtl' || $body.css('direction') === 'rtl' || $context.attr('dir') === 'rtl' || $context.css('direction') === 'rtl';
23315 }
23316
23317 return module.cache.isRTL;
23318 },
23319 },
23320
23321 setting: function (name, value) {
23322 module.debug('Changing setting', name, value);
23323 if ($.isPlainObject(name)) {
23324 $.extend(true, settings, name);
23325 } else if (value !== undefined) {
23326 if ($.isPlainObject(settings[name])) {
23327 $.extend(true, settings[name], value);
23328 } else {
23329 settings[name] = value;
23330 }
23331 } else {
23332 return settings[name];
23333 }
23334 },
23335 internal: function (name, value) {
23336 if ($.isPlainObject(name)) {
23337 $.extend(true, module, name);
23338 } else if (value !== undefined) {
23339 module[name] = value;
23340 } else {
23341 return module[name];
23342 }
23343 },
23344 debug: function () {
23345 if (!settings.silent && settings.debug) {
23346 if (settings.performance) {
23347 module.performance.log(arguments);
23348 } else {
23349 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
23350 module.debug.apply(console, arguments);
23351 }
23352 }
23353 },
23354 verbose: function () {
23355 if (!settings.silent && settings.verbose && settings.debug) {
23356 if (settings.performance) {
23357 module.performance.log(arguments);
23358 } else {
23359 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
23360 module.verbose.apply(console, arguments);
23361 }
23362 }
23363 },
23364 error: function () {
23365 if (!settings.silent) {
23366 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
23367 module.error.apply(console, arguments);
23368 }
23369 },
23370 performance: {
23371 log: function (message) {
23372 var
23373 currentTime,
23374 executionTime,
23375 previousTime
23376 ;
23377 if (settings.performance) {
23378 currentTime = Date.now();
23379 previousTime = time || currentTime;
23380 executionTime = currentTime - previousTime;
23381 time = currentTime;
23382 performance.push({
23383 Name: message[0],
23384 Arguments: [].slice.call(message, 1) || '',
23385 Element: element,
23386 'Execution Time': executionTime,
23387 });
23388 }
23389 clearTimeout(module.performance.timer);
23390 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
23391 },
23392 display: function () {
23393 var
23394 title = settings.name + ':',
23395 totalTime = 0
23396 ;
23397 time = false;
23398 clearTimeout(module.performance.timer);
23399 $.each(performance, function (index, data) {
23400 totalTime += data['Execution Time'];
23401 });
23402 title += ' ' + totalTime + 'ms';
23403 if (performance.length > 0) {
23404 console.groupCollapsed(title);
23405 if (console.table) {
23406 console.table(performance);
23407 } else {
23408 $.each(performance, function (index, data) {
23409 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
23410 });
23411 }
23412 console.groupEnd();
23413 }
23414 performance = [];
23415 },
23416 },
23417 invoke: function (query, passedArguments, context) {
23418 var
23419 object = instance,
23420 maxDepth,
23421 found,
23422 response
23423 ;
23424 passedArguments = passedArguments || queryArguments;
23425 context = context || element;
23426 if (typeof query === 'string' && object !== undefined) {
23427 query = query.split(/[ .]/);
23428 maxDepth = query.length - 1;
23429 $.each(query, function (depth, value) {
23430 var camelCaseValue = depth !== maxDepth
23431 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
23432 : query
23433 ;
23434 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
23435 object = object[camelCaseValue];
23436 } else if (object[camelCaseValue] !== undefined) {
23437 found = object[camelCaseValue];
23438
23439 return false;
23440 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
23441 object = object[value];
23442 } else if (object[value] !== undefined) {
23443 found = object[value];
23444
23445 return false;
23446 } else {
23447 module.error(error.method, query);
23448
23449 return false;
23450 }
23451 });
23452 }
23453 if (isFunction(found)) {
23454 response = found.apply(context, passedArguments);
23455 } else if (found !== undefined) {
23456 response = found;
23457 }
23458 if (Array.isArray(returnedValue)) {
23459 returnedValue.push(response);
23460 } else if (returnedValue !== undefined) {
23461 returnedValue = [returnedValue, response];
23462 } else if (response !== undefined) {
23463 returnedValue = response;
23464 }
23465
23466 return found;
23467 },
23468 };
23469
23470 if (methodInvoked) {
23471 if (instance === undefined) {
23472 module.initialize();
23473 }
23474 module.invoke(query);
23475 } else {
23476 if (instance !== undefined) {
23477 module.invoke('destroy');
23478 }
23479 module.initialize();
23480 }
23481 });
23482
23483 return returnedValue !== undefined
23484 ? returnedValue
23485 : this;
23486 };
23487
23488 $.fn.sidebar.settings = {
23489
23490 name: 'Sidebar',
23491 namespace: 'sidebar',
23492
23493 silent: false,
23494 debug: false,
23495 verbose: false,
23496 performance: true,
23497
23498 transition: 'auto',
23499 mobileTransition: 'auto',
23500
23501 defaultTransition: {
23502 computer: {
23503 left: 'uncover',
23504 right: 'uncover',
23505 top: 'overlay',
23506 bottom: 'overlay',
23507 },
23508 mobile: {
23509 left: 'uncover',
23510 right: 'uncover',
23511 top: 'overlay',
23512 bottom: 'overlay',
23513 },
23514 },
23515
23516 context: 'body',
23517 exclusive: false,
23518 closable: true,
23519 dimPage: true,
23520 scrollLock: false,
23521 returnScroll: false,
23522 delaySetup: false,
23523
23524 onChange: function () {},
23525 onShow: function () {},
23526 onHide: function () {},
23527
23528 onHidden: function () {},
23529 onVisible: function () {},
23530
23531 className: {
23532 active: 'active',
23533 animating: 'animating',
23534 blurring: 'blurring',
23535 closing: 'closing',
23536 dimmed: 'dimmed',
23537 locked: 'locked',
23538 pushable: 'pushable',
23539 pushed: 'pushed',
23540 right: 'right',
23541 top: 'top',
23542 left: 'left',
23543 bottom: 'bottom',
23544 visible: 'visible',
23545 },
23546
23547 selector: {
23548 bodyFixed: '> .ui.fixed.menu, > .ui.right.toast-container, > .ui.right.sidebar, > .ui.fixed.nag, > .ui.fixed.nag > .close',
23549 fixed: '.fixed',
23550 omitted: 'script, link, style, .ui.modal, .ui.dimmer, .ui.nag, .ui.fixed',
23551 pusher: '.pusher',
23552 sidebar: '.ui.sidebar',
23553 },
23554
23555 regExp: {
23556 mobile: /Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune/g,
23557 },
23558
23559 error: {
23560 method: 'The method you called is not defined.',
23561 pusher: 'Had to add pusher element. For optimal performance make sure body content is inside a pusher element',
23562 movedSidebar: 'Had to move sidebar. For optimal performance make sure sidebar and pusher are direct children of your body tag',
23563 overlay: 'The overlay setting is no longer supported, use animation: overlay',
23564 notFound: 'There were no elements that matched the specified selector',
23565 },
23566
23567 };
23568})(jQuery, window, document);
23569
23570/*!
23571 * # Fomantic-UI 2.9.3 - Sticky
23572 * https://github.com/fomantic/Fomantic-UI/
23573 *
23574 *
23575 * Released under the MIT license
23576 * https://opensource.org/licenses/MIT
23577 *
23578 */
23579
23580(function ($, window, document) {
23581 'use strict';
23582
23583 function isFunction(obj) {
23584 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
23585 }
23586
23587 window = window !== undefined && window.Math === Math
23588 ? window
23589 : globalThis;
23590
23591 $.fn.sticky = function (parameters) {
23592 var
23593 $allModules = $(this),
23594 $document = $(document),
23595
23596 time = Date.now(),
23597 performance = [],
23598
23599 query = arguments[0],
23600 methodInvoked = typeof query === 'string',
23601 queryArguments = [].slice.call(arguments, 1),
23602 contextCheck = function (context, win) {
23603 var $context;
23604 if ([window, document].indexOf(context) >= 0) {
23605 $context = $(context);
23606 } else {
23607 $context = $(win.document).find(context);
23608 if ($context.length === 0) {
23609 $context = win.frameElement ? contextCheck(context, win.parent) : window;
23610 }
23611 }
23612
23613 return $context;
23614 },
23615 returnedValue
23616 ;
23617
23618 $allModules.each(function () {
23619 var
23620 settings = $.isPlainObject(parameters)
23621 ? $.extend(true, {}, $.fn.sticky.settings, parameters)
23622 : $.extend({}, $.fn.sticky.settings),
23623
23624 className = settings.className,
23625 namespace = settings.namespace,
23626 error = settings.error,
23627
23628 eventNamespace = '.' + namespace,
23629 moduleNamespace = 'module-' + namespace,
23630
23631 $module = $(this),
23632 $window = $(window),
23633 $scroll = contextCheck(settings.scrollContext, window),
23634 $container,
23635 $context,
23636
23637 instance = $module.data(moduleNamespace),
23638
23639 element = this,
23640
23641 documentObserver,
23642 observer,
23643 module
23644 ;
23645
23646 module = {
23647
23648 initialize: function () {
23649 module.determineContainer();
23650 module.determineContext();
23651 module.verbose('Initializing sticky', settings, $container);
23652
23653 module.save.positions();
23654 module.checkErrors();
23655 module.bind.events();
23656
23657 if (settings.observeChanges) {
23658 module.observeChanges();
23659 }
23660 module.instantiate();
23661 },
23662
23663 instantiate: function () {
23664 module.verbose('Storing instance of module', module);
23665 instance = module;
23666 $module
23667 .data(moduleNamespace, module)
23668 ;
23669 },
23670
23671 destroy: function () {
23672 module.verbose('Destroying previous instance');
23673 module.reset();
23674 if (documentObserver) {
23675 documentObserver.disconnect();
23676 }
23677 if (observer) {
23678 observer.disconnect();
23679 }
23680 $window
23681 .off('load' + eventNamespace, module.event.load)
23682 .off('resize' + eventNamespace, module.event.resize)
23683 ;
23684 $scroll
23685 .off('scrollchange' + eventNamespace, module.event.scrollchange)
23686 ;
23687 $module.removeData(moduleNamespace);
23688 },
23689
23690 observeChanges: function () {
23691 if ('MutationObserver' in window) {
23692 documentObserver = new MutationObserver(module.event.documentChanged);
23693 observer = new MutationObserver(module.event.changed);
23694 documentObserver.observe(document, {
23695 childList: true,
23696 subtree: true,
23697 });
23698 observer.observe(element, {
23699 childList: true,
23700 subtree: true,
23701 });
23702 observer.observe($context[0], {
23703 childList: true,
23704 subtree: true,
23705 });
23706 module.debug('Setting up mutation observer', observer);
23707 }
23708 },
23709
23710 determineContainer: function () {
23711 $container = settings.container ? contextCheck(settings.container, window) : $module.offsetParent();
23712 },
23713
23714 determineContext: function () {
23715 $context = settings.context ? contextCheck(settings.context, window) : $container;
23716 if ($context.length === 0) {
23717 module.error(error.invalidContext, settings.context, $module);
23718 }
23719 },
23720
23721 checkErrors: function () {
23722 if (module.is.hidden()) {
23723 module.error(error.visible, $module);
23724 }
23725 if (module.cache.element.height > module.cache.context.height) {
23726 module.reset();
23727 module.error(error.elementSize, $module);
23728 }
23729 },
23730
23731 bind: {
23732 events: function () {
23733 $window
23734 .on('load' + eventNamespace, module.event.load)
23735 .on('resize' + eventNamespace, module.event.resize)
23736 ;
23737 // pub/sub pattern
23738 $scroll
23739 .off('scroll' + eventNamespace)
23740 .on('scroll' + eventNamespace, module.event.scroll)
23741 .on('scrollchange' + eventNamespace, module.event.scrollchange)
23742 ;
23743 },
23744 },
23745
23746 event: {
23747 changed: function (mutations) {
23748 clearTimeout(module.timer);
23749 module.timer = setTimeout(function () {
23750 module.verbose('DOM tree modified, updating sticky menu', mutations);
23751 module.refresh();
23752 }, 100);
23753 },
23754 documentChanged: function (mutations) {
23755 [].forEach.call(mutations, function (mutation) {
23756 if (mutation.removedNodes) {
23757 [].forEach.call(mutation.removedNodes, function (node) {
23758 if (node === element || $(node).find(element).length > 0) {
23759 module.debug('Element removed from DOM, tearing down events');
23760 module.destroy();
23761 }
23762 });
23763 }
23764 });
23765 },
23766 load: function () {
23767 module.verbose('Page contents finished loading');
23768 requestAnimationFrame(module.refresh);
23769 },
23770 resize: function () {
23771 module.verbose('Window resized');
23772 requestAnimationFrame(module.refresh);
23773 },
23774 scroll: function () {
23775 requestAnimationFrame(function () {
23776 $scroll.triggerHandler('scrollchange' + eventNamespace, $scroll.scrollTop());
23777 });
23778 },
23779 scrollchange: function (event, scrollPosition) {
23780 module.stick(scrollPosition);
23781 settings.onScroll.call(element);
23782 },
23783 },
23784
23785 refresh: function (hardRefresh) {
23786 module.reset();
23787 if (!settings.context) {
23788 module.determineContext();
23789 }
23790 if (hardRefresh) {
23791 module.determineContainer();
23792 }
23793 module.save.positions();
23794 module.stick();
23795 settings.onReposition.call(element);
23796 },
23797
23798 supports: {
23799 sticky: function () {
23800 var
23801 $element = $('<div/>')
23802 ;
23803 $element.addClass(className.supported);
23804
23805 return $element.css('position').match('sticky');
23806 },
23807 },
23808
23809 save: {
23810 lastScroll: function (scroll) {
23811 module.lastScroll = scroll;
23812 },
23813 elementScroll: function (scroll) {
23814 module.elementScroll = scroll;
23815 },
23816 positions: function () {
23817 var
23818 scrollContext = {
23819 height: $scroll.height(),
23820 },
23821 element = {
23822 margin: {
23823 top: parseInt($module.css('margin-top'), 10),
23824 bottom: parseInt($module.css('margin-bottom'), 10),
23825 },
23826 offset: $module.offset(),
23827 width: $module.outerWidth(),
23828 height: $module.outerHeight(),
23829 },
23830 context = {
23831 offset: $context.offset(),
23832 height: $context.outerHeight(),
23833 }
23834 ;
23835 if (!module.is.standardScroll()) {
23836 module.debug('Non-standard scroll. Removing scroll offset from element offset');
23837
23838 scrollContext.top = $scroll.scrollTop();
23839 scrollContext.left = $scroll.scrollLeft();
23840
23841 element.offset.top += scrollContext.top;
23842 context.offset.top += scrollContext.top;
23843 element.offset.left += scrollContext.left;
23844 context.offset.left += scrollContext.left;
23845 }
23846 module.cache = {
23847 fits: (element.height + settings.offset) <= scrollContext.height,
23848 sameHeight: element.height === context.height,
23849 scrollContext: {
23850 height: scrollContext.height,
23851 },
23852 element: {
23853 margin: element.margin,
23854 top: element.offset.top - element.margin.top,
23855 left: element.offset.left,
23856 width: element.width,
23857 height: element.height,
23858 bottom: element.offset.top + element.height,
23859 },
23860 context: {
23861 top: context.offset.top,
23862 height: context.height,
23863 bottom: context.offset.top + context.height,
23864 },
23865 };
23866 module.set.containerSize();
23867
23868 module.stick();
23869 module.debug('Caching element positions', module.cache);
23870 },
23871 },
23872
23873 get: {
23874 direction: function (scroll) {
23875 var
23876 direction = 'down'
23877 ;
23878 scroll = scroll || $scroll.scrollTop();
23879 if (module.lastScroll && module.lastScroll > scroll) {
23880 direction = 'up';
23881 }
23882
23883 return direction;
23884 },
23885 scrollChange: function (scroll) {
23886 scroll = scroll || $scroll.scrollTop();
23887
23888 return module.lastScroll
23889 ? scroll - module.lastScroll
23890 : 0;
23891 },
23892 currentElementScroll: function () {
23893 if (module.elementScroll) {
23894 return module.elementScroll;
23895 }
23896
23897 return module.is.top()
23898 ? Math.abs(parseInt($module.css('top'), 10)) || 0
23899 : Math.abs(parseInt($module.css('bottom'), 10)) || 0;
23900 },
23901
23902 elementScroll: function (scroll) {
23903 scroll = scroll || $scroll.scrollTop();
23904 var
23905 element = module.cache.element,
23906 scrollContext = module.cache.scrollContext,
23907 delta = module.get.scrollChange(scroll),
23908 maxScroll = element.height - scrollContext.height + settings.offset,
23909 elementScroll = module.get.currentElementScroll(),
23910 possibleScroll = elementScroll + delta
23911 ;
23912 if (module.cache.fits || possibleScroll < 0) {
23913 elementScroll = 0;
23914 } else if (possibleScroll > maxScroll) {
23915 elementScroll = maxScroll;
23916 } else {
23917 elementScroll = possibleScroll;
23918 }
23919
23920 return elementScroll;
23921 },
23922 },
23923
23924 remove: {
23925 lastScroll: function () {
23926 delete module.lastScroll;
23927 },
23928 elementScroll: function () {
23929 delete module.elementScroll;
23930 },
23931 minimumSize: function () {
23932 $container
23933 .css('min-height', '')
23934 ;
23935 },
23936 offset: function () {
23937 $module.css('margin-top', '');
23938 },
23939 },
23940
23941 set: {
23942 offset: function () {
23943 module.verbose('Setting offset on element', settings.offset);
23944 $module
23945 .css('margin-top', settings.offset)
23946 ;
23947 },
23948 containerSize: function () {
23949 var
23950 tagName = $container[0].tagName
23951 ;
23952 if (tagName === 'HTML' || tagName === 'body') {
23953 module.determineContainer();
23954 } else {
23955 var tallestHeight = Math.max(module.cache.context.height, module.cache.element.height);
23956 if (tallestHeight - $container.outerHeight() > settings.jitter) {
23957 module.debug('Context is taller than container. Specifying exact height for container', module.cache.context.height);
23958 $container.css({
23959 height: tallestHeight,
23960 });
23961 } else {
23962 $container.css({
23963 height: '',
23964 });
23965 }
23966 if (Math.abs($container.outerHeight() - module.cache.context.height) > settings.jitter) {
23967 module.debug('Context has padding, specifying exact height for container', module.cache.context.height);
23968 $container.css({
23969 height: module.cache.context.height,
23970 });
23971 }
23972 }
23973 },
23974 minimumSize: function () {
23975 var
23976 element = module.cache.element
23977 ;
23978 $container
23979 .css('min-height', element.height)
23980 ;
23981 },
23982 scroll: function (scroll) {
23983 module.debug('Setting scroll on element', scroll);
23984 if (module.elementScroll === scroll) {
23985 return;
23986 }
23987 if (module.is.top()) {
23988 $module
23989 .css('bottom', '')
23990 .css('top', -scroll + 'px')
23991 ;
23992 }
23993 if (module.is.bottom()) {
23994 $module
23995 .css('top', '')
23996 .css('bottom', scroll + 'px')
23997 ;
23998 }
23999 },
24000 size: function () {
24001 if (module.cache.element.height !== 0 && module.cache.element.width !== 0) {
24002 element.style.setProperty('width', module.cache.element.width + 'px', 'important');
24003 element.style.setProperty('height', module.cache.element.height + 'px', 'important');
24004 }
24005 },
24006 },
24007
24008 is: {
24009 standardScroll: function () {
24010 return $scroll[0] === window;
24011 },
24012 top: function () {
24013 return $module.hasClass(className.top);
24014 },
24015 bottom: function () {
24016 return $module.hasClass(className.bottom);
24017 },
24018 initialPosition: function () {
24019 return !module.is.fixed() && !module.is.bound();
24020 },
24021 hidden: function () {
24022 return !$module.is(':visible');
24023 },
24024 bound: function () {
24025 return $module.hasClass(className.bound);
24026 },
24027 fixed: function () {
24028 return $module.hasClass(className.fixed);
24029 },
24030 },
24031
24032 stick: function (scrollPosition) {
24033 var
24034 cachedPosition = scrollPosition || $scroll.scrollTop(),
24035 cache = module.cache,
24036 fits = cache.fits,
24037 sameHeight = cache.sameHeight,
24038 element = cache.element,
24039 scrollContext = cache.scrollContext,
24040 context = cache.context,
24041 offset = module.is.bottom() && settings.pushing
24042 ? settings.bottomOffset
24043 : settings.offset,
24044 scroll = {
24045 top: cachedPosition + offset,
24046 bottom: cachedPosition + offset + scrollContext.height,
24047 },
24048 elementScroll = fits
24049 ? 0
24050 : module.get.elementScroll(scroll.top),
24051
24052 // shorthand
24053 doesntFit = !fits,
24054 elementVisible = element.height !== 0
24055 ;
24056 if (elementVisible && !sameHeight) {
24057 if (module.is.initialPosition()) {
24058 if (scroll.top >= context.bottom) {
24059 module.debug('Initial element position is bottom of container');
24060 module.bindBottom();
24061 } else if (scroll.top > element.top) {
24062 if ((element.height + scroll.top - elementScroll) >= context.bottom && element.height < context.height) {
24063 module.debug('Initial element position is bottom of container');
24064 module.bindBottom();
24065 } else {
24066 module.debug('Initial element position is fixed');
24067 module.fixTop();
24068 }
24069 }
24070 } else if (module.is.fixed()) {
24071 if (module.is.top()) {
24072 if (scroll.top <= element.top) {
24073 module.debug('Fixed element reached top of container');
24074 module.setInitialPosition();
24075 } else if ((element.height + scroll.top - elementScroll) >= context.bottom) {
24076 module.debug('Fixed element reached bottom of container');
24077 module.bindBottom();
24078 } else if (doesntFit) { // scroll element if larger than screen
24079 module.set.scroll(elementScroll);
24080 module.save.lastScroll(scroll.top);
24081 module.save.elementScroll(elementScroll);
24082 }
24083 } else if (module.is.bottom()) {
24084 if ((scroll.bottom - element.height) <= element.top) { // top edge
24085 module.debug('Bottom fixed rail has reached top of container');
24086 module.setInitialPosition();
24087 } else if (scroll.bottom >= context.bottom) { // bottom edge
24088 module.debug('Bottom fixed rail has reached bottom of container');
24089 module.bindBottom();
24090 } else if (doesntFit) { // scroll element if larger than screen
24091 module.set.scroll(elementScroll);
24092 module.save.lastScroll(scroll.top);
24093 module.save.elementScroll(elementScroll);
24094 }
24095 }
24096 } else if (module.is.bottom()) {
24097 if (scroll.top <= element.top) {
24098 module.debug('Jumped from bottom fixed to top fixed, most likely used home/end button');
24099 module.setInitialPosition();
24100 } else {
24101 if (settings.pushing) {
24102 if (module.is.bound() && scroll.bottom <= context.bottom) {
24103 module.debug('Fixing bottom attached element to bottom of browser.');
24104 module.fixBottom();
24105 }
24106 } else {
24107 if (module.is.bound() && (scroll.top <= context.bottom - element.height)) {
24108 module.debug('Fixing bottom attached element to top of browser.');
24109 module.fixTop();
24110 }
24111 }
24112 }
24113 }
24114 }
24115 },
24116
24117 bindTop: function () {
24118 module.debug('Binding element to top of parent container');
24119 module.remove.offset();
24120 if (settings.setSize) {
24121 module.set.size();
24122 }
24123 $module
24124 .css({
24125 left: '',
24126 top: '',
24127 marginBottom: '',
24128 })
24129 .removeClass(className.fixed)
24130 .removeClass(className.bottom)
24131 .addClass(className.bound)
24132 .addClass(className.top)
24133 ;
24134 settings.onTop.call(element);
24135 settings.onUnstick.call(element);
24136 },
24137 bindBottom: function () {
24138 module.debug('Binding element to bottom of parent container');
24139 module.remove.offset();
24140 if (settings.setSize) {
24141 module.set.size();
24142 }
24143 $module
24144 .css({
24145 left: '',
24146 top: '',
24147 })
24148 .removeClass(className.fixed)
24149 .removeClass(className.top)
24150 .addClass(className.bound)
24151 .addClass(className.bottom)
24152 ;
24153 settings.onBottom.call(element);
24154 settings.onUnstick.call(element);
24155 },
24156
24157 setInitialPosition: function () {
24158 module.debug('Returning to initial position');
24159 module.unfix();
24160 module.unbind();
24161 },
24162
24163 fixTop: function () {
24164 module.debug('Fixing element to top of page');
24165 if (settings.setSize) {
24166 module.set.size();
24167 }
24168 module.set.minimumSize();
24169 module.set.offset();
24170 $module
24171 .css({
24172 left: module.cache.element.left,
24173 bottom: '',
24174 marginBottom: '',
24175 })
24176 .removeClass(className.bound)
24177 .removeClass(className.bottom)
24178 .addClass(className.fixed)
24179 .addClass(className.top)
24180 ;
24181 settings.onStick.call(element);
24182 },
24183
24184 fixBottom: function () {
24185 module.debug('Sticking element to bottom of page');
24186 if (settings.setSize) {
24187 module.set.size();
24188 }
24189 module.set.minimumSize();
24190 module.set.offset();
24191 $module
24192 .css({
24193 left: module.cache.element.left,
24194 bottom: '',
24195 marginBottom: '',
24196 })
24197 .removeClass(className.bound)
24198 .removeClass(className.top)
24199 .addClass(className.fixed)
24200 .addClass(className.bottom)
24201 ;
24202 settings.onStick.call(element);
24203 },
24204
24205 unbind: function () {
24206 if (module.is.bound()) {
24207 module.debug('Removing container bound position on element');
24208 module.remove.offset();
24209 $module
24210 .removeClass(className.bound)
24211 .removeClass(className.top)
24212 .removeClass(className.bottom)
24213 ;
24214 }
24215 },
24216
24217 unfix: function () {
24218 if (module.is.fixed()) {
24219 module.debug('Removing fixed position on element');
24220 module.remove.minimumSize();
24221 module.remove.offset();
24222 $module
24223 .removeClass(className.fixed)
24224 .removeClass(className.top)
24225 .removeClass(className.bottom)
24226 ;
24227 settings.onUnstick.call(element);
24228 }
24229 },
24230
24231 reset: function () {
24232 module.debug('Resetting elements position');
24233 module.unbind();
24234 module.unfix();
24235 module.resetCSS();
24236 module.remove.offset();
24237 module.remove.lastScroll();
24238 },
24239
24240 resetCSS: function () {
24241 $module
24242 .css({
24243 width: '',
24244 height: '',
24245 })
24246 ;
24247 $container
24248 .css({
24249 height: '',
24250 })
24251 ;
24252 },
24253
24254 setting: function (name, value) {
24255 if ($.isPlainObject(name)) {
24256 $.extend(true, settings, name);
24257 } else if (value !== undefined) {
24258 settings[name] = value;
24259 } else {
24260 return settings[name];
24261 }
24262 },
24263 internal: function (name, value) {
24264 if ($.isPlainObject(name)) {
24265 $.extend(true, module, name);
24266 } else if (value !== undefined) {
24267 module[name] = value;
24268 } else {
24269 return module[name];
24270 }
24271 },
24272 debug: function () {
24273 if (!settings.silent && settings.debug) {
24274 if (settings.performance) {
24275 module.performance.log(arguments);
24276 } else {
24277 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
24278 module.debug.apply(console, arguments);
24279 }
24280 }
24281 },
24282 verbose: function () {
24283 if (!settings.silent && settings.verbose && settings.debug) {
24284 if (settings.performance) {
24285 module.performance.log(arguments);
24286 } else {
24287 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
24288 module.verbose.apply(console, arguments);
24289 }
24290 }
24291 },
24292 error: function () {
24293 if (!settings.silent) {
24294 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
24295 module.error.apply(console, arguments);
24296 }
24297 },
24298 performance: {
24299 log: function (message) {
24300 var
24301 currentTime,
24302 executionTime,
24303 previousTime
24304 ;
24305 if (settings.performance) {
24306 currentTime = Date.now();
24307 previousTime = time || currentTime;
24308 executionTime = currentTime - previousTime;
24309 time = currentTime;
24310 performance.push({
24311 Name: message[0],
24312 Arguments: [].slice.call(message, 1) || '',
24313 Element: element,
24314 'Execution Time': executionTime,
24315 });
24316 }
24317 clearTimeout(module.performance.timer);
24318 module.performance.timer = setTimeout(function () { module.performance.display(); }, 0);
24319 },
24320 display: function () {
24321 var
24322 title = settings.name + ':',
24323 totalTime = 0
24324 ;
24325 time = false;
24326 clearTimeout(module.performance.timer);
24327 $.each(performance, function (index, data) {
24328 totalTime += data['Execution Time'];
24329 });
24330 title += ' ' + totalTime + 'ms';
24331 if (performance.length > 0) {
24332 console.groupCollapsed(title);
24333 if (console.table) {
24334 console.table(performance);
24335 } else {
24336 $.each(performance, function (index, data) {
24337 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
24338 });
24339 }
24340 console.groupEnd();
24341 }
24342 performance = [];
24343 },
24344 },
24345 invoke: function (query, passedArguments, context) {
24346 var
24347 object = instance,
24348 maxDepth,
24349 found,
24350 response
24351 ;
24352 passedArguments = passedArguments || queryArguments;
24353 context = context || element;
24354 if (typeof query === 'string' && object !== undefined) {
24355 query = query.split(/[ .]/);
24356 maxDepth = query.length - 1;
24357 $.each(query, function (depth, value) {
24358 var camelCaseValue = depth !== maxDepth
24359 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
24360 : query
24361 ;
24362 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
24363 object = object[camelCaseValue];
24364 } else if (object[camelCaseValue] !== undefined) {
24365 found = object[camelCaseValue];
24366
24367 return false;
24368 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
24369 object = object[value];
24370 } else if (object[value] !== undefined) {
24371 found = object[value];
24372
24373 return false;
24374 } else {
24375 module.error(error.method, query);
24376
24377 return false;
24378 }
24379 });
24380 }
24381 if (isFunction(found)) {
24382 response = found.apply(context, passedArguments);
24383 } else if (found !== undefined) {
24384 response = found;
24385 }
24386 if (Array.isArray(returnedValue)) {
24387 returnedValue.push(response);
24388 } else if (returnedValue !== undefined) {
24389 returnedValue = [returnedValue, response];
24390 } else if (response !== undefined) {
24391 returnedValue = response;
24392 }
24393
24394 return found;
24395 },
24396 };
24397
24398 if (methodInvoked) {
24399 if (instance === undefined) {
24400 module.initialize();
24401 }
24402 module.invoke(query);
24403 } else {
24404 if (instance !== undefined) {
24405 instance.invoke('destroy');
24406 }
24407 module.initialize();
24408 }
24409 });
24410
24411 return returnedValue !== undefined
24412 ? returnedValue
24413 : this;
24414 };
24415
24416 $.fn.sticky.settings = {
24417
24418 name: 'Sticky',
24419 namespace: 'sticky',
24420
24421 silent: false,
24422 debug: false,
24423 verbose: true,
24424 performance: true,
24425
24426 // whether to stick in the opposite direction on scroll up
24427 pushing: false,
24428
24429 context: false,
24430 container: false,
24431
24432 // Context to watch scroll events
24433 scrollContext: window,
24434
24435 // Offset to adjust scroll
24436 offset: 0,
24437
24438 // Offset to adjust scroll when attached to bottom of screen
24439 bottomOffset: 0,
24440
24441 // will only set container height if difference between context and container is larger than this number
24442 jitter: 5,
24443
24444 // set width of sticky element when it is fixed to page (used to make sure 100% width is maintained if no fixed size set)
24445 setSize: true,
24446
24447 // Whether to automatically observe changes with Mutation Observers
24448 observeChanges: false,
24449
24450 // Called when position is recalculated
24451 onReposition: function () {},
24452
24453 // Called on each scroll
24454 onScroll: function () {},
24455
24456 // Called when element is stuck to viewport
24457 onStick: function () {},
24458
24459 // Called when element is unstuck from viewport
24460 onUnstick: function () {},
24461
24462 // Called when element reaches top of context
24463 onTop: function () {},
24464
24465 // Called when element reaches bottom of context
24466 onBottom: function () {},
24467
24468 error: {
24469 visible: 'Element is hidden, you must call refresh after element becomes visible. Use silent setting to suppress this warning in production.',
24470 method: 'The method you called is not defined.',
24471 invalidContext: 'Context specified does not exist',
24472 elementSize: 'Sticky element is larger than its container, cannot create sticky.',
24473 },
24474
24475 className: {
24476 bound: 'bound',
24477 fixed: 'fixed',
24478 supported: 'native',
24479 top: 'top',
24480 bottom: 'bottom',
24481 },
24482
24483 };
24484})(jQuery, window, document);
24485
24486/*!
24487 * # Fomantic-UI 2.9.3 - Tab
24488 * https://github.com/fomantic/Fomantic-UI/
24489 *
24490 *
24491 * Released under the MIT license
24492 * https://opensource.org/licenses/MIT
24493 *
24494 */
24495
24496(function ($, window, document) {
24497 'use strict';
24498
24499 function isWindow(obj) {
24500 return obj !== null && obj === obj.window;
24501 }
24502
24503 function isFunction(obj) {
24504 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
24505 }
24506
24507 window = window !== undefined && window.Math === Math
24508 ? window
24509 : globalThis;
24510
24511 $.fn.tab = function (parameters) {
24512 var
24513 // use window context if none specified
24514 $allModules = isFunction(this)
24515 ? $(window)
24516 : $(this),
24517 $document = $(document),
24518 time = Date.now(),
24519 performance = [],
24520
24521 query = arguments[0],
24522 methodInvoked = typeof query === 'string',
24523 queryArguments = [].slice.call(arguments, 1),
24524 contextCheck = function (context, win) {
24525 var $context;
24526 if ([window, document].indexOf(context) >= 0) {
24527 $context = $(context);
24528 } else {
24529 $context = $(win.document).find(context);
24530 if ($context.length === 0) {
24531 $context = win.frameElement ? contextCheck(context, win.parent) : window;
24532 }
24533 }
24534
24535 return $context;
24536 },
24537 initializedHistory = false,
24538 returnedValue
24539 ;
24540
24541 $allModules.each(function () {
24542 var
24543 settings = $.isPlainObject(parameters)
24544 ? $.extend(true, {}, $.fn.tab.settings, parameters)
24545 : $.extend({}, $.fn.tab.settings),
24546
24547 className = settings.className,
24548 metadata = settings.metadata,
24549 selector = settings.selector,
24550 error = settings.error,
24551 regExp = settings.regExp,
24552
24553 eventNamespace = '.' + settings.namespace,
24554 moduleNamespace = 'module-' + settings.namespace,
24555
24556 $module = $(this),
24557 $context,
24558 $tabs,
24559
24560 cache = {},
24561 firstLoad = true,
24562 recursionDepth = 0,
24563 element = this,
24564 instance = $module.data(moduleNamespace),
24565
24566 activeTabPath,
24567 parameterArray,
24568 module,
24569
24570 historyEvent
24571 ;
24572
24573 module = {
24574
24575 initialize: function () {
24576 module.debug('Initializing tab menu item', $module);
24577 module.determineTabs();
24578
24579 module.debug('Determining tabs', settings.context, $tabs);
24580 // set up automatic routing
24581 if (settings.auto) {
24582 module.set.auto();
24583 }
24584 module.bind.events();
24585
24586 if (settings.history && !initializedHistory) {
24587 settings.history = module.initializeHistory();
24588 initializedHistory = true;
24589 }
24590
24591 var activeTab = module.determine.activeTab();
24592 if (settings.autoTabActivation && instance === undefined && activeTab === null) {
24593 activeTab = settings.autoTabActivation === true ? module.get.initialPath() : settings.autoTabActivation;
24594 module.debug('No active tab detected, setting tab active', activeTab);
24595 module.changeTab(activeTab);
24596 }
24597 if (activeTab !== null && settings.history && settings.historyType === 'state') {
24598 var autoUpdate = $.address.autoUpdate();
24599 $.address.autoUpdate(false);
24600 $.address.value(activeTab);
24601 $.address.autoUpdate(autoUpdate);
24602 }
24603
24604 module.instantiate();
24605 },
24606
24607 instantiate: function () {
24608 module.verbose('Storing instance of module', module);
24609 instance = module;
24610 $module
24611 .data(moduleNamespace, module)
24612 ;
24613 },
24614
24615 destroy: function () {
24616 module.debug('Destroying tabs', $module);
24617 $module
24618 .removeData(moduleNamespace)
24619 .off(eventNamespace)
24620 ;
24621 },
24622
24623 bind: {
24624 events: function () {
24625 // if using $.tab don't add events
24626 if (!isWindow(element)) {
24627 module.debug('Attaching tab activation events to element', $module);
24628 $module
24629 .on('click' + eventNamespace, module.event.click)
24630 ;
24631 }
24632 },
24633 },
24634
24635 determineTabs: function () {
24636 var
24637 $reference
24638 ;
24639
24640 // determine tab context
24641 if (settings.context === 'parent') {
24642 if ($module.closest(selector.ui).length > 0) {
24643 $reference = $module.closest(selector.ui);
24644 module.verbose('Using closest UI element as parent', $reference);
24645 } else {
24646 $reference = $module;
24647 }
24648 $context = $reference.parent();
24649 module.verbose('Determined parent element for creating context', $context);
24650 } else if (settings.context) {
24651 $context = contextCheck(settings.context, window);
24652 module.verbose('Using selector for tab context', settings.context, $context);
24653 } else {
24654 $context = $('body');
24655 }
24656 // find tabs
24657 if (settings.childrenOnly) {
24658 $tabs = $context.children(selector.tabs);
24659 module.debug('Searching tab context children for tabs', $context, $tabs);
24660 } else {
24661 $tabs = $context.find(selector.tabs);
24662 module.debug('Searching tab context for tabs', $context, $tabs);
24663 }
24664 },
24665
24666 initializeHistory: function () {
24667 module.debug('Initializing page state');
24668 if ($.address === undefined) {
24669 module.error(error.state);
24670
24671 return false;
24672 }
24673 if (settings.historyType === 'state') {
24674 module.debug('Using HTML5 to manage state');
24675 if (settings.path !== false) {
24676 $.address
24677 .history(true)
24678 .state(settings.path)
24679 ;
24680 $(window).trigger('popstate');
24681 } else {
24682 module.error(error.path);
24683
24684 return false;
24685 }
24686 }
24687 $.address
24688 .bind('change', module.event.history.change)
24689 ;
24690
24691 return true;
24692 },
24693
24694 event: {
24695 click: function (event) {
24696 var
24697 tabPath = $(this).data(metadata.tab)
24698 ;
24699 if (tabPath !== undefined) {
24700 if (settings.history) {
24701 module.verbose('Updating page state', event);
24702 $.address.value(tabPath);
24703 } else {
24704 module.verbose('Changing tab', event);
24705 module.changeTab(tabPath);
24706 }
24707 event.preventDefault();
24708 } else {
24709 module.debug('No tab specified');
24710 }
24711 },
24712 history: {
24713 change: function (event) {
24714 var
24715 tabPath = event.pathNames.join('/') || module.get.initialPath(),
24716 pageTitle = settings.templates.determineTitle(tabPath) || false
24717 ;
24718 module.performance.display();
24719 module.debug('History change event', tabPath, event);
24720 historyEvent = event;
24721 if (tabPath !== undefined) {
24722 module.changeTab(tabPath);
24723 }
24724 if (pageTitle) {
24725 $.address.title(pageTitle);
24726 }
24727 },
24728 },
24729 },
24730
24731 refresh: function () {
24732 if (activeTabPath) {
24733 module.debug('Refreshing tab', activeTabPath);
24734 module.changeTab(activeTabPath);
24735 }
24736 },
24737
24738 cache: {
24739
24740 read: function (cacheKey) {
24741 return cacheKey !== undefined
24742 ? cache[cacheKey]
24743 : false;
24744 },
24745 add: function (cacheKey, content) {
24746 cacheKey = cacheKey || activeTabPath;
24747 module.debug('Adding cached content for', cacheKey);
24748 cache[cacheKey] = content;
24749 },
24750 remove: function (cacheKey) {
24751 cacheKey = cacheKey || activeTabPath;
24752 module.debug('Removing cached content for', cacheKey);
24753 delete cache[cacheKey];
24754 },
24755 },
24756
24757 escape: {
24758 string: function (text) {
24759 text = String(text);
24760
24761 return text.replace(regExp.escape, '\\$&');
24762 },
24763 },
24764
24765 set: {
24766 auto: function () {
24767 var
24768 url = typeof settings.path === 'string'
24769 ? settings.path.replace(/\/$/, '') + '/{$tab}'
24770 : '/{$tab}'
24771 ;
24772 module.verbose('Setting up automatic tab retrieval from server', url);
24773 if ($.isPlainObject(settings.apiSettings)) {
24774 settings.apiSettings.url = url;
24775 } else {
24776 settings.apiSettings = {
24777 url: url,
24778 };
24779 }
24780 },
24781 loading: function (tabPath) {
24782 var
24783 $tab = module.get.tabElement(tabPath),
24784 isLoading = $tab.hasClass(className.loading)
24785 ;
24786 if (!isLoading) {
24787 module.verbose('Setting loading state for', $tab);
24788 $tab
24789 .addClass(className.loading)
24790 .siblings($tabs)
24791 .removeClass(className.active + ' ' + className.loading)
24792 ;
24793 if ($tab.length > 0) {
24794 settings.onRequest.call($tab[0], tabPath);
24795 }
24796 }
24797 },
24798 state: function (state) {
24799 $.address.value(state);
24800 },
24801 },
24802
24803 changeTab: function (tabPath) {
24804 var
24805 pushStateAvailable = window.history && window.history.pushState,
24806 shouldIgnoreLoad = pushStateAvailable && settings.ignoreFirstLoad && firstLoad,
24807 remoteContent = settings.auto || $.isPlainObject(settings.apiSettings),
24808 // only add default path if not remote content
24809 pathArray = remoteContent && !shouldIgnoreLoad
24810 ? module.utilities.pathToArray(tabPath)
24811 : module.get.defaultPathArray(tabPath)
24812 ;
24813 tabPath = module.utilities.arrayToPath(pathArray);
24814 $.each(pathArray, function (index, tab) {
24815 var
24816 currentPathArray = pathArray.slice(0, index + 1),
24817 currentPath = module.utilities.arrayToPath(currentPathArray),
24818
24819 isTab = module.is.tab(currentPath),
24820 isLastIndex = index + 1 === pathArray.length,
24821
24822 $tab = module.get.tabElement(currentPath),
24823 $anchor,
24824 nextPathArray,
24825 nextPath,
24826 isLastTab
24827 ;
24828 module.verbose('Looking for tab', tab);
24829 if (isTab) {
24830 module.verbose('Tab was found', tab);
24831 // scope up
24832 activeTabPath = currentPath;
24833 parameterArray = module.utilities.filterArray(pathArray, currentPathArray);
24834
24835 if (isLastIndex) {
24836 isLastTab = true;
24837 } else {
24838 nextPathArray = pathArray.slice(0, index + 2);
24839 nextPath = module.utilities.arrayToPath(nextPathArray);
24840 isLastTab = !module.is.tab(nextPath);
24841 if (isLastTab) {
24842 module.verbose('Tab parameters found', nextPathArray);
24843 }
24844 }
24845 if (settings.onBeforeChange.call(element, currentPath) === false) {
24846 module.debug('onBeforeChange returned false, cancelling tab change', $tab);
24847
24848 return false;
24849 }
24850 if (isLastTab && remoteContent) {
24851 if (!shouldIgnoreLoad) {
24852 module.activate.navigation(currentPath);
24853 module.fetch.content(currentPath, tabPath);
24854 } else {
24855 module.debug('Ignoring remote content on first tab load', currentPath);
24856 firstLoad = false;
24857 module.cache.add(tabPath, $tab.html());
24858 module.activate.all(currentPath);
24859 settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
24860 settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
24861 }
24862
24863 return false;
24864 }
24865
24866 module.debug('Opened local tab', currentPath);
24867 module.activate.all(currentPath);
24868 if (!module.cache.read(currentPath)) {
24869 module.cache.add(currentPath, true);
24870 module.debug('First time tab loaded calling tab init');
24871 settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
24872 }
24873 settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
24874 } else if (tabPath.search('/') === -1 && tabPath !== '') {
24875 // look for in page anchor
24876 tabPath = module.escape.string(tabPath);
24877 $anchor = $('#' + tabPath + ', a[name="' + tabPath + '"]');
24878 currentPath = $anchor.closest('[data-tab]').data(metadata.tab);
24879 $tab = module.get.tabElement(currentPath);
24880 // if anchor exists use parent tab
24881 if ($anchor && $anchor.length > 0 && currentPath) {
24882 module.debug('Anchor link used, opening parent tab', $tab, $anchor);
24883 if (settings.onBeforeChange.call(element, currentPath) === false) {
24884 module.debug('onBeforeChange returned false, cancelling tab change', $tab);
24885
24886 return false;
24887 }
24888 if (!$tab.hasClass(className.active)) {
24889 setTimeout(function () {
24890 module.scrollTo($anchor);
24891 }, 0);
24892 }
24893 module.activate.all(currentPath);
24894 if (!module.cache.read(currentPath)) {
24895 module.cache.add(currentPath, true);
24896 module.debug('First time tab loaded calling tab init');
24897 settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
24898 }
24899 settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
24900
24901 return false;
24902 }
24903 } else {
24904 module.error(error.missingTab, $module, $context, currentPath);
24905
24906 return false;
24907 }
24908 });
24909 },
24910
24911 scrollTo: function ($element) {
24912 var
24913 scrollOffset = $element && $element.length > 0
24914 ? $element.offset().top
24915 : false
24916 ;
24917 if (scrollOffset !== false) {
24918 module.debug('Forcing scroll to an in-page link in a hidden tab', scrollOffset, $element);
24919 $document.scrollTop(scrollOffset);
24920 }
24921 },
24922
24923 update: {
24924 content: function (tabPath, html, evaluateScripts) {
24925 var
24926 $tab = module.get.tabElement(tabPath),
24927 tab = $tab[0]
24928 ;
24929 evaluateScripts = evaluateScripts !== undefined
24930 ? evaluateScripts
24931 : settings.evaluateScripts;
24932 if (typeof settings.cacheType === 'string' && settings.cacheType.toLowerCase() === 'dom' && typeof html !== 'string') {
24933 $tab
24934 .empty()
24935 .append($(html).clone(true))
24936 ;
24937 } else {
24938 if (evaluateScripts) {
24939 module.debug('Updating HTML and evaluating inline scripts', tabPath, html);
24940 $tab.html(html);
24941 } else {
24942 module.debug('Updating HTML', tabPath, html);
24943 tab.innerHTML = html;
24944 }
24945 }
24946 },
24947 },
24948
24949 fetch: {
24950
24951 content: function (tabPath, fullTabPath) {
24952 var
24953 $tab = module.get.tabElement(tabPath),
24954 apiSettings = {
24955 dataType: 'html',
24956 encodeParameters: false,
24957 on: 'now',
24958 cache: settings.alwaysRefresh,
24959 headers: {
24960 'X-Remote': true,
24961 },
24962 onSuccess: function (response) {
24963 if (settings.cacheType === 'response') {
24964 module.cache.add(fullTabPath, response);
24965 }
24966 module.update.content(tabPath, response);
24967 if (tabPath == activeTabPath) {
24968 module.debug('Content loaded', tabPath);
24969 module.activate.tab(tabPath);
24970 } else {
24971 module.debug('Content loaded in background', tabPath);
24972 }
24973 settings.onFirstLoad.call($tab[0], tabPath, parameterArray, historyEvent);
24974 settings.onLoad.call($tab[0], tabPath, parameterArray, historyEvent);
24975
24976 if (settings.loadOnce) {
24977 module.cache.add(fullTabPath, true);
24978 } else if (typeof settings.cacheType === 'string' && settings.cacheType.toLowerCase() === 'dom' && $tab.children().length > 0) {
24979 setTimeout(function () {
24980 var
24981 $clone = $tab.children().clone(true)
24982 ;
24983 $clone = $clone.not('script');
24984 module.cache.add(fullTabPath, $clone);
24985 }, 0);
24986 } else {
24987 module.cache.add(fullTabPath, $tab.html());
24988 }
24989 },
24990 urlData: {
24991 tab: fullTabPath,
24992 },
24993 },
24994 request = $tab.api('get request') || false,
24995 existingRequest = request && request.state() === 'pending',
24996 requestSettings,
24997 cachedContent
24998 ;
24999
25000 fullTabPath = fullTabPath || tabPath;
25001 cachedContent = module.cache.read(fullTabPath);
25002
25003 if (settings.cache && cachedContent) {
25004 module.activate.tab(tabPath);
25005 module.debug('Adding cached content', fullTabPath);
25006 if (!settings.loadOnce) {
25007 if (settings.evaluateScripts === 'once') {
25008 module.update.content(tabPath, cachedContent, false);
25009 } else {
25010 module.update.content(tabPath, cachedContent);
25011 }
25012 }
25013 settings.onLoad.call($tab[0], tabPath, parameterArray, historyEvent);
25014 } else if (existingRequest) {
25015 module.set.loading(tabPath);
25016 module.debug('Content is already loading', fullTabPath);
25017 } else if ($.api !== undefined) {
25018 requestSettings = $.extend(true, {}, settings.apiSettings, apiSettings);
25019 module.debug('Retrieving remote content', fullTabPath, requestSettings);
25020 module.set.loading(tabPath);
25021 $tab.api(requestSettings);
25022 } else {
25023 module.error(error.api);
25024 }
25025 },
25026 },
25027
25028 activate: {
25029 all: function (tabPath) {
25030 module.activate.tab(tabPath);
25031 module.activate.navigation(tabPath);
25032 },
25033 tab: function (tabPath) {
25034 var
25035 $tab = module.get.tabElement(tabPath),
25036 $deactiveTabs = settings.deactivate === 'siblings'
25037 ? $tab.siblings($tabs)
25038 : $tabs.not($tab),
25039 isActive = $tab.hasClass(className.active)
25040 ;
25041 module.verbose('Showing tab content for', $tab);
25042 if (!isActive) {
25043 $tab
25044 .addClass(className.active)
25045 ;
25046 $deactiveTabs
25047 .removeClass(className.active + ' ' + className.loading)
25048 ;
25049 if ($tab.length > 0) {
25050 settings.onVisible.call($tab[0], tabPath);
25051 }
25052 }
25053 },
25054 navigation: function (tabPath) {
25055 var
25056 $navigation = module.get.navElement(tabPath),
25057 $deactiveNavigation = settings.deactivate === 'siblings'
25058 ? $navigation.siblings($allModules)
25059 : $allModules.not($navigation),
25060 isActive = $navigation.hasClass(className.active)
25061 ;
25062 module.verbose('Activating tab navigation for', $navigation, tabPath);
25063 if (!isActive) {
25064 $navigation
25065 .addClass(className.active)
25066 ;
25067 $deactiveNavigation
25068 .removeClass(className.active + ' ' + className.loading)
25069 ;
25070 }
25071 },
25072 },
25073
25074 deactivate: {
25075 all: function () {
25076 module.deactivate.navigation();
25077 module.deactivate.tabs();
25078 },
25079 navigation: function () {
25080 $allModules
25081 .removeClass(className.active)
25082 ;
25083 },
25084 tabs: function () {
25085 $tabs
25086 .removeClass(className.active + ' ' + className.loading)
25087 ;
25088 },
25089 },
25090
25091 is: {
25092 tab: function (tabName) {
25093 return tabName !== undefined
25094 ? module.get.tabElement(tabName).length > 0
25095 : false;
25096 },
25097 },
25098
25099 get: {
25100 initialPath: function () {
25101 return $allModules.eq(0).data(metadata.tab) || $tabs.eq(0).data(metadata.tab);
25102 },
25103 path: function () {
25104 return $.address.value();
25105 },
25106 // adds default tabs to tab path
25107 defaultPathArray: function (tabPath) {
25108 return module.utilities.pathToArray(module.get.defaultPath(tabPath));
25109 },
25110 defaultPath: function (tabPath) {
25111 var
25112 $defaultNav = $allModules.filter('[data-' + metadata.tab + '^="' + module.escape.string(tabPath) + '/"]').eq(0),
25113 defaultTab = $defaultNav.data(metadata.tab) || false
25114 ;
25115 if (defaultTab) {
25116 module.debug('Found default tab', defaultTab);
25117 if (recursionDepth < settings.maxDepth) {
25118 recursionDepth++;
25119
25120 return module.get.defaultPath(defaultTab);
25121 }
25122 module.error(error.recursion);
25123 } else {
25124 module.debug('No default tabs found for', tabPath, $tabs);
25125 }
25126 recursionDepth = 0;
25127
25128 return tabPath;
25129 },
25130 navElement: function (tabPath) {
25131 tabPath = tabPath || activeTabPath;
25132
25133 return $allModules.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]');
25134 },
25135 tabElement: function (tabPath) {
25136 var
25137 $fullPathTab,
25138 $simplePathTab,
25139 tabPathArray,
25140 lastTab
25141 ;
25142 tabPath = tabPath || activeTabPath;
25143 tabPathArray = module.utilities.pathToArray(tabPath);
25144 lastTab = module.utilities.last(tabPathArray);
25145 $fullPathTab = $tabs.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]');
25146 $simplePathTab = $tabs.filter('[data-' + metadata.tab + '="' + module.escape.string(lastTab) + '"]');
25147
25148 return $fullPathTab.length > 0
25149 ? $fullPathTab
25150 : $simplePathTab;
25151 },
25152 tab: function () {
25153 return activeTabPath;
25154 },
25155 },
25156
25157 determine: {
25158 activeTab: function () {
25159 var activeTab = null;
25160
25161 $tabs.each(function (_index, tab) {
25162 var $tab = $(tab);
25163
25164 if ($tab.hasClass(className.active)) {
25165 var
25166 tabPath = $(this).data(metadata.tab),
25167 $anchor = $allModules.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]')
25168 ;
25169
25170 if ($anchor.hasClass(className.active)) {
25171 activeTab = tabPath;
25172 }
25173 }
25174 });
25175
25176 return activeTab;
25177 },
25178 },
25179
25180 utilities: {
25181 filterArray: function (keepArray, removeArray) {
25182 return $.grep(keepArray, function (keepValue) {
25183 return $.inArray(keepValue, removeArray) === -1;
25184 });
25185 },
25186 last: function (array) {
25187 return Array.isArray(array)
25188 ? array[array.length - 1]
25189 : false;
25190 },
25191 pathToArray: function (pathName) {
25192 if (pathName === undefined) {
25193 pathName = activeTabPath;
25194 }
25195
25196 return typeof pathName === 'string'
25197 ? pathName.split('/')
25198 : [pathName];
25199 },
25200 arrayToPath: function (pathArray) {
25201 return Array.isArray(pathArray)
25202 ? pathArray.join('/')
25203 : false;
25204 },
25205 },
25206
25207 setting: function (name, value) {
25208 module.debug('Changing setting', name, value);
25209 if ($.isPlainObject(name)) {
25210 $.extend(true, settings, name);
25211 } else if (value !== undefined) {
25212 if ($.isPlainObject(settings[name])) {
25213 $.extend(true, settings[name], value);
25214 } else {
25215 settings[name] = value;
25216 }
25217 } else {
25218 return settings[name];
25219 }
25220 },
25221 internal: function (name, value) {
25222 if ($.isPlainObject(name)) {
25223 $.extend(true, module, name);
25224 } else if (value !== undefined) {
25225 module[name] = value;
25226 } else {
25227 return module[name];
25228 }
25229 },
25230 debug: function () {
25231 if (!settings.silent && settings.debug) {
25232 if (settings.performance) {
25233 module.performance.log(arguments);
25234 } else {
25235 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
25236 module.debug.apply(console, arguments);
25237 }
25238 }
25239 },
25240 verbose: function () {
25241 if (!settings.silent && settings.verbose && settings.debug) {
25242 if (settings.performance) {
25243 module.performance.log(arguments);
25244 } else {
25245 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
25246 module.verbose.apply(console, arguments);
25247 }
25248 }
25249 },
25250 error: function () {
25251 if (!settings.silent) {
25252 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
25253 module.error.apply(console, arguments);
25254 }
25255 },
25256 performance: {
25257 log: function (message) {
25258 var
25259 currentTime,
25260 executionTime,
25261 previousTime
25262 ;
25263 if (settings.performance) {
25264 currentTime = Date.now();
25265 previousTime = time || currentTime;
25266 executionTime = currentTime - previousTime;
25267 time = currentTime;
25268 performance.push({
25269 Name: message[0],
25270 Arguments: [].slice.call(message, 1) || '',
25271 Element: element,
25272 'Execution Time': executionTime,
25273 });
25274 }
25275 clearTimeout(module.performance.timer);
25276 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
25277 },
25278 display: function () {
25279 var
25280 title = settings.name + ':',
25281 totalTime = 0
25282 ;
25283 time = false;
25284 clearTimeout(module.performance.timer);
25285 $.each(performance, function (index, data) {
25286 totalTime += data['Execution Time'];
25287 });
25288 title += ' ' + totalTime + 'ms';
25289 if (performance.length > 0) {
25290 console.groupCollapsed(title);
25291 if (console.table) {
25292 console.table(performance);
25293 } else {
25294 $.each(performance, function (index, data) {
25295 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
25296 });
25297 }
25298 console.groupEnd();
25299 }
25300 performance = [];
25301 },
25302 },
25303 invoke: function (query, passedArguments, context) {
25304 var
25305 object = instance,
25306 maxDepth,
25307 found,
25308 response
25309 ;
25310 passedArguments = passedArguments || queryArguments;
25311 context = context || element;
25312 if (typeof query === 'string' && object !== undefined) {
25313 query = query.split(/[ .]/);
25314 maxDepth = query.length - 1;
25315 $.each(query, function (depth, value) {
25316 var camelCaseValue = depth !== maxDepth
25317 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
25318 : query
25319 ;
25320 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
25321 object = object[camelCaseValue];
25322 } else if (object[camelCaseValue] !== undefined) {
25323 found = object[camelCaseValue];
25324
25325 return false;
25326 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
25327 object = object[value];
25328 } else if (object[value] !== undefined) {
25329 found = object[value];
25330
25331 return false;
25332 } else {
25333 module.error(error.method, query);
25334
25335 return false;
25336 }
25337 });
25338 }
25339 if (isFunction(found)) {
25340 response = found.apply(context, passedArguments);
25341 } else if (found !== undefined) {
25342 response = found;
25343 }
25344 if (Array.isArray(returnedValue)) {
25345 returnedValue.push(response);
25346 } else if (returnedValue !== undefined) {
25347 returnedValue = [returnedValue, response];
25348 } else if (response !== undefined) {
25349 returnedValue = response;
25350 }
25351
25352 return found;
25353 },
25354 };
25355 if (methodInvoked) {
25356 if (instance === undefined) {
25357 module.initialize();
25358 }
25359 module.invoke(query);
25360 } else {
25361 if (instance !== undefined) {
25362 instance.invoke('destroy');
25363 }
25364 module.initialize();
25365 }
25366 });
25367
25368 return returnedValue !== undefined
25369 ? returnedValue
25370 : this;
25371 };
25372
25373 // shortcut for tabbed content with no defined navigation
25374 $.tab = function () {
25375 $(window).tab.apply(this, arguments);
25376 };
25377
25378 $.fn.tab.settings = {
25379
25380 name: 'Tab',
25381 namespace: 'tab',
25382
25383 silent: false,
25384 debug: false,
25385 verbose: false,
25386 performance: true,
25387
25388 auto: false, // uses pjax style endpoints fetching content from same url with remote-content headers
25389 history: false, // use browser history
25390 historyType: 'hash', // #/ or html5 state
25391 path: false, // base path of url
25392
25393 context: false, // specify a context that tabs must appear inside
25394 childrenOnly: false, // use only tabs that are children of context
25395 maxDepth: 25, // max depth a tab can be nested
25396
25397 deactivate: 'siblings', // whether tabs should deactivate sibling menu elements or all elements initialized together
25398
25399 alwaysRefresh: false, // load tab content new every tab click
25400 cache: true, // cache the content requests to pull locally
25401 loadOnce: false, // Whether tab data should only be loaded once when using remote content
25402 cacheType: 'response', // Whether to cache exact response, or to html cache contents after scripts execute
25403 ignoreFirstLoad: false, // don't load remote content on first load
25404
25405 apiSettings: false, // settings for api call
25406 evaluateScripts: 'once', // whether inline scripts should be parsed (true/false/once). Once will not re-evaluate on cached content
25407 autoTabActivation: true, // whether a non existing active tab will auto activate the first available tab
25408
25409 onFirstLoad: function (tabPath, parameterArray, historyEvent) {}, // called first time loaded
25410 onLoad: function (tabPath, parameterArray, historyEvent) {}, // called on every load
25411 onVisible: function (tabPath, parameterArray, historyEvent) {}, // called every time tab visible
25412 onRequest: function (tabPath, parameterArray, historyEvent) {}, // called ever time a tab beings loading remote content
25413 onBeforeChange: function (tabPath) {}, // called before a tab is about to be changed. Returning false will cancel the tab change
25414
25415 templates: {
25416 determineTitle: function (tabArray) {}, // returns page title for path
25417 },
25418
25419 error: {
25420 api: 'You attempted to load content without API module',
25421 method: 'The method you called is not defined',
25422 missingTab: 'Activated tab cannot be found. Tabs are case-sensitive.',
25423 noContent: 'The tab you specified is missing a content url.',
25424 path: 'History enabled, but no path was specified',
25425 recursion: 'Max recursive depth reached',
25426 state: 'History requires Asual\'s Address library <https://github.com/asual/jquery-address>',
25427 },
25428
25429 regExp: {
25430 escape: /[\s#$()*+,.:=?@[\\\]^{|}-]/g,
25431 },
25432
25433 metadata: {
25434 tab: 'tab',
25435 loaded: 'loaded',
25436 promise: 'promise',
25437 },
25438
25439 className: {
25440 loading: 'loading',
25441 active: 'active',
25442 },
25443
25444 selector: {
25445 tabs: '.ui.tab',
25446 ui: '.ui',
25447 },
25448
25449 };
25450})(jQuery, window, document);
25451
25452/*!
25453 * # Fomantic-UI 2.9.3 - Toast
25454 * https://github.com/fomantic/Fomantic-UI/
25455 *
25456 *
25457 * Released under the MIT license
25458 * https://opensource.org/licenses/MIT
25459 *
25460 */
25461
25462(function ($, window, document) {
25463 'use strict';
25464
25465 function isFunction(obj) {
25466 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
25467 }
25468
25469 window = window !== undefined && window.Math === Math
25470 ? window
25471 : globalThis;
25472
25473 $.fn.toast = function (parameters) {
25474 var
25475 $allModules = $(this),
25476 $body = $('body'),
25477
25478 time = Date.now(),
25479 performance = [],
25480
25481 query = arguments[0],
25482 methodInvoked = typeof query === 'string',
25483 queryArguments = [].slice.call(arguments, 1),
25484 contextCheck = function (context, win) {
25485 var $context;
25486 if ([window, document].indexOf(context) >= 0) {
25487 $context = $(context);
25488 } else {
25489 $context = $(win.document).find(context);
25490 if ($context.length === 0) {
25491 $context = win.frameElement ? contextCheck(context, win.parent) : $body;
25492 }
25493 }
25494
25495 return $context;
25496 },
25497 returnedValue
25498 ;
25499 $allModules.each(function () {
25500 var
25501 settings = $.isPlainObject(parameters)
25502 ? $.extend(true, {}, $.fn.toast.settings, parameters)
25503 : $.extend({}, $.fn.toast.settings),
25504
25505 className = settings.className,
25506 selector = settings.selector,
25507 error = settings.error,
25508 namespace = settings.namespace,
25509 fields = settings.fields,
25510
25511 eventNamespace = '.' + namespace,
25512 moduleNamespace = namespace + '-module',
25513
25514 $module = $(this),
25515 $toastBox,
25516 $toast,
25517 $actions,
25518 $progress,
25519 $progressBar,
25520 $animationObject,
25521 $close,
25522 $context = settings.context ? contextCheck(settings.context, window) : $body,
25523
25524 isToastComponent = $module.hasClass('toast') || $module.hasClass('message') || $module.hasClass('card'),
25525
25526 element = this,
25527 instance = isToastComponent ? $module.data(moduleNamespace) : undefined,
25528
25529 id,
25530 module
25531 ;
25532 module = {
25533
25534 initialize: function () {
25535 module.verbose('Initializing element');
25536 module.create.id();
25537 if (!module.has.container()) {
25538 module.create.container();
25539 }
25540 if (isToastComponent || settings.message !== '' || settings.title !== '' || module.get.iconClass() !== '' || settings.showImage || module.has.configActions()) {
25541 if (typeof settings.showProgress !== 'string' || [className.top, className.bottom].indexOf(settings.showProgress) === -1) {
25542 settings.showProgress = false;
25543 }
25544 module.create.toast();
25545 if (settings.closeOnClick && (settings.closeIcon || $($toast).find(selector.input).length > 0 || module.has.configActions())) {
25546 settings.closeOnClick = false;
25547 }
25548 if (!settings.closeOnClick) {
25549 $toastBox.addClass(className.unclickable);
25550 }
25551 module.bind.events();
25552 }
25553 module.instantiate();
25554 if ($toastBox) {
25555 module.show();
25556 }
25557 },
25558
25559 instantiate: function () {
25560 module.verbose('Storing instance of toast');
25561 instance = module;
25562 $module
25563 .data(moduleNamespace, instance)
25564 ;
25565 },
25566
25567 destroy: function () {
25568 if ($toastBox) {
25569 module.debug('Removing toast', $toastBox);
25570 module.unbind.events();
25571 settings.onRemove.call($toastBox, element);
25572 $toastBox.remove();
25573 $toastBox = undefined;
25574 $toast = undefined;
25575 $animationObject = undefined;
25576 $progress = undefined;
25577 $progressBar = undefined;
25578 $close = undefined;
25579 }
25580 $module
25581 .removeData(moduleNamespace)
25582 ;
25583 },
25584
25585 show: function (callback) {
25586 if (settings.onShow.call($toastBox, element) === false) {
25587 module.debug('onShow callback returned false, cancelling toast animation');
25588
25589 return;
25590 }
25591 callback = callback || function () {};
25592 module.debug('Showing toast');
25593 module.animate.show(callback);
25594 },
25595
25596 close: function (callback) {
25597 if (settings.onHide.call($toastBox, element) === false) {
25598 module.debug('onHide callback returned false, cancelling toast animation');
25599
25600 return;
25601 }
25602 callback = callback || function () {};
25603 module.debug('Closing toast');
25604 module.remove.visible();
25605 module.unbind.events();
25606 module.animate.close(callback);
25607 },
25608
25609 create: {
25610 container: function () {
25611 module.verbose('Creating container');
25612 $context.append($('<div/>', {
25613 class: settings.position + ' ' + className.container + ' '
25614 + (settings.horizontal ? className.horizontal : '') + ' '
25615 + (settings.context && settings.context !== 'body' ? className.absolute : ''),
25616 }));
25617 },
25618 id: function () {
25619 id = (Math.random().toString(16) + '000000000').slice(2, 10);
25620 module.verbose('Creating unique id for element', id);
25621 },
25622 toast: function () {
25623 $toastBox = $('<div/>', { class: className.box });
25624 var iconClass = module.get.iconClass();
25625 if (!isToastComponent) {
25626 module.verbose('Creating toast');
25627 $toast = $('<div/>', { role: 'alert' });
25628 var $content = $('<div/>', { class: className.content });
25629 if (iconClass !== '') {
25630 $toast.append($('<i/>', { class: iconClass + ' ' + className.icon }));
25631 }
25632
25633 if (settings.showImage) {
25634 $toast.append($('<img>', {
25635 class: className.image + ' ' + settings.classImage,
25636 src: settings.showImage,
25637 }));
25638 }
25639 if (settings.title !== '') {
25640 var titleId = '_' + module.get.id() + 'title';
25641 $toast.attr('aria-labelledby', titleId);
25642 $content.append($('<div/>', {
25643 class: className.title,
25644 id: titleId,
25645 html: module.helpers.escape(settings.title, settings.preserveHTML),
25646 }));
25647 }
25648 var descId = '_' + module.get.id() + 'desc';
25649 $toast.attr('aria-describedby', descId);
25650 $content.append($('<div/>', {
25651 class: className.message,
25652 id: descId,
25653 html: module.helpers.escape(settings.message, settings.preserveHTML),
25654 }));
25655
25656 $toast
25657 .addClass(settings.class + ' ' + className.toast)
25658 .append($content)
25659 ;
25660 $toast.css('opacity', String(settings.opacity));
25661 if (settings.closeIcon) {
25662 $close = $('<i/>', {
25663 class: className.close + ' ' + (typeof settings.closeIcon === 'string' ? settings.closeIcon : ''),
25664 role: 'button',
25665 tabindex: 0,
25666 'aria-label': settings.text.close,
25667 });
25668 if ($close.hasClass(className.left)) {
25669 $toast.prepend($close);
25670 } else {
25671 $toast.append($close);
25672 }
25673 }
25674 } else {
25675 $toast = settings.cloneModule ? $module.clone().removeAttr('id') : $module;
25676 $close = $toast.find('> i' + module.helpers.toClass(className.close));
25677 settings.closeIcon = $close.length > 0;
25678 if (iconClass !== '') {
25679 $toast.find(selector.icon).attr('class', iconClass + ' ' + className.icon);
25680 }
25681 if (settings.showImage) {
25682 $toast.find(selector.image).attr('src', settings.showImage);
25683 }
25684 if (settings.title !== '') {
25685 $toast.find(selector.title).html(module.helpers.escape(settings.title, settings.preserveHTML));
25686 }
25687 if (settings.message !== '') {
25688 $toast.find(selector.message).html(module.helpers.escape(settings.message, settings.preserveHTML));
25689 }
25690 }
25691 if ($toast.hasClass(className.compact)) {
25692 settings.compact = true;
25693 }
25694 if ($toast.hasClass('card')) {
25695 settings.compact = false;
25696 }
25697 $actions = $toast.find('.actions');
25698 if (module.has.configActions()) {
25699 if ($actions.length === 0) {
25700 $actions = $('<div/>', { class: className.actions + ' ' + (settings.classActions || '') }).appendTo($toast);
25701 }
25702 if ($toast.hasClass('card') && !$actions.hasClass(className.attached)) {
25703 $actions.addClass(className.extraContent);
25704 if ($actions.hasClass(className.vertical)) {
25705 $actions.removeClass(className.vertical);
25706 module.error(error.verticalCard);
25707 }
25708 }
25709 settings.actions.forEach(function (el) {
25710 var
25711 icon = el[fields.icon]
25712 ? '<i ' + (el[fields.text] ? 'aria-hidden="true"' : '')
25713 + ' class="' + module.helpers.deQuote(el[fields.icon]) + ' icon"></i>'
25714 : '',
25715 text = module.helpers.escape(el[fields.text] || '', settings.preserveHTML),
25716 cls = module.helpers.deQuote(el[fields.class] || ''),
25717 click = el[fields.click] && isFunction(el[fields.click])
25718 ? el[fields.click]
25719 : function () {}
25720 ;
25721 $actions.append($('<button/>', {
25722 html: icon + text,
25723 'aria-label': (el[fields.text] || el[fields.icon] || '').replace(/<[^>]+(>|$)/g, ''),
25724 class: className.button + ' ' + cls,
25725 on: {
25726 click: function () {
25727 var $button = $(this);
25728 if ($button.is(selector.approve) || $button.is(selector.deny) || click.call(element, $module) === false) {
25729 return;
25730 }
25731 module.close();
25732 },
25733 },
25734 }));
25735 });
25736 }
25737 if ($actions && $actions.hasClass(className.vertical)) {
25738 $toast.addClass(className.vertical);
25739 }
25740 if ($actions.length > 0 && !$actions.hasClass(className.attached)) {
25741 if ($actions && (!$actions.hasClass(className.basic) || $actions.hasClass(className.left))) {
25742 $toast.addClass(className.actions);
25743 }
25744 }
25745 if (settings.displayTime === 'auto') {
25746 settings.displayTime = Math.max(settings.minDisplayTime, ($toast.text().split(' ').length / settings.wordsPerMinute) * 60000);
25747 }
25748 $toastBox.append($toast);
25749
25750 if ($actions.length > 0 && $actions.hasClass(className.attached)) {
25751 $actions.addClass(className.buttons);
25752 $actions.detach();
25753 $toast.addClass(className.attached);
25754 if (!$actions.hasClass(className.vertical)) {
25755 if ($actions.hasClass(className.top)) {
25756 $toastBox.prepend($actions);
25757 $toast.addClass(className.bottom);
25758 } else {
25759 $toastBox.append($actions);
25760 $toast.addClass(className.top);
25761 }
25762 } else {
25763 $toast.wrap(
25764 $('<div/>', {
25765 class: className.vertical + ' '
25766 + className.attached + ' '
25767 + (settings.compact ? className.compact : ''),
25768 })
25769 );
25770 if ($actions.hasClass(className.left)) {
25771 $toast.addClass(className.left).parent().addClass(className.left).prepend($actions);
25772 } else {
25773 $toast.parent().append($actions);
25774 }
25775 }
25776 }
25777 if ($module !== $toast) {
25778 $module = $toast;
25779 element = $toast[0];
25780 }
25781 if (settings.displayTime > 0) {
25782 var progressingClass = className.progressing + ' ' + (settings.pauseOnHover ? className.pausable : '');
25783 if (settings.showProgress) {
25784 $progress = $('<div/>', {
25785 class: className.progress + ' ' + (settings.classProgress || settings.class),
25786 'data-percent': '',
25787 });
25788 if (!settings.classProgress) {
25789 if ($toast.hasClass('toast') && !$toast.hasClass(className.inverted)) {
25790 $progress.addClass(className.inverted);
25791 } else {
25792 $progress.removeClass(className.inverted);
25793 }
25794 }
25795 $progressBar = $('<div/>', { class: 'bar ' + (settings.progressUp ? 'up ' : 'down ') + progressingClass });
25796 $progress
25797 .addClass(settings.showProgress)
25798 .append($progressBar)
25799 ;
25800 if ($progress.hasClass(className.top)) {
25801 $toastBox.prepend($progress);
25802 } else {
25803 $toastBox.append($progress);
25804 }
25805 $progressBar.css('animation-duration', settings.displayTime / 1000 + 's');
25806 }
25807 $animationObject = $('<span/>', { class: 'wait ' + progressingClass });
25808 $animationObject.css('animation-duration', settings.displayTime / 1000 + 's');
25809 $animationObject.appendTo($toast);
25810 }
25811 if (settings.compact) {
25812 $toastBox.addClass(className.compact);
25813 $toast.addClass(className.compact);
25814 if ($progress) {
25815 $progress.addClass(className.compact);
25816 }
25817 }
25818 if (settings.newestOnTop) {
25819 $toastBox.prependTo(module.get.container());
25820 } else {
25821 $toastBox.appendTo(module.get.container());
25822 }
25823 },
25824 },
25825
25826 bind: {
25827 events: function () {
25828 module.debug('Binding events to toast');
25829 if (settings.closeIcon) {
25830 $close.on('click' + eventNamespace, module.event.close);
25831 }
25832 $toast.on('click' + eventNamespace, module.event.click);
25833 if ($animationObject) {
25834 $animationObject.on('animationend' + eventNamespace, module.event.close);
25835 }
25836 $toastBox
25837 .on('click' + eventNamespace, selector.approve, module.event.approve)
25838 .on('click' + eventNamespace, selector.deny, module.event.deny)
25839 ;
25840 },
25841 },
25842
25843 unbind: {
25844 events: function () {
25845 module.debug('Unbinding events to toast');
25846 if (settings.closeIcon) {
25847 $close.off('click' + eventNamespace);
25848 }
25849 $toast.off('click' + eventNamespace);
25850 if ($animationObject) {
25851 $animationObject.off('animationend' + eventNamespace);
25852 }
25853 $toastBox
25854 .off('click' + eventNamespace)
25855 ;
25856 },
25857 },
25858
25859 animate: {
25860 show: function (callback) {
25861 callback = isFunction(callback) ? callback : function () {};
25862 if (settings.transition && module.can.useElement('transition')) {
25863 module.set.visible();
25864 $toastBox
25865 .transition({
25866 animation: settings.transition.showMethod + ' in',
25867 queue: false,
25868 debug: settings.debug,
25869 verbose: settings.verbose,
25870 silent: settings.silent,
25871 duration: settings.transition.showDuration,
25872 onComplete: function () {
25873 callback.call($toastBox, element);
25874 settings.onVisible.call($toastBox, element);
25875 },
25876 })
25877 ;
25878 }
25879 },
25880 close: function (callback) {
25881 callback = isFunction(callback) ? callback : function () {};
25882 if (settings.transition && $.fn.transition !== undefined) {
25883 $toastBox
25884 .transition({
25885 animation: settings.transition.hideMethod + ' out',
25886 queue: false,
25887 duration: settings.transition.hideDuration,
25888 debug: settings.debug,
25889 verbose: settings.verbose,
25890 silent: settings.silent,
25891 interval: 50,
25892
25893 onBeforeHide: function (callback) {
25894 callback = isFunction(callback) ? callback : function () {};
25895 if (settings.transition.closeEasing !== '') {
25896 if ($toastBox) {
25897 $toastBox.css('opacity', '0');
25898 $toastBox.wrap('<div/>').parent().hide(settings.transition.closeDuration, settings.transition.closeEasing, function () {
25899 if ($toastBox) {
25900 $toastBox.parent().remove();
25901 callback.call($toastBox);
25902 }
25903 });
25904 }
25905 } else {
25906 callback.call($toastBox);
25907 }
25908 },
25909 onComplete: function () {
25910 callback.call($toastBox, element);
25911 settings.onHidden.call($toastBox, element);
25912 module.destroy();
25913 },
25914 })
25915 ;
25916 } else {
25917 module.error(error.noTransition);
25918 }
25919 },
25920 pause: function () {
25921 $animationObject.css('animationPlayState', 'paused');
25922 if ($progressBar) {
25923 $progressBar.css('animationPlayState', 'paused');
25924 }
25925 },
25926 continue: function () {
25927 $animationObject.css('animationPlayState', 'running');
25928 if ($progressBar) {
25929 $progressBar.css('animationPlayState', 'running');
25930 }
25931 },
25932 },
25933
25934 has: {
25935 container: function () {
25936 module.verbose('Determining if there is already a container');
25937
25938 return module.get.containers().length > 0;
25939 },
25940 toast: function () {
25941 return !!module.get.toast();
25942 },
25943 toasts: function () {
25944 return module.get.toasts().length > 0;
25945 },
25946 configActions: function () {
25947 return Array.isArray(settings.actions) && settings.actions.length > 0;
25948 },
25949 },
25950
25951 get: {
25952 id: function () {
25953 return id;
25954 },
25955 containers: function () {
25956 return $context.children(module.helpers.toClass(settings.position) + selector.container
25957 + (settings.horizontal
25958 ? module.helpers.toClass(className.horizontal)
25959 : ':not(' + module.helpers.toClass(className.horizontal) + ')')
25960 + (settings.context && settings.context !== 'body'
25961 ? module.helpers.toClass(className.absolute)
25962 : ':not(' + module.helpers.toClass(className.absolute) + ')'));
25963 },
25964 container: function () {
25965 return module.get.containers()[0];
25966 },
25967 toastBox: function () {
25968 return $toastBox || null;
25969 },
25970 toast: function () {
25971 return $toast || null;
25972 },
25973 toasts: function () {
25974 return $(module.get.container()).find(selector.box);
25975 },
25976 iconClass: function () {
25977 return typeof settings.showIcon === 'string'
25978 ? settings.showIcon
25979 : (settings.showIcon && settings.icons[settings.class]
25980 ? settings.icons[settings.class]
25981 : '');
25982 },
25983 remainingTime: function () {
25984 return $animationObject ? $animationObject.css('opacity') * settings.displayTime : 0;
25985 },
25986 },
25987
25988 set: {
25989 visible: function () {
25990 $toast.addClass(className.visible);
25991 },
25992 },
25993
25994 remove: {
25995 visible: function () {
25996 $toast.removeClass(className.visible);
25997 },
25998 },
25999
26000 event: {
26001 close: function () {
26002 module.close();
26003 },
26004 click: function (event) {
26005 if ($(event.target).closest(selector.clickable).length === 0) {
26006 if (settings.onClick.call($toastBox, element) === false || !settings.closeOnClick) {
26007 module.verbose('Click callback returned false or close denied by setting cancelling close');
26008
26009 return;
26010 }
26011 module.close();
26012 }
26013 },
26014 approve: function () {
26015 if (settings.onApprove.call(element, $module) === false) {
26016 module.verbose('Approve callback returned false cancelling close');
26017
26018 return;
26019 }
26020 module.close();
26021 },
26022 deny: function () {
26023 if (settings.onDeny.call(element, $module) === false) {
26024 module.verbose('Deny callback returned false cancelling close');
26025
26026 return;
26027 }
26028 module.close();
26029 },
26030 },
26031
26032 helpers: {
26033 toClass: function (selector) {
26034 var
26035 classes = selector.trim().split(/\s+/),
26036 result = ''
26037 ;
26038
26039 classes.forEach(function (element) {
26040 result += '.' + element;
26041 });
26042
26043 return result;
26044 },
26045 deQuote: function (string) {
26046 return String(string).replace(/"/g, '');
26047 },
26048 escape: function (string, preserveHTML) {
26049 if (preserveHTML) {
26050 return string;
26051 }
26052 var
26053 badChars = /["'<>`]/g,
26054 shouldEscape = /["&'<>`]/,
26055 escape = {
26056 '<': '&lt;',
26057 '>': '&gt;',
26058 '"': '&quot;',
26059 "'": '&#x27;',
26060 '`': '&#x60;',
26061 },
26062 escapedChar = function (chr) {
26063 return escape[chr];
26064 }
26065 ;
26066 if (shouldEscape.test(string)) {
26067 string = string.replace(/&(?![\d#a-z]{1,12};)/gi, '&amp;');
26068
26069 return string.replace(badChars, escapedChar);
26070 }
26071
26072 return string;
26073 },
26074 },
26075
26076 can: {
26077 useElement: function (element) {
26078 if ($.fn[element] !== undefined) {
26079 return true;
26080 }
26081 module.error(error.noElement.replace('{element}', element));
26082
26083 return false;
26084 },
26085 },
26086
26087 setting: function (name, value) {
26088 module.debug('Changing setting', name, value);
26089 if ($.isPlainObject(name)) {
26090 $.extend(true, settings, name);
26091 } else if (value !== undefined) {
26092 if ($.isPlainObject(settings[name])) {
26093 $.extend(true, settings[name], value);
26094 } else {
26095 settings[name] = value;
26096 }
26097 } else {
26098 return settings[name];
26099 }
26100 },
26101 internal: function (name, value) {
26102 if ($.isPlainObject(name)) {
26103 $.extend(true, module, name);
26104 } else if (value !== undefined) {
26105 module[name] = value;
26106 } else {
26107 return module[name];
26108 }
26109 },
26110 debug: function () {
26111 if (!settings.silent && settings.debug) {
26112 if (settings.performance) {
26113 module.performance.log(arguments);
26114 } else {
26115 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
26116 module.debug.apply(console, arguments);
26117 }
26118 }
26119 },
26120 verbose: function () {
26121 if (!settings.silent && settings.verbose && settings.debug) {
26122 if (settings.performance) {
26123 module.performance.log(arguments);
26124 } else {
26125 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
26126 module.verbose.apply(console, arguments);
26127 }
26128 }
26129 },
26130 error: function () {
26131 if (!settings.silent) {
26132 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
26133 module.error.apply(console, arguments);
26134 }
26135 },
26136 performance: {
26137 log: function (message) {
26138 var
26139 currentTime,
26140 executionTime,
26141 previousTime
26142 ;
26143 if (settings.performance) {
26144 currentTime = Date.now();
26145 previousTime = time || currentTime;
26146 executionTime = currentTime - previousTime;
26147 time = currentTime;
26148 performance.push({
26149 Name: message[0],
26150 Arguments: [].slice.call(message, 1) || '',
26151 Element: element,
26152 'Execution Time': executionTime,
26153 });
26154 }
26155 clearTimeout(module.performance.timer);
26156 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
26157 },
26158 display: function () {
26159 var
26160 title = settings.name + ':',
26161 totalTime = 0
26162 ;
26163 time = false;
26164 clearTimeout(module.performance.timer);
26165 $.each(performance, function (index, data) {
26166 totalTime += data['Execution Time'];
26167 });
26168 title += ' ' + totalTime + 'ms';
26169 if (performance.length > 0) {
26170 console.groupCollapsed(title);
26171 if (console.table) {
26172 console.table(performance);
26173 } else {
26174 $.each(performance, function (index, data) {
26175 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
26176 });
26177 }
26178 console.groupEnd();
26179 }
26180 performance = [];
26181 },
26182 },
26183 invoke: function (query, passedArguments, context) {
26184 var
26185 object = instance,
26186 maxDepth,
26187 found,
26188 response
26189 ;
26190 passedArguments = passedArguments || queryArguments;
26191 context = context || element;
26192 if (typeof query === 'string' && object !== undefined) {
26193 query = query.split(/[ .]/);
26194 maxDepth = query.length - 1;
26195 $.each(query, function (depth, value) {
26196 var camelCaseValue = depth !== maxDepth
26197 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
26198 : query
26199 ;
26200 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
26201 object = object[camelCaseValue];
26202 } else if (object[camelCaseValue] !== undefined) {
26203 found = object[camelCaseValue];
26204
26205 return false;
26206 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
26207 object = object[value];
26208 } else if (object[value] !== undefined) {
26209 found = object[value];
26210
26211 return false;
26212 } else {
26213 module.error(error.method, query);
26214
26215 return false;
26216 }
26217 });
26218 }
26219 if (isFunction(found)) {
26220 response = found.apply(context, passedArguments);
26221 } else if (found !== undefined) {
26222 response = found;
26223 }
26224 if (Array.isArray(returnedValue)) {
26225 returnedValue.push(response);
26226 } else if (returnedValue !== undefined) {
26227 returnedValue = [returnedValue, response];
26228 } else if (response !== undefined) {
26229 returnedValue = response;
26230 }
26231
26232 return found;
26233 },
26234 };
26235
26236 if (methodInvoked) {
26237 if (instance === undefined) {
26238 module.initialize();
26239 }
26240 module.invoke(query);
26241 } else {
26242 if (instance !== undefined) {
26243 instance.invoke('destroy');
26244 }
26245 module.initialize();
26246 returnedValue = $module;
26247 }
26248 });
26249
26250 return returnedValue !== undefined
26251 ? returnedValue
26252 : this;
26253 };
26254 $.toast = $.fn.toast;
26255
26256 $.fn.toast.settings = {
26257
26258 name: 'Toast',
26259 namespace: 'toast',
26260
26261 silent: false,
26262 debug: false,
26263 verbose: false,
26264 performance: true,
26265
26266 context: 'body',
26267
26268 position: 'top right',
26269 horizontal: false,
26270 class: 'neutral',
26271 classProgress: false,
26272 classActions: false,
26273 classImage: 'mini',
26274
26275 title: '',
26276 message: '',
26277 displayTime: 3000, // set to zero to require manually dismissal, otherwise hides on its own
26278 minDisplayTime: 1000, // minimum displaytime in case displayTime is set to 'auto'
26279 wordsPerMinute: 120,
26280 showIcon: false,
26281 newestOnTop: false,
26282 showProgress: false,
26283 pauseOnHover: true,
26284 progressUp: false, // if true, the bar will start at 0% and increase to 100%
26285 opacity: 1,
26286 compact: true,
26287 closeIcon: false,
26288 closeOnClick: true,
26289 cloneModule: true,
26290 actions: false,
26291 preserveHTML: true,
26292 showImage: false,
26293
26294 // transition settings
26295 transition: {
26296 showMethod: 'scale',
26297 showDuration: 500,
26298 hideMethod: 'scale',
26299 hideDuration: 500,
26300 closeEasing: 'easeOutCubic', // Set to empty string to stack the closed toast area immediately (old behaviour)
26301 closeDuration: 500,
26302 },
26303
26304 error: {
26305 method: 'The method you called is not defined.',
26306 noElement: 'This module requires ui {element}',
26307 verticalCard: 'Vertical but not attached actions are not supported for card layout',
26308 },
26309
26310 className: {
26311 container: 'ui toast-container',
26312 absolute: 'absolute',
26313 box: 'floating toast-box',
26314 progress: 'ui attached active progress',
26315 toast: 'ui toast',
26316 icon: 'centered icon',
26317 visible: 'visible',
26318 content: 'content',
26319 title: 'ui header',
26320 message: 'message',
26321 actions: 'actions',
26322 extraContent: 'extra content',
26323 button: 'ui button',
26324 buttons: 'ui buttons',
26325 close: 'close icon',
26326 image: 'ui image',
26327 vertical: 'vertical',
26328 horizontal: 'horizontal',
26329 attached: 'attached',
26330 inverted: 'inverted',
26331 compact: 'compact',
26332 pausable: 'pausable',
26333 progressing: 'progressing',
26334 top: 'top',
26335 bottom: 'bottom',
26336 left: 'left',
26337 basic: 'basic',
26338 unclickable: 'unclickable',
26339 },
26340
26341 text: {
26342 close: 'Close',
26343 },
26344
26345 icons: {
26346 info: 'info',
26347 success: 'checkmark',
26348 warning: 'warning',
26349 error: 'times',
26350 },
26351
26352 selector: {
26353 container: '.ui.toast-container',
26354 box: '.toast-box',
26355 toast: '.ui.toast',
26356 title: '.header',
26357 message: '.message:not(.ui)',
26358 image: '> img.image, > .image > img',
26359 icon: '> i.icon',
26360 input: 'input:not([type="hidden"]), textarea, select, button, .ui.button, ui.dropdown',
26361 clickable: 'a, details, .ui.accordion',
26362 approve: '.actions .positive, .actions .approve, .actions .ok',
26363 deny: '.actions .negative, .actions .deny, .actions .cancel',
26364 },
26365
26366 fields: {
26367 class: 'class',
26368 text: 'text',
26369 icon: 'icon',
26370 click: 'click',
26371 },
26372
26373 // callbacks
26374 onShow: function () {},
26375 onVisible: function () {},
26376 onClick: function () {},
26377 onHide: function () {},
26378 onHidden: function () {},
26379 onRemove: function () {},
26380 onApprove: function () {},
26381 onDeny: function () {},
26382 };
26383
26384 $.extend($.easing, {
26385 easeOutBounce: function (x) {
26386 var
26387 n1 = 7.5625,
26388 d1 = 2.75
26389 ;
26390 if (x < 1 / d1) {
26391 return n1 * x * x;
26392 }
26393 if (x < 2 / d1) {
26394 x -= 1.5 / d1;
26395
26396 return n1 * x * x + 0.75;
26397 }
26398 if (x < 2.5 / d1) {
26399 x -= 2.25 / d1;
26400
26401 return n1 * x * x + 0.9375;
26402 }
26403 x -= 2.625 / d1;
26404
26405 return n1 * x * x + 0.984375;
26406 },
26407 easeOutCubic: function (t) {
26408 return --t * t * t + 1;
26409 },
26410 });
26411})(jQuery, window, document);
26412
26413/*!
26414 * # Fomantic-UI 2.9.3 - Transition
26415 * https://github.com/fomantic/Fomantic-UI/
26416 *
26417 *
26418 * Released under the MIT license
26419 * https://opensource.org/licenses/MIT
26420 *
26421 */
26422
26423(function ($, window, document) {
26424 'use strict';
26425
26426 function isFunction(obj) {
26427 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
26428 }
26429
26430 window = window !== undefined && window.Math === Math
26431 ? window
26432 : globalThis;
26433
26434 $.fn.transition = function () {
26435 var
26436 $allModules = $(this),
26437
26438 time = Date.now(),
26439 performance = [],
26440
26441 moduleArguments = arguments,
26442 query = moduleArguments[0],
26443 queryArguments = [].slice.call(arguments, 1),
26444 methodInvoked = typeof query === 'string',
26445
26446 returnedValue
26447 ;
26448 $allModules.each(function (index) {
26449 var
26450 $module = $(this),
26451 element = this,
26452
26453 // set at run time
26454 settings,
26455 instance,
26456
26457 error,
26458 className,
26459 metadata,
26460
26461 moduleNamespace,
26462 eventNamespace,
26463 module
26464 ;
26465
26466 module = {
26467
26468 initialize: function () {
26469 // get full settings
26470 settings = module.get.settings.apply(element, moduleArguments);
26471
26472 // shorthand
26473 className = settings.className;
26474 error = settings.error;
26475 metadata = settings.metadata;
26476
26477 // define namespace
26478 eventNamespace = '.' + settings.namespace;
26479 moduleNamespace = 'module-' + settings.namespace;
26480 instance = $module.data(moduleNamespace) || module;
26481
26482 if (methodInvoked) {
26483 methodInvoked = module.invoke(query);
26484 }
26485
26486 // method not invoked, lets run an animation
26487 if (methodInvoked === false) {
26488 module.verbose('Converted arguments into settings object', settings);
26489 if (settings.interval) {
26490 module.delay(settings.interval);
26491 } else {
26492 module.animate();
26493 }
26494 module.instantiate();
26495 }
26496 },
26497
26498 instantiate: function () {
26499 module.verbose('Storing instance of module', module);
26500 instance = module;
26501 $module
26502 .data(moduleNamespace, instance)
26503 ;
26504 },
26505
26506 destroy: function () {
26507 module.verbose('Destroying previous module for', element);
26508 $module
26509 .removeData(moduleNamespace)
26510 ;
26511 },
26512
26513 refresh: function () {
26514 module.verbose('Refreshing display type on next animation');
26515 delete module.displayType;
26516 },
26517
26518 forceRepaint: function () {
26519 module.verbose('Forcing element repaint');
26520 var
26521 $parentElement = $module.parent(),
26522 $nextElement = $module.next()
26523 ;
26524 if ($nextElement.length === 0) {
26525 $module.detach().appendTo($parentElement);
26526 } else {
26527 $module.detach().insertBefore($nextElement);
26528 }
26529 },
26530
26531 repaint: function () {
26532 module.verbose('Repainting element');
26533 var
26534 fakeAssignment = element.offsetWidth
26535 ;
26536 },
26537
26538 delay: function (interval) {
26539 var
26540 direction = module.get.animationDirection(),
26541 shouldReverse,
26542 delay
26543 ;
26544 if (!direction) {
26545 direction = module.can.transition()
26546 ? module.get.direction()
26547 : 'static';
26548 }
26549 interval = interval !== undefined
26550 ? interval
26551 : settings.interval;
26552 shouldReverse = settings.reverse === 'auto' && direction === className.outward;
26553 delay = shouldReverse || settings.reverse === true
26554 ? ($allModules.length - index) * interval
26555 : index * interval;
26556 module.debug('Delaying animation by', delay);
26557 setTimeout(function () { module.animate(); }, delay);
26558 },
26559
26560 animate: function (overrideSettings) {
26561 settings = overrideSettings || settings;
26562
26563 module.debug('Preparing animation', settings.animation);
26564 if (module.is.animating()) {
26565 if (settings.queue) {
26566 if (!settings.allowRepeats && module.has.direction() && module.is.occurring() && module.queuing !== true) {
26567 module.debug('Animation is currently occurring, preventing queueing same animation', settings.animation);
26568 } else {
26569 module.queue(settings.animation);
26570 }
26571
26572 return false;
26573 }
26574 if (!settings.allowRepeats && module.is.occurring()) {
26575 module.debug('Animation is already occurring, will not execute repeated animation', settings.animation);
26576
26577 return false;
26578 }
26579
26580 module.debug('New animation started, completing previous early', settings.animation);
26581 instance.complete();
26582 }
26583 if (module.can.animate()) {
26584 module.set.animating(settings.animation);
26585 } else {
26586 module.error(error.noAnimation, settings.animation, element);
26587 }
26588 },
26589
26590 reset: function () {
26591 module.debug('Resetting animation to beginning conditions');
26592 module.remove.animationCallbacks();
26593 module.restore.conditions();
26594 module.remove.animating();
26595 },
26596
26597 queue: function (animation) {
26598 module.debug('Queueing animation of', animation);
26599 module.queuing = true;
26600 $module
26601 .one('animationend.queue' + eventNamespace, function () {
26602 module.queuing = false;
26603 module.repaint();
26604 module.animate.apply(this, settings);
26605 })
26606 ;
26607 },
26608
26609 complete: function (event) {
26610 if (event && event.target === element) {
26611 event.stopPropagation();
26612 }
26613 module.debug('Animation complete', settings.animation);
26614 module.remove.completeCallback();
26615 module.remove.failSafe();
26616 if (!module.is.looping()) {
26617 if (module.is.outward()) {
26618 module.verbose('Animation is outward, hiding element');
26619 module.restore.conditions();
26620 module.hide();
26621 } else if (module.is.inward()) {
26622 module.verbose('Animation is inward, showing element');
26623 module.restore.conditions();
26624 module.show();
26625 } else {
26626 module.verbose('Static animation completed');
26627 module.restore.conditions();
26628 settings.onComplete.call(element);
26629 }
26630 }
26631 },
26632
26633 force: {
26634 visible: function () {
26635 var
26636 style = $module.attr('style'),
26637 userStyle = module.get.userStyle(style),
26638 displayType = module.get.displayType(),
26639 overrideStyle = userStyle + 'display: ' + displayType + ' !important;',
26640 inlineDisplay = $module[0].style.display,
26641 mustStayHidden = !displayType || (inlineDisplay === 'none' && settings.skipInlineHidden) || $module[0].tagName.match(/(script|link|style)/i)
26642 ;
26643 if (mustStayHidden) {
26644 module.remove.transition();
26645
26646 return false;
26647 }
26648 module.verbose('Overriding default display to show element', displayType);
26649 $module
26650 .attr('style', overrideStyle)
26651 ;
26652
26653 return true;
26654 },
26655 hidden: function () {
26656 var
26657 style = $module.attr('style'),
26658 currentDisplay = $module.css('display'),
26659 emptyStyle = style === undefined || style === ''
26660 ;
26661 if (currentDisplay !== 'none' && !module.is.hidden()) {
26662 module.verbose('Overriding default display to hide element');
26663 $module
26664 .css('display', 'none')
26665 ;
26666 } else if (emptyStyle) {
26667 $module
26668 .removeAttr('style')
26669 ;
26670 }
26671 },
26672 },
26673
26674 has: {
26675 direction: function (animation) {
26676 var
26677 hasDirection = false
26678 ;
26679 animation = animation || settings.animation;
26680 if (typeof animation === 'string') {
26681 animation = animation.split(' ');
26682 $.each(animation, function (index, word) {
26683 if (word === className.inward || word === className.outward) {
26684 hasDirection = true;
26685 }
26686 });
26687 }
26688
26689 return hasDirection;
26690 },
26691 inlineDisplay: function () {
26692 var
26693 style = $module.attr('style') || ''
26694 ;
26695
26696 return Array.isArray(style.match(/display.*?;/, ''));
26697 },
26698 },
26699
26700 set: {
26701 animating: function (animation) {
26702 // remove previous callbacks
26703 module.remove.completeCallback();
26704
26705 // determine exact animation
26706 animation = animation || settings.animation;
26707 var animationClass = module.get.animationClass(animation);
26708
26709 // save animation class in cache to restore class names
26710 module.save.animation(animationClass);
26711
26712 if (module.force.visible()) {
26713 module.remove.hidden();
26714 module.remove.direction();
26715
26716 module.start.animation(animationClass);
26717 }
26718 },
26719 duration: function (animationName, duration) {
26720 duration = duration || settings.duration;
26721 duration = typeof duration === 'number'
26722 ? duration + 'ms'
26723 : duration;
26724 if (duration || duration === 0) {
26725 module.verbose('Setting animation duration', duration);
26726 $module
26727 .css({
26728 'animation-duration': duration,
26729 })
26730 ;
26731 }
26732 },
26733 direction: function (direction) {
26734 direction = direction || module.get.direction();
26735 if (direction === className.inward) {
26736 module.set.inward();
26737 } else {
26738 module.set.outward();
26739 }
26740 },
26741 looping: function () {
26742 module.debug('Transition set to loop');
26743 $module
26744 .addClass(className.looping)
26745 ;
26746 },
26747 hidden: function () {
26748 $module
26749 .addClass(className.transition)
26750 .addClass(className.hidden)
26751 ;
26752 },
26753 inward: function () {
26754 module.debug('Setting direction to inward');
26755 $module
26756 .removeClass(className.outward)
26757 .addClass(className.inward)
26758 ;
26759 },
26760 outward: function () {
26761 module.debug('Setting direction to outward');
26762 $module
26763 .removeClass(className.inward)
26764 .addClass(className.outward)
26765 ;
26766 },
26767 visible: function () {
26768 $module
26769 .addClass(className.transition)
26770 .addClass(className.visible)
26771 ;
26772 },
26773 },
26774
26775 start: {
26776 animation: function (animationClass) {
26777 animationClass = animationClass || module.get.animationClass();
26778 module.debug('Starting tween', animationClass);
26779 $module
26780 .addClass(animationClass)
26781 .one('animationend.complete' + eventNamespace, module.complete)
26782 ;
26783 if (settings.useFailSafe) {
26784 module.add.failSafe();
26785 }
26786 module.set.duration(settings.duration);
26787 settings.onStart.call(element);
26788 },
26789 },
26790
26791 save: {
26792 animation: function (animation) {
26793 if (!module.cache) {
26794 module.cache = {};
26795 }
26796 module.cache.animation = animation;
26797 },
26798 displayType: function (displayType) {
26799 if (displayType !== 'none') {
26800 $module.data(metadata.displayType, displayType);
26801 }
26802 },
26803 transitionExists: function (animation, exists) {
26804 $.fn.transition.exists[animation] = exists;
26805 module.verbose('Saving existence of transition', animation, exists);
26806 },
26807 },
26808
26809 restore: {
26810 conditions: function () {
26811 var
26812 animation = module.get.currentAnimation()
26813 ;
26814 if (animation) {
26815 $module
26816 .removeClass(animation)
26817 ;
26818 module.verbose('Removing animation class', module.cache);
26819 }
26820 module.remove.duration();
26821 },
26822 },
26823
26824 add: {
26825 failSafe: function () {
26826 var
26827 duration = module.get.duration()
26828 ;
26829 module.timer = setTimeout(function () {
26830 $module.triggerHandler('animationend');
26831 }, duration + settings.failSafeDelay);
26832 module.verbose('Adding fail safe timer', module.timer);
26833 },
26834 },
26835
26836 remove: {
26837 animating: function () {
26838 $module.removeClass(className.animating);
26839 },
26840 animationCallbacks: function () {
26841 module.remove.queueCallback();
26842 module.remove.completeCallback();
26843 },
26844 queueCallback: function () {
26845 $module.off('.queue' + eventNamespace);
26846 },
26847 completeCallback: function () {
26848 $module.off('.complete' + eventNamespace);
26849 },
26850 display: function () {
26851 $module.css('display', '');
26852 },
26853 direction: function () {
26854 $module
26855 .removeClass(className.inward)
26856 .removeClass(className.outward)
26857 ;
26858 },
26859 duration: function () {
26860 $module
26861 .css('animation-duration', '')
26862 ;
26863 },
26864 failSafe: function () {
26865 module.verbose('Removing fail safe timer', module.timer);
26866 if (module.timer) {
26867 clearTimeout(module.timer);
26868 }
26869 },
26870 hidden: function () {
26871 $module.removeClass(className.hidden);
26872 },
26873 visible: function () {
26874 $module.removeClass(className.visible);
26875 },
26876 looping: function () {
26877 module.debug('Transitions are no longer looping');
26878 if (module.is.looping()) {
26879 module.reset();
26880 $module
26881 .removeClass(className.looping)
26882 ;
26883 }
26884 },
26885 transition: function () {
26886 $module
26887 .removeClass(className.transition)
26888 .removeClass(className.visible)
26889 .removeClass(className.hidden)
26890 ;
26891 },
26892 },
26893 get: {
26894 settings: function (animation, duration, onComplete) {
26895 if (typeof animation === 'object') { // single settings object
26896 return $.extend(true, {}, $.fn.transition.settings, animation);
26897 }
26898 if (typeof onComplete === 'function') { // all arguments provided
26899 return $.extend({}, $.fn.transition.settings, {
26900 animation: animation,
26901 onComplete: onComplete,
26902 duration: duration,
26903 });
26904 }
26905 if (typeof duration === 'string' || typeof duration === 'number') { // only duration provided
26906 return $.extend({}, $.fn.transition.settings, {
26907 animation: animation,
26908 duration: duration,
26909 });
26910 }
26911 if (typeof duration === 'object') { // duration is actually settings object
26912 return $.extend({}, $.fn.transition.settings, duration, {
26913 animation: animation,
26914 });
26915 }
26916 if (typeof duration === 'function') { // duration is actually callback
26917 return $.extend({}, $.fn.transition.settings, {
26918 animation: animation,
26919 onComplete: duration,
26920 });
26921 }
26922
26923 // only animation provided
26924 return $.extend({}, $.fn.transition.settings, {
26925 animation: animation,
26926 });
26927 },
26928 animationClass: function (animation) {
26929 var
26930 animationClass = animation || settings.animation,
26931 directionClass = module.can.transition() && !module.has.direction()
26932 ? module.get.direction() + ' '
26933 : ''
26934 ;
26935
26936 return className.animating + ' '
26937 + className.transition + ' '
26938 + directionClass
26939 + animationClass;
26940 },
26941 currentAnimation: function () {
26942 return module.cache && module.cache.animation !== undefined
26943 ? module.cache.animation
26944 : false;
26945 },
26946 currentDirection: function () {
26947 return module.is.inward()
26948 ? className.inward
26949 : className.outward;
26950 },
26951 direction: function () {
26952 return module.is.hidden() || !module.is.visible()
26953 ? className.inward
26954 : className.outward;
26955 },
26956 animationDirection: function (animation) {
26957 var
26958 direction
26959 ;
26960 animation = animation || settings.animation;
26961 if (typeof animation === 'string') {
26962 animation = animation.split(' ');
26963 // search animation name for out/in class
26964 $.each(animation, function (index, word) {
26965 if (word === className.inward) {
26966 direction = className.inward;
26967 } else if (word === className.outward) {
26968 direction = className.outward;
26969 }
26970 });
26971 }
26972 // return found direction
26973 if (direction) {
26974 return direction;
26975 }
26976
26977 return false;
26978 },
26979 duration: function (duration) {
26980 duration = duration || settings.duration;
26981 if (duration === false) {
26982 duration = $module.css('animation-duration') || 0;
26983 }
26984
26985 return typeof duration === 'string'
26986 ? (duration.indexOf('ms') > -1
26987 ? parseFloat(duration)
26988 : parseFloat(duration) * 1000)
26989 : duration;
26990 },
26991 displayType: function (shouldDetermine) {
26992 shouldDetermine = shouldDetermine !== undefined
26993 ? shouldDetermine
26994 : true;
26995 if (settings.displayType) {
26996 return settings.displayType;
26997 }
26998 if (shouldDetermine && $module.data(metadata.displayType) === undefined) {
26999 var currentDisplay = $module.css('display');
27000 if (currentDisplay === '' || currentDisplay === 'none') {
27001 // create fake element to determine display state
27002 module.can.transition(true);
27003 } else {
27004 module.save.displayType(currentDisplay);
27005 }
27006 }
27007
27008 return $module.data(metadata.displayType);
27009 },
27010 userStyle: function (style) {
27011 style = style || $module.attr('style') || '';
27012
27013 return style.replace(/display.*?;/, '');
27014 },
27015 transitionExists: function (animation) {
27016 return $.fn.transition.exists[animation];
27017 },
27018 },
27019
27020 can: {
27021 transition: function (forced) {
27022 var
27023 animation = settings.animation,
27024 transitionExists = module.get.transitionExists(animation),
27025 displayType = module.get.displayType(false),
27026 elementClass,
27027 tagName,
27028 $clone,
27029 currentAnimation,
27030 inAnimation,
27031 directionExists
27032 ;
27033 if (transitionExists === undefined || forced) {
27034 module.verbose('Determining whether animation exists');
27035 elementClass = $module.attr('class');
27036 tagName = $module.prop('tagName');
27037
27038 $clone = $('<' + tagName + ' />').addClass(elementClass).insertAfter($module);
27039 currentAnimation = $clone
27040 .addClass(animation)
27041 .removeClass(className.inward)
27042 .removeClass(className.outward)
27043 .addClass(className.animating)
27044 .addClass(className.transition)
27045 .css('animationName')
27046 ;
27047 $clone.detach().insertAfter($module);
27048 inAnimation = $clone
27049 .addClass(className.inward)
27050 .css('animationName')
27051 ;
27052 if (!displayType) {
27053 $clone.detach().insertAfter($module);
27054 displayType = $clone
27055 .attr('class', elementClass)
27056 .removeAttr('style')
27057 .removeClass(className.hidden)
27058 .removeClass(className.visible)
27059 .show()
27060 .css('display')
27061 ;
27062 module.verbose('Determining final display state', displayType);
27063 module.save.displayType(displayType);
27064 }
27065
27066 $clone.remove();
27067 if (currentAnimation !== inAnimation) {
27068 module.debug('Direction exists for animation', animation);
27069 directionExists = true;
27070 } else if (currentAnimation === 'none' || !currentAnimation) {
27071 module.debug('No animation defined in css', animation);
27072
27073 return;
27074 } else {
27075 module.debug('Static animation found', animation, displayType);
27076 directionExists = false;
27077 }
27078 module.save.transitionExists(animation, directionExists);
27079 }
27080
27081 return transitionExists !== undefined
27082 ? transitionExists
27083 : directionExists;
27084 },
27085 animate: function () {
27086 // can transition does not return a value if animation does not exist
27087 return module.can.transition() !== undefined;
27088 },
27089 },
27090
27091 is: {
27092 animating: function () {
27093 return $module.hasClass(className.animating);
27094 },
27095 inward: function () {
27096 return $module.hasClass(className.inward);
27097 },
27098 outward: function () {
27099 return $module.hasClass(className.outward);
27100 },
27101 looping: function () {
27102 return $module.hasClass(className.looping);
27103 },
27104 occurring: function (animation) {
27105 animation = animation || settings.animation;
27106 animation = '.' + animation.replace(' ', '.');
27107
27108 return $module.filter(animation).length > 0;
27109 },
27110 visible: function () {
27111 return $module.is(':visible');
27112 },
27113 hidden: function () {
27114 return $module.css('visibility') === 'hidden';
27115 },
27116 supported: function () {
27117 // keep method for backward compatibility until 2.10.0
27118 return true;
27119 },
27120 },
27121
27122 hide: function () {
27123 if (settings.onHide.call(element) === false) {
27124 module.verbose('Hide callback returned false cancelling hide');
27125
27126 return false;
27127 }
27128 module.verbose('Hiding element');
27129 if (module.is.animating()) {
27130 module.reset();
27131 }
27132 element.blur(); // IE will trigger focus change if element is not blurred before hiding
27133 module.remove.display();
27134 module.remove.visible();
27135 settings.onBeforeHide.call(element, module.hideNow);
27136 },
27137
27138 hideNow: function () {
27139 module.set.hidden();
27140 module.force.hidden();
27141 settings.onHidden.call(element);
27142 settings.onComplete.call(element);
27143 },
27144
27145 show: function (display) {
27146 if (module.force.visible() && settings.onShow.call(element) !== false) {
27147 module.verbose('Showing element', display);
27148 module.remove.hidden();
27149 settings.onBeforeShow.call(element, module.showNow);
27150 }
27151 },
27152
27153 showNow: function () {
27154 module.set.visible();
27155 settings.onVisible.call(element);
27156 settings.onComplete.call(element);
27157 },
27158
27159 toggle: function () {
27160 if (module.is.visible()) {
27161 module.hide();
27162 } else {
27163 module.show();
27164 }
27165 },
27166
27167 stop: function () {
27168 module.debug('Stopping current animation');
27169 $module.triggerHandler('animationend');
27170 },
27171
27172 stopAll: function () {
27173 module.debug('Stopping all animation');
27174 module.remove.queueCallback();
27175 $module.triggerHandler('animationend');
27176 },
27177
27178 clear: {
27179 queue: function () {
27180 module.debug('Clearing animation queue');
27181 module.remove.queueCallback();
27182 },
27183 },
27184
27185 enable: function () {
27186 module.verbose('Starting animation');
27187 $module.removeClass(className.disabled);
27188 },
27189
27190 disable: function () {
27191 module.debug('Stopping animation');
27192 $module.addClass(className.disabled);
27193 },
27194
27195 setting: function (name, value) {
27196 module.debug('Changing setting', name, value);
27197 if ($.isPlainObject(name)) {
27198 $.extend(true, settings, name);
27199 } else if (value !== undefined) {
27200 if ($.isPlainObject(settings[name])) {
27201 $.extend(true, settings[name], value);
27202 } else {
27203 settings[name] = value;
27204 }
27205 } else {
27206 return settings[name];
27207 }
27208 },
27209 internal: function (name, value) {
27210 if ($.isPlainObject(name)) {
27211 $.extend(true, module, name);
27212 } else if (value !== undefined) {
27213 module[name] = value;
27214 } else {
27215 return module[name];
27216 }
27217 },
27218 debug: function () {
27219 if (!settings.silent && settings.debug) {
27220 if (settings.performance) {
27221 module.performance.log(arguments);
27222 } else {
27223 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
27224 module.debug.apply(console, arguments);
27225 }
27226 }
27227 },
27228 verbose: function () {
27229 if (!settings.silent && settings.verbose && settings.debug) {
27230 if (settings.performance) {
27231 module.performance.log(arguments);
27232 } else {
27233 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
27234 module.verbose.apply(console, arguments);
27235 }
27236 }
27237 },
27238 error: function () {
27239 if (!settings.silent) {
27240 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
27241 module.error.apply(console, arguments);
27242 }
27243 },
27244 performance: {
27245 log: function (message) {
27246 var
27247 currentTime,
27248 executionTime,
27249 previousTime
27250 ;
27251 if (settings.performance) {
27252 currentTime = Date.now();
27253 previousTime = time || currentTime;
27254 executionTime = currentTime - previousTime;
27255 time = currentTime;
27256 performance.push({
27257 Name: message[0],
27258 Arguments: [].slice.call(message, 1) || '',
27259 Element: element,
27260 'Execution Time': executionTime,
27261 });
27262 }
27263 clearTimeout(module.performance.timer);
27264 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
27265 },
27266 display: function () {
27267 var
27268 title = settings.name + ':',
27269 totalTime = 0
27270 ;
27271 time = false;
27272 clearTimeout(module.performance.timer);
27273 $.each(performance, function (index, data) {
27274 totalTime += data['Execution Time'];
27275 });
27276 title += ' ' + totalTime + 'ms';
27277 if ($allModules.length > 1) {
27278 title += ' (' + $allModules.length + ')';
27279 }
27280 if (performance.length > 0) {
27281 console.groupCollapsed(title);
27282 if (console.table) {
27283 console.table(performance);
27284 } else {
27285 $.each(performance, function (index, data) {
27286 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
27287 });
27288 }
27289 console.groupEnd();
27290 }
27291 performance = [];
27292 },
27293 },
27294 // modified for transition to return invoke success
27295 invoke: function (query, passedArguments, context) {
27296 var
27297 object = instance,
27298 maxDepth,
27299 found,
27300 response
27301 ;
27302 passedArguments = passedArguments || queryArguments;
27303 context = context || element;
27304 if (typeof query === 'string' && object !== undefined) {
27305 query = query.split(/[ .]/);
27306 maxDepth = query.length - 1;
27307 $.each(query, function (depth, value) {
27308 var camelCaseValue = depth !== maxDepth
27309 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
27310 : query;
27311 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
27312 object = object[camelCaseValue];
27313 } else if (object[camelCaseValue] !== undefined) {
27314 found = object[camelCaseValue];
27315
27316 return false;
27317 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
27318 object = object[value];
27319 } else if (object[value] !== undefined) {
27320 found = object[value];
27321
27322 return false;
27323 } else {
27324 return false;
27325 }
27326 });
27327 }
27328 if (isFunction(found)) {
27329 response = found.apply(context, passedArguments);
27330 } else if (found !== undefined) {
27331 response = found;
27332 }
27333
27334 if (Array.isArray(returnedValue)) {
27335 returnedValue.push(response);
27336 } else if (returnedValue !== undefined) {
27337 returnedValue = [returnedValue, response];
27338 } else if (response !== undefined) {
27339 returnedValue = response;
27340 }
27341
27342 return found !== undefined
27343 ? found
27344 : false;
27345 },
27346 };
27347 module.initialize();
27348 });
27349
27350 return returnedValue !== undefined
27351 ? returnedValue
27352 : this;
27353 };
27354
27355 // Records if CSS transition is available
27356 $.fn.transition.exists = {};
27357
27358 $.fn.transition.settings = {
27359
27360 // module info
27361 name: 'Transition',
27362
27363 // hide all output from this component regardless of other settings
27364 silent: false,
27365
27366 // debug content outputted to console
27367 debug: false,
27368
27369 // verbose debug output
27370 verbose: false,
27371
27372 // performance data output
27373 performance: true,
27374
27375 // event namespace
27376 namespace: 'transition',
27377
27378 // delay between animations in group
27379 interval: 0,
27380
27381 // whether group animations should be reversed
27382 reverse: 'auto',
27383
27384 // animation callback event
27385 onStart: function () {},
27386 onComplete: function () {},
27387 onShow: function () {},
27388 onBeforeShow: function (callback) {
27389 callback.call(this);
27390 },
27391 onVisible: function () {},
27392 onHide: function () {},
27393 onHidden: function () {},
27394 onBeforeHide: function (callback) {
27395 callback.call(this);
27396 },
27397
27398 // whether timeout should be used to ensure callback fires in cases animationend does not
27399 useFailSafe: true,
27400
27401 // delay in ms for fail safe
27402 failSafeDelay: 100,
27403
27404 // whether EXACT animation can occur twice in a row
27405 allowRepeats: false,
27406
27407 // Override final display type on visible
27408 displayType: false,
27409
27410 // animation duration
27411 animation: 'fade',
27412 duration: false,
27413
27414 // new animations will occur after previous ones
27415 queue: true,
27416
27417 // whether initially inline hidden objects should be skipped for transition
27418 skipInlineHidden: false,
27419
27420 metadata: {
27421 displayType: 'display',
27422 },
27423
27424 className: {
27425 animating: 'animating',
27426 disabled: 'disabled',
27427 hidden: 'hidden',
27428 inward: 'in',
27429 loading: 'loading',
27430 looping: 'looping',
27431 outward: 'out',
27432 transition: 'transition',
27433 visible: 'visible',
27434 },
27435
27436 // possible errors
27437 error: {
27438 noAnimation: 'Element is no longer attached to DOM. Unable to animate. Use silent setting to suppress this warning in production.',
27439 },
27440
27441 };
27442})(jQuery, window, document);
27443
27444/*!
27445 * # Fomantic-UI 2.9.3 - API
27446 * https://github.com/fomantic/Fomantic-UI/
27447 *
27448 *
27449 * Released under the MIT license
27450 * https://opensource.org/licenses/MIT
27451 *
27452 */
27453
27454(function ($, window, document) {
27455 'use strict';
27456
27457 function isWindow(obj) {
27458 return obj !== null && obj === obj.window;
27459 }
27460
27461 function isFunction(obj) {
27462 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
27463 }
27464
27465 window = window !== undefined && window.Math === Math
27466 ? window
27467 : globalThis;
27468
27469 $.fn.api = function (parameters) {
27470 var
27471 // use window context if none specified
27472 $allModules = isFunction(this)
27473 ? $(window)
27474 : $(this),
27475 time = Date.now(),
27476 performance = [],
27477
27478 query = arguments[0],
27479 methodInvoked = typeof query === 'string',
27480 queryArguments = [].slice.call(arguments, 1),
27481 contextCheck = function (context, win) {
27482 var $context;
27483 if ([window, document].indexOf(context) >= 0) {
27484 $context = $(context);
27485 } else {
27486 $context = $(win.document).find(context);
27487 if ($context.length === 0) {
27488 $context = win.frameElement ? contextCheck(context, win.parent) : window;
27489 }
27490 }
27491
27492 return $context;
27493 },
27494 returnedValue
27495 ;
27496
27497 $allModules.each(function () {
27498 var
27499 settings = $.isPlainObject(parameters)
27500 ? $.extend(true, {}, $.fn.api.settings, parameters)
27501 : $.extend({}, $.fn.api.settings),
27502
27503 // internal aliases
27504 regExp = settings.regExp,
27505 namespace = settings.namespace,
27506 metadata = settings.metadata,
27507 selector = settings.selector,
27508 error = settings.error,
27509 className = settings.className,
27510
27511 // define namespaces for modules
27512 eventNamespace = '.' + namespace,
27513 moduleNamespace = 'module-' + namespace,
27514
27515 // element that creates request
27516 $module = $(this),
27517 $form = $module.closest(selector.form),
27518
27519 // context used for state
27520 $context = settings.stateContext ? contextCheck(settings.stateContext, window) : $module,
27521
27522 // request details
27523 ajaxSettings,
27524 requestSettings,
27525 url,
27526 data,
27527 requestStartTime,
27528 originalData,
27529
27530 // standard module
27531 element = this,
27532 context = $context[0],
27533 instance = $module.data(moduleNamespace),
27534 module
27535 ;
27536
27537 module = {
27538
27539 initialize: function () {
27540 if (!methodInvoked) {
27541 originalData = settings.data;
27542 module.bind.events();
27543 }
27544 module.instantiate();
27545 },
27546
27547 instantiate: function () {
27548 module.verbose('Storing instance of module', module);
27549 instance = module;
27550 $module
27551 .data(moduleNamespace, instance)
27552 ;
27553 },
27554
27555 destroy: function () {
27556 module.verbose('Destroying previous module for', element);
27557 $module
27558 .removeData(moduleNamespace)
27559 .off(eventNamespace)
27560 ;
27561 },
27562
27563 bind: {
27564 events: function () {
27565 var
27566 triggerEvent = module.get.event()
27567 ;
27568 if (triggerEvent) {
27569 module.verbose('Attaching API events to element', triggerEvent);
27570 $module
27571 .on(triggerEvent + eventNamespace, module.event.trigger)
27572 ;
27573 } else if (settings.on === 'now') {
27574 module.debug('Querying API endpoint immediately');
27575 module.query();
27576 }
27577 },
27578 },
27579
27580 decode: {
27581 json: function (response) {
27582 if (response !== undefined && typeof response === 'string') {
27583 try {
27584 response = JSON.parse(response);
27585 } catch (e) {
27586 // isn't json string
27587 }
27588 }
27589
27590 return response;
27591 },
27592 },
27593
27594 read: {
27595 cachedResponse: function (url) {
27596 var
27597 response
27598 ;
27599 if (window.Storage === undefined) {
27600 module.error(error.noStorage);
27601
27602 return;
27603 }
27604 response = sessionStorage.getItem(url + module.get.normalizedData());
27605 module.debug('Using cached response', url, settings.data, response);
27606 response = module.decode.json(response);
27607
27608 return response;
27609 },
27610 },
27611 write: {
27612 cachedResponse: function (url, response) {
27613 if (window.Storage === undefined) {
27614 module.error(error.noStorage);
27615
27616 return;
27617 }
27618 if ($.isPlainObject(response)) {
27619 response = JSON.stringify(response);
27620 }
27621 sessionStorage.setItem(url + module.get.normalizedData(), response);
27622 module.verbose('Storing cached response for url', url, settings.data, response);
27623 },
27624 },
27625
27626 query: function () {
27627 if (module.is.disabled()) {
27628 module.debug('Element is disabled API request aborted');
27629
27630 return;
27631 }
27632
27633 if (module.is.loading()) {
27634 if (settings.interruptRequests) {
27635 module.debug('Interrupting previous request');
27636 module.abort();
27637 } else {
27638 module.debug('Cancelling request, previous request is still pending');
27639
27640 return;
27641 }
27642 }
27643
27644 // pass element metadata to url (value, text)
27645 if (settings.defaultData) {
27646 $.extend(true, settings.urlData, module.get.defaultData());
27647 }
27648
27649 // Add form content
27650 if (settings.serializeForm) {
27651 settings.data = module.add.formData(originalData || settings.data);
27652 }
27653
27654 // call beforesend and get any settings changes
27655 requestSettings = module.get.settings();
27656
27657 // check if before send cancelled request
27658 if (requestSettings === false) {
27659 module.cancelled = true;
27660 module.error(error.beforeSend);
27661
27662 return;
27663 }
27664
27665 module.cancelled = false;
27666
27667 // get url
27668 url = module.get.templatedURL();
27669
27670 if (!url && !module.is.mocked()) {
27671 module.error(error.missingURL);
27672
27673 return;
27674 }
27675
27676 // replace variables
27677 url = module.add.urlData(url);
27678 // missing url parameters
27679 if (!url && !module.is.mocked()) {
27680 return;
27681 }
27682
27683 requestSettings.url = settings.base + url;
27684
27685 // look for jQuery ajax parameters in settings
27686 ajaxSettings = $.extend(true, {}, settings, {
27687 type: settings.method || settings.type,
27688 data: data,
27689 url: settings.base + url,
27690 beforeSend: settings.beforeXHR,
27691 success: function () {},
27692 failure: function () {},
27693 complete: function () {},
27694 });
27695
27696 module.debug('Querying URL', ajaxSettings.url);
27697 module.verbose('Using AJAX settings', ajaxSettings);
27698 if (settings.cache === 'local' && module.read.cachedResponse(url)) {
27699 module.debug('Response returned from local cache');
27700 module.request = module.create.request();
27701 module.request.resolveWith(context, [module.read.cachedResponse(url)]);
27702
27703 return;
27704 }
27705
27706 if (!settings.throttle) {
27707 module.debug('Sending request', data, ajaxSettings.method);
27708 module.send.request();
27709 } else {
27710 if (!settings.throttleFirstRequest && !module.timer) {
27711 module.debug('Sending request', data, ajaxSettings.method);
27712 module.send.request();
27713 module.timer = setTimeout(function () {}, settings.throttle);
27714 } else {
27715 module.debug('Throttling request', settings.throttle);
27716 clearTimeout(module.timer);
27717 module.timer = setTimeout(function () {
27718 if (module.timer) {
27719 delete module.timer;
27720 }
27721 module.debug('Sending throttled request', data, ajaxSettings.method);
27722 module.send.request();
27723 }, settings.throttle);
27724 }
27725 }
27726 },
27727
27728 should: {
27729 removeError: function () {
27730 return settings.hideError === true || (settings.hideError === 'auto' && !module.is.form());
27731 },
27732 },
27733
27734 is: {
27735 disabled: function () {
27736 return $module.filter(selector.disabled).length > 0;
27737 },
27738 expectingJSON: function () {
27739 return settings.dataType === 'json' || settings.dataType === 'jsonp';
27740 },
27741 form: function () {
27742 return $module.is('form') || $context.is('form');
27743 },
27744 mocked: function () {
27745 return settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync;
27746 },
27747 input: function () {
27748 return $module.is('input');
27749 },
27750 loading: function () {
27751 return module.request
27752 ? module.request.state() === 'pending'
27753 : false;
27754 },
27755 abortedRequest: function (xhr) {
27756 if (xhr && xhr.readyState !== undefined && xhr.readyState === 0) {
27757 module.verbose('XHR request determined to be aborted');
27758
27759 return true;
27760 }
27761
27762 module.verbose('XHR request was not aborted');
27763
27764 return false;
27765 },
27766 validResponse: function (response) {
27767 if (!module.is.expectingJSON() || !isFunction(settings.successTest)) {
27768 module.verbose('Response is not JSON, skipping validation', settings.successTest, response);
27769
27770 return true;
27771 }
27772 module.debug('Checking JSON returned success', settings.successTest, response);
27773 if (settings.successTest(response)) {
27774 module.debug('Response passed success test', response);
27775
27776 return true;
27777 }
27778
27779 module.debug('Response failed success test', response);
27780
27781 return false;
27782 },
27783 },
27784
27785 was: {
27786 cancelled: function () {
27787 return module.cancelled || false;
27788 },
27789 successful: function () {
27790 return module.request && module.request.state() === 'resolved';
27791 },
27792 failure: function () {
27793 return module.request && module.request.state() === 'rejected';
27794 },
27795 complete: function () {
27796 return module.request && (module.request.state() === 'resolved' || module.request.state() === 'rejected');
27797 },
27798 },
27799
27800 add: {
27801 urlData: function (url, urlData) {
27802 var
27803 requiredVariables,
27804 optionalVariables
27805 ;
27806 if (url) {
27807 requiredVariables = url.match(regExp.required);
27808 optionalVariables = url.match(regExp.optional);
27809 urlData = urlData || settings.urlData;
27810 if (requiredVariables) {
27811 module.debug('Looking for required URL variables', requiredVariables);
27812 $.each(requiredVariables, function (index, templatedString) {
27813 var
27814 // allow legacy {$var} style
27815 variable = templatedString.indexOf('$') !== -1
27816 ? templatedString.slice(2, -1)
27817 : templatedString.slice(1, -1),
27818 value = $.isPlainObject(urlData) && urlData[variable] !== undefined
27819 ? urlData[variable]
27820 : ($module.data(variable) !== undefined
27821 ? $module.data(variable)
27822 : ($context.data(variable) !== undefined // eslint-disable-line unicorn/no-nested-ternary
27823 ? $context.data(variable)
27824 : urlData[variable]))
27825 ;
27826 // remove value
27827 if (value === undefined) {
27828 module.error(error.requiredParameter, variable, url);
27829 url = false;
27830
27831 return false;
27832 }
27833
27834 module.verbose('Found required variable', variable, value);
27835 value = settings.encodeParameters
27836 ? module.get.urlEncodedValue(value)
27837 : value;
27838 url = url.replace(templatedString, value);
27839 });
27840 }
27841 if (optionalVariables) {
27842 module.debug('Looking for optional URL variables', requiredVariables);
27843 $.each(optionalVariables, function (index, templatedString) {
27844 var
27845 // allow legacy {/$var} style
27846 variable = templatedString.indexOf('$') !== -1
27847 ? templatedString.slice(3, -1)
27848 : templatedString.slice(2, -1),
27849 value = $.isPlainObject(urlData) && urlData[variable] !== undefined
27850 ? urlData[variable]
27851 : ($module.data(variable) !== undefined
27852 ? $module.data(variable)
27853 : ($context.data(variable) !== undefined // eslint-disable-line unicorn/no-nested-ternary
27854 ? $context.data(variable)
27855 : urlData[variable]))
27856 ;
27857 // optional replacement
27858 if (value !== undefined) {
27859 module.verbose('Optional variable Found', variable, value);
27860 url = url.replace(templatedString, value);
27861 } else {
27862 module.verbose('Optional variable not found', variable);
27863 // remove preceding slash if set
27864 url = url.indexOf('/' + templatedString) !== -1
27865 ? url.replace('/' + templatedString, '')
27866 : url.replace(templatedString, '');
27867 }
27868 });
27869 }
27870 }
27871
27872 return url;
27873 },
27874 formData: function (data) {
27875 var
27876 formData = {},
27877 hasOtherData,
27878 useFormDataApi = settings.serializeForm === 'formdata'
27879 ;
27880 data = data || originalData || settings.data;
27881 hasOtherData = $.isPlainObject(data);
27882
27883 if (useFormDataApi) {
27884 formData = new FormData($form[0]);
27885 settings.processData = settings.processData !== undefined ? settings.processData : false;
27886 settings.contentType = settings.contentType !== undefined ? settings.contentType : false;
27887 } else {
27888 var
27889 formArray = $form.serializeArray(),
27890 pushes = {},
27891 pushValues = {},
27892 build = function (base, key, value) {
27893 base[key] = value;
27894
27895 return base;
27896 }
27897 ;
27898 // add files
27899 $.each($('input[type="file"]', $form), function (i, tag) {
27900 $.each($(tag)[0].files, function (j, file) {
27901 formArray.push({ name: tag.name, value: file });
27902 });
27903 });
27904 $.each(formArray, function (i, el) {
27905 if (!regExp.validate.test(el.name)) {
27906 return;
27907 }
27908 var
27909 isCheckbox = $('[name="' + el.name + '"]', $form).attr('type') === 'checkbox',
27910 floatValue = parseFloat(el.value),
27911 value = (isCheckbox && el.value === 'on')
27912 || el.value === 'true'
27913 || (String(floatValue) === el.value
27914 ? floatValue
27915 : (el.value === 'false' ? false : el.value)),
27916 nameKeys = el.name.match(regExp.key) || [],
27917 pushKey = el.name.replace(/\[]$/, '')
27918 ;
27919 if (!(pushKey in pushes)) {
27920 pushes[pushKey] = 0;
27921 pushValues[pushKey] = value;
27922 } else if (Array.isArray(pushValues[pushKey])) {
27923 pushValues[pushKey].push(value);
27924 } else {
27925 pushValues[pushKey] = [pushValues[pushKey], value];
27926 }
27927 if (pushKey.indexOf('[]') === -1) {
27928 value = pushValues[pushKey];
27929 }
27930
27931 while (nameKeys.length > 0) {
27932 var k = nameKeys.pop();
27933
27934 if (k === '' && !Array.isArray(value)) { // foo[]
27935 value = build([], pushes[pushKey]++, value);
27936 } else if (regExp.fixed.test(k)) { // foo[n]
27937 value = build([], k, value);
27938 } else if (regExp.named.test(k)) { // foo; foo[bar]
27939 value = build({}, k, value);
27940 }
27941 }
27942 formData = $.extend(true, formData, value);
27943 });
27944 }
27945
27946 if (hasOtherData) {
27947 module.debug('Extending existing data with form data', data, formData);
27948 if (useFormDataApi) {
27949 $.each(Object.keys(data), function (i, el) {
27950 formData.append(el, data[el]);
27951 });
27952 data = formData;
27953 } else {
27954 data = $.extend(true, {}, data, formData);
27955 }
27956 } else {
27957 module.debug('Adding form data', formData);
27958 data = formData;
27959 }
27960
27961 return data;
27962 },
27963 },
27964
27965 send: {
27966 request: function () {
27967 module.set.loading();
27968 module.request = module.create.request();
27969 if (module.is.mocked()) {
27970 module.mockedXHR = module.create.mockedXHR();
27971 } else {
27972 module.xhr = module.create.xhr();
27973 }
27974 settings.onRequest.call(context, module.request, module.xhr);
27975 },
27976 },
27977
27978 event: {
27979 trigger: function (event) {
27980 module.query();
27981 if (event.type === 'submit' || event.type === 'click') {
27982 event.preventDefault();
27983 }
27984 },
27985 xhr: {
27986 always: function () {
27987 // nothing special
27988 },
27989 done: function (response, textStatus, xhr) {
27990 var
27991 context = this,
27992 elapsedTime = Date.now() - requestStartTime,
27993 timeLeft = settings.loadingDuration - elapsedTime,
27994 translatedResponse = isFunction(settings.onResponse)
27995 ? (module.is.expectingJSON() && !settings.rawResponse
27996 ? settings.onResponse.call(context, $.extend(true, {}, response))
27997 : settings.onResponse.call(context, response))
27998 : false
27999 ;
28000 timeLeft = timeLeft > 0
28001 ? timeLeft
28002 : 0;
28003 if (translatedResponse) {
28004 module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response);
28005 response = translatedResponse;
28006 }
28007 if (timeLeft > 0) {
28008 module.debug('Response completed early delaying state change by', timeLeft);
28009 }
28010 setTimeout(function () {
28011 if (module.is.validResponse(response)) {
28012 module.request.resolveWith(context, [response, xhr]);
28013 } else {
28014 module.request.rejectWith(context, [xhr, 'invalid']);
28015 }
28016 }, timeLeft);
28017 },
28018 fail: function (xhr, status, httpMessage) {
28019 var
28020 context = this,
28021 elapsedTime = Date.now() - requestStartTime,
28022 timeLeft = settings.loadingDuration - elapsedTime
28023 ;
28024 timeLeft = timeLeft > 0
28025 ? timeLeft
28026 : 0;
28027 if (timeLeft > 0) {
28028 module.debug('Response completed early delaying state change by', timeLeft);
28029 }
28030 setTimeout(function () {
28031 if (module.is.abortedRequest(xhr)) {
28032 module.request.rejectWith(context, [xhr, 'aborted', httpMessage]);
28033 } else {
28034 module.request.rejectWith(context, [xhr, 'error', status, httpMessage]);
28035 }
28036 }, timeLeft);
28037 },
28038 },
28039 request: {
28040 done: function (response, xhr) {
28041 module.debug('Successful API Response', response);
28042 if (settings.cache === 'local' && url) {
28043 module.write.cachedResponse(url, response);
28044 module.debug('Saving server response locally', module.cache);
28045 }
28046 settings.onSuccess.call(context, response, $module, xhr);
28047 },
28048 complete: function (firstParameter, secondParameter) {
28049 var
28050 xhr,
28051 response
28052 ;
28053 // have to guess callback parameters based on request success
28054 if (module.was.successful()) {
28055 response = firstParameter;
28056 xhr = secondParameter;
28057 } else {
28058 xhr = firstParameter;
28059 response = module.get.responseFromXHR(xhr);
28060 }
28061 module.remove.loading();
28062 settings.onComplete.call(context, response, $module, xhr);
28063 },
28064 fail: function (xhr, status, httpMessage) {
28065 var
28066 // pull response from xhr if available
28067 response = module.get.responseFromXHR(xhr),
28068 errorMessage = module.get.errorFromRequest(response, status, httpMessage)
28069 ;
28070 if (status === 'aborted') {
28071 module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage);
28072 settings.onAbort.call(context, status, $module, xhr);
28073
28074 return true;
28075 }
28076 if (status === 'invalid') {
28077 module.debug('JSON did not pass success test. A server-side error has most likely occurred', response);
28078 } else if (status === 'error') {
28079 if (xhr !== undefined) {
28080 module.debug('XHR produced a server error', status, httpMessage);
28081 // make sure we have an error to display to console
28082 if ((xhr.status < 200 || xhr.status >= 300) && httpMessage !== undefined && httpMessage !== '') {
28083 module.error(error.statusMessage + httpMessage, ajaxSettings.url);
28084 }
28085 settings.onError.call(context, errorMessage, $module, xhr);
28086 }
28087 }
28088
28089 if (settings.errorDuration && status !== 'aborted') {
28090 module.debug('Adding error state');
28091 module.set.error();
28092 if (module.should.removeError()) {
28093 setTimeout(function () { module.remove.error(); }, settings.errorDuration);
28094 }
28095 }
28096 module.debug('API Request failed', errorMessage, xhr);
28097 settings.onFailure.call(context, response, $module, xhr);
28098 },
28099 },
28100 },
28101
28102 create: {
28103
28104 request: function () {
28105 // api request promise
28106 return $.Deferred()
28107 .always(module.event.request.complete)
28108 .done(module.event.request.done)
28109 .fail(module.event.request.fail)
28110 ;
28111 },
28112
28113 mockedXHR: function () {
28114 var
28115 // xhr does not simulate these properties of xhr but must return them
28116 textStatus = false,
28117 status = false,
28118 httpMessage = false,
28119 responder = settings.mockResponse || settings.response,
28120 asyncResponder = settings.mockResponseAsync || settings.responseAsync,
28121 asyncCallback,
28122 response,
28123 mockedXHR
28124 ;
28125
28126 mockedXHR = $.Deferred()
28127 .always(module.event.xhr.complete)
28128 .done(module.event.xhr.done)
28129 .fail(module.event.xhr.fail)
28130 ;
28131
28132 if (responder) {
28133 if (isFunction(responder)) {
28134 module.debug('Using specified synchronous callback', responder);
28135 response = responder.call(context, requestSettings);
28136 } else {
28137 module.debug('Using settings specified response', responder);
28138 response = responder;
28139 }
28140 // simulating response
28141 mockedXHR.resolveWith(context, [response, textStatus, { responseText: response }]);
28142 } else if (isFunction(asyncResponder)) {
28143 asyncCallback = function (response) {
28144 module.debug('Async callback returned response', response);
28145
28146 if (response) {
28147 mockedXHR.resolveWith(context, [response, textStatus, { responseText: response }]);
28148 } else {
28149 mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]);
28150 }
28151 };
28152 module.debug('Using specified async response callback', asyncResponder);
28153 asyncResponder.call(context, requestSettings, asyncCallback);
28154 }
28155
28156 return mockedXHR;
28157 },
28158
28159 xhr: function () {
28160 var
28161 xhr
28162 ;
28163 // ajax request promise
28164 xhr = $.ajax(ajaxSettings)
28165 .always(module.event.xhr.always)
28166 .done(module.event.xhr.done)
28167 .fail(module.event.xhr.fail)
28168 ;
28169 module.verbose('Created server request', xhr, ajaxSettings);
28170
28171 return xhr;
28172 },
28173 },
28174
28175 set: {
28176 error: function () {
28177 module.verbose('Adding error state to element', $context);
28178 $context.addClass(className.error);
28179 },
28180 loading: function () {
28181 module.verbose('Adding loading state to element', $context);
28182 $context.addClass(className.loading);
28183 requestStartTime = Date.now();
28184 },
28185 },
28186
28187 remove: {
28188 error: function () {
28189 module.verbose('Removing error state from element', $context);
28190 $context.removeClass(className.error);
28191 },
28192 loading: function () {
28193 module.verbose('Removing loading state from element', $context);
28194 $context.removeClass(className.loading);
28195 },
28196 },
28197
28198 get: {
28199 normalizedData: function () {
28200 return typeof settings.data === 'string' ? settings.data : JSON.stringify(settings.data, Object.keys(settings.data).sort());
28201 },
28202 responseFromXHR: function (xhr) {
28203 return $.isPlainObject(xhr)
28204 ? (module.is.expectingJSON()
28205 ? module.decode.json(xhr.responseText)
28206 : xhr.responseText)
28207 : false;
28208 },
28209 errorFromRequest: function (response, status, httpMessage) {
28210 return $.isPlainObject(response) && response.error !== undefined
28211 ? response.error // use json error message
28212 : (settings.error[status] !== undefined // use server error message
28213 ? settings.error[status]
28214 : httpMessage);
28215 },
28216 request: function () {
28217 return module.request || false;
28218 },
28219 xhr: function () {
28220 return module.xhr || false;
28221 },
28222 settings: function () {
28223 var
28224 runSettings
28225 ;
28226 runSettings = settings.beforeSend.call($module, settings);
28227 if (runSettings) {
28228 if (runSettings.success !== undefined) {
28229 module.debug('Legacy success callback detected', runSettings);
28230 module.error(error.legacyParameters, runSettings.success);
28231 runSettings.onSuccess = runSettings.success;
28232 }
28233 if (runSettings.failure !== undefined) {
28234 module.debug('Legacy failure callback detected', runSettings);
28235 module.error(error.legacyParameters, runSettings.failure);
28236 runSettings.onFailure = runSettings.failure;
28237 }
28238 if (runSettings.complete !== undefined) {
28239 module.debug('Legacy complete callback detected', runSettings);
28240 module.error(error.legacyParameters, runSettings.complete);
28241 runSettings.onComplete = runSettings.complete;
28242 }
28243 }
28244 if (runSettings === undefined) {
28245 module.error(error.noReturnedValue);
28246 }
28247 if (runSettings === false) {
28248 return runSettings;
28249 }
28250
28251 return runSettings !== undefined
28252 ? $.extend(true, {}, runSettings)
28253 : $.extend(true, {}, settings);
28254 },
28255 urlEncodedValue: function (value) {
28256 var
28257 decodedValue = window.decodeURIComponent(value),
28258 encodedValue = window.encodeURIComponent(value),
28259 alreadyEncoded = decodedValue !== value
28260 ;
28261 if (alreadyEncoded) {
28262 module.debug('URL value is already encoded, avoiding double encoding', value);
28263
28264 return value;
28265 }
28266 module.verbose('Encoding value using encodeURIComponent', value, encodedValue);
28267
28268 return encodedValue;
28269 },
28270 defaultData: function () {
28271 var
28272 data = {}
28273 ;
28274 if (!isWindow(element)) {
28275 if (module.is.input()) {
28276 data.value = $module.val();
28277 } else if (!module.is.form()) {
28278 data.text = $module.text();
28279 }
28280 }
28281
28282 return data;
28283 },
28284 event: function () {
28285 if (isWindow(element) || settings.on === 'now') {
28286 module.debug('API called without element, no events attached');
28287
28288 return false;
28289 }
28290 if (settings.on === 'auto') {
28291 if ($module.is('input')) {
28292 return element.oninput !== undefined
28293 ? 'input'
28294 : (element.onpropertychange !== undefined
28295 ? 'propertychange'
28296 : 'keyup');
28297 }
28298 if ($module.is('form')) {
28299 return 'submit';
28300 }
28301
28302 return 'click';
28303 }
28304
28305 return settings.on;
28306 },
28307 templatedURL: function (action) {
28308 action = action || settings.action || $module.data(metadata.action) || false;
28309 url = settings.url || $module.data(metadata.url) || false;
28310 if (url) {
28311 module.debug('Using specified url', url);
28312
28313 return url;
28314 }
28315 if (action) {
28316 module.debug('Looking up url for action', action, settings.api);
28317 if (settings.api[action] === undefined && !module.is.mocked()) {
28318 module.error(error.missingAction, settings.action, settings.api);
28319
28320 return;
28321 }
28322 url = settings.api[action];
28323 } else if (module.is.form()) {
28324 url = $module.attr('action') || $context.attr('action') || false;
28325 module.debug('No url or action specified, defaulting to form action', url);
28326 }
28327
28328 return url;
28329 },
28330 },
28331
28332 abort: function () {
28333 var
28334 xhr = module.get.xhr()
28335 ;
28336 if (xhr && xhr.state() !== 'resolved') {
28337 module.debug('Cancelling API request');
28338 xhr.abort();
28339 }
28340 },
28341
28342 // reset state
28343 reset: function () {
28344 module.remove.error();
28345 module.remove.loading();
28346 },
28347
28348 setting: function (name, value) {
28349 module.debug('Changing setting', name, value);
28350 if ($.isPlainObject(name)) {
28351 $.extend(true, settings, name);
28352 } else if (value !== undefined) {
28353 if ($.isPlainObject(settings[name])) {
28354 $.extend(true, settings[name], value);
28355 } else {
28356 settings[name] = value;
28357 }
28358 } else {
28359 return settings[name];
28360 }
28361 },
28362 internal: function (name, value) {
28363 if ($.isPlainObject(name)) {
28364 $.extend(true, module, name);
28365 } else if (value !== undefined) {
28366 module[name] = value;
28367 } else {
28368 return module[name];
28369 }
28370 },
28371 debug: function () {
28372 if (!settings.silent && settings.debug) {
28373 if (settings.performance) {
28374 module.performance.log(arguments);
28375 } else {
28376 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
28377 module.debug.apply(console, arguments);
28378 }
28379 }
28380 },
28381 verbose: function () {
28382 if (!settings.silent && settings.verbose && settings.debug) {
28383 if (settings.performance) {
28384 module.performance.log(arguments);
28385 } else {
28386 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
28387 module.verbose.apply(console, arguments);
28388 }
28389 }
28390 },
28391 error: function () {
28392 if (!settings.silent) {
28393 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
28394 module.error.apply(console, arguments);
28395 }
28396 },
28397 performance: {
28398 log: function (message) {
28399 var
28400 currentTime,
28401 executionTime,
28402 previousTime
28403 ;
28404 if (settings.performance) {
28405 currentTime = Date.now();
28406 previousTime = time || currentTime;
28407 executionTime = currentTime - previousTime;
28408 time = currentTime;
28409 performance.push({
28410 Name: message[0],
28411 Arguments: [].slice.call(message, 1) || '',
28412 // 'Element' : element,
28413 'Execution Time': executionTime,
28414 });
28415 }
28416 clearTimeout(module.performance.timer);
28417 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
28418 },
28419 display: function () {
28420 var
28421 title = settings.name + ':',
28422 totalTime = 0
28423 ;
28424 time = false;
28425 clearTimeout(module.performance.timer);
28426 $.each(performance, function (index, data) {
28427 totalTime += data['Execution Time'];
28428 });
28429 title += ' ' + totalTime + 'ms';
28430 if (performance.length > 0) {
28431 console.groupCollapsed(title);
28432 if (console.table) {
28433 console.table(performance);
28434 } else {
28435 $.each(performance, function (index, data) {
28436 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
28437 });
28438 }
28439 console.groupEnd();
28440 }
28441 performance = [];
28442 },
28443 },
28444 invoke: function (query, passedArguments, context) {
28445 var
28446 object = instance,
28447 maxDepth,
28448 found,
28449 response
28450 ;
28451 passedArguments = passedArguments || queryArguments;
28452 context = context || element;
28453 if (typeof query === 'string' && object !== undefined) {
28454 query = query.split(/[ .]/);
28455 maxDepth = query.length - 1;
28456 $.each(query, function (depth, value) {
28457 var camelCaseValue = depth !== maxDepth
28458 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
28459 : query
28460 ;
28461 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
28462 object = object[camelCaseValue];
28463 } else if (object[camelCaseValue] !== undefined) {
28464 found = object[camelCaseValue];
28465
28466 return false;
28467 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
28468 object = object[value];
28469 } else if (object[value] !== undefined) {
28470 found = object[value];
28471
28472 return false;
28473 } else {
28474 module.error(error.method, query);
28475
28476 return false;
28477 }
28478 });
28479 }
28480 if (isFunction(found)) {
28481 response = found.apply(context, passedArguments);
28482 } else if (found !== undefined) {
28483 response = found;
28484 }
28485 if (Array.isArray(returnedValue)) {
28486 returnedValue.push(response);
28487 } else if (returnedValue !== undefined) {
28488 returnedValue = [returnedValue, response];
28489 } else if (response !== undefined) {
28490 returnedValue = response;
28491 }
28492
28493 return found;
28494 },
28495 };
28496
28497 if (methodInvoked) {
28498 if (instance === undefined) {
28499 module.initialize();
28500 }
28501 module.invoke(query);
28502 } else {
28503 if (instance !== undefined) {
28504 instance.invoke('destroy');
28505 }
28506 module.initialize();
28507 }
28508 });
28509
28510 return returnedValue !== undefined
28511 ? returnedValue
28512 : this;
28513 };
28514 $.api = $.fn.api;
28515
28516 $.api.settings = {
28517
28518 name: 'API',
28519 namespace: 'api',
28520
28521 debug: false,
28522 verbose: false,
28523 performance: true,
28524
28525 // object containing all templates endpoints
28526 api: {},
28527
28528 // whether to cache responses
28529 cache: true,
28530
28531 // whether new requests should abort previous requests
28532 interruptRequests: true,
28533
28534 // event binding
28535 on: 'auto',
28536
28537 // context for applying state classes
28538 stateContext: false,
28539
28540 // duration for loading state
28541 loadingDuration: 0,
28542
28543 // whether to hide errors after a period of time
28544 hideError: 'auto',
28545
28546 // duration for error state
28547 errorDuration: 2000,
28548
28549 // whether parameters should be encoded with encodeURIComponent
28550 encodeParameters: true,
28551
28552 // API action to use
28553 action: false,
28554
28555 // templated URL to use
28556 url: false,
28557
28558 // base URL to apply to all endpoints
28559 base: '',
28560
28561 // data that will
28562 urlData: {},
28563
28564 // whether to add default data to url data
28565 defaultData: true,
28566
28567 // whether to serialize closest form
28568 // use true to convert complex named keys like a[b][1][c][] into a nested object
28569 // use 'formdata' for formdata web api
28570 serializeForm: false,
28571
28572 // how long to wait before request should occur
28573 throttle: 0,
28574
28575 // whether to throttle first request or only repeated
28576 throttleFirstRequest: true,
28577
28578 // standard ajax settings
28579 method: 'get',
28580 data: {},
28581 dataType: 'json',
28582
28583 // mock response
28584 mockResponse: false,
28585 mockResponseAsync: false,
28586
28587 // aliases for mock
28588 response: false,
28589 responseAsync: false,
28590
28591 // whether onResponse should work with response value without force converting into an object
28592 rawResponse: true,
28593
28594 // callbacks before request
28595 beforeSend: function (settings) {
28596 return settings;
28597 },
28598 beforeXHR: function (xhr) {},
28599 onRequest: function (promise, xhr) {},
28600
28601 // after request
28602 onResponse: false, // function(response) { },
28603
28604 // response was successful, if JSON passed validation
28605 onSuccess: function (response, $module) {},
28606
28607 // request finished without aborting
28608 onComplete: function (response, $module) {},
28609
28610 // failed JSON success test
28611 onFailure: function (response, $module) {},
28612
28613 // server error
28614 onError: function (errorMessage, $module) {},
28615
28616 // request aborted
28617 onAbort: function (errorMessage, $module) {},
28618
28619 successTest: false,
28620
28621 // errors
28622 error: {
28623 beforeSend: 'The before send function has aborted the request',
28624 error: 'There was an error with your request',
28625 exitConditions: 'API Request Aborted. Exit conditions met',
28626 JSONParse: 'JSON could not be parsed during error handling',
28627 legacyParameters: 'You are using legacy API success callback names',
28628 method: 'The method you called is not defined',
28629 missingAction: 'API action used but no url was defined',
28630 missingURL: 'No URL specified for api event',
28631 noReturnedValue: 'The beforeSend callback must return a settings object, beforeSend ignored.',
28632 noStorage: 'Caching responses locally requires session storage',
28633 parseError: 'There was an error parsing your request',
28634 requiredParameter: 'Missing a required URL parameter: ',
28635 statusMessage: 'Server gave an error: ',
28636 timeout: 'Your request timed out',
28637 },
28638
28639 regExp: {
28640 required: /{\$*[\da-z]+}/gi,
28641 optional: /{\/\$*[\da-z]+}/gi,
28642 validate: /^[_a-z][\w-]*(?:\[[\w-]*])*$/i,
28643 key: /[\w-]+|(?=\[])/gi,
28644 push: /^$/,
28645 fixed: /^\d+$/,
28646 named: /^[\w-]+$/i,
28647 },
28648
28649 className: {
28650 loading: 'loading',
28651 error: 'error',
28652 },
28653
28654 selector: {
28655 disabled: '.disabled',
28656 form: 'form',
28657 },
28658
28659 metadata: {
28660 action: 'action',
28661 url: 'url',
28662 },
28663 };
28664})(jQuery, window, document);
28665
28666/*!
28667 * # Fomantic-UI 2.9.3 - State
28668 * https://github.com/fomantic/Fomantic-UI/
28669 *
28670 *
28671 * Released under the MIT license
28672 * https://opensource.org/licenses/MIT
28673 *
28674 */
28675
28676(function ($, window, document) {
28677 'use strict';
28678
28679 function isFunction(obj) {
28680 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
28681 }
28682
28683 window = window !== undefined && window.Math === Math
28684 ? window
28685 : globalThis;
28686
28687 $.fn.state = function (parameters) {
28688 var
28689 $allModules = $(this),
28690
28691 time = Date.now(),
28692 performance = [],
28693
28694 query = arguments[0],
28695 methodInvoked = typeof query === 'string',
28696 queryArguments = [].slice.call(arguments, 1),
28697 contextCheck = function (context, win) {
28698 var $context;
28699 if ([window, document].indexOf(context) >= 0) {
28700 $context = $(context);
28701 } else {
28702 $context = $(win.document).find(context);
28703 if ($context.length === 0) {
28704 $context = win.frameElement ? contextCheck(context, win.parent) : window;
28705 }
28706 }
28707
28708 return $context;
28709 },
28710 returnedValue
28711 ;
28712 $allModules.each(function () {
28713 var
28714 settings = $.isPlainObject(parameters)
28715 ? $.extend(true, {}, $.fn.state.settings, parameters)
28716 : $.extend({}, $.fn.state.settings),
28717
28718 error = settings.error,
28719 metadata = settings.metadata,
28720 className = settings.className,
28721 namespace = settings.namespace,
28722 states = settings.states,
28723 text = settings.text,
28724
28725 eventNamespace = '.' + namespace,
28726 moduleNamespace = namespace + '-module',
28727
28728 $module = $(this),
28729 $context = settings.context ? contextCheck(settings.context, window) : $module,
28730
28731 element = this,
28732 instance = $module.data(moduleNamespace),
28733
28734 module
28735 ;
28736 module = {
28737
28738 initialize: function () {
28739 module.verbose('Initializing module');
28740
28741 // allow module to guess desired state based on element
28742 if (settings.automatic) {
28743 module.add.defaults();
28744 }
28745
28746 // bind events with delegated events
28747 $context
28748 .on('mouseenter' + eventNamespace, module.change.text)
28749 .on('mouseleave' + eventNamespace, module.reset.text)
28750 .on('click' + eventNamespace, module.toggle.state)
28751 ;
28752 module.instantiate();
28753 },
28754
28755 instantiate: function () {
28756 module.verbose('Storing instance of module', module);
28757 instance = module;
28758 $module
28759 .data(moduleNamespace, module)
28760 ;
28761 },
28762
28763 destroy: function () {
28764 module.verbose('Destroying previous module', instance);
28765 $context
28766 .off(eventNamespace)
28767 ;
28768 $module
28769 .removeData(metadata.storedText)
28770 .removeData(moduleNamespace)
28771 ;
28772 },
28773
28774 refresh: function () {
28775 module.verbose('Refreshing selector cache');
28776 $module = $(element);
28777 },
28778
28779 add: {
28780 defaults: function () {
28781 var
28782 userStates = parameters && $.isPlainObject(parameters.states)
28783 ? parameters.states
28784 : {}
28785 ;
28786 $.each(settings.defaults, function (type, typeStates) {
28787 if (module.is[type] !== undefined && module.is[type]()) {
28788 module.verbose('Adding default states', type, element);
28789 $.extend(settings.states, typeStates, userStates);
28790 }
28791 });
28792 },
28793 },
28794
28795 is: {
28796
28797 active: function () {
28798 return $module.hasClass(className.active);
28799 },
28800 loading: function () {
28801 return $module.hasClass(className.loading);
28802 },
28803 inactive: function () {
28804 return !$module.hasClass(className.active);
28805 },
28806 state: function (state) {
28807 if (className[state] === undefined) {
28808 return false;
28809 }
28810
28811 return $module.hasClass(className[state]);
28812 },
28813
28814 enabled: function () {
28815 return !$module.is(settings.filter.active);
28816 },
28817 disabled: function () {
28818 return $module.is(settings.filter.active);
28819 },
28820 textEnabled: function () {
28821 return !$module.is(settings.filter.text);
28822 },
28823
28824 // definitions for automatic type detection
28825 button: function () {
28826 return $module.is('.button:not(a, .submit)');
28827 },
28828 input: function () {
28829 return $module.is('input');
28830 },
28831 progress: function () {
28832 return $module.is('.ui.progress');
28833 },
28834 },
28835
28836 allow: function (state) {
28837 module.debug('Now allowing state', state);
28838 states[state] = true;
28839 },
28840 disallow: function (state) {
28841 module.debug('No longer allowing', state);
28842 states[state] = false;
28843 },
28844
28845 allows: function (state) {
28846 return states[state] || false;
28847 },
28848
28849 enable: function () {
28850 $module.removeClass(className.disabled);
28851 },
28852
28853 disable: function () {
28854 $module.addClass(className.disabled);
28855 },
28856
28857 setState: function (state) {
28858 if (module.allows(state)) {
28859 $module.addClass(className[state]);
28860 }
28861 },
28862
28863 removeState: function (state) {
28864 if (module.allows(state)) {
28865 $module.removeClass(className[state]);
28866 }
28867 },
28868
28869 toggle: {
28870 state: function () {
28871 var
28872 apiRequest,
28873 requestCancelled
28874 ;
28875 if (module.allows('active') && module.is.enabled()) {
28876 module.refresh();
28877 if ($.fn.api !== undefined) {
28878 apiRequest = $module.api('get request');
28879 requestCancelled = $module.api('was cancelled');
28880 if (requestCancelled) {
28881 module.debug('API Request cancelled by beforesend');
28882 settings.activateTest = function () {
28883 return false;
28884 };
28885 settings.deactivateTest = function () {
28886 return false;
28887 };
28888 } else if (apiRequest) {
28889 module.listenTo(apiRequest);
28890
28891 return;
28892 }
28893 }
28894 module.change.state();
28895 }
28896 },
28897 },
28898
28899 listenTo: function (apiRequest) {
28900 module.debug('API request detected, waiting for state signal', apiRequest);
28901 if (apiRequest) {
28902 if (text.loading) {
28903 module.update.text(text.loading);
28904 }
28905 $.when(apiRequest)
28906 .then(function () {
28907 if (apiRequest.state() === 'resolved') {
28908 module.debug('API request succeeded');
28909 settings.activateTest = function () {
28910 return true;
28911 };
28912 settings.deactivateTest = function () {
28913 return true;
28914 };
28915 } else {
28916 module.debug('API request failed');
28917 settings.activateTest = function () {
28918 return false;
28919 };
28920 settings.deactivateTest = function () {
28921 return false;
28922 };
28923 }
28924 module.change.state();
28925 })
28926 ;
28927 }
28928 },
28929
28930 // checks whether active/inactive state can be given
28931 change: {
28932
28933 state: function () {
28934 module.debug('Determining state change direction');
28935 // inactive to active change
28936 if (module.is.inactive()) {
28937 module.activate();
28938 } else {
28939 module.deactivate();
28940 }
28941 if (settings.sync) {
28942 module.sync();
28943 }
28944 settings.onChange.call(element);
28945 },
28946
28947 text: function () {
28948 if (module.is.textEnabled()) {
28949 if (module.is.disabled()) {
28950 module.verbose('Changing text to disabled text', text.hover);
28951 module.update.text(text.disabled);
28952 } else if (module.is.active()) {
28953 if (text.hover) {
28954 module.verbose('Changing text to hover text', text.hover);
28955 module.update.text(text.hover);
28956 } else if (text.deactivate) {
28957 module.verbose('Changing text to deactivating text', text.deactivate);
28958 module.update.text(text.deactivate);
28959 }
28960 } else {
28961 if (text.hover) {
28962 module.verbose('Changing text to hover text', text.hover);
28963 module.update.text(text.hover);
28964 } else if (text.activate) {
28965 module.verbose('Changing text to activating text', text.activate);
28966 module.update.text(text.activate);
28967 }
28968 }
28969 }
28970 },
28971
28972 },
28973
28974 activate: function () {
28975 if (settings.activateTest.call(element)) {
28976 module.debug('Setting state to active');
28977 $module
28978 .addClass(className.active)
28979 ;
28980 module.update.text(text.active);
28981 settings.onActivate.call(element);
28982 }
28983 },
28984
28985 deactivate: function () {
28986 if (settings.deactivateTest.call(element)) {
28987 module.debug('Setting state to inactive');
28988 $module
28989 .removeClass(className.active)
28990 ;
28991 module.update.text(text.inactive);
28992 settings.onDeactivate.call(element);
28993 }
28994 },
28995
28996 sync: function () {
28997 module.verbose('Syncing other buttons to current state');
28998 if (module.is.active()) {
28999 $allModules
29000 .not($module)
29001 .state('activate')
29002 ;
29003 } else {
29004 $allModules
29005 .not($module)
29006 .state('deactivate')
29007 ;
29008 }
29009 },
29010
29011 get: {
29012 text: function () {
29013 return settings.selector.text
29014 ? $module.find(settings.selector.text).text()
29015 : $module.html();
29016 },
29017 textFor: function (state) {
29018 return text[state] || false;
29019 },
29020 },
29021
29022 flash: {
29023 text: function (text, duration, callback) {
29024 var
29025 previousText = module.get.text();
29026 module.debug('Flashing text message', text, duration);
29027 text = text || settings.text.flash;
29028 duration = duration || settings.flashDuration;
29029 callback = callback || function () {};
29030 module.update.text(text);
29031 setTimeout(function () {
29032 module.update.text(previousText);
29033 callback.call(element);
29034 }, duration);
29035 },
29036 },
29037
29038 reset: {
29039 // on mouseout sets text to previous value
29040 text: function () {
29041 var
29042 activeText = text.active || $module.data(metadata.storedText),
29043 inactiveText = text.inactive || $module.data(metadata.storedText)
29044 ;
29045 if (module.is.textEnabled()) {
29046 if (module.is.active() && activeText) {
29047 module.verbose('Resetting active text', activeText);
29048 module.update.text(activeText);
29049 } else if (inactiveText) {
29050 module.verbose('Resetting inactive text', activeText);
29051 module.update.text(inactiveText);
29052 }
29053 }
29054 },
29055 },
29056
29057 update: {
29058 text: function (text) {
29059 var
29060 currentText = module.get.text();
29061 if (text && text !== currentText) {
29062 module.debug('Updating text', text);
29063 if (settings.selector.text) {
29064 $module
29065 .data(metadata.storedText, text)
29066 .find(settings.selector.text)
29067 .text(text)
29068 ;
29069 } else {
29070 $module
29071 .data(metadata.storedText, text)
29072 .html(text)
29073 ;
29074 }
29075 } else {
29076 module.debug('Text is already set, ignoring update', text);
29077 }
29078 },
29079 },
29080
29081 setting: function (name, value) {
29082 module.debug('Changing setting', name, value);
29083 if ($.isPlainObject(name)) {
29084 $.extend(true, settings, name);
29085 } else if (value !== undefined) {
29086 if ($.isPlainObject(settings[name])) {
29087 $.extend(true, settings[name], value);
29088 } else {
29089 settings[name] = value;
29090 }
29091 } else {
29092 return settings[name];
29093 }
29094 },
29095 internal: function (name, value) {
29096 if ($.isPlainObject(name)) {
29097 $.extend(true, module, name);
29098 } else if (value !== undefined) {
29099 module[name] = value;
29100 } else {
29101 return module[name];
29102 }
29103 },
29104 debug: function () {
29105 if (!settings.silent && settings.debug) {
29106 if (settings.performance) {
29107 module.performance.log(arguments);
29108 } else {
29109 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
29110 module.debug.apply(console, arguments);
29111 }
29112 }
29113 },
29114 verbose: function () {
29115 if (!settings.silent && settings.verbose && settings.debug) {
29116 if (settings.performance) {
29117 module.performance.log(arguments);
29118 } else {
29119 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
29120 module.verbose.apply(console, arguments);
29121 }
29122 }
29123 },
29124 error: function () {
29125 if (!settings.silent) {
29126 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
29127 module.error.apply(console, arguments);
29128 }
29129 },
29130 performance: {
29131 log: function (message) {
29132 var
29133 currentTime,
29134 executionTime,
29135 previousTime
29136 ;
29137 if (settings.performance) {
29138 currentTime = Date.now();
29139 previousTime = time || currentTime;
29140 executionTime = currentTime - previousTime;
29141 time = currentTime;
29142 performance.push({
29143 Name: message[0],
29144 Arguments: [].slice.call(message, 1) || '',
29145 Element: element,
29146 'Execution Time': executionTime,
29147 });
29148 }
29149 clearTimeout(module.performance.timer);
29150 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
29151 },
29152 display: function () {
29153 var
29154 title = settings.name + ':',
29155 totalTime = 0
29156 ;
29157 time = false;
29158 clearTimeout(module.performance.timer);
29159 $.each(performance, function (index, data) {
29160 totalTime += data['Execution Time'];
29161 });
29162 title += ' ' + totalTime + 'ms';
29163 if (performance.length > 0) {
29164 console.groupCollapsed(title);
29165 if (console.table) {
29166 console.table(performance);
29167 } else {
29168 $.each(performance, function (index, data) {
29169 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
29170 });
29171 }
29172 console.groupEnd();
29173 }
29174 performance = [];
29175 },
29176 },
29177 invoke: function (query, passedArguments, context) {
29178 var
29179 object = instance,
29180 maxDepth,
29181 found,
29182 response
29183 ;
29184 passedArguments = passedArguments || queryArguments;
29185 context = context || element;
29186 if (typeof query === 'string' && object !== undefined) {
29187 query = query.split(/[ .]/);
29188 maxDepth = query.length - 1;
29189 $.each(query, function (depth, value) {
29190 var camelCaseValue = depth !== maxDepth
29191 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
29192 : query
29193 ;
29194 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
29195 object = object[camelCaseValue];
29196 } else if (object[camelCaseValue] !== undefined) {
29197 found = object[camelCaseValue];
29198
29199 return false;
29200 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
29201 object = object[value];
29202 } else if (object[value] !== undefined) {
29203 found = object[value];
29204
29205 return false;
29206 } else {
29207 module.error(error.method, query);
29208
29209 return false;
29210 }
29211 });
29212 }
29213 if (isFunction(found)) {
29214 response = found.apply(context, passedArguments);
29215 } else if (found !== undefined) {
29216 response = found;
29217 }
29218 if (Array.isArray(returnedValue)) {
29219 returnedValue.push(response);
29220 } else if (returnedValue !== undefined) {
29221 returnedValue = [returnedValue, response];
29222 } else if (response !== undefined) {
29223 returnedValue = response;
29224 }
29225
29226 return found;
29227 },
29228 };
29229
29230 if (methodInvoked) {
29231 if (instance === undefined) {
29232 module.initialize();
29233 }
29234 module.invoke(query);
29235 } else {
29236 if (instance !== undefined) {
29237 instance.invoke('destroy');
29238 }
29239 module.initialize();
29240 }
29241 });
29242
29243 return returnedValue !== undefined
29244 ? returnedValue
29245 : this;
29246 };
29247
29248 $.fn.state.settings = {
29249
29250 // module info
29251 name: 'State',
29252
29253 // debug output
29254 debug: false,
29255
29256 // verbose debug output
29257 verbose: false,
29258
29259 // namespace for events
29260 namespace: 'state',
29261
29262 // debug data includes performance
29263 performance: true,
29264
29265 // callback occurs on state change
29266 onActivate: function () {},
29267 onDeactivate: function () {},
29268 onChange: function () {},
29269
29270 // state test functions
29271 activateTest: function () {
29272 return true;
29273 },
29274 deactivateTest: function () {
29275 return true;
29276 },
29277
29278 // whether to automatically map default states
29279 automatic: true,
29280
29281 // activate / deactivate changes all elements instantiated at same time
29282 sync: false,
29283
29284 // default flash text duration, used for temporarily changing text of an element
29285 flashDuration: 1000,
29286
29287 // selector filter
29288 filter: {
29289 text: '.loading, .disabled',
29290 active: '.disabled',
29291 },
29292
29293 context: false,
29294
29295 // error
29296 error: {
29297 method: 'The method you called is not defined.',
29298 },
29299
29300 // metadata
29301 metadata: {
29302 promise: 'promise',
29303 storedText: 'stored-text',
29304 },
29305
29306 // change class on state
29307 className: {
29308 active: 'active',
29309 disabled: 'disabled',
29310 error: 'error',
29311 loading: 'loading',
29312 success: 'success',
29313 warning: 'warning',
29314 },
29315
29316 selector: {
29317 // selector for text node
29318 text: false,
29319 },
29320
29321 defaults: {
29322 input: {
29323 disabled: true,
29324 loading: true,
29325 active: true,
29326 },
29327 button: {
29328 disabled: true,
29329 loading: true,
29330 active: true,
29331 },
29332 progress: {
29333 active: true,
29334 success: true,
29335 warning: true,
29336 error: true,
29337 },
29338 },
29339
29340 states: {
29341 active: true,
29342 disabled: true,
29343 error: true,
29344 loading: true,
29345 success: true,
29346 warning: true,
29347 },
29348
29349 text: {
29350 disabled: false,
29351 flash: false,
29352 hover: false,
29353 active: false,
29354 inactive: false,
29355 activate: false,
29356 deactivate: false,
29357 },
29358
29359 };
29360})(jQuery, window, document);
29361
29362/*!
29363 * # Fomantic-UI 2.9.3 - Visibility
29364 * https://github.com/fomantic/Fomantic-UI/
29365 *
29366 *
29367 * Released under the MIT license
29368 * https://opensource.org/licenses/MIT
29369 *
29370 */
29371
29372(function ($, window, document) {
29373 'use strict';
29374
29375 function isFunction(obj) {
29376 return typeof obj === 'function' && typeof obj.nodeType !== 'number';
29377 }
29378
29379 window = window !== undefined && window.Math === Math
29380 ? window
29381 : globalThis;
29382
29383 $.fn.visibility = function (parameters) {
29384 var
29385 $allModules = $(this),
29386
29387 time = Date.now(),
29388 performance = [],
29389
29390 query = arguments[0],
29391 methodInvoked = typeof query === 'string',
29392 queryArguments = [].slice.call(arguments, 1),
29393 contextCheck = function (context, win) {
29394 var $context;
29395 if ([window, document].indexOf(context) >= 0) {
29396 $context = $(context);
29397 } else {
29398 $context = $(win.document).find(context);
29399 if ($context.length === 0) {
29400 $context = win.frameElement ? contextCheck(context, win.parent) : window;
29401 }
29402 }
29403
29404 return $context;
29405 },
29406 returnedValue,
29407
29408 moduleCount = $allModules.length,
29409 loadedCount = 0
29410 ;
29411
29412 $allModules.each(function () {
29413 var
29414 settings = $.isPlainObject(parameters)
29415 ? $.extend(true, {}, $.fn.visibility.settings, parameters)
29416 : $.extend({}, $.fn.visibility.settings),
29417
29418 className = settings.className,
29419 namespace = settings.namespace,
29420 error = settings.error,
29421 metadata = settings.metadata,
29422
29423 eventNamespace = '.' + namespace,
29424 moduleNamespace = 'module-' + namespace,
29425
29426 $window = $(window),
29427
29428 $module = $(this),
29429 $context = contextCheck(settings.context, window),
29430
29431 $placeholder,
29432
29433 instance = $module.data(moduleNamespace),
29434
29435 element = this,
29436 disabled = false,
29437
29438 contextObserver,
29439 observer,
29440 module
29441 ;
29442
29443 module = {
29444
29445 initialize: function () {
29446 module.debug('Initializing', settings);
29447
29448 module.setup.cache();
29449
29450 if (module.should.trackChanges()) {
29451 if (settings.type === 'image') {
29452 module.setup.image();
29453 }
29454 if (settings.type === 'fixed') {
29455 module.setup.fixed();
29456 }
29457
29458 if (settings.observeChanges) {
29459 module.observeChanges();
29460 }
29461 module.bind.events();
29462 }
29463
29464 module.save.position();
29465 if (!module.is.visible()) {
29466 module.error(error.visible, $module);
29467 }
29468
29469 if (settings.initialCheck) {
29470 module.checkVisibility();
29471 }
29472 module.instantiate();
29473 },
29474
29475 instantiate: function () {
29476 module.debug('Storing instance', module);
29477 $module
29478 .data(moduleNamespace, module)
29479 ;
29480 instance = module;
29481 },
29482
29483 destroy: function () {
29484 module.verbose('Destroying previous module');
29485 if (observer) {
29486 observer.disconnect();
29487 }
29488 if (contextObserver) {
29489 contextObserver.disconnect();
29490 }
29491 $window
29492 .off('load' + eventNamespace, module.event.load)
29493 .off('resize' + eventNamespace, module.event.resize)
29494 ;
29495 $context
29496 .off('scroll' + eventNamespace, module.event.scroll)
29497 .off('scrollchange' + eventNamespace, module.event.scrollchange)
29498 ;
29499 if (settings.type === 'fixed') {
29500 module.resetFixed();
29501 module.remove.placeholder();
29502 }
29503 $module
29504 .off(eventNamespace)
29505 .removeData(moduleNamespace)
29506 ;
29507 },
29508
29509 observeChanges: function () {
29510 if ('MutationObserver' in window) {
29511 contextObserver = new MutationObserver(module.event.contextChanged);
29512 observer = new MutationObserver(module.event.changed);
29513 contextObserver.observe(document, {
29514 childList: true,
29515 subtree: true,
29516 });
29517 observer.observe(element, {
29518 childList: true,
29519 subtree: true,
29520 });
29521 module.debug('Setting up mutation observer', observer);
29522 }
29523 },
29524
29525 bind: {
29526 events: function () {
29527 module.verbose('Binding visibility events to scroll and resize');
29528 if (settings.refreshOnLoad) {
29529 $window
29530 .on('load' + eventNamespace, module.event.load)
29531 ;
29532 }
29533 $window
29534 .on('resize' + eventNamespace, module.event.resize)
29535 ;
29536 // pub/sub pattern
29537 $context
29538 .off('scroll' + eventNamespace)
29539 .on('scroll' + eventNamespace, module.event.scroll)
29540 .on('scrollchange' + eventNamespace, module.event.scrollchange)
29541 ;
29542 },
29543 },
29544
29545 event: {
29546 changed: function (mutations) {
29547 module.verbose('DOM tree modified, updating visibility calculations');
29548 module.timer = setTimeout(function () {
29549 module.verbose('DOM tree modified, updating sticky menu');
29550 module.refresh();
29551 }, 100);
29552 },
29553 contextChanged: function (mutations) {
29554 [].forEach.call(mutations, function (mutation) {
29555 if (mutation.removedNodes) {
29556 [].forEach.call(mutation.removedNodes, function (node) {
29557 if (node === element || $(node).find(element).length > 0) {
29558 module.debug('Element removed from DOM, tearing down events');
29559 module.destroy();
29560 }
29561 });
29562 }
29563 });
29564 },
29565 resize: function () {
29566 module.debug('Window resized');
29567 if (settings.refreshOnResize) {
29568 requestAnimationFrame(module.refresh);
29569 }
29570 },
29571 load: function () {
29572 module.debug('Page finished loading');
29573 requestAnimationFrame(module.refresh);
29574 },
29575 // publishes scrollchange event on one scroll
29576 scroll: function () {
29577 if (settings.throttle) {
29578 clearTimeout(module.timer);
29579 module.timer = setTimeout(function () {
29580 $context.triggerHandler('scrollchange' + eventNamespace, [$context.scrollTop()]);
29581 }, settings.throttle);
29582 } else {
29583 requestAnimationFrame(function () {
29584 $context.triggerHandler('scrollchange' + eventNamespace, [$context.scrollTop()]);
29585 });
29586 }
29587 },
29588 // subscribes to scrollchange
29589 scrollchange: function (event, scrollPosition) {
29590 module.checkVisibility(scrollPosition);
29591 },
29592 },
29593
29594 precache: function (images, callback) {
29595 if (!Array.isArray(images)) {
29596 images = [images];
29597 }
29598 var
29599 imagesLength = images.length,
29600 loadedCounter = 0,
29601 cache = [],
29602 cacheImage = document.createElement('img'),
29603 handleLoad = function () {
29604 loadedCounter++;
29605 if (loadedCounter >= images.length) {
29606 if (isFunction(callback)) {
29607 callback();
29608 }
29609 }
29610 }
29611 ;
29612 while (imagesLength--) {
29613 cacheImage = document.createElement('img');
29614 cacheImage.addEventListener('load', handleLoad);
29615 cacheImage.addEventListener('error', handleLoad);
29616 cacheImage.src = images[imagesLength];
29617 cache.push(cacheImage);
29618 }
29619 },
29620
29621 enableCallbacks: function () {
29622 module.debug('Allowing callbacks to occur');
29623 disabled = false;
29624 },
29625
29626 disableCallbacks: function () {
29627 module.debug('Disabling all callbacks temporarily');
29628 disabled = true;
29629 },
29630
29631 should: {
29632 trackChanges: function () {
29633 if (methodInvoked) {
29634 module.debug('One time query, no need to bind events');
29635
29636 return false;
29637 }
29638 module.debug('Callbacks being attached');
29639
29640 return true;
29641 },
29642 },
29643
29644 setup: {
29645 cache: function () {
29646 module.cache = {
29647 occurred: {},
29648 screen: {},
29649 element: {},
29650 };
29651 },
29652 image: function () {
29653 var
29654 src = $module.data(metadata.src)
29655 ;
29656 if (src) {
29657 module.verbose('Lazy loading image', src);
29658 settings.once = true;
29659 settings.observeChanges = false;
29660
29661 // show when top visible
29662 settings.onOnScreen = function () {
29663 module.debug('Image on screen', element);
29664 module.precache(src, function () {
29665 module.set.image(src, function () {
29666 loadedCount++;
29667 if (loadedCount === moduleCount) {
29668 settings.onAllLoaded.call(this);
29669 }
29670 settings.onLoad.call(this);
29671 });
29672 });
29673 };
29674 }
29675 },
29676 fixed: function () {
29677 module.debug('Setting up fixed');
29678 settings.once = false;
29679 settings.observeChanges = false;
29680 settings.initialCheck = true;
29681 settings.refreshOnLoad = true;
29682 if (!parameters.transition) {
29683 settings.transition = false;
29684 }
29685 module.create.placeholder();
29686 module.debug('Added placeholder', $placeholder);
29687 settings.onTopPassed = function () {
29688 module.debug('Element passed, adding fixed position', $module);
29689 module.show.placeholder();
29690 module.set.fixed();
29691 if (settings.transition) {
29692 if ($.fn.transition !== undefined) {
29693 $module.transition(settings.transition, settings.duration);
29694 }
29695 }
29696 };
29697 settings.onTopPassedReverse = function () {
29698 module.debug('Element returned to position, removing fixed', $module);
29699 module.hide.placeholder();
29700 module.remove.fixed();
29701 };
29702 },
29703 },
29704
29705 create: {
29706 placeholder: function () {
29707 module.verbose('Creating fixed position placeholder');
29708 $placeholder = $module
29709 .clone(false)
29710 .css('display', 'none')
29711 .addClass(className.placeholder)
29712 .insertAfter($module)
29713 ;
29714 },
29715 },
29716
29717 show: {
29718 placeholder: function () {
29719 module.verbose('Showing placeholder');
29720 $placeholder
29721 .css('display', 'block')
29722 .css('visibility', 'hidden')
29723 ;
29724 },
29725 },
29726 hide: {
29727 placeholder: function () {
29728 module.verbose('Hiding placeholder');
29729 $placeholder
29730 .css('display', 'none')
29731 .css('visibility', '')
29732 ;
29733 },
29734 },
29735
29736 set: {
29737 fixed: function () {
29738 module.verbose('Setting element to fixed position');
29739 $module
29740 .addClass(className.fixed)
29741 .css({
29742 position: 'fixed',
29743 top: settings.offset + 'px',
29744 left: 'auto',
29745 zIndex: settings.zIndex,
29746 })
29747 ;
29748 settings.onFixed.call(element);
29749 },
29750 image: function (src, callback) {
29751 $module
29752 .attr('src', src)
29753 ;
29754 if (settings.transition) {
29755 if ($.fn.transition !== undefined) {
29756 if ($module.hasClass(className.visible)) {
29757 module.debug('Transition already occurred on this image, skipping animation');
29758
29759 return;
29760 }
29761 $module.transition(settings.transition, settings.duration, callback);
29762 } else {
29763 $module.fadeIn(settings.duration, callback);
29764 }
29765 } else {
29766 $module.show();
29767 }
29768 },
29769 },
29770
29771 is: {
29772 onScreen: function () {
29773 var
29774 calculations = module.get.elementCalculations()
29775 ;
29776
29777 return calculations.onScreen;
29778 },
29779 offScreen: function () {
29780 var
29781 calculations = module.get.elementCalculations()
29782 ;
29783
29784 return calculations.offScreen;
29785 },
29786 visible: function () {
29787 if (module.cache && module.cache.element) {
29788 return !(module.cache.element.width === 0 && module.cache.element.offset.top === 0);
29789 }
29790
29791 return false;
29792 },
29793 verticallyScrollableContext: function () {
29794 var
29795 overflowY = $context[0] !== window
29796 ? $context.css('overflow-y')
29797 : false
29798 ;
29799
29800 return overflowY === 'auto' || overflowY === 'scroll';
29801 },
29802 horizontallyScrollableContext: function () {
29803 var
29804 overflowX = $context[0] !== window
29805 ? $context.css('overflow-x')
29806 : false
29807 ;
29808
29809 return overflowX === 'auto' || overflowX === 'scroll';
29810 },
29811 },
29812
29813 refresh: function () {
29814 module.debug('Refreshing constants (width/height)');
29815 if (settings.type === 'fixed') {
29816 module.resetFixed();
29817 }
29818 module.reset();
29819 module.save.position();
29820 if (settings.checkOnRefresh) {
29821 module.checkVisibility();
29822 }
29823 settings.onRefresh.call(element);
29824 },
29825
29826 resetFixed: function () {
29827 module.remove.fixed();
29828 module.remove.occurred();
29829 },
29830
29831 reset: function () {
29832 module.verbose('Resetting all cached values');
29833 if ($.isPlainObject(module.cache)) {
29834 module.cache.screen = {};
29835 module.cache.element = {};
29836 }
29837 },
29838
29839 checkVisibility: function (scroll) {
29840 module.verbose('Checking visibility of element', module.cache.element);
29841
29842 if (!disabled && module.is.visible()) {
29843 // save scroll position
29844 module.save.scroll(scroll);
29845
29846 // update calculations derived from scroll
29847 module.save.calculations();
29848
29849 // percentage
29850 module.passed();
29851
29852 // reverse (must be first)
29853 module.passingReverse();
29854 module.topVisibleReverse();
29855 module.bottomVisibleReverse();
29856 module.topPassedReverse();
29857 module.bottomPassedReverse();
29858
29859 // one time
29860 module.onScreen();
29861 module.offScreen();
29862 module.passing();
29863 module.topVisible();
29864 module.bottomVisible();
29865 module.topPassed();
29866 module.bottomPassed();
29867
29868 // on update callback
29869 if (settings.onUpdate) {
29870 settings.onUpdate.call(element, module.get.elementCalculations());
29871 }
29872 }
29873 },
29874
29875 passed: function (amount, newCallback) {
29876 var
29877 calculations = module.get.elementCalculations()
29878 ;
29879 // assign callback
29880 if (amount && newCallback) {
29881 settings.onPassed[amount] = newCallback;
29882 } else if (amount !== undefined) {
29883 return module.get.pixelsPassed(amount) > calculations.pixelsPassed;
29884 } else if (calculations.passing) {
29885 $.each(settings.onPassed, function (amount, callback) {
29886 if (calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) {
29887 module.execute(callback, amount);
29888 } else if (!settings.once) {
29889 module.remove.occurred(callback);
29890 }
29891 });
29892 }
29893 },
29894
29895 onScreen: function (newCallback) {
29896 var
29897 calculations = module.get.elementCalculations(),
29898 callback = newCallback || settings.onOnScreen,
29899 callbackName = 'onScreen'
29900 ;
29901 if (newCallback) {
29902 module.debug('Adding callback for onScreen', newCallback);
29903 settings.onOnScreen = newCallback;
29904 }
29905 if (calculations.onScreen) {
29906 module.execute(callback, callbackName);
29907 } else if (!settings.once) {
29908 module.remove.occurred(callbackName);
29909 }
29910 if (newCallback !== undefined) {
29911 return calculations.onOnScreen;
29912 }
29913 },
29914
29915 offScreen: function (newCallback) {
29916 var
29917 calculations = module.get.elementCalculations(),
29918 callback = newCallback || settings.onOffScreen,
29919 callbackName = 'offScreen'
29920 ;
29921 if (newCallback) {
29922 module.debug('Adding callback for offScreen', newCallback);
29923 settings.onOffScreen = newCallback;
29924 }
29925 if (calculations.offScreen) {
29926 module.execute(callback, callbackName);
29927 } else if (!settings.once) {
29928 module.remove.occurred(callbackName);
29929 }
29930 if (newCallback !== undefined) {
29931 return calculations.onOffScreen;
29932 }
29933 },
29934
29935 passing: function (newCallback) {
29936 var
29937 calculations = module.get.elementCalculations(),
29938 callback = newCallback || settings.onPassing,
29939 callbackName = 'passing'
29940 ;
29941 if (newCallback) {
29942 module.debug('Adding callback for passing', newCallback);
29943 settings.onPassing = newCallback;
29944 }
29945 if (calculations.passing) {
29946 module.execute(callback, callbackName);
29947 } else if (!settings.once) {
29948 module.remove.occurred(callbackName);
29949 }
29950 if (newCallback !== undefined) {
29951 return calculations.passing;
29952 }
29953 },
29954
29955 topVisible: function (newCallback) {
29956 var
29957 calculations = module.get.elementCalculations(),
29958 callback = newCallback || settings.onTopVisible,
29959 callbackName = 'topVisible'
29960 ;
29961 if (newCallback) {
29962 module.debug('Adding callback for top visible', newCallback);
29963 settings.onTopVisible = newCallback;
29964 }
29965 if (calculations.topVisible) {
29966 module.execute(callback, callbackName);
29967 } else if (!settings.once) {
29968 module.remove.occurred(callbackName);
29969 }
29970 if (newCallback === undefined) {
29971 return calculations.topVisible;
29972 }
29973 },
29974
29975 bottomVisible: function (newCallback) {
29976 var
29977 calculations = module.get.elementCalculations(),
29978 callback = newCallback || settings.onBottomVisible,
29979 callbackName = 'bottomVisible'
29980 ;
29981 if (newCallback) {
29982 module.debug('Adding callback for bottom visible', newCallback);
29983 settings.onBottomVisible = newCallback;
29984 }
29985 if (calculations.bottomVisible) {
29986 module.execute(callback, callbackName);
29987 } else if (!settings.once) {
29988 module.remove.occurred(callbackName);
29989 }
29990 if (newCallback === undefined) {
29991 return calculations.bottomVisible;
29992 }
29993 },
29994
29995 topPassed: function (newCallback) {
29996 var
29997 calculations = module.get.elementCalculations(),
29998 callback = newCallback || settings.onTopPassed,
29999 callbackName = 'topPassed'
30000 ;
30001 if (newCallback) {
30002 module.debug('Adding callback for top passed', newCallback);
30003 settings.onTopPassed = newCallback;
30004 }
30005 if (calculations.topPassed) {
30006 module.execute(callback, callbackName);
30007 } else if (!settings.once) {
30008 module.remove.occurred(callbackName);
30009 }
30010 if (newCallback === undefined) {
30011 return calculations.topPassed;
30012 }
30013 },
30014
30015 bottomPassed: function (newCallback) {
30016 var
30017 calculations = module.get.elementCalculations(),
30018 callback = newCallback || settings.onBottomPassed,
30019 callbackName = 'bottomPassed'
30020 ;
30021 if (newCallback) {
30022 module.debug('Adding callback for bottom passed', newCallback);
30023 settings.onBottomPassed = newCallback;
30024 }
30025 if (calculations.bottomPassed) {
30026 module.execute(callback, callbackName);
30027 } else if (!settings.once) {
30028 module.remove.occurred(callbackName);
30029 }
30030 if (newCallback === undefined) {
30031 return calculations.bottomPassed;
30032 }
30033 },
30034
30035 passingReverse: function (newCallback) {
30036 var
30037 calculations = module.get.elementCalculations(),
30038 callback = newCallback || settings.onPassingReverse,
30039 callbackName = 'passingReverse'
30040 ;
30041 if (newCallback) {
30042 module.debug('Adding callback for passing reverse', newCallback);
30043 settings.onPassingReverse = newCallback;
30044 }
30045 if (!calculations.passing) {
30046 if (module.get.occurred('passing')) {
30047 module.execute(callback, callbackName);
30048 }
30049 } else if (!settings.once) {
30050 module.remove.occurred(callbackName);
30051 }
30052 if (newCallback !== undefined) {
30053 return !calculations.passing;
30054 }
30055 },
30056
30057 topVisibleReverse: function (newCallback) {
30058 var
30059 calculations = module.get.elementCalculations(),
30060 callback = newCallback || settings.onTopVisibleReverse,
30061 callbackName = 'topVisibleReverse'
30062 ;
30063 if (newCallback) {
30064 module.debug('Adding callback for top visible reverse', newCallback);
30065 settings.onTopVisibleReverse = newCallback;
30066 }
30067 if (!calculations.topVisible) {
30068 if (module.get.occurred('topVisible')) {
30069 module.execute(callback, callbackName);
30070 }
30071 } else if (!settings.once) {
30072 module.remove.occurred(callbackName);
30073 }
30074 if (newCallback === undefined) {
30075 return !calculations.topVisible;
30076 }
30077 },
30078
30079 bottomVisibleReverse: function (newCallback) {
30080 var
30081 calculations = module.get.elementCalculations(),
30082 callback = newCallback || settings.onBottomVisibleReverse,
30083 callbackName = 'bottomVisibleReverse'
30084 ;
30085 if (newCallback) {
30086 module.debug('Adding callback for bottom visible reverse', newCallback);
30087 settings.onBottomVisibleReverse = newCallback;
30088 }
30089 if (!calculations.bottomVisible) {
30090 if (module.get.occurred('bottomVisible')) {
30091 module.execute(callback, callbackName);
30092 }
30093 } else if (!settings.once) {
30094 module.remove.occurred(callbackName);
30095 }
30096 if (newCallback === undefined) {
30097 return !calculations.bottomVisible;
30098 }
30099 },
30100
30101 topPassedReverse: function (newCallback) {
30102 var
30103 calculations = module.get.elementCalculations(),
30104 callback = newCallback || settings.onTopPassedReverse,
30105 callbackName = 'topPassedReverse'
30106 ;
30107 if (newCallback) {
30108 module.debug('Adding callback for top passed reverse', newCallback);
30109 settings.onTopPassedReverse = newCallback;
30110 }
30111 if (!calculations.topPassed) {
30112 if (module.get.occurred('topPassed')) {
30113 module.execute(callback, callbackName);
30114 }
30115 } else if (!settings.once) {
30116 module.remove.occurred(callbackName);
30117 }
30118 if (newCallback === undefined) {
30119 return !calculations.onTopPassed;
30120 }
30121 },
30122
30123 bottomPassedReverse: function (newCallback) {
30124 var
30125 calculations = module.get.elementCalculations(),
30126 callback = newCallback || settings.onBottomPassedReverse,
30127 callbackName = 'bottomPassedReverse'
30128 ;
30129 if (newCallback) {
30130 module.debug('Adding callback for bottom passed reverse', newCallback);
30131 settings.onBottomPassedReverse = newCallback;
30132 }
30133 if (!calculations.bottomPassed) {
30134 if (module.get.occurred('bottomPassed')) {
30135 module.execute(callback, callbackName);
30136 }
30137 } else if (!settings.once) {
30138 module.remove.occurred(callbackName);
30139 }
30140 if (newCallback === undefined) {
30141 return !calculations.bottomPassed;
30142 }
30143 },
30144
30145 execute: function (callback, callbackName) {
30146 var
30147 calculations = module.get.elementCalculations(),
30148 screen = module.get.screenCalculations()
30149 ;
30150 callback = callback || false;
30151 if (callback) {
30152 if (settings.continuous) {
30153 module.debug('Callback being called continuously', callbackName, calculations);
30154 callback.call(element, calculations, screen);
30155 } else if (!module.get.occurred(callbackName)) {
30156 module.debug('Conditions met', callbackName, calculations);
30157 callback.call(element, calculations, screen);
30158 }
30159 }
30160 module.save.occurred(callbackName);
30161 },
30162
30163 remove: {
30164 fixed: function () {
30165 module.debug('Removing fixed position');
30166 $module
30167 .removeClass(className.fixed)
30168 .css({
30169 position: '',
30170 top: '',
30171 left: '',
30172 zIndex: '',
30173 })
30174 ;
30175 settings.onUnfixed.call(element);
30176 },
30177 placeholder: function () {
30178 module.debug('Removing placeholder content');
30179 if ($placeholder) {
30180 $placeholder.remove();
30181 }
30182 },
30183 occurred: function (callback) {
30184 if (callback) {
30185 var
30186 occurred = module.cache.occurred
30187 ;
30188 if (occurred[callback] !== undefined && occurred[callback] === true) {
30189 module.debug('Callback can now be called again', callback);
30190 module.cache.occurred[callback] = false;
30191 }
30192 } else {
30193 module.cache.occurred = {};
30194 }
30195 },
30196 },
30197
30198 save: {
30199 calculations: function () {
30200 module.verbose('Saving all calculations necessary to determine positioning');
30201 module.save.direction();
30202 module.save.screenCalculations();
30203 module.save.elementCalculations();
30204 },
30205 occurred: function (callback) {
30206 if (callback) {
30207 if (module.cache.occurred[callback] === undefined || (module.cache.occurred[callback] !== true)) {
30208 module.verbose('Saving callback occurred', callback);
30209 module.cache.occurred[callback] = true;
30210 }
30211 }
30212 },
30213 scroll: function (scrollPosition) {
30214 scrollPosition = scrollPosition + settings.offset || $context.scrollTop() + settings.offset;
30215 module.cache.scroll = scrollPosition;
30216 },
30217 direction: function () {
30218 var
30219 scroll = module.get.scroll(),
30220 lastScroll = module.get.lastScroll(),
30221 direction
30222 ;
30223 if (scroll > lastScroll && lastScroll) {
30224 direction = 'down';
30225 } else if (scroll < lastScroll && lastScroll) {
30226 direction = 'up';
30227 } else {
30228 direction = 'static';
30229 }
30230 module.cache.direction = direction;
30231
30232 return module.cache.direction;
30233 },
30234 elementPosition: function () {
30235 var
30236 element = module.cache.element,
30237 screen = module.get.screenSize()
30238 ;
30239 module.verbose('Saving element position');
30240 // (quicker than $.extend)
30241 element.fits = element.height < screen.height;
30242 element.offset = $module.offset();
30243 element.width = $module.outerWidth();
30244 element.height = $module.outerHeight();
30245 // compensate for scroll in context
30246 if (module.is.verticallyScrollableContext()) {
30247 element.offset.top += $context.scrollTop() - $context.offset().top;
30248 }
30249 if (module.is.horizontallyScrollableContext()) {
30250 element.offset.left += $context.scrollLeft() - $context.offset().left;
30251 }
30252 // store
30253 module.cache.element = element;
30254
30255 return element;
30256 },
30257 elementCalculations: function () {
30258 var
30259 screen = module.get.screenCalculations(),
30260 element = module.get.elementPosition()
30261 ;
30262 // offset
30263 if (settings.includeMargin) {
30264 element.margin = {};
30265 element.margin.top = parseInt($module.css('margin-top'), 10);
30266 element.margin.bottom = parseInt($module.css('margin-bottom'), 10);
30267 element.top = element.offset.top - element.margin.top;
30268 element.bottom = element.offset.top + element.height + element.margin.bottom;
30269 } else {
30270 element.top = element.offset.top;
30271 element.bottom = element.offset.top + element.height;
30272 }
30273
30274 // visibility
30275 element.topPassed = screen.top >= element.top;
30276 element.bottomPassed = screen.top >= element.bottom;
30277 element.topVisible = (screen.bottom >= element.top) && !element.topPassed;
30278 element.bottomVisible = (screen.bottom >= element.bottom) && !element.bottomPassed;
30279 element.pixelsPassed = 0;
30280 element.percentagePassed = 0;
30281
30282 // meta calculations
30283 element.onScreen = (element.topVisible || element.passing) && !element.bottomPassed;
30284 element.passing = element.topPassed && !element.bottomPassed;
30285 element.offScreen = !element.onScreen;
30286
30287 // passing calculations
30288 if (element.passing) {
30289 element.pixelsPassed = screen.top - element.top;
30290 element.percentagePassed = (screen.top - element.top) / element.height;
30291 }
30292 module.cache.element = element;
30293 module.verbose('Updated element calculations', element);
30294
30295 return element;
30296 },
30297 screenCalculations: function () {
30298 var
30299 scroll = module.get.scroll()
30300 ;
30301 module.save.direction();
30302 module.cache.screen.top = scroll;
30303 module.cache.screen.bottom = scroll + module.cache.screen.height;
30304
30305 return module.cache.screen;
30306 },
30307 screenSize: function () {
30308 module.verbose('Saving window position');
30309 module.cache.screen = {
30310 height: $context.height(),
30311 };
30312 },
30313 position: function () {
30314 module.save.screenSize();
30315 module.save.elementPosition();
30316 },
30317 },
30318
30319 get: {
30320 pixelsPassed: function (amount) {
30321 var
30322 element = module.get.elementCalculations()
30323 ;
30324 if (amount.search('%') > -1) {
30325 return element.height * (parseInt(amount, 10) / 100);
30326 }
30327
30328 return parseInt(amount, 10);
30329 },
30330 occurred: function (callback) {
30331 return module.cache.occurred !== undefined
30332 ? module.cache.occurred[callback] || false
30333 : false;
30334 },
30335 direction: function () {
30336 if (module.cache.direction === undefined) {
30337 module.save.direction();
30338 }
30339
30340 return module.cache.direction;
30341 },
30342 elementPosition: function () {
30343 if (module.cache.element === undefined) {
30344 module.save.elementPosition();
30345 }
30346
30347 return module.cache.element;
30348 },
30349 elementCalculations: function () {
30350 if (module.cache.element === undefined) {
30351 module.save.elementCalculations();
30352 }
30353
30354 return module.cache.element;
30355 },
30356 screenCalculations: function () {
30357 if (module.cache.screen === undefined) {
30358 module.save.screenCalculations();
30359 }
30360
30361 return module.cache.screen;
30362 },
30363 screenSize: function () {
30364 if (module.cache.screen === undefined) {
30365 module.save.screenSize();
30366 }
30367
30368 return module.cache.screen;
30369 },
30370 scroll: function () {
30371 if (module.cache.scroll === undefined) {
30372 module.save.scroll();
30373 }
30374
30375 return module.cache.scroll;
30376 },
30377 lastScroll: function () {
30378 if (module.cache.screen === undefined) {
30379 module.debug('First scroll event, no last scroll could be found');
30380
30381 return false;
30382 }
30383
30384 return module.cache.screen.top;
30385 },
30386 },
30387
30388 setting: function (name, value) {
30389 if ($.isPlainObject(name)) {
30390 $.extend(true, settings, name);
30391 } else if (value !== undefined) {
30392 settings[name] = value;
30393 } else {
30394 return settings[name];
30395 }
30396 },
30397 internal: function (name, value) {
30398 if ($.isPlainObject(name)) {
30399 $.extend(true, module, name);
30400 } else if (value !== undefined) {
30401 module[name] = value;
30402 } else {
30403 return module[name];
30404 }
30405 },
30406 debug: function () {
30407 if (!settings.silent && settings.debug) {
30408 if (settings.performance) {
30409 module.performance.log(arguments);
30410 } else {
30411 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
30412 module.debug.apply(console, arguments);
30413 }
30414 }
30415 },
30416 verbose: function () {
30417 if (!settings.silent && settings.verbose && settings.debug) {
30418 if (settings.performance) {
30419 module.performance.log(arguments);
30420 } else {
30421 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
30422 module.verbose.apply(console, arguments);
30423 }
30424 }
30425 },
30426 error: function () {
30427 if (!settings.silent) {
30428 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
30429 module.error.apply(console, arguments);
30430 }
30431 },
30432 performance: {
30433 log: function (message) {
30434 var
30435 currentTime,
30436 executionTime,
30437 previousTime
30438 ;
30439 if (settings.performance) {
30440 currentTime = Date.now();
30441 previousTime = time || currentTime;
30442 executionTime = currentTime - previousTime;
30443 time = currentTime;
30444 performance.push({
30445 Name: message[0],
30446 Arguments: [].slice.call(message, 1) || '',
30447 Element: element,
30448 'Execution Time': executionTime,
30449 });
30450 }
30451 clearTimeout(module.performance.timer);
30452 module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
30453 },
30454 display: function () {
30455 var
30456 title = settings.name + ':',
30457 totalTime = 0
30458 ;
30459 time = false;
30460 clearTimeout(module.performance.timer);
30461 $.each(performance, function (index, data) {
30462 totalTime += data['Execution Time'];
30463 });
30464 title += ' ' + totalTime + 'ms';
30465 if (performance.length > 0) {
30466 console.groupCollapsed(title);
30467 if (console.table) {
30468 console.table(performance);
30469 } else {
30470 $.each(performance, function (index, data) {
30471 console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
30472 });
30473 }
30474 console.groupEnd();
30475 }
30476 performance = [];
30477 },
30478 },
30479 invoke: function (query, passedArguments, context) {
30480 var
30481 object = instance,
30482 maxDepth,
30483 found,
30484 response
30485 ;
30486 passedArguments = passedArguments || queryArguments;
30487 context = context || element;
30488 if (typeof query === 'string' && object !== undefined) {
30489 query = query.split(/[ .]/);
30490 maxDepth = query.length - 1;
30491 $.each(query, function (depth, value) {
30492 var camelCaseValue = depth !== maxDepth
30493 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
30494 : query
30495 ;
30496 if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
30497 object = object[camelCaseValue];
30498 } else if (object[camelCaseValue] !== undefined) {
30499 found = object[camelCaseValue];
30500
30501 return false;
30502 } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
30503 object = object[value];
30504 } else if (object[value] !== undefined) {
30505 found = object[value];
30506
30507 return false;
30508 } else {
30509 module.error(error.method, query);
30510
30511 return false;
30512 }
30513 });
30514 }
30515 if (isFunction(found)) {
30516 response = found.apply(context, passedArguments);
30517 } else if (found !== undefined) {
30518 response = found;
30519 }
30520 if (Array.isArray(returnedValue)) {
30521 returnedValue.push(response);
30522 } else if (returnedValue !== undefined) {
30523 returnedValue = [returnedValue, response];
30524 } else if (response !== undefined) {
30525 returnedValue = response;
30526 }
30527
30528 return found;
30529 },
30530 };
30531
30532 if (methodInvoked) {
30533 if (instance === undefined) {
30534 module.initialize();
30535 }
30536 instance.save.scroll();
30537 instance.save.calculations();
30538 module.invoke(query);
30539 } else {
30540 if (instance !== undefined) {
30541 instance.invoke('destroy');
30542 }
30543 module.initialize();
30544 }
30545 });
30546
30547 return returnedValue !== undefined
30548 ? returnedValue
30549 : this;
30550 };
30551
30552 $.fn.visibility.settings = {
30553
30554 name: 'Visibility',
30555 namespace: 'visibility',
30556
30557 debug: false,
30558 verbose: false,
30559 performance: true,
30560
30561 // whether to use mutation observers to follow changes
30562 observeChanges: true,
30563
30564 // check position immediately on init
30565 initialCheck: true,
30566
30567 // whether to refresh calculations after all page images load
30568 refreshOnLoad: true,
30569
30570 // whether to refresh calculations after page resize event
30571 refreshOnResize: true,
30572
30573 // should call callbacks on refresh event (resize, etc)
30574 checkOnRefresh: true,
30575
30576 // callback should only occur one time
30577 once: true,
30578
30579 // callback should fire continuously when evaluates to true
30580 continuous: false,
30581
30582 // offset to use with scroll top
30583 offset: 0,
30584
30585 // whether to include margin in elements position
30586 includeMargin: false,
30587
30588 // scroll context for visibility checks
30589 context: window,
30590
30591 // visibility check delay in ms (defaults to animationFrame)
30592 throttle: false,
30593
30594 // special visibility type (image, fixed)
30595 type: false,
30596
30597 // z-index to use with visibility 'fixed'
30598 zIndex: '10',
30599
30600 // image only animation settings
30601 transition: 'fade in',
30602 duration: 1000,
30603
30604 // array of callbacks for percentage
30605 onPassed: {},
30606
30607 // standard callbacks
30608 onOnScreen: false,
30609 onOffScreen: false,
30610 onPassing: false,
30611 onTopVisible: false,
30612 onBottomVisible: false,
30613 onTopPassed: false,
30614 onBottomPassed: false,
30615
30616 // reverse callbacks
30617 onPassingReverse: false,
30618 onTopVisibleReverse: false,
30619 onBottomVisibleReverse: false,
30620 onTopPassedReverse: false,
30621 onBottomPassedReverse: false,
30622
30623 // special callbacks for image
30624 onLoad: function () {},
30625 onAllLoaded: function () {},
30626
30627 // special callbacks for fixed position
30628 onFixed: function () {},
30629 onUnfixed: function () {},
30630
30631 // utility callbacks
30632 onUpdate: false, // disabled by default for performance
30633 onRefresh: function () {},
30634
30635 metadata: {
30636 src: 'src',
30637 },
30638
30639 className: {
30640 fixed: 'fixed',
30641 placeholder: 'constraint',
30642 visible: 'visible',
30643 },
30644
30645 error: {
30646 method: 'The method you called is not defined.',
30647 visible: 'Element is hidden, you must call refresh after element becomes visible',
30648 },
30649
30650 };
30651})(jQuery, window, document);