PageSourceSearch

https://timegoat.app/assets/theme/assets/js/scripts.bundle.js

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

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.