PageSourceSearch

https://cp.castle-host.com/assets/js/scripts.bundle.js

js castle-host.com collected 2026-10-08 14:53:44 UTC 327,552 bytes, 11,018 lines download raw bytes

1"use strict";
2
3// Component Definition
4var KTApp = function() {
5    /** @type {object} colors State colors **/
6    var settings = {};
7
8    var initTooltip = function(el) {
9        var theme = el.data('theme') ? 'tooltip-' + el.data('theme') : '';
10        var width = el.data('width') == 'auto' ? 'tooltop-auto-width' : '';
11        var trigger = el.data('trigger') ? el.data('trigger') : 'hover';
12
13        $(el).tooltip({
14            trigger: trigger,
15            template: '<div class="tooltip ' + theme + ' ' + width + '" role="tooltip">\
16                <div class="arrow"></div>\
17                <div class="tooltip-inner"></div>\
18            </div>'
19        });
20    }
21
22    var initTooltips = function() {
23        // init bootstrap tooltips
24        $('[data-toggle="tooltip"]').each(function() {
25            initTooltip($(this));
26        });
27    }
28
29    var initPopover = function(el) {
30        var skin = el.data('skin') ? 'popover-' + el.data('skin') : '';
31        var triggerValue = el.data('trigger') ? el.data('trigger') : 'hover';
32
33        el.popover({
34            trigger: triggerValue,
35            template: '\
36            <div class="popover ' + skin + '" role="tooltip">\
37                <div class="arrow"></div>\
38                <h3 class="popover-header"></h3>\
39                <div class="popover-body"></div>\
40            </div>'
41        });
42    }
43
44    var initPopovers = function() {
45        // init bootstrap popover
46        $('[data-toggle="popover"]').each(function() {
47            initPopover($(this));
48        });
49    }
50
51    var initFileInput = function() {
52        // init bootstrap popover
53        $('.custom-file-input').on('change', function() {
54            var fileName = $(this).val();
55            $(this).next('.custom-file-label').addClass("selected").html(fileName);
56        });
57    }
58
59    var initScroll = function() {
60        $('[data-scroll="true"]').each(function() {
61            var el = $(this);
62
63            KTUtil.scrollInit(this, {
64                mobileNativeScroll: true,
65                handleWindowResize: true,
66                rememberPosition: (el.data('remember-position') == 'true' ? true : false)
67            });
68        });
69    }
70
71    var initAlerts = function() {
72        // init bootstrap popover
73        $('body').on('click', '[data-close=alert]', function() {
74            $(this).closest('.alert').hide();
75        });
76    }
77
78    var initCard = function(el, options) {
79        // init card tools
80        var el = $(el);
81        var card = new KTCard(el[0], options);
82    }
83
84    var initCards = function() {
85        // init card tools
86        $('[data-card="true"]').each(function() {
87            var el = $(this);
88            var options = {};
89
90            if (el.data('data-card-initialized') !== true) {
91                initCard(el, options);
92                el.data('data-card-initialized', true);
93            }
94        });
95    }
96
97    var initStickyCard = function() {
98        if (typeof Sticky === 'undefined') {
99            return;
100        }
101
102        var sticky = new Sticky('[data-sticky="true"]');
103    }
104
105    var initAbsoluteDropdown = function(context) {
106        var dropdownMenu;
107
108        if (!context) {
109            return;
110        }
111
112        $('body').on('show.bs.dropdown', context, function(e) {
113        	dropdownMenu = $(e.target).find('.dropdown-menu');
114        	$('body').append(dropdownMenu.detach());
115        	dropdownMenu.css('display', 'block');
116        	dropdownMenu.position({
117        		'my': 'right top',
118        		'at': 'right bottom',
119        		'of': $(e.relatedTarget),
120        	});
121        }).on('hide.bs.dropdown', context, function(e) {
122        	$(e.target).append(dropdownMenu.detach());
123        	dropdownMenu.hide();
124        });
125    }
126
127    var initAbsoluteDropdowns = function() {
128        $('body').on('show.bs.dropdown', function(e) {
129            // e.target is always parent (contains toggler and menu)
130            var $toggler = $(e.target).find("[data-attach='body']");
131            if ($toggler.length === 0) {
132                return;
133            }
134            var $dropdownMenu = $(e.target).find('.dropdown-menu');
135            // save detached menu
136            var $detachedDropdownMenu = $dropdownMenu.detach();
137            // save reference to detached menu inside data of toggler
138            $toggler.data('dropdown-menu', $detachedDropdownMenu);
139
140            $('body').append($detachedDropdownMenu);
141            $detachedDropdownMenu.css('display', 'block');
142            $detachedDropdownMenu.position({
143                my: 'right top',
144                at: 'right bottom',
145                of: $(e.relatedTarget),
146            });
147        });
148
149        $('body').on('hide.bs.dropdown', function(e) {
150            var $toggler = $(e.target).find("[data-attach='body']");
151            if ($toggler.length === 0) {
152                return;
153            }
154            // access to reference of detached menu from data of toggler
155            var $detachedDropdownMenu = $toggler.data('dropdown-menu');
156            // re-append detached menu inside parent
157            $(e.target).append($detachedDropdownMenu.detach());
158            // hide dropdown
159            $detachedDropdownMenu.hide();
160        });
161    };
162
163    return {
164        init: function(settingsArray) {
165            if (settingsArray) {
166                settings = settingsArray;
167            }
168
169            KTApp.initComponents();
170        },
171
172        initComponents: function() {
173            initScroll();
174            initTooltips();
175            initPopovers();
176            initAlerts();
177            initFileInput();
178            initCards();
179            initStickyCard();
180            initAbsoluteDropdowns();
181        },
182
183        initTooltips: function() {
184            initTooltips();
185        },
186
187        initTooltip: function(el) {
188            initTooltip(el);
189        },
190
191        initPopovers: function() {
192            initPopovers();
193        },
194
195        initPopover: function(el) {
196            initPopover(el);
197        },
198
199        initCard: function(el, options) {
200            initCard(el, options);
201        },
202
203        initCards: function() {
204            initCards();
205        },
206
207        initSticky: function() {
208            initSticky();
209        },
210
211        initAbsoluteDropdown: function(context) {
212            initAbsoluteDropdown(context);
213        },
214
215        block: function(target, options) {
216            var el = $(target);
217
218            options = $.extend(true, {
219                opacity: 0.05,
220                overlayColor: '#000000',
221                type: '',
222                size: '',
223                state: 'primary',
224                centerX: true,
225                centerY: true,
226                message: '',
227                shadow: true,
228                width: 'auto'
229            }, options);
230
231            var html;
232            var version = options.type ? 'spinner-' + options.type : '';
233            var state = options.state ? 'spinner-' + options.state : '';
234            var size = options.size ? 'spinner-' + options.size : '';
235            var spinner = '<span class="spinner ' + version + ' ' + state 
235+ ' ' + size + '"></span';
236
237            if (options.message && options.message.length > 0) {
238                var classes = 'blockui ' + (options.shadow === false ? 'blockui' : '');
239
240                html = '<div class="' + classes + '"><span>' + options.message + '</span>' + spinner + '</div>';
241
242                var el = document.createElement('div');
243
244                $('body').prepend(el);
245                KTUtil.addClass(el, classes);
246                el.innerHTML = html;
247                options.width = KTUtil.actualWidth(el) + 10;
248                KTUtil.remove(el);
249
250                if (target == 'body') {
251                    html = '<div class="' + classes + '" style="margin-left:-' + (options.width / 2) + 'px;"><span>' + options.message + '</span><span>' + spinner + '</span></div>';
252                }
253            } else {
254                html = spinner;
255            }
256
257            var params = {
258                message: html,
259                centerY: options.centerY,
260                centerX: options.centerX,
261                css: {
262                    top: '30%',
263                    left: '50%',
264                    border: '0',
265                    padding: '0',
266                    backgroundColor: 'none',
267                    width: options.width
268                },
269                overlayCSS: {
270                    backgroundColor: options.overlayColor,
271                    opacity: options.opacity,
272                    cursor: 'wait',
273                    zIndex: (target == 'body' ? 1100 : 10)
274                },
275                onUnblock: function() {
276                    if (el && el[0]) {
277                        KTUtil.css(el[0], 'position', '');
278                        KTUtil.css(el[0], 'zoom', '');
279                    }
280                }
281            };
282
283            if (target == 'body') {
284                params.css.top = '50%';
285                $.blockUI(params);
286            } else {
287                var el = $(target);
288                el.block(params);
289            }
290        },
291
292        unblock: function(target) {
293            if (target && target != 'body') {
294                $(target).unblock();
295            } else {
296                $.unblockUI();
297            }
298        },
299
300        blockPage: function(options) {
301            return KTApp.block('body', options);
302        },
303
304        unblockPage: function() {
305            return KTApp.unblock('body');
306        },
307
308        getSettings: function() {
309            return settings;
310        }
311    };
312}();
313
314// webpack support
315if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
316    module.exports = KTApp;
317}
318
319// Initialize KTApp class on document ready
320$(document).ready(function() {
321    KTApp.init(KTAppSettings);
322});
323
324"use strict";
325
326// Component Definition
327var KTCard = function(elementId, options) {
328    // Main object
329    var the = this;
330    var init = false;
331
332    // Get element object
333    var element = KTUtil.getById(elementId);
334    var body = KTUtil.getBody();
335
336    if (!element) {
337        return;
338    }
339
340    // Default options
341    var defaultOptions = {
342        toggleSpeed: 400,
343        sticky: {
344            releseOnReverse: false,
345            offset: 300,
346            zIndex: 101
347        }
348    };
349
350    ////////////////////////////
351    // ** Private Methods  ** //
352    ////////////////////////////
353
354    var Plugin = {
355        /**
356         * Construct
357         */
358
359        construct: function(options) {
360            if (KTUtil.data(element).has('card')) {
361                the = KTUtil.data(element).get('card');
362            } else {
363                // reset menu
364                Plugin.init(options);
365
366                // build menu
367                Plugin.build();
368
369                KTUtil.data(element).set('card', the);
370            }
371
372            return the;
373        },
374
375        /**
376         * Init card
377         */
378        init: function(options) {
379            the.element = element;
380            the.events = [];
381
382            // merge default and user defined options
383            the.options = KTUtil.deepExtend({}, defaultOptions, options);
384            the.header = KTUtil.child(element, '.card-header');
385            the.footer = KTUtil.child(element, '.card-footer');
386
387            if (KTUtil.child(element, '.card-body')) {
388                the.body = KTUtil.child(element, '.card-body');
389            } else if (KTUtil.child(element, '.form')) {
390                the.body = KTUtil.child(element, '.form');
391            }
392        },
393
394        /**
395         * Build Form Wizard
396         */
397        build: function() {
398            // Remove
399            var remove = KTUtil.find(the.header, '[data-card-tool=remove]');
400            if (remove) {
401                KTUtil.addEvent(remove, 'click', function(e) {
402                    e.preventDefault();
403                    Plugin.remove();
404                });
405            }
406
407            // Reload
408            var reload = KTUtil.find(the.header, '[data-card-tool=reload]');
409            if (reload) {
410                KTUtil.addEvent(reload, 'click', function(e) {
411                    e.preventDefault();
412                    Plugin.reload();
413                });
414            }
415
416            // Toggle
417            var toggle = KTUtil.find(the.header, '[data-card-tool=toggle]');
418            if (toggle) {
419                KTUtil.addEvent(toggle, 'click', function(e) {
420                    e.preventDefault();
421                    Plugin.toggle();
422                });
423            }
424        },
425
426        /**
427         * Enable stickt mode
428         */
429        initSticky: function() {
430            var lastScrollTop = 0;
431            var offset = the.options.sticky.offset;
432
433            if (!the.header) {
434                return;
435            }
436
437	        window.addEventListener('scroll', Plugin.onScrollSticky);
438        },
439
440	    /**
441	     * Window scroll handle event for sticky card
442	     */
443	    onScrollSticky: function(e) {
444		    var offset = the.options.sticky.offset;
445
446		    if(isNaN(offset)) return;
447
448		    var st = KTUtil.getScrollTop();
449
450		    if (st >= offset && KTUtil.hasClass(body, 'card-sticky-on') === false) {
451			    Plugin.eventTrigger('stickyOn');
452
453			    KTUtil.addClass(body, 'card-sticky-on');
454
455			    Plugin.updateSticky();
456
457		    } else if ((st*1.5) <= offset && KTUtil.hasClass(body, 'card-sticky-on')) {
458			    // Back scroll mode
459			    Plugin.eventTrigger('stickyOff');
460
461			    KTUtil.removeClass(body, 'card-sticky-on');
462
463			    Plugin.resetSticky();
464		    }
465	    },
466
467        updateSticky: function() {
468            if (!the.header) {
469                return;
470            }
471
472            var top;
473
474            if (KTUtil.hasClass(body, 'card-sticky-on')) {
475                if (the.options.sticky.position.top instanceof Function) {
476                    top = parseInt(the.options.sticky.position.top.call(this, the));
477                } else {
478                    top = parseInt(the.options.sticky.position.top);
479                }
480
481                var left;
482                if (the.options.sticky.position.left instanceof Function) {
483                    left = parseInt(the.options.sticky.position.left.call(this, the));
484                } else {
485                    left = parseInt(the.options.sticky.position.left);
486                }
487
488                var right;
489                if (the.options.sticky.position.right instanceof Function) {
490                    right = parseInt(the.options.sticky.position.right.call(this, the));
491                } else {
492                    right = parseInt(the.options.sticky.position.right);
493                }
494
495                KTUtil.css(the.header, 'z-index', the.options.sticky.zIndex);
496                KTUtil.css(the.header, 'top', top + 'px');
497                KTUtil.css(the.header, 'left', left + 'px');
498                KTUtil.css(the.header, 'right', right + 'px');
499            }
500        },
501
502        resetSticky: function() {
503            if (!the.header) {
504                return;
505            }
506
507            if (KTUtil.hasClass(body, 'card-sticky-on') === false) {
508                KTUtil.css(the.header, 'z-index', '');
509                KTUtil.css(the.header, 'top', '');
510                KTUtil.css(the.header, 'left', '');
511                KTUtil.css(the.header, 'right', '');
512            }
513        },
514
515        /**
516         * Remove card
517         */
518        remove: function() {
519            if (Plugin.eventTrigger('beforeRemove') === false) {
520                return;
521            }
522
523            KTUtil.remove(element);
524
525            Plugin.eventTrigger('afterRemove');
526        },
527
528        /**
529         * Set content
530         */
531        setContent: function(html) {
532            if (html) {
533                the.body.innerHTML = html;
534            }
535        },
536
537        /**
538         * Get body
539         */
540        getBody: function() {
541            return the.body;
542        },
543
544        /**
545         * Get self
546         */
547        getSelf: function() {
548            return element;
549        },
550
551        /**
552         * Reload
553         */
554        reload: function() {
555            Plugin.eventTrigger('reload');
556        },
557
558        /**
559         * Toggle
560         */
561        toggle: function() {
562            if (KTUtil.hasClass(element, 'card-collapse') || KTUtil.hasClass(element, 'card-collapsed')) {
563                Plugin.expand();
564            } else {
565                Plugin.collapse();
566            }
567        },
568
569        /**
570         * Collapse
571         */
572        collapse: function() {
573            if (Plugin.eventTrigger('beforeCollapse') === false) {
574                return;
575            }
576
577            KTUtil.slideUp(the.body, the.options.toggleSpeed, function() {
578                Plugin.eventTrigger('afterCollapse');
579            });
580
581            KTUtil.addClass(element, 'card-collapse');
582        },
583
584        /**
585         * Expand
586         */
587        expand: function() {
588            if (Plugin.eventTrigger('beforeExpand') === false) {
589                return;
590            }
591
592            KTUtil.slideDown(the.body, the.options.toggleSpeed, function() {
593                Plugin.eventTrigger('afterExpand');
594            });
595
596            KTUtil.removeClass(element, 'card-collapse');
597            KTUtil.removeClass(element, 'card-collapsed');
598        },
599
600        /**
601         * Trigger events
602         */
603        eventTrigger: function(name) {
604            //KTUtil.triggerCustomEvent(name);
605            for (var i = 0; i < the.events.length; i++) {
606                var event = the.events[i];
607                if (event.name == name) {
608                    if (event.one == true) {
609                        if (event.fired == false) {
610                            the.events[i].fired = true;
611                            return event.handler.call(this, the);
612                        }
613                    } else {
614                        return event.handler.call(this, the);
615                    }
616                }
617            }
618        },
619
620        addEvent: function(name, handler, one) {
621            the.events.push({
622                name: name,
623                handler: handler,
624                one: one,
625                fired: false
626            });
627
628            return the;
629        }
630    };
631
632    //////////////////////////
633    // ** Public Methods ** //
634    //////////////////////////
635
636    /**
637     * Set default options
638     */
639
640    the.setDefaults = function(options) {
641        defaultOptions = options;
642    };
643
644    /**
645     * Remove card
646     */
647    the.remove = function() {
648        return Plugin.remove(html);
649    };
650
651    /**
652     * Init sticky card
653     */
654    the.initSticky = function() {
655        return Plugin.initSticky();
656    };
657
658    /**
659     * Rerender sticky layout
660     */
661    the.updateSticky = function() {
662        return Plugin.updateSticky();
663    };
664
665    /**
666     * Reset the sticky
667     */
668    the.resetSticky = function() {
669        return Plugin.resetSticky();
670    };
671
672	/**
673	 * Destroy sticky card
674	 */
675	the.destroySticky = function() {
676		Plugin.resetSticky();
677		window.removeEventListener('scroll', Plugin.onScrollSticky);
678	};
679
680    /**
681     * Reload card
682     */
683    the.reload = function() {
684        return Plugin.reload();
685    };
686
687    /**
688     * Set card content
689     */
690    the.setContent = function(html) {
691        return Plugin.setContent(html);
692    };
693
694    /**
695     * Toggle card
696     */
697    the.toggle = function() {
698        return Plugin.toggle();
699    };
700
701    /**
702     * Collapse card
703     */
704    the.collapse = function() {
705        return Plugin.collapse();
706    };
707
708    /**
709     * Expand card
710     */
711    the.expand = function() {
712        return Plugin.expand();
713    };
714
715    /**
716     * Get cardbody
717     * @returns {jQuery}
718     */
719    the.getBody = function() {
720        return Plugin.getBody();
721    };
722
723    /**
724     * Get cardbody
725     * @returns {jQuery}
726     */
727    the.getSelf = function() {
728        return Plugin.getSelf();
729    };
730
731    /**
732     * Attach event
733     */
734    the.on = function(name, handler) {
735        return Plugin.addEvent(name, handler);
736    };
737
738    /**
739     * Attach event that will be fired once
740     */
741    the.one = function(name, handler) {
742        return Plugin.addEvent(name, handler, true);
743    };
744
745    // Construct plugin
746    Plugin.construct.apply(the, [options]);
747
748    return the;
749};
750
751// webpack support
752if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
753    module.exports = KTCard;
754}
755
756"use strict";
757// DOCS: https://javascript.info/cookie
758
759// Component Definition
760var KTCookie = function() {
761  return {
762    // returns the cookie with the given name,
763    // or undefined if not found
764    getCookie: function(name) {
765      var matches = document.cookie.match(new RegExp(
766        "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
767      ));
768      return matches ? decodeURIComponent(matches[1]) : undefined;
769    },
770    // Please note that a cookie value is encoded,
771    // so getCookie uses a built-in decodeURIComponent function to decode it.
772    setCookie: function(name, value, options) {
773      if (!options) {
774          options = {};
775      }
776
777      options = Object.assign({}, {path: '/'}, options);
778
779      if (options.expires instanceof Date) {
780        options.expires = options.expires.toUTCString();
781      }
782
783      var updatedCookie = encodeURIComponent(name) + "=" + encodeURIComponent(value);
784
785      for (var optionKey in options) {
786        if (!options.hasOwnProperty(optionKey)) {
787          continue;
788        }
789        updatedCookie += "; " + optionKey;
790        var optionValue = options[optionKey];
791        if (optionValue !== true) {
792          updatedCookie += "=" + optionValue;
793        }
794      }
795
796      document.cookie = updatedCookie;
797    },
798    // To delete a cookie, we can call it with a negative expiration date:
799    deleteCookie: function(name) {
800      setCookie(name, "", {
801        'max-age': -1
802      })
803    }
804  }
805}();
806
807// webpack support
808if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
809  module.exports = KTCookie;
810}
811
812"use strict";
813
814// Component Definition 
815var KTDialog = function(options) {
816    // Main object
817    var the = this;
818
819    // Get element object
820    var element;
821    var body = KTUtil.getBody();
822
823    // Default options
824    var defaultOptions = {
825        'placement' : 'top center',
826        'type'  : 'loader',
827        'width' : 100,
828        'state' : 'default',
829        'message' : 'Loading...'
830    };
831
832    ////////////////////////////
833    // ** Private Methods  ** //
834    ////////////////////////////
835
836    var Plugin = {
837        /**
838         * Construct
839         */
840
841        construct: function(options) {
842            Plugin.init(options);
843
844            return the;
845        },
846
847        /**
848         * Handles subtoggle click toggle
849         */
850        init: function(options) {
851            the.events = [];
852
853            // merge default and user defined options
854            the.options = KTUtil.deepExtend({}, defaultOptions, options);
855
856            the.state = false;
857        },
858
859        /**
860         * Show dialog
861         */
862        show: function() {
863            Plugin.eventTrigger('show');
864
865            element = document.createElement("DIV");
866            KTUtil.setHTML(element, the.options.message);
867
868            KTUtil.addClass(element, 'dialog dialog-shown');
869            KTUtil.addClass(element, 'dialog-' + the.options.state);
870            KTUtil.addClass(element, 'dialog-' + the.options.type);
871
872            if (the.options.placement == 'top center') {
873                KTUtil.addClass(element, 'dialog-top-center');
874            }
875
876            body.appendChild(element);
877
878            the.state = 'shown';
879
880            Plugin.eventTrigger('shown');
881
882            return the;
883        },
884
885        /**
886         * Hide dialog
887         */
888        hide: function() {
889            if (element) {
890                Plugin.eventTrigger('hide');
891
892                element.remove();
893                the.state = 'hidden';
894
895                Plugin.eventTrigger('hidden');
896            }
897
898            return the;
899        },
900
901        /**
902         * Trigger events
903         */
904        eventTrigger: function(name) {
905            for (var i = 0; i < the.events.length; i++) {
906                var event = the.events[i];
907
908                if (event.name == name) {
909                    if (event.one == true) {
910                        if (event.fired == false) {
911                            the.events[i].fired = true;
912                            return event.handler.call(this, the);
913                        }
914                    } else {
915                        return event.handler.call(this, the);
916                    }
917                }
918            }
919        },
920
921        addEvent: function(name, handler, one) {
922            the.events.push({
923                name: name,
924                handler: handler,
925                one: one,
926                fired: false
927            });
928
929            return the;
930        }
931    };
932
933    //////////////////////////
934    // ** Public Methods ** //
935    //////////////////////////
936
937    /**
938     * Set default options
939     */
940
941    the.setDefaults = function(options) {
942        defaultOptions = options;
943    };
944
945    /**
946     * Check shown state
947     */
948    the.shown = function() {
949        return the.state == 'shown';
950    };
951
952    /**
953     * Check hidden state
954     */
955    the.hidden = function() {
956        return the.state == 'hidden';
957    };
958
959    /**
960     * Show dialog
961     */
962    the.show = function() {
963        return Plugin.show();
964    };
965
966    /**
967     * Hide dialog
968     */
969    the.hide = function() {
970        return Plugin.hide();
971    };
972
973    /**
974     * Attach event
975     * @returns {KTToggle}
976     */
977    the.on = function(name, handler) {
978        return Plugin.addEvent(name, handler);
979    };
980
981    /**
982     * Attach event that will be fired once
983     * @returns {KTToggle}
984     */
985    the.one = function(name, handler) {
986        return Plugin.addEvent(name, handler, true);
987    };
988
989    // Construct plugin
990    Plugin.construct.apply(the, [options]);
991
992    return the;
993};
994
995// webpack support
996if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
997    module.exports = KTDialog;
998}
999
1000"use strict";
1001
1002// Component Definition
1003var KTHeader = function(elementId, options) {
1004    // Main object
1005    var the = this;
1006    var init = false;
1007
1008    // Get element object
1009    var element = KTUtil.getById(elementId);
1010    var body = KTUtil.getBody();
1011
1012    if (element === undefined) {
1013        return;
1014    }
1015
1016    // Default options
1017    var defaultOptions = {
1018        offset: {
1019            desktop: true,
1020            tabletAndMobile: true
1021        },
1022        releseOnReverse: {
1023            desktop: false,
1024            tabletAndMobile: false
1025        }
1026    };
1027
1028    ////////////////////////////
1029    // ** Private Methods  ** //
1030    ////////////////////////////
1031
1032    var Plugin = {
1033        /**
1034         * Run plugin
1035         * @returns {KTHeader}
1036         */
1037        construct: function(options) {
1038            if (KTUtil.data(element).has('header')) {
1039                the = KTUtil.data(element).get('header');
1040            } else {
1041                // reset header
1042                Plugin.init(options);
1043
1044                // build header
1045                Plugin.build();
1046
1047                KTUtil.data(element).set('header', the);
1048            }
1049
1050            return the;
1051        },
1052
1053        /**
1054         * Handles subheader click toggle
1055         * @returns {KTHeader}
1056         */
1057        init: function(options) {
1058            the.events = [];
1059
1060            // merge default and user defined options
1061            the.options = KTUtil.deepExtend({}, defaultOptions, options);
1062        },
1063
1064        /**
1065         * Reset header
1066         * @returns {KTHeader}
1067         */
1068        build: function() {
1069            var eventTriggerState = true;
1070            var lastScrollTop = 0;
1071
1072            window.addEventListener('scroll', function() {
1073                var offset = 0, st, attrName;
1074
1075                if (KTUtil.isBreakpointDown('lg') && the.options.offset.tabletAndMobile === false) {
1076                    return;
1077                }
1078
1079                if (KTUtil.isBreakpointUp('lg') && the.options.offset.desktop === false) {
1080                    return;
1081                }
1082
1083                if (KTUtil.isBreakpointUp('lg')) {
1084                    offset = the.options.offset.desktop;
1085                } else if (KTUtil.isBreakpointDown('lg')) {
1086                    offset = the.options.offset.tabletAndMobile;
1087                }
1088
1089                st = KTUtil.getScrollTop();
1090
1091                if (
1092                    (KTUtil.isBreakpointDown('lg') && the.options.releseOnReverse.tabletAndMobile) ||
1093                    (KTUtil.isBreakpointUp('lg') && the.options.releseOnReverse.desktop)
1094                ) {
1095                    if (st > offset && lastScrollTop < st) { // down scroll mode
1096                        if (body.hasAttribute('data-header-scroll') === false) {
1097                            body.setAttribute('data-header-scroll', 'on');
1098                        }
1099
1100                        if (eventTriggerState) {
1101                            Plugin.eventTrigger('scrollOn', the);
1102                            eventTriggerState = false;
1103                        }
1104                    } else { // back scroll mode
1105                        if (body.hasAttribute('data-header-scroll') === true) {
1106                            body.removeAttribute('data-header-scroll');
1107                        }
1108
1109                        if (eventTriggerState == false) {
1110                            Plugin.eventTrigger('scrollOff', the);
1111                            eventTriggerState = true;
1112                        }
1113                    }
1114
1115                    lastScrollTop = st;
1116                } else {
1117                    if (st > offset) { // down scroll mode
1118                        if (body.hasAttribute('data-header-scroll') === false) {
1119                            body.setAttribute('data-header-scroll', 'on');
1120                        }
1121
1122                        if (eventTriggerState) {
1123                            Plugin.eventTrigger('scrollOn', the);
1124                            eventTriggerState = false;
1125                        }
1126                    } else { // back scroll mode
1127                        if (body.hasAttribute('data-header-scroll') === true) {
1128                            body.removeAttribute('data-header-scroll');
1129                        }
1130
1131                        if (eventTriggerState == false) {
1132                            Plugin.eventTrigger('scrollOff', the);
1133                            eventTriggerState = true;
1134                        }
1135                    }
1136                }
1137            });
1138        },
1139
1140        /**
1141         * Trigger events
1142         */
1143        eventTrigger: function(name, args) {
1144            for (var i = 0; i < the.events.length; i++) {
1145                var event = the.events[i];
1146                if (event.name == name) {
1147                    if (event.one == true) {
1148                        if (event.fired == false) {
1149                            the.events[i].fired = true;
1150                            return event.handler.call(this, the, args);
1151                        }
1152                    } else {
1153                        return event.handler.call(this, the, args);
1154                    }
1155                }
1156            }
1157        },
1158
1159        addEvent: function(name, handler, one) {
1160            the.events.push({
1161                name: name,
1162                handler: handler,
1163                one: one,
1164                fired: false
1165            });
1166        }
1167    };
1168
1169    //////////////////////////
1170    // ** Public Methods ** //
1171    //////////////////////////
1172
1173    /**
1174     * Set default options
1175     */
1176
1177    the.setDefaults = function(options) {
1178        defaultOptions = options;
1179    };
1180
1181    /**
1182     * Register event
1183     */
1184    the.on = function(name, handler) {
1185        return Plugin.addEvent(name, handler);
1186    };
1187
1188    ///////////////////////////////
1189    // ** Plugin Construction ** //
1190    ///////////////////////////////
1191
1192    // Run plugin
1193    Plugin.construct.apply(the, [options]);
1194
1195    // Init done
1196    init = true;
1197
1198    // Return plugin instance
1199    return the;
1200};
1201
1202// webpack support
1203if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
1204    module.exports = KTHeader;
1205}
1206
1207"use strict";
1208
1209// Component Definition 
1210var KTImageInput = function(elementId, options) {
1211    // Main object
1212    var the = this;
1213    var init = false;
1214
1215    // Get element object
1216    var element = KTUtil.getById(elementId);
1217    var body = KTUtil.getBody();
1218
1219    if (!element) {
1220        return;
1221    }
1222
1223    // Default options
1224    var defaultOptions = {
1225        editMode: false
1226    };
1227
1228    ////////////////////////////
1229    // ** Private Methods  ** //
1230    ////////////////////////////
1231
1232    var Plugin = {
1233        /**
1234         * Construct
1235         */
1236
1237        construct: function(options) {
1238            if (KTUtil.data(element).has('imageinput')) {
1239                the = KTUtil.data(element).get('imageinput');
1240            } else {
1241                // reset menu
1242                Plugin.init(options);
1243
1244                // build menu
1245                Plugin.build();
1246
1247                KTUtil.data(element).set('imageinput', the);
1248            }
1249
1250            return the;
1251        },
1252
1253        /**
1254         * Init avatar
1255         */
1256        init: function(options) {
1257            the.element = element;
1258            the.events = [];
1259
1260            the.input = KTUtil.find(element, 'input[type="file"]');
1261            the.wrapper = KTUtil.find(element, '.image-input-wrapper');
1262            the.cancel = KTUtil.find(element, '[data-action="cancel"]');
1263            the.remove = KTUtil.find(element, '[data-action="remove"]');
1264            the.src = KTUtil.css(the.wrapper, 'backgroundImage');
1265            the.hidden = KTUtil.find(element, 'input[type="hidden"]');
1266
1267            // merge default and user defined options
1268            the.options = KTUtil.deepExtend({}, defaultOptions, options);
1269        },
1270
1271        /**
1272         * Build
1273         */
1274        build: function() {
1275            // Handle change
1276            KTUtil.addEvent(the.input, 'change', function(e) {
1277                e.preventDefault();
1278
1279	            if (the.input && the.input.files && the.input.files[0]) {
1280	                var reader = new FileReader();
1281	                reader.onload = function(e) {
1282	                    KTUtil.css(the.wrapper, 'background-image', 'url('+e.target.result +')');
1283	                }
1284	                reader.readAsDataURL(the.input.files[0]);
1285
1286	                KTUtil.addClass(the.element, 'image-input-changed');
1287                    KTUtil.removeClass(the.element, 'image-input-empty');
1288
1289                    // Fire change event
1290                    Plugin.eventTrigger('change');
1291	            }
1292            });
1293
1294            // Handle cancel
1295            KTUtil.addEvent(the.cancel, 'click', function(e) {
1296                e.preventDefault();
1297
1298                // Fire cancel event
1299                Plugin.eventTrigger('cancel');
1300
1301	            KTUtil.removeClass(the.element, 'image-input-changed');
1302                KTUtil.removeClass(the.element, 'image-input-empty');
1303	            KTUtil.css(the.wrapper, 'background-image', the.src);
1304	            the.input.value = "";
1305
1306                if (the.hidden) {
1307                    the.hidden.value = "0";
1308                }
1309            });
1310
1311            // Handle remove
1312            KTUtil.addEvent(the.remove, 'click', function(e) {
1313                e.preventDefault();
1314
1315                // Fire cancel event
1316                Plugin.eventTrigger('remove');
1317
1318	            KTUtil.removeClass(the.element, 'image-input-changed');
1319                KTUtil.addClass(the.element, 'image-input-empty');
1320	            KTUtil.css(the.wrapper, 'background-image', "none");
1321	            the.input.value = "";
1322
1323                if (the.hidden) {
1324                    the.hidden.value = "1";
1325                }
1326            });
1327        },
1328
1329        /**
1330         * Trigger events
1331         */
1332        eventTrigger: function(name) {
1333            //KTUtil.triggerCustomEvent(name);
1334            for (var i = 0; i < the.events.length; i++) {
1335                var event = the.events[i];
1336                if (event.name == name) {
1337                    if (event.one == true) {
1338                        if (event.fired == false) {
1339                            the.events[i].fired = true;
1340                            return event.handler.call(this, the);
1341                        }
1342                    } else {
1343                        return event.handler.call(this, the);
1344                    }
1345                }
1346            }
1347        },
1348
1349        addEvent: function(name, handler, one) {
1350            the.events.push({
1351                name: name,
1352                handler: handler,
1353                one: one,
1354                fired: false
1355            });
1356
1357            return the;
1358        }
1359    };
1360
1361    //////////////////////////
1362    // ** Public Methods ** //
1363    //////////////////////////
1364
1365    /**
1366     * Set default options
1367     */
1368
1369    the.setDefaults = function(options) {
1370        defaultOptions = options;
1371    };
1372
1373    /**
1374     * Attach event
1375     */
1376    the.on = function(name, handler) {
1377        return Plugin.addEvent(name, handler);
1378    };
1379
1380    /**
1381     * Attach event that will be fired once
1382     */
1383    the.one = function(name, handler) {
1384        return Plugin.addEvent(name, handler, true);
1385    };
1386
1387    // Construct plugin
1388    Plugin.construct.apply(the, [options]);
1389
1390    return the;
1391};
1392
1393// webpack support
1394if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
1395    module.exports = KTImageInput;
1396}
1397
1398"use strict";
1399
1400// Component Definition
1401var KTMenu = function(elementId, options) {
1402    // Main object
1403    var the = this;
1404    var init = false;
1405
1406    // Get element object
1407    var element = KTUtil.getById(elementId);
1408    var body = KTUtil.getBody();
1409
1410    if (!element) {
1411        return;
1412    }
1413
1414    // Default options
1415    var defaultOptions = {
1416        // scrollable area with Perfect Scroll
1417        scroll: {
1418            rememberPosition: false
1419        },
1420
1421        // accordion submenu mode
1422        accordion: {
1423            slideSpeed: 200, // accordion toggle slide speed in milliseconds
1424            autoScroll: false, // enable auto scrolling(focus) to the clicked menu item
1425            autoScrollSpeed: 1200,
1426            expandAll: true // allow having multiple expanded accordions in the menu
1427        },
1428
1429        // dropdown submenu mode
1430        dropdown: {
1431            timeout: 500 // timeout in milliseconds to show and hide the hoverable submenu dropdown
1432        }
1433    };
1434
1435    ////////////////////////////
1436    // ** Private Methods  ** //
1437    ////////////////////////////
1438
1439    var Plugin = {
1440        /**
1441         * Run plugin
1442         * @returns {KTMenu}
1443         */
1444        construct: function(options) {
1445            if (KTUtil.data(element).has('menu')) {
1446                the = KTUtil.data(element).get('menu');
1447            } else {
1448                // reset menu
1449                Plugin.init(options);
1450
1451                // reset menu
1452                Plugin.reset();
1453
1454                // build menu
1455                Plugin.build();
1456
1457                KTUtil.data(element).set('menu', the);
1458            }
1459
1460            return the;
1461        },
1462
1463        /**
1464         * Handles submenu click toggle
1465         * @returns {KTMenu}
1466         */
1467        init: function(options) {
1468            the.events = [];
1469
1470            the.eventHandlers = {};
1471
1472            // merge default and user defined options
1473            the.options = KTUtil.deepExtend({}, defaultOptions, options);
1474
1475            // pause menu
1476            the.pauseDropdownHoverTime = 0;
1477
1478            the.uid = KTUtil.getUniqueID();
1479        },
1480
1481        update: function(options) {
1482            // merge default and user defined options
1483            the.options = KTUtil.deepExtend({}, defaultOptions, options);
1484
1485            // pause menu
1486            the.pauseDropdownHoverTime = 0;
1487
1488             // reset menu
1489            Plugin.reset();
1490
1491            the.eventHandlers = {};
1492
1493            // build menu
1494            Plugin.build();
1495
1496            KTUtil.data(element).set('menu', the);
1497        },
1498
1499        reload: function() {
1500             // reset menu
1501            Plugin.reset();
1502
1503            // build menu
1504            Plugin.build();
1505
1506            // reset submenu props
1507            Plugin.resetSubmenuProps();
1508        },
1509
1510        /**
1511         * Reset menu
1512         * @returns {KTMenu}
1513         */
1514        build: function() {
1515            // General accordion submenu toggle
1516            the.eventHandlers['event_1'] = KTUtil.on( element, '.menu-toggle', 'click', Plugin.handleSubmenuAccordion);
1517
1518            // Dropdown mode(hoverable)
1519            if (Plugin.getSubmenuMode() === 'dropdown' || Plugin.isConditionalSubmenuDropdown()) {
1520                // dropdown submenu - hover toggle
1521                the.eventHandlers['event_2'] = KTUtil.on( element, '[data-menu-toggle="hover"]', 'mouseover', Plugin.handleSubmenuDrodownHoverEnter);
1522                the.eventHandlers['event_3'] = KTUtil.on( element, '[data-menu-toggle="hover"]', 'mouseout', Plugin.handleSubmenuDrodownHoverExit);
1523
1524                // dropdown submenu - click toggle
1525                the.eventHandlers['event_4'] = KTUtil.on( element, '[data-menu-toggle="click"] > .menu-toggle, [data-menu-toggle="click"] > .menu-link .menu-toggle', 'click', Plugin.handleSubmenuDropdownClick);
1526                the.eventHandlers['event_5'] = KTUtil.on( element, '[data-menu-toggle="tab"] > .menu-toggle, [data-menu-toggle="tab"] > .menu-link .menu-toggle', 'click', Plugin.handleSubmenuDropdownTabClick);
1527            }
1528
1529            // Handle general link click
1530            the.eventHandlers['event_6'] = KTUtil.on(element, '.menu-item > .menu-link:not(.menu-toggle):not(.menu-link-toggle-skip)', 'click', Plugin.handleLinkClick);
1531
1532            // Init scrollable menu
1533            if (the.options.scroll && the.options.scroll.height) {
1534                Plugin.scrollInit();
1535            }
1536        },
1537
1538        /**
1539         * Reset menu
1540         * @returns {KTMenu}
1541         */
1542        reset: function() {
1543            KTUtil.off( element, 'click', the.eventHandlers['event_1']);
1544
1545            // dropdown submenu - hover toggle
1546            KTUtil.off( element, 'mouseover', the.eventHandlers['event_2']);
1547            KTUtil.off( element, 'mouseout', the.eventHandlers['event_3']);
1548
1549            // dropdown submenu - click toggle
1550            KTUtil.off( element, 'click', the.eventHandlers['event_4']);
1551            KTUtil.off( element, 'click', the.eventHandlers['event_5']);
1552
1553            // handle link click
1554            KTUtil.off(element, 'click', the.eventHandlers['event_6']);
1555        },
1556
1557        /**
1558         * Init scroll menu
1559         *
1560        */
1561        scrollInit: function() {
1562            if ( the.options.scroll && the.options.scroll.height ) {
1563                KTUtil.scrollDestroy(element, true);
1564                KTUtil.scrollInit(element, {mobileNativeScroll: true, windowScroll: false, resetHeightOnDestroy: true, handleWindowResize: true, height: the.options.scroll.height, rememberPosition: the.options.scroll.rememberPosition});
1565            } else {
1566                KTUtil.scrollDestroy(element, true);
1567            }
1568        },
1569
1570        /**
1571         * Update scroll menu
1572        */
1573        scrollUpdate: function() {
1574            if ( the.options.scroll && the.options.scroll.height ) {
1575                KTUtil.scrollUpdate(element);
1576            }
1577        },
1578
1579        /**
1580         * Scroll top
1581        */
1582        scrollTop: function() {
1583            if ( the.options.scroll && the.options.scroll.height ) {
1584                KTUtil.scrollTop(element);
1585            }
1586        },
1587
1588        /**
1589         * Get submenu mode for current breakpoint and menu state
1590         * @returns {KTMenu}
1591         */
1592        getSubmenuMode: function(el) {
1593            if ( KTUtil.isBreakpointUp('lg') ) {
1594                if (el && KTUtil.hasAttr(el, 'data-menu-toggle') && KTUtil.attr(el, 'data-menu-toggle') == 'hover') {
1595                    return 'dropdown';
1596                }
1597
1598                if ( KTUtil.isset(the.options.submenu, 'desktop.state.body') ) {
1599                    if ( KTUtil.hasClasses(body, the.options.submenu.desktop.state.body) ) {
1600                        return the.options.submenu.desktop.state.mode;
1601                    } else {
1602                        return the.options.submenu.desktop.default;
1603                    }
1604                } else if ( KTUtil.isset(the.options.submenu, 'desktop') ) {
1605                    return the.options.submenu.desktop;
1606                }
1607            } else if ( KTUtil.isBreakpointUp('md') && KTUtil.isBreakpointDown('lg') && KTUtil.isset(the.options.submenu, 'tablet') ) {
1608                return the.options.submenu.tablet;
1609            } else if ( KTUtil.isBreakpointDown('md') && KTUtil.isset(the.options.submenu, 'mobile') ) {
1610                return the.options.submenu.mobile;
1611            } else {
1612                return false;
1613            }
1614        },
1615
1616        /**
1617         * Get submenu mode for current breakpoint and menu state
1618         * @returns {KTMenu}
1619         */
1620        isConditionalSubmenuDropdown: function() {
1621            if ( KTUtil.isBreakpointUp('lg') && KTUtil.isset(the.options.submenu, 'desktop.state.body') ) {
1622                return true;
1623            } else {
1624                return false;
1625            }
1626        },
1627
1628
1629        /**
1630         * Reset submenu attributes
1631         * @returns {KTMenu}
1632         */
1633        resetSubmenuProps: function(e) {
1634            var submenus = KTUtil.findAll(element, '.menu-submenu');
1635            if ( submenus ) {
1636                for (var i = 0, len = submenus.length; i < len; i++) {
1637                    var submenu = submenus[0];
1638
1639                    KTUtil.css(submenu, 'display', '');
1640                    KTUtil.css(submenu, 'overflow', '');
1641
1642                    if (submenu.hasAttribute('data-hor-direction')) {
1643                        KTUtil.removeClass(submenu, 'menu-submenu-left');
1644                        KTUtil.removeClass(submenu, 'menu-submenu-right');
1645                        KTUtil.addClass(submenu, submenu.getAttribute('data-hor-direction'));
1646                    }
1647                }
1648            }
1649        },
1650
1651        /**
1652         * Handles submenu hover toggle
1653         * @returns {KTMenu}
1654         */
1655        handleSubmenuDrodownHoverEnter: function(e) {
1656            if ( Plugin.getSubmenuMode(this) === 'accordion' ) {
1657                return;
1658            }
1659
1660            if ( the.resumeDropdownHover() === false ) {
1661                return;
1662            }
1663
1664            var item = this;
1665
1666            if ( item.getAttribute('data-hover') == '1' ) {
1667                item.removeAttribute('data-hover');
1668                clearTimeout( item.getAttribute('data-timeout') );
1669                item.removeAttribute('data-timeout');
1670            }
1671
1672            Plugin.showSubmenuDropdown(item);
1673        },
1674
1675        /**
1676         * Handles submenu hover toggle
1677         * @returns {KTMenu}
1678         */
1679        handleSubmenuDrodownHoverExit: function(e) {
1680            if ( the.resumeDropdownHover() === false ) {
1681                return;
1682            }
1683
1684            if ( Plugin.getSubmenuMode(this) === 'accordion' ) {
1685                return;
1686            }
1687
1688            var item = this;
1689            var time = the.options.dropdown.timeout;
1690
1691            var timeout = setTimeout(function() {
1692                if ( item.getAttribute('data-hover') == '1' ) {
1693                    Plugin.hideSubmenuDropdown(item, true);
1694                }
1695            }, time);
1696
1697            item.setAttribute('data-hover', '1');
1698            item.setAttribute('data-timeout', timeout);
1699        },
1700
1701        /**
1702         * Handles submenu click toggle
1703         * @returns {KTMenu}
1704         */
1705        handleSubmenuDropdownClick: function(e) {
1706            if ( Plugin.getSubmenuMode(this) === 'accordion' ) {
1707                return;
1708            }
1709
1710            var item = this.closest('.menu-item');
1711
1712            // Trigger click event handlers
1713            var result = Plugin.eventTrigger('submenuToggle', this, e);
1714            if (result === false) {
1715                return;
1716            }
1717
1718            if ( item.getAttribute('data-menu-submenu-mode') == 'accordion' ) {
1719                return;
1720            }
1721
1722            if ( KTUtil.hasClass(item, 'menu-item-hover') === false ) {
1723                KTUtil.addClass(item, 'menu-item-open-dropdown');
1724                Plugin.showSubmenuDropdown(item);
1725            } else {
1726                KTUtil.removeClass(item, 'menu-item-open-dropdown' );
1727                Plugin.hideSubmenuDropdown(item, true);
1728            }
1729
1730            e.preventDefault();
1731        },
1732
1733        /**
1734         * Handles tab click toggle
1735         * @returns {KTMenu}
1736         */
1737        handleSubmenuDropdownTabClick: function(e) {
1738            if (Plugin.getSubmenuMode(this) === 'accordion') {
1739                return;
1740            }
1741            var item = this.closest('.menu-item');
1742
1743            // Trigger click event handlers
1744            var result = Plugin.eventTrigger('submenuToggle', this, e);
1745            if (result === false) {
1746                return;
1747            }
1748
1749            if (item.getAttribute('data-menu-submenu-mode') == 'accordion') {
1750                return;
1751            }
1752
1753            if (KTUtil.hasClass(item, 'menu-item-hover') == false) {
1754                KTUtil.addClass(item, 'menu-item-open-dropdown');
1755                Plugin.showSubmenuDropdown(item);
1756            }
1757
1758            e.preventDefault();
1759        },
1760
1761        /**
1762         * Handles link click
1763         * @returns {KTMenu}
1764         */
1765        handleLinkClick: function(e) {
1766            var submenu = this.closest('.menu-item.menu-item-submenu');
1767
1768            // Trigger click event handlers
1769            var result = Plugin.eventTrigger('linkClick', this, e);
1770            if (result === false) {
1771                return;
1772            }
1773
1774            if ( submenu && Plugin.getSubmenuMode(submenu) === 'dropdown' ) {
1775                Plugin.hideSubmenuDropdowns();
1776            }
1777        },
1778
1779        /**
1780         * Handles submenu dropdown close on link click
1781         * @returns {KTMenu}
1782         */
1783        handleSubmenuDropdownClose: function(e, el) {
1784            // exit if its not submenu dropdown mode
1785            if (Plugin.getSubmenuMode(el) === 'accordion') {
1786                return;
1787            }
1788
1789            var shown = element.querySelectorAll('.menu-item.menu-item-submenu.menu-item-hover:not(.menu-item-tabs)');
1790
1791            // check if currently clicked link's parent item ha
1792            if (shown.length > 0 && KTUtil.hasClass(el, 'menu-toggle') === false && el.querySelectorAll('.menu-toggle').length === 0) {
1793                // close opened dropdown menus
1794                for (var i = 0, len = shown.length; i < len; i++) {
1795                    Plugin.hideSubmenuDropdown(shown[0], true);
1796                }
1797            }
1798        },
1799
1800        /**
1801         * helper functions
1802         * @returns {KTMenu}
1803         */
1804        handleSubmenuAccordion: function(e, el) {
1805            var query;
1806            var item = el ? el : this;
1807
1808            // Trigger click event handlers
1809            var result = Plugin.eventTrigger('submenuToggle', this, e);
1810            if (result === false) {
1811                return;
1812            }
1813
1814            if ( Plugin.getSubmenuMode(el) === 'dropdown' && (query = item.closest('.menu-item') ) ) {
1815                if (query.getAttribute('data-menu-submenu-mode') != 'accordion' ) {
1816                    e.preventDefault();
1817                    return;
1818                }
1819            }
1820
1821            var li = item.closest('.menu-item');
1822            var submenu = KTUtil.child(li, '.menu-submenu, .menu-inner');
1823
1824            if (KTUtil.hasClass(item.closest('.menu-item'), 'menu-item-open-always')) {
1825                return;
1826            }
1827
1828            if ( li && submenu ) {
1829                e.preventDefault();
1830                var speed = the.options.accordion.slideSpeed;
1831                var hasClosables = false;
1832
1833                if ( KTUtil.hasClass(li, 'menu-item-open') === false ) {
1834                    // hide other accordions
1835                    if ( the.options.accordion.expandAll === false ) {
1836                        var subnav = item.closest('.menu-nav, .menu-subnav');
1837                        var closables = KTUtil.children(subnav, '.menu-item.menu-item-open.menu-item-submenu:not(.menu-item-here):not(.menu-item-open-always)');
1838
1839                        if ( subnav && closables ) {
1840                            for (var i = 0, len = closables.length; i < len; i++) {
1841                                var el_ = closables[0];
1842                                var submenu_ = KTUtil.child(el_, '.menu-submenu');
1843                                if ( submenu_ ) {
1844                                    KTUtil.slideUp(submenu_, speed, function() {
1845                                        Plugin.scrollUpdate();
1846                                        KTUtil.removeClass(el_, 'menu-item-open');
1847                                    });
1848                                }
1849                            }
1850                        }
1851                    }
1852
1853                    KTUtil.slideDown(submenu, speed, function() {
1854                        Plugin.scrollToItem(item);
1855                        Plugin.scrollUpdate();
1856
1857                        Plugin.eventTrigger('submenuToggle', submenu, e);
1858                    });
1859
1860                    KTUtil.addClass(li, 'menu-item-open');
1861
1862                } else {
1863                    KTUtil.slideUp(submenu, speed, function() {
1864                        Plugin.scrollToItem(item);
1865                        Plugin.eventTrigger('submenuToggle', submenu, e);
1866                    });
1867
1868                    KTUtil.removeClass(li, 'menu-item-open');
1869                }
1870            }
1871        },
1872
1873        /**
1874         * scroll to item function
1875         * @returns {KTMenu}
1876         */
1877        scrollToItem: function(item) {
1878            // handle auto scroll for accordion submenus
1879            if ( KTUtil.isBreakpointUp('lg')  && the.options.accordion.autoScroll && element.getAttribute('data-menu-scroll') !== '1' ) {
1880                KTUtil.scrollTo(item, the.options.accordion.autoScrollSpeed);
1881            }
1882        },
1883
1884        /**
1885         * Hide submenu dropdown
1886         * @returns {KTMenu}
1887         */
1888        hideSubmenuDropdown: function(item, classAlso) {
1889            // remove submenu activation class
1890            if ( classAlso ) {
1891                KTUtil.removeClass(item, 'menu-item-hover');
1892                KTUtil.removeClass(item, 'menu-item-active-tab');
1893            }
1894
1895            // clear timeout
1896            item.removeAttribute('data-hover');
1897
1898            if ( item.getAttribute('data-menu-toggle-class') ) {
1899                KTUtil.removeClass(body, item.getAttribute('data-menu-toggle-class'));
1900            }
1901
1902            var timeout = item.getAttribute('data-timeout');
1903            item.removeAttribute('data-timeout');
1904            clearTimeout(timeout);
1905        },
1906
1907        /**
1908         * Hide submenu dropdowns
1909         * @returns {KTMenu}
1910         */
1911        hideSubmenuDropdowns: function() {
1912            var items;
1913            if ( items = element.querySelectorAll('.menu-item-submenu.menu-item-hover:not(.menu-item-tabs):not([data-menu-toggle="tab"])') ) {
1914                for (var j = 0, cnt = items.length; j < cnt; j++) {
1915                    Plugin.hideSubmenuDropdown(items[j], true);
1916                }
1917            }
1918        },
1919
1920        /**
1921         * helper functions
1922         * @returns {KTMenu}
1923         */
1924        showSubmenuDropdown: function(item) {
1925            // close active submenus
1926            var list = element.querySelectorAll('.menu-item-submenu.menu-item-hover, .menu-item-submenu.menu-item-active-tab');
1927
1928            if ( list ) {
1929                for (var i = 0, len = list.length; i < len; i++) {
1930                    var el = list[i];
1931                    if ( item !== el && el.contains(item) === false && item.contains(el) === false ) {
1932                        Plugin.hideSubmenuDropdown(el, true);
1933                    }
1934                }
1935            }
1936
1937            // add submenu activation class
1938            KTUtil.addClass(item, 'menu-item-hover');
1939
1940            // Change the alignment of submenu is offscreen.
1941            var submenu = KTUtil.find(item, '.menu-submenu');
1942
1943            if (submenu && submenu.hasAttribute('data-hor-direction') === false) {
1944                if (KTUtil.hasClass(submenu, 'menu-submenu-left')) {
1945                    submenu.setAttribute('data-hor-direction', 'menu-submenu-left');
1946                } else if (KTUtil.hasClass(submenu, 'menu-submenu-right')) {
1947                    submenu.setAttribute('data-hor-direction', 'menu-submenu-right');
1948                }
1949            }
1950
1951            if ( submenu && KTUtil.isOffscreen(submenu, 'left', 15) === true ) {
1952                KTUtil.removeClass(submenu, 'menu-submenu-left');
1953                KTUtil.addClass(submenu, 'menu-submenu-right');
1954            } else if ( submenu && KTUtil.isOffscreen(submenu, 'right', 15) === true ) {
1955                KTUtil.removeClass(submenu, 'menu-submenu-right');
1956                KTUtil.addClass(submenu, 'menu-submenu-left');
1957            }
1958
1959            if ( item.getAttribute('data-menu-toggle-class') ) {
1960                KTUtil.addClass(body, item.getAttribute('data-menu-toggle-class'));
1961            }
1962        },
1963
1964        /**
1965         * Handles submenu slide toggle
1966         * @returns {KTMenu}
1967         */
1968        createSubmenuDropdownClickDropoff: function(el) {
1969            var query;
1970            var zIndex = (query = KTUtil.child(el, '.menu-submenu') ? KTUtil.css(query, 'z-index') : 0) - 1;
1971
1972            var dropoff = document.createElement('<div class="menu-dropoff" style="background: transparent; position: fixed; top: 0; bottom: 0; left: 0; right: 0; z-index: ' + zIndex + '"></div>');
1973
1974            body.appendChild(dropoff);
1975
1976            KTUtil.addEvent(dropoff, 'click', function(e) {
1977                e.stopPropagation();
1978                e.preventDefault();
1979                KTUtil.remove(this);
1980                Plugin.hideSubmenuDropdown(el, true);
1981            });
1982        },
1983
1984        /**
1985         * Handles submenu hover toggle
1986         * @returns {KTMenu}
1987         */
1988        pauseDropdownHover: function(time) {
1989            var date = new Date();
1990
1991            the.pauseDropdownHoverTime = date.getTime() + time;
1992        },
1993
1994        /**
1995         * Handles submenu hover toggle
1996         * @returns {KTMenu}
1997         */
1998        resumeDropdownHover: function() {
1999            var date = new Date();
2000
2001            return (date.getTime() > the.pauseDropdownHoverTime ? true : false);
2002        },
2003
2004        /**
2005         * Reset menu's current active item
2006         * @returns {KTMenu}
2007         */
2008        resetActiveItem: function(item) {
2009            var list;
2010            var parents;
2011
2012            list = element.querySelectorAll('.menu-item-active');
2013
2014            for (var i = 0, len = list.length; i < len; i++) {
2015                var el = list[0];
2016                KTUtil.removeClass(el, 'menu-item-active');
2017                KTUtil.hide( KTUtil.child(el, '.menu-submenu') );
2018                parents = KTUtil.parents(el, '.menu-item-submenu') || [];
2019
2020                for (var i_ = 0, len_ = parents.length; i_ < len_; i_++) {
2021                    var el_ = parents[i];
2022                    KTUtil.removeClass(el_, 'menu-item-open');
2023                    KTUtil.hide( KTUtil.child(el_, '.menu-submenu') );
2024                }
2025            }
2026
2027            // close open submenus
2028            if ( the.options.accordion.expandAll === false ) {
2029                if ( list = element.querySelectorAll('.menu-item-open') ) {
2030                    for (var i = 0, len = list.length; i < len; i++) {
2031                        KTUtil.removeClass(parents[0], 'menu-item-open');
2032                    }
2033                }
2034            }
2035        },
2036
2037        /**
2038         * Sets menu's active item
2039         * @returns {KTMenu}
2040         */
2041        setActiveItem: function(item) {
2042            // reset current active item
2043            Plugin.resetActiveItem();
2044
2045            var parents = KTUtil.parents(item, '.menu-item-submenu') || [];
2046            for (var i = 0, len = parents.length; i < len; i++) {
2047                KTUtil.addClass(parents[i], 'menu-item-open');
2048            }
2049
2050            KTUtil.addClass(item, 'menu-item-active');
2051        },
2052
2053        /**
2054         * Returns page breadcrumbs for the menu's active item
2055         * @returns {KTMenu}
2056         */
2057        getBreadcrumbs: function(item) {
2058            var query;
2059            var breadcrumbs = [];
2060            var link = KTUtil.child(item, '.menu-link');
2061
2062            breadcrumbs.push({
2063                text: (query = KTUtil.child(link, '.menu-text') ? query.innerHTML : ''),
2064                title: link.getAttribute('title'),
2065                href: link.getAttribute('href')
2066            });
2067
2068            var parents = KTUtil.parents(item, '.menu-item-submenu');
2069            for (var i = 0, len = parents.length; i < len; i++) {
2070                var submenuLink = KTUtil.child(parents[i], '.menu-link');
2071
2072                breadcrumbs.push({
2073                    text: (query = KTUtil.child(submenuLink, '.menu-text') ? query.innerHTML : ''),
2074                    title: submenuLink.getAttribute('title'),
2075                    href: submenuLink.getAttribute('href')
2076                });
2077            }
2078
2079            return  breadcrumbs.reverse();
2080        },
2081
2082        /**
2083         * Returns page title for the menu's active item
2084         * @returns {KTMenu}
2085         */
2086        getPageTitle: function(item) {
2087            var query;
2088
2089            return (query = KTUtil.child(item, '.menu-text') ? query.innerHTML : '');
2090        },
2091
2092        /**
2093         * Trigger events
2094         */
2095        eventTrigger: function(name, target, e) {
2096            for (var i = 0; i < the.events.length; i++ ) {
2097                var event = the.events[i];
2098                if ( event.name == name ) {
2099                    if ( event.one == true ) {
2100                        if ( event.fired == false ) {
2101                            the.events[i].fired = true;
2102                            return event.handler.call(this, target, e);
2103                        }
2104                    } else {
2105                        return event.handler.call(this, target, e);
2106                    }
2107                }
2108            }
2109        },
2110
2111        addEvent: function(name, handler, one) {
2112            the.events.push({
2113                name: name,
2114                handler: handler,
2115                one: one,
2116                fired: false
2117            });
2118        },
2119
2120        removeEvent: function(name) {
2121            if (the.events[name]) {
2122                delete the.events[name];
2123            }
2124        }
2125    };
2126
2127    //////////////////////////
2128    // ** Public Methods ** //
2129    //////////////////////////
2130
2131    /**
2132     * Set default options
2133     */
2134
2135    the.setDefaults = function(options) {
2136        defaultOptions = options;
2137    };
2138
2139    /**
2140     * Update scroll
2141     */
2142    the.scrollUpdate = function() {
2143        return Plugin.scrollUpdate();
2144    };
2145
2146    /**
2147     * Re-init scroll
2148     */
2149    the.scrollReInit = function() {
2150        return Plugin.scrollInit();
2151    };
2152
2153    /**
2154     * Scroll top
2155     */
2156    the.scrollTop = function() {
2157        return Plugin.scrollTop();
2158    };
2159
2160    /**
2161     * Set active menu item
2162     */
2163    the.setActiveItem = function(item) {
2164        return Plugin.setActiveItem(item);
2165    };
2166
2167    the.reload = function() {
2168        return Plugin.reload();
2169    };
2170
2171    the.update = function(options) {
2172        return Plugin.update(options);
2173    };
2174
2175    /**
2176     * Set breadcrumb for menu item
2177     */
2178    the.getBreadcrumbs = function(item) {
2179        return Plugin.getBreadcrumbs(item);
2180    };
2181
2182    /**
2183     * Set page title for menu item
2184     */
2185    the.getPageTitle = function(item) {
2186        return Plugin.getPageTitle(item);
2187    };
2188
2189    /**
2190     * Get submenu mode
2191     */
2192    the.getSubmenuMode = function(el) {
2193        return Plugin.getSubmenuMode(el);
2194    };
2195
2196    /**
2197     * Hide dropdown
2198     * @returns {Object}
2199     */
2200    the.hideDropdown = function(item) {
2201        Plugin.hideSubmenuDropdown(item, true);
2202    };
2203
2204    /**
2205     * Hide dropdowns
2206     * @returns {Object}
2207     */
2208    the.hideDropdowns = function() {
2209        Plugin.hideSubmenuDropdowns();
2210    };
2211
2212    /**
2213     * Disable menu for given time
2214     * @returns {Object}
2215     */
2216    the.pauseDropdownHover = function(time) {
2217        Plugin.pauseDropdownHover(time);
2218    };
2219
2220    /**
2221     * Disable menu for given time
2222     * @returns {Object}
2223     */
2224    the.resumeDropdownHover = function() {
2225        return Plugin.resumeDropdownHover();
2226    };
2227
2228    /**
2229     * Register event
2230     */
2231    the.on = function(name, handler) {
2232        return Plugin.addEvent(name, handler);
2233    };
2234
2235    the.off = function(name) {
2236        return Plugin.removeEvent(name);
2237    };
2238
2239    the.one = function(name, handler) {
2240        return Plugin.addEvent(name, handler, true);
2241    };
2242
2243    ///////////////////////////////
2244    // ** Plugin Construction ** //
2245    ///////////////////////////////
2246
2247    // Run plugin
2248    Plugin.construct.apply(the, [options]);
2249
2250    // Handle plugin on window resize
2251    KTUtil.addResizeHandler(function() {
2252        if (init) {
2253            the.reload();
2254        }
2255    });
2256
2257    // Init done
2258    init = true;
2259
2260    // Return plugin instance
2261    return the;
2262};
2263
2264// webpack support
2265if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
2266    module.exports = KTMenu;
2267}
2268
2269// Plugin global lazy initialization
2270document.addEventListener("click", function (e) {
2271    var body = KTUtil.getByTagName('body')[0];
2272    var query;
2273    if ( query = body.querySelectorAll('.menu-nav .menu-item.menu-item-submenu.menu-item-hover:not(.menu-item-tabs)[data-menu-toggle="click"]') ) {
2274        for (var i = 0, len = query.length; i < len; i++) {
2275            var element = query[i].closest('.menu-nav').parentNode;
2276
2277            if ( element ) {
2278                var the = KTUtil.data(element).get('menu');
2279
2280                if ( !the ) {
2281                    break;
2282                }
2283
2284                if ( !the || the.getSubmenuMode() !== 'dropdown' ) {
2285                    break;
2286                }
2287
2288                if ( e.target !== element && element.contains(e.target) === false ) {
2289                    the.hideDropdowns();
2290                }
2291            }
2292        }
2293    }
2294});
2295
2296"use strict";
2297
2298// Component Definition
2299var KTOffcanvas = function(elementId, options) {
2300    // Main object
2301    var the = this;
2302    var init = false;
2303
2304    // Get element object
2305    var element = KTUtil.getById(elementId);
2306    var body = KTUtil.getBody();
2307
2308    if (!element) {
2309        return;
2310    }
2311
2312    // Default options
2313    var defaultOptions = {
2314        attrCustom: ''
2315    };
2316
2317    ////////////////////////////
2318    // ** Private Methods  ** //
2319    ////////////////////////////
2320
2321    var Plugin = {
2322        construct: function(options) {
2323            if (KTUtil.data(element).has('offcanvas')) {
2324                the = KTUtil.data(element).get('offcanvas');
2325            } else {
2326                // Reset offcanvas
2327                Plugin.init(options);
2328
2329                // Build offcanvas
2330                Plugin.build();
2331
2332                KTUtil.data(element).set('offcanvas', the);
2333            }
2334
2335            return the;
2336        },
2337
2338        init: function(options) {
2339            the.events = [];
2340
2341            // merge default and user defined options
2342            the.options = KTUtil.deepExtend({}, defaultOptions, options);
2343
2344            the.classBase = the.options.baseClass;
2345            the.attrCustom = the.options.attrCustom;
2346            the.classShown = the.classBase + '-on';
2347            the.classOverlay = the.classBase + '-overlay';
2348            the.target;
2349
2350            the.state = KTUtil.hasClass(element, the.classShown) ? 'shown' : 'hidden';
2351        },
2352
2353        build: function() {
2354            // offcanvas toggle
2355            if (the.options.toggleBy) {
2356                if (typeof the.options.toggleBy === 'string') {
2357                    KTUtil.addEvent(KTUtil.getById(the.options.toggleBy), 'click', function(e) {
2358                        e.preventDefault();
2359                        the.target = this;
2360                        Plugin.toggle();
2361                    });
2362                } else if (the.options.toggleBy && the.options.toggleBy[0]) {
2363                    if (the.options.toggleBy[0].target) {
2364                        for (var i in the.options.toggleBy) {
2365                            KTUtil.addEvent(KTUtil.getById(the.options.toggleBy[i].target), 'click', function(e) {
2366                                e.preventDefault();
2367                                the.target = this;
2368                                Plugin.toggle();
2369                            });
2370                        }
2371                    } else {
2372                        for (var i in the.options.toggleBy) {
2373                            KTUtil.addEvent(KTUtil.getById(the.options.toggleBy[i]), 'click', function(e) {
2374                                e.preventDefault();
2375                                the.target = this;
2376                                Plugin.toggle();
2377                            });
2378                        }
2379                    }
2380
2381                } else if (the.options.toggleBy && the.options.toggleBy.target) {
2382                    KTUtil.addEvent( KTUtil.getById(the.options.toggleBy.target), 'click', function(e) {
2383                        e.preventDefault();
2384                        the.target = this;
2385                        Plugin.toggle();
2386                    });
2387                }
2388            }
2389
2390            // offcanvas close
2391            var closeBy = KTUtil.getById(the.options.closeBy);
2392            if (closeBy) {
2393                KTUtil.addEvent(closeBy, 'click', function(e) {
2394                    e.preventDefault();
2395                    the.target = this;
2396                    Plugin.hide();
2397                });
2398            }
2399        },
2400
2401        isShown: function() {
2402            return (the.state == 'shown' ? true : false);
2403        },
2404
2405        toggle: function() {;
2406            Plugin.eventTrigger('toggle');
2407
2408            if (the.state == 'shown') {
2409                Plugin.hide();
2410            } else {
2411                Plugin.show();
2412            }
2413        },
2414
2415        show: function() {
2416            if (the.state == 'shown') {
2417                return;
2418            }
2419
2420            Plugin.eventTrigger('beforeShow');
2421
2422            Plugin.toggleClass('show');
2423
2424            // Offcanvas panel
2425            KTUtil.attr(body, 'data-offcanvas-' + the.classBase, 'on');
2426            KTUtil.addClass(element, the.classShown);
2427
2428            if (the.attrCustom.length > 0) {
2429                KTUtil.attr(body, 'data-offcanvas-' + the.classCustom, 'on');
2430                //KTUtil.addClass(body, the.classCustom);
2431            }
2432
2433            the.state = 'shown';
2434
2435            if (the.options.overlay) {
2436                the.overlay = KTUtil.insertAfter(document.createElement('DIV') , element );
2437                KTUtil.addClass(the.overlay, the.classOverlay);
2438
2439                KTUtil.addEvent(the.overlay, 'click', function(e) {
2440                    //e.stopPropagation();
2441                    e.preventDefault();
2442                    Plugin.hide(the.target);
2443                });
2444            }
2445
2446            Plugin.eventTrigger('afterShow');
2447        },
2448
2449        hide: function() {
2450            if (the.state == 'hidden') {
2451                return;
2452            }
2453
2454            Plugin.eventTrigger('beforeHide');
2455
2456            Plugin.toggleClass('hide');
2457
2458            KTUtil.removeAttr(body, 'data-offcanvas-' + the.classBase);
2459            KTUtil.removeClass(element, the.classShown);
2460
2461            if (the.attrCustom.length > 0) {
2462                KTUtil.removeAttr(body, 'data-offcanvas-' + the.attrCustom);
2463            }
2464
2465            the.state = 'hidden';
2466
2467            if (the.options.overlay && the.overlay) {
2468                KTUtil.remove(the.overlay);
2469            }
2470
2471            Plugin.eventTrigger('afterHide');
2472        },
2473
2474        toggleClass: function(mode) {
2475            var id = KTUtil.attr(the.target, 'id');
2476            var toggleBy;
2477
2478            if (the.options.toggleBy && the.options.toggleBy[0] && the.options.toggleBy[0].target) {
2479                for (var i in the.options.toggleBy) {
2480                    if (the.options.toggleBy[i].target === id) {
2481                        toggleBy = the.options.toggleBy[i];
2482                    }
2483                }
2484            } else if (the.options.toggleBy && the.options.toggleBy.target) {
2485                toggleBy = the.options.toggleBy;
2486            }
2487
2488            if (toggleBy) {
2489                var el = KTUtil.getById(toggleBy.target);
2490
2491                if (mode === 'show') {
2492                    KTUtil.addClass(el, toggleBy.state);
2493                }
2494
2495                if (mode === 'hide') {
2496                    KTUtil.removeClass(el, toggleBy.state);
2497                }
2498            }
2499        },
2500
2501        eventTrigger: function(name, args) {
2502            for (var i = 0; i < the.events.length; i++) {
2503                var event = the.events[i];
2504                if (event.name == name) {
2505                    if (event.one == true) {
2506                        if (event.fired == false) {
2507                            the.events[i].fired = true;
2508                            return event.handler.call(this, the, args);
2509                        }
2510                    } else {
2511                        return event.handler.call(this, the, args);
2512                    }
2513                }
2514            }
2515        },
2516
2517        addEvent: function(name, handler, one) {
2518            the.events.push({
2519                name: name,
2520                handler: handler,
2521                one: one,
2522                fired: false
2523            });
2524        }
2525    };
2526
2527    //////////////////////////
2528    // ** Public Methods ** //
2529    //////////////////////////
2530
2531    /**
2532     * Set default options
2533     * @param options
2534     */
2535    the.setDefaults = function(options) {
2536        defaultOptions = options;
2537    };
2538
2539    /**
2540     * Check if canvas is shown
2541     * @returns {boolean}
2542     */
2543    the.isShown = function() {
2544        return Plugin.isShown();
2545    };
2546
2547    /**
2548     * Set to hide the canvas
2549     */
2550    the.hide = function() {
2551        return Plugin.hide();
2552    };
2553
2554    /**
2555     * Set to show the canvas
2556     */
2557    the.show = function() {
2558        return Plugin.show();
2559    };
2560
2561    /**
2562     * Attach event
2563     * @param name
2564     * @param handler
2565     */
2566    the.on = function(name, handler) {
2567        return Plugin.addEvent(name, handler);
2568    };
2569
2570    /**
2571     * Attach event that will be fired once
2572     * @param name
2573     * @param handler
2574     */
2575    the.one = function(name, handler) {
2576        return Plugin.addEvent(name, handler, true);
2577    };
2578
2579    ///////////////////////////////
2580    // ** Plugin Construction ** //
2581    ///////////////////////////////
2582
2583    // Run plugin
2584    Plugin.construct.apply(the, [options]);
2585
2586    // Init done
2587    init = true;
2588
2589    // Return plugin instance
2590    return the;
2591};
2592
2593// webpack support
2594if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
2595    module.exports = KTOffcanvas;
2596}
2597
2598"use strict";
2599
2600// Component Definition
2601var KTScrolltop = function(elementId, options) {
2602    // Main object
2603    var the = this;
2604    var init = false;
2605
2606    // Get element object
2607    var element = KTUtil.getById(elementId);
2608    var body = KTUtil.getBody();
2609
2610    if (!element) {
2611        return;
2612    }
2613
2614    // Default options
2615    var defaultOptions = {
2616        offset: 300,
2617        speed: 6000
2618    };
2619
2620    ////////////////////////////
2621    // ** Private Methods  ** //
2622    ////////////////////////////
2623
2624    var Plugin = {
2625        /**
2626         * Run plugin
2627         * @returns {mscrolltop}
2628         */
2629        construct: function(options) {
2630            if (KTUtil.data(element).has('scrolltop')) {
2631                the = KTUtil.data(element).get('scrolltop');
2632            } else {
2633                // reset scrolltop
2634                Plugin.init(options);
2635
2636                // build scrolltop
2637                Plugin.build();
2638
2639                KTUtil.data(element).set('scrolltop', the);
2640            }
2641
2642            return the;
2643        },
2644
2645        /**
2646         * Handles subscrolltop click toggle
2647         * @returns {mscrolltop}
2648         */
2649        init: function(options) {
2650            the.events = [];
2651
2652            // merge default and user defined options
2653            the.options = KTUtil.deepExtend({}, defaultOptions, options);
2654        },
2655
2656        build: function() {
2657            var timer;
2658
2659            window.addEventListener('scroll', function() {
2660                KTUtil.throttle(timer, function() {
2661                    Plugin.handle();
2662                }, 200);
2663            });
2664
2665            // handle button click
2666            KTUtil.addEvent(element, 'click', Plugin.scroll);
2667        },
2668
2669        /**
2670         * Handles scrolltop click scrollTop
2671         */
2672        handle: function() {
2673            var pos = KTUtil.getScrollTop(); // current vertical position
2674
2675            if (pos > the.options.offset) {
2676                if (body.hasAttribute('data-scrolltop') === false) {
2677                    body.setAttribute('data-scrolltop', 'on');
2678                }
2679            } else {
2680                if (body.hasAttribute('data-scrolltop') === true) {
2681                    body.removeAttribute('data-scrolltop');
2682                }
2683            }
2684        },
2685
2686        /**
2687         * Handles scrolltop click scrollTop
2688         */
2689        scroll: function(e) {
2690            e.preventDefault();
2691
2692            KTUtil.scrollTop(0, the.options.speed);
2693        },
2694
2695
2696        /**
2697         * Trigger events
2698         */
2699        eventTrigger: function(name, args) {
2700            for (var i = 0; i < the.events.length; i++) {
2701                var event = the.events[i];
2702                if (event.name == name) {
2703                    if (event.one == true) {
2704                        if (event.fired == false) {
2705                            the.events[i].fired = true;
2706                            return event.handler.call(this, the, args);
2707                        }
2708                    } else {
2709                       return event.handler.call(this, the, args);
2710                    }
2711                }
2712            }
2713        },
2714
2715        addEvent: function(name, handler, one) {
2716            the.events.push({
2717                name: name,
2718                handler: handler,
2719                one: one,
2720                fired: false
2721            });
2722        }
2723    };
2724
2725    //////////////////////////
2726    // ** Public Methods ** //
2727    //////////////////////////
2728
2729    /**
2730     * Set default options
2731     */
2732
2733    the.setDefaults = function(options) {
2734        defaultOptions = options;
2735    };
2736
2737    /**
2738     * Get subscrolltop mode
2739     */
2740    the.on = function(name, handler) {
2741        return Plugin.addEvent(name, handler);
2742    };
2743
2744    /**
2745     * Set scrolltop content
2746     * @returns {mscrolltop}
2747     */
2748    the.one = function(name, handler) {
2749        return Plugin.addEvent(name, handler, true);
2750    };
2751
2752    ///////////////////////////////
2753    // ** Plugin Construction ** //
2754    ///////////////////////////////
2755
2756    // Run plugin
2757    Plugin.construct.apply(the, [options]);
2758
2759    // Init done
2760    init = true;
2761
2762    // Return plugin instance
2763    return the;
2764};
2765
2766// webpack support
2767if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
2768    module.exports = KTScrolltop;
2769}
2770
2771"use strict";
2772
2773// Component Definition
2774var KTToggle = function(toggleElement, targetElement, options) {
2775    // Main object
2776    var the = this;
2777    var init = false;
2778
2779    // Get element object
2780    var element = toggleElement;
2781    var target = targetElement;
2782
2783    if (!element) {
2784        return;
2785    }
2786
2787    // Default options
2788    var defaultOptions = {
2789        targetToggleMode: 'class' // class|attribute
2790    };
2791
2792    ////////////////////////////
2793    // ** Private Methods  ** //
2794    ////////////////////////////
2795
2796    var Plugin = {
2797        /**
2798         * Construct
2799         */
2800
2801        construct: function(options) {
2802            if (KTUtil.data(element).has('toggle')) {
2803                the = KTUtil.data(element).get('toggle');
2804            } else {
2805                // reset menu
2806                Plugin.init(options);
2807
2808                // build menu
2809                Plugin.build();
2810
2811                KTUtil.data(element).set('toggle', the);
2812            }
2813
2814            return the;
2815        },
2816
2817        /**
2818         * Handles subtoggle click toggle
2819         */
2820        init: function(options) {
2821            the.element = element;
2822            the.events = [];
2823
2824            // Merge default and user defined options
2825            the.options = KTUtil.deepExtend({}, defaultOptions, options);
2826
2827            //alert(the.options.target.tagName);
2828            the.target = target;
2829
2830            the.targetState = the.options.targetState;
2831            the.toggleState = the.options.toggleState;
2832
2833            if (the.options.targetToggleMode == 'class') {
2834                the.state = KTUtil.hasClasses(the.target, the.targetState) ? 'on' : 'off';
2835            } else {
2836                the.state = KTUtil.hasAttr(the.target, 'data-' + the.targetState) ? KTUtil.attr(the.target, 'data-' + the.targetState) : 'off';
2837            }
2838        },
2839
2840        /**
2841         * Setup toggle
2842         */
2843        build: function() {
2844            KTUtil.addEvent(element, 'mouseup', Plugin.toggle);
2845        },
2846
2847        /**
2848         * Handles offcanvas click toggle
2849         */
2850        toggle: function(e) {
2851            Plugin.eventTrigger('beforeToggle');
2852
2853            if (the.state == 'off') {
2854                Plugin.toggleOn();
2855            } else {
2856                Plugin.toggleOff();
2857            }
2858
2859            Plugin.eventTrigger('afterToggle');
2860
2861            e.preventDefault();
2862
2863            return the;
2864        },
2865
2866        /**
2867         * Handles toggle click toggle
2868         */
2869        toggleOn: function() {
2870            Plugin.eventTrigger('beforeOn');
2871
2872            if (the.options.targetToggleMode == 'class') {
2873                KTUtil.addClass(the.target, the.targetState);
2874            } else {
2875                KTUtil.attr(the.target, 'data-' + the.targetState, 'on');
2876            }
2877
2878            if (the.toggleState) {
2879                KTUtil.addClass(element, the.toggleState);
2880            }
2881
2882            the.state = 'on';
2883
2884            Plugin.eventTrigger('afterOn');
2885
2886            Plugin.eventTrigger('toggle');
2887
2888            return the;
2889        },
2890
2891        /**
2892         * Handles toggle click toggle
2893         */
2894        toggleOff: function() {
2895            Plugin.eventTrigger('beforeOff');
2896
2897            if (the.options.targetToggleMode == 'class') {
2898                KTUtil.removeClass(the.target, the.targetState);
2899            } else {
2900                KTUtil.removeAttr(the.target, 'data-' + the.targetState);
2901            }
2902
2903            if (the.toggleState) {
2904                KTUtil.removeClass(element, the.toggleState);
2905            }
2906
2907            the.state = 'off';
2908
2909            Plugin.eventTrigger('afterOff');
2910
2911            Plugin.eventTrigger('toggle');
2912
2913            return the;
2914        },
2915
2916        /**
2917         * Trigger events
2918         */
2919        eventTrigger: function(name) {
2920            for (var i = 0; i < the.events.length; i++) {
2921                var event = the.events[i];
2922
2923                if (event.name == name) {
2924                    if (event.one == true) {
2925                        if (event.fired == false) {
2926                            the.events[i].fired = true;
2927                            return event.handler.call(this, the);
2928                        }
2929                    } else {
2930                        return event.handler.call(this, the);
2931                    }
2932                }
2933            }
2934        },
2935
2936        addEvent: function(name, handler, one) {
2937            the.events.push({
2938                name: name,
2939                handler: handler,
2940                one: one,
2941                fired: false
2942            });
2943
2944            return the;
2945        }
2946    };
2947
2948    //////////////////////////
2949    // ** Public Methods ** //
2950    //////////////////////////
2951
2952    /**
2953     * Set default options
2954     */
2955
2956    the.setDefaults = function(options) {
2957        defaultOptions = options;
2958    };
2959
2960    /**
2961     * Get toggle state
2962     */
2963    the.getState = function() {
2964        return the.state;
2965    };
2966
2967    /**
2968     * Toggle
2969     */
2970    the.toggle = function() {
2971        return Plugin.toggle();
2972    };
2973
2974    /**
2975     * Toggle on
2976     */
2977    the.toggleOn = function() {
2978        return Plugin.toggleOn();
2979    };
2980
2981    /**
2982     * Toggle off
2983     */
2984    the.toggleOff = function() {
2985        return Plugin.toggleOff();
2986    };
2987
2988    /**
2989     * Attach event
2990     * @returns {KTToggle}
2991     */
2992    the.on = function(name, handler) {
2993        return Plugin.addEvent(name, handler);
2994    };
2995
2996    /**
2997     * Attach event that will be fired once
2998     * @returns {KTToggle}
2999     */
3000    the.one = function(name, handler) {
3001        return Plugin.addEvent(name, handler, true);
3002    };
3003
3004    // Construct plugin
3005    Plugin.construct.apply(the, [options]);
3006
3007    return the;
3008};
3009
3010// webpack support
3011if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
3012    module.exports = KTToggle;
3013}
3014
3015"use strict";
3016
3017/**
3018 * @class KTUtil  base utilize class that privides helper functions
3019 */
3020
3021// Polyfills
3022/**
3023 * Element.matches() polyfill (simple version)
3024 * https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
3025 */
3026if (!Element.prototype.matches) {
3027	Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
3028}
3029
3030/**
3031 * Element.closest() polyfill
3032 * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
3033 */
3034if (!Element.prototype.closest) {
3035	if (!Element.prototype.matches) {
3036		Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
3037	}
3038	Element.prototype.closest = function (s) {
3039		var el = this;
3040		var ancestor = this;
3041		if (!document.documentElement.contains(el)) return null;
3042		do {
3043			if (ancestor.matches(s)) return ancestor;
3044			ancestor = ancestor.parentElement;
3045		} while (ancestor !== null);
3046		return null;
3047	};
3048}
3049
3050/**
3051 * ChildNode.remove() polyfill
3052 * https://gomakethings.com/removing-an-element-from-the-dom-the-es6-way/
3053 * @author Chris Ferdinandi
3054 * @license MIT
3055 */
3056(function (elem) {
3057	for (var i = 0; i < elem.length; i++) {
3058		if (!window[elem[i]] || 'remove' in window[elem[i]].prototype) continue;
3059		window[elem[i]].prototype.remove = function () {
3060			this.parentNode.removeChild(this);
3061		};
3062	}
3063})(['Element', 'CharacterData', 'DocumentType']);
3064
3065
3066//
3067// requestAnimationFrame polyfill by Erik Möller.
3068//  With fixes from Paul Irish and Tino Zijdel
3069//
3070//  http://paulirish.com/2011/requestanimationframe-for-smart-animating/
3071//  http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
3072//
3073//  MIT license
3074//
3075(function() {
3076    var lastTime = 0;
3077    var vendors = ['webkit', 'moz'];
3078    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
3079        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
3080        window.cancelAnimationFrame =
3081            window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
3082    }
3083
3084    if (!window.requestAnimationFrame)
3085        window.requestAnimationFrame = function(callback) {
3086            var currTime = new Date().getTime();
3087            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
3088            var id = window.setTimeout(function() {
3089                callback(currTime + timeToCall);
3090            }, timeToCall);
3091            lastTime = currTime + timeToCall;
3092            return id;
3093        };
3094
3095    if (!window.cancelAnimationFrame)
3096        window.cancelAnimationFrame = function(id) {
3097            clearTimeout(id);
3098        };
3099}());
3100
3101// Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/prepend()/prepend().md
3102(function(arr) {
3103    arr.forEach(function(item) {
3104        if (item.hasOwnProperty('prepend')) {
3105            return;
3106        }
3107        Object.defineProperty(item, 'prepend', {
3108            configurable: true,
3109            enumerable: true,
3110            writable: true,
3111            value: function prepend() {
3112                var argArr = Array.prototype.slice.call(arguments),
3113                    docFrag = document.createDocumentFragment();
3114
3115                argArr.forEach(function(argItem) {
3116                    var isNode = argItem instanceof Node;
3117                    docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
3118                });
3119
3120                this.insertBefore(docFrag, this.firstChild);
3121            }
3122        });
3123    });
3124})([Element.prototype, Document.prototype, DocumentFragment.prototype]);
3125
3126// getAttributeNames
3127if (Element.prototype.getAttributeNames == undefined) {
3128  Element.prototype.getAttributeNames = function () {
3129    var attributes = this.attributes;
3130    var length = attributes.length;
3131    var result = new Array(length);
3132    for (var i = 0; i < length; i++) {
3133      result[i] = attributes[i].name;
3134    }
3135    return result;
3136  };
3137}
3138
3139// Global variables
3140window.KTUtilElementDataStore = {};
3141window.KTUtilElementDataStoreID = 0;
3142window.KTUtilDelegatedEventHandlers = {};
3143
3144var KTUtil = function() {
3145    var resizeHandlers = [];
3146
3147    /** @type {object} breakpoints The device width breakpoints **/
3148    var breakpoints = {
3149        sm: 544, // Small screen / phone
3150        md: 768, // Medium screen / tablet
3151        lg: 992, // Large screen / desktop
3152        xl: 1200 // Extra large screen / wide desktop
3153    };
3154
3155    /**
3156     * Handle window resize event with some
3157     * delay to attach event handlers upon resize complete
3158     */
3159    var _windowResizeHandler = function() {
3160        var _runResizeHandlers = function() {
3161            // reinitialize other subscribed elements
3162            for (var i = 0; i < resizeHandlers.length; i++) {
3163                var each = resizeHandlers[i];
3164                each.call();
3165            }
3166        };
3167
3168        var timer;
3169
3170        window.addEventListener('resize', function() {
3171            KTUtil.throttle(timer, function() {
3172                _runResizeHandlers();
3173            }, 200);
3174        });
3175    };
3176
3177    return {
3178        /**
3179         * Class main initializer.
3180         * @param {object} settings.
3181         * @returns null
3182         */
3183        //main function to initiate the theme
3184        init: function(settings) {
3185            if (settings && settings.breakpoints) {
3186                breakpoints = settings.breakpoints;
3187            }
3188
3189            _windowResizeHandler();
3190        },
3191
3192        /**
3193         * Adds window resize event handler.
3194         * @param {function} callback function.
3195         */
3196        addResizeHandler: function(callback) {
3197            resizeHandlers.push(callback);
3198        },
3199
3200        /**
3201         * Removes window resize event handler.
3202         * @param {function} callback function.
3203         */
3204        removeResizeHandler: function(callback) {
3205            for (var i = 0; i < resizeHandlers.length; i++) {
3206                if (callback === resizeHandlers[i]) {
3207                    delete resizeHandlers[i];
3208                }
3209            }
3210        },
3211
3212        /**
3213         * Trigger window resize handlers.
3214         */
3215        runResizeHandlers: function() {
3216            _runResizeHandlers();
3217        },
3218
3219        resize: function() {
3220            if (typeof(Event) === 'function') {
3221                // modern browsers
3222                window.dispatchEvent(new Event('resize'));
3223            } else {
3224                // for IE and other old browsers
3225                // causes deprecation warning on modern browsers
3226                var evt = window.document.createEvent('UIEvents');
3227                evt.initUIEvent('resize', true, false, window, 0);
3228                window.dispatchEvent(evt);
3229            }
3230        },
3231
3232        /**
3233         * Get GET parameter value from URL.
3234         * @param {string} paramName Parameter name.
3235         * @returns {string}
3236         */
3237        getURLParam: function(paramName) {
3238            var searchString = window.location.search.substring(1),
3239                i, val, params = searchString.split("&");
3240
3241            for (i = 0; i < params.length; i++) {
3242                val = params[i].split("=");
3243                if (val[0] == paramName) {
3244                    return unescape(val[1]);
3245                }
3246            }
3247
3248            return null;
3249        },
3250
3251        /**
3252         * Checks whether current device is mobile touch.
3253         * @returns {boolean}
3254         */
3255        isMobileDevice: function() {
3256            var test = (this.getViewPort().width < this.getBreakp
3256oint('lg') ? true : false);
3257
3258            if (test === false) {
3259                // For use within normal web clients
3260                test = navigator.userAgent.match(/iPad/i) != null;
3261            }
3262
3263            return test;
3264        },
3265
3266        /**
3267         * Checks whether current device is desktop.
3268         * @returns {boolean}
3269         */
3270        isDesktopDevice: function() {
3271            return KTUtil.isMobileDevice() ? false : true;
3272        },
3273
3274        /**
3275         * Gets browser window viewport size. Ref:
3276         * http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/
3277         * @returns {object}
3278         */
3279        getViewPort: function() {
3280            var e = window,
3281                a = 'inner';
3282            if (!('innerWidth' in window)) {
3283                a = 'client';
3284                e = document.documentElement || document.body;
3285            }
3286
3287            return {
3288                width: e[a + 'Width'],
3289                height: e[a + 'Height']
3290            };
3291        },
3292
3293        /**
3294         * Checks whether given device mode is currently activated.
3295         * @param {string} mode Responsive mode name(e.g: desktop,
3296         *     desktop-and-tablet, tablet, tablet-and-mobile, mobile)
3297         * @returns {boolean}
3298         */
3299        isInResponsiveRange: function(mode) {
3300            var breakpoint = this.getViewPort().width;
3301
3302            if (mode == 'general') {
3303                return true;
3304            } else if (mode == 'desktop' && breakpoint >= (this.getBreakpoint('lg') + 1)) {
3305                return true;
3306            } else if (mode == 'tablet' && (breakpoint >= (this.getBreakpoint('md') + 1) && breakpoint < this.getBreakpoint('lg'))) {
3307                return true;
3308            } else if (mode == 'mobile' && breakpoint <= this.getBreakpoint('md')) {
3309                return true;
3310            } else if (mode == 'desktop-and-tablet' && breakpoint >= (this.getBreakpoint('md') + 1)) {
3311                return true;
3312            } else if (mode == 'tablet-and-mobile' && breakpoint <= this.getBreakpoint('lg')) {
3313                return true;
3314            } else if (mode == 'minimal-desktop-and-below' && breakpoint <= this.getBreakpoint('xl')) {
3315                return true;
3316            }
3317
3318            return false;
3319        },
3320
3321		/**
3322         * Checks whether given device mode is currently activated.
3323         * @param {string} mode Responsive mode name(e.g: desktop,
3324         *     desktop-and-tablet, tablet, tablet-and-mobile, mobile)
3325         * @returns {boolean}
3326         */
3327        isBreakpointUp: function(mode) {
3328            var width = this.getViewPort().width;
3329			var breakpoint = this.getBreakpoint(mode);
3330
3331			return (width >= breakpoint);
3332        },
3333
3334		isBreakpointDown: function(mode) {
3335            var width = this.getViewPort().width;
3336			var breakpoint = this.getBreakpoint(mode);
3337
3338			return (width < breakpoint);
3339        },
3340
3341        /**
3342         * Generates unique ID for give prefix.
3343         * @param {string} prefix Prefix for generated ID
3344         * @returns {boolean}
3345         */
3346        getUniqueID: function(prefix) {
3347            return prefix + Math.floor(Math.random() * (new Date()).getTime());
3348        },
3349
3350        /**
3351         * Gets window width for give breakpoint mode.
3352         * @param {string} mode Responsive mode name(e.g: xl, lg, md, sm)
3353         * @returns {number}
3354         */
3355        getBreakpoint: function(mode) {
3356            return breakpoints[mode];
3357        },
3358
3359        /**
3360         * Checks whether object has property matchs given key path.
3361         * @param {object} obj Object contains values paired with given key path
3362         * @param {string} keys Keys path seperated with dots
3363         * @returns {object}
3364         */
3365        isset: function(obj, keys) {
3366            var stone;
3367
3368            keys = keys || '';
3369
3370            if (keys.indexOf('[') !== -1) {
3371                throw new Error('Unsupported object path notation.');
3372            }
3373
3374            keys = keys.split('.');
3375
3376            do {
3377                if (obj === undefined) {
3378                    return false;
3379                }
3380
3381                stone = keys.shift();
3382
3383                if (!obj.hasOwnProperty(stone)) {
3384                    return false;
3385                }
3386
3387                obj = obj[stone];
3388
3389            } while (keys.length);
3390
3391            return true;
3392        },
3393
3394        /**
3395         * Gets highest z-index of the given element parents
3396         * @param {object} el jQuery element object
3397         * @returns {number}
3398         */
3399        getHighestZindex: function(el) {
3400            var position, value;
3401
3402            while (el && el !== document) {
3403                // Ignore z-index if position is set to a value where z-index is ignored by the browser
3404                // This makes behavior of this function consistent across browsers
3405                // WebKit always returns auto if the element is positioned
3406                position = KTUtil.css(el, 'position');
3407
3408                if (position === "absolute" || position === "relative" || position === "fixed") {
3409                    // IE returns 0 when zIndex is not specified
3410                    // other browsers return a string
3411                    // we ignore the case of nested elements with an explicit value of 0
3412                    // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
3413                    value = parseInt(KTUtil.css(el, 'z-index'));
3414
3415                    if (!isNaN(value) && value !== 0) {
3416                        return value;
3417                    }
3418                }
3419
3420                el = el.parentNode;
3421            }
3422
3423            return null;
3424        },
3425
3426        /**
3427         * Checks whether the element has any parent with fixed positionfreg
3428         * @param {object} el jQuery element object
3429         * @returns {boolean}
3430         */
3431        hasFixedPositionedParent: function(el) {
3432            var position;
3433
3434            while (el && el !== document) {
3435                position = KTUtil.css(el, 'position');
3436
3437                if (position === "fixed") {
3438                    return true;
3439                }
3440
3441                el = el.parentNode;
3442            }
3443
3444            return false;
3445        },
3446
3447        /**
3448         * Simulates delay
3449         */
3450        sleep: function(milliseconds) {
3451            var start = new Date().getTime();
3452            for (var i = 0; i < 1e7; i++) {
3453                if ((new Date().getTime() - start) > milliseconds) {
3454                    break;
3455                }
3456            }
3457        },
3458
3459        /**
3460         * Gets randomly generated integer value within given min and max range
3461         * @param {number} min Range start value
3462         * @param {number} max Range end value
3463         * @returns {number}
3464         */
3465        getRandomInt: function(min, max) {
3466            return Math.floor(Math.random() * (max - min + 1)) + min;
3467        },
3468
3469        /**
3470         * Checks whether Angular library is included
3471         * @returns {boolean}
3472         */
3473        isAngularVersion: function() {
3474            return window.Zone !== undefined ? true : false;
3475        },
3476
3477        // jQuery Workarounds
3478
3479        // Deep extend:  $.extend(true, {}, objA, objB);
3480        deepExtend: function(out) {
3481            out = out || {};
3482
3483            for (var i = 1; i < arguments.length; i++) {
3484                var obj = arguments[i];
3485
3486                if (!obj)
3487                    continue;
3488
3489                for (var key in obj) {
3490                    if (obj.hasOwnProperty(key)) {
3491                        if (typeof obj[key] === 'object')
3492                            out[key] = KTUtil.deepExtend(out[key], obj[key]);
3493                        else
3494                            out[key] = obj[key];
3495                    }
3496                }
3497            }
3498
3499            return out;
3500        },
3501
3502        // extend:  $.extend({}, objA, objB);
3503        extend: function(out) {
3504            out = out || {};
3505
3506            for (var i = 1; i < arguments.length; i++) {
3507                if (!arguments[i])
3508                    continue;
3509
3510                for (var key in arguments[i]) {
3511                    if (arguments[i].hasOwnProperty(key))
3512                        out[key] = arguments[i][key];
3513                }
3514            }
3515
3516            return out;
3517        },
3518
3519        getById: function(el) {
3520            if (typeof el === 'string') {
3521                return document.getElementById(el);
3522            } else {
3523                return el;
3524            }
3525        },
3526
3527        getByTag: function(query) {
3528            return document.getElementsByTagName(query);
3529        },
3530
3531        getByTagName: function(query) {
3532            return document.getElementsByTagName(query);
3533        },
3534
3535        getByClass: function(query) {
3536            return document.getElementsByClassName(query);
3537        },
3538
3539        getBody: function() {
3540            return document.getElementsByTagName('body')[0];
3541        },
3542
3543        /**
3544         * Checks whether the element has given classes
3545         * @param {object} el jQuery element object
3546         * @param {string} Classes string
3547         * @returns {boolean}
3548         */
3549        hasClasses: function(el, classes) {
3550            if (!el) {
3551                return;
3552            }
3553
3554            var classesArr = classes.split(" ");
3555
3556            for (var i = 0; i < classesArr.length; i++) {
3557                if (KTUtil.hasClass(el, KTUtil.trim(classesArr[i])) == false) {
3558                    return false;
3559                }
3560            }
3561
3562            return true;
3563        },
3564
3565        hasClass: function(el, className) {
3566            if (!el) {
3567                return;
3568            }
3569
3570            return el.classList ? el.classList.contains(className) : new RegExp('\\b' + className + '\\b').test(el.className);
3571        },
3572
3573        addClass: function(el, className) {
3574            if (!el || typeof className === 'undefined') {
3575                return;
3576            }
3577
3578            var classNames = className.split(' ');
3579
3580            if (el.classList) {
3581                for (var i = 0; i < classNames.length; i++) {
3582                    if (classNames[i] && classNames[i].length > 0) {
3583                        el.classList.add(KTUtil.trim(classNames[i]));
3584                    }
3585                }
3586            } else if (!KTUtil.hasClass(el, className)) {
3587                for (var x = 0; x < classNames.length; x++) {
3588                    el.className += ' ' + KTUtil.trim(classNames[x]);
3589                }
3590            }
3591        },
3592
3593        removeClass: function(el, className) {
3594          if (!el || typeof className === 'undefined') {
3595                return;
3596            }
3597
3598            var classNames = className.split(' ');
3599
3600            if (el.classList) {
3601                for (var i = 0; i < classNames.length; i++) {
3602                    el.classList.remove(KTUtil.trim(classNames[i]));
3603                }
3604            } else if (KTUtil.hasClass(el, className)) {
3605                for (var x = 0; x < classNames.length; x++) {
3606                    el.className = el.className.replace(new RegExp('\\b' + KTUtil.trim(classNames[x]) + '\\b', 'g'), '');
3607                }
3608            }
3609        },
3610
3611        triggerCustomEvent: function(el, eventName, data) {
3612            var event;
3613            if (window.CustomEvent) {
3614                event = new CustomEvent(eventName, {
3615                    detail: data
3616                });
3617            } else {
3618                event = document.createEvent('CustomEvent');
3619                event.initCustomEvent(eventName, true, true, data);
3620            }
3621
3622            el.dispatchEvent(event);
3623        },
3624
3625        triggerEvent: function(node, eventName) {
3626            // Make sure we use the ownerDocument from the provided node to avoid cross-window problems
3627            var doc;
3628            if (node.ownerDocument) {
3629                doc = node.ownerDocument;
3630            } else if (node.nodeType == 9) {
3631                // the node may be the document itself, nodeType 9 = DOCUMENT_NODE
3632                doc = node;
3633            } else {
3634                throw new Error("Invalid node passed to fireEvent: " + node.id);
3635            }
3636
3637            if (node.dispatchEvent) {
3638                // Gecko-style approach (now the standard) takes more work
3639                var eventClass = "";
3640
3641                // Different events have different event classes.
3642                // If this switch statement can't map an eventName to an eventClass,
3643                // the event firing is going to fail.
3644                switch (eventName) {
3645                case "click": // Dispatching of 'click' appears to not work correctly in Safari. Use 'mousedown' or 'mouseup' instead.
3646                case "mouseenter":
3647                case "mouseleave":
3648                case "mousedown":
3649                case "mouseup":
3650                    eventClass = "MouseEvents";
3651                    break;
3652
3653                case "focus":
3654                case "change":
3655                case "blur":
3656                case "select":
3657                    eventClass = "HTMLEvents";
3658                    break;
3659
3660                default:
3661                    throw "fireEvent: Couldn't find an event class for event '" + eventName + "'.";
3662                    break;
3663                }
3664                var event = doc.createEvent(eventClass);
3665
3666                var bubbles = eventName == "change" ? false : true;
3667                event.initEvent(eventName, bubbles, true); // All events created as bubbling and cancelable.
3668
3669                event.synthetic = true; // allow detection of synthetic events
3670                // The second parameter says go ahead with the default action
3671                node.dispatchEvent(event, true);
3672            } else if (node.fireEvent) {
3673                // IE-old school style
3674                var event = doc.createEventObject();
3675                event.synthetic = true; // allow detection of synthetic events
3676                node.fireEvent("on" + eventName, event);
3677            }
3678        },
3679
3680        index: function( el ){
3681            var c = el.parentNode.children, i = 0;
3682            for(; i < c.length; i++ )
3683                if( c[i] == el ) return i;
3684        },
3685
3686        trim: function(string) {
3687            return string.trim();
3688        },
3689
3690        eventTriggered: function(e) {
3691            if (e.currentTarget.dataset.triggered) {
3692                return true;
3693            } else {
3694                e.currentTarget.dataset.triggered = true;
3695
3696                return false;
3697            }
3698        },
3699
3700        remove: function(el) {
3701            if (el && el.parentNode) {
3702                el.parentNode.removeChild(el);
3703            }
3704        },
3705
3706        find: function(parent, query) {
3707            parent = KTUtil.getById(parent);
3708            if (parent) {
3709                return parent.querySelector(query);
3710            }
3711        },
3712
3713        findAll: function(parent, query) {
3714            parent = KTUtil.getById(parent);
3715            if (parent) {
3716                return parent.querySelectorAll(query);
3717            }
3718        },
3719
3720        insertAfter: function(el, referenceNode) {
3721            return referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling);
3722        },
3723
3724        parents: function(elem, selector) {
3725            // Element.matches() polyfill
3726            if (!Element.prototype.matches) {
3727                Element.prototype.matches =
3728                    Element.prototype.matchesSelector ||
3729                    Element.prototype.mozMatchesSelector ||
3730                    Element.prototype.msMatchesSelector ||
3731                    Element.prototype.oMatchesSelector ||
3732                    Element.prototype.webkitMatchesSelector ||
3733                    function(s) {
3734                        var matches = (this.document || this.ownerDocument).querySelectorAll(s),
3735                            i = matches.length;
3736                        while (--i >= 0 && matches.item(i) !== this) {}
3737                        return i > -1;
3738                    };
3739            }
3740
3741            // Set up a parent array
3742            var parents = [];
3743
3744            // Push each parent element to the array
3745            for ( ; elem && elem !== document; elem = elem.parentNode ) {
3746                if (selector) {
3747                    if (elem.matches(selector)) {
3748                        parents.push(elem);
3749                    }
3750                    continue;
3751                }
3752                parents.push(elem);
3753            }
3754
3755            // Return our parent array
3756            return parents;
3757        },
3758
3759        children: function(el, selector, log) {
3760            if (!el || !el.childNodes) {
3761                return;
3762            }
3763
3764            var result = [],
3765                i = 0,
3766                l = el.childNodes.length;
3767
3768            for (var i; i < l; ++i) {
3769                if (el.childNodes[i].nodeType == 1 && KTUtil.matches(el.childNodes[i], selector, log)) {
3770                    result.push(el.childNodes[i]);
3771                }
3772            }
3773
3774            return result;
3775        },
3776
3777        child: function(el, selector, log) {
3778            var children = KTUtil.children(el, selector, log);
3779
3780            return children ? children[0] : null;
3781        },
3782
3783        matches: function(el, selector, log) {
3784            var p = Element.prototype;
3785            var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
3786                return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
3787            };
3788
3789            if (el && el.tagName) {
3790                return f.call(el, selector);
3791            } else {
3792                return false;
3793            }
3794        },
3795
3796        data: function(el) {
3797            return {
3798                set: function(name, data) {
3799                    if (!el) {
3800                        return;
3801                    }
3802
3803                    if (el.customDataTag === undefined) {
3804                        window.KTUtilElementDataStoreID++;
3805                        el.customDataTag = window.KTUtilElementDataStoreID;
3806                    }
3807
3808                    if (window.KTUtilElementDataStore[el.customDataTag] === undefined) {
3809                        window.KTUtilElementDataStore[el.customDataTag] = {};
3810                    }
3811
3812                    window.KTUtilElementDataStore[el.customDataTag][name] = data;
3813                },
3814
3815                get: function(name) {
3816                    if (!el) {
3817                        return;
3818                    }
3819
3820                    if (el.customDataTag === undefined) {
3821                        return null;
3822                    }
3823
3824                    return this.has(name) ? window.KTUtilElementDataStore[el.customDataTag][name] : null;
3825                },
3826
3827                has: function(name) {
3828                    if (!el) {
3829                        return false;
3830                    }
3831
3832                    if (el.customDataTag === undefined) {
3833                        return false;
3834                    }
3835
3836                    return (window.KTUtilElementDataStore[el.customDataTag] && window.KTUtilElementDataStore[el.customDataTag][name]) ? true : false;
3837                },
3838
3839                remove: function(name) {
3840                    if (el && this.has(name)) {
3841                        delete window.KTUtilElementDataStore[el.customDataTag][name];
3842                    }
3843                }
3844            };
3845        },
3846
3847        outerWidth: function(el, margin) {
3848            var width;
3849
3850            if (margin === true) {
3851                width = parseFloat(el.offsetWidth);
3852                width += parseFloat(KTUtil.css(el, 'margin-left')) + parseFloat(KTUtil.css(el, 'margin-right'));
3853
3854                return parseFloat(width);
3855            } else {
3856                width = parseFloat(el.offsetWidth);
3857
3858                return width;
3859            }
3860        },
3861
3862        offset: function(el) {
3863            var rect, win;
3864
3865            if ( !el ) {
3866                return;
3867            }
3868
3869            // Return zeros for disconnected and hidden (display: none) elements (gh-2310)
3870            // Support: IE <=11 only
3871            // Running getBoundingClientRect on a
3872            // disconnected node in IE throws an error
3873
3874            if ( !el.getClientRects().length ) {
3875                return { top: 0, left: 0 };
3876            }
3877
3878            // Get document-relative position by adding viewport scroll to viewport-relative gBCR
3879            rect = el.getBoundingClientRect();
3880            win = el.ownerDocument.defaultView;
3881
3882            return {
3883                top: rect.top + win.pageYOffset,
3884                left: rect.left + win.pageXOffset
3885            };
3886        },
3887
3888        height: function(el) {
3889            return KTUtil.css(el, 'height');
3890        },
3891
3892        outerHeight: function(el, withMargin) {
3893            var height = el.offsetHeight;
3894            var style;
3895
3896            if (typeof withMargin !== 'undefined' && withMargin === true) {
3897                style = getComputedStyle(el);
3898                height += parseInt(style.marginTop) + parseInt(style.marginBottom);
3899
3900                return height;
3901            } else {
3902                return height;
3903            }
3904        },
3905
3906        visible: function(el) {
3907            return !(el.offsetWidth === 0 && el.offsetHeight === 0);
3908        },
3909
3910        attr: function(el, name, value) {
3911            if (el == undefined) {
3912                return;
3913            }
3914
3915            if (value !== undefined) {
3916                el.setAttribute(name, value);
3917            } else {
3918                return el.getAttribute(name);
3919            }
3920        },
3921
3922        hasAttr: function(el, name) {
3923            if (el == undefined) {
3924                return;
3925            }
3926
3927            return el.getAttribute(name) ? true : false;
3928        },
3929
3930        removeAttr: function(el, name) {
3931            if (el == undefined) {
3932                return;
3933            }
3934
3935            el.removeAttribute(name);
3936        },
3937
3938        animate: function(from, to, duration, update, easing, done) {
3939            /**
3940             * TinyAnimate.easings
3941             *  Adapted from jQuery Easing
3942             */
3943            var easings = {};
3944            var easing;
3945
3946            easings.linear = function(t, b, c, d) {
3947                return c * t / d + b;
3948            };
3949
3950            easing = easings.linear;
3951
3952            // Early bail out if called incorrectly
3953            if (typeof from !== 'number' ||
3954                typeof to !== 'number' ||
3955                typeof duration !== 'number' ||
3956                typeof update !== 'function') {
3957                return;
3958            }
3959
3960            // Create mock done() function if necessary
3961            if (typeof done !== 'function') {
3962                done = function() {};
3963            }
3964
3965            // Pick implementation (requestAnimationFrame | setTimeout)
3966            var rAF = window.requestAnimationFrame || function(callback) {
3967                window.setTimeout(callback, 1000 / 50);
3968            };
3969
3970            // Animation loop
3971            var canceled = false;
3972            var change = to - from;
3973
3974            function loop(timestamp) {
3975                var time = (timestamp || +new Date()) - start;
3976
3977                if (time >= 0) {
3978                    update(easing(time, from, change, duration));
3979                }
3980                if (time >= 0 && time >= duration) {
3981                    update(to);
3982                    done();
3983                } else {
3984                    rAF(loop);
3985                }
3986            }
3987
3988            update(from);
3989
3990            // Start animation loop
3991            var start = window.performance && window.performance.now ? window.performance.now() : +new Date();
3992
3993            rAF(loop);
3994        },
3995
3996        actualCss: function(el, prop, cache) {
3997            var css = '';
3998
3999            if (el instanceof HTMLElement === false) {
4000                return;
4001            }
4002
4003            if (!el.getAttribute('kt-hidden-' + prop) || cache === false) {
4004                var value;
4005
4006                // the element is hidden so:
4007                // making the el block so we can meassure its height but still be hidden
4008                css = el.style.cssText;
4009                el.style.cssText = 'position: absolute; visibility: hidden; display: block;';
4010
4011                if (prop == 'width') {
4012                    value = el.offsetWidth;
4013                } else if (prop == 'height') {
4014                    value = el.offsetHeight;
4015                }
4016
4017                el.style.cssText = css;
4018
4019                // store it in cache
4020                el.setAttribute('kt-hidden-' + prop, value);
4021
4022                return parseFloat(value);
4023            } else {
4024                // store it in cache
4025                return parseFloat(el.getAttribute('kt-hidden-' + prop));
4026            }
4027        },
4028
4029        actualHeight: function(el, cache) {
4030            return KTUtil.actualCss(el, 'height', cache);
4031        },
4032
4033        actualWidth: function(el, cache) {
4034            return KTUtil.actualCss(el, 'width', cache);
4035        },
4036
4037        getScroll: function(element, method) {
4038            // The passed in `method` value should be 'Top' or 'Left'
4039            method = 'scroll' + method;
4040            return (element == window || element == document) ? (
4041                self[(method == 'scrollTop') ? 'pageYOffset' : 'pageXOffset'] ||
4042                (browserSupportsBoxModel && document.documentElement[method]) ||
4043                document.body[method]
4044            ) : element[method];
4045        },
4046
4047        css: function(el, styleProp, value) {
4048            if (!el) {
4049                return;
4050            }
4051
4052            if (value !== undefined) {
4053                el.style[styleProp] = value;
4054            } else {
4055                var defaultView = (el.ownerDocument || document).defaultView;
4056                // W3C standard way:
4057                if (defaultView && defaultView.getComputedStyle) {
4058                    // sanitize property name to css notation
4059                    // (hyphen separated words eg. font-Size)
4060                    styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
4061                    return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
4062                } else if (el.currentStyle) { // IE
4063                    // sanitize property name to camelCase
4064                    styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
4065                        return letter.toUpperCase();
4066                    });
4067                    value = el.currentStyle[styleProp];
4068                    // convert other units to pixels on IE
4069                    if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
4070                        return (function(value) {
4071                            var oldLeft = el.style.left,
4072                                oldRsLeft = el.runtimeStyle.left;
4073                            el.runtimeStyle.left = el.currentStyle.left;
4074                            el.style.left = value || 0;
4075                            value = el.style.pixelLeft + "px";
4076                            el.style.left = oldLeft;
4077                            el.runtimeStyle.left = oldRsLeft;
4078                            return value;
4079                        })(value);
4080                    }
4081                    return value;
4082                }
4083            }
4084        },
4085
4086        slide: function(el, dir, speed, callback, recalcMaxHeight) {
4087            if (!el || (dir == 'up' && KTUtil.visible(el) === false) || (dir == 'down' && KTUtil.visible(el) === true)) {
4088                return;
4089            }
4090
4091            speed = (speed ? speed : 600);
4092            var calcHeight = KTUtil.actualHeight(el);
4093            var calcPaddingTop = false;
4094            var calcPaddingBottom = false;
4095
4096            if (KTUtil.css(el, 'padding-top') && KTUtil.data(el).has('slide-padding-top') !== true) {
4097                KTUtil.data(el).set('slide-padding-top', KTUtil.css(el, 'padding-top'));
4098            }
4099
4100            if (KTUtil.css(el, 'padding-bottom') && KTUtil.data(el).has('slide-padding-bottom') !== true) {
4101                KTUtil.data(el).set('slide-padding-bottom', KTUtil.css(el, 'padding-bottom'));
4102            }
4103
4104            if (KTUtil.data(el).has('slide-padding-top')) {
4105                calcPaddingTop = parseInt(KTUtil.data(el).get('slide-padding-top'));
4106            }
4107
4108            if (KTUtil.data(el).has('slide-padding-bottom')) {
4109                calcPaddingBottom = parseInt(KTUtil.data(el).get('slide-padding-bottom'));
4110            }
4111
4112            if (dir == 'up') { // up
4113                el.style.cssText = 'display: block; overflow: hidden;';
4114
4115                if (calcPaddingTop) {
4116                    KTUtil.animate(0, calcPaddingTop, speed, function(value) {
4117                        el.style.paddingTop = (calcPaddingTop - value) + 'px';
4118                    }, 'linear');
4119                }
4120
4121                if (calcPaddingBottom) {
4122                    KTUtil.animate(0, calcPaddingBottom, speed, function(value) {
4123                        el.style.paddingBottom = (calcPaddingBottom - value) + 'px';
4124                    }, 'linear');
4125                }
4126
4127                KTUtil.animate(0, calcHeight, speed, function(value) {
4128                    el.style.height = (calcHeight - value) + 'px';
4129                }, 'linear', function() {
4130                    el.style.height = '';
4131                    el.style.display = 'none';
4132
4133                    if (typeof callback === 'function') {
4134                        callback();
4135                    }
4136                });
4137
4138
4139            } else if (dir == 'down') { // down
4140                el.style.cssText = 'display: block; overflow: hidden;';
4141
4142                if (calcPaddingTop) {
4143                    KTUtil.animate(0, calcPaddingTop, speed, function(value) {//
4144                        el.style.paddingTop = value + 'px';
4145                    }, 'linear', function() {
4146                        el.style.paddingTop = '';
4147                    });
4148                }
4149
4150                if (calcPaddingBottom) {
4151                    KTUtil.animate(0, calcPaddingBottom, speed, function(value) {
4152                        el.style.paddingBottom = value + 'px';
4153                    }, 'linear', function() {
4154                        el.style.paddingBottom = '';
4155                    });
4156                }
4157
4158                KTUtil.animate(0, calcHeight, speed, function(value) {
4159                    el.style.height = value + 'px';
4160                }, 'linear', function() {
4161                    el.style.height = '';
4162                    el.style.display = '';
4163                    el.style.overflow = '';
4164
4165                    if (typeof callback === 'function') {
4166                        callback();
4167                    }
4168                });
4169            }
4170        },
4171
4172        slideUp: function(el, speed, callback) {
4173            KTUtil.slide(el, 'up', speed, callback);
4174        },
4175
4176        slideDown: function(el, speed, callback) {
4177            KTUtil.slide(el, 'down', speed, callback);
4178        },
4179
4180        show: function(el, display) {
4181            if (typeof el !== 'undefined') {
4182                el.style.display = (display ? display : 'block');
4183            }
4184        },
4185
4186        hide: function(el) {
4187            if (typeof el !== 'undefined') {
4188                el.style.display = 'none';
4189            }
4190        },
4191
4192        addEvent: function(el, type, handler, one) {
4193            if (typeof el !== 'undefined' && el !== null) {
4194                el.addEventListener(type, handler);
4195            }
4196        },
4197
4198        removeEvent: function(el, type, handler) {
4199            if (el !== null) {
4200                el.removeEventListener(type, handler);
4201            }
4202        },
4203
4204        on: function(element, selector, event, handler) {
4205            if (!selector) {
4206                return;
4207            }
4208
4209            var eventId = KTUtil.getUniqueID('event');
4210
4211            window.KTUtilDelegatedEventHandlers[eventId] = function(e) {
4212                var targets = element.querySelectorAll(selector);
4213                var target = e.target;
4214
4215                while (target && target !== element) {
4216                    for (var i = 0, j = targets.length; i < j; i++) {
4217                        if (target === targets[i]) {
4218                            handler.call(target, e);
4219                        }
4220                    }
4221
4222                    target = target.parentNode;
4223                }
4224            }
4225
4226            KTUtil.addEvent(element, event, window.KTUtilDelegatedEventHandlers[eventId]);
4227
4228            return eventId;
4229        },
4230
4231        off: function(element, event, eventId) {
4232            if (!element || !window.KTUtilDelegatedEventHandlers[eventId]) {
4233                return;
4234            }
4235
4236            KTUtil.removeEvent(element, event, window.KTUtilDelegatedEventHandlers[eventId]);
4237
4238            delete window.KTUtilDelegatedEventHandlers[eventId];
4239        },
4240
4241        one: function onetime(el, type, callback) {
4242            el.addEventListener(type, function callee(e) {
4243                // remove event
4244                if (e.target && e.target.removeEventListener) {
4245                    e.target.removeEventListener(e.type, callee);
4246                }
4247
4248                // need to verify from https://themeforest.net/author_dashboard#comment_23615588
4249                if (el && el.removeEventListener) {
4250				    e.currentTarget.removeEventListener(e.type, callee);
4251			    }
4252
4253                // call handler
4254                return callback(e);
4255            });
4256        },
4257
4258        hash: function(str) {
4259            var hash = 0,
4260                i, chr;
4261
4262            if (str.length === 0) return hash;
4263            for (i = 0; i < str.length; i++) {
4264                chr = str.charCodeAt(i);
4265                hash = ((hash << 5) - hash) + chr;
4266                hash |= 0; // Convert to 32bit integer
4267            }
4268
4269            return hash;
4270        },
4271
4272        animateClass: function(el, animationName, callback) {
4273            var animation;
4274            var animations = {
4275                animation: 'animationend',
4276                OAnimation: 'oAnimationEnd',
4277                MozAnimation: 'mozAnimationEnd',
4278                WebkitAnimation: 'webkitAnimationEnd',
4279                msAnimation: 'msAnimationEnd',
4280            };
4281
4282            for (var t in animations) {
4283                if (el.style[t] !== undefined) {
4284                    animation = animations[t];
4285                }
4286            }
4287
4288            KTUtil.addClass(el, 'animated ' + animationName);
4289
4290            KTUtil.one(el, animation, function() {
4291                KTUtil.removeClass(el, 'animated ' + animationName);
4292            });
4293
4294            if (callback) {
4295                KTUtil.one(el, animation, callback);
4296            }
4297        },
4298
4299        transitionEnd: function(el, callback) {
4300            var transition;
4301            var transitions = {
4302                transition: 'transitionend',
4303                OTransition: 'oTransitionEnd',
4304                MozTransition: 'mozTransitionEnd',
4305                WebkitTransition: 'webkitTransitionEnd',
4306                msTransition: 'msTransitionEnd'
4307            };
4308
4309            for (var t in transitions) {
4310                if (el.style[t] !== undefined) {
4311                    transition = transitions[t];
4312                }
4313            }
4314
4315            KTUtil.one(el, transition, callback);
4316        },
4317
4318        animationEnd: function(el, callback) {
4319            var animation;
4320            var animations = {
4321                animation: 'animationend',
4322                OAnimation: 'oAnimationEnd',
4323                MozAnimation: 'mozAnimationEnd',
4324                WebkitAnimation: 'webkitAnimationEnd',
4325                msAnimation: 'msAnimationEnd'
4326            };
4327
4328            for (var t in animations) {
4329                if (el.style[t] !== undefined) {
4330                    animation = animations[t];
4331                }
4332            }
4333
4334            KTUtil.one(el, animation, callback);
4335        },
4336
4337        animateDelay: function(el, value) {
4338            var vendors = ['webkit-', 'moz-', 'ms-', 'o-', ''];
4339            for (var i = 0; i < vendors.length; i++) {
4340                KTUtil.css(el, vendors[i] + 'animation-delay', value);
4341            }
4342        },
4343
4344        animateDuration: function(el, value) {
4345            var vendors = ['webkit-', 'moz-', 'ms-', 'o-', ''];
4346            for (var i = 0; i < vendors.length; i++) {
4347                KTUtil.css(el, vendors[i] + 'animation-duration', value);
4348            }
4349        },
4350
4351        scrollTo: function(target, offset, duration) {
4352            var duration = duration ? duration : 500;
4353            var targetPos = target ? KTUtil.offset(target).top : 0;
4354            var scrollPos = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
4355            var from, to;
4356
4357            if (offset) {
4358                scrollPos += offset;
4359            }
4360
4361            from = scrollPos;
4362            to = targetPos;
4363
4364            KTUtil.animate(from, to, duration, function(value) {
4365                document.documentElement.scrollTop = value;
4366                document.body.parentNode.scrollTop = value;
4367                document.body.scrollTop = value;
4368            }); //, easing, done
4369        },
4370
4371        scrollTop: function(offset, duration) {
4372            KTUtil.scrollTo(null, offset, duration);
4373        },
4374
4375        isArray: function(obj) {
4376            return obj && Array.isArray(obj);
4377        },
4378
4379        ready: function(callback) {
4380            if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
4381                callback();
4382            } else {
4383                document.addEventListener('DOMContentLoaded', callback);
4384            }
4385        },
4386
4387        isEmpty: function(obj) {
4388            for (var prop in obj) {
4389                if (obj.hasOwnProperty(prop)) {
4390                    return false;
4391                }
4392            }
4393
4394            return true;
4395        },
4396
4397        numberString: function(nStr) {
4398            nStr += '';
4399            var x = nStr.split('.');
4400            var x1 = x[0];
4401            var x2 = x.length > 1 ? '.' + x[1] : '';
4402            var rgx = /(\d+)(\d{3})/;
4403            while (rgx.test(x1)) {
4404                x1 = x1.replace(rgx, '$1' + ',' + '$2');
4405            }
4406            return x1 + x2;
4407        },
4408
4409        detectIE: function() {
4410            var ua = window.navigator.userAgent;
4411
4412            // Test values; Uncomment to check result …
4413
4414            // IE 10
4415            // ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)';
4416
4417            // IE 11
4418            // ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko';
4419
4420            // Edge 12 (Spartan)
4421            // ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0';
4422
4423            // Edge 13
4424            // ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586';
4425
4426            var msie = ua.indexOf('MSIE ');
4427            if (msie > 0) {
4428                // IE 10 or older => return version number
4429                return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
4430            }
4431
4432            var trident = ua.indexOf('Trident/');
4433            if (trident > 0) {
4434                // IE 11 => return version number
4435                var rv = ua.indexOf('rv:');
4436                return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
4437            }
4438
4439            var edge = ua.indexOf('Edge/');
4440            if (edge > 0) {
4441                // Edge (IE 12+) => return version number
4442                return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
4443            }
4444
4445            // other browser
4446            return false;
4447        },
4448
4449        isRTL: function() {
4450            var html = KTUtil.getByTagName('html')[0];
4451
4452            if (html) {
4453                return (KTUtil.attr(html, 'direction') == 'rtl');
4454            }
4455        },
4456
4457        // Scroller
4458        scrollInit: function(element, options) {
4459            if (!element) {
4460                return;
4461            }
4462
4463            // Learn more: https://github.com/mdbootstrap/perfect-scrollbar#options
4464            var pluginDefOptions = {
4465                wheelSpeed: 0.5,
4466                swipeEasing: true,
4467                wheelPropagation: false,
4468                minScrollbarLength: 40,
4469                maxScrollbarLength: 300,
4470                suppressScrollX: true
4471            };
4472
4473            options = KTUtil.deepExtend({}, pluginDefOptions, options);
4474
4475            // Define init function
4476            function init() {
4477                var ps;
4478                var height;
4479
4480                // Get extra options via data attributes
4481                var attrs = element.getAttributeNames();
4482                if (attrs.length > 0) {
4483                    attrs.forEach(function(attrName) {
4484            			// more options; https://github.com/ganlanyuan/tiny-slider#options
4485            			if ((/^data-.*/g).test(attrName)) {
4486                            if (['scroll', 'height', 'mobile-height'].includes(optionName) == false) {
4487                                var optionName = attrName.replace('data-', '').toLowerCase().replace(/(?:[\s-])\w/g, function(match) {
4488                					return match.replace('-', '').toUpperCase();
4489                				});
4490
4491                                options[optionName] = KTUtil.filterBoolean(element.getAttribute(attrName));
4492                            }
4493            			}
4494            		});
4495                }
4496
4497                if (options.height instanceof Function) {
4498                    height = options.height.call();
4499                } else {
4500                    if (KTUtil.isMobileDevice() === true && options.mobileHeight) {
4501                        height = parseInt(options.mobileHeight);
4502                    } else if (options.height) {
4503                        height = parseInt(options.height);
4504                    } else {
4505                        height = parseInt(KTUtil.css(element, 'height'));
4506                    }
4507                }
4508
4509                if (height === false) {
4510                    KTUtil.scrollDestroy(element, true);
4511
4512                    return;
4513                }
4514
4515                height = parseInt(height);
4516
4517                // Destroy scroll on table and mobile modes
4518                if ((options.mobileNativeScroll || options.disableForMobile) && KTUtil.isMobileDevice() === true) {
4519                    ps = KTUtil.data(element).get('ps');
4520                    if (ps) {
4521                        if (options.resetHeightOnDestroy) {
4522                            KTUtil.css(element, 'height', 'auto');
4523                        } else {
4524                            KTUtil.css(element, 'overflow', 'auto');
4525                            if (height > 0) {
4526                                KTUtil.css(element, 'height', height + 'px');
4527                            }
4528                        }
4529
4530                        ps.destroy();
4531                        ps = KTUtil.data(element).remove('ps');
4532                    } else if (height > 0){
4533                        KTUtil.css(element, 'overflow', 'auto');
4534                        KTUtil.css(element, 'height', height + 'px');
4535                    }
4536
4537                    return;
4538                }
4539
4540                if (height > 0) {
4541                    KTUtil.css(element, 'height', height + 'px');
4542                }
4543
4544                if (options.desktopNativeScroll) {
4545                    KTUtil.css(element, 'overflow', 'auto');
4546                    return;
4547                }
4548
4549                // Pass options via HTML Attributes
4550                if (KTUtil.attr(element, 'data-window-scroll') == 'true') {
4551                     options.windowScroll = true;
4552                }
4553
4554                // Init scroll
4555                ps = KTUtil.data(element).get('ps');
4556
4557                if (ps) {
4558                    ps.update();
4559                } else {
4560                    KTUtil.css(element, 'overflow', 'hidden');
4561                    KTUtil.addClass(element, 'scroll');
4562
4563                    ps = new PerfectScrollbar(element, options);
4564
4565                    KTUtil.data(element).set('ps', ps);
4566                }
4567
4568                // Remember scroll position in cookie
4569                var uid = KTUtil.attr(element, 'id');
4570
4571                // Todo:Consider using Localstorage
4572                if (options.rememberPosition === true && KTCookie && uid) {
4573                    if (KTCookie.getCookie(uid)) {
4574                        var pos = parseInt(KTCookie.getCookie(uid));
4575
4576                        if (pos > 0) {
4577                            element.scrollTop = pos;
4578                        }
4579                    }
4580
4581                    element.addEventListener('ps-scroll-y', function() {
4582                        KTCookie.setCookie(uid, element.scrollTop);
4583                    });
4584                }
4585            }
4586
4587            // Init
4588            init();
4589
4590            // Handle window resize
4591            if (options.handleWindowResize) {
4592                KTUtil.addResizeHandler(function() {
4593                    init();
4594                });
4595            }
4596        },
4597
4598        scrollUpdate: function(element) {
4599            var ps = KTUtil.data(element).get('ps');
4600            if (ps) {
4601                ps.update();
4602            }
4603        },
4604
4605        scrollUpdateAll: function(parent) {
4606            var scrollers = KTUtil.findAll(parent, '.ps');
4607            for (var i = 0, len = scrollers.length; i < len; i++) {
4608                KTUtil.scrollUpdate(scrollers[i]);
4609            }
4610        },
4611
4612        scrollDestroy: function(element, resetAll) {
4613            var ps = KTUtil.data(element).get('ps');
4614
4615            if (ps) {
4616                ps.destroy();
4617                ps = KTUtil.data(element).remove('ps');
4618            }
4619
4620            if (element && resetAll) {
4621                element.style.setProperty('overflow', '');
4622                element.style.setProperty('height', '');
4623            }
4624        },
4625
4626        filterBoolean: function(val) {
4627            // Convert string boolean
4628			if (val === true || val === 'true') {
4629				return true;
4630			}
4631
4632			if (val === false || val === 'false') {
4633				return false;
4634			}
4635
4636            return val;
4637        },
4638
4639        setHTML: function(el, html) {
4640            el.innerHTML = html;
4641        },
4642
4643        getHTML: function(el) {
4644            if (el) {
4645                return el.innerHTML;
4646            }
4647        },
4648
4649        getDocumentHeight: function() {
4650            var body = document.body;
4651            var html = document.documentElement;
4652
4653            return Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
4654        },
4655
4656        getScrollTop: function() {
4657            return  (document.scrollingElement || document.documentElement).scrollTop;
4658        },
4659
4660        changeColor: function(col, amt) {
4661
4662            var usePound = false;
4663
4664            if (col[0] == "#") {
4665                col = col.slice(1);
4666                usePound = true;
4667            }
4668
4669            var num = parseInt(col,16);
4670
4671            var r = (num >> 16) + amt;
4672
4673            if (r > 255) r = 255;
4674            else if  (r < 0) r = 0;
4675
4676            var b = ((num >> 8) & 0x00FF) + amt;
4677
4678            if (b > 255) b = 255;
4679            else if  (b < 0) b = 0;
4680
4681            var g = (num & 0x0000FF) + amt;
4682
4683            if (g > 255) g = 255;
4684            else if (g < 0) g = 0;
4685
4686            return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
4687
4688        },
4689
4690        // Throttle function: Input as function which needs to be throttled and delay is the time interval in milliseconds
4691        throttle:  function (timer, func, delay) {
4692        	// If setTimeout is already scheduled, no need to do anything
4693        	if (timer) {
4694        		return;
4695        	}
4696
4697        	// Schedule a setTimeout after delay seconds
4698        	timer  =  setTimeout(function () {
4699        		func();
4700
4701        		// Once setTimeout function execution is finished, timerId = undefined so that in <br>
4702        		// the next scroll event function execution can be scheduled by the setTimeout
4703        		timer  =  undefined;
4704        	}, delay);
4705        },
4706
4707        // Debounce function: Input as function which needs to be debounced and delay is the debounced time in milliseconds
4708        debounce: function (timer, func, delay) {
4709        	// Cancels the setTimeout method execution
4710        	clearTimeout(timer)
4711
4712        	// Executes the func after delay time.
4713        	timer  =  setTimeout(func, delay);
4714        },
4715
4716        btnWait: function(el, cls, message, disable) {
4717            if (!el) {
4718                return;
4719            }
4720
4721            if (typeof disable !== 'undefined' && disable === true) {
4722                KTUtil.attr(el, "disabled", true);
4723            }
4724
4725            if (cls) {
4726                KTUtil.addClass(el, cls);
4727                KTUtil.attr(el, "wait-class", cls);
4728            }
4729
4730            if (message) {
4731                var caption = KTUtil.find(el, '.btn-caption');
4732
4733                if (caption) {
4734                    KTUtil.data(caption).set('caption', KTUtil.getHTML(caption));
4735                    KTUtil.setHTML(caption, message);
4736                } else {
4737                    KTUtil.data(el).set('caption', KTUtil.getHTML(el));
4738                    KTUtil.setHTML(el, message);
4739                }
4740            }
4741        },
4742
4743        btnRelease: function(el) {
4744            if (!el) {
4745                return;
4746            }
4747
4748            /// Show loading state on button
4749            KTUtil.removeAttr(el, "disabled");
4750
4751            if (KTUtil.hasAttr(el, "wait-class")) {
4752                KTUtil.removeClass(el, KTUtil.attr(el, "wait-class"));
4753            }
4754
4755            var caption = KTUtil.find(el, '.btn-caption');
4756
4757            if (caption && KTUtil.data(caption).has('caption')) {
4758                KTUtil.setHTML(caption, KTUtil.data(caption).get('caption'));
4759            } else if (KTUtil.data(el).has('caption')) {
4760                KTUtil.setHTML(el, KTUtil.data(el).get('caption'));
4761            }
4762        },
4763
4764        isOffscreen: function(el, direction, offset) {
4765            offset = offset || 0;
4766
4767            var windowWidth = KTUtil.getViewPort().width;
4768            var windowHeight = KTUtil.getViewPort().height;
4769
4770            var top = KTUtil.offset(el).top;
4771            var height = KTUtil.outerHeight(el) + offset;
4772            var left = KTUtil.offset(el).left;
4773            var width = KTUtil.outerWidth(el) + offset;
4774
4775            if (direction == 'bottom') {
4776                if (windowHeight < top + height) {
4777                    return true;
4778                } else if (windowHeight > top + height * 1.5) {
4779                    return true;
4780                }
4781            }
4782
4783            if (direction == 'top') {
4784                if (top < 0) {
4785                    return true;
4786                } else if (top > height) {
4787                    return true;
4788                }
4789            }
4790
4791            if (direction == 'left') {
4792                if (left < 0) {
4793                    return true;
4794                } else if (left * 2 > width) {
4795                    //console.log('left 2');
4796                    //return true;
4797                }
4798            }
4799
4800            if (direction == 'right') {
4801                if (windowWidth < left + width) {
4802                    return true;
4803                } else {
4804                    //console.log('right 2');
4805                    //return true;
4806                }
4807            }
4808
4809            return false;
4810        }
4811    }
4812}();
4813
4814// webpack support
4815if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
4816    module.exports = KTUtil;
4817}
4818
4819// Initialize KTUtil class on document ready
4820KTUtil.ready(function() {
4821	if (typeof KTAppSettings !== 'undefined') {
4822		KTUtil.init(KTAppSettings);
4823	} else {
4824		KTUtil.init();
4825	}
4826});
4827
4828// CSS3 Transitions only after page load(.page-loading class added to body tag and remove with JS on page load)
4829window.onload = function() {
4830    var result = KTUtil.getByTagName('body');
4831    if (result && result[0]) {
4832        KTUtil.removeClass(result[0], 'page-loading');
4833    }
4834}
4835
4836"use strict";
4837
4838// Component Definition
4839var KTWizard = function(elementId, options) {
4840    // Main object
4841    var the = this;
4842    var init = false;
4843
4844    // Get element object
4845    var element = KTUtil.getById(elementId);
4846    var body = KTUtil.getBody();
4847
4848    if (!element) {
4849        return;
4850    }
4851
4852    // Default options
4853    var defaultOptions = {
4854        startStep: 1,
4855        clickableSteps: false // to make steps clickable this set value true and add data-wizard-clickable="true" in HTML for class="wizard" element
4856    };
4857
4858    ////////////////////////////
4859    // ** Private Methods  ** //
4860    ////////////////////////////
4861
4862    var Plugin = {
4863        /**
4864         * Construct
4865         */
4866
4867        construct: function(options) {
4868            if (KTUtil.data(element).has('wizard')) {
4869                the = KTUtil.data(element).get('wizard');
4870            } else {
4871                // reset menu
4872                Plugin.init(options);
4873
4874                // build menu
4875                Plugin.build();
4876
4877                KTUtil.data(element).set('wizard', the);
4878            }
4879
4880            return the;
4881        },
4882
4883        /**
4884         * Init wizard
4885         */
4886        init: function(options) {
4887            the.element = element;
4888            the.events = [];
4889
4890            // merge default and user defined options
4891            the.options = KTUtil.deepExtend({}, defaultOptions, options);
4892
4893            // Elements
4894            the.steps = KTUtil.findAll(element, '[data-wizard-type="step"]');
4895
4896            the.btnNext = KTUtil.find(element, '[data-wizard-type="action-next"]');
4897            the.btnPrev = KTUtil.find(element, '[data-wizard-type="action-prev"]');
4898            the.btnSubmit = KTUtil.find(element, '[data-wizard-type="action-submit"]');
4899
4900            // Variables
4901            the.events = [];
4902            the.lastStep = 0;
4903            the.currentStep = 1;
4904            the.newStep = 0;
4905            the.stopped = false;
4906            the.totalSteps = the.steps.length;
4907
4908            // Init current step
4909            if (the.options.startStep > 1) {
4910                Plugin.goTo(the.options.startStep);
4911            }
4912
4913            // Init UI
4914            Plugin.updateUI();
4915        },
4916
4917        /**
4918         * Build Form Wizard
4919         */
4920        build: function() {
4921            // Next button event handler
4922            KTUtil.addEvent(the.btnNext, 'click', function(e) {
4923                e.preventDefault();
4924
4925                // Set new step number
4926                Plugin.setNewStep(Plugin.getNextStep());
4927
4928                // Trigger change event
4929                if (Plugin.eventTrigger('change') !== false) {
4930                    Plugin.goTo(Plugin.getNextStep());
4931                }
4932            });
4933
4934            // Prev button event handler
4935            KTUtil.addEvent(the.btnPrev, 'click', function(e) {
4936                e.preventDefault();
4937
4938                // Set new step number
4939                Plugin.setNewStep(Plugin.getPrevStep());
4940
4941                // Trigger change event
4942                if (Plugin.eventTrigger('change') !== false) {
4943                    Plugin.goTo(Plugin.getPrevStep());
4944                }
4945            });
4946
4947            if (the.options.clickableSteps === true) {
4948                KTUtil.on(element, '[data-wizard-type="step"]', 'click', function() {
4949                    var index = KTUtil.index(this) + 1;
4950
4951                    if (index !== the.currentStep) {
4952                        Plugin.setNewStep(index);
4953
4954                        // Trigger change event
4955                        if (Plugin.eventTrigger('change') !== false) {
4956                            Plugin.goTo(index);
4957                        }
4958                    }
4959                });
4960            }
4961
4962            // Submit button event handler
4963            KTUtil.addEvent(the.btnSubmit, 'click', function(e) {
4964                e.preventDefault();
4965
4966                Plugin.eventTrigger('submit');
4967            });
4968        },
4969
4970        /**
4971         * Handles wizard click wizard
4972         */
4973        goTo: function(number) {
4974            // Skip if stopped
4975            if (the.stopped === true) {
4976                the.stopped = false;
4977                return;
4978            }
4979
4980            // Skip if this step is already shown
4981            if (number === the.currentStep || number > the.totalSteps || number < 0) {
4982                return;
4983            }
4984
4985            // Validate step number
4986            number = parseInt(number);
4987
4988            // Set current step
4989            the.lastStep = the.currentStep;
4990            the.currentStep = number;
4991            the.newStep = 0;
4992
4993            Plugin.updateUI();
4994
4995            Plugin.eventTrigger('changed');
4996
4997            return the;
4998        },
4999
5000        /**
5001         * Stop wizard
5002         */
5003        stop: function() {
5004            the.stopped = true;
5005        },
5006
5007        /**
5008         * Resume wizard
5009         */
5010        resume: function() {
5011            the.stopped = false;
5012        },
5013
5014        /**
5015         * Check last step
5016         */
5017        isLastStep: function() {
5018            return the.currentStep === the.totalSteps;
5019        },
5020
5021        /**
5022         * Check first step
5023         */
5024        isFirstStep: function() {
5025            return the.currentStep === 1;
5026        },
5027
5028        /**
5029         * Check between step
5030         */
5031        isBetweenStep: function() {
5032            return Plugin.isLastStep() === false && Plugin.isFirstStep() === false;
5033        },
5034
5035        /**
5036         * Update wizard UI after step change
5037         */
5038        updateUI: function() {
5039            var stepType = '';
5040            var index = the.currentStep - 1;
5041
5042            if (Plugin.isLastStep()) {
5043                stepType = 'last';
5044            } else if (Plugin.isFirstStep()) {
5045                stepType = 'first';
5046            } else {
5047                stepType = 'between';
5048            }
5049
5050            KTUtil.attr(the.element, 'data-wizard-state', stepType);
5051
5052            // Steps
5053            var steps = KTUtil.findAll(the.element, '[data-wizard-type="step"]');
5054
5055            if (steps && steps.length > 0) {
5056                for (var i = 0, len = steps.length; i < len; i++) {
5057                    if (i == index) {
5058                        KTUtil.attr(steps[i], 'data-wizard-state', 'current');
5059                    } else {
5060                        if (i < index) {
5061                            KTUtil.attr(steps[i], 'data-wizard-state', 'done');
5062                        } else {
5063                            KTUtil.attr(steps[i], 'data-wizard-state', 'pending');
5064                        }
5065                    }
5066                }
5067            }
5068
5069            // Steps Info
5070            var stepsInfo = KTUtil.findAll(the.element, '[data-wizard-type="step-info"]');
5071            if (stepsInfo &&stepsInfo.length > 0) {
5072                for (var i = 0, len = stepsInfo.length; i < len; i++) {
5073                    if (i == index) {
5074                        KTUtil.attr(stepsInfo[i], 'data-wizard-state', 'current');
5075                    } else {
5076                        KTUtil.removeAttr(stepsInfo[i], 'data-wizard-state');
5077                    }
5078                }
5079            }
5080
5081            // Steps Content
5082            var stepsContent = KTUtil.findAll(the.element, '[data-wizard-type="step-content"]');
5083            if (stepsContent&& stepsContent.length > 0) {
5084                for (var i = 0, len = stepsContent.length; i < len; i++) {
5085                    if (i == index) {
5086                        KTUtil.attr(stepsContent[i], 'data-wizard-state', 'current');
5087                    } else {
5088                        KTUtil.removeAttr(stepsContent[i], 'data-wizard-state');
5089                    }
5090                }
5091            }
5092        },
5093
5094        /**
5095         * Get next step number
5096         */
5097        getNextStep: function() {
5098            if (the.totalSteps >= (the.currentStep + 1)) {
5099                return the.currentStep + 1;
5100            } else {
5101                return the.totalSteps;
5102            }
5103        },
5104
5105        /**
5106         * Get prev step number
5107         */
5108        getPrevStep: function() {
5109            if ((the.currentStep - 1) >= 1) {
5110                return the.currentStep - 1;
5111            } else {
5112                return 1;
5113            }
5114        },
5115
5116        /**
5117         * Get new step number
5118         */
5119        getNewStep: function() {
5120            return the.newStep;
5121        },
5122
5123        /**
5124         * Set new step
5125         */
5126        setNewStep: function(step) {
5127            the.newStep = step;
5128        },
5129
5130        /**
5131         * Trigger events
5132         */
5133        eventTrigger: function(name, nested) {
5134            //KTUtil.triggerCustomEvent(name);
5135            for (var i = 0; i < the.events.length; i++) {
5136                var event = the.events[i];
5137                if (event.name == name) {
5138                    if (event.one == true) {
5139                        if (event.fired == false) {
5140                            the.events[i].fired = true;
5141                            return event.handler.call(this, the);
5142                        }
5143                    } else {
5144                        return event.handler.call(this, the);
5145                    }
5146                }
5147            }
5148        },
5149
5150        addEvent: function(name, handler, one) {
5151            the.events.push({
5152                name: name,
5153                handler: handler,
5154                one: one,
5155                fired: false
5156            });
5157
5158            return the;
5159        }
5160    };
5161
5162    //////////////////////////
5163    // ** Public Methods ** //
5164    //////////////////////////
5165
5166    /**
5167     * Set default options
5168     */
5169
5170    the.setDefaults = function(options) {
5171        defaultOptions = options;
5172    };
5173
5174    /**
5175     * Go to the next step
5176     */
5177    the.goNext = function() {
5178        return Plugin.goTo(Plugin.getNextStep());
5179    };
5180
5181    /**
5182     * Go to the prev step
5183     */
5184    the.goPrev = function() {
5185        return Plugin.goTo(Plugin.getPrevStep());
5186    };
5187
5188    /**
5189     * Go to the last step
5190     */
5191    the.goLast = function() {
5192        return Plugin.goTo(Plugin.getLastStep());
5193    };
5194
5195    /**
5196     * Go to the first step
5197     */
5198    the.goFirst = function() {
5199        return Plugin.goTo(Plugin.getFirstStep());
5200    };
5201
5202    /**
5203     * Go to a step
5204     */
5205    the.goTo = function(number) {
5206        return Plugin.goTo(number);
5207    };
5208
5209    /**
5210     * Stop wizard
5211     */
5212    the.stop = function() {
5213        return Plugin.stop();
5214    };
5215
5216    /**
5217     * Resume wizard
5218     */
5219    the.resume = function() {
5220        return Plugin.resume();
5221    };
5222
5223    /**
5224     * Get current step number
5225     */
5226    the.getStep = function() {
5227        return the.currentStep;
5228    };
5229
5230    /**
5231     * Get new step number
5232     */
5233    the.getNewStep = function() {
5234        return Plugin.getNewStep();
5235    };
5236
5237    /**
5238     * Set new step number
5239     */
5240    the.setNewStep = function(number) {
5241        Plugin.setNewStep(number);
5242    };
5243
5244    /**
5245     * Check last step
5246     */
5247    the.isLastStep = function() {
5248        return Plugin.isLastStep();
5249    };
5250
5251    /**
5252     * Check first step
5253     */
5254    the.isFirstStep = function() {
5255        return Plugin.isFirstStep();
5256    };
5257
5258    /**
5259     * Attach event("change", "changed", "submit")
5260     */
5261    the.on = function(name, handler) {
5262        return Plugin.addEvent(name, handler);
5263    };
5264
5265    /**
5266     * Attach event that will be fired once
5267     */
5268    the.one = function(name, handler) {
5269        return Plugin.addEvent(name, handler, true);
5270    };
5271
5272    // Construct plugin
5273    Plugin.construct.apply(the, [options]);
5274
5275    return the;
5276};
5277
5278// webpack support
5279if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
5280    module.exports = KTWizard;
5281}
5282
5283'use strict';
5284(function($) {
5285
5286	var pluginName = 'KTDatatable';
5287	var pfx = '';
5288	var util = KTUtil;
5289	var app = KTApp;
5290
5291	if (typeof util === 'undefined') throw new Error('Util class is required and must be included before ' + pluginName);
5292
5293	// plugin setup
5294	$.fn[pluginName] = function(options) {
5295		if ($(this).length === 0) {
5296			console.warn('No ' + pluginName + ' element exist.');
5297			return;
5298		}
5299
5300		// global variables
5301		var datatable = this;
5302
5303		// debug enabled?
5304		// 1) state will be cleared on each refresh
5305		// 2) enable some logs
5306		// 3) etc.
5307		datatable.debug = false;
5308
5309		datatable.API = {
5310			record: null,
5311			value: null,
5312			params: null,
5313		};
5314
5315		var Plugin = {
5316			/********************
5317			 ** PRIVATE METHODS
5318			 ********************/
5319			isInit: false,
5320			cellOffset: 110,
5321			iconOffset: 15,
5322			stateId: 'meta',
5323			ajaxParams: {},
5324			pagingObject: {},
5325
5326			init: function(options) {
5327				var isHtmlTable = false;
5328				// data source option empty is normal table
5329				if (options.data.source === null) {
5330					Plugin.extractTable();
5331					isHtmlTable = true;
5332				}
5333
5334				Plugin.setupBaseDOM.call();
5335				Plugin.setupDOM(datatable.table);
5336
5337				// on event after layout had done setup, show datatable
5338				$(datatable).on(pfx + 'datatable-on-layout-updated', Plugin.afterRender);
5339
5340				if (datatable.debug) {
5341					Plugin.stateRemove(Plugin.stateId);
5342				}
5343
5344				/*var es = Plugin.stateGet(Plugin.stateId);
5345				var eq = {};
5346				if (es && es.hasOwnProperty('query')) {
5347					eq = es.query;
5348				}
5349				Plugin.setDataSourceQuery(Object.assign({}, eq, Plugin.getOption('data.source.read.params.query')));*/
5350
5351				// set custom query from options
5352				Plugin.setDataSourceQuery(Plugin.getOption('data.source.read.params.query'));
5353
5354				// initialize extensions
5355				$.each(Plugin.getOption('extensions'), function(extName, extOptions) {
5356					if (typeof $.fn[pluginName][extName] === 'function') {
5357						if (typeof extOptions !== 'object') {
5358							extOptions = $.extend({}, extOptions);
5359						}
5360						new $.fn[pluginName][extName](datatable, extOptions);
5361					}
5362				});
5363
5364				Plugin.spinnerCallback(true);
5365				// get data
5366				if (options.data.type === 'remote' || options.data.type === 'local') {
5367					if (options.data.saveState === false) {
5368						Plugin.stateRemove(Plugin.stateId);
5369					}
5370					// get data for local datatable and local table
5371					if (options.data.type === 'local' && typeof options.data.source === 'object') {
5372						datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(options.data.source);
5373					}
5374					Plugin.dataRender();
5375				}
5376
5377				// if html table, remove and setup a new header
5378				if (isHtmlTable) {
5379					$(datatable.tableHead).find('tr').remove();
5380					$(datatable.tableFoot).find('tr').remove();
5381				}
5382
5383				Plugin.setHeadTitle();
5384				if (Plugin.getOption('layout.footer')) {
5385					Plugin.setHeadTitle(datatable.tableFoot);
5386				}
5387
5388				// hide header
5389				if (typeof options.layout.header !== 'undefined' &&
5390					options.layout.header === false) {
5391					$(datatable.table).find('thead').remove();
5392				}
5393
5394				// hide footer
5395				if (typeof options.layout.footer !== 'undefined' &&
5396					options.layout.footer === false) {
5397					$(datatable.table).find('tfoot').remove();
5398				}
5399
5400				// for normal and local data type, run layoutUpdate
5401				if (options.data.type === null ||
5402					options.data.type === 'local') {
5403					Plugin.setupCellField.call();
5404					Plugin.setupTemplateCell.call();
5405
5406					// setup nested datatable, if option enabled
5407					Plugin.setupSubDatatable.call();
5408
5409					// setup extra system column properties
5410					Plugin.setupSystemColumn.call();
5411					Plugin.redraw();
5412				}
5413
5414				var width;
5415				var initialWidth = false;
5416				$(window).resize(function() {
5417					// issue: URL Bar Resizing on mobile, https://developers.google.com/web/updates/2016/12/url-bar-resizing
5418					// trigger datatable resize on width change only
5419					if ($(this).width() !== width) {
5420						width = $(this).width();
5421						Plugin.fullRender();
5422					}
5423					// get initial width
5424					if (!initialWidth) {
5425						width = $(this).width();
5426						initialWidth = true;
5427					}
5428				});
5429
5430				$(datatable).height('');
5431
5432				var prevKeyword = '';
5433				$(Plugin.getOption('search.input')).on('keyup', function(e) {
5434					if (Plugin.getOption('search.onEnter') && e.which !== 13) return;
5435					var keyword = $(this).val();
5436					// prevent multiple search request on every button keyup
5437					if (prevKeyword !== keyword) {
5438						Plugin.search(keyword);
5439						prevKeyword = keyword;
5440					}
5441				});
5442
5443				return datatable;
5444			},
5445
5446			/**
5447			 * Extract static HTML table content into datasource
5448			 */
5449			extractTable: function() {
5450				var columns = [];
5451				var headers = $(datatable).find('tr:first-child th').get().map(function(cell, i) {
5452					var field = $(cell).data('field');
5453					var title = $(cell).data('title');
5454					if (typeof field === 'undefined') {
5455						field = $(cell).text().trim();
5456					}
5457					if (typeof title === 'undefined') {
5458						title = $(cell).text().trim();
5459					}
5460					var column = {field: field, title: title};
5461					for (var ii in options.columns) {
5462						if (options.columns[ii].field === field) {
5463							column = $.extend(true, {}, options.columns[ii], column);
5464						}
5465					}
5466					columns.push(column);
5467					return field;
5468				});
5469				// auto create columns config
5470				options.columns = columns;
5471
5472				var rowProp = [];
5473				var source = [];
5474
5475				$(datatable).find('tr').each(function() {
5476					if ($(this).find('td').length) {
5477						rowProp.push($(this).prop('attributes'));
5478					}
5479					var td = {};
5480					$(this).find('td').each(function(i, cell) {
5481						td[headers[i]] = cell.innerHTML.trim();
5482					});
5483					if (!util.isEmpty(td)) {
5484						source.push(td);
5485					}
5486				});
5487
5488				options.data.attr.rowProps = rowProp;
5489				options.data.source = source;
5490			},
5491
5492			/**
5493			 * One time layout update on init
5494			 */
5495			layoutUpdate: function() {
5496				// setup nested datatable, if option enabled
5497				Plugin.setupSubDatatable.call();
5498
5499				// setup extra system column properties
5500				Plugin.setupSystemColumn.call();
5501
5502				// setup cell hover event
5503				Plugin.setupHover.call();
5504
5505				if (typeof options.detail === 'undefined'
5506					// temporary disable lock column in subtable
5507					&& Plugin.getDepth() === 1) {
5508					// lock columns handler
5509					Plugin.lockTable.call();
5510				}
5511
5512				Plugin.resetScroll();
5513
5514				// check if not is a locked column
5515				if (!Plugin.isLocked()) {
5516					Plugin.redraw.call();
5517					// check if its not a subtable and has autoHide option enabled
5518					if (!Plugin.isSubtable() && Plugin.getOption('rows.autoHide') === true) {
5519						Plugin.autoHide();
5520					}
5521					// reset row
5522					$(datatable.table).find('.' + pfx + 'datatable-row').css('height', '');
5523				}
5524
5525				Plugin.columnHide.call();
5526
5527				Plugin.rowEvenOdd.call();
5528
5529				Plugin.sorting.call();
5530
5531				Plugin.scrollbar.call();
5532
5533				if (!Plugin.isInit) {
5534					// run once dropdown inside datatable
5535					Plugin.dropdownFix();
5536					$(datatable).trigger(pfx + 'datatable-on-init', {table: $(datatable.wrap).attr('id'), options: options});
5537					Plugin.isInit = true;
5538				}
5539
5540				$(datatable).trigger(pfx + 'datatable-on-layout-updated', {table: $(datatable.wrap).attr('id')});
5541			},
5542
5543			dropdownFix: function() {
5544				var dropdownMenu;
5545				$('body').on('show.bs.dropdown', '.' + pfx + 'datatable .' + pfx + 'datatable-body', function(e) {
5546					dropdownMenu = $(e.target).find('.dropdown-menu');
5547					$('body').append(dropdownMenu.detach());
5548					dropdownMenu.css('display', 'block');
5549					dropdownMenu.position({
5550						'my': 'right top',
5551						'at': 'right bottom',
5552						'of': $(e.relatedTarget),
5553					});
5554					// if datatable is inside modal
5555					if (datatable.closest('.modal').length) {
5556						// increase dropdown z-index
5557						dropdownMenu.css('z-index', '2000');
5558					}
5559				}).on('hide.bs.dropdown', '.' + pfx + 'datatable .' + pfx + 'datatable-body', function(e) {
5560					$(e.target).append(dropdownMenu.detach());
5561					dropdownMenu.hide();
5562				});
5563
5564				// remove dropdown if window resize
5565				$(window).on('resize', function(e) {
5566					if (typeof dropdownMenu !== 'undefined') {
5567						dropdownMenu.hide();
5568					}
5569				});
5570			},
5571
5572			lockTable: function() {
5573				var lock = {
5574					lockEnabled: false,
5575					init: function() {
5576						// check if table should be locked columns
5577						lock.lockEnabled = Plugin.lockEnabledColumns();
5578						if (lock.lockEnabled.left.length === 0 &&
5579							lock.lockEnabled.right.length === 0) {
5580							return;
5581						}
5582						lock.enable();
5583					},
5584					enable: function() {
5585						var enableLock = function(tablePart) {
5586							// check if already has lock column
5587							if ($(tablePart).find('.' + pfx + 'datatable-lock').length > 0) {
5588								Plugin.log('Locked container already exist in: ', tablePart);
5589								return;
5590							}
5591							// check if no rows exists
5592							if ($(tablePart).find('.' + pfx + 'datatable-row').length === 0) {
5593								Plugin.log('No row exist in: ', tablePart);
5594								return;
5595							}
5596
5597							// locked div container
5598							var lockLeft = $('<div/>').addClass(pfx + 'datatable-lock ' + pfx + 'datatable-lock-left');
5599							var lockScroll = $('<div/>').addClass(pfx + 'datatable-lock ' + pfx + 'datatable-lock-scroll');
5600							var lockRight = $('<div/>').addClass(pfx + 'datatable-lock ' + pfx + 'datatable-lock-right');
5601
5602							$(tablePart).find('.' + pfx + 'datatable-row').each(function() {
5603								// create new row for lock columns and pass the data
5604								var rowLeft = $('<tr/>').addClass(pfx + 'datatable-row').data('obj', $(this).data('obj')).appendTo(lockLeft);
5605								var rowScroll = $('<tr/>').addClass(pfx + 'datatable-row').data('obj', $(this).data('obj')).appendTo(lockScroll);
5606								var rowRight = $('<tr/>').addClass(pfx + 'datatable-row').data('obj', $(this).data('obj')).appendTo(lockRight);
5607								$(this).find('.' + pfx + 'datatable-cell').each(function() {
5608									var locked = $(this).data('locked');
5609									if (typeof locked !== 'undefined') {
5610										if (typeof locked.left !== 'undefined' || locked === true) {
5611											// default locked to left
5612											$(this).appendTo(rowLeft);
5613										}
5614										if (typeof locked.right !== 'undefined') {
5615											$(this).appendTo(rowRight);
5616										}
5617									} else {
5618										$(this).appendTo(rowScroll);
5619									}
5620								});
5621								// remove old row
5622								$(this).remove();
5623							});
5624
5625							if (lock.lockEnabled.left.length > 0) {
5626								$(datatable.wrap).addClass(pfx + 'datatable-lock');
5627								$(lockLeft).appendTo(tablePart);
5628							}
5629							if (lock.lockEnabled.left.length > 0 || lock.lockEnabled.right.length > 0) {
5630								$(lockScroll).appendTo(tablePart);
5631							}
5632							if (lock.lockEnabled.right.length > 0) {
5633								$(datatable.wrap).addClass(pfx + 'datatable-lock');
5634								$(lockRight).appendTo(tablePart);
5635							}
5636						};
5637
5638						$(datatable.table).find('thead,tbody,tfoot').each(function() {
5639							var tablePart = this;
5640							if ($(this).find('.' + pfx + 'datatable-lock').length === 0) {
5641								$(this).ready(function() {
5642									enableLock(tablePart);
5643								});
5644							}
5645						});
5646					},
5647				};
5648				lock.init();
5649				return lock;
5650			},
5651
5652			/**
5653			 * Render everything for resize
5654			 */
5655			fullRender: function() {
5656				$(datatable.tableHead).empty();
5657				Plugin.setHeadTitle();
5658				if (Plugin.getOption('layout.footer')) {
5659					$(datatable.tableFoot).empty();
5660					Plugin.setHeadTitle(datatable.tableFoot);
5661				}
5662
5663				Plugin.spinnerCallback(true);
5664				$(datatable.wrap).removeClass(pfx + 'datatable-loaded');
5665
5666				Plugin.insertData();
5667			},
5668
5669			lockEnabledColumns: function() {
5670				var screen = $(window).width();
5671				var columns = options.columns;
5672				var enabled = {left: [], right: []};
5673				$.each(columns, function(i, column) {
5674					if (typeof column.locked !== 'undefined') {
5675						if (typeof column.locked.left !== 'undefined') {
5676							if (util.getBreakpoint(column.locked.left) <= screen) {
5677								enabled['left'].push(column.locked.left);
5678							}
5679						}
5680						if (typeof column.locked.right !== 'undefined') {
5681							if (util.getBreakpoint(column.locked.right) <= screen) {
5682								enabled['right'].push(column.locked.right);
5683							}
5684						}
5685					}
5686				});
5687				return enabled;
5688			},
5689
5690			/**
5691			 * After render event, called by "datatable-on-layout-updated"
5692			 * @param e
5693			 * @param args
5694			 */
5695			afterRender: function(e, args) {
5696				$(datatable).ready(function() {
5697					// redraw locked columns table
5698					if (Plugin.isLocked()) {
5699						Plugin.redraw();
5700					}
5701
5702					$(datatable.tableBody).css('visibility', '');
5703					$(datatable.wrap).addClass(pfx + 'datatable-loaded');
5704
5705					Plugin.spinnerCallback(false);
5706				});
5707			},
5708
5709			hoverTimer: 0,
5710			isScrolling: false,
5711			setupHover: function() {
5712				$(window).scroll(function(e) {
5713					// stop hover when scrolling
5714					clearTimeout(Plugin.hoverTimer);
5715					Plugin.isScrolling = true;
5716				});
5717
5718				$(datatable.tableBody).find('.' + pfx + 'datatable-cell').off('mouseenter', 'mouseleave').on('mouseenter', function() {
5719					// reset scroll timer to hover class
5720					Plugin.hoverTimer = setTimeout(function() {
5721						Plugin.isScrolling = false;
5722					}, 200);
5723					if (Plugin.isScrolling) return;
5724
5725					// normal table
5726					var row = $(this).closest('.' + pfx + 'datatable-row').addClass(pfx + 'datatable-row-hover');
5727					var index = $(row).index() + 1;
5728
5729					// lock table
5730					$(row).closest('.' + pfx + 'datatable-lock').parent().find('.' + pfx + 'datatable-row:nth-child(' + index + ')').addClass(pfx + 'datatable-row-hover');
5731				}).on('mouseleave', function() {
5732					// normal table
5733					var row = $(this).closest('.' + pfx + 'datatable-row').removeClass(pfx + 'datatable-row-hover');
5734					var index = $(row).index() + 1;
5735
5736					// look table
5737					$(row).closest('.' + pfx + 'datatable-lock').parent().find('.' + pfx + 'datatable-row:nth-child(' + index + ')').removeClass(pfx + 'datatable-row-hover');
5738				});
5739			},
5740
5741			/**
5742			 * Adjust width of locked table containers by resize handler
5743			 * @returns {number}
5744			 */
5745			adjustLockContainer: function() {
5746				if (!Plugin.isLocked()) return 0;
5747
5748				// refer to head dimension
5749				var containerWidth = $(datatable.tableHead).width();
5750				var lockLeft = $(datatable.tableHead).find('.' + pfx + 'datatable-lock-left').width();
5751				var lockRight = $(datatable.tableHead).find('.' + pfx + 'datatable-lock-right').width();
5752
5753				if (typeof lockLeft === 'undefined') lockLeft = 0;
5754				if (typeof lockRight === 'undefined') lockRight = 0;
5755
5756				var lockScroll = Math.floor(containerWidth - lockLeft - lockRight);
5757				$(datatable.table).find('.' + pfx + 'datatable-lock-scroll').css('width', lockScroll);
5758
5759				return lockScroll;
5760			},
5761
5762			/**
5763			 * todo; not in use
5764			 */
5765			dragResize: function() {
5766				var pressed = false;
5767				var start = undefined;
5768				var startX, startWidth;
5769				$(datatable.tableHead).find('.' + pfx + 'datatable-cell').mousedown(function(e) {
5770					start = $(this);
5771					pressed = true;
5772					startX = e.pageX;
5773					startWidth = $(this).width();
5774					$(start).addClass(pfx + 'datatable-cell-resizing');
5775
5776				}).mousemove(function(e) {
5777					if (pressed) {
5778						var i = $(start).index();
5779						var tableBody = $(datatable.tableBody);
5780						var ifLocked = $(start).closest('.' + pfx + 'datatable-lock');
5781
5782						if (ifLocked) {
5783							var lockedIndex = $(ifLocked).index();
5784							tableBody = $(datatable.tableBody).find('.' + pfx + 'datatable-lock').eq(lockedIndex);
5785						}
5786
5787						$(tableBody).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
5788							$(tr).find('.' + pfx + 'datatable-cell').eq(i).width(startWidth + (e.pageX - startX)).children().width(startWidth + (e.pageX - startX));
5789						});
5790
5791						$(start).children().css('width', startWidth + (e.pageX - startX));
5792					}
5793
5794				}).mouseup(function() {
5795					$(start).removeClass(pfx + 'datatable-cell-resizing');
5796					pressed = false;
5797				});
5798
5799				$(document).mouseup(function() {
5800					$(start).removeClass(pfx + 'datatable-cell-resizing');
5801					pressed = false;
5802				});
5803			},
5804
5805			/**
5806			 * To prepare placeholder for table before content is loading
5807			 */
5808			initHeight: function() {
5809				if (options.layout.height && options.layout.scroll) {
5810					var theadHeight = $(datatable.tableHead).find('.' + pfx + 'datatable-row').outerHeight();
5811					var tfootHeight = $(datatable.tableFoot).find('.' + pfx + 'datatable-row').outerHeight();
5812					var bodyHeight = options.layout.height;
5813					if (theadHeight > 0) {
5814						bodyHeight -= theadHeight;
5815					}
5816					if (tfootHeight > 0) {
5817						bodyHeight -= tfootHeight;
5818					}
5819
5820					// scrollbar offset
5821					bodyHeight -= 2;
5822
5823					$(datatable.tableBody).css('max-height', Math.floor(parseFloat(bodyHeight)));
5824
5825					// set scrollable area fixed height
5826					// $(datatable.tableBody).find('.' + pfx + 'datatable-lock-scroll').css('height', Math.floor(parseFloat(bodyHeight)));
5827				}
5828			},
5829
5830			/**
5831			 * Setup base DOM (table, thead, tbody, tfoot) and create if not
5832			 * exist.
5833			 */
5834			setupBaseDOM: function() {
5835				// keep original state before datatable initialize
5836				datatable.initialDatatable = $(datatable).clone();
5837
5838				// main element
5839				if ($(datatable).prop('tagName') === 'TABLE') {
5840					// if main init element is <table>, wrap with div
5841					datatable.table = $(datatable).removeClass(pfx + 'datatable').addClass(pfx + 'datatable-table');
5842					if ($(datatable.table).parents('.' + pfx + 'datatable').length === 0) {
5843						datatable.table.wrap($('<div/>').addClass(pfx + 'datatable').addClass(pfx + 'datatable-' + options.layout.theme));
5844						datatable.wrap = $(datatable.table).parent();
5845					}
5846				} else {
5847					// create table
5848					datatable.wrap = $(datatable).addClass(pfx + 'datatable').addClass(pfx + 'datatable-' + options.layout.theme);
5849					datatable.table = $('<table/>').addClass(pfx + 'datatable-table').appendTo(datatable);
5850				}
5851
5852				if (typeof options.layout.class !== 'undefined') {
5853					$(datatable.wrap).addClass(options.layout.class);
5854				}
5855
5856				$(datatable.table).removeClass(pfx + 'datatable-destroyed').css('display', 'block');
5857
5858				// force disable save state
5859				if (typeof $(datatable).attr('id') === 'undefined') {
5860					Plugin.setOption('data.saveState', false);
5861					$(datatable.table).attr('id', util.getUniqueID(pfx + 'datatable-'));
5862				}
5863
5864				// predefine table height
5865				if (Plugin.getOption('layout.minHeight'))
5866					$(datatable.table).css('min-height', Plugin.getOption('layout.minHeight'));
5867
5868				if (Plugin.getOption('layout.height'))
5869					$(datatable.table).css('max-height', Plugin.getOption('layout.height'));
5870
5871				// for normal table load
5872				if (options.data.type === null) {
5873					$(datatable.table).css('width', '').css('display', '');
5874				}
5875
5876				// create table head element
5877				datatable.tableHead = $(datatable.table).find('thead');
5878				if ($(datatable.tableHead).length === 0) {
5879					datatable.tableHead = $('<thead/>').prependTo(datatable.table);
5880				}
5881
5882				// create table head element
5883				datatable.tableBody = $(datatable.table).find('tbody');
5884				if ($(datatable.tableBody).length === 0) {
5885					datatable.tableBody = $('<tbody/>').appendTo(datatable.table);
5886				}
5887
5888				if (typeof options.layout.footer !== 'undefined' &&
5889					options.layout.footer) {
5890					// create table foot element
5891					datatable.tableFoot = $(datatable.table).find('tfoot');
5892					if ($(datatable.tableFoot).length === 0) {
5893						datatable.tableFoot = $('<tfoot/>').appendTo(datatable.table);
5894					}
5895				}
5896			},
5897
5898			/**
5899			 * Set column data before table manipulation.
5900			 */
5901			setupCellField: function(tableParts) {
5902				if (typeof tableParts === 'undefined') tableParts = $(datatable.table).children();
5903				var columns = options.columns;
5904				$.each(tableParts, function(part, tablePart) {
5905					$(tablePart).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
5906						// prepare data
5907						$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
5908							if (typeof columns[tdi] !== 'undefined') {
5909								$(td).data(columns[tdi]);
5910							}
5911						});
5912					});
5913				});
5914			},
5915
5916			/**
5917			 * Set column template callback
5918			 * @param tablePart
5919			 */
5920			setupTemplateCell: function(tablePart) {
5921				if (typeof tablePart === 'undefined') tablePart = datatable.tableBody;
5922				var columns = options.columns;
5923				$(tablePart).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
5924					// row data object, if any
5925					var obj = $(tr).data('obj');
5926					if (typeof obj === 'undefined') {
5927						return;
5928					}
5929
5930					// @deprecated in v5.0.6
5931					// obj['getIndex'] = function() {
5932					// 	return tri;
5933					// };
5934					// @deprecated in v5.0.6
5935					// obj['getDatatable'] = function() {
5936					// 	return datatable;
5937					// };
5938
5939					// @deprecated in v5.0.6
5940					var rowCallback = Plugin.getOption('rows.callback');
5941					if (typeof rowCallback === 'function') {
5942						rowCallback($(tr), obj, tri);
5943					}
5944					// before template row callback
5945					var beforeTemplate = Plugin.getOption('rows.beforeTemplate');
5946					if (typeof beforeTemplate === 'function') {
5947						beforeTemplate($(tr), obj, tri);
5948					}
5949					// if data object is undefined, collect from table
5950					if (typeof obj === 'undefined') {
5951						obj = {};
5952						$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
5953							// get column settings by field
5954							var column = $.grep(columns, function(n, i) {
5955								return $(td).data('field') === n.field;
5956							})[0];
5957							if (typeof column !== 'undefined') {
5958								obj[column['field']] = $(td).text();
5959							}
5960						});
5961					}
5962
5963					$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
5964						// get column settings by field
5965						var column = $.grep(columns, function(n, i) {
5966							return $(td).data('field') === n.field;
5967						})[0];
5968						if (typeof column !== 'undefined') {
5969							// column template
5970							if (typeof column.template !== 'undefined') {
5971								var finalValue = '';
5972								// template string
5973								if (typeof column.template === 'string') {
5974									finalValue = Plugin.dataPlaceholder(column.template, obj);
5975								}
5976								// template callback function
5977								if (typeof column.template === 'function') {
5978									finalValue = column.template(obj, tri, datatable);
5979								}
5980
5981								// sanitize using DOMPurify if installed
5982								if (typeof DOMPurify !== 'undefined') {
5983									finalValue = DOMPurify.sanitize(finalValue);
5984								}
5985
5986								var span = document.createElement('span');
5987								span.innerHTML = finalValue;
5988
5989								// insert to cell, wrap with span
5990								$(td).html(span);
5991
5992								// set span overflow
5993								if (typeof column.overflow !== 'undefined') {
5994									$(span).css('overflow', column.overflow);
5995									$(span).css('position', 'relative');
5996								}
5997							}
5998						}
5999					});
6000
6001					// after template row callback
6002					var afterTemplate = Plugin.getOption('rows.afterTemplate');
6003					if (typeof afterTemplate === 'function') {
6004						afterTemplate($(tr), obj, tri);
6005					}
6006				});
6007			},
6008
6009			/**
6010			 * Setup extra system column properties
6011			 * Note: selector checkbox, subtable toggle
6012			 */
6013			setupSystemColumn: function() {
6014				datatable.dataSet = datatable.dataSet || [];
6015				// no records available
6016				if (datatable.dataSet.length === 0) return;
6017
6018				var columns = options.columns;
6019				$(datatable.tableBody).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
6020					$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
6021						// get column settings by field
6022						var column = $.grep(columns, function(n, i) {
6023							return $(td).data('field') === n.field;
6024						})[0];
6025						if (typeof column !== 'undefined') {
6026							var value = $(td).text();
6027
6028							// enable column selector
6029							if (typeof column.selector !== 'undefined' && column.selector !== false) {
6030								// check if checkbox exist
6031								if ($(td).find('.' + pfx + 'checkbox [type="checkbox"]').length > 0) return;
6032
6033								$(td).addClass(pfx + 'datatable-cell-check');
6034
6035								// append checkbox
6036								var chk = $('<label/>').
6037									addClass(pfx + 'checkbox ' + pfx + 'checkbox-single').
6038									append($('<input/>').attr('type', 'checkbox').attr('value', value).on('click', function() {
6039										if ($(this).is(':checked')) {
6040											// add checkbox active row class
6041											Plugin.setActive(this);
6042										} else {
6043											// add checkbox active row class
6044											Plugin.setInactive(this);
6045										}
6046									})).
6047									append('&nbsp;<span></span>');
6048
6049								// checkbox selector has outline style
6050								if (typeof column.selector.class !== 'undefined') {
6051									$(chk).addClass(column.selector.class);
6052								}
6053
6054								$(td).children().html(chk);
6055							}
6056
6057							// enable column subtable toggle
6058							if (typeof column.subtable !== 'undefined' && column.subtable) {
6059								// check if subtable toggle exist
6060								if ($(td).find('.' + pfx + 'datatable-toggle-subtable').length > 0) return;
6061								// append subtable toggle
6062								$(td).
6063									children().
6064									html($('<a/>').
6065										addClass(pfx + 'datatable-toggle-subtable').
6066										attr('href', '#').
6067										attr('data-value', value).
6068										append($('<i/>').addClass(Plugin.getOption('layout.icons.rowDetail.collapse'))));
6069							}
6070						}
6071					});
6072				});
6073
6074				// init checkbox for header/footer
6075				var initCheckbox = function(tr) {
6076					// get column settings by field
6077					var column = $.grep(columns, function(n, i) {
6078						return typeof n.selector !== 'undefined' && n.selector !== false;
6079					})[0];
6080
6081					if (typeof column !== 'undefined') {
6082						// enable column selector
6083						if (typeof column.selector !== 'undefined' && column.selector !== false) {
6084							var td = $(tr).find('[data-field="' + column.field + '"]');
6085							// check if checkbox exist
6086							if ($(td).find('.' + pfx + 'checkbox [type="checkbox"]').length > 0) return;
6087
6088							$(td).addClass(pfx + 'datatable-cell-check');
6089
6090							// append checkbox
6091							var chk = $('<label/>').
6092								addClass(pfx + 'checkbox ' + pfx + 'checkbox-single ' + pfx + 'checkbox-all').
6093								append($('<input/>').attr('type', 'checkbox').on('click', function() {
6094									if ($(this).is(':checked')) {
6095										Plugin.setActiveAll(true);
6096									} else {
6097										Plugin.setActiveAll(false);
6098									}
6099								})).
6100								append('&nbsp;<span></span>');
6101
6102							// checkbox selector has outline style
6103							if (typeof column.selector.class !== 'undefined') {
6104								$(chk).addClass(column.selector.class);
6105							}
6106
6107							$(td).children().html(chk);
6108						}
6109					}
6110				};
6111
6112				if (options.layout.header) {
6113					initCheckbox($(datatable.tableHead).find('.' + pfx + 'datatable-row').first());
6114				}
6115				if (options.layout.footer) {
6116					initCheckbox($(datatable.tableFoot).find('.' + pfx + 'datatable-row').first());
6117				}
6118			},
6119
6120			maxWidthList: {},
6121
6122			/**
6123			 * Adjust width to match container size
6124			 */
6125			adjustCellsWidth: function() {
6126				// get table width
6127				var containerWidth = $(datatable.tableBody).innerWidth() - Plugin.iconOffset;
6128
6129				// get total number of columns
6130				var columns = $(datatable.tableHead).
6131					find('.' + pfx + 'datatable-row:first-child').
6132					find('.' + pfx + 'datatable-cell').
6133					// exclude expand icon
6134					not('.' + pfx + 'datatable-toggle-detail').
6135					not(':hidden').length;
6136
6137				if (columns > 0) {
6138					//  remove reserved sort icon width
6139					containerWidth = containerWidth - (Plugin.iconOffset * columns);
6140					var minWidth = Math.floor(containerWidth / columns);
6141
6142					// minimum width
6143					if (minWidth <= Plugin.cellOffset) {
6144						minWidth = Plugin.cellOffset;
6145					}
6146
6147					$(datatable.table).find('.' + pfx + 'datatable-row').
6148							find('.' + pfx + 'datatable-cell').
6149							// exclude expand icon
6150							not('.' + pfx + 'datatable-toggle-detail').
6151							not(':hidden').each(function(tdi, td) {
6152
6153						var width = minWidth;
6154						var dataWidth = $(td).data('width');
6155
6156						if (typeof dataWidth !== 'undefined') {
6157							if (dataWidth === 'auto') {
6158								var field = $(td).data('field');
6159								if (Plugin.maxWidthList[field]) {
6160									width = Plugin.maxWidthList[field];
6161								}
6162								else {
6163									var cells = $(datatable.table).find('.' + pfx + 'datatable-cell[data-field="' + field + '"]');
6164									width = Plugin.maxWidthList[field] = Math.max.apply(null,
6165											$(cells).map(function() {
6166												return $(this).outerWidth();
6167											}).get());
6168								}
6169							}
6170							else {
6171								width = dataWidth;
6172							}
6173						}
6174						$(td).children().css('width', Math.ceil(width));
6175					});
6176				}
6177
6178				return datatable;
6179			},
6180
6181			/**
6182			 * Adjust height to match container size
6183			 */
6184			adjustCellsHeight: function() {
6185				$.each($(datatable.table).children(), function(part, tablePart) {
6186					var totalRows = $(tablePart).find('.' + pfx + 'datatable-row').first().parent().find('.' + pfx + 'datatable-row').length;
6187					for (var i = 1; i <= totalRows; i++) {
6188						var rows = $(tablePart).find('.' + pfx + 'datatable-row:nth-child(' + i + ')');
6189						if ($(rows).length > 0) {
6190							var maxHeight = Math.max.apply(null, $(rows).map(function() {
6191								return $(this).outerHeight();
6192							}).get());
6193							$(rows).css('height', Math.ceil(maxHeight));
6194						}
6195					}
6196				});
6197			},
6198
6199			/**
6200			 * Setup table DOM and classes
6201			 */
6202			setupDOM: function(table) {
6203				// set table classes
6204				$(table).find('> thead').addClass(pfx + 'datatable-head');
6205				$(table).find('> tbody').addClass(pfx + 'datatable-body');
6206				$(table).find('> tfoot').addClass(pfx + 'datatable-foot');
6207				$(table).find('tr').addClass(pfx + 'datatable-row');
6208				$(table).find('tr > th, tr > td').addClass(pfx + 'datatable-cell');
6209				$(table).find('tr > th, tr > td').each(function(i, td) {
6210					if ($(td).find('span').length === 0) {
6211						$(td).wrapInner($('<span/>').css('width', Plugin.cellOffset));
6212					}
6213				});
6214			},
6215
6216			/**
6217			 * Default scrollbar
6218			 * @returns {{tableLocked: null, init: init, onScrolling:
6219			 *     onScrolling}}
6220			 */
6221			scrollbar: function() {
6222				var scroll = {
6223					scrollable: null,
6224					tableLocked: null,
6225					initPosition: null,
6226					init: function() {
6227						var screen = util.getViewPort().width;
6228						// setup scrollable datatable
6229						if (options.layout.scroll) {
6230							// add scrollable datatable class
6231							$(datatable.wrap).addClass(pfx + 'datatable-scroll');
6232
6233							var scrollable = $(datatable.tableBody).find('.' + pfx + 'datatable-lock-scroll');
6234
6235							// check if scrollable area have rows
6236							if ($(scrollable).find('.' + pfx + 'datatable-row').length > 0 && $(scrollable).length > 0) {
6237								scroll.scrollHead = $(datatable.tableHead).find('> .' + pfx + 'datatable-lock-scroll > .' + pfx + 'datatable-row');
6238								scroll.scrollFoot = $(datatable.tableFoot).find('> .' + pfx + 'datatable-lock-scroll > .' + pfx + 'datatable-row');
6239								scroll.tableLocked = $(datatable.tableBody).find('.' + pfx + 'datatable-lock:not(.' + pfx + 'datatable-lock-scroll)');
6240								if (Plugin.getOption('layout.customScrollbar') && util.detectIE() != 10 && screen > util.getBreakpoint('lg')) {
6241									scroll.initCustomScrollbar(scrollable[0]);
6242								} else {
6243									scroll.initDefaultScrollbar(scrollable);
6244								}
6245							} else if ($(datatable.tableBody).find('.' + pfx + 'datatable-row').length > 0) {
6246								scroll.scrollHead = $(datatable.tableHead).find('> .' + pfx + 'datatable-row');
6247								scroll.scrollFoot = $(datatable.tableFoot).find('> .' + pfx + 'datatable-row');
6248								if (Plugin.getOption('layout.customScrollbar') && util.detectIE() != 10 && screen > util.getBreakpoint('lg')) {
6249									scroll.initCustomScrollbar(datatable.tableBody);
6250								} else {
6251									scroll.initDefaultScrollbar(datatable.tableBody);
6252								}
6253							}
6254						}
6255					},
6256					initDefaultScrollbar: function(scrollable) {
6257						// get initial scroll position
6258						scroll.initPosition = $(scrollable).scrollLeft();
6259						$(scrollable).css('overflow-y', 'auto').off().on('scroll', scroll.onScrolling);
6260						$(scrollable).css('overflow-x', 'auto');
6261					},
6262					onScrolling: function(e) {
6263						var left = $(this).scrollLeft();
6264						var top = $(this).scrollTop();
6265						if (util.isRTL()) {
6266							// deduct initial position for RTL
6267							left = left - scroll.initPosition;
6268						}
6269						$(scroll.scrollHead).css('left', -left);
6270						$(scroll.scrollFoot).css('left', -left);
6271						$(scroll.tableLocked).each(function(i, table) {
6272							if (Plugin.isLocked()) {
6273								// scrollbar offset
6274								top -= 1;
6275							}
6276							$(table).css('top', -top);
6277						});
6278					},
6279					initCustomScrollbar: function(scrollable) {
6280						scroll.scrollable = scrollable;
6281						// create a new instance for table body with scrollbar
6282						Plugin.initScrollbar(scrollable);
6283						// get initial scroll position
6284						scroll.initPosition = $(scrollable).scrollLeft();
6285						$(scrollable).off().on('scroll', scroll.onScrolling);
6286					},
6287				};
6288				scroll.init();
6289				return scroll;
6290			},
6291
6292			/**
6293			 * Init custom scrollbar and reset position
6294			 * @param element
6295			 * @param options
6296			 */
6297			initScrollbar: function(element, options) {
6298				if (!element || !element.nodeName) {
6299					return;
6300				}
6301				$(datatable.tableBody).css('overflow', '');
6302				var ps = $(element).data('ps');
6303				if (util.hasClass(element, 'ps') && typeof ps !== 'undefined') {
6304					ps.update();
6305				} else {
6306					ps = new PerfectScrollbar(element, Object.assign({}, {
6307						wheelSpeed: 0.5,
6308						swipeEasing: true,
6309						// wheelPropagation: false,
6310						minScrollbarLength: 40,
6311						maxScrollbarLength: 300,
6312						suppressScrollX: Plugin.getOption('rows.autoHide') && !Plugin.isLocked()
6313					}, options));
6314					$(element).data('ps', ps);
6315				}
6316
6317				// reset perfect scrollbar on resize
6318				$(window).resize(function() {
6319					ps.update();
6320				});
6321			},
6322
6323			/**
6324			 * Set column title from options.columns settings
6325			 */
6326			setHeadTitle: function(tablePart) {
6327				if (typeof tablePart === 'undefined') tablePart = datatable.tableHead;
6328				tablePart = $(tablePart)[0];
6329				var columns = options.columns;
6330				var row = tablePart.getElementsByTagName('tr')[0];
6331				var ths = tablePart.getElementsByTagName('td');
6332
6333				if (typeof row === 'undefined') {
6334					row = document.createElement('tr');
6335					tablePart.appendChild(row);
6336				}
6337
6338				$.each(columns, function(i, column) {
6339					var th = ths[i];
6340					if (typeof th === 'undefined') {
6341						th = document.createElement('th');
6342						row.appendChild(th);
6343					}
6344
6345					// set column title
6346					if (typeof column['title'] !== 'undefined') {
6347						th.innerHTML = column.title;
6348						th.setAttribute('data-field', column.field);
6349						util.addClass(th, column.class);
6350						// set disable autoHide or force enable
6351						if (typeof column.autoHide !== 'undefined') {
6352							if (column.autoHide !== true) {
6353								th.setAttribute('data-autohide-disabled', column.autoHide);
6354							} else {
6355								th.setAttribute('data-autohide-enabled', column.autoHide);
6356							}
6357						}
6358						$(th).data(column);
6359					}
6360
6361					// set header attr option
6362					if (typeof column.attr !== 'undefined') {
6363						$.each(column.attr, function(key, val) {
6364							th.setAttribute(key, val);
6365						});
6366					}
6367
6368					// apply text align to thead/tfoot
6369					if (typeof column.textAlign !== 'undefined') {
6370						var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : '';
6371						util.addClass(th, align);
6372					}
6373				});
6374				Plugin.setupDOM(tablePart);
6375			},
6376
6377			/**
6378			 * Initiate to get remote or local data via ajax
6379			 */
6380			dataRender: function(action) {
6381				$(datatable.table).siblings('.' + pfx + 'datatable-pager').removeClass(pfx + 'datatable-paging-loaded');
6382
6383				var buildMeta = function() {
6384					datatable.dataSet = datatable.dataSet || [];
6385					Plugin.localDataUpdate();
6386					// local pagination meta
6387					var meta = Plugin.getDataSourceParam('pagination');
6388					if (meta.perpage === 0) {
6389						meta.perpage = options.data.pageSize || 10;
6390					}
6391					meta.total = datatable.dataSet.length;
6392					var start = Math.max(meta.perpage * (meta.page - 1), 0);
6393					var end = Math.min(start + meta.perpage, meta.total);
6394					datatable.dataSet = $(datatable.dataSet).slice(start, end);
6395					return meta;
6396				};
6397
6398				var afterGetData = function(result) {
6399					var localPagingCallback = function(ctx, meta) {
6400						if (!$(ctx.pager).hasClass(pfx + 'datatable-paging-loaded')) {
6401							$(ctx.pager).remove();
6402							ctx.init(meta);
6403						}
6404						$(ctx.pager).off().on(pfx + 'datatable-on-goto-page', function(e) {
6405							$(ctx.pager).remove();
6406							ctx.init(meta);
6407						});
6408
6409						var start = Math.max(meta.perpage * (meta.page - 1), 0);
6410						var end = Math.min(start + meta.perpage, meta.total);
6411
6412						Plugin.localDataUpdate();
6413						datatable.dataSet = $(datatable.dataSet).slice(start, end);
6414
6415						// insert data into table content
6416						Plugin.insertData();
6417					};
6418
6419					$(datatable.wrap).removeClass(pfx + 'datatable-error');
6420					// pagination enabled
6421					if (options.pagination) {
6422						if (options.data.serverPaging && options.data.type !== 'local') {
6423							// server pagination
6424							var serverMeta = Plugin.getObject('meta', result || null);
6425							if (serverMeta !== null) {
6426								Plugin.pagingObject = Plugin.paging(serverMeta);
6427							} else {
6428								// no meta object from server response, fallback to local pagination
6429								Plugin.pagingObject = Plugin.paging(buildMeta(), localPagingCallback);
6430							}
6431						} else {
6432							// local pagination can be used by remote data also
6433							Plugin.pagingObject = Plugin.paging(buildMeta(), localPagingCallback);
6434						}
6435					} else {
6436						// pagination is disabled
6437						Plugin.localDataUpdate();
6438					}
6439					// insert data into table content
6440					Plugin.insertData();
6441				};
6442
6443				// get local datasource
6444				if (options.data.type === 'local'
6445					// for remote json datasource
6446					// || typeof options.data.source.read === 'undefined' && datatable.dataSet !== null
6447					// for remote datasource, server sorting is disabled and data already received from remote
6448					|| options.data.serverSorting === false && action === 'sort'
6449					|| options.data.serverFiltering === false && action === 'search'
6450				) {
6451					setTimeout(function() {
6452						afterGetData();
6453						Plugin.setAutoColumns();
6454					});
6455					return;
6456				}
6457
6458				// getting data from remote only
6459				Plugin.getData().done(afterGetData);
6460			},
6461
6462			/**
6463			 * Process ajax data
6464			 */
6465			insertData: function() {
6466				datatable.dataSet = datatable.dataSet || [];
6467				var params = Plugin.getDataSourceParam();
6468
6469				// get row attributes
6470				var pagination = params.pagination;
6471				var start = (Math.max(pagination.page, 1) - 1) * pagination.perpage;
6472				var end = Math.min(pagination.page, pagination.pages) * pagination.perpage;
6473				var rowProps = {};
6474				if (typeof options.data.attr.rowProps !== 'undefined' && options.data.attr.rowProps.length) {
6475					rowProps = options.data.attr.rowProps.slice(start, end);
6476				}
6477
6478				var tableBody = document.createElement('tbody');
6479				tableBody.style.visibility = 'hidden';
6480				var colLength = options.columns.length;
6481
6482				$.each(datatable.dataSet, function(rowIndex, row) {
6483					var tr = document.createElement('tr');
6484					tr.setAttribute('data-row', rowIndex);
6485					// keep data object to row
6486					$(tr).data('obj', row);
6487
6488					if (typeof rowProps[rowIndex] !== 'undefined') {
6489						$.each(rowProps[rowIndex], function() {
6490							tr.setAttribute(this.name, this.value);
6491						});
6492					}
6493
6494					var cellIndex = 0;
6495					var tds = [];
6496					for (var a = 0; a < colLength; a += 1) {
6497						var column = options.columns[a];
6498						var classes = [];
6499						// add sorted class to cells
6500						if (Plugin.getObject('sort.field', params) === column.field) {
6501							classes.push(pfx + 'datatable-cell-sorted');
6502						}
6503
6504						// apply text align
6505						if (typeof column.textAlign !== 'undefined') {
6506							var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : '';
6507							classes.push(align);
6508						}
6509
6510						// var classAttr = '';
6511						if (typeof column.class !== 'undefined') {
6512							classes.push(column.class);
6513						}
6514
6515						var td = document.createElement('td');
6516						util.addClass(td, classes.join(' '));
6517						td.setAttribute('data-field', column.field);
6518						// set disable autoHide or force enable
6519						if (typeof column.autoHide !== 'undefined') {
6520							if (column.autoHide !== true) {
6521								td.setAttribute('data-autohide-disabled', column.autoHide);
6522							} else {
6523								td.setAttribute('data-autohide-enabled', column.autoHide);
6524							}
6525						}
6526						td.innerHTML = Plugin.getObject(column.field, row);
6527						td.setAttribute('aria-label', Plugin.getObject(column.field, row));
6528						tr.appendChild(td);
6529					}
6530
6531					tableBody.appendChild(tr);
6532				});
6533
6534				// display no records message
6535				if (datatable.dataSet.length === 0) {
6536					var errorSpan = document.createElement('span');
6537					util.addClass(errorSpan, pfx + 'datatable-error');
6538					errorSpan.innerHTML = Plugin.getOption('translate.records.noRecords');
6539					tableBody.appendChild(errorSpan);
6540					$(datatable.wrap).addClass(pfx + 'datatable-error ' + pfx + 'datatable-loaded');
6541					Plugin.spinnerCallback(false);
6542				}
6543
6544				// replace existing table body
6545				$(datatable.tableBody).replaceWith(tableBody);
6546				datatable.tableBody = tableBody;
6547
6548				// layout update
6549				Plugin.setupDOM(datatable.table);
6550				Plugin.setupCellField([datatable.tableBody]);
6551				Plugin.setupTemplateCell(datatable.tableBody);
6552				Plugin.layoutUpdate();
6553			},
6554
6555			updateTableComponents: function() {
6556				datatable.tableHead = $(datatable.table).children('thead').get(0);
6557				datatable.tableBody = $(datatable.table).children('tbody').get(0);
6558				datatable.tableFoot = $(datatable.table).children('tfoot').get(0);
6559			},
6560
6561			/**
6562			 * Call ajax for raw JSON data
6563			 */
6564			getData: function() {
6565				// Plugin.spinnerCallback(true);
6566
6567				var ajaxParams = {
6568					dataType: 'json',
6569					method: 'POST',
6570					data: {},
6571					timeout: Plugin.getOption('data.source.read.timeout') || 30000,
6572				};
6573
6574				if (options.data.type === 'local') {
6575					ajaxParams.url = options.data.source;
6576				}
6577
6578				if (options.data.type === 'remote') {
6579					var data = Plugin.getDataSourceParam();
6580					// remove if server params is not enabled
6581					if (!Plugin.getOption('data.serverPaging')) {
6582						delete data['pagination'];
6583					}
6584					if (!Plugin.getOption('data.serverSorting')) {
6585						delete data['sort'];
6586					}
6587					ajaxParams.data = $.extend({}, ajaxParams.data, Plugin.getOption('data.source.read.params'), data);
6588					ajaxParams = $.extend({}, ajaxParams, Plugin.getOption('data.source.read'));
6589
6590					if (typeof ajaxParams.url !== 'string') ajaxParams.url = Plugin.getOption('data.source.read');
6591					if (typeof ajaxParams.url !== 'string') ajaxParams.url = Plugin.getOption('data.source');
6592					// ajaxParams.data = $.extend(ajaxParams.data, data.pagination);
6593				}
6594
6595				return $.ajax(ajaxParams).done(function(response, textStatus, jqXHR) {
6596					datatable.lastResponse = response;
6597					// extendible data map callback for custom datasource
6598					datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(response);
6599					Plugin.setAutoColumns();
6600					$(datatable).trigger(pfx + 'datatable-on-ajax-done', [datatable.dataSet]);
6601				}).fail(function(jqXHR, textStatus, errorThrown) {
6602					$(datatable).trigger(pfx + 'datatable-on-ajax-fail', [jqXHR]);
6603					$(datatable.tableBody).html($('<span/>').addClass(pfx + 'datatable-error').html(Plugin.getOption('translate.records.noRecords')));
6604					$(datatable.wrap).addClass(pfx + 'datatable-error ' + pfx + 'datatable-loaded');
6605					Plugin.spinnerCallback(false);
6606				}).always(function() {
6607				});
6608			},
6609
6610			/**
6611			 * Pagination object
6612			 * @param meta if null, local pagination, otherwise remote
6613			 *     pagination
6614			 * @param callback for update data when navigating page
6615			 */
6616			paging: function(meta, callback) {
6617				var pg = {
6618					meta: null,
6619					pager: null,
6620					paginateEvent: null,
6621					pagerLayout: {pagination: null, info: null},
6622					callback: null,
6623					init: function(meta) {
6624						pg.meta = meta;
6625
6626						// parse pagination meta to integer
6627						pg.meta.page = parseInt(pg.meta.page);
6628						pg.meta.pages = parseInt(pg.meta.pages);
6629						pg.meta.perpage = parseInt(pg.meta.perpage);
6630						pg.meta.total = parseInt(pg.meta.total);
6631
6632						// always recount total pages
6633						pg.meta.pages = Math.max(Math.ceil(pg.meta.total / pg.meta.perpage), 1);
6634
6635						// current page must be not over than total pages
6636						if (pg.meta.page > pg.meta.pages) pg.meta.page = pg.meta.pages;
6637
6638						// set unique event name between tables
6639						pg.paginateEvent = Plugin.getTablePrefix('paging');
6640
6641						pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable-pager');
6642						if ($(pg.pager).hasClass(pfx + 'datatable-paging-loaded')) return;
6643
6644						// if class .'+pfx+'datatable-paging-loaded not exist, recreate pagination
6645						$(pg.pager).remove();
6646
6647						// if no pages available
6648						if (pg.meta.pages === 0) return;
6649
6650						// update datasource params
6651						Plugin.setDataSourceParam('pagination', {
6652							page: pg.meta.page,
6653							pages: pg.meta.pages,
6654							perpage: pg.meta.perpage,
6655							total: pg.meta.total,
6656						});
6657
6658						// default callback function, contains remote pagination handler
6659						pg.callback = pg.serverCallback;
6660						// custom callback function
6661						if (typeof callback === 'function') pg.callback = callback;
6662
6663						pg.addPaginateEvent();
6664						pg.populate();
6665
6666						pg.meta.page = Math.max(pg.meta.page || 1, pg.meta.page);
6667
6668						$(datatable).trigger(pg.paginateEvent, pg.meta);
6669
6670						pg.pagingBreakpoint.call();
6671						$(window).resize(pg.pagingBreakpoint);
6672					},
6673					serverCallback: function(ctx, meta) {
6674						Plugin.dataRender();
6675					},
6676					populate: function() {
6677						datatable.dataSet = datatable.dataSet || [];
6678						// no records available
6679						if (datatable.dataSet.length === 0) return;
6680
6681						var icons = Plugin.getOption('layout.icons.pagination');
6682						var title = Plugin.getOption('translate.toolbar.pagination.items.default');
6683						// pager root element
6684						pg.pager = $('<div/>').addClass(pfx + 'datatable-pager ' + pfx + 'datatable-paging-loaded');
6685						// numbering links
6686						var pagerNumber = $('<ul/>').addClass(pfx + 'datatable-pager-nav my-2 mb-sm-0');
6687						pg.pagerLayout['pagination'] = pagerNumber;
6688
6689						// pager first/previous button
6690						$('<li/>').
6691							append($('<a/>').
6692								attr('title', title.first).
6693								addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-first').
6694								append($('<i/>').addClass(icons.first)).
6695								on('click', pg.gotoMorePage).
6696								attr('data-page', 1)).
6697							appendTo(pagerNumber);
6698						$('<li/>').
6699							append($('<a/>').
6700								attr('title', title.prev).
6701								addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-prev').
6702								append($('<i/>').addClass(icons.prev)).
6703								on('click', pg.gotoMorePage)).
6704							appendTo(pagerNumber);
6705
6706						$('<li/>').append($('<input/>').attr('type', 'text').addClass(pfx + 'datatable-pager-input form-control').attr('title', title.input).on('keyup', function() {
6707							// on keyup update [data-page]
6708							$(this).attr('data-page', Math.abs($(this).val()));
6709						}).on('keypress', function(e) {
6710							// on keypressed enter button
6711							if (e.which === 13) pg.gotoMorePage(e);
6712						})).appendTo(pagerNumber);
6713
6714						var pagesNumber = Plugin.getOption('toolbar.items.pagination.pages.desktop.pagesNumber');
6715						var end = Math.ceil(pg.meta.page / pagesNumber) * pagesNumber;
6716						var start = end - pagesNumber;
6717						if (end > pg.meta.pages) {
6718							end = pg.meta.pages;
6719						}
6720
6721						// keep pagination 1 if there is no records
6722						if (start < 0) {
6723							start = 0;
6724						}
6725
6726						for (var x = start; x < (end || 1); x++) {
6727							var pageNumber = x + 1;
6728							$('<li/>').
6729								append($('<a/>').
6730									addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-number').
6731									text(pageNumber).
6732									attr('data-page', pageNumber).
6733									attr('title', pageNumber).
6734									on('click', pg.gotoPage)).
6735								appendTo(pagerNumber);
6736						}
6737
6738						// pager next/last button
6739						$('<li/>').
6740							append($('<a/>').
6741								attr('title', title.next).
6742								addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-next').
6743								append($('<i/>').addClass(icons.next)).
6744								on('click', pg.gotoMorePage)).
6745							appendTo(pagerNumber);
6746						$('<li/>').
6747							append($('<a/>').
6748								attr('title', title.last).
6749								addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-last').
6750								append($('<i/>').addClass(icons.last)).
6751								on('click', pg.gotoMorePage).
6752								attr('data-page', pg.meta.pages)).
6753							appendTo(pagerNumber);
6754
6755						// page info
6756						if (Plugin.getOption('toolbar.items.info')) {
6757							pg.pagerLayout['info'] = $('<div/>').addClass(pfx + 'datatable-pager-info my-2 mb-sm-0').append($('<span/>').addClass(pfx + 'datatable-pager-detail'));
6758						}
6759
6760						$.each(Plugin.getOption('toolbar.layout'), function(i, layout) {
6761							$(pg.pagerLayout[layout]).appendTo(pg.pager);
6762						});
6763
6764						// page size select
6765						var pageSizeSelect = $('<select/>').
6766							addClass('selectpicker ' + pfx + 'datatable-pager-size').
6767							attr('title', Plugin.getOption('translate.toolbar.pagination.items.default.select')).
6768							attr('data-width', '60px').
6769							attr('data-container', 'body').
6770							val(pg.meta.perpage).
6771							on('change', pg.updatePerpage).
6772							prependTo(pg.pagerLayout['info']);
6773
6774						var pageSizes = Plugin.getOption('toolbar.items.pagination.pageSizeSelect');
6775						// default value here, to fix override option by user
6776						if (pageSizes.length == 0) pageSizes = [5, 10, 20, 30, 50, 100];
6777						$.each(pageSizes, function(i, size) {
6778							var display = size;
6779							if (size === -1) display = Plugin.getOption('translate.toolbar.pagination.items.default.all');
6780							$('<option/>').attr('value', size).html(display).appendTo(pageSizeSelect);
6781						});
6782
6783						// init selectpicker to dropdown
6784						$(datatable).ready(function() {
6785							$('.selectpicker').
6786								selectpicker().
6787								on('hide.bs.select', function() {
6788									// fix dropup arrow icon on hide
6789									$(this).closest('.bootstrap-select').removeClass('dropup');
6790								}).
6791								siblings('.dropdown-toggle').
6792								attr('title', Plugin.getOption('translate.toolbar.pagination.items.default.select'));
6793						});
6794
6795						pg.paste();
6796					},
6797					paste: function() {
6798						// insert pagination based on placement position, top|bottom
6799						$.each($.unique(Plugin.getOption('toolbar.placement')),
6800							function(i, position) {
6801								if (position === 'bottom') {
6802									$(pg.pager).clone(true).insertAfter(datatable.table);
6803								}
6804								if (position === 'top') {
6805									// pager top need some extra space
6806									$(pg.pager).clone(true).addClass(pfx + 'datatable-pager-top').insertBefore(datatable.table);
6807								}
6808							});
6809					},
6810					gotoMorePage: function(e) {
6811						e.preventDefault();
6812						// $(this) is a link of .'+pfx+'datatable-pager-link
6813
6814						if ($(this).attr('disabled') === 'disabled') return false;
6815
6816						var page = $(this).attr('data-page');
6817
6818						// event from text input
6819						if (typeof page === 'undefined') {
6820							page = $(e.target).attr('data-page');
6821						}
6822
6823						pg.openPage(parseInt(page));
6824						return false;
6825					},
6826					gotoPage: function(e) {
6827						e.preventDefault();
6828						// prevent from click same page number
6829						if ($(this).hasClass(pfx + 'datatable-pager-link-active')) return;
6830
6831						pg.openPage(parseInt($(this).data('page')));
6832					},
6833					openPage: function(page) {
6834						// currentPage is 1-based index
6835						pg.meta.page = parseInt(page);
6836
6837						$(datatable).trigger(pg.paginateEvent, pg.meta);
6838						pg.callback(pg, pg.meta);
6839
6840						// update page callback function
6841						$(pg.pager).trigger(pfx + 'datatable-on-goto-page', pg.meta);
6842					},
6843					updatePerpage: function(e) {
6844						e.preventDefault();
6845						// if (Plugin.getOption('layout.height') === null) {
6846						// fix white space, when perpage is set from many records to less records
6847						// $('html, body').animate({scrollTop: $(datatable).position().top});
6848						// }
6849
6850						// hide dropdown after select
6851						$(this).selectpicker('toggle');
6852
6853						pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable-pager').removeClass(pfx + 'datatable-paging-loaded');
6854
6855						// on change select page size
6856						if (e.originalEvent) {
6857							pg.meta.perpage = parseInt($(this).val());
6858						}
6859
6860						$(pg.pager).find('select.' + pfx + 'datatable-pager-size').val(pg.meta.perpage).attr('data-selected', pg.meta.perpage);
6861
6862						// update datasource params
6863						Plugin.setDataSourceParam('pagination', {
6864							page: pg.meta.page,
6865							pages: pg.meta.pages,
6866							perpage: pg.meta.perpage,
6867							total: pg.meta.total,
6868						});
6869
6870						// update page callback function
6871						$(pg.pager).trigger(pfx + 'datatable-on-update-perpage', pg.meta);
6872						$(datatable).trigger(pg.paginateEvent, pg.meta);
6873						pg.callback(pg, pg.meta);
6874
6875						// update pagination info
6876						pg.updateInfo.call();
6877					},
6878					addPaginateEvent: function(e) {
6879						// pagination event
6880						$(datatable).off(pg.paginateEvent).on(pg.paginateEvent, function(e, meta) {
6881							Plugin.spinnerCallback(true);
6882
6883							pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable-pager');
6884							var pagerNumber = $(pg.pager).find('.' + pfx + 'datatable-pager-nav');
6885
6886							// set sync active page class
6887							$(pagerNumber).find('.' + pfx + 'datatable-pager-link-active').removeClass(pfx + 'datatable-pager-link-active');
6888							$(pagerNumber).find('.' + pfx + 'datatable-pager-link-number[data-page="' + meta.page + '"]').addClass(pfx + 'datatable-pager-link-active');
6889
6890							// set next and previous link page number
6891							$(pagerNumber).find('.' + pfx + 'datatable-pager-link-prev').attr('data-page', Math.max(meta.page - 1, 1));
6892							$(pagerNumber).find('.' + pfx + 'datatable-pager-link-next').attr('data-page', Math.min(meta.page + 1, meta.pages));
6893
6894							// current page input value sync
6895							$(pg.pager).each(function() {
6896								$(this).find('.' + pfx + 'datatable-pager-input[type="text"]').prop('value', meta.page);
6897							});
6898
6899							// if only 1 page, should hide page?
6900							// $(pg.pager).find('.' + pfx + 'datatable-pager-nav').show();
6901							// if (meta.pages <= 1) {
6902							// 	// hide pager if has 1 page
6903							// 	$(pg.pager).find('.' + pfx + 'datatable-pager-nav').hide();
6904							// }
6905
6906							// update datasource params
6907							Plugin.setDataSourceParam('pagination', {
6908								page: pg.meta.page,
6909								pages: pg.meta.pages,
6910								perpage: pg.meta.perpage,
6911								total: pg.meta.total,
6912							});
6913
6914							$(pg.pager).find('select.' + pfx + 'datatable-pager-size').val(meta.perpage).attr('data-selected', meta.perpage);
6915
6916							// clear active rows
6917							$(datatable.table).find('.' + pfx + 'checkbox > [type="checkbox"]').prop('checked', false);
6918							$(datatable.table).find('.' + pfx + 'datatable-row-active').removeClass(pfx + 'datatable-row-active');
6919
6920							pg.updateInfo.call();
6921							pg.pagingBreakpoint.call();
6922							// Plugin.resetScroll();
6923						});
6924					},
6925					updateInfo: function() {
6926						var start = Math.max(pg.meta.perpage * (pg.meta.page - 1) + 1, 1);
6927						var end = Math.min(start + pg.meta.perpage - 1, pg.meta.total);
6928						// page info update
6929						$(pg.pager).find('.' + pfx + 'datatable-pager-info').find('.' + pfx + 'datatable-pager-detail').html(Plugin.dataPlaceholder(
6930							Plugin.getOption('translate.toolbar.pagination.items.info'), {
6931								// set start page 0 if the is no records. eg. Showing 0 - 0 of 0
6932								start: pg.meta.total === 0 ? 0 : start,
6933								end: pg.meta.perpage === -1 ? pg.meta.total : end,
6934								pageSize: pg.meta.perpage === -1 ||
6935								pg.meta.perpage >= pg.meta.total
6936									? pg.meta.total
6937									: pg.meta.perpage,
6938								total: pg.meta.total,
6939							}));
6940					},
6941
6942					/**
6943					 * Update pagination layout breakpoint
6944					 */
6945					pagingBreakpoint: function() {
6946						// keep page links reference
6947						var pagerNumber = $(datatable.table).siblings('.' + pfx + 'datatable-pager').find('.' + pfx + 'datatable-pager-nav');
6948						if ($(pagerNumber).length === 0) return;
6949
6950						var currentPage = Plugin.getCurrentPage();
6951						var pagerInput = $(pagerNumber).find('.' + pfx + 'datatable-pager-input').closest('li');
6952
6953						// reset
6954						$(pagerNumber).find('li').show();
6955
6956						// pagination update
6957						$.each(Plugin.getOption('toolbar.items.pagination.pages'),
6958							function(mode, option) {
6959								if (util.isInResponsiveRange(mode)) {
6960									switch (mode) {
6961										case 'desktop':
6962										case 'tablet':
6963											var end = Math.ceil(currentPage / option.pagesNumber) * option.pagesNumber;
6964											var start = end - option.pagesNumber;
6965											$(pagerInput).hide();
6966											pg.meta = Plugin.getDataSourceParam('pagination');
6967											pg.paginationUpdate();
6968											break;
6969
6970										case 'mobile':
6971											$(pagerInput).show();
6972											$(pagerNumber).find('.' + pfx + 'datatable-pager-link-more-prev').closest('li').hide();
6973											$(pagerNumber).find('.' + pfx + 'datatable-pager-link-more-next').closest('li').hide();
6974											$(pagerNumber).find('.' + pfx + 'datatable-pager-link-number').closest('li').hide();
6975											break;
6976									}
6977
6978									return false;
6979								}
6980							});
6981					},
6982
6983					/**
6984					 * Update pagination number and button display
6985					 */
6986					paginationUpdate: function() {
6987						var pager = $(datatable.table).siblings('.' + pfx + 'datatable-pager').find('.' + pfx + 'datatable-pager-nav'),
6988							pagerMorePrev = $(pager).find('.' + pfx + 'datatable-pager-link-more-prev'),
6989							pagerMoreNext = $(pager).find('.' + pfx + 'datatable-pager-link-more-next'),
6990							pagerFirst = $(pager).find('.' + pfx + 'datatable-pager-link-first'),
6991							pagerPrev = $(pager).find('.' + pfx + 'datatable-pager-link-prev'),
6992							pagerNext = $(pager).find('.' + pfx + 'datatable-pager-link-next'),
6993							pagerLast = $(pager).find('.' + pfx + 'datatable-pager-link-last');
6994
6995						// get visible page
6996						var pagerNumber = $(pager).find('.' + pfx + 'datatable-pager-link-number');
6997						// get page before of first visible
6998						var morePrevPage = Math.max($(pagerNumber).first().data('page') - 1, 1);
6999						$(pagerMorePrev).each(function(i, prev) {
7000							$(prev).attr('data-page', morePrevPage);
7001						});
7002						// show/hide <li>
7003						if (morePrevPage === 1) {
7004							$(pagerMorePrev).parent().hide();
7005						} else {
7006							$(pagerMorePrev).parent().show();
7007						}
7008
7009						// get page after of last visible
7010						var moreNextPage = Math.min($(pagerNumber).last().data('page') + 1,
7011							pg.meta.pages);
7012						$(pagerMoreNext).each(function(i, prev) {
7013							$(pagerMoreNext).attr('data-page', moreNextPage).show();
7014						});
7015
7016						// show/hide <li>
7017						if (moreNextPage === pg.meta.pages
7018							// missing dot fix when last hidden page is one left
7019							&& moreNextPage === $(pagerNumber).last().data('page')) {
7020							$(pagerMoreNext).parent().hide();
7021						} else {
7022							$(pagerMoreNext).parent().show();
7023						}
7024
7025						// begin/end of pages
7026						if (pg.meta.page === 1) {
7027							$(pagerFirst).attr('disabled', true).addClass(pfx + 'datatable-pager-link-disabled');
7028							$(pagerPrev).attr('disabled', true).addClass(pfx + 'datatable-pager-link-disabled');
7029						} else {
7030							$(pagerFirst).removeAttr('disabled').removeClass(pfx + 'datatable-pager-link-disabled');
7031							$(pagerPrev).removeAttr('disabled').removeClass(pfx + 'datatable-pager-link-disabled');
7032						}
7033						if (pg.meta.page === pg.meta.pages) {
7034							$(pagerNext).attr('disabled', true).addClass(pfx + 'datatable-pager-link-disabled');
7035							$(pagerLast).attr('disabled', true).addClass(pfx + 'datatable-pager-link-disabled');
7036						} else {
7037							$(pagerNext).removeAttr('disabled').removeClass(pfx + 'datatable-pager-link-disabled');
7038							$(pagerLast).removeAttr('disabled').removeClass(pfx + 'datatable-pager-link-disabled');
7039						}
7040
7041						// display more buttons
7042						var nav = Plugin.getOption('toolbar.items.pagination.navigation');
7043						if (!nav.first) $(pagerFirst).remove();
7044						if (!nav.prev) $(pagerPrev).remove();
7045						if (!nav.next) $(pagerNext).remove();
7046						if (!nav.last) $(pagerLast).remove();
7047						if (!nav.more) {
7048							$(pagerMorePrev).remove();
7049							$(pagerMoreNext).remove();
7050						}
7051					},
7052				};
7053				pg.init(meta);
7054				return pg;
7055			},
7056
7057			/**
7058			 * Hide/show table cell defined by
7059			 * options[columns][i][responsive][visible/hidden]
7060			 */
7061			columnHide: function() {
7062				var screen = util.getViewPort().width;
7063				// foreach columns setting
7064				$.each(options.columns, function(i, column) {
7065					if (typeof column.responsive !== 'undefined' || typeof column.visible !== 'undefined') {
7066						var field = column.field;
7067						var tds = $.grep($(datatable.table).find('.' + pfx + 'datatable-cell'), function(n, i) {
7068							return field === $(n).data('field');
7069						});
7070
7071						setTimeout(function () {
7072							// hide by force
7073							if (Plugin.getObject('visible', column) === false) {
7074								$(tds).hide();
7075							} else {
7076								// show/hide by responsive breakpoint
7077								if (util.getBreakpoint(Plugin.getObject('responsive.hidden', column)) >= screen) {
7078									$(tds).hide();
7079								} else {
7080									$(tds).show();
7081								}
7082								if (util.getBreakpoint(Plugin.getObject('responsive.visible', column)) <= screen) {
7083									$(tds).show();
7084								} else {
7085									$(tds).hide();
7086								}
7087							}
7088						});
7089					}
7090				});
7091			},
7092
7093			/**
7094			 * Setup sub datatable
7095			 */
7096			setupSubDatatable: function() {
7097				var subTableCallback = Plugin.getOption('detail.content');
7098				if (typeof subTableCallback !== 'function') return;
7099
7100				// subtable already exist
7101				if ($(datatable.table).find('.' + pfx + 'datatable-subtable').length > 0) return;
7102
7103				$(datatable.wrap).addClass(pfx + 'datatable-subtable');
7104
7105				options.columns[0]['subtable'] = true;
7106
7107				// toggle on open sub table
7108				var toggleSubTable = function(e) {
7109					e.preventDefault();
7110					// get parent row of this subtable
7111					var parentRow = $(this).closest('.' + pfx + 'datatable-row');
7112
7113					// get subtable row for sub table
7114					var subTableRow = $(parentRow).next('.' + pfx + 'datatable-row-subtable');
7115					if ($(subTableRow).length === 0) {
7116						// prepare DOM for sub table, each <tr> as parent and add <tr> as child table
7117						subTableRow = $('<tr/>').
7118							addClass(pfx + 'datatable-row-subtable ' + pfx + 'datatable-row-loading').
7119							hide().
7120							append($('<td/>').addClass(pfx + 'datatable-subtable').attr('colspan', Plugin.getTotalColumns()));
7121						$(parentRow).after(subTableRow);
7122						// add class to even row
7123						if ($(parentRow).hasClass(pfx + 'datatable-row-even')) {
7124							$(subTableRow).addClass(pfx + 'datatable-row-subtable-even');
7125						}
7126					}
7127
7128					$(subTableRow).toggle();
7129
7130					var subTable = $(subTableRow).find('.' + pfx + 'datatable-subtable');
7131
7132					// get id from first column of parent row
7133					var primaryKey = $(this).closest('[data-field]:first-child').find('.' + pfx + 'datatable-toggle-subtable').data('value');
7134
7135					var icon = $(this).find('i').removeAttr('class');
7136
7137					// prevent duplicate datatable init
7138					if ($(parentRow).hasClass(pfx + 'datatable-row-subtable-expanded')) {
7139						$(icon).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'));
7140						// remove expand class from parent row
7141						$(parentRow).removeClass(pfx + 'datatable-row-subtable-expanded');
7142						// trigger event on collapse
7143						$(datatable).trigger(pfx + 'datatable-on-collapse-subtable', [parentRow]);
7144					} else {
7145						// expand and run callback function
7146						$(icon).addClass(Plugin.getOption('layout.icons.rowDetail.expand'));
7147						// add expand class to parent row
7148						$(parentRow).addClass(pfx + 'datatable-row-subtable-expanded');
7149						// trigger event on expand
7150						$(datatable).trigger(pfx + 'datatable-on-expand-subtable', [parentRow]);
7151					}
7152
7153					// prevent duplicate datatable init
7154					if ($(subTable).find('.' + pfx + 'datatable').length === 0) {
7155						// get data by primary id
7156						$.map(datatable.dataSet, function(n, i) {
7157							// primary id must be at the first column, otherwise e.data will be undefined
7158							if (primaryKey === n[options.columns[0].field]) {
7159								e.data = n;
7160								return true;
7161							}
7162							return false;
7163						});
7164
7165						// deprecated in v5.0.6
7166						e.detailCell = subTable;
7167
7168						e.parentRow = parentRow;
7169						e.subTable = subTable;
7170
7171						// run callback with event
7172						subTableCallback(e);
7173
7174						$(subTable).children('.' + pfx + 'datatable').on(pfx + 'datatable-on-init', function(e) {
7175							$(subTableRow).removeClass(pfx + 'datatable-row-loading');
7176						});
7177						if (Plugin.getOption('data.type') === 'local') {
7178							$(subTableRow).removeClass(pfx + 'datatable-row-loading');
7179						}
7180					}
7181				};
7182
7183				var columns = options.columns;
7184				$(datatable.tableBody).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
7185					$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
7186						// get column settings by field
7187						var column = $.grep(columns, function(n, i) {
7188							return $(td).data('field') === n.field;
7189						})[0];
7190						if (typeof column !== 'undefined') {
7191							var value = $(td).text();
7192							// enable column subtable toggle
7193							if (typeof column.subtable !== 'undefined' && column.subtable) {
7194								// check if subtable toggle exist
7195								if ($(td).find('.' + pfx + 'datatable-toggle-subtable').length > 0) return;
7196								// append subtable toggle
7197								$(td).
7198									html($('<a/>').
7199										addClass(pfx + 'datatable-toggle-subtable').
7200										attr('href', '#').
7201										attr('data-value', value).
7202										attr('title', Plugin.getOption('detail.title')).
7203										on('click', toggleSubTable).
7204										append($('<i/>').css('width', $(td).data('width')).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'))));
7205							}
7206						}
7207					});
7208				});
7209
7210				// $(datatable.tableHead).find('.'+pfx+'-datatable-row').first()
7211			},
7212
7213			/**
7214			 * Datasource mapping callback
7215			 */
7216			dataMapCallback: function(raw) {
7217				// static dataset array
7218				var dataSet = raw;
7219				// dataset mapping callback
7220				if (typeof Plugin.getOption('data.source.read.map') === 'function') {
7221					return Plugin.getOption('data.source.read.map')(raw);
7222				} else {
7223					// default data mapping fallback
7224					if (typeof raw !== 'undefined' && typeof raw.data !== 'undefined') {
7225						dataSet = raw.data;
7226					}
7227				}
7228				return dataSet;
7229			},
7230
7231			isSpinning: false,
7232			/**
7233			 * BlockUI spinner callback
7234			 * @param block
7235			 * @param target
7236			 */
7237			spinnerCallback: function(block, target) {
7238				if (typeof target === 'undefined') target = datatable;
7239				// get spinner options
7240				var spinnerOptions = Plugin.getOption('layout.spinner');
7241				// spinner is disabled
7242				if (typeof spinnerOptions === 'undefined' || !spinnerOptions) {
7243					return;
7244				}
7245				if (block) {
7246					if (!Plugin.isSpinning) {
7247						if (typeof spinnerOptions.message !== 'undefined' && spinnerOptions.message === true) {
7248							// use default spinner message from translation
7249							spinnerOptions.message = Plugin.getOption('translate.records.processing');
7250						}
7251						Plugin.isSpinning = true;
7252						if (typeof app !== 'undefined') {
7253							app.block(target, spinnerOptions);
7254						}
7255					}
7256				} else {
7257					Plugin.isSpinning = false;
7258					if (typeof app !== 'undefined') {
7259						app.unblock(target);
7260					}
7261				}
7262			},
7263
7264			/**
7265			 * Default sort callback function
7266			 * @param data
7267			 * @param sort
7268			 * @param column
7269			 * @returns {*|Array.<T>|{sort, field}|{asc, desc}}
7270			 */
7271			sortCallback: function(data, sort, column) {
7272				var type = column['type'] || 'string';
7273				var format = column['format'] || '';
7274				var field = column['field'];
7275
7276				return $(data).sort(function(a, b) {
7277					var aField = a[field];
7278					var bField = b[field];
7279
7280					switch (type) {
7281						case 'date':
7282							if (typeof moment === 'undefined') {
7283								throw new Error('Moment.js is required.');
7284							}
7285							var diff = moment(aField, format).diff(moment(bField, format));
7286							if (sort === 'asc') {
7287								return diff > 0 ? 1 : diff < 0 ? -1 : 0;
7288							} else {
7289								return diff < 0 ? 1 : diff > 0 ? -1 : 0;
7290							}
7291							break;
7292
7293						case 'number':
7294							if (isNaN(parseFloat(aField)) && aField != null) {
7295								aField = Number(aField.replace(/[^0-9\.-]+/g, ''));
7296							}
7297							if (isNaN(parseFloat(bField)) && bField != null) {
7298								bField = Number(bField.replace(/[^0-9\.-]+/g, ''));
7299							}
7300							aField = parseFloat(aField);
7301							bField = parseFloat(bField);
7302							if (sort === 'asc') {
7303								return aField > bField ? 1 : aField < bField ? -1 : 0;
7304							} else {
7305								return aField < bField ? 1 : aField > bField ? -1 : 0;
7306							}
7307							break;
7308
7309						case 'html':
7310							return $(data).sort(function(a, b) {
7311								// get the text only from html
7312								aField = $(a[field]).text();
7313								bField = $(b[field]).text();
7314								// sort
7315								if (sort === 'asc') {
7316									return aField > bField ? 1 : aField < bField ? -1 : 0;
7317								} else {
7318									return aField < bField ? 1 : aField > bField ? -1 : 0;
7319								}
7320							});
7321							break;
7322
7323						case 'string':
7324						default:
7325							if (sort === 'asc') {
7326								return aField > bField ? 1 : aField < bField ? -1 : 0;
7327							} else {
7328								return aField < bField ? 1 : aField > bField ? -1 : 0;
7329							}
7330							break;
7331					}
7332				});
7333			},
7334
7335			/**
7336			 * Custom debug log
7337			 * @param text
7338			 * @param obj
7339			 */
7340			log: function(text, obj) {
7341				if (typeof obj === 'undefined') obj = '';
7342				if (datatable.debug) {
7343					console.log(text, obj);
7344				}
7345			},
7346
7347			/**
7348			 * Auto hide columnds overflow in row
7349			 */
7350			autoHide: function() {
7351				var hiddenExist = false;
7352				// force hide enabled
7353				var hidDefault = $(datatable.table).find('[data-autohide-enabled]');
7354				if (hidDefault.length) {
7355					hiddenExist = true;
7356					hidDefault.hide();
7357				}
7358
7359				var toggleHiddenColumns = function(e) {
7360					e.preventDefault();
7361
7362					var row = $(this).closest('.' + pfx + 'datatable-row');
7363					var detailRow = $(row).next();
7364
7365					if (!$(detailRow).hasClass(pfx + 'datatable-row-detail')) {
7366						$(this).find('i').removeClass(Plugin.getOption('layout.icons.rowDetail.collapse')).addClass(Plugin.getOption('layout.icons.rowDetail.expand'));
7367
7368						var hiddenCells = $(row).find('.' + pfx + 'datatable-cell:hidden');
7369						var clonedCells = hiddenCells.clone().show();
7370
7371						detailRow = $('<tr/>').addClass(pfx + 'datatable-row-detail').insertAfter(row);
7372						var detailRowTd = $('<td/>').addClass(pfx + 'datatable-detail').attr('colspan', Plugin.getTotalColumns()).appendTo(detailRow);
7373
7374						var detailSubTable = $('<table/>');
7375						$(clonedCells).each(function() {
7376							var field = $(this).data('field');
7377							var column = $.grep(options.columns, function(n, i) {
7378								return field === n.field;
7379							})[0];
7380							if (typeof column === 'undefined' || column.visible !== false) {
7381								$(detailSubTable).
7382										append($('<tr class="' + pfx + 'datatable-row"></tr>').
7383												append($('<td class="' + pfx + 'datatable-cell"></td>').append($('<span/>').append(column.title))).
7384												append(this));
7385							}
7386						});
7387						$(detailRowTd).append(detailSubTable);
7388
7389					} else {
7390						$(this).find('i').removeClass(Plugin.getOption('layout.icons.rowDetail.expand')).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'));
7391						$(detailRow).remove();
7392					}
7393				};
7394
7395				setTimeout(function () {
7396					$(datatable.table).find('.' + pfx + 'datatable-cell').show();
7397					$(datatable.tableBody).each(function() {
7398						var recursive = 0;
7399						while ($(this)[0].offsetWidth < $(this)[0].scrollWidth && recursive < options.columns.length) {
7400							$(datatable.table).find('.' + pfx + 'datatable-row').each(function(i) {
7401								var cell = $(this).find('.' + pfx + 'datatable-cell:not(:hidden):not([data-autohide-disabled])').last();
7402									if (cell.length) {
7403										$(cell).hide();
7404										hiddenExist = true;
7405									}
7406							});
7407							recursive++;
7408						}
7409					});
7410
7411					if (hiddenExist) {
7412						// toggle show hidden columns
7413						$(datatable.tableBody).find('.' + pfx + 'datatable-row').each(function() {
7414							// if no toggle yet
7415							if($(this).find('.' + pfx + 'datatable-toggle-detail').length === 0) {
7416								// add toggle
7417								$(this).prepend($('<td/>').
7418										addClass(pfx + 'datatable-cell ' + pfx + 'datatable-toggle-detail').
7419										append($('<a/>').
7420											addClass(pfx + 'datatable-toggle-detail').
7421											attr('href', '').
7422											on('click', toggleHiddenColumns).
7423											append('<i class="' + Plugin.getOption('layout.icons.rowDetail.collapse') + '"></i>')));
7424							}
7425
7426							// check if subtable toggle exist
7427							if ($(datatable.tableHead).find('.' + pfx + 'datatable-toggle-detail').length === 0) {
7428								// add empty column to the header and footer
7429								$(datatable.tableHead).
7430									find('.' + pfx + 'datatable-row').
7431									first().
7432									prepend('<th class="' + pfx + 'datatable-cell ' + pfx + 'datatable-toggle-detail"><span></span></th>');
7433								$(datatable.tableFoot).
7434									find('.' + pfx + 'datatable-row').
7435									first().
7436									prepend('<th class="' + pfx + 'datatable-cell ' + pfx + 'datatable-toggle-detail"><span></span></th>');
7437							} else {
7438								$(datatable.tableHead).find('.' + pfx + 'datatable-toggle-detail').find('span');
7439							}
7440						});
7441					}
7442				});
7443
7444				Plugin.adjustCellsWidth.call();
7445			},
7446
7447			/**
7448			 * To enable auto columns features for remote data source
7449			 */
7450			setAutoColumns: function() {
7451				if (Plugin.getOption('data.autoColumns')) {
7452					$.each(datatable.dataSet[0], function(k, v) {
7453						var found = $.grep(options.columns, function(n, i) {
7454							return k === n.field;
7455						});
7456						if (found.length === 0) {
7457							options.columns.push({field: k, title: k});
7458						}
7459					});
7460					$(datatable.tableHead).find('.' + pfx + 'datatable-row').remove();
7461					Plugin.setHeadTitle();
7462					if (Plugin.getOption('layout.footer')) {
7463						$(datatable.tableFoot).find('.' + pfx + 'datatable-row').remove();
7464						Plugin.setHeadTitle(datatable.tableFoot);
7465					}
7466				}
7467			},
7468
7469			/********************
7470			 ** HELPERS
7471			 ********************/
7472
7473			/**
7474			 * Check if table is a locked colums table
7475			 */
7476			isLocked: function() {
7477				var isLocked = Plugin.lockEnabledColumns();
7478				return isLocked.left.length > 0 || isLocked.right.length > 0;
7479			},
7480
7481			isSubtable: function() {
7482				return util.hasClass(datatable.wrap[0], pfx + 'datatable-subtable') || false;
7483			},
7484
7485			/**
7486			 * Get total extra space of an element for width calculation,
7487			 * including padding, margin, border
7488			 * @param element
7489			 * @returns {number}
7490			 */
7491			getExtraSpace: function(element) {
7492				var padding = parseInt($(element).css('paddingRight')) +
7493					parseInt($(element).css('paddingLeft'));
7494				var margin = parseInt($(element).css('marginRight')) +
7495					parseInt($(element).css('marginLeft'));
7496				var border = Math.ceil(
7497					$(element).css('border-right-width').replace('px', ''));
7498				return padding + margin + border;
7499			},
7500
7501			/**
7502			 * Insert data of array into {{ }} template placeholder
7503			 * @param template
7504			 * @param data
7505			 * @returns {*}
7506			 */
7507			dataPlaceholder: function(template, data) {
7508				var result = template;
7509				$.each(data, function(key, val) {
7510					result = result.replace('{{' + key + '}}', val);
7511				});
7512				return result;
7513			},
7514
7515			/**
7516			 * Get table unique ID
7517			 * Note: table unique change each time refreshed
7518			 * @param suffix
7519			 * @returns {*}
7520			 */
7521			getTableId: function(suffix) {
7522				if (typeof suffix === 'undefined') suffix = '';
7523				var id = $(datatable).attr('id');
7524				if (typeof id === 'undefined') {
7525					id = $(datatable).attr('class').split(' ')[0];
7526				}
7527				return id + suffix;
7528			},
7529
7530			/**
7531			 * Get table prefix with depth number
7532			 */
7533			getTablePrefix: function(suffix) {
7534				if (typeof suffix !== 'undefined') suffix = '-' + suffix;
7535				return Plugin.getTableId() + '-' + Plugin.getDepth() + suffix;
7536			},
7537
7538			/**
7539			 * Get current table depth of sub table
7540			 * @returns {number}
7541			 */
7542			getDepth: function() {
7543				var depth = 0;
7544				var table = datatable.table;
7545				do {
7546					table = $(table).parents('.' + pfx + 'datatable-table');
7547					depth++;
7548				} while ($(table).length > 0);
7549				return depth;
7550			},
7551
7552			/**
7553			 * Keep state item
7554			 * @param key
7555			 * @param value
7556			 */
7557			stateKeep: function(key, value) {
7558				key = Plugin.getTablePrefix(key);
7559				if (Plugin.getOption('data.saveState') === false) return;
7560				if (localStorage) {
7561					localStorage.setItem(key, JSON.stringify(value));
7562				}
7563			},
7564
7565			/**
7566			 * Get state item
7567			 * @param key
7568			 * @param defValue
7569			 */
7570			stateGet: function(key, defValue) {
7571				key = Plugin.getTablePrefix(key);
7572				if (Plugin.getOption('data.saveState') === false) return;
7573				var value = null;
7574				if (localStorage) {
7575					value = localStorage.getItem(key);
7576				}
7577				if (typeof value !== 'undefined' && value !== null) {
7578					return JSON.parse(value);
7579				}
7580			},
7581
7582			/**
7583			 * Update data in state without clear existing
7584			 * @param key
7585			 * @param value
7586			 */
7587			stateUpdate: function(key, value) {
7588				var ori = Plugin.stateGet(key);
7589				if (typeof ori === 'undefined' || ori === null) ori = {};
7590				Plugin.stateKeep(key, $.extend({}, ori, value));
7591			},
7592
7593			/**
7594			 * Remove state item
7595			 * @param key
7596			 */
7597			stateRemove: function(key) {
7598				key = Plugin.getTablePrefix(key);
7599				if (localStorage) {
7600					localStorage.removeItem(key);
7601				}
7602			},
7603
7604			/**
7605			 * Get total columns.
7606			 */
7607			getTotalColumns: function(tablePart) {
7608				if (typeof tablePart === 'undefined') tablePart = datatable.tableBody;
7609				return $(tablePart).find('.' + pfx + 'datatable-row').first().find('.' + pfx + 'datatable-cell').length;
7610			},
7611
7612			/**
7613			 * Get table row. Useful to get row when current table is in lock
7614			 * mode. Can be used for both lock and normal table mode. By
7615			 * default, returning result will be in a list of <td>.
7616			 * @param tablePart
7617			 * @param row 1-based index
7618			 * @param tdOnly Optional. Default true
7619			 * @returns {*}
7620			 */
7621			getOneRow: function(tablePart, row, tdOnly) {
7622				if (typeof tdOnly === 'undefined') tdOnly = true;
7623				// get list of <tr>
7624				var result = $(tablePart).find('.' + pfx + 'datatable-row:not(.' + pfx + 'datatable-row-detail):nth-child(' + row + ')');
7625				if (tdOnly) {
7626					// get list of <td> or <th>
7627					result = result.find('.' + pfx + 'datatable-cell');
7628				}
7629				return result;
7630			},
7631
7632			/**
7633			 * Sort table row at HTML level by column index.
7634			 * todo; Not in use.
7635			 * @param header Header sort clicked
7636			 * @param sort asc|desc. Optional. Default asc
7637			 * @param int Boolean. Optional. Comparison value parse to integer.
7638			 *     Default false
7639			 */
7640			sortColumn: function(header, sort, int) {
7641				if (typeof sort === 'undefined') sort = 'asc'; // desc
7642				if (typeof int === 'undefined') int = false;
7643
7644				var column = $(header).index();
7645				var rows = $(datatable.tableBody).find('.' + pfx + 'datatable-row');
7646				var hIndex = $(header).closest('.' + pfx + 'datatable-lock').index();
7647				if (hIndex !== -1) {
7648					rows = $(datatable.tableBody).find('.' + pfx + 'datatable-lock:nth-child(' + (hIndex + 1) + ')').find('.' + pfx + 'datatable-row');
7649				}
7650
7651				var container = $(rows).parent();
7652				$(rows).sort(function(a, b) {
7653					var tda = $(a).find('td:nth-child(' + column + ')').text();
7654					var tdb = $(b).find('td:nth-child(' + column + ')').text();
7655
7656					if (int) {
7657						// useful for integer type sorting
7658						tda = parseInt(tda);
7659						tdb = parseInt(tdb);
7660					}
7661
7662					if (sort === 'asc') {
7663						return tda > tdb ? 1 : tda < tdb ? -1 : 0;
7664					} else {
7665						return tda < tdb ? 1 : tda > tdb ? -1 : 0;
7666					}
7667				}).appendTo(container);
7668			},
7669
7670			/**
7671			 * Perform sort remote and local
7672			 */
7673			sorting: function() {
7674				var sortObj = {
7675					init: function() {
7676						if (options.sortable) {
7677							$(datatable.tableHead).
7678								find('.' + pfx + 'datatable-cell:not(.' + pfx + 'datatable-cell-check)').
7679								addClass(pfx + 'datatable-cell-sort').
7680								off('click').
7681								on('click', sortObj.sortClick);
7682							// first init
7683							sortObj.setIcon();
7684						}
7685					},
7686					setIcon: function() {
7687						var meta = Plugin.getDataSourceParam('sort');
7688						if ($.isEmptyObject(meta)) return;
7689
7690						var column = Plugin.getColumnByField(meta.field);
7691						// sort is disabled for this column
7692						if (typeof column === 'undefined') return;
7693						if (typeof column.sortable !== 'undefined' && column.sortable === false) return;
7694						if (typeof column.selector !== 'undefined' && column.selector === true) return;
7695
7696						// sort icon beside column header
7697						var td = $(datatable.tableHead).find('.' + pfx + 'datatable-cell[data-field="' + meta.field + '"]').attr('data-sort', meta.sort);
7698						var sorting = $(td).find('span');
7699						var icon = $(sorting).find('i');
7700
7701						var icons = Plugin.getOption('layout.icons.sort');
7702						// update sort icon; desc & asc
7703						if ($(icon).length > 0) {
7704							$(icon).removeAttr('class').addClass(icons[meta.sort]);
7705						} else {
7706							$(sorting).append($('<i/>').addClass(icons[meta.sort]));
7707						}
7708
7709						// set sorted class to header on init
7710						$(td).addClass(pfx + 'datatable-cell-sorted');
7711					},
7712					sortClick: function(e) {
7713						var meta = Plugin.getDataSourceParam('sort');
7714						var field = $(this).data('field');
7715						var column = Plugin.getColumnByField(field);
7716						// sort is disabled for this column
7717						if (typeof column === 'undefined') return;
7718						if (typeof column.sortable !== 'undefined' && column.sortable === false) return;
7719						if (typeof column.selector !== 'undefined' && column.selector === true) return;
7720
7721						// set sorted class to header
7722						$(datatable.tableHead).find('th').removeClass(pfx + 'datatable-cell-sorted');
7723						util.addClass(this, pfx + 'datatable-cell-sorted');
7724
7725						$(datatable.tableHead).find('.' + pfx + 'datatable-cell > span > i').remove();
7726
7727						if (options.sortable) {
7728							Plugin.spinnerCallback(true);
7729
7730							var sort = 'desc';
7731							if (Plugin.getObject('field', meta) === field) {
7732								sort = Plugin.getObject('sort', meta);
7733							}
7734
7735							// toggle sort
7736							sort = typeof sort === 'undefined' || sort === 'desc'
7737								? 'asc'
7738								: 'desc';
7739
7740							// update field and sort params
7741							meta = {field: field, sort: sort};
7742							Plugin.setDataSourceParam('sort', meta);
7743
7744							sortObj.setIcon();
7745
7746							setTimeout(function() {
7747								Plugin.dataRender('sort');
7748								$(datatable).trigger(pfx + 'datatable-on-sort', meta);
7749							}, 300);
7750						}
7751					},
7752				};
7753				sortObj.init();
7754			},
7755
7756			/**
7757			 * Update JSON data list linked with sort, filter and pagination.
7758			 * Call this method, before using dataSet variable.
7759			 * @returns {*|null}
7760			 */
7761			localDataUpdate: function() {
7762				var params = Plugin.getDataSourceParam();
7763				if (typeof datatable.originalDataSet === 'undefined') {
7764					datatable.originalDataSet = datatable.dataSet;
7765				}
7766
7767				var field = Plugin.getObject('sort.field', params);
7768				var sort = Plugin.getObject('sort.sort', params);
7769				var column = Plugin.getColumnByField(field);
7770				if (typeof column !== 'undefined' && Plugin.getOption('data.serverSorting') !== true) {
7771					if (typeof column.sortCallback === 'function') {
7772						datatable.dataSet = column.sortCallback(datatable.originalDataSet, sort, column);
7773					} else {
7774						datatable.dataSet = Plugin.sortCallback(datatable.originalDataSet, sort, column);
7775					}
7776				} else {
7777					datatable.dataSet = datatable.originalDataSet;
7778				}
7779
7780				// if server filter enable, don't pass local filter
7781				if (typeof params.query === 'object' && !Plugin.getOption('data.serverFiltering')) {
7782					params.query = params.query || {};
7783
7784					var nestedSearch = function(obj) {
7785						for (var field in obj) {
7786							if (!obj.hasOwnProperty(field)) continue;
7787							if (typeof obj[field] === 'string') {
7788								if (obj[field].toLowerCase() == search || obj[field].toLowerCase().indexOf(search) !== -1) {
7789									return true;
7790								}
7791							} else if (typeof obj[field] === 'number') {
7792								if (obj[field] === search) {
7793									return true;
7794								}
7795							} else if (typeof obj[field] === 'object') {
7796								if (nestedSearch(obj[field])) {
7797									return true;
7798								}
7799							}
7800						}
7801						return false;
7802					};
7803
7804					var search = $(Plugin.getOption('search.input')).val();
7805					if (typeof search !== 'undefined' && search !== '') {
7806						search = search.toLowerCase();
7807						datatable.dataSet = $.grep(datatable.dataSet, nestedSearch);
7808						// remove generalSearch as we don't need this for next columns filter
7809						delete params.query[Plugin.getGeneralSearchKey()];
7810					}
7811
7812					// remove empty element from array
7813					$.each(params.query, function(k, v) {
7814						if (v === '') {
7815							delete params.query[k];
7816						}
7817					});
7818
7819					// filter array by query
7820					datatable.dataSet = Plugin.filterArray(datatable.dataSet, params.query);
7821
7822					// reset array index
7823					datatable.dataSet = datatable.dataSet.filter(function() {
7824						return true;
7825					});
7826				}
7827
7828				return datatable.dataSet;
7829			},
7830
7831			/**
7832			 * Utility helper to filter array by object pair of {key:value}
7833			 * @param list
7834			 * @param args
7835			 * @param operator
7836			 * @returns {*}
7837			 */
7838			filterArray: function(list, args, operator) {
7839				if (typeof list !== 'object') {
7840					return [];
7841				}
7842
7843				if (typeof operator === 'undefined') operator = 'AND';
7844
7845				if (typeof args !== 'object') {
7846					return list;
7847				}
7848
7849				operator = operator.toUpperCase();
7850
7851				if ($.inArray(operator, ['AND', 'OR', 'NOT']) === -1) {
7852					return [];
7853				}
7854
7855				var count = Object.keys(args).length;
7856				var filtered = [];
7857
7858				$.each(list, function(key, obj) {
7859					var to_match = obj;
7860
7861					var matched = 0;
7862					$.each(args, function(m_key, m_value) {
7863						m_value = m_value instanceof Array ? m_value : [m_value];
7864						var match_property = Plugin.getObject(m_key, to_match);
7865						if (typeof match_property !== 'undefined' && match_property) {
7866							var lhs = match_property.toString().toLowerCase();
7867							m_value.forEach(function(item, index) {
7868								if (item.toString().toLowerCase() == lhs || lhs.indexOf(item.toString().toLowerCase()) !== -1) {
7869									matched++;
7870								}
7871							});
7872						}
7873					});
7874
7875					if (('AND' == operator && matched == count) ||
7876						('OR' == operator && matched > 0) ||
7877						('NOT' == operator && 0 == matched)) {
7878						filtered[key] = obj;
7879					}
7880				});
7881
7882				list = filtered;
7883
7884				return list;
7885			},
7886
7887			/**
7888			 * Reset lock column scroll to 0 when resize
7889			 */
7890			resetScroll: function() {
7891				if (typeof options.detail === 'undefined' && Plugin.getDepth() === 1) {
7892					$(datatable.table).find('.' + pfx + 'datatable-row').css('left', 0);
7893					$(datatable.table).find('.' + pfx + 'datatable-lock').css('top', 0);
7894					$(datatable.tableBody).scrollTop(0);
7895				}
7896			},
7897
7898			/**
7899			 * Get column options by field
7900			 * @param field
7901			 * @returns {boolean}
7902			 */
7903			getColumnByField: function(field) {
7904				if (typeof field === 'undefined') return;
7905				var result;
7906				$.each(options.columns, function(i, column) {
7907					if (field === column.field) {
7908						result = column;
7909						return false;
7910					}
7911				});
7912				return result;
7913			},
7914
7915			/**
7916			 * Get default sort column
7917			 */
7918			getDefaultSortColumn: function() {
7919				var result;
7920				$.each(options.columns, function(i, column) {
7921					if (typeof column.sortable !== 'undefined'
7922						&& $.inArray(column.sortable, ['asc', 'desc']) !== -1) {
7923						result = {sort: column.sortable, field: column.field};
7924						return false;
7925					}
7926				});
7927				return result;
7928			},
7929
7930			/**
7931			 * Helper to get element dimensions, when the element is hidden
7932			 * @param element
7933			 * @param includeMargin
7934			 * @returns {{width: number, height: number, innerWidth: number,
7935			 *     innerHeight: number, outerWidth: number, outerHeight:
7936			 *     number}}
7937			 */
7938			getHiddenDimensions: function(element, includeMargin) {
7939				var props = {
7940						position: 'absolute',
7941						visibility: 'hidden',
7942						display: 'block',
7943					},
7944					dim = {
7945						width: 0,
7946						height: 0,
7947						innerWidth: 0,
7948						innerHeight: 0,
7949						outerWidth: 0,
7950						outerHeight: 0,
7951					},
7952					hiddenParents = $(element).parents().addBack().not(':visible');
7953				includeMargin = (typeof includeMargin === 'boolean')
7954					? includeMargin
7955					: false;
7956
7957				var oldProps = [];
7958				hiddenParents.each(function() {
7959					var old = {};
7960
7961					for (var name in props) {
7962						old[name] = this.style[name];
7963						this.style[name] = props[name];
7964					}
7965
7966					oldProps.push(old);
7967				});
7968
7969				dim.width = $(element).width();
7970				dim.outerWidth = $(element).outerWidth(includeMargin);
7971				dim.innerWidth = $(element).innerWidth();
7972				dim.height = $(element).height();
7973				dim.innerHeight = $(element).innerHeight();
7974				dim.outerHeight = $(element).outerHeight(includeMargin);
7975
7976				hiddenParents.each(function(i) {
7977					var old = oldProps[i];
7978					for (var name in props) {
7979						this.style[name] = old[name];
7980					}
7981				});
7982
7983				return dim;
7984			},
7985
7986			getGeneralSearchKey: function() {
7987				var searchInput = $(Plugin.getOption('search.input'));
7988				return Plugin.getOption('search.key') || $(searchInput).prop('name');
7989			},
7990
7991			/**
7992			 * Get value by dot notation path string and to prevent undefined
7993			 * errors
7994			 * @param path String Dot notation path in string
7995			 * @param object Object to iterate
7996			 * @returns {*}
7997			 */
7998			getObject: function(path, object) {
7999				return path.split('.').reduce(function(obj, i) {
8000					return obj !== null && typeof obj[i] !== 'undefined' ? obj[i] : null;
8001				}, object);
8002			},
8003
8004			/**
8005			 * Extend object
8006			 * @param obj
8007			 * @param path
8008			 * @param value
8009			 * @returns {*}
8010			 */
8011			extendObj: function(obj, path, value) {
8012				var levels = path.split('.'),
8013					i = 0;
8014
8015				function createLevel(child) {
8016					var name = levels[i++];
8017					if (typeof child[name] !== 'undefined' && child[name] !== null) {
8018						if (typeof child[name] !== 'object' &&
8019							typeof child[name] !== 'function') {
8020							child[name] = {};
8021						}
8022					} else {
8023						child[name] = {};
8024					}
8025					if (i === levels.length) {
8026						child[name] = value;
8027					} else {
8028						createLevel(child[name]);
8029					}
8030				}
8031
8032				createLevel(obj);
8033				return obj;
8034			},
8035
8036			rowEvenOdd: function() {
8037				// row even class
8038				$(datatable.tableBody).find('.' + pfx + 'datatable-row').removeClass(pfx + 'datatable-row-even');
8039				if ($(datatable.wrap).hasClass(pfx + 'datatable-subtable')) {
8040					$(datatable.tableBody).find('.' + pfx + 'datatable-row:not(.' + pfx + 'datatable-row-detail):even').addClass(pfx + 'datatable-row-even');
8041				} else {
8042					$(datatable.tableBody).find('.' + pfx + 'datatable-row:nth-child(even)').addClass(pfx + 'datatable-row-even');
8043				}
8044			},
8045
8046			/********************
8047			 ** PUBLIC API METHODS
8048			 ********************/
8049
8050			// delay timer
8051			timer: 0,
8052
8053			/**
8054			 * Redraw datatable by recalculating its DOM elements, etc.
8055			 * @returns {jQuery}
8056			 */
8057			redraw: function() {
8058				Plugin.adjustCellsWidth.call();
8059				if (Plugin.isLocked()) {
8060					// fix hiding cell width issue
8061					Plugin.scrollbar();
8062					Plugin.resetScroll();
8063					Plugin.adjustCellsHeight.call();
8064				}
8065				Plugin.adjustLockContainer.call();
8066				Plugin.initHeight.call();
8067				return datatable;
8068			},
8069
8070			/**
8071			 * Shortcode to reload
8072			 * @returns {jQuery}
8073			 */
8074			load: function() {
8075				Plugin.reload();
8076				return datatable;
8077			},
8078
8079			/**
8080			 * Datasource reload
8081			 * @returns {jQuery}
8082			 */
8083			reload: function() {
8084				var delay = (function() {
8085					return function(callback, ms) {
8086						clearTimeout(Plugin.timer);
8087						Plugin.timer = setTimeout(callback, ms);
8088					};
8089				})();
8090				delay(function() {
8091					// local only. remote pagination will skip this block
8092					if (!options.data.serverFiltering) {
8093						Plugin.localDataUpdate();
8094					}
8095					Plugin.dataRender();
8096					$(datatable).trigger(pfx + 'datatable-on-reloaded');
8097				}, Plugin.getOption('search.delay'));
8098				return datatable;
8099			},
8100
8101			/**
8102			 * Get record by record ID
8103			 * @param id
8104			 * @returns {jQuery}
8105			 */
8106			getRecord: function(id) {
8107				if (typeof datatable.tableBody === 'undefined') datatable.tableBody = $(datatable.table).children('tbody');
8108				$(datatable.tableBody).find('.' + pfx + 'datatable-cell:first-child').each(function(i, cell) {
8109					if (id == $(cell).text()) {
8110						var rowNumber = $(cell).closest('.' + pfx + 'datatable-row').index() + 1;
8111						datatable.API.record = datatable.API.value = Plugin.getOneRow(datatable.tableBody, rowNumber);
8112						return datatable;
8113					}
8114				});
8115				return datatable;
8116			},
8117
8118			/**
8119			 * @deprecated in v5.0.6
8120			 * Get column of current record ID
8121			 * @param columnName
8122			 * @returns {jQuery}
8123			 */
8124			getColumn: function(columnName) {
8125				Plugin.setSelectedRecords();
8126				datatable.API.value = $(datatable.API.record).find('[data-field="' + columnName + '"]');
8127				return datatable;
8128			},
8129
8130			/**
8131			 * Destroy datatable to original DOM state before datatable was
8132			 * initialized
8133			 * @returns {jQuery}
8134			 */
8135			destroy: function() {
8136				$(datatable).parent().find('.' + pfx + 'datatable-pager').remove();
8137				var initialDatatable = $(datatable.initialDatatable).addClass(pfx + 'datatable-destroyed').show();
8138				$(datatable).replaceWith(initialDatatable);
8139				datatable = initialDatatable;
8140				$(datatable).trigger(pfx + 'datatable-on-destroy');
8141				Plugin.isInit = false;
8142
8143				// clean up variables
8144				initialDatatable = null;
8145				datatable.dataSet = null;
8146				datatable.originalDataSet = null;
8147				datatable.tableHead = null;
8148				datatable.tableBody = null;
8149				datatable.table = null;
8150				datatable.wrap = null;
8151				datatable.API = {
8152					record: null,
8153					value: null,
8154					params: null,
8155				};
8156
8157				Plugin.ajaxParams = {};
8158				Plugin.pagingObject = {};
8159				Plugin.nodeTr = [];
8160				Plugin.nodeTd = [];
8161				Plugin.nodeCols = [];
8162				Plugin.recentNode = [];
8163
8164				return initialDatatable;
8165			},
8166
8167			/**
8168			 * Sort by column field
8169			 * @param field
8170			 * @param sort
8171			 */
8172			sort: function(field, sort) {
8173				// toggle sort
8174				sort = typeof sort === 'undefined' ? 'asc' : sort;
8175
8176				Plugin.spinnerCallback(true);
8177
8178				// update field and sort params
8179				var meta = {field: field, sort: sort};
8180				Plugin.setDataSourceParam('sort', meta);
8181
8182				setTimeout(function() {
8183					Plugin.dataRender('sort');
8184					$(datatable).trigger(pfx + 'datatable-on-sort', meta);
8185					$(datatable.tableHead).find('.' + pfx + 'datatable-cell > span > i').remove();
8186				}, 300);
8187
8188				return datatable;
8189			},
8190
8191			/**
8192			 * @deprecated in v5.0.6
8193			 * Get current selected column value
8194			 * @returns {jQuery}
8195			 */
8196			getValue: function() {
8197				return $(datatable.API.value).text();
8198			},
8199
8200			/**
8201			 * Set checkbox active
8202			 * @param cell JQuery selector or checkbox ID
8203			 */
8204			setActive: function(cell) {
8205				if (typeof cell === 'string') {
8206					// set by checkbox id
8207					cell = $(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"][value="' + cell + '"]');
8208				}
8209
8210				$(cell).prop('checked', true);
8211
8212				var ids = [];
8213				$(cell).each(function(i, td) {
8214					// normal table
8215					var row = $(td).closest('tr').addClass(pfx + 'datatable-row-active');
8216
8217					var id = $(td).attr('value');
8218					if (typeof id !== 'undefined') {
8219						ids.push(id);
8220					}
8221				});
8222
8223				$(datatable).trigger(pfx + 'datatable-on-check', [ids]);
8224			},
8225
8226			/**
8227			 * Set checkbox inactive
8228			 * @param cell JQuery selector or checkbox ID
8229			 */
8230			setInactive: function(cell) {
8231				if (typeof cell === 'string') {
8232					// set by checkbox id
8233					cell = $(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"][value="' + cell + '"]');
8234				}
8235
8236				$(cell).prop('checked', false);
8237
8238				var ids = [];
8239				$(cell).each(function(i, td) {
8240					// normal table
8241					var row = $(td).closest('tr').removeClass(pfx + 'datatable-row-active');
8242
8243					var id = $(td).attr('value');
8244					if (typeof id !== 'undefined') {
8245						ids.push(id);
8246					}
8247				});
8248
8249				$(datatable).trigger(pfx + 'datatable-on-uncheck', [ids]);
8250			},
8251
8252			/**
8253			 * Set all checkboxes active or inactive
8254			 * @param active
8255			 */
8256			setActiveAll: function(active) {
8257				var checkboxes = $(datatable.table).
8258					find('> tbody, > thead').
8259					find('tr').not('.' + pfx + 'datatable-row-subtable').
8260					find('.' + pfx + 'datatable-cell-check [type="checkbox"]');
8261				if (active) {
8262					Plugin.setActive(checkboxes);
8263				} else {
8264					Plugin.setInactive(checkboxes);
8265				}
8266			},
8267
8268			/**
8269			 * @deprecated in v5.0.6
8270			 * Get selected rows which are active
8271			 * @returns {jQuery}
8272			 */
8273			setSelectedRecords: function() {
8274				datatable.API.record = $(datatable.tableBody).find('.' + pfx + 'datatable-row-active');
8275				return datatable;
8276			},
8277
8278			/**
8279			 * Get selected records
8280			 * @returns {null}
8281			 */
8282			getSelectedRecords: function() {
8283				// support old method
8284				Plugin.setSelectedRecords();
8285				datatable.API.record = datatable.rows('.' + pfx + 'datatable-row-active').nodes();
8286				return datatable.API.record;
8287			},
8288
8289			/**
8290			 * Get options by dots notation path
8291			 * @param path String Dot notation path in string
8292			 * @returns {*}
8293			 */
8294			getOption: function(path) {
8295				return Plugin.getObject(path, options);
8296			},
8297
8298			/**
8299			 * Set global options nodes by dots notation path
8300			 * @param path
8301			 * @param object
8302			 */
8303			setOption: function(path, object) {
8304				options = Plugin.extendObj(options, path, object);
8305			},
8306
8307			/**
8308			 * Search filter for local & remote
8309			 * @param value
8310			 * @param columns. Optional list of columns to be filtered.
8311			 */
8312			search: function(value, columns) {
8313				if (typeof columns !== 'undefined') columns = $.makeArray(columns);
8314				var delay = (function() {
8315					return function(callback, ms) {
8316						clearTimeout(Plugin.timer);
8317						Plugin.timer = setTimeout(callback, ms);
8318					};
8319				})();
8320
8321				delay(function() {
8322					// get query parameters
8323					var query = Plugin.getDataSourceQuery();
8324
8325					// search not by columns
8326					if (typeof columns === 'undefined' && typeof value !== 'undefined') {
8327						var key = Plugin.getGeneralSearchKey();
8328						query[key] = value;
8329					}
8330
8331					// search by columns, support multiple columns
8332					if (typeof columns === 'object') {
8333						$.each(columns, function(k, column) {
8334							query[column] = value;
8335						});
8336						// remove empty element from arrays
8337						$.each(query, function(k, v) {
8338							if (v === '' || $.isEmptyObject(v)) {
8339								delete query[k];
8340							}
8341						});
8342					}
8343
8344					Plugin.setDataSourceQuery(query);
8345
8346					// reset pagination to 1 when doing seearching
8347					datatable.setDataSourceParam('pagination', Object.assign({}, datatable.getDataSourceParam('pagination'), {page: 1}));
8348
8349					// local filter only. remote pagination will skip this block
8350					if (!options.data.serverFiltering) {
8351						Plugin.localDataUpdate();
8352					}
8353					Plugin.dataRender('search');
8354				}, Plugin.getOption('search.delay'));
8355			},
8356
8357			/**
8358			 * Set datasource params extract
8359			 * @param param
8360			 * @param value
8361			 */
8362			setDataSourceParam: function(param, value) {
8363				datatable.API.params = $.extend({}, {
8364					pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')},
8365					sort: Plugin.getDefaultSortColumn(),
8366					query: {},
8367				}, datatable.API.params, Plugin.stateGet(Plugin.stateId));
8368
8369				datatable.API.params = Plugin.extendObj(datatable.API.params, param, value);
8370
8371				Plugin.stateKeep(Plugin.stateId, datatable.API.params);
8372			},
8373
8374			/**
8375			 * Get datasource params
8376			 * @param param
8377			 */
8378			getDataSourceParam: function(param) {
8379				datatable.API.params = $.extend({}, {
8380					pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')},
8381					sort: Plugin.getDefaultSortColumn(),
8382					query: {},
8383				}, datatable.API.params, Plugin.stateGet(Plugin.stateId));
8384
8385				if (typeof param === 'string') {
8386					return Plugin.getObject(param, datatable.API.params);
8387				}
8388
8389				return datatable.API.params;
8390			},
8391
8392			/**
8393			 * Shortcode to datatable.getDataSourceParam('query');
8394			 * @returns {*}
8395			 */
8396			getDataSourceQuery: function() {
8397				return Plugin.getDataSourceParam('query') || {};
8398			},
8399
8400			/**
8401			 * Shortcode to datatable.setDataSourceParam('query', query);
8402			 * @param query
8403			 */
8404			setDataSourceQuery: function(query) {
8405				Plugin.setDataSourceParam('query', query);
8406			},
8407
8408			/**
8409			 * Get current page number
8410			 * @returns {number}
8411			 */
8412			getCurrentPage: function() {
8413				return $(datatable.table).
8414					siblings('.' + pfx + 'datatable-pager').
8415					last().
8416					find('.' + pfx + 'datatable-pager-nav').
8417					find('.' + pfx + 'datatable-pager-link.' + pfx + 'datatable-pager-link-active').
8418					data('page') || 1;
8419			},
8420
8421			/**
8422			 * Get selected dropdown page size
8423			 * @returns {*|number}
8424			 */
8425			getPageSize: function() {
8426				return $(datatable.table).siblings('.' + pfx + 'datatable-pager').last().find('select.' + pfx + 'datatable-pager-size').val() || 10;
8427			},
8428
8429			/**
8430			 * Get total rows
8431			 */
8432			getTotalRows: function() {
8433				return datatable.API.params.pagination.total;
8434			},
8435
8436			/**
8437			 * Get full dataset in grid
8438			 * @returns {*|null|Array}
8439			 */
8440			getDataSet: function() {
8441				return datatable.originalDataSet;
8442			},
8443
8444			nodeTr: [],
8445			nodeTd: [],
8446			nodeCols: [],
8447			recentNode: [],
8448
8449			table: function() {
8450				if (typeof datatable.table !== 'undefined') {
8451					return datatable.table;
8452				}
8453			},
8454
8455			/**
8456			 * Select a single row from the table
8457			 * @param selector
8458			 * @returns {jQuery}
8459			 */
8460			row: function(selector) {
8461				Plugin.rows(selector);
8462				Plugin.nodeTr = Plugin.recentNode = $(Plugin.nodeTr).first();
8463				return datatable;
8464			},
8465
8466			/**
8467			 * Select multiple rows from the table
8468			 * @param selector
8469			 * @returns {jQuery}
8470			 */
8471			rows: function(selector) {
8472				if (Plugin.isLocked()) {
8473					Plugin.nodeTr = Plugin.recentNode = $(datatable.tableBody).find(selector).filter('.' + pfx + 'datatable-lock-scroll > .' + pfx + 'datatable-row');
8474				} else {
8475					Plugin.nodeTr = Plugin.recentNode = $(datatable.tableBody).find(selector).filter('.' + pfx + 'datatable-row');
8476				}
8477				return datatable;
8478			},
8479
8480			/**
8481			 * Select a single column from the table
8482			 * @param index zero-based index
8483			 * @returns {jQuery}
8484			 */
8485			column: function(index) {
8486				Plugin.nodeCols = Plugin.recentNode = $(datatable.tableBody).find('.' + pfx + 'datatable-cell:nth-child(' + (index + 1) + ')');
8487				return datatable;
8488			},
8489
8490			/**
8491			 * Select multiple columns from the table
8492			 * @param selector
8493			 * @returns {jQuery}
8494			 */
8495			columns: function(selector) {
8496				var context = datatable.table;
8497				if (Plugin.nodeTr === Plugin.recentNode) {
8498					context = Plugin.nodeTr;
8499				}
8500				var columns = $(context).find('.' + pfx + 'datatable-cell[data-field="' + selector + '"]');
8501				if (columns.length > 0) {
8502					Plugin.nodeCols = Plugin.recentNode = columns;
8503				} else {
8504					Plugin.nodeCols = Plugin.recentNode = $(context).find(selector).filter('.' + pfx + 'datatable-cell');
8505				}
8506				return datatable;
8507			},
8508
8509			cell: function(selector) {
8510				Plugin.cells(selector);
8511				Plugin.nodeTd = Plugin.recentNode = $(Plugin.nodeTd).first();
8512				return datatable;
8513			},
8514
8515			cells: function(selector) {
8516				var cells = $(datatable.tableBody).find('.' + pfx + 'datatable-cell');
8517				if (typeof selector !== 'undefined') {
8518					cells = $(cells).filter(selector);
8519				}
8520				Plugin.nodeTd = Plugin.recentNode = cells;
8521				return datatable;
8522			},
8523
8524			/**
8525			 * Delete the selected row from the table
8526			 * @returns {jQuery}
8527			 */
8528			remove: function() {
8529				if ($(Plugin.nodeTr.length) && Plugin.nodeTr === Plugin.recentNode) {
8530					$(Plugin.nodeTr).remove();
8531				}
8532				Plugin.layoutUpdate();
8533				return datatable;
8534			},
8535
8536			/**
8537			 * Show or hide the columns or rows
8538			 */
8539			visible: function(bool) {
8540				if ($(Plugin.recentNode.length)) {
8541					var locked = Plugin.lockEnabledColumns();
8542					if (Plugin.recentNode === Plugin.nodeCols) {
8543						var index = Plugin.recentNode.index();
8544
8545						if (Plugin.isLocked()) {
8546							var scrollColumns = $(Plugin.recentNode).closest('.' + pfx + 'datatable-lock-scroll').length;
8547							if (scrollColumns) {
8548								// is at center of scrollable area
8549								index += locked.left.length + 1;
8550							} else if ($(Plugin.recentNode).closest('.' + pfx + 'datatable-lock-right').length) {
8551								// is at the right locked table
8552								index += locked.left.length + scrollColumns + 1;
8553							}
8554						}
8555					}
8556
8557					if (bool) {
8558						if (Plugin.recentNode === Plugin.nodeCols) {
8559							delete options.columns[index].visible;
8560						}
8561						$(Plugin.recentNode).show();
8562					} else {
8563						if (Plugin.recentNode === Plugin.nodeCols) {
8564							Plugin.setOption('columns.' + (index) + '.visible', false);
8565						}
8566						$(Plugin.recentNode).hide();
8567					}
8568					Plugin.columnHide();
8569					Plugin.redraw();
8570				}
8571			},
8572
8573			/**
8574			 * Get the the DOM element for the selected rows or columns
8575			 * @returns {Array}
8576			 */
8577			nodes: function() {
8578				return Plugin.recentNode;
8579			},
8580
8581			/**
8582			 * will be implemented soon
8583			 * @returns {jQuery}
8584			 */
8585			dataset: function() {
8586				return datatable;
8587			},
8588
8589			/**
8590			 * Open page by number
8591			 * @param page number
8592			 */
8593			gotoPage: function (page) {
8594				if (typeof Plugin.pagingObject !== 'undefined') {
8595					Plugin.isInit = true;
8596					Plugin.pagingObject.openPage(page);
8597				}
8598			},
8599
8600		};
8601
8602		/**
8603		 * Public API methods can be used directly by datatable
8604		 */
8605		$.each(Plugin, function(funcName, func) {
8606			datatable[funcName] = func;
8607		});
8608
8609		// initialize main datatable plugin
8610		if (typeof options !== 'undefined') {
8611			if (typeof options === 'string') {
8612				var method = options;
8613				datatable = $(this).data(pluginName);
8614				if (typeof datatable !== 'undefined') {
8615					options = datatable.options;
8616					Plugin[method].apply(this, Array.prototype.slice.call(arguments, 1));
8617				}
8618			} else {
8619				if (!datatable.data(pluginName) && !$(this).hasClass(pfx + 'datatable-loaded')) {
8620					datatable.dataSet = null;
8621					datatable.textAlign = {
8622						left: pfx + 'datatable-cell-left',
8623						center: pfx + 'datatable-cell-center',
8624						right: pfx + 'datatable-cell-right',
8625					};
8626
8627					// merge default and user defined options
8628					options = $.extend(true, {}, $.fn[pluginName].defaults, options);
8629
8630					datatable.options = options;
8631
8632					// init plugin process
8633					Plugin.init.apply(this, [options]);
8634
8635					$(datatable.wrap).data(pluginName, datatable);
8636				}
8637			}
8638		} else {
8639			// get existing instance datatable
8640			datatable = $(this).data(pluginName);
8641			if (typeof datatable === 'undefined') {
8642				$.error(pluginName + ' not initialized');
8643			}
8644			options = datatable.options;
8645		}
8646
8647		return datatable;
8648	};
8649
8650	// default options
8651	$.fn[pluginName].defaults = {
8652		// datasource definition
8653		data: {
8654			type: 'local',
8655			source: null,
8656			pageSize: 10, // display records per page
8657			saveState: true,
8658
8659			serverPaging: false,
8660			serverFiltering: false,
8661			serverSorting: false,
8662
8663			autoColumns: false,
8664			attr: {
8665				rowProps: [],
8666			},
8667		},
8668
8669		// layout definition
8670		layout: {
8671			theme: 'default', // datatable will support multiple themes and designs
8672			class: pfx + 'datatable-primary', // custom wrapper class
8673			scroll: false, // enable/disable datatable scroll both horizontal and vertical when needed.
8674			height: null, // datatable's body's fixed height
8675			minHeight: null,
8676			footer: false, // display/hide footer
8677			header: true, // display/hide header
8678			customScrollbar: true, // set false to disable custom scrollbar
8679
8680			// datatable spinner
8681			spinner: {
8682				overlayColor: '#000000',
8683				opacity: 0,
8684				type: 'loader',
8685				state: 'primary',
8686				message: true,
8687			},
8688
8689			// datatable UI icons
8690			icons: {
8691				sort: {asc: 'flaticon2-arrow-up', desc: 'flaticon2-arrow-down'},
8692				pagination: {
8693					next: 'flaticon2-next',
8694					prev: 'flaticon2-back',
8695					first: 'flaticon2-fast-back',
8696					last: 'flaticon2-fast-next',
8697					more: 'flaticon-more-1',
8698				},
8699				rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'},
8700			},
8701		},
8702
8703		// column sorting
8704		sortable: true,
8705
8706		// resize column size with mouse drag coming soon)
8707		resizable: false,
8708
8709		// column based filtering (coming soon)
8710		filterable: false,
8711
8712		pagination: true,
8713
8714		// inline and bactch editing (cooming soon)
8715		editable: false,
8716
8717		// columns definition
8718		columns: [],
8719
8720		search: {
8721			// enable trigger search by keyup enter
8722			onEnter: false,
8723			// input text for search
8724			input: null,
8725			// search delay in milliseconds
8726			delay: 400,
8727			//	remote server search key value
8728			key: null
8729		},
8730
8731		rows: {
8732			// deprecated
8733			callback: function() {
8734			},
8735			// call before row template
8736			beforeTemplate: function() {
8737			},
8738			// call after row template
8739			afterTemplate: function() {
8740			},
8741			autoHide: true,
8742		},
8743
8744		// toolbar
8745		toolbar: {
8746			// place pagination and displayInfo blocks according to the array order
8747			layout: ['pagination', 'info'],
8748
8749			// toolbar placement can be at top or bottom or both top and bottom repeated
8750			placement: ['bottom'],  //'top', 'bottom'
8751
8752			// toolbar items
8753			items: {
8754				// pagination
8755				pagination: {
8756					// pagination type(default or scroll)
8757					type: 'default',
8758
8759					// number of pages to display by breakpoints
8760					pages: {
8761						desktop: {
8762							layout: 'default',
8763							pagesNumber: 5,
8764						},
8765						tablet: {
8766							layout: 'default',
8767							pagesNumber: 3,
8768						},
8769						mobile: {
8770							layout: 'compact',
8771						},
8772					},
8773
8774					// navigation buttons
8775					navigation: {
8776						prev: true, // display prev button
8777						next: true, // display next button
8778						first: true, // display first button
8779						last: true, // display last button
8780						more: false // display more button
8781					},
8782
8783					// page size select
8784					pageSizeSelect: [], // display dropdown to select pagination size. -1 is used for "ALl" option
8785				},
8786
8787				// records info
8788				info: true,
8789			},
8790		},
8791
8792		// here we will keep all strings and message used by datatable UI so developer can easiliy translate to any language.
8793		// By default the stirngs will be in the plugin source and here can override it
8794		translate: {
8795			records: {
8796				processing: 'Please wait...',
8797				noRecords: 'No records found',
8798			},
8799			toolbar: {
8800				pagination: {
8801					items: {
8802						default: {
8803							first: 'First',
8804							prev: 'Previous',
8805							next: 'Next',
8806							last: 'Last',
8807							more: 'More pages',
8808							input: 'Page number',
8809							select: 'Select page size',
8810							all: 'all',
8811						},
8812						info: 'Showing {{start}} - {{end}} of {{total}}',
8813					},
8814				},
8815			},
8816		},
8817
8818		extensions: {},
8819	};
8820
8821}(jQuery));
8822
8823"use strict";
8824(function($) {
8825
8826	var pluginName = 'KTDatatable';
8827	var pfx = '';
8828
8829	$.fn[pluginName] = $.fn[pluginName] || {};
8830
8831	/**
8832	 * @param datatable Main datatable plugin instance
8833	 * @param options Extension options
8834	 * @returns {*}
8835	 */
8836	$.fn[pluginName].checkbox = function(datatable, options) {
8837		var Extension = {
8838			selectedAllRows: false,
8839			selectedRows: [],
8840			unselectedRows: [],
8841
8842			init: function() {
8843				if (Extension.selectorEnabled()) {
8844					// reset
8845					datatable.setDataSourceParam(options.vars.selectedAllRows, false);
8846					datatable.stateRemove('checkbox');
8847
8848					// requestIds is not null
8849					if (options.vars.requestIds) {
8850						// request ids in response
8851						datatable.setDataSourceParam(options.vars.requestIds, true);
8852					}
8853
8854					// remove selected checkbox on datatable reload
8855					$(datatable).on(pfx + 'datatable-on-reloaded', function() {
8856						datatable.stateRemove('checkbox');
8857						datatable.setDataSourceParam(options.vars.selectedAllRows, false);
8858						Extension.selectedAllRows = false;
8859						Extension.selectedRows = [];
8860						Extension.unselectedRows = [];
8861					});
8862
8863					// select all on extension init
8864					Extension.selectedAllRows = datatable.getDataSourceParam(options.vars.selectedAllRows);
8865
8866					$(datatable).on(pfx + 'datatable-on-layout-updated', function(e, args) {
8867						if (args.table != $(datatable.wrap).attr('id')) {
8868							return;
8869						}
8870						datatable.ready(function() {
8871							Extension.initVars();
8872							Extension.initEvent();
8873							Extension.initSelect();
8874						});
8875					});
8876
8877					$(datatable).on(pfx + 'datatable-on-check', function(e, ids) {
8878						ids.forEach(function(id) {
8879							Extension.selectedRows.push(id);
8880							// // remove from unselected rows
8881							Extension.unselectedRows = Extension.remove(Extension.unselectedRows, id);
8882						});
8883						var storage = {};
8884						storage['selectedRows'] = $.unique(Extension.selectedRows);
8885						storage['unselectedRows'] = $.unique(Extension.unselectedRows);
8886						datatable.stateKeep('checkbox', storage);
8887					});
8888					$(datatable).on(pfx + 'datatable-on-uncheck', function(e, ids) {
8889						ids.forEach(function(id) {
8890							Extension.unselectedRows.push(id);
8891							// // remove from selected rows
8892							Extension.selectedRows = Extension.remove(Extension.selectedRows, id);
8893						});
8894						var storage = {};
8895						storage['selectedRows'] = $.unique(Extension.selectedRows);
8896						storage['unselectedRows'] = $.unique(Extension.unselectedRows);
8897						datatable.stateKeep('checkbox', storage);
8898					});
8899				}
8900			},
8901
8902			/**
8903			 * Init checkbox clicks event
8904			 */
8905			initEvent: function() {
8906				// select all checkbox click
8907				$(datatable.tableHead).find('.' + pfx + 'checkbox-all > [type="checkbox"]').click(function(e) {
8908					// clear selected and unselected rows
8909					Extension.selectedRows = Extension.unselectedRows = [];
8910					datatable.stateRemove('checkbox');
8911
8912					// select all rows
8913					Extension.selectedAllRows = !!$(this).is(':checked');
8914
8915					// local select all current page rows
8916					if (!options.vars.requestIds) {
8917						if ($(this).is(':checked')) {
8918							Extension.selectedRows = $.makeArray($(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"]').map(function(i, chk) {
8919								return $(chk).val();
8920							}));
8921						}
8922						var storage = {};
8923						storage['selectedRows'] = $.unique(Extension.selectedRows);
8924						datatable.stateKeep('checkbox', storage);
8925					}
8926
8927					// keep selectedAllRows in datasource params
8928					datatable.setDataSourceParam(options.vars.selectedAllRows, Extension.selectedAllRows);
8929
8930					$(datatable).trigger(pfx + 'datatable-on-click-checkbox', [$(this)]);
8931				});
8932
8933				// single row checkbox click
8934				$(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"]').click(function(e) {
8935					var id = $(this).val();
8936					if ($(this).is(':checked')) {
8937						Extension.selectedRows.push(id);
8938						// remove from unselected rows
8939						Extension.unselectedRows = Extension.remove(Extension.unselectedRows, id);
8940					}
8941					else {
8942						Extension.unselectedRows.push(id);
8943						// remove from selected rows
8944						Extension.selectedRows = Extension.remove(Extension.selectedRows, id);
8945					}
8946
8947					// local checkbox header check
8948					if (!options.vars.requestIds && Extension.selectedRows.length < 1) {
8949						// remove select all checkbox, if there is no checked checkbox left
8950						$(datatable.tableHead).find('.' + pfx + 'checkbox-all > [type="checkbox"]').prop('checked', false);
8951					}
8952
8953					var storage = {};
8954					storage['selectedRows'] = Extension.selectedRows.filter(Extension.unique);
8955					storage['unselectedRows'] = Extension.unselectedRows.filter(Extension.unique);
8956					datatable.stateKeep('checkbox', storage);
8957
8958					$(datatable).trigger(pfx + 'datatable-on-click-checkbox', [$(this)]);
8959				});
8960			},
8961
8962			unique: function(value, index, self) {
8963				return self.indexOf(value) === index;
8964			},
8965
8966			initSelect: function() {
8967				// selected all rows from server
8968				if (Extension.selectedAllRows && options.vars.requestIds) {
8969					if (!datatable.hasClass(pfx + 'datatable-error')) {
8970						// set header select all checkbox checked
8971						$(datatable.tableHead).find('.' + pfx + 'checkbox-all > [type="checkbox"]').prop('checked', true);
8972					}
8973
8974					// set all checkbox in table body
8975					datatable.setActiveAll(true);
8976
8977					// remove unselected rows
8978					Extension.unselectedRows.forEach(function(id) {
8979						datatable.setInactive(id);
8980					});
8981
8982				}
8983				else {
8984					// single check for server and local
8985					Extension.selectedRows.forEach(function(id) {
8986						datatable.setActive(id);
8987					});
8988
8989					// local checkbox; check if all checkboxes of currect page are checked
8990					if (!datatable.hasClass(pfx + 'datatable-error') && $(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"]').not(':checked').length < 1) {
8991						// set header select all checkbox checked
8992						$(datatable.tableHead).find('.' + pfx + 'checkbox-all > [type="checkbox"]').prop('checked', true);
8993					}
8994				}
8995			},
8996
8997			/**
8998			 * Check if selector is enabled from options
8999			 */
9000			selectorEnabled: function() {
9001				return $.grep(datatable.options.columns, function(n, i) {
9002					return n.selector || false;
9003				})[0];
9004			},
9005
9006			initVars: function() {
9007				// get single select/unselect from localstorage
9008				var storage = datatable.stateGet('checkbox');
9009				if (typeof storage !== 'undefined') {
9010					Extension.selectedRows = storage['selectedRows'] || [];
9011					Extension.unselectedRows = storage['unselectedRows'] || [];
9012				}
9013			},
9014
9015			getSelectedId: function(path) {
9016				Extension.initVars();
9017
9018				// server selected all rows
9019				if (Extension.selectedAllRows && options.vars.requestIds) {
9020					if (typeof path === 'undefined') {
9021						path = options.vars.rowIds;
9022					}
9023
9024					// if selected all rows, return id from response meta
9025					var selectedAllRows = datatable.getObject(path, datatable.lastResponse) || [];
9026
9027					if (selectedAllRows.length > 0) {
9028						// remove single unselected rows from selectedAllRows ids from server response emta
9029						Extension.unselectedRows.forEach(function(id) {
9030							selectedAllRows = Extension.remove(selectedAllRows, parseInt(id));
9031						});
9032					}
9033					return $.unique(selectedAllRows);
9034				}
9035
9036				// else return single checked selected rows
9037				return Extension.selectedRows;
9038			},
9039
9040			remove: function(array, element) {
9041				return array.filter(function(e) {
9042					return e !== element;
9043				});
9044			},
9045		};
9046
9047		// make the extension accessible from datatable init
9048		datatable.checkbox = function() {
9049			return Extension;
9050		};
9051
9052		if (typeof options === 'object') {
9053			options = $.extend(true, {}, $.fn[pluginName].checkbox.default, options);
9054			Extension.init.apply(this, [options]);
9055		}
9056
9057		return datatable;
9058	};
9059
9060	$.fn[pluginName].checkbox.default = {
9061		vars: {
9062			// select all rows flag to be sent to the server
9063			selectedAllRows: 'selectedAllRows',
9064			// request id parameter's name
9065			requestIds: 'requestIds',
9066			// response path to all rows id
9067			rowIds: 'meta.rowIds',
9068		},
9069	};
9070
9071}(jQuery));
9072
9073var defaults = {
9074	layout: {
9075		icons: {
9076			pagination: {
9077				next: 'flaticon2-next',
9078				prev: 'flaticon2-back',
9079				first: 'flaticon2-fast-back',
9080				last: 'flaticon2-fast-next',
9081				more: 'flaticon-more-1',
9082			},
9083			rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'},
9084		}
9085	}
9086};
9087
9088if (KTUtil.isRTL()) {
9089	defaults = {
9090		layout: {
9091			icons: {
9092				pagination: {
9093					next: 'flaticon2-back',
9094					prev: 'flaticon2-next',
9095					first: 'flaticon2-fast-next',
9096					last: 'flaticon2-fast-back',
9097				},
9098				rowDetail: {collapse: 'fa fa-caret-down', expand: 'fa fa-caret-right'},
9099			}
9100		}
9101	}
9102}
9103
9104$.extend(true, $.fn.KTDatatable.defaults, defaults);
9105
9106"use strict";
9107
9108// Initialization
9109KTUtil.ready(function() {
9110    ////////////////////////////////////////////////////
9111    // Layout Base Partials(mandatory for core layout)//
9112    ////////////////////////////////////////////////////
9113
9114    // Init Desktop & Mobile Headers
9115    if (typeof KTLayoutHeader !== 'undefined') {
9116        KTLayoutHeader.init('kt_header', 'kt_header_mobile');
9117    }
9118
9119    // Init Header Menu
9120    if (typeof KTLayoutHeaderMenu !== 'undefined') {
9121        KTLayoutHeaderMenu.init('kt_header_menu', 'kt_header_menu_wrapper');
9122    }
9123
9124    // Init Header Topbar For Mobile Mode
9125    if (typeof KTLayoutHeaderTopbar !== 'undefined') {
9126        KTLayoutHeaderTopbar.init('kt_header_mobile_topbar_toggle');
9127    }
9128
9129    // Init Aside
9130    if (typeof KTLayoutAside !== 'undefined') {
9131        KTLayoutAside.init('kt_aside');
9132    }
9133
9134    // Init Aside Menu
9135    if (typeof KTLayoutAsideMenu !== 'undefined') {
9136        KTLayoutAsideMenu.init('kt_aside_menu');
9137    }
9138
9139    // Init Subheader
9140    if (typeof KTLayoutSubheader !== 'undefined') {
9141        KTLayoutSubheader.init('kt_subheader');
9142    }
9143
9144    // Init Content
9145    if (typeof KTLayoutContent !== 'undefined') {
9146        KTLayoutContent.init('kt_content');
9147    }
9148
9149    // Init Footer
9150    if (typeof KTLayoutFooter !== 'undefined') {
9151        KTLayoutFooter.init('kt_footer');
9152    }
9153
9154
9155
9156    //////////////////////////////////////////////
9157    // Layout Extended Partials(optional to use)//
9158    //////////////////////////////////////////////
9159
9160    // Init Scrolltop
9161    if (typeof KTLayoutScrolltop !== 'undefined') {
9162        KTLayoutScrolltop.init('kt_scrolltop');
9163    }
9164
9165    // Init Sticky Card
9166    if (typeof KTLayoutStickyCard !== 'undefined') {
9167        KTLayoutStickyCard.init('kt_page_sticky_card');
9168    }
9169
9170    // Init Stretched Card
9171    if (typeof KTLayoutStretchedCard !== 'undefined') {
9172        KTLayoutStretchedCard.init('kt_page_stretched_card');
9173    }
9174
9175    // Init Code Highlighter & Preview Blocks(used to demonstrate the theme features)
9176    if (typeof KTLayoutExamples !== 'undefined') {
9177	    KTLayoutExamples.init();
9178    }
9179
9180    // Init Demo Selection Panel
9181    if (typeof KTLayoutDemoPanel !== 'undefined') {
9182	    KTLayoutDemoPanel.init('kt_demo_panel');
9183    }
9184
9185    // Init Chat App(quick modal chat)
9186    if (typeof KTLayoutChat !== 'undefined') {
9187        KTLayoutChat.init('kt_chat_modal');
9188    }
9189
9190    // Init Quick Actions Offcanvas Panel
9191    if (typeof KTLayoutQuickActions !== 'undefined') {
9192        KTLayoutQuickActions.init('kt_quick_actions');
9193    }
9194
9195    // Init Quick Notifications Offcanvas Panel
9196    if (typeof KTLayoutQuickNotifications !== 'undefined') {
9197        KTLayoutQuickNotifications.init('kt_quick_notifications');
9198    }
9199
9200    // Init Quick Offcanvas Panel
9201    if (typeof KTLayoutQuickPanel !== 'undefined') {
9202        KTLayoutQuickPanel.init('kt_quick_panel');
9203    }
9204
9205    // Init Quick Search Panel
9206    if (typeof KTLayoutQuickSearch !== 'undefined') {
9207        KTLayoutQuickSearch.init('kt_quick_search');
9208    }
9209
9210    // Init Quick User Panel
9211    if (typeof KTLayoutQuickUser !== 'undefined') {
9212        KTLayoutQuickUser.init('kt_quick_user');
9213    }
9214
9215    if (typeof KTLayoutQuickUser2 !== 'undefined') {
9216        KTLayoutQuickUser2.init('kt_quick_user2');
9217    }
9218
9219    // Init Search Inline Dropdown For Desktop Mode
9220    if (typeof KTLayoutSearchInline !== 'undefined') {
9221        KTLayoutSearchInline().init('kt_quick_search_inline');
9222    }
9223
9224    // Init Search Dropdown For Tablet & Mobile Mode
9225    if (typeof KTLayoutSearch !== 'undefined') {
9226        KTLayoutSearch().init('kt_quick_search_dropdown');
9227    }
9228});
9229
9230"use strict";
9231
9232var KTLayoutAsideMenu = function() {
9233    // Private properties
9234    var _element;
9235    var _menuObject;
9236
9237	// Initialize
9238	var _init = function() {
9239		var menuDesktopMode = (KTUtil.attr(_element, 'data-menu-dropdown') === '1' ? 'dropdown' : 'accordion');
9240        var scroll;
9241
9242		if (KTUtil.isBreakpointDown('lg') && KTUtil.attr(_element, 'data-menu-scroll') === '1') {
9243			scroll = {
9244				rememberPosition: true, // remember position on page reload
9245				height: function() { // calculate available scrollable area height
9246					var height = parseInt(KTUtil.getViewPort().height);
9247
9248					height = height - (parseInt(KTUtil.css(_element, 'marginBottom')) + parseInt(KTUtil.css(_element, 'marginTop')));
9249
9250					return height;
9251				}
9252			};
9253		}
9254
9255		_menuObject = new KTMenu(_element, {
9256			// Vertical scroll
9257			scroll: scroll,
9258
9259			// Submenu setup
9260			submenu: {
9261				desktop: menuDesktopMode,
9262				tablet: 'accordion', // menu set to accordion in tablet mode
9263				mobile: 'accordion' // menu set to accordion in mobile mode
9264			},
9265
9266			// Accordion setup
9267			accordion: {
9268				expandAll: false // allow having multiple expanded accordions in the menu
9269			}
9270		});
9271	}
9272
9273    // Public methods
9274	return {
9275		init: function(id) {
9276            _element = KTUtil.getById(id);
9277
9278            if (!_element) {
9279                return;
9280            }
9281
9282            // Initialize menu
9283            _init();
9284		},
9285
9286		getElement: function() {
9287			return _element;
9288		},
9289
9290        getMenu: function() {
9291			return _menuObject;
9292		},
9293
9294        pauseDropdownHover: function(time) {
9295			if (_menuObject) {
9296				_menuObject.pauseDropdownHover(time);
9297			}
9298		},
9299
9300		closeMobileOffcanvas: function() {
9301			if (_menuObject && KTUtil.isMobileDevice()) {
9302				_menuObject.hide();
9303			}
9304		}
9305	};
9306}();
9307
9308// Webpack support
9309if (typeof module !== 'undefined') {
9310	module.exports = KTLayoutAsideMenu;
9311}
9312
9313"use strict";
9314
9315var KTLayoutAside = function() {
9316    // Private properties
9317    var _body;
9318    var _element;
9319    var _offcanvasObject;
9320
9321    // Private functions
9322	// Initialize
9323	var _init = function() {
9324		var offcanvasClass = KTUtil.hasClass(_element, 'aside-offcanvas-default') ? 'aside-offcanvas-default' : 'aside';
9325
9326        // Initialize mobile aside offcanvas
9327		_offcanvasObject = new KTOffcanvas(_element, {
9328			baseClass: offcanvasClass,
9329			overlay: true,
9330			closeBy: 'kt_aside_close_btn',
9331			toggleBy: {
9332				target: 'kt_aside_mobile_toggle',
9333				state: 'active'
9334			}
9335		});
9336	}
9337
9338    // Public methods
9339	return {
9340		init: function(id) {
9341            _element = KTUtil.getById(id);
9342            _body = KTUtil.getBody();
9343
9344            if (!_element) {
9345                return;
9346            }
9347
9348            // Initialize
9349            _init();
9350        },
9351
9352        getElement: function() {
9353            return _element;
9354        },
9355
9356        getOffcanvas: function() {
9357            return _offcanvasObject;
9358        }
9359	};
9360}();
9361
9362// Webpack support
9363if (typeof module !== 'undefined') {
9364	module.exports = KTLayoutAside;
9365}
9366
9367"use strict";
9368
9369var KTLayoutContent = function() {
9370    // Private properties
9371    var _element;
9372
9373	// Private functions
9374	var _getHeight = function() {
9375		var height;
9376
9377		height = KTUtil.getViewPort().height;
9378
9379        if (_element) {
9380            height = height - parseInt(KTUtil.css(_element, 'paddingTop')) - parseInt(KTUtil.css(_element, 'paddingBottom'));
9381        }        
9382
9383        height = height - KTLayoutHeader.getHeight();
9384        height = height - KTLayoutSubheader.getHeight();
9385        height = height - KTLayoutFooter.getHeight();
9386
9387		return height;
9388	}
9389
9390    // Public methods
9391	return {
9392		init: function(id) {
9393            _element = KTUtil.getById(id);
9394		},
9395
9396		getHeight: function() {
9397			return _getHeight();
9398		},
9399
9400        getElement: function() {
9401            return _element;
9402        }
9403	};
9404}();
9405
9406// Webpack support
9407if (typeof module !== 'undefined') {
9408	module.exports = KTLayoutContent;
9409}
9410
9411"use strict";
9412
9413var KTLayoutFooter = function() {
9414    // Private properties
9415    var _element;
9416
9417	// Private functions
9418	var _getHeight = function() {
9419		var height = 0;
9420
9421        if (_element) {
9422            height = KTUtil.actualHeight(_element);
9423        }
9424
9425		return height;
9426	}
9427
9428    // Public methods
9429	return {
9430		init: function(id) {
9431            _element = KTUtil.getById(id);
9432		},
9433
9434		getHeight: function() {
9435			return _getHeight();
9436		},
9437
9438        getElement: function() {
9439            return _element;
9440        }
9441	};
9442}();
9443
9444// Webpack support
9445if (typeof module !== 'undefined') {
9446	module.exports = KTLayoutFooter;
9447}
9448
9449"use strict";
9450
9451var KTLayoutHeaderMenu = function() {
9452    // Private properties
9453	var _menuElement;
9454    var _menuObject;
9455    var _offcanvasElement;
9456    var _offcanvasObject;
9457
9458	// Private functions
9459	var _init = function() {
9460		// Initialize Offcanvas Panel For Horizontal  Menu On Mobile Mode
9461		_offcanvasObject = new KTOffcanvas(_offcanvasElement, {
9462			overlay: true,
9463			baseClass: 'header-menu-wrapper',
9464			closeBy: 'kt_header_menu_mobile_close_btn',
9465			toggleBy: {
9466				target: 'kt_header_mobile_toggle',
9467				state: 'active'
9468			}
9469		});
9470
9471		// Initialize Menu For Desktop & Mobile Modes
9472		_menuObject = new KTMenu(_menuElement, {
9473			submenu: {
9474				desktop: 'dropdown',
9475				tablet: 'accordion',
9476				mobile: 'accordion'
9477			},
9478			accordion: {
9479				slideSpeed: 200, // accordion toggle slide speed in milliseconds
9480				expandAll: false // allow having multiple expanded accordions in the menu
9481			}
9482		});
9483	}
9484
9485    // Public methods
9486	return {
9487        init: function(menuId, offcanvasId) {
9488            _menuElement = KTUtil.getById(menuId);
9489            _offcanvasElement = KTUtil.getById(offcanvasId);
9490
9491            if (!_menuElement) {
9492                return;
9493            }
9494
9495            // Initialize menu
9496            _init();
9497		},
9498
9499		getMenuElement: function() {
9500			return _menuElement;
9501		},
9502
9503        getOffcanvasElement: function() {
9504			return _offcanvasElement;
9505		},
9506
9507        getMenu: function() {
9508			return _menuObject;
9509		},
9510
9511		pauseDropdownHover: function(time) {
9512			if (_menuObject) {
9513				_menuObject.pauseDropdownHover(time);
9514			}
9515		},
9516
9517        getOffcanvas: function() {
9518			return _offcanvasObject;
9519		},
9520
9521		closeMobileOffcanvas: function() {
9522			if (_menuObject && KTUtil.isMobileDevice()) {
9523				_offcanvasObject.hide();
9524			}
9525		}
9526	};
9527}();
9528
9529// Webpack support
9530if (typeof module !== 'undefined') {
9531	module.exports = KTLayoutHeaderMenu;
9532}
9533
9534"use strict";
9535
9536var KTLayoutHeaderTopbar = function() {
9537    // Private properties
9538	var _toggleElement;
9539    var _toggleObject;
9540
9541    // Private functions
9542    var _init = function() {
9543		_toggleObject = new KTToggle(_toggleElement, KTUtil.getBody(), {
9544			targetState: 'topbar-mobile-on',
9545			toggleState: 'active'
9546		});
9547    }
9548
9549    // Public methods
9550	return {
9551		init: function(id) {
9552            _toggleElement = KTUtil.getById(id);
9553
9554			if (!_toggleElement) {
9555                return;
9556            }
9557
9558            // Initialize
9559            _init();
9560		},
9561
9562        getToggleElement: function() {
9563            return _toggleElement;
9564        }
9565	};
9566}();
9567
9568// Webpack support
9569if (typeof module !== 'undefined') {
9570	module.exports = KTLayoutHeaderTopbar;
9571}
9572
9573"use strict";
9574
9575var KTLayoutHeader = function() {
9576    // Private properties
9577    var _element;
9578    var _elementForMobile;
9579    var _object;
9580
9581	// Private functions
9582	var _init = function() {
9583        var options = {
9584            offset: {
9585                desktop: 200,
9586                tabletAndMobile: 300
9587            }
9588		};
9589
9590		_object = new KTHeader(_element, options);
9591	}
9592
9593    // Get height
9594    var _getHeight = function() {
9595        var height = 0;
9596
9597        if (_element) {
9598            height = KTUtil.actualHeight(_element) + 1;
9599        }
9600
9601        return height;
9602    }
9603
9604    // Get height
9605    var _getHeightForMobile = function() {
9606        var height;
9607
9608        height = KTUtil.actualHeight(_elementForMobile);
9609
9610        return height;
9611    }
9612
9613    // Public methods
9614	return {
9615		init: function(id, idForMobile) {
9616            _element = KTUtil.getById(id);
9617            _elementForMobile = KTUtil.getById(idForMobile);
9618
9619            if (!_element) {
9620                return;
9621            }
9622
9623            // Initialize
9624            _init();
9625		},
9626
9627        isFixed: function() {
9628            return KTUtil.hasClass(KTUtil.getBody(), 'header-fixed')
9629        },
9630
9631        isFixedForMobile: function() {
9632            return KTUtil.hasClass(KTUtil.getBody(), 'header-mobile-fixed')
9633        },
9634
9635        getElement: function() {
9636            return _element;
9637        },
9638
9639        getElementForMobile: function() {
9640            return _elementForMobile;
9641        },
9642
9643        getHeader: function() {
9644            return _object;
9645        },
9646
9647        getHeight: function() {
9648            return _getHeight();
9649        },
9650
9651        getHeightForMobile: function() {
9652            return _getHeightForMobile();
9653        }
9654	};
9655}();
9656
9657// Webpack support
9658if (typeof module !== 'undefined') {
9659	module.exports = KTLayoutHeader;
9660}
9661
9662"use strict";
9663
9664var KTLayoutStickyCard = function() {
9665    // Private properties
9666	var _element;
9667    var _object;
9668
9669	// Private functions
9670	var _init = function() {
9671		var offset = 300;
9672
9673		if (typeof KTLayoutHeader !== 'undefined') {
9674			offset = KTLayoutHeader.getHeight();
9675		}
9676
9677        _object = new KTCard(_element, {
9678			sticky: {
9679				offset: offset,
9680				zIndex: 90,
9681				position: {
9682					top: function() {
9683						var pos = 0;
9684                        var body = KTUtil.getBody();
9685
9686						if (KTUtil.isBreakpointUp('lg')) {
9687							if (typeof KTLayoutHeader !== 'undefined' && KTLayoutHeader.isFixed()) {
9688								pos = pos + KTLayoutHeader.getHeight();
9689							}
9690
9691							if (typeof KTLayoutSubheader !== 'undefined' && KTLayoutSubheader.isFixed()) {
9692								pos = pos + KTLayoutSubheader.getHeight();
9693							}
9694						} else {
9695							if (typeof KTLayoutHeader !== 'undefined' && KTLayoutHeader.isFixedForMobile()) {
9696								pos = pos + KTLayoutHeader.getHeightForMobile();
9697							}
9698						}
9699
9700						pos = pos - 1; // remove header border width
9701
9702						return pos;
9703					},
9704					left: function(card) {
9705						return KTUtil.offset(_element).left;
9706					},
9707					right: function(card) {
9708						var body = KTUtil.getBody();
9709
9710						var cardWidth = parseInt(KTUtil.css(_element, 'width'));
9711						var bodyWidth = parseInt(KTUtil.css(body, 'width'));
9712						var cardOffsetLeft = KTUtil.offset(_element).left;
9713
9714						return bodyWidth - cardWidth - cardOffsetLeft;
9715					}
9716				}
9717			}
9718		});
9719
9720		_object.initSticky();
9721
9722		KTUtil.addResizeHandler(function() {
9723			_object.updateSticky();
9724		});
9725	}
9726
9727    // Public methods
9728	return {
9729		init: function(id) {
9730            _element = KTUtil.getById(id);
9731
9732            if (!_element) {
9733                return;
9734            }
9735
9736            // Initialize
9737			_init();
9738		},
9739
9740		update: function() {
9741			if (_object) {
9742				_object.updateSticky();
9743			}
9744		}
9745	};
9746}();
9747
9748// Webpack support
9749if (typeof module !== 'undefined') {
9750	module.exports = KTLayoutStickyCard;
9751}
9752
9753"use strict";
9754
9755var KTLayoutStretchedCard = function() {
9756    // Private properties
9757	var _element;
9758
9759	// Private functions
9760	var _init = function() {
9761		var scroll = KTUtil.find(_element, '.card-scroll');
9762		var cardBody = KTUtil.find(_element, '.card-body');
9763		var cardHeader = KTUtil.find(_element, '.card-header');
9764
9765		var height = KTLayoutContent.getHeight();
9766
9767		height = height - parseInt(KTUtil.actualHeight(cardHeader));
9768
9769		height = height - parseInt(KTUtil.css(_element, 'marginTop')) - parseInt(KTUtil.css(_element, 'marginBottom'));
9770		height = height - parseInt(KTUtil.css(_element, 'paddingTop')) - parseInt(KTUtil.css(_element, 'paddingBottom'));
9771
9772		height = height - parseInt(KTUtil.css(cardBody, 'paddingTop')) - parseInt(KTUtil.css(cardBody, 'paddingBottom'));
9773		height = height - parseInt(KTUtil.css(cardBody, 'marginTop')) - parseInt(KTUtil.css(cardBody, 'marginBottom'));
9774
9775		height = height - 3;
9776
9777		KTUtil.css(scroll, 'height', height + 'px');
9778	}
9779
9780    // Public methods
9781	return {
9782		init: function(id) {
9783            _element = KTUtil.getById(id);
9784
9785            if (!_element) {
9786                return;
9787            }
9788
9789            // Initialize
9790			_init();
9791
9792            // Re-calculate on window resize
9793            KTUtil.addResizeHandler(function() {
9794				_init();
9795			});
9796		},
9797
9798		update: function() {
9799			_init();
9800		}
9801	};
9802}();
9803
9804// Webpack support
9805if (typeof module !== 'undefined') {
9806	module.exports = KTLayoutStretchedCard;
9807}
9808
9809"use strict";
9810
9811var KTLayoutSubheader = function() {
9812    // Private properties
9813    var _element;
9814
9815    // Private functions
9816    var _getHeight = function() {
9817        var height = 0;
9818
9819        if (_element) {
9820            height = KTUtil.actualHeight(_element);
9821        }
9822
9823        return height;
9824    }
9825
9826    // Public methods
9827	return {
9828		init: function(id) {
9829            _element = KTUtil.getById(id);
9830
9831            if (!_element) {
9832                return;
9833            }
9834		},
9835
9836        isFixed: function() {
9837            return KTUtil.hasClass(KTUtil.getBody(), 'subheader-fixed');
9838        },
9839
9840        getElement: function() {
9841            return _element;
9842        },
9843
9844        getHeight: function() {
9845            return _getHeight();
9846        }
9847	};
9848}();
9849
9850// Webpack support
9851if (typeof module !== 'undefined') {
9852	module.exports = KTLayoutSubheader;
9853}
9854
9855"use strict";
9856
9857// Class definition
9858var KTLayoutChat = function () {
9859	// Private functions
9860	var _init = function (element) {
9861		var scrollEl = KTUtil.find(element, '.scroll');
9862		var cardBodyEl = KTUtil.find(element, '.card-body');
9863		var cardHeaderEl = KTUtil.find(element, '.card-header');
9864		var cardFooterEl = KTUtil.find(element, '.card-footer');
9865
9866		if (!scrollEl) {
9867			return;
9868		}
9869
9870		// initialize perfect scrollbar(see:  https://github.com/utatti/perfect-scrollbar)
9871		KTUtil.scrollInit(scrollEl, {
9872			windowScroll: false, // allow browser scroll when the scroll reaches the end of the side
9873			mobileNativeScroll: true,  // enable native scroll for mobile
9874			desktopNativeScroll: false, // disable native scroll and use custom scroll for desktop
9875			resetHeightOnDestroy: true,  // reset css height on scroll feature destroyed
9876			handleWindowResize: true, // recalculate hight on window resize
9877			rememberPosition: true, // remember scroll position in cookie
9878			height: function() {  // calculate height
9879				var height;
9880
9881				if (KTUtil.isBreakpointDown('lg')) { // Mobile mode
9882					return KTUtil.hasAttr(scrollEl, 'data-mobile-height') ? parseInt(KTUtil.attr(scrollEl, 'data-mobile-height')) : 400;
9883				} else if (KTUtil.isBreakpointUp('lg') && KTUtil.hasAttr(scrollEl, 'data-height')) { // Desktop Mode
9884					return parseInt(KTUtil.attr(scrollEl, 'data-height'));
9885				} else {
9886					height = KTLayoutContent.getHeight();
9887
9888					if (scrollEl) {
9889						height = height - parseInt(KTUtil.css(scrollEl, 'margin-top')) - parseInt(KTUtil.css(scrollEl, 'margin-bottom'));
9890					}
9891
9892					if (cardHeaderEl) {
9893						height = height - parseInt(KTUtil.css(cardHeaderEl, 'height'));
9894						height = height - parseInt(KTUtil.css(cardHeaderEl, 'margin-top')) - parseInt(KTUtil.css(cardHeaderEl, 'margin-bottom'));
9895					}
9896
9897					if (cardBodyEl) {
9898						height = height - parseInt(KTUtil.css(cardBodyEl, 'padding-top')) - parseInt(KTUtil.css(cardBodyEl, 'padding-bottom'));
9899					}
9900
9901					if (cardFooterEl) {
9902						height = height - parseInt(KTUtil.css(cardFooterEl, 'height'));
9903						height = height - parseInt(KTUtil.css(cardFooterEl, 'margin-top')) - parseInt(KTUtil.css(cardFooterEl, 'margin-bottom'));
9904					}
9905				}
9906
9907				// Remove additional space
9908				height = height - 2;
9909
9910				return height;
9911			}
9912		});
9913
9914		// attach events
9915		KTUtil.on(element, '.card-footer textarea', 'keydown', function(e) {
9916			if (e.keyCode == 13) {
9917				_handeMessaging(element);
9918				e.preventDefault();
9919
9920				return false;
9921			}
9922		});
9923
9924		KTUtil.on(element, '.card-footer .chat-send', 'click', function(e) {
9925			_handeMessaging(element);
9926		});
9927	}
9928
9929	var _handeMessaging = function(element) {
9930		var messagesEl = KTUtil.find(element, '.messages');
9931		var scrollEl = KTUtil.find(element, '.scroll');
9932        var textarea = KTUtil.find(element, 'textarea');
9933
9934        if (textarea.value.length === 0 ) {
9935            return;
9936        }
9937
9938		var node = document.createElement("DIV");
9939		KTUtil.addClass(node, 'd-flex flex-column mb-5 align-items-end');
9940
9941		var html = '';
9942		html += '<div class="d-flex align-items-center">';
9943		html += '	<div>';
9944		html += '		<span class="text-muted font-size-sm">2 Hours</span>';
9945		html += '		<a href="#" class="text-dark-75 text-hover-primary font-weight-bold font-size-h6">You</a>';
9946		html += '	</div>';
9947		html += '	<div class="symbol symbol-circle symbol-40 ml-3">';
9948		html += '		<img alt="Pic" src="assets/media/users/150-9.jpg"/>';
9949		html += '	</div>';
9950		html += '</div>';
9951		html += '<div class="mt-2 rounded p-5 bg-light-primary text-dark-50 font-weight-bold font-size-lg text-right max-w-400px">' + textarea.value + '</div>';
9952
9953		KTUtil.setHTML(node, html);
9954		messagesEl.appendChild(node);
9955		textarea.value = '';
9956		scrollEl.scrollTop = parseInt(KTUtil.css(messagesEl, 'height'));
9957
9958		var ps;
9959		if (ps = KTUtil.data(scrollEl).get('ps')) {
9960			ps.update();
9961		}
9962
9963		setTimeout(function() {
9964			var node = document.createElement("DIV");
9965			KTUtil.addClass(node, 'd-flex flex-column mb-5 align-items-start');
9966
9967			var html = '';
9968			html += '<div class="d-flex align-items-center">';
9969			html += '	<div class="symbol symbol-circle symbol-40 mr-3">';
9970			html += '		<img alt="Pic" src="assets/media/users/150-11.jpg"/>';
9971			html += '	</div>';
9972			html += '	<div>';
9973			html += '		<a href="#" class="text-dark-75 text-hover-primary font-weight-bold font-size-h6">Matt Pears</a>';
9974			html += '		<span class="text-muted font-size-sm">Just now</span>';
9975			html += '	</div>';
9976			html += '</div>';
9977			html += '<div class="mt-2 rounded p-5 bg-light-success text-dark-50 font-weight-bold font-size-lg text-left max-w-400px">';
9978			html += 'Right before vacation season we have the next Big Deal for you.';
9979			html += '</div>';
9980
9981			KTUtil.setHTML(node, html);
9982			messagesEl.appendChild(node);
9983			textarea.value = '';
9984			scrollEl.scrollTop = parseInt(KTUtil.css(messagesEl, 'height'));
9985
9986			var ps;
9987			if (ps = KTUtil.data(scrollEl).get('ps')) {
9988				ps.update();
9989			}
9990		}, 2000);
9991	}
9992
9993	// Public methods
9994	return {
9995		init: function(id) {
9996			// Init modal chat example
9997			_init(KTUtil.getById(id));
9998
9999			// Trigger click to show popup modal chat on page load
10000			if (encodeURI(window.location.hostname) == 'keenthemes.com' || encodeURI(window.location.hostname) == 'www.keenthemes.com') {
10001				setTimeout(function() {
10002		            if (!KTCookie.getCookie('kt_app_chat_shown')) {
10003		                var expires = new Date(new Date().getTime() + 60 * 60 * 1000); // expire in 60 minutes from now
10004
10005						KTCookie.setCookie('kt_app_chat_shown', 1, { expires: expires });
10006
10007						if (KTUtil.getById('kt_app_chat_launch_btn')) {
10008							KTUtil.getById('kt_app_chat_launch_btn').click();
10009						}
10010		            }
10011		        }, 2000);
10012	        }
10013        },
10014
10015        setup: function(element) {
10016            _init(element);
10017        }
10018	};
10019}();
10020
10021// Webpack support
10022if (typeof module !== 'undefined') {
10023	module.exports = KTLayoutChat;
10024}
10025
10026"use strict";
10027
10028var KTLayoutDemoPanel = function() {
10029    // Private properties
10030    var _element;
10031    var _offcanvasObject;
10032
10033    // Private functions
10034    var _init = function() {
10035        _offcanvasObject = new KTOffcanvas(_element, {
10036            overlay: true,
10037            baseClass: 'offcanvas',
10038            placement: 'right',
10039            closeBy: 'kt_demo_panel_close',
10040            toggleBy: 'kt_demo_panel_toggle'
10041        });
10042
10043        var header = KTUtil.find(_element, '.offcanvas-header');
10044        var content = KTUtil.find(_element, '.offcanvas-content');
10045        var wrapper = KTUtil.find(_element, '.offcanvas-wrapper');
10046        var footer = KTUtil.find(_element, '.offcanvas-footer');
10047
10048        KTUtil.scrollInit(wrapper, {
10049            disableForMobile: true,
10050            resetHeightOnDestroy: true,
10051            handleWindowResize: true,
10052            height: function() {
10053                var height = parseInt(KTUtil.getViewPort().height);
10054
10055                if (header) {
10056                    height = height - parseInt(KTUtil.actualHeight(header));
10057                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10058                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10059                }
10060
10061                if (content) {
10062                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10063                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10064                }
10065
10066                if (wrapper) {
10067                    height = height - parseInt(KTUtil.css(wrapper, 'marginTop'));
10068                    height = height - parseInt(KTUtil.css(wrapper, 'marginBottom'));
10069                }
10070
10071                if (footer) {
10072                    height = height - parseInt(KTUtil.actualHeight(footer));
10073                    height = height - parseInt(KTUtil.css(footer, 'marginTop'));
10074                    height = height - parseInt(KTUtil.css(footer, 'marginBottom'));
10075                }
10076
10077                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10078                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10079
10080                height = height - 2;
10081
10082                return height;
10083            }
10084        });
10085
10086        if (typeof offcanvas !== 'undefined' && offcanvas.length === 0) {
10087            offcanvas.on('hide', function() {
10088                var expires = new Date(new Date().getTime() + 60 * 60 * 1000); // expire in 60 minutes from now
10089                KTCookie.setCookie('kt_demo_panel_shown', 1, {expires: expires});
10090            });
10091        }
10092    }
10093
10094    var _remind = function() {
10095        if (!(encodeURI(window.location.hostname) == 'keenthemes.com' || encodeURI(window.location.hostname) == 'www.keenthemes.com')) {
10096            return;
10097        }
10098
10099        setTimeout(function() {
10100            if (!KTCookie.getCookie('kt_demo_panel_shown')) {
10101                var expires = new Date(new Date().getTime() + 15 * 60 * 1000); // expire in 15 minutes from now
10102                KTCookie.setCookie('kt_demo_panel_shown', 1, { expires: expires });
10103                if (typeof _offcanvasObject !== 'undefined') {
10104                    _offcanvasObject.show();
10105                }
10106            }
10107        }, 4000);
10108    }
10109
10110    // Public methods
10111    return {
10112        init: function(id) {
10113            _element = KTUtil.getById(id);
10114
10115            if (!_element) {
10116                return;
10117            }
10118
10119            // Initialize
10120            _init();
10121
10122            // Remind
10123            _remind();
10124        }
10125    };
10126}();
10127
10128// Webpack support
10129if (typeof module !== 'undefined') {
10130	module.exports = KTLayoutDemoPanel;
10131}
10132
10133"use strict";
10134
10135var KTLayoutExamples = function() {
10136
10137    var initDefaultMode = function(element) {
10138        var elements = element;
10139        if (typeof elements === 'undefined') {
10140            elements = document.querySelectorAll('.example:not(.example-compact):not(.example-hover):not(.example-basic)');
10141        }
10142
10143        for (var i = 0; i < elements.length; ++i) {
10144            var example = elements[i];
10145            var copy = KTUtil.find(example, '.example-copy');
10146
10147            var clipboard = new ClipboardJS(copy, {
10148                target: function(trigger) {
10149                    var example = trigger.closest('.example');
10150                    var el = KTUtil.find(example, '.example-code .tab-pane.active');
10151
10152                    if (!el) {
10153                        el = KTUtil.find(example, '.example-code');
10154                    }
10155
10156                    return el;
10157                }
10158            });
10159
10160            clipboard.on('success', function(e) {
10161                KTUtil.addClass(e.trigger, 'example-copied');
10162                e.clearSelection();
10163
10164                setTimeout(function() {
10165                    KTUtil.removeClass(e.trigger, 'example-copied');
10166                }, 2000);
10167            });
10168        }
10169    }
10170
10171    var initCompactMode = function(element) {
10172        var example,code,toggle,copy, clipboard;
10173        var elements = element;
10174        if (typeof elements === 'undefined') {
10175            var elements = document.querySelectorAll('.example.example-compact');
10176        }
10177
10178        for (var i = 0; i < elements.length; ++i) {
10179            var example = elements[i];
10180            var toggle = KTUtil.find(example, '.example-toggle');
10181            var copy = KTUtil.find(example, '.example-copy');
10182
10183            // Handle toggle
10184            KTUtil.addEvent(toggle, 'click', function() {
10185                var example = this.closest('.example');
10186                var code =  KTUtil.find(example, '.example-code');
10187                var the = this;
10188
10189                if (KTUtil.hasClass(this, 'example-toggled')) {
10190                    KTUtil.slideUp(code, 300, function() {
10191                        KTUtil.removeClass(the, 'example-toggled');
10192                        KTUtil.removeClass(code, 'example-code-on');
10193                        KTUtil.hide(code);
10194                    });
10195                } else {
10196                    KTUtil.addClass(code, 'example-code-on');
10197                    KTUtil.addClass(this, 'example-toggled');
10198                    KTUtil.slideDown(code, 300, function() {
10199                        KTUtil.show(code);
10200                    });
10201                }
10202            });
10203
10204            // Handle copy
10205            var clipboard = new ClipboardJS(copy, {
10206                target: function(trigger) {
10207                    var example = trigger.closest('.example');
10208                    var el = KTUtil.find(example, '.example-code .tab-pane.active');
10209
10210                    if (!el) {
10211                        el = KTUtil.find(example, '.example-code');
10212                    }
10213
10214                    return el;
10215                }
10216            });
10217
10218            clipboard.on('success', function(e) {
10219                KTUtil.addClass(e.trigger, 'example-copied');
10220                e.clearSelection();
10221
10222                setTimeout(function() {
10223                    KTUtil.removeClass(e.trigger, 'example-copied');
10224                }, 2000);
10225            });
10226        }
10227    }
10228
10229    return {
10230        init: function(element, options) {
10231            initDefaultMode(element);
10232            initCompactMode(element);
10233        }
10234    };
10235}();
10236
10237// webpack support
10238if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
10239    module.exports = KTLayoutExamples;
10240}
10241
10242"use strict";
10243
10244var KTLayoutQuickActions = function() {
10245    // Private properties
10246    var _element;
10247    var _offcanvasObject;
10248
10249    // Private functions
10250    var _init = function() {
10251        var header = KTUtil.find(_element, '.offcanvas-header');
10252        var content = KTUtil.find(_element, '.offcanvas-content');
10253
10254        _offcanvasObject = new KTOffcanvas(_element, {
10255            overlay: true,
10256            baseClass: 'offcanvas',
10257            placement: 'right',
10258            closeBy: 'kt_quick_actions_close',
10259            toggleBy: 'kt_quick_actions_toggle'
10260        });
10261
10262        KTUtil.scrollInit(content, {
10263            disableForMobile: true,
10264            resetHeightOnDestroy: true,
10265            handleWindowResize: true,
10266            height: function() {
10267                var height = parseInt(KTUtil.getViewPort().height);
10268
10269                if (header) {
10270                    height = height - parseInt(KTUtil.actualHeight(header));
10271                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10272                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10273                }
10274
10275                if (content) {
10276                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10277                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10278                }
10279
10280                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10281                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10282
10283                height = height - 2;
10284
10285                return height;
10286            }
10287        });
10288    }
10289
10290    // Public methods
10291    return {
10292        init: function(id) {
10293            _element = KTUtil.getById(id);
10294
10295            if (!_element) {
10296                return;
10297            }
10298
10299            // Initialize
10300            _init();
10301        },
10302
10303        getElement: function() {
10304            return _element;
10305        }
10306    };
10307}();
10308
10309// Webpack support
10310if (typeof module !== 'undefined') {
10311	module.exports = KTLayoutQuickActions;
10312}
10313
10314"use strict";
10315
10316var KTLayoutQuickCartPanel = function() {
10317    // Private properties
10318    var _element;
10319    var _offcanvasObject;
10320
10321    // Private functions
10322    var _init = function() {
10323        _offcanvasObject = new KTOffcanvas(_element, {
10324            overlay: true,
10325            baseClass: 'offcanvas',
10326            placement: 'right',
10327            closeBy: 'kt_quick_cart_close',
10328            toggleBy: 'kt_quick_cart_toggle'
10329        });
10330
10331        var header = KTUtil.find(_element, '.offcanvas-header');
10332        var content = KTUtil.find(_element, '.offcanvas-content');
10333        var wrapper = KTUtil.find(_element, '.offcanvas-wrapper');
10334        var footer = KTUtil.find(_element, '.offcanvas-footer');
10335
10336        KTUtil.scrollInit(wrapper, {
10337            disableForMobile: true,
10338            resetHeightOnDestroy: true,
10339            handleWindowResize: true,
10340            height: function() {
10341                var height = parseInt(KTUtil.getViewPort().height);
10342
10343                if (header) {
10344                    height = height - parseInt(KTUtil.actualHeight(header));
10345                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10346                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10347                }
10348
10349                if (content) {
10350                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10351                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10352                }
10353
10354                if (wrapper) {
10355                    height = height - parseInt(KTUtil.css(wrapper, 'marginTop'));
10356                    height = height - parseInt(KTUtil.css(wrapper, 'marginBottom'));
10357                }
10358
10359                if (footer) {
10360                    height = height - parseInt(KTUtil.actualHeight(footer));
10361                    height = height - parseInt(KTUtil.css(footer, 'marginTop'));
10362                    height = height - parseInt(KTUtil.css(footer, 'marginBottom'));
10363                }
10364
10365                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10366                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10367
10368                height = height - 2;
10369
10370                return height;
10371            }
10372        });
10373    }
10374
10375    // Public methods
10376    return {
10377        init: function(id) {
10378            _element = KTUtil.getById(id);
10379
10380            if (!_element) {
10381                return;
10382            }
10383
10384            // Initialize
10385            _init();
10386        }
10387    };
10388}();
10389
10390// Webpack support
10391if (typeof module !== 'undefined') {
10392	module.exports = KTLayoutQuickCartPanel;
10393}
10394
10395"use strict";
10396
10397var KTLayoutQuickNotifications = function() {
10398    // Private properties
10399    var _element;
10400    var _offcanvasObject;
10401
10402    // Private functions
10403    var _init = function() {
10404        var header = KTUtil.find(_element, '.offcanvas-header');
10405        var content = KTUtil.find(_element, '.offcanvas-content');
10406
10407        _offcanvasObject = new KTOffcanvas(_element, {
10408            overlay: true,
10409            baseClass: 'offcanvas',
10410            placement: 'right',
10411            closeBy: 'kt_quick_notifications_close',
10412            toggleBy: 'kt_quick_notifications_toggle'
10413        });
10414
10415        KTUtil.scrollInit(content, {
10416            disableForMobile: true,
10417            resetHeightOnDestroy: true,
10418            handleWindowResize: true,
10419            height: function() {
10420                var height = parseInt(KTUtil.getViewPort().height);
10421
10422                if (header) {
10423                    height = height - parseInt(KTUtil.actualHeight(header));
10424                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10425                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10426                }
10427
10428                if (content) {
10429                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10430                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10431                }
10432
10433                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10434                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10435
10436                height = height - 2;
10437
10438                return height;
10439            }
10440        });
10441    }
10442
10443    // Public methods
10444    return {
10445        init: function(id) {
10446            _element = KTUtil.getById(id);
10447
10448            if (!_element) {
10449                return;
10450            }
10451
10452            // Initialize
10453            _init();
10454        },
10455
10456        getElement: function() {
10457            return _element;
10458        }
10459    };
10460}();
10461
10462// Webpack support
10463if (typeof module !== 'undefined') {
10464	module.exports = KTLayoutQuickNotifications;
10465}
10466
10467"use strict";
10468
10469var KTLayoutQuickPanel = function() {
10470    // Private properties
10471    var _element;
10472    var _offcanvasObject;
10473    var _notificationsElement;
10474    var _logsElement;
10475    var _settingsElement;
10476
10477    // Private functions
10478    var _getContentHeight = function() {
10479        var height;
10480
10481        var header = KTUtil.find(_element, '.offcanvas-header');
10482        var content = KTUtil.find(_element, '.offcanvas-content');
10483
10484        var height = parseInt(KTUtil.getViewPort().height);
10485
10486        if (header) {
10487            height = height - parseInt(KTUtil.actualHeight(header));
10488            height = height - parseInt(KTUtil.css(header, 'marginTop'));
10489            height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10490        }
10491
10492        if (content) {
10493            height = height - parseInt(KTUtil.css(content, 'marginTop'));
10494            height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10495        }
10496
10497        height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10498        height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10499
10500        height = height - 2;
10501
10502        return height;
10503    }
10504
10505    var _init = function() {
10506        _offcanvasObject = new KTOffcanvas(_element, {
10507            overlay: true,
10508            baseClass: 'offcanvas',
10509            placement: 'right',
10510            closeBy: 'kt_quick_panel_close',
10511            toggleBy: 'kt_quick_panel_toggle'
10512        });
10513    }
10514
10515    var _initNotifications = function() {
10516        KTUtil.scrollInit(_notificationsElement, {
10517            mobileNativeScroll: true,
10518            resetHeightOnDestroy: true,
10519            handleWindowResize: true,
10520            height: function() {
10521                return _getContentHeight();
10522            }
10523        });
10524    }
10525
10526    var _initLogs = function() {
10527        KTUtil.scrollInit(_logsElement, {
10528            mobileNativeScroll: true,
10529            resetHeightOnDestroy: true,
10530            handleWindowResize: true,
10531            height: function() {
10532                return _getContentHeight();
10533            }
10534        });
10535    }
10536
10537    var _initSettings = function() {
10538        KTUtil.scrollInit(_settingsElement, {
10539            mobileNativeScroll: true,
10540            resetHeightOnDestroy: true,
10541            handleWindowResize: true,
10542            height: function() {
10543                return _getContentHeight();
10544            }
10545        });
10546    }
10547
10548    var _updateScrollbars = function() {
10549        $(_element).find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
10550            KTUtil.scrollUpdate(_notificationsElement);
10551            KTUtil.scrollUpdate(_logsElement);
10552            KTUtil.scrollUpdate(_settingsElement);
10553        });
10554    }
10555
10556    // Public methods
10557    return {
10558        init: function(id) {
10559            _element = KTUtil.getById(id);
10560            _notificationsElement = KTUtil.getById('kt_quick_panel_notifications');
10561            _logsElement = KTUtil.getById('kt_quick_panel_logs');
10562            _settingsElement = KTUtil.getById('kt_quick_panel_settings');
10563
10564            _init();
10565            _initNotifications();
10566            _initLogs();
10567            _initSettings();
10568
10569            _updateScrollbars();
10570        }
10571    };
10572}();
10573
10574// Webpack support
10575if (typeof module !== 'undefined') {
10576	module.exports = KTLayoutQuickPanel;
10577}
10578
10579"use strict";
10580
10581var KTLayoutQuickSearch = function() {
10582    // Private properties
10583    var _element;
10584    var _offcanvasObject;
10585
10586    // Private functions
10587    var _init = function() {
10588        var header = KTUtil.find(_element, '.offcanvas-header');
10589        var content = KTUtil.find(_element, '.offcanvas-content');
10590        var form = KTUtil.find(_element, '.quick-search-form');
10591        var results = KTUtil.find(_element, '.quick-search-wrapper');
10592
10593        _offcanvasObject = new KTOffcanvas(_element, {
10594            overlay: true,
10595            baseClass: 'offcanvas',
10596            placement: 'right',
10597            closeBy: 'kt_quick_search_close',
10598            toggleBy: 'kt_quick_search_toggle'
10599        });
10600
10601        KTUtil.scrollInit(results, {
10602            disableForMobile: true,
10603            resetHeightOnDestroy: true,
10604            handleWindowResize: true,
10605            height: function() {
10606                var height = parseInt(KTUtil.getViewPort().height);
10607
10608                if (header) {
10609                    height = height - parseInt(KTUtil.actualHeight(header));
10610                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10611                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10612                }
10613
10614                if (content) {
10615                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10616                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10617                }
10618
10619                if (results) {
10620                    height = height - parseInt(KTUtil.actualHeight(form));
10621                    height = height - parseInt(KTUtil.css(form, 'marginTop'));
10622                    height = height - parseInt(KTUtil.css(form, 'marginBottom'));
10623
10624                    height = height - parseInt(KTUtil.css(results, 'marginTop'));
10625                    height = height - parseInt(KTUtil.css(results, 'marginBottom'));
10626                }
10627
10628                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10629                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10630
10631                height = height - 2;
10632
10633                return height;
10634            }
10635        });
10636    }
10637
10638    // Public methods
10639    return {
10640        init: function(id) {
10641            _element = KTUtil.getById(id);
10642
10643            if (!_element) {
10644                return;
10645            }
10646
10647  
10647          // Initialize
10648            _init();
10649        },
10650
10651        getElement: function() {
10652            return _element;
10653        }
10654    };
10655}();
10656
10657// Webpack support
10658if (typeof module !== 'undefined') {
10659	module.exports = KTLayoutQuickSearch;
10660}
10661
10662"use strict";
10663
10664var KTLayoutQuickUser = function() {
10665    // Private properties
10666    var _element;
10667    var _offcanvasObject;
10668
10669    // Private functions
10670    var _init = function() {
10671        var header = KTUtil.find(_element, '.offcanvas-header');
10672        var content = KTUtil.find(_element, '.offcanvas-content');
10673
10674        _offcanvasObject = new KTOffcanvas(_element, {
10675            overlay: true,
10676            baseClass: 'offcanvas',
10677            placement: 'right',
10678            closeBy: 'kt_quick_user_close',
10679            toggleBy: 'kt_quick_user_toggle'
10680        });
10681
10682        KTUtil.scrollInit(content, {
10683            disableForMobile: true,
10684            resetHeightOnDestroy: true,
10685            handleWindowResize: true,
10686            height: function() {
10687                var height = parseInt(KTUtil.getViewPort().height);
10688
10689                if (header) {
10690                    height = height - parseInt(KTUtil.actualHeight(header));
10691                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10692                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10693                }
10694
10695                if (content) {
10696                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10697                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10698                }
10699
10700                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10701                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10702
10703                height = height - 2;
10704
10705                return height;
10706            }
10707        });
10708    }
10709
10710    // Public methods
10711    return {
10712        init: function(id) {
10713            _element = KTUtil.getById(id);
10714
10715            if (!_element) {
10716                return;
10717            }
10718
10719            // Initialize
10720            _init();
10721        },
10722
10723        getElement: function() {
10724            return _element;
10725        }
10726    };
10727}();
10728
10729// Webpack support
10730if (typeof module !== 'undefined') {
10731	module.exports = KTLayoutQuickUser;
10732}
10733
10734"use strict";
10735
10736var KTLayoutQuickUser2 = function() {
10737    // Private properties
10738    var _element;
10739    var _offcanvasObject;
10740
10741    // Private functions
10742    var _init = function() {
10743        var header = KTUtil.find(_element, '.offcanvas-header');
10744        var content = KTUtil.find(_element, '.offcanvas-content');
10745
10746        _offcanvasObject = new KTOffcanvas(_element, {
10747            overlay: true,
10748            baseClass: 'offcanvas',
10749            placement: 'right',
10750            closeBy: 'kt_quick_user2_close',
10751            toggleBy: 'kt_quick_user2_toggle'
10752        });
10753
10754        KTUtil.scrollInit(content, {
10755            disableForMobile: true,
10756            resetHeightOnDestroy: true,
10757            handleWindowResize: true,
10758            height: function() {
10759                var height = parseInt(KTUtil.getViewPort().height);
10760
10761                if (header) {
10762                    height = height - parseInt(KTUtil.actualHeight(header));
10763                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10764                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10765                }
10766
10767                if (content) {
10768                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10769                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10770                }
10771
10772                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10773                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10774
10775                height = height - 2;
10776
10777                return height;
10778            }
10779        });
10780    }
10781
10782    // Public methods
10783    return {
10784        init: function(id) {
10785            _element = KTUtil.getById(id);
10786
10787            if (!_element) {
10788                return;
10789            }
10790
10791            // Initialize
10792            _init();
10793        },
10794
10795        getElement: function() {
10796            return _element;
10797        }
10798    };
10799}();
10800
10801// Webpack support
10802if (typeof module !== 'undefined') {
10803	module.exports = KTLayoutQuickUser2;
10804}
10805
10806"use strict";
10807
10808var KTLayoutScrolltop = function() {
10809    // Private properties
10810    var _element;
10811    var _object;
10812
10813    // Private functions
10814    var _init = function() {
10815        _object = new KTScrolltop(_element, {
10816            offset: 300,
10817			speed: 600
10818		});
10819    }
10820
10821    // Public methods
10822	return {
10823		init: function(id) {
10824            _element = KTUtil.getById(id);
10825
10826            if (!_element) {
10827                return;
10828            }
10829
10830            // Initialize
10831            _init();
10832		},
10833
10834        getElement: function() {
10835            return _element;
10836        }
10837	};
10838}();
10839
10840// Webpack support
10841if (typeof module !== 'undefined') {
10842	module.exports = KTLayoutScrolltop;
10843}
10844
10845"use strict";
10846
10847var KTLayoutSearch = function() {
10848    // Private properties
10849    var _target;
10850    var _form;
10851    var _input;
10852    var _closeIcon;
10853    var _resultWrapper;
10854    var _resultDropdown;
10855    var _resultDropdownToggle;
10856    var _closeIconContainer;
10857    var _inputGroup;
10858    var _query = '';
10859
10860    var _hasResult = false;
10861    var _timeout = false;
10862    var _isProcessing = false;
10863    var _requestTimeout = 200; // ajax request fire timeout in milliseconds
10864    var _spinnerClass = 'spinner spinner-sm spinner-primary';
10865    var _resultClass = 'quick-search-has-result';
10866    var _minLength = 2;
10867
10868    // Private functions
10869    var _showProgress = function() {
10870        _isProcessing = true;
10871        KTUtil.addClass(_closeIconContainer, _spinnerClass);
10872
10873        if (_closeIcon) {
10874            KTUtil.hide(_closeIcon);
10875        }
10876    }
10877
10878    var _hideProgress = function() {
10879        _isProcessing = false;
10880        KTUtil.removeClass(_closeIconContainer, _spinnerClass);
10881
10882        if (_closeIcon) {
10883            if (_input.value.length < _minLength) {
10884                KTUtil.hide(_closeIcon);
10885            } else {
10886                KTUtil.show(_closeIcon, 'flex');
10887            }
10888        }
10889    }
10890
10891    var _showDropdown = function() {
10892        if (_resultDropdownToggle && !KTUtil.hasClass(_resultDropdown, 'show')) {
10893            $(_resultDropdownToggle).dropdown('toggle');
10894            $(_resultDropdownToggle).dropdown('update');
10895        }
10896    }
10897
10898    var _hideDropdown = function() {
10899        if (_resultDropdownToggle && KTUtil.hasClass(_resultDropdown, 'show')) {
10900            $(_resultDropdownToggle).dropdown('toggle');
10901        }
10902    }
10903
10904    var _processSearch = function() {
10905        if (_hasResult && _query === _input.value) {
10906            _hideProgress();
10907            KTUtil.addClass(_target, _resultClass);
10908            _showDropdown();
10909            KTUtil.scrollUpdate(_resultWrapper);
10910
10911            return;
10912        }
10913
10914        _query = _input.value;
10915
10916        KTUtil.removeClass(_target, _resultClass);
10917        _showProgress();
10918        _hideDropdown();
10919
10920        setTimeout(function() {
10921            $.ajax({
10922                url: HOST_URL + '/api/quick_search.php',
10923                data: {
10924                    query: _query
10925                },
10926                dataType: 'html',
10927                success: function(res) {
10928                    _hasResult = true;
10929                    _hideProgress();
10930                    KTUtil.addClass(_target, _resultClass);
10931                    KTUtil.setHTML(_resultWrapper, res);
10932                    _showDropdown();
10933                    KTUtil.scrollUpdate(_resultWrapper);
10934                },
10935                error: function(res) {
10936                    _hasResult = false;
10937                    _hideProgress();
10938                    KTUtil.addClass(_target, _resultClass);
10939                    KTUtil.setHTML(_resultWrapper, '<span class="font-weight-bold text-muted">Connection error. Please try again later..</div>');
10940                    _showDropdown();
10941                    KTUtil.scrollUpdate(_resultWrapper);
10942                }
10943            });
10944        }, 1000);
10945    }
10946
10947    var _handleCancel = function(e) {
10948        _input.value = '';
10949        _query = '';
10950        _hasResult = false;
10951        KTUtil.hide(_closeIcon);
10952        KTUtil.removeClass(_target, _resultClass);
10953        _hideDropdown();
10954    }
10955
10956    var _handleSearch = function() {
10957        if (_input.value.length < _minLength) {
10958            _hideProgress();
10959            _hideDropdown();
10960
10961            return;
10962        }
10963
10964        if (_isProcessing == true) {
10965            return;
10966        }
10967
10968        if (_timeout) {
10969            clearTimeout(_timeout);
10970        }
10971
10972        _timeout = setTimeout(function() {
10973            _processSearch();
10974        }, _requestTimeout);
10975    }
10976
10977    // Public methods
10978    return {
10979        init: function(id) {
10980            _target = KTUtil.getById(id);
10981
10982            if (!_target) {
10983                return;
10984            }
10985
10986            _form = KTUtil.find(_target, '.quick-search-form');
10987            _input = KTUtil.find(_target, '.form-control');
10988            _closeIcon = KTUtil.find(_target, '.quick-search-close');
10989            _resultWrapper = KTUtil.find(_target, '.quick-search-wrapper');
10990            _resultDropdown = KTUtil.find(_target, '.dropdown-menu');
10991            _resultDropdownToggle = KTUtil.find(_target, '[data-toggle="dropdown"]');
10992            _inputGroup = KTUtil.find(_target, '.input-group');
10993            _closeIconContainer = KTUtil.find(_target, '.input-group .input-group-append');
10994
10995            // Attach input keyup handler
10996            KTUtil.addEvent(_input, 'keyup', _handleSearch);
10997            KTUtil.addEvent(_input, 'focus', _handleSearch);
10998
10999            // Prevent enter click
11000            _form.onkeypress = function(e) {
11001                var key = e.charCode || e.keyCode || 0;
11002                if (key == 13) {
11003                    e.preventDefault();
11004                }
11005            }
11006
11007            KTUtil.addEvent(_closeIcon, 'click', _handleCancel);
11008        }
11009    };
11010};
11011
11012// Webpack support
11013if (typeof module !== 'undefined') {
11014    module.exports = KTLayoutSearch;
11015}
11016
11017var KTLayoutSearchInline = KTLayoutSearch;
11018var KTLayoutSearchOffcanvas = KTLayoutSearch;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.