PageSourceSearch

https://deepskyblue-chimpanzee-409292.hostingersite.com/public/assets/dashboard/js/scripts.bundle.js?v=7.2.3

js deepskyblue-chimpanzee-409292.hostingersite.com collected 2026-10-03 04:22:04 UTC 332,320 bytes, 11,180 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    };
4864
4865    ////////////////////////////
4866    // ** Private Methods  ** //
4867    ////////////////////////////
4868
4869    var Plugin = {
4870        /**
4871         * Construct
4872         */
4873
4874        construct: function(options) {
4875            if (KTUtil.data(element).has('wizard')) {
4876                the = KTUtil.data(element).get('wizard');
4877            } else {
4878                // reset menu
4879                Plugin.init(options);
4880
4881                // build menu
4882                Plugin.build();
4883
4884                KTUtil.data(element).set('wizard', the);
4885            }
4886
4887            return the;
4888        },
4889
4890        /**
4891         * Init wizard
4892         */
4893        init: function(options) {
4894            the.element = element;
4895            the.events = [];
4896
4897            // merge default and user defined options
4898            the.options = KTUtil.deepExtend({}, defaultOptions, options);
4899
4900            // Elements
4901            the.steps = KTUtil.findAll(element, '[data-wizard-type="step"]');
4902
4903            the.btnNext = KTUtil.find(element, '[data-wizard-type="action-next"]');
4904            the.btnPrev = KTUtil.find(element, '[data-wizard-type="action-prev"]');
4905            the.btnSubmit = KTUtil.find(element, '[data-wizard-type="action-submit"]');
4906
4907            // Variables
4908            the.events = [];
4909            the.lastStep = 0;
4910            the.currentStep = 1;
4911            the.newStep = 0;
4912            the.stopped = false;
4913            the.totalSteps = the.steps.length;
4914
4915            // Init current step
4916            if (the.options.startStep > 1) {
4917                Plugin.goTo(the.options.startStep);
4918            }
4919
4920            // Init UI
4921            Plugin.updateUI();
4922        },
4923
4924        /**
4925         * Build Form Wizard
4926         */
4927        build: function() {
4928            // Next button event handler
4929            KTUtil.addEvent(the.btnNext, 'click', function(e) {
4930                e.preventDefault();
4931
4932                // Set new step number
4933                Plugin.setNewStep(Plugin.getNextStep());
4934
4935                // Trigger change event
4936                if (Plugin.eventTrigger('change') !== false) {
4937                    Plugin.goTo(Plugin.getNextStep());
4938                }
4939            });
4940
4941            // Prev button event handler
4942            KTUtil.addEvent(the.btnPrev, 'click', function(e) {
4943                e.preventDefault();
4944
4945                // Set new step number
4946                Plugin.setNewStep(Plugin.getPrevStep());
4947
4948                // Trigger change event
4949                if (Plugin.eventTrigger('change') !== false) {
4950                    Plugin.goTo(Plugin.getPrevStep());
4951                }
4952            });
4953
4954            if (the.options.clickableSteps === true) {
4955                KTUtil.on(element, '[data-wizard-type="step"]', 'click', function() {
4956                    var index = KTUtil.index(this) + 1;
4957
4958                    if (index !== the.currentStep) {
4959                        Plugin.setNewStep(index);
4960
4961                        // Trigger change event
4962                        if (Plugin.eventTrigger('change') !== false) {
4963                            Plugin.goTo(index);
4964                        }
4965                    }
4966                });
4967            }
4968
4969            // Submit button event handler
4970            KTUtil.addEvent(the.btnSubmit, 'click', function(e) {
4971                e.preventDefault();
4972
4973                Plugin.eventTrigger('submit');
4974            });
4975        },
4976
4977        /**
4978         * Handles wizard click wizard
4979         */
4980        goTo: function(number) {
4981            // Skip if stopped
4982            if (the.stopped === true) {
4983                the.stopped = false;
4984                return;
4985            }
4986
4987            // Skip if this step is already shown
4988            if (number === the.currentStep || number > the.totalSteps || number < 0) {
4989                return;
4990            }
4991
4992            // Validate step number
4993            number = parseInt(number);
4994
4995            // Set current step
4996            the.lastStep = the.currentStep;
4997            the.currentStep = number;
4998            the.newStep = 0;
4999
5000            Plugin.updateUI();
5001
5002            Plugin.eventTrigger('changed');
5003
5004            return the;
5005        },
5006
5007        /**
5008         * Stop wizard
5009         */
5010        stop: function() {
5011            the.stopped = true;
5012        },
5013
5014        /**
5015         * Resume wizard
5016         */
5017        resume: function() {
5018            the.stopped = false;
5019        },
5020
5021        /**
5022         * Check last step
5023         */
5024        isLastStep: function() {
5025            return the.currentStep === the.totalSteps;
5026        },
5027
5028        /**
5029         * Check first step
5030         */
5031        isFirstStep: function() {
5032            return the.currentStep === 1;
5033        },
5034
5035        /**
5036         * Check between step
5037         */
5038        isBetweenStep: function() {
5039            return Plugin.isLastStep() === false && Plugin.isFirstStep() === false;
5040        },
5041
5042        /**
5043         * Update wizard UI after step change
5044         */
5045        updateUI: function() {
5046            var stepType = '';
5047            var index = the.currentStep - 1;
5048
5049            if (Plugin.isLastStep()) {
5050                stepType = 'last';
5051            } else if (Plugin.isFirstStep()) {
5052                stepType = 'first';
5053            } else {
5054                stepType = 'between';
5055            }
5056
5057            KTUtil.attr(the.element, 'data-wizard-state', stepType);
5058
5059            // Steps
5060            var steps = KTUtil.findAll(the.element, '[data-wizard-type="step"]');
5061
5062            if (steps && steps.length > 0) {
5063                for (var i = 0, len = steps.length; i < len; i++) {
5064                    if (i == index) {
5065                        KTUtil.attr(steps[i], 'data-wizard-state', 'current');
5066                    } else {
5067                        if (i < index) {
5068                            KTUtil.attr(steps[i], 'data-wizard-state', 'done');
5069                        } else {
5070                            KTUtil.attr(steps[i], 'data-wizard-state', 'pending');
5071                        }
5072                    }
5073                }
5074            }
5075
5076            // Steps Info
5077            var stepsInfo = KTUtil.findAll(the.element, '[data-wizard-type="step-info"]');
5078            if (stepsInfo &&stepsInfo.length > 0) {
5079                for (var i = 0, len = stepsInfo.length; i < len; i++) {
5080                    if (i == index) {
5081                        KTUtil.attr(stepsInfo[i], 'data-wizard-state', 'current');
5082                    } else {
5083                        KTUtil.removeAttr(stepsInfo[i], 'data-wizard-state');
5084                    }
5085                }
5086            }
5087
5088            // Steps Content
5089            var stepsContent = KTUtil.findAll(the.element, '[data-wizard-type="step-content"]');
5090            if (stepsContent&& stepsContent.length > 0) {
5091                for (var i = 0, len = stepsContent.length; i < len; i++) {
5092                    if (i == index) {
5093                        KTUtil.attr(stepsContent[i], 'data-wizard-state', 'current');
5094                    } else {
5095                        KTUtil.removeAttr(stepsContent[i], 'data-wizard-state');
5096                    }
5097                }
5098            }
5099        },
5100
5101        /**
5102         * Get next step number
5103         */
5104        getNextStep: function() {
5105            if (the.totalSteps >= (the.currentStep + 1)) {
5106                return the.currentStep + 1;
5107            } else {
5108                return the.totalSteps;
5109            }
5110        },
5111
5112        /**
5113         * Get prev step number
5114         */
5115        getPrevStep: function() {
5116            if ((the.currentStep - 1) >= 1) {
5117                return the.currentStep - 1;
5118            } else {
5119                return 1;
5120            }
5121        },
5122
5123        /**
5124         * Get new step number
5125         */
5126        getNewStep: function() {
5127            return the.newStep;
5128        },
5129
5130        /**
5131         * Set new step
5132         */
5133        setNewStep: function(step) {
5134            the.newStep = step;
5135        },
5136
5137        /**
5138         * Trigger events
5139         */
5140        eventTrigger: function(name, nested) {
5141            //KTUtil.triggerCustomEvent(name);
5142            for (var i = 0; i < the.events.length; i++) {
5143                var event = the.events[i];
5144                if (event.name == name) {
5145                    if (event.one == true) {
5146                        if (event.fired == false) {
5147                            the.events[i].fired = true;
5148                            return event.handler.call(this, the);
5149                        }
5150                    } else {
5151                        return event.handler.call(this, the);
5152                    }
5153                }
5154            }
5155        },
5156
5157        addEvent: function(name, handler, one) {
5158            the.events.push({
5159                name: name,
5160                handler: handler,
5161                one: one,
5162                fired: false
5163            });
5164
5165            return the;
5166        }
5167    };
5168
5169    //////////////////////////
5170    // ** Public Methods ** //
5171    //////////////////////////
5172
5173    /**
5174     * Set default options
5175     */
5176
5177    the.setDefaults = function(options) {
5178        defaultOptions = options;
5179    };
5180
5181    /**
5182     * Go to the next step
5183     */
5184    the.goNext = function() {
5185        return Plugin.goTo(Plugin.getNextStep());
5186    };
5187
5188    /**
5189     * Go to the prev step
5190     */
5191    the.goPrev = function() {
5192        return Plugin.goTo(Plugin.getPrevStep());
5193    };
5194
5195    /**
5196     * Go to the last step
5197     */
5198    the.goLast = function() {
5199        return Plugin.goTo(Plugin.getLastStep());
5200    };
5201
5202    /**
5203     * Go to the first step
5204     */
5205    the.goFirst = function() {
5206        return Plugin.goTo(Plugin.getFirstStep());
5207    };
5208
5209    /**
5210     * Go to a step
5211     */
5212    the.goTo = function(number) {
5213        return Plugin.goTo(number);
5214    };
5215
5216    /**
5217     * Stop wizard
5218     */
5219    the.stop = function() {
5220        return Plugin.stop();
5221    };
5222
5223    /**
5224     * Resume wizard
5225     */
5226    the.resume = function() {
5227        return Plugin.resume();
5228    };
5229
5230    /**
5231     * Get current step number
5232     */
5233    the.getStep = function() {
5234        return the.currentStep;
5235    };
5236
5237    /**
5238     * Get new step number
5239     */
5240    the.getNewStep = function() {
5241        return Plugin.getNewStep();
5242    };
5243
5244    /**
5245     * Set new step number
5246     */
5247    the.setNewStep = function(number) {
5248        Plugin.setNewStep(number);
5249    };
5250
5251    /**
5252     * Check last step
5253     */
5254    the.isLastStep = function() {
5255        return Plugin.isLastStep();
5256    };
5257
5258    /**
5259     * Check first step
5260     */
5261    the.isFirstStep = function() {
5262        return Plugin.isFirstStep();
5263    };
5264
5265    /**
5266     * Attach event("change", "changed", "submit")
5267     */
5268    the.on = function(name, handler) {
5269        return Plugin.addEvent(name, handler);
5270    };
5271
5272    /**
5273     * Attach event that will be fired once
5274     */
5275    the.one = function(name, handler) {
5276        return Plugin.addEvent(name, handler, true);
5277    };
5278
5279    // Construct plugin
5280    Plugin.construct.apply(the, [options]);
5281
5282    return the;
5283};
5284
5285// webpack support
5286if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
5287    module.exports = KTWizard;
5288}
5289
5290'use strict';
5291(function($) {
5292
5293	var pluginName = 'KTDatatable';
5294	var pfx = '';
5295	var util = KTUtil;
5296	var app = KTApp;
5297
5298	if (typeof util === 'undefined') throw new Error('Util class is required and must be included before ' + pluginName);
5299
5300	// plugin setup
5301	$.fn[pluginName] = function(options) {
5302		if ($(this).length === 0) {
5303			console.warn('No ' + pluginName + ' element exist.');
5304			return;
5305		}
5306
5307		// global variables
5308		var datatable = this;
5309
5310		// debug enabled?
5311		// 1) state will be cleared on each refresh
5312		// 2) enable some logs
5313		// 3) etc.
5314		datatable.debug = false;
5315
5316		datatable.API = {
5317			record: null,
5318			value: null,
5319			params: null,
5320		};
5321
5322		var Plugin = {
5323			/********************
5324			 ** PRIVATE METHODS
5325			 ********************/
5326			isInit: false,
5327			cellOffset: 110,
5328			iconOffset: 15,
5329			stateId: 'meta',
5330			ajaxParams: {},
5331			pagingObject: {},
5332
5333			init: function(options) {
5334				var isHtmlTable = false;
5335				// data source option empty is normal table
5336				if (options.data.source === null) {
5337					Plugin.extractTable();
5338					isHtmlTable = true;
5339				}
5340
5341				Plugin.setupBaseDOM.call();
5342				Plugin.setupDOM(datatable.table);
5343
5344				// on event after layout had done setup, show datatable
5345				$(datatable).on(pfx + 'datatable-on-layout-updated', Plugin.afterRender);
5346
5347				if (datatable.debug) {
5348					Plugin.stateRemove(Plugin.stateId);
5349				}
5350
5351				/*var es = Plugin.stateGet(Plugin.stateId);
5352				var eq = {};
5353				if (es && es.hasOwnProperty('query')) {
5354					eq = es.query;
5355				}
5356				Plugin.setDataSourceQuery(Object.assign({}, eq, Plugin.getOption('data.source.read.params.query')));*/
5357
5358				// set custom query from options
5359				Plugin.setDataSourceQuery(Plugin.getOption('data.source.read.params.query'));
5360
5361				// initialize extensions
5362				$.each(Plugin.getOption('extensions'), function(extName, extOptions) {
5363					if (typeof $.fn[pluginName][extName] === 'function') {
5364						if (typeof extOptions !== 'object') {
5365							extOptions = $.extend({}, extOptions);
5366						}
5367						new $.fn[pluginName][extName](datatable, extOptions);
5368					}
5369				});
5370
5371				Plugin.spinnerCallback(true);
5372				// get data
5373				if (options.data.type === 'remote' || options.data.type === 'local') {
5374					if (options.data.saveState === false) {
5375						Plugin.stateRemove(Plugin.stateId);
5376					}
5377					// get data for local datatable and local table
5378					if (options.data.type === 'local' && typeof options.data.source === 'object') {
5379						datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(options.data.source);
5380					}
5381					Plugin.dataRender();
5382				}
5383
5384				// if html table, remove and setup a new header
5385				if (isHtmlTable) {
5386					$(datatable.tableHead).find('tr').remove();
5387					$(datatable.tableFoot).find('tr').remove();
5388				}
5389
5390				Plugin.setHeadTitle();
5391				if (Plugin.getOption('layout.footer')) {
5392					Plugin.setHeadTitle(datatable.tableFoot);
5393				}
5394
5395				// hide header
5396				if (typeof options.layout.header !== 'undefined' &&
5397					options.layout.header === false) {
5398					$(datatable.table).find('thead').remove();
5399				}
5400
5401				// hide footer
5402				if (typeof options.layout.footer !== 'undefined' &&
5403					options.layout.footer === false) {
5404					$(datatable.table).find('tfoot').remove();
5405				}
5406
5407				// for normal and local data type, run layoutUpdate
5408				if (options.data.type === null ||
5409					options.data.type === 'local') {
5410					Plugin.setupCellField.call();
5411					Plugin.setupTemplateCell.call();
5412
5413					// setup nested datatable, if option enabled
5414					Plugin.setupSubDatatable.call();
5415
5416					// setup extra system column properties
5417					Plugin.setupSystemColumn.call();
5418					Plugin.redraw();
5419				}
5420
5421				var width;
5422				var initialWidth = false;
5423				$(window).resize(function() {
5424					// issue: URL Bar Resizing on mobile, https://developers.google.com/web/updates/2016/12/url-bar-resizing
5425					// trigger datatable resize on width change only
5426					if ($(this).width() !== width) {
5427						width = $(this).width();
5428						Plugin.fullRender();
5429					}
5430					// get initial width
5431					if (!initialWidth) {
5432						width = $(this).width();
5433						initialWidth = true;
5434					}
5435				});
5436
5437				$(datatable).height('');
5438
5439				var prevKeyword = '';
5440				$(Plugin.getOption('search.input')).on('keyup', function(e) {
5441					if (Plugin.getOption('search.onEnter') && e.which !== 13) return;
5442					var keyword = $(this).val();
5443					// prevent multiple search request on every button keyup
5444					if (prevKeyword !== keyword) {
5445						Plugin.search(keyword);
5446						prevKeyword = keyword;
5447					}
5448				});
5449
5450				return datatable;
5451			},
5452
5453			/**
5454			 * Extract static HTML table content into datasource
5455			 */
5456			extractTable: function() {
5457				var columns = [];
5458				var headers = $(datatable).find('tr:first-child th').get().map(function(cell, i) {
5459					var field = $(cell).data('field');
5460					var title = $(cell).data('title');
5461					if (typeof field === 'undefined') {
5462						field = $(cell).text().trim();
5463					}
5464					if (typeof title === 'undefined') {
5465						title = $(cell).text().trim();
5466					}
5467					var column = {field: field, title: title};
5468					for (var ii in options.columns) {
5469						if (options.columns[ii].field === field) {
5470							column = $.extend(true, {}, options.columns[ii], column);
5471						}
5472					}
5473					columns.push(column);
5474					return field;
5475				});
5476				// auto create columns config
5477				options.columns = columns;
5478
5479				var rowProp = [];
5480				var source = [];
5481
5482				$(datatable).find('tr').each(function() {
5483					if ($(this).find('td').length) {
5484						rowProp.push($(this).prop('attributes'));
5485					}
5486					var td = {};
5487					$(this).find('td').each(function(i, cell) {
5488						td[headers[i]] = cell.innerHTML.trim();
5489					});
5490					if (!util.isEmpty(td)) {
5491						source.push(td);
5492					}
5493				});
5494
5495				options.data.attr.rowProps = rowProp;
5496				options.data.source = source;
5497			},
5498
5499			/**
5500			 * One time layout update on init
5501			 */
5502			layoutUpdate: function() {
5503				// setup nested datatable, if option enabled
5504				Plugin.setupSubDatatable.call();
5505
5506				// setup extra system column properties
5507				Plugin.setupSystemColumn.call();
5508
5509				// setup cell hover event
5510				Plugin.setupHover.call();
5511
5512				if (typeof options.detail === 'undefined'
5513					// temporary disable lock column in subtable
5514					&& Plugin.getDepth() === 1) {
5515					// lock columns handler
5516					Plugin.lockTable.call();
5517				}
5518
5519				Plugin.resetScroll();
5520
5521				// check if not is a locked column
5522				if (!Plugin.isLocked()) {
5523					Plugin.redraw.call();
5524					// check if its not a subtable and has autoHide option enabled
5525					if (!Plugin.isSubtable() && Plugin.getOption('rows.autoHide') === true) {
5526						Plugin.autoHide();
5527					}
5528					// reset row
5529					$(datatable.table).find('.' + pfx + 'datatable-row').css('height', '');
5530				}
5531
5532				Plugin.columnHide.call();
5533
5534				Plugin.rowEvenOdd.call();
5535
5536				Plugin.sorting.call();
5537
5538				Plugin.scrollbar.call();
5539
5540				if (!Plugin.isInit) {
5541					// run once dropdown inside datatable
5542					Plugin.dropdownFix();
5543					$(datatable).trigger(pfx + 'datatable-on-init', {table: $(datatable.wrap).attr('id'), options: options});
5544					Plugin.isInit = true;
5545				}
5546
5547				$(datatable).trigger(pfx + 'datatable-on-layout-updated', {table: $(datatable.wrap).attr('id')});
5548			},
5549
5550			dropdownFix: function() {
5551				var dropdownMenu;
5552				$('body').on('show.bs.dropdown', '.' + pfx + 'datatable .' + pfx + 'datatable-body', function(e) {
5553					dropdownMenu = $(e.target).find('.dropdown-menu');
5554					$('body').append(dropdownMenu.detach());
5555					// dropdownMenu.css('display', 'block');
5556					dropdownMenu.position({
5557						'my': 'right top',
5558						'at': 'right bottom',
5559						'of': $(e.relatedTarget),
5560					});
5561					// if datatable is inside modal
5562					if (datatable.closest('.modal').length) {
5563						// increase dropdown z-index
5564						dropdownMenu.css('z-index', '2000');
5565					}
5566				}).on('hide.bs.dropdown', '.' + pfx + 'datatable .' + pfx + 'datatable-body', function(e) {
5567					$(e.target).append(dropdownMenu.detach());
5568					dropdownMenu.hide();
5569				});
5570
5571				// remove dropdown if window resize
5572				$(window).on('resize', function(e) {
5573					if (typeof dropdownMenu !== 'undefined') {
5574						dropdownMenu.hide();
5575					}
5576				});
5577			},
5578
5579			lockTable: function() {
5580				var lock = {
5581					lockEnabled: false,
5582					init: function() {
5583						// check if table should be locked columns
5584						lock.lockEnabled = Plugin.lockEnabledColumns();
5585						if (lock.lockEnabled.left.length === 0 &&
5586							lock.lockEnabled.right.length === 0) {
5587							return;
5588						}
5589						lock.enable();
5590					},
5591					enable: function() {
5592						var enableLock = function(tablePart) {
5593							// check if already has lock column
5594							if ($(tablePart).find('.' + pfx + 'datatable-lock').length > 0) {
5595								Plugin.log('Locked container already exist in: ', tablePart);
5596								return;
5597							}
5598							// check if no rows exists
5599							if ($(tablePart).find('.' + pfx + 'datatable-row').length === 0) {
5600								Plugin.log('No row exist in: ', tablePart);
5601								return;
5602							}
5603
5604							// locked div container
5605							var lockLeft = $('<div/>').addClass(pfx + 'datatable-lock ' + pfx + 'datatable-lock-left');
5606							var lockScroll = $('<div/>').addClass(pfx + 'datatable-lock ' + pfx + 'datatable-lock-scroll');
5607							var lockRight = $('<div/>').addClass(pfx + 'datatable-lock ' + pfx + 'datatable-lock-right');
5608
5609							$(tablePart).find('.' + pfx + 'datatable-row').each(function() {
5610								// create new row for lock columns and pass the data
5611								var rowLeft = $('<tr/>').addClass(pfx + 'datatable-row').data('obj', $(this).data('obj')).appendTo(lockLeft);
5612								var rowScroll = $('<tr/>').addClass(pfx + 'datatable-row').data('obj', $(this).data('obj')).appendTo(lockScroll);
5613								var rowRight = $('<tr/>').addClass(pfx + 'datatable-row').data('obj', $(this).data('obj')).appendTo(lockRight);
5614								$(this).find('.' + pfx + 'datatable-cell').each(function() {
5615									var locked = $(this).data('locked');
5616									if (typeof locked !== 'undefined') {
5617										if (typeof locked.left !== 'undefined' || locked === true) {
5618											// default locked to left
5619											$(this).appendTo(rowLeft);
5620										}
5621										if (typeof locked.right !== 'undefined') {
5622											$(this).appendTo(rowRight);
5623										}
5624									} else {
5625										$(this).appendTo(rowScroll);
5626									}
5627								});
5628								// remove old row
5629								$(this).remove();
5630							});
5631
5632							if (lock.lockEnabled.left.length > 0) {
5633								$(datatable.wrap).addClass(pfx + 'datatable-lock');
5634								$(lockLeft).appendTo(tablePart);
5635							}
5636							if (lock.lockEnabled.left.length > 0 || lock.lockEnabled.right.length > 0) {
5637								$(lockScroll).appendTo(tablePart);
5638							}
5639							if (lock.lockEnabled.right.length > 0) {
5640								$(datatable.wrap).addClass(pfx + 'datatable-lock');
5641								$(lockRight).appendTo(tablePart);
5642							}
5643						};
5644
5645						$(datatable.table).find('thead,tbody,tfoot').each(function() {
5646							var tablePart = this;
5647							if ($(this).find('.' + pfx + 'datatable-lock').length === 0) {
5648								$(this).ready(function() {
5649									enableLock(tablePart);
5650								});
5651							}
5652						});
5653					},
5654				};
5655				lock.init();
5656				return lock;
5657			},
5658
5659			/**
5660			 * Render everything for resize
5661			 */
5662			fullRender: function() {
5663				$(datatable.tableHead).empty();
5664				Plugin.setHeadTitle();
5665				if (Plugin.getOption('layout.footer')) {
5666					$(datatable.tableFoot).empty();
5667					Plugin.setHeadTitle(datatable.tableFoot);
5668				}
5669
5670				Plugin.spinnerCallback(true);
5671				$(datatable.wrap).removeClass(pfx + 'datatable-loaded');
5672
5673				Plugin.insertData();
5674			},
5675
5676			lockEnabledColumns: function() {
5677				var screen = $(window).width();
5678				var columns = options.columns;
5679				var enabled = {left: [], right: []};
5680				$.each(columns, function(i, column) {
5681					if (typeof column.locked !== 'undefined') {
5682						if (typeof column.locked.left !== 'undefined') {
5683							if (util.getBreakpoint(column.locked.left) <= screen) {
5684								enabled['left'].push(column.locked.left);
5685							}
5686						}
5687						if (typeof column.locked.right !== 'undefined') {
5688							if (util.getBreakpoint(column.locked.right) <= screen) {
5689								enabled['right'].push(column.locked.right);
5690							}
5691						}
5692					}
5693				});
5694				return enabled;
5695			},
5696
5697			/**
5698			 * After render event, called by "datatable-on-layout-updated"
5699			 * @param e
5700			 * @param args
5701			 */
5702			afterRender: function(e, args) {
5703				$(datatable).ready(function() {
5704					// redraw locked columns table
5705					if (Plugin.isLocked()) {
5706						Plugin.redraw();
5707					}
5708
5709					$(datatable.tableBody).css('visibility', '');
5710					$(datatable.wrap).addClass(pfx + 'datatable-loaded');
5711
5712					Plugin.spinnerCallback(false);
5713				});
5714			},
5715
5716			hoverTimer: 0,
5717			isScrolling: false,
5718			setupHover: function() {
5719				$(window).scroll(function(e) {
5720					// stop hover when scrolling
5721					clearTimeout(Plugin.hoverTimer);
5722					Plugin.isScrolling = true;
5723				});
5724
5725				$(datatable.tableBody).find('.' + pfx + 'datatable-cell').off('mouseenter', 'mouseleave').on('mouseenter', function() {
5726					// reset scroll timer to hover class
5727					Plugin.hoverTimer = setTimeout(function() {
5728						Plugin.isScrolling = false;
5729					}, 200);
5730					if (Plugin.isScrolling) return;
5731
5732					// normal table
5733					var row = $(this).closest('.' + pfx + 'datatable-row').addClass(pfx + 'datatable-row-hover');
5734					var index = $(row).index() + 1;
5735
5736					// lock table
5737					$(row).closest('.' + pfx + 'datatable-lock').parent().find('.' + pfx + 'datatable-row:nth-child(' + index + ')').addClass(pfx + 'datatable-row-hover');
5738				}).on('mouseleave', function() {
5739					// normal table
5740					var row = $(this).closest('.' + pfx + 'datatable-row').removeClass(pfx + 'datatable-row-hover');
5741					var index = $(row).index() + 1;
5742
5743					// look table
5744					$(row).closest('.' + pfx + 'datatable-lock').parent().find('.' + pfx + 'datatable-row:nth-child(' + index + ')').removeClass(pfx + 'datatable-row-hover');
5745				});
5746			},
5747
5748			/**
5749			 * Adjust width of locked table containers by resize handler
5750			 * @returns {number}
5751			 */
5752			adjustLockContainer: function() {
5753				if (!Plugin.isLocked()) return 0;
5754
5755				// refer to head dimension
5756				var containerWidth = $(datatable.tableHead).width();
5757				var lockLeft = $(datatable.tableHead).find('.' + pfx + 'datatable-lock-left').width();
5758				var lockRight = $(datatable.tableHead).find('.' + pfx + 'datatable-lock-right').width();
5759
5760				if (typeof lockLeft === 'undefined') lockLeft = 0;
5761				if (typeof lockRight === 'undefined') lockRight = 0;
5762
5763				var lockScroll = Math.floor(containerWidth - lockLeft - lockRight);
5764				$(datatable.table).find('.' + pfx + 'datatable-lock-scroll').css('width', lockScroll);
5765
5766				return lockScroll;
5767			},
5768
5769			/**
5770			 * todo; not in use
5771			 */
5772			dragResize: function() {
5773				var pressed = false;
5774				var start = undefined;
5775				var startX, startWidth;
5776				$(datatable.tableHead).find('.' + pfx + 'datatable-cell').mousedown(function(e) {
5777					start = $(this);
5778					pressed = true;
5779					startX = e.pageX;
5780					startWidth = $(this).width();
5781					$(start).addClass(pfx + 'datatable-cell-resizing');
5782
5783				}).mousemove(function(e) {
5784					if (pressed) {
5785						var i = $(start).index();
5786						var tableBody = $(datatable.tableBody);
5787						var ifLocked = $(start).closest('.' + pfx + 'datatable-lock');
5788
5789						if (ifLocked) {
5790							var lockedIndex = $(ifLocked).index();
5791							tableBody = $(datatable.tableBody).find('.' + pfx + 'datatable-lock').eq(lockedIndex);
5792						}
5793
5794						$(tableBody).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
5795							$(tr).find('.' + pfx + 'datatable-cell').eq(i).width(startWidth + (e.pageX - startX)).children().width(startWidth + (e.pageX - startX));
5796						});
5797
5798						$(start).children().css('width', startWidth + (e.pageX - startX));
5799					}
5800
5801				}).mouseup(function() {
5802					$(start).removeClass(pfx + 'datatable-cell-resizing');
5803					pressed = false;
5804				});
5805
5806				$(document).mouseup(function() {
5807					$(start).removeClass(pfx + 'datatable-cell-resizing');
5808					pressed = false;
5809				});
5810			},
5811
5812			/**
5813			 * To prepare placeholder for table before content is loading
5814			 */
5815			initHeight: function() {
5816				if (options.layout.height && options.layout.scroll) {
5817					var theadHeight = $(datatable.tableHead).find('.' + pfx + 'datatable-row').outerHeight();
5818					var tfootHeight = $(datatable.tableFoot).find('.' + pfx + 'datatable-row').outerHeight();
5819					var bodyHeight = options.layout.height;
5820					if (theadHeight > 0) {
5821						bodyHeight -= theadHeight;
5822					}
5823					if (tfootHeight > 0) {
5824						bodyHeight -= tfootHeight;
5825					}
5826
5827					// scrollbar offset
5828					bodyHeight -= 2;
5829
5830					$(datatable.tableBody).css('max-height', Math.floor(parseFloat(bodyHeight)));
5831
5832					// set scrollable area fixed height
5833					// $(datatable.tableBody).find('.' + pfx + 'datatable-lock-scroll').css('height', Math.floor(parseFloat(bodyHeight)));
5834				}
5835			},
5836
5837			/**
5838			 * Setup base DOM (table, thead, tbody, tfoot) and create if not
5839			 * exist.
5840			 */
5841			setupBaseDOM: function() {
5842				// keep original state before datatable initialize
5843				datatable.initialDatatable = $(datatable).clone();
5844
5845				// main element
5846				if ($(datatable).prop('tagName') === 'TABLE') {
5847					// if main init element is <table>, wrap with div
5848					datatable.table = $(datatable).removeClass(pfx + 'datatable').addClass(pfx + 'datatable-table');
5849					if ($(datatable.table).parents('.' + pfx + 'datatable').length === 0) {
5850						datatable.table.wrap($('<div/>').addClass(pfx + 'datatable').addClass(pfx + 'datatable-' + options.layout.theme));
5851						datatable.wrap = $(datatable.table).parent();
5852					}
5853				} else {
5854					// create table
5855					datatable.wrap = $(datatable).addClass(pfx + 'datatable').addClass(pfx + 'datatable-' + options.layout.theme);
5856					datatable.table = $('<table/>').addClass(pfx + 'datatable-table').appendTo(datatable);
5857				}
5858
5859				if (typeof options.layout.class !== 'undefined') {
5860					$(datatable.wrap).addClass(options.layout.class);
5861				}
5862
5863				$(datatable.table).removeClass(pfx + 'datatable-destroyed').css('display', 'block');
5864
5865				// force disable save state
5866				if (typeof $(datatable).attr('id') === 'undefined') {
5867					Plugin.setOption('data.saveState', false);
5868					$(datatable.table).attr('id', util.getUniqueID(pfx + 'datatable-'));
5869				}
5870
5871				// predefine table height
5872				if (Plugin.getOption('layout.minHeight'))
5873					$(datatable.table).css('min-height', Plugin.getOption('layout.minHeight'));
5874
5875				if (Plugin.getOption('layout.height'))
5876					$(datatable.table).css('max-height', Plugin.getOption('layout.height'));
5877
5878				// for normal table load
5879				if (options.data.type === null) {
5880					$(datatable.table).css('width', '').css('display', '');
5881				}
5882
5883				// create table head element
5884				datatable.tableHead = $(datatable.table).find('thead');
5885				if ($(datatable.tableHead).length === 0) {
5886					datatable.tableHead = $('<thead/>').prependTo(datatable.table);
5887				}
5888
5889				// create table head element
5890				datatable.tableBody = $(datatable.table).find('tbody');
5891				if ($(datatable.tableBody).length === 0) {
5892					datatable.tableBody = $('<tbody/>').appendTo(datatable.table);
5893				}
5894
5895				if (typeof options.layout.footer !== 'undefined' &&
5896					options.layout.footer) {
5897					// create table foot element
5898					datatable.tableFoot = $(datatable.table).find('tfoot');
5899					if ($(datatable.tableFoot).length === 0) {
5900						datatable.tableFoot = $('<tfoot/>').appendTo(datatable.table);
5901					}
5902				}
5903			},
5904
5905			/**
5906			 * Set column data before table manipulation.
5907			 */
5908			setupCellField: function(tableParts) {
5909				if (typeof tableParts === 'undefined') tableParts = $(datatable.table).children();
5910				var columns = options.columns;
5911				$.each(tableParts, function(part, tablePart) {
5912					$(tablePart).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
5913						// prepare data
5914						$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
5915							if (typeof columns[tdi] !== 'undefined') {
5916								$(td).data(columns[tdi]);
5917							}
5918						});
5919					});
5920				});
5921			},
5922
5923			/**
5924			 * Set column template callback
5925			 * @param tablePart
5926			 */
5927			setupTemplateCell: function(tablePart) {
5928				if (typeof tablePart === 'undefined') tablePart = datatable.tableBody;
5929				var columns = options.columns;
5930				$(tablePart).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
5931					// row data object, if any
5932					var obj = $(tr).data('obj');
5933					if (typeof obj === 'undefined') {
5934						return;
5935					}
5936
5937					// @deprecated in v5.0.6
5938					// obj['getIndex'] = function() {
5939					// 	return tri;
5940					// };
5941					// @deprecated in v5.0.6
5942					// obj['getDatatable'] = function() {
5943					// 	return datatable;
5944					// };
5945
5946					// @deprecated in v5.0.6
5947					var rowCallback = Plugin.getOption('rows.callback');
5948					if (typeof rowCallback === 'function') {
5949						rowCallback($(tr), obj, tri);
5950					}
5951					// before template row callback
5952					var beforeTemplate = Plugin.getOption('rows.beforeTemplate');
5953					if (typeof beforeTemplate === 'function') {
5954						beforeTemplate($(tr), obj, tri);
5955					}
5956					// if data object is undefined, collect from table
5957					if (typeof obj === 'undefined') {
5958						obj = {};
5959						$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
5960							// get column settings by field
5961							var column = $.grep(columns, function(n, i) {
5962								return $(td).data('field') === n.field;
5963							})[0];
5964							if (typeof column !== 'undefined') {
5965								obj[column['field']] = $(td).text();
5966							}
5967						});
5968					}
5969
5970					$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
5971						// get column settings by field
5972						var column = $.grep(columns, function(n, i) {
5973							return $(td).data('field') === n.field;
5974						})[0];
5975						if (typeof column !== 'undefined') {
5976							// column template
5977							if (typeof column.template !== 'undefined') {
5978								var finalValue = '';
5979								// template string
5980								if (typeof column.template === 'string') {
5981									finalValue = Plugin.dataPlaceholder(column.template, obj);
5982								}
5983								// template callback function
5984								if (typeof column.template === 'function') {
5985									finalValue = column.template(obj, tri, datatable);
5986								}
5987
5988								// sanitize using DOMPurify if installed
5989								if (typeof DOMPurify !== 'undefined') {
5990									finalValue = DOMPurify.sanitize(finalValue);
5991								}
5992
5993								var span = document.createElement('span');
5994								span.innerHTML = finalValue;
5995
5996								// insert to cell, wrap with span
5997								$(td).html(span);
5998
5999								// set span overflow
6000								if (typeof column.overflow !== 'undefined') {
6001									$(span).css('overflow', column.overflow);
6002									$(span).css('position', 'relative');
6003								}
6004							}
6005						}
6006					});
6007
6008					// after template row callback
6009					var afterTemplate = Plugin.getOption('rows.afterTemplate');
6010					if (typeof afterTemplate === 'function') {
6011						afterTemplate($(tr), obj, tri);
6012					}
6013				});
6014			},
6015
6016			/**
6017			 * Setup extra system column properties
6018			 * Note: selector checkbox, subtable toggle
6019			 */
6020			setupSystemColumn: function() {
6021				datatable.dataSet = datatable.dataSet || [];
6022				// no records available
6023				if (datatable.dataSet.length === 0) return;
6024
6025				var columns = options.columns;
6026				$(datatable.tableBody).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
6027					$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
6028						// get column settings by field
6029						var column = $.grep(columns, function(n, i) {
6030							return $(td).data('field') === n.field;
6031						})[0];
6032						if (typeof column !== 'undefined') {
6033							var value = $(td).text();
6034
6035							// enable column selector
6036							if (typeof column.selector !== 'undefined' && column.selector !== false) {
6037								// check if checkbox exist
6038								if ($(td).find('.' + pfx + 'checkbox [type="checkbox"]').length > 0) return;
6039
6040								$(td).addClass(pfx + 'datatable-cell-check');
6041
6042								// append checkbox
6043								var chk = $('<label/>').
6044									addClass(pfx + 'checkbox ' + pfx + 'checkbox-single').
6045									append($('<input/>').attr('type', 'checkbox').attr('value', value).on('click', function() {
6046										if ($(this).is(':checked')) {
6047											// add checkbox active row class
6048											Plugin.setActive(this);
6049										} else {
6050											// add checkbox active row class
6051											Plugin.setInactive(this);
6052										}
6053									})).
6054									append('&nbsp;<span></span>');
6055
6056								// checkbox selector has outline style
6057								if (typeof column.selector.class !== 'undefined') {
6058									$(chk).addClass(column.selector.class);
6059								}
6060
6061								$(td).children().html(chk);
6062							}
6063
6064							// enable column subtable toggle
6065							if (typeof column.subtable !== 'undefined' && column.subtable) {
6066								// check if subtable toggle exist
6067								if ($(td).find('.' + pfx + 'datatable-toggle-subtable').length > 0) return;
6068								// append subtable toggle
6069								$(td).
6070									children().
6071									html($('<a/>').
6072										addClass(pfx + 'datatable-toggle-subtable').
6073										attr('href', '#').
6074										attr('data-value', value).
6075										append($('<i/>').addClass(Plugin.getOption('layout.icons.rowDetail.collapse'))));
6076							}
6077						}
6078					});
6079				});
6080
6081				// init checkbox for header/footer
6082				var initCheckbox = function(tr) {
6083					// get column settings by field
6084					var column = $.grep(columns, function(n, i) {
6085						return typeof n.selector !== 'undefined' && n.selector !== false;
6086					})[0];
6087
6088					if (typeof column !== 'undefined') {
6089						// enable column selector
6090						if (typeof column.selector !== 'undefined' && column.selector !== false) {
6091							var td = $(tr).find('[data-field="' + column.field + '"]');
6092							// check if checkbox exist
6093							if ($(td).find('.' + pfx + 'checkbox [type="checkbox"]').length > 0) return;
6094
6095							$(td).addClass(pfx + 'datatable-cell-check');
6096
6097							// append checkbox
6098							var chk = $('<label/>').
6099								addClass(pfx + 'checkbox ' + pfx + 'checkbox-single ' + pfx + 'checkbox-all').
6100								append($('<input/>').attr('type', 'checkbox').on('click', function() {
6101									if ($(this).is(':checked')) {
6102										Plugin.setActiveAll(true);
6103									} else {
6104										Plugin.setActiveAll(false);
6105									}
6106								})).
6107								append('&nbsp;<span></span>');
6108
6109							// checkbox selector has outline style
6110							if (typeof column.selector.class !== 'undefined') {
6111								$(chk).addClass(column.selector.class);
6112							}
6113
6114							$(td).children().html(chk);
6115						}
6116					}
6117				};
6118
6119				if (options.layout.header) {
6120					initCheckbox($(datatable.tableHead).find('.' + pfx + 'datatable-row').first());
6121				}
6122				if (options.layout.footer) {
6123					initCheckbox($(datatable.tableFoot).find('.' + pfx + 'datatable-row').first());
6124				}
6125			},
6126
6127			maxWidthList: {},
6128
6129			/**
6130			 * Adjust width to match container size
6131			 */
6132			adjustCellsWidth: function() {
6133				// get table width
6134				var containerWidth = $(datatable.tableBody).innerWidth() - Plugin.iconOffset;
6135
6136				// get total number of columns
6137				var columns = $(datatable.tableHead).
6138					find('.' + pfx + 'datatable-row:first-child').
6139					find('.' + pfx + 'datatable-cell').
6140					// exclude expand icon
6141					not('.' + pfx + 'datatable-toggle-detail').
6142					not(':hidden').length;
6143
6144				if (columns > 0) {
6145					//  remove reserved sort icon width
6146					containerWidth = containerWidth - (Plugin.iconOffset * columns);
6147					var minWidth = Math.floor(containerWidth / columns);
6148
6149					// minimum width
6150					if (minWidth <= Plugin.cellOffset) {
6151						minWidth = Plugin.cellOffset;
6152					}
6153
6154					$(datatable.table).find('.' + pfx + 'datatable-row').
6155							find('.' + pfx + 'datatable-cell').
6156							// exclude expand icon
6157							not('.' + pfx + 'datatable-toggle-detail').
6158							not(':hidden').each(function(tdi, td) {
6159
6160						var width = minWidth;
6161						var dataWidth = $(td).data('width');
6162
6163						if (typeof dataWidth !== 'undefined') {
6164							if (dataWidth === 'auto') {
6165								var field = $(td).data('field');
6166								if (Plugin.maxWidthList[field]) {
6167									width = Plugin.maxWidthList[field];
6168								}
6169								else {
6170									var cells = $(datatable.table).find('.' + pfx + 'datatable-cell[data-field="' + field + '"]');
6171									width = Plugin.maxWidthList[field] = Math.max.apply(null,
6172											$(cells).map(function() {
6173												return $(this).outerWidth();
6174											}).get());
6175								}
6176							}
6177							else {
6178								width = dataWidth;
6179							}
6180						}
6181						$(td).children().css('width', Math.ceil(width));
6182					});
6183				}
6184
6185				return datatable;
6186			},
6187
6188			/**
6189			 * Adjust height to match container size
6190			 */
6191			adjustCellsHeight: function() {
6192				$.each($(datatable.table).children(), function(part, tablePart) {
6193					var totalRows = $(tablePart).find('.' + pfx + 'datatable-row').first().parent().find('.' + pfx + 'datatable-row').length;
6194					for (var i = 1; i <= totalRows; i++) {
6195						var rows = $(tablePart).find('.' + pfx + 'datatable-row:nth-child(' + i + ')');
6196						if ($(rows).length > 0) {
6197							var maxHeight = Math.max.apply(null, $(rows).map(function() {
6198								return $(this).outerHeight();
6199							}).get());
6200							$(rows).css('height', Math.ceil(maxHeight));
6201						}
6202					}
6203				});
6204			},
6205
6206			/**
6207			 * Setup table DOM and classes
6208			 */
6209			setupDOM: function(table) {
6210				// set table classes
6211				$(table).find('> thead').addClass(pfx + 'datatable-head');
6212				$(table).find('> tbody').addClass(pfx + 'datatable-body');
6213				$(table).find('> tfoot').addClass(pfx + 'datatable-foot');
6214				$(table).find('tr').addClass(pfx + 'datatable-row');
6215				$(table).find('tr > th, tr > td').addClass(pfx + 'datatable-cell');
6216				$(table).find('tr > th, tr > td').each(function(i, td) {
6217					if ($(td).find('span').length === 0) {
6218						$(td).wrapInner($('<span/>').css('width', Plugin.cellOffset));
6219					}
6220				});
6221			},
6222
6223			/**
6224			 * Default scrollbar
6225			 * @returns {{tableLocked: null, init: init, onScrolling:
6226			 *     onScrolling}}
6227			 */
6228			scrollbar: function() {
6229				var scroll = {
6230					scrollable: null,
6231					tableLocked: null,
6232					initPosition: null,
6233					init: function() {
6234						var screen = util.getViewPort().width;
6235						// setup scrollable datatable
6236						if (options.layout.scroll) {
6237							// add scrollable datatable class
6238							$(datatable.wrap).addClass(pfx + 'datatable-scroll');
6239
6240							var scrollable = $(datatable.tableBody).find('.' + pfx + 'datatable-lock-scroll');
6241
6242							// check if scrollable area have rows
6243							if ($(scrollable).find('.' + pfx + 'datatable-row').length > 0 && $(scrollable).length > 0) {
6244								scroll.scrollHead = $(datatable.tableHead).find('> .' + pfx + 'datatable-lock-scroll > .' + pfx + 'datatable-row');
6245								scroll.scrollFoot = $(datatable.tableFoot).find('> .' + pfx + 'datatable-lock-scroll > .' + pfx + 'datatable-row');
6246								scroll.tableLocked = $(datatable.tableBody).find('.' + pfx + 'datatable-lock:not(.' + pfx + 'datatable-lock-scroll)');
6247								if (Plugin.getOption('layout.customScrollbar') && util.detectIE() != 10 && screen > util.getBreakpoint('lg')) {
6248									scroll.initCustomScrollbar(scrollable[0]);
6249								} else {
6250									scroll.initDefaultScrollbar(scrollable);
6251								}
6252							} else if ($(datatable.tableBody).find('.' + pfx + 'datatable-row').length > 0) {
6253								scroll.scrollHead = $(datatable.tableHead).find('> .' + pfx + 'datatable-row');
6254								scroll.scrollFoot = $(datatable.tableFoot).find('> .' + pfx + 'datatable-row');
6255								if (Plugin.getOption('layout.customScrollbar') && util.detectIE() != 10 && screen > util.getBreakpoint('lg')) {
6256									scroll.initCustomScrollbar(datatable.tableBody);
6257								} else {
6258									scroll.initDefaultScrollbar(datatable.tableBody);
6259								}
6260							}
6261						}
6262					},
6263					initDefaultScrollbar: function(scrollable) {
6264						// get initial scroll position
6265						scroll.initPosition = $(scrollable).scrollLeft();
6266						$(scrollable).css('overflow-y', 'auto').off().on('scroll', scroll.onScrolling);
6267						$(scrollable).css('overflow-x', 'auto');
6268					},
6269					onScrolling: function(e) {
6270						var left = $(this).scrollLeft();
6271						var top = $(this).scrollTop();
6272						if (util.isRTL()) {
6273							// deduct initial position for RTL
6274							left = left - scroll.initPosition;
6275						}
6276						$(scroll.scrollHead).css('left', -left);
6277						$(scroll.scrollFoot).css('left', -left);
6278						$(scroll.tableLocked).each(function(i, table) {
6279							if (Plugin.isLocked()) {
6280								// scrollbar offset
6281								top -= 1;
6282							}
6283							$(table).css('top', -top);
6284						});
6285					},
6286					initCustomScrollbar: function(scrollable) {
6287						scroll.scrollable = scrollable;
6288						// create a new instance for table body with scrollbar
6289						Plugin.initScrollbar(scrollable);
6290						// get initial scroll position
6291						scroll.initPosition = $(scrollable).scrollLeft();
6292						$(scrollable).off().on('scroll', scroll.onScrolling);
6293					},
6294				};
6295				scroll.init();
6296				return scroll;
6297			},
6298
6299			/**
6300			 * Init custom scrollbar and reset position
6301			 * @param element
6302			 * @param options
6303			 */
6304			initScrollbar: function(element, options) {
6305				if (!element || !element.nodeName) {
6306					return;
6307				}
6308				$(datatable.tableBody).css('overflow', '');
6309				var ps = $(element).data('ps');
6310				if (util.hasClass(element, 'ps') && typeof ps !== 'undefined') {
6311					ps.update();
6312				} else {
6313					ps = new PerfectScrollbar(element, Object.assign({}, {
6314						wheelSpeed: 0.5,
6315						swipeEasing: true,
6316						// wheelPropagation: false,
6317						minScrollbarLength: 40,
6318						maxScrollbarLength: 300,
6319						suppressScrollX: Plugin.getOption('rows.autoHide') && !Plugin.isLocked()
6320					}, options));
6321					$(element).data('ps', ps);
6322				}
6323
6324				// reset perfect scrollbar on resize
6325				$(window).resize(function() {
6326					ps.update();
6327				});
6328			},
6329
6330			/**
6331			 * Set column title from options.columns settings
6332			 */
6333			setHeadTitle: function(tablePart) {
6334				if (typeof tablePart === 'undefined') tablePart = datatable.tableHead;
6335				tablePart = $(tablePart)[0];
6336				var columns = options.columns;
6337				var row = tablePart.getElementsByTagName('tr')[0];
6338				var ths = tablePart.getElementsByTagName('td');
6339
6340				if (typeof row === 'undefined') {
6341					row = document.createElement('tr');
6342					tablePart.appendChild(row);
6343				}
6344
6345				$.each(columns, function(i, column) {
6346					var th = ths[i];
6347					if (typeof th === 'undefined') {
6348						th = document.createElement('th');
6349						row.appendChild(th);
6350					}
6351
6352					// set column title
6353					if (typeof column['title'] !== 'undefined') {
6354						th.innerHTML = column.title;
6355						th.setAttribute('data-field', column.field);
6356						util.addClass(th, column.class);
6357						// set disable autoHide or force enable
6358						if (typeof column.autoHide !== 'undefined') {
6359							if (column.autoHide !== true) {
6360								th.setAttribute('data-autohide-disabled', column.autoHide);
6361							} else {
6362								th.setAttribute('data-autohide-enabled', column.autoHide);
6363							}
6364						}
6365						$(th).data(column);
6366					}
6367
6368					// set header attr option
6369					if (typeof column.attr !== 'undefined') {
6370						$.each(column.attr, function(key, val) {
6371							th.setAttribute(key, val);
6372						});
6373					}
6374
6375					// apply text align to thead/tfoot
6376					if (typeof column.textAlign !== 'undefined') {
6377						var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : '';
6378						util.addClass(th, align);
6379					}
6380				});
6381				Plugin.setupDOM(tablePart);
6382			},
6383
6384			/**
6385			 * Initiate to get remote or local data via ajax
6386			 */
6387			dataRender: function(action) {
6388				$(datatable.table).siblings('.' + pfx + 'datatable-pager').removeClass(pfx + 'datatable-paging-loaded');
6389
6390				var buildMeta = function() {
6391					datatable.dataSet = datatable.dataSet || [];
6392					Plugin.localDataUpdate();
6393					// local pagination meta
6394					var meta = Plugin.getDataSourceParam('pagination');
6395					if (meta.perpage === 0) {
6396						meta.perpage = options.data.pageSize || 10;
6397					}
6398					meta.total = datatable.dataSet.length;
6399					var start = Math.max(meta.perpage * (meta.page - 1), 0);
6400					var end = Math.min(start + meta.perpage, meta.total);
6401					datatable.dataSet = $(datatable.dataSet).slice(start, end);
6402					return meta;
6403				};
6404
6405				var afterGetData = function(result) {
6406					var localPagingCallback = function(ctx, meta) {
6407						if (!$(ctx.pager).hasClass(pfx + 'datatable-paging-loaded')) {
6408							$(ctx.pager).remove();
6409							ctx.init(meta);
6410						}
6411						$(ctx.pager).off().on(pfx + 'datatable-on-goto-page', function(e) {
6412							$(ctx.pager).remove();
6413							ctx.init(meta);
6414						});
6415
6416						var start = Math.max(meta.perpage * (meta.page - 1), 0);
6417						var end = Math.min(start + meta.perpage, meta.total);
6418
6419						Plugin.localDataUpdate();
6420						datatable.dataSet = $(datatable.dataSet).slice(start, end);
6421
6422						// insert data into table content
6423						Plugin.insertData();
6424					};
6425
6426					$(datatable.wrap).removeClass(pfx + 'datatable-error');
6427					// pagination enabled
6428					if (options.pagination) {
6429						if (options.data.serverPaging && options.data.type !== 'local') {
6430							// server pagination
6431							var serverMeta = Plugin.getObject('meta', result || null);
6432							if (serverMeta !== null) {
6433								Plugin.pagingObject = Plugin.paging(serverMeta);
6434							} else {
6435								// no meta object from server response, fallback to local pagination
6436								Plugin.pagingObject = Plugin.paging(buildMeta(), localPagingCallback);
6437							}
6438						} else {
6439							// local pagination can be used by remote data also
6440							Plugin.pagingObject = Plugin.paging(buildMeta(), localPagingCallback);
6441						}
6442					} else {
6443						// pagination is disabled
6444						Plugin.localDataUpdate();
6445					}
6446					// insert data into table content
6447					Plugin.insertData();
6448				};
6449
6450				// get local datasource
6451				if (options.data.type === 'local'
6452					// for remote json datasource
6453					// || typeof options.data.source.read === 'undefined' && datatable.dataSet !== null
6454					// for remote datasource, server sorting is disabled and data already received from remote
6455					|| options.data.serverSorting === false && action === 'sort'
6456					|| options.data.serverFiltering === false && action === 'search'
6457				) {
6458					setTimeout(function() {
6459						Plugin.setAutoColumns();
6460						afterGetData();
6461					});
6462					return;
6463				}
6464
6465				// getting data from remote only
6466				Plugin.getData().done(afterGetData);
6467			},
6468
6469			/**
6470			 * Process ajax data
6471			 */
6472			insertData: function() {
6473				datatable.dataSet = datatable.dataSet || [];
6474				var params = Plugin.getDataSourceParam();
6475
6476				// get row attributes
6477				var pagination = params.pagination;
6478				var start = (Math.max(pagination.page, 1) - 1) * pagination.perpage;
6479				var end = Math.min(pagination.page, pagination.pages) * pagination.perpage;
6480				var rowProps = {};
6481				if (typeof options.data.attr.rowProps !== 'undefined' && options.data.attr.rowProps.length) {
6482					rowProps = options.data.attr.rowProps.slice(start, end);
6483				}
6484
6485				var tableBody = document.createElement('tbody');
6486				tableBody.style.visibility = 'hidden';
6487				var colLength = options.columns.length;
6488
6489				$.each(datatable.dataSet, function(rowIndex, row) {
6490					var tr = document.createElement('tr');
6491					tr.setAttribute('data-row', rowIndex);
6492					// keep data object to row
6493					$(tr).data('obj', row);
6494
6495					if (typeof rowProps[rowIndex] !== 'undefined') {
6496						$.each(rowProps[rowIndex], function() {
6497							tr.setAttribute(this.name, this.value);
6498						});
6499					}
6500
6501					var cellIndex = 0;
6502					var tds = [];
6503					for (var a = 0; a < colLength; a += 1) {
6504						var column = options.columns[a];
6505						var classes = [];
6506						// add sorted class to cells
6507						if (Plugin.getObject('sort.field', params) === column.field) {
6508							classes.push(pfx + 'datatable-cell-sorted');
6509						}
6510
6511						// apply text align
6512						if (typeof column.textAlign !== 'undefined') {
6513							var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : '';
6514							classes.push(align);
6515						}
6516
6517						// var classAttr = '';
6518						if (typeof column.class !== 'undefined') {
6519							classes.push(column.class);
6520						}
6521
6522						var td = document.createElement('td');
6523						util.addClass(td, classes.join(' '));
6524						td.setAttribute('data-field', column.field);
6525						// set disable autoHide or force enable
6526						if (typeof column.autoHide !== 'undefined') {
6527							if (column.autoHide !== true) {
6528								td.setAttribute('data-autohide-disabled', column.autoHide);
6529							} else {
6530								td.setAttribute('data-autohide-enabled', column.autoHide);
6531							}
6532						}
6533						td.innerHTML = Plugin.getObject(column.field, row);
6534						td.setAttribute('aria-label', Plugin.getObject(column.field, row));
6535						tr.appendChild(td);
6536					}
6537
6538					tableBody.appendChild(tr);
6539				});
6540
6541				// display no records message
6542				if (datatable.dataSet.length === 0) {
6543					var errorSpan = document.createElement('span');
6544					util.addClass(errorSpan, pfx + 'datatable-error');
6545					errorSpan.innerHTML = Plugin.getOption('translate.records.noRecords');
6546					tableBody.appendChild(errorSpan);
6547					$(datatable.wrap).addClass(pfx + 'datatable-error ' + pfx + 'datatable-loaded');
6548					Plugin.spinnerCallback(false);
6549				}
6550
6551				// replace existing table body
6552				$(datatable.tableBody).replaceWith(tableBody);
6553				datatable.tableBody = tableBody;
6554
6555				// layout update
6556				Plugin.setupDOM(datatable.table);
6557				Plugin.setupCellField([datatable.tableBody]);
6558				Plugin.setupTemplateCell(datatable.tableBody);
6559				Plugin.layoutUpdate();
6560			},
6561
6562			updateTableComponents: function() {
6563				datatable.tableHead = $(datatable.table).children('thead').get(0);
6564				datatable.tableBody = $(datatable.table).children('tbody').get(0);
6565				datatable.tableFoot = $(datatable.table).children('tfoot').get(0);
6566			},
6567
6568			/**
6569			 * Call ajax for raw JSON data
6570			 */
6571			getData: function() {
6572				// Plugin.spinnerCallback(true);
6573
6574				var ajaxParams = {
6575					dataType: 'json',
6576					method: 'POST',
6577					data: {},
6578					timeout: Plugin.getOption('data.source.read.timeout') || 30000,
6579				};
6580
6581				if (options.data.type === 'local') {
6582					ajaxParams.url = options.data.source;
6583				}
6584
6585				if (options.data.type === 'remote') {
6586					var data = Plugin.getDataSourceParam();
6587					// remove if server params is not enabled
6588					if (!Plugin.getOption('data.serverPaging')) {
6589						delete data['pagination'];
6590					}
6591					if (!Plugin.getOption('data.serverSorting')) {
6592						delete data['sort'];
6593					}
6594					ajaxParams.data = $.extend({}, ajaxParams.data, Plugin.getOption('data.source.read.params'), data);
6595					ajaxParams = $.extend({}, ajaxParams, Plugin.getOption('data.source.read'));
6596
6597					if (typeof ajaxParams.url !== 'string') ajaxParams.url = Plugin.getOption('data.source.read');
6598					if (typeof ajaxParams.url !== 'string') ajaxParams.url = Plugin.getOption('data.source');
6599					// ajaxParams.data = $.extend(ajaxParams.data, data.pagination);
6600				}
6601
6602				return $.ajax(ajaxParams).done(function(response, textStatus, jqXHR) {
6603					datatable.lastResponse = response;
6604					// extendible data map callback for custom datasource
6605					datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(response);
6606					Plugin.setAutoColumns();
6607					$(datatable).trigger(pfx + 'datatable-on-ajax-done', [datatable.dataSet]);
6608				}).fail(function(jqXHR, textStatus, errorThrown) {
6609					$(datatable).trigger(pfx + 'datatable-on-ajax-fail', [jqXHR]);
6610					$(datatable.tableBody).html($('<span/>').addClass(pfx + 'datatable-error').html(Plugin.getOption('translate.records.noRecords')));
6611					$(datatable.wrap).addClass(pfx + 'datatable-error ' + pfx + 'datatable-loaded');
6612					Plugin.spinnerCallback(false);
6613				}).always(function() {
6614				});
6615			},
6616
6617			/**
6618			 * Pagination object
6619			 * @param meta if null, local pagination, otherwise remote
6620			 *     pagination
6621			 * @param callback for update data when navigating page
6622			 */
6623			paging: function(meta, callback) {
6624				var pg = {
6625					meta: null,
6626					pager: null,
6627					paginateEvent: null,
6628					pagerLayout: {pagination: null, info: null},
6629					callback: null,
6630					init: function(meta) {
6631						pg.meta = meta;
6632
6633						// parse pagination meta to integer
6634						pg.meta.page = parseInt(pg.meta.page);
6635						pg.meta.pages = parseInt(pg.meta.pages);
6636						pg.meta.perpage = parseInt(pg.meta.perpage);
6637						pg.meta.total = parseInt(pg.meta.total);
6638
6639						// always recount total pages
6640						pg.meta.pages = Math.max(Math.ceil(pg.meta.total / pg.meta.perpage), 1);
6641
6642						// current page must be not over than total pages
6643						if (pg.meta.page > pg.meta.pages) pg.meta.page = pg.meta.pages;
6644
6645						// set unique event name between tables
6646						pg.paginateEvent = Plugin.getTablePrefix('paging');
6647
6648						pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable-pager');
6649						if ($(pg.pager).hasClass(pfx + 'datatable-paging-loaded')) return;
6650
6651						// if class .'+pfx+'datatable-paging-loaded not exist, recreate pagination
6652						$(pg.pager).remove();
6653
6654						// if no pages available
6655						if (pg.meta.pages === 0) return;
6656
6657						// update datasource params
6658						Plugin.setDataSourceParam('pagination', {
6659							page: pg.meta.page,
6660							pages: pg.meta.pages,
6661							perpage: pg.meta.perpage,
6662							total: pg.meta.total,
6663						});
6664
6665						// default callback function, contains remote pagination handler
6666						pg.callback = pg.serverCallback;
6667						// custom callback function
6668						if (typeof callback === 'function') pg.callback = callback;
6669
6670						pg.addPaginateEvent();
6671						pg.populate();
6672
6673						pg.meta.page = Math.max(pg.meta.page || 1, pg.meta.page);
6674
6675						$(datatable).trigger(pg.paginateEvent, pg.meta);
6676
6677						pg.pagingBreakpoint.call();
6678						$(window).resize(pg.pagingBreakpoint);
6679					},
6680					serverCallback: function(ctx, meta) {
6681						Plugin.dataRender();
6682					},
6683					populate: function() {
6684						datatable.dataSet = datatable.dataSet || [];
6685						// no records available
6686						if (datatable.dataSet.length === 0) return;
6687
6688						var icons = Plugin.getOption('layout.icons.pagination');
6689						var title = Plugin.getOption('translate.toolbar.pagination.items.default');
6690						// pager root element
6691						pg.pager = $('<div/>').addClass(pfx + 'datatable-pager ' + pfx + 'datatable-paging-loaded');
6692						// numbering links
6693						var pagerNumber = $('<ul/>').addClass(pfx + 'datatable-pager-nav my-2 mb-sm-0');
6694						pg.pagerLayout['pagination'] = pagerNumber;
6695
6696						// pager first/previous button
6697						$('<li/>').
6698							append($('<a/>').
6699								attr('title', title.first).
6700								addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-first').
6701								append($('<i/>').addClass(icons.first)).
6702								on('click', pg.gotoMorePage).
6703								attr('data-page', 1)).
6704							appendTo(pagerNumber);
6705						$('<li/>').
6706							append($('<a/>').
6707								attr('title', title.prev).
6708								addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-prev').
6709								append($('<i/>').addClass(icons.prev)).
6710								on('click', pg.gotoMorePage)).
6711							appendTo(pagerNumber);
6712
6713						$('<li/>').append($('<input/>').attr('type', 'text').addClass(pfx + 'datatable-pager-input form-control').attr('title', title.input).on('keyup', function() {
6714							// on keyup update [data-page]
6715							$(this).attr('data-page', Math.abs($(this).val()));
6716						}).on('keypress', function(e) {
6717							// on keypressed enter button
6718							if (e.which === 13) pg.gotoMorePage(e);
6719						})).appendTo(pagerNumber);
6720
6721						var pagesNumber = Plugin.getOption('toolbar.items.pagination.pages.desktop.pagesNumber');
6722						var end = Math.ceil(pg.meta.page / pagesNumber) * pagesNumber;
6723						var start = end - pagesNumber;
6724						if (end > pg.meta.pages) {
6725							end = pg.meta.pages;
6726						}
6727
6728						// keep pagination 1 if there is no records
6729						if (start < 0) {
6730							start = 0;
6731						}
6732
6733						for (var x = start; x < (end || 1); x++) {
6734							var pageNumber = x + 1;
6735							$('<li/>').
6736								append($('<a/>').
6737									addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-number').
6738									text(pageNumber).
6739									attr('data-page', pageNumber).
6740									attr('title', pageNumber).
6741									on('click', pg.gotoPage)).
6742								appendTo(pagerNumber);
6743						}
6744
6745						// pager next/last button
6746						$('<li/>').
6747							append($('<a/>').
6748								attr('title', title.next).
6749								addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-next').
6750								append($('<i/>').addClass(icons.next)).
6751								on('click', pg.gotoMorePage)).
6752							appendTo(pagerNumber);
6753						$('<li/>').
6754							append($('<a/>').
6755								attr('title', title.last).
6756								addClass(pfx + 'datatable-pager-link ' + pfx + 'datatable-pager-link-last').
6757								append($('<i/>').addClass(icons.last)).
6758								on('click', pg.gotoMorePage).
6759								attr('data-page', pg.meta.pages)).
6760							appendTo(pagerNumber);
6761
6762						// page info
6763						if (Plugin.getOption('toolbar.items.info')) {
6764							pg.pagerLayout['info'] = $('<div/>').addClass(pfx + 'datatable-pager-info my-2 mb-sm-0').append($('<span/>').addClass(pfx + 'datatable-pager-detail'));
6765						}
6766
6767						$.each(Plugin.getOption('toolbar.layout'), function(i, layout) {
6768							$(pg.pagerLayout[layout]).appendTo(pg.pager);
6769						});
6770
6771						// page size select
6772						var pageSizeSelect = $('<select/>').
6773							addClass('selectpicker ' + pfx + 'datatable-pager-size').
6774							attr('title', Plugin.getOption('translate.toolbar.pagination.items.default.select')).
6775							attr('data-width', '60px').
6776							attr('data-container', 'body').
6777							val(pg.meta.perpage).
6778							on('change', pg.updatePerpage).
6779							prependTo(pg.pagerLayout['info']);
6780
6781						var pageSizes = Plugin.getOption('toolbar.items.pagination.pageSizeSelect');
6782						// default value here, to fix override option by user
6783						if (pageSizes.length == 0) pageSizes = [5, 10, 20, 30, 50, 100];
6784						$.each(pageSizes, function(i, size) {
6785							var display = size;
6786							if (size === -1) display = Plugin.getOption('translate.toolbar.pagination.items.default.all');
6787							$('<option/>').attr('value', size).html(display).appendTo(pageSizeSelect);
6788						});
6789
6790						// init selectpicker to dropdown
6791						$(datatable).ready(function() {
6792							$('.selectpicker').
6793								selectpicker().
6794								on('hide.bs.select', function() {
6795									// fix dropup arrow icon on hide
6796									$(this).closest('.bootstrap-select').removeClass('dropup');
6797								}).
6798								siblings('.dropdown-toggle').
6799								attr('title', Plugin.getOption('translate.toolbar.pagination.items.default.select'));
6800						});
6801
6802						pg.paste();
6803					},
6804					paste: function() {
6805						// insert pagination based on placement position, top|bottom
6806						$.each($.unique(Plugin.getOption('toolbar.placement')),
6807							function(i, position) {
6808								if (position === 'bottom') {
6809									$(pg.pager).clone(true).insertAfter(datatable.table);
6810								}
6811								if (position === 'top') {
6812									// pager top need some extra space
6813									$(pg.pager).clone(true).addClass(pfx + 'datatable-pager-top').insertBefore(datatable.table);
6814								}
6815							});
6816					},
6817					gotoMorePage: function(e) {
6818						e.preventDefault();
6819						// $(this) is a link of .'+pfx+'datatable-pager-link
6820
6821						if ($(this).attr('disabled') === 'disabled') return false;
6822
6823						var page = $(this).attr('data-page');
6824
6825						// event from text input
6826						if (typeof page === 'undefined') {
6827							page = $(e.target).attr('data-page');
6828						}
6829
6830						pg.openPage(parseInt(page));
6831						return false;
6832					},
6833					gotoPage: function(e) {
6834						e.preventDefault();
6835						// prevent from click same page number
6836						if ($(this).hasClass(pfx + 'datatable-pager-link-active')) return;
6837
6838						pg.openPage(parseInt($(this).data('page')));
6839					},
6840					openPage: function(page) {
6841						// currentPage is 1-based index
6842						pg.meta.page = parseInt(page);
6843
6844						$(datatable).trigger(pg.paginateEvent, pg.meta);
6845						pg.callback(pg, pg.meta);
6846
6847						// update page callback function
6848						$(pg.pager).trigger(pfx + 'datatable-on-goto-page', pg.meta);
6849					},
6850					updatePerpage: function(e) {
6851						e.preventDefault();
6852						// if (Plugin.getOption('layout.height') === null) {
6853						// fix white space, when perpage is set from many records to less records
6854						// $('html, body').animate({scrollTop: $(datatable).position().top});
6855						// }
6856
6857						// hide dropdown after select
6858						$(this).selectpicker('toggle');
6859
6860						pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable-pager').removeClass(pfx + 'datatable-paging-loaded');
6861
6862						// on change select page size
6863						if (e.originalEvent) {
6864							pg.meta.perpage = parseInt($(this).val());
6865						}
6866
6867						$(pg.pager).find('select.' + pfx + 'datatable-pager-size').val(pg.meta.perpage).attr('data-selected', pg.meta.perpage);
6868
6869						// update datasource params
6870						Plugin.setDataSourceParam('pagination', {
6871							page: pg.meta.page,
6872							pages: pg.meta.pages,
6873							perpage: pg.meta.perpage,
6874							total: pg.meta.total,
6875						});
6876
6877						// update page callback function
6878						$(pg.pager).trigger(pfx + 'datatable-on-update-perpage', pg.meta);
6879						$(datatable).trigger(pg.paginateEvent, pg.meta);
6880						pg.callback(pg, pg.meta);
6881
6882						// update pagination info
6883						pg.updateInfo.call();
6884					},
6885					addPaginateEvent: function(e) {
6886						// pagination event
6887						$(datatable).off(pg.paginateEvent).on(pg.paginateEvent, function(e, meta) {
6888							Plugin.spinnerCallback(true);
6889
6890							pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable-pager');
6891							var pagerNumber = $(pg.pager).find('.' + pfx + 'datatable-pager-nav');
6892
6893							// set sync active page class
6894							$(pagerNumber).find('.' + pfx + 'datatable-pager-link-active').removeClass(pfx + 'datatable-pager-link-active');
6895							$(pagerNumber).find('.' + pfx + 'datatable-pager-link-number[data-page="' + meta.page + '"]').addClass(pfx + 'datatable-pager-link-active');
6896
6897							// set next and previous link page number
6898							$(pagerNumber).find('.' + pfx + 'datatable-pager-link-prev').attr('data-page', Math.max(meta.page - 1, 1));
6899							$(pagerNumber).find('.' + pfx + 'datatable-pager-link-next').attr('data-page', Math.min(meta.page + 1, meta.pages));
6900
6901							// current page input value sync
6902							$(pg.pager).each(function() {
6903								$(this).find('.' + pfx + 'datatable-pager-input[type="text"]').prop('value', meta.page);
6904							});
6905
6906							// if only 1 page, should hide page?
6907							// $(pg.pager).find('.' + pfx + 'datatable-pager-nav').show();
6908							// if (meta.pages <= 1) {
6909							// 	// hide pager if has 1 page
6910							// 	$(pg.pager).find('.' + pfx + 'datatable-pager-nav').hide();
6911							// }
6912
6913							// update datasource params
6914							Plugin.setDataSourceParam('pagination', {
6915								page: pg.meta.page,
6916								pages: pg.meta.pages,
6917								perpage: pg.meta.perpage,
6918								total: pg.meta.total,
6919							});
6920
6921							$(pg.pager).find('select.' + pfx + 'datatable-pager-size').val(meta.perpage).attr('data-selected', meta.perpage);
6922
6923							// clear active rows
6924							$(datatable.table).find('.' + pfx + 'checkbox > [type="checkbox"]').prop('checked', false);
6925							$(datatable.table).find('.' + pfx + 'datatable-row-active').removeClass(pfx + 'datatable-row-active');
6926
6927							pg.updateInfo.call();
6928							pg.pagingBreakpoint.call();
6929							// Plugin.resetScroll();
6930						});
6931					},
6932					updateInfo: function() {
6933						var start = Math.max(pg.meta.perpage * (pg.meta.page - 1) + 1, 1);
6934						var end = Math.min(start + pg.meta.perpage - 1, pg.meta.total);
6935						// page info update
6936						$(pg.pager).find('.' + pfx + 'datatable-pager-info').find('.' + pfx + 'datatable-pager-detail').html(Plugin.dataPlaceholder(
6937							Plugin.getOption('translate.toolbar.pagination.items.info'), {
6938								// set start page 0 if the is no records. eg. Showing 0 - 0 of 0
6939								start: pg.meta.total === 0 ? 0 : start,
6940								end: pg.meta.perpage === -1 ? pg.meta.total : end,
6941								pageSize: pg.meta.perpage === -1 ||
6942								pg.meta.perpage >= pg.meta.total
6943									? pg.meta.total
6944									: pg.meta.perpage,
6945								total: pg.meta.total,
6946							}));
6947					},
6948
6949					/**
6950					 * Update pagination layout breakpoint
6951					 */
6952					pagingBreakpoint: function() {
6953						// keep page links reference
6954						var pagerNumber = $(datatable.table).siblings('.' + pfx + 'datatable-pager').find('.' + pfx + 'datatable-pager-nav');
6955						if ($(pagerNumber).length === 0) return;
6956
6957						var currentPage = Plugin.getCurrentPage();
6958						var pagerInput = $(pagerNumber).find('.' + pfx + 'datatable-pager-input').closest('li');
6959
6960						// reset
6961						$(pagerNumber).find('li').show();
6962
6963						// pagination update
6964						$.each(Plugin.getOption('toolbar.items.pagination.pages'),
6965							function(mode, option) {
6966								if (util.isInResponsiveRange(mode)) {
6967									switch (mode) {
6968										case 'desktop':
6969										case 'tablet':
6970											var end = Math.ceil(currentPage / option.pagesNumber) * option.pagesNumber;
6971											var start = end - option.pagesNumber;
6972											$(pagerInput).hide();
6973											pg.meta = Plugin.getDataSourceParam('pagination');
6974											pg.paginationUpdate();
6975											break;
6976
6977										case 'mobile':
6978											$(pagerInput).show();
6979											$(pagerNumber).find('.' + pfx + 'datatable-pager-link-more-prev').closest('li').hide();
6980											$(pagerNumber).find('.' + pfx + 'datatable-pager-link-more-next').closest('li').hide();
6981											$(pagerNumber).find('.' + pfx + 'datatable-pager-link-number').closest('li').hide();
6982											break;
6983									}
6984
6985									return false;
6986								}
6987							});
6988					},
6989
6990					/**
6991					 * Update pagination number and button display
6992					 */
6993					paginationUpdate: function() {
6994						var pager = $(datatable.table).siblings('.' + pfx + 'datatable-pager').find('.' + pfx + 'datatable-pager-nav'),
6995							pagerMorePrev = $(pager).find('.' + pfx + 'datatable-pager-link-more-prev'),
6996							pagerMoreNext = $(pager).find('.' + pfx + 'datatable-pager-link-more-next'),
6997							pagerFirst = $(pager).find('.' + pfx + 'datatable-pager-link-first'),
6998							pagerPrev = $(pager).find('.' + pfx + 'datatable-pager-link-prev'),
6999							pagerNext = $(pager).find('.' + pfx + 'datatable-pager-link-next'),
7000							pagerLast = $(pager).find('.' + pfx + 'datatable-pager-link-last');
7001
7002						// get visible page
7003						var pagerNumber = $(pager).find('.' + pfx + 'datatable-pager-link-number');
7004						// get page before of first visible
7005						var morePrevPage = Math.max($(pagerNumber).first().data('page') - 1, 1);
7006						$(pagerMorePrev).each(function(i, prev) {
7007							$(prev).attr('data-page', morePrevPage);
7008						});
7009						// show/hide <li>
7010						if (morePrevPage === 1) {
7011							$(pagerMorePrev).parent().hide();
7012						} else {
7013							$(pagerMorePrev).parent().show();
7014						}
7015
7016						// get page after of last visible
7017						var moreNextPage = Math.min($(pagerNumber).last().data('page') + 1,
7018							pg.meta.pages);
7019						$(pagerMoreNext).each(function(i, prev) {
7020							$(pagerMoreNext).attr('data-page', moreNextPage).show();
7021						});
7022
7023						// show/hide <li>
7024						if (moreNextPage === pg.meta.pages
7025							// missing dot fix when last hidden page is one left
7026							&& moreNextPage === $(pagerNumber).last().data('page')) {
7027							$(pagerMoreNext).parent().hide();
7028						} else {
7029							$(pagerMoreNext).parent().show();
7030						}
7031
7032						// begin/end of pages
7033						if (pg.meta.page === 1) {
7034							$(pagerFirst).attr('disabled', true).addClass(pfx + 'datatable-pager-link-disabled');
7035							$(pagerPrev).attr('disabled', true).addClass(pfx + 'datatable-pager-link-disabled');
7036						} else {
7037							$(pagerFirst).removeAttr('disabled').removeClass(pfx + 'datatable-pager-link-disabled');
7038							$(pagerPrev).removeAttr('disabled').removeClass(pfx + 'datatable-pager-link-disabled');
7039						}
7040						if (pg.meta.page === pg.meta.pages) {
7041							$(pagerNext).attr('disabled', true).addClass(pfx + 'datatable-pager-link-disabled');
7042							$(pagerLast).attr('disabled', true).addClass(pfx + 'datatable-pager-link-disabled');
7043						} else {
7044							$(pagerNext).removeAttr('disabled').removeClass(pfx + 'datatable-pager-link-disabled');
7045							$(pagerLast).removeAttr('disabled').removeClass(pfx + 'datatable-pager-link-disabled');
7046						}
7047
7048						// display more buttons
7049						var nav = Plugin.getOption('toolbar.items.pagination.navigation');
7050						if (!nav.first) $(pagerFirst).remove();
7051						if (!nav.prev) $(pagerPrev).remove();
7052						if (!nav.next) $(pagerNext).remove();
7053						if (!nav.last) $(pagerLast).remove();
7054						if (!nav.more) {
7055							$(pagerMorePrev).remove();
7056							$(pagerMoreNext).remove();
7057						}
7058					},
7059				};
7060				pg.init(meta);
7061				return pg;
7062			},
7063
7064			/**
7065			 * Hide/show table cell defined by
7066			 * options[columns][i][responsive][visible/hidden]
7067			 */
7068			columnHide: function() {
7069				var screen = util.getViewPort().width;
7070				// foreach columns setting
7071				$.each(options.columns, function(i, column) {
7072					if (typeof column.responsive !== 'undefined' || typeof column.visible !== 'undefined') {
7073						var field = column.field;
7074						var tds = $.grep($(datatable.table).find('.' + pfx + 'datatable-cell'), function(n, i) {
7075							return field === $(n).data('field');
7076						});
7077
7078						setTimeout(function () {
7079							// hide by force
7080							if (Plugin.getObject('visible', column) === false) {
7081								$(tds).hide();
7082							} else {
7083								// show/hide by responsive breakpoint
7084								if (util.getBreakpoint(Plugin.getObject('responsive.hidden', column)) >= screen) {
7085									$(tds).hide();
7086								} else {
7087									$(tds).show();
7088								}
7089								if (util.getBreakpoint(Plugin.getObject('responsive.visible', column)) <= screen) {
7090									$(tds).show();
7091								} else {
7092									$(tds).hide();
7093								}
7094							}
7095						});
7096					}
7097				});
7098			},
7099
7100			/**
7101			 * Setup sub datatable
7102			 */
7103			setupSubDatatable: function() {
7104				var subTableCallback = Plugin.getOption('detail.content');
7105				if (typeof subTableCallback !== 'function') return;
7106
7107				// subtable already exist
7108				if ($(datatable.table).find('.' + pfx + 'datatable-subtable').length > 0) return;
7109
7110				$(datatable.wrap).addClass(pfx + 'datatable-subtable');
7111
7112				options.columns[0]['subtable'] = true;
7113
7114				// toggle on open sub table
7115				var toggleSubTable = function(e) {
7116					e.preventDefault();
7117					// get parent row of this subtable
7118					var parentRow = $(this).closest('.' + pfx + 'datatable-row');
7119
7120					// get subtable row for sub table
7121					var subTableRow = $(parentRow).next('.' + pfx + 'datatable-row-subtable');
7122					if ($(subTableRow).length === 0) {
7123						// prepare DOM for sub table, each <tr> as parent and add <tr> as child table
7124						subTableRow = $('<tr/>').
7125							addClass(pfx + 'datatable-row-subtable ' + pfx + 'datatable-row-loading').
7126							hide().
7127							append($('<td/>').addClass(pfx + 'datatable-subtable').attr('colspan', Plugin.getTotalColumns()));
7128						$(parentRow).after(subTableRow);
7129						// add class to even row
7130						if ($(parentRow).hasClass(pfx + 'datatable-row-even')) {
7131							$(subTableRow).addClass(pfx + 'datatable-row-subtable-even');
7132						}
7133					}
7134
7135					$(subTableRow).toggle();
7136
7137					var subTable = $(subTableRow).find('.' + pfx + 'datatable-subtable');
7138
7139					// get id from first column of parent row
7140					var primaryKey = $(this).closest('[data-field]:first-child').find('.' + pfx + 'datatable-toggle-subtable').data('value');
7141
7142					var icon = $(this).find('i').removeAttr('class');
7143
7144					// prevent duplicate datatable init
7145					if ($(parentRow).hasClass(pfx + 'datatable-row-subtable-expanded')) {
7146						$(icon).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'));
7147						// remove expand class from parent row
7148						$(parentRow).removeClass(pfx + 'datatable-row-subtable-expanded');
7149						// trigger event on collapse
7150						$(datatable).trigger(pfx + 'datatable-on-collapse-subtable', [parentRow]);
7151					} else {
7152						// expand and run callback function
7153						$(icon).addClass(Plugin.getOption('layout.icons.rowDetail.expand'));
7154						// add expand class to parent row
7155						$(parentRow).addClass(pfx + 'datatable-row-subtable-expanded');
7156						// trigger event on expand
7157						$(datatable).trigger(pfx + 'datatable-on-expand-subtable', [parentRow]);
7158					}
7159
7160					// prevent duplicate datatable init
7161					if ($(subTable).find('.' + pfx + 'datatable').length === 0) {
7162						// get data by primary id
7163						$.map(datatable.dataSet, function(n, i) {
7164							// primary id must be at the first column, otherwise e.data will be undefined
7165							if (primaryKey === n[options.columns[0].field]) {
7166								e.data = n;
7167								return true;
7168							}
7169							return false;
7170						});
7171
7172						// deprecated in v5.0.6
7173						e.detailCell = subTable;
7174
7175						e.parentRow = parentRow;
7176						e.subTable = subTable;
7177
7178						// run callback with event
7179						subTableCallback(e);
7180
7181						$(subTable).children('.' + pfx + 'datatable').on(pfx + 'datatable-on-init', function(e) {
7182							$(subTableRow).removeClass(pfx + 'datatable-row-loading');
7183						});
7184						if (Plugin.getOption('data.type') === 'local') {
7185							$(subTableRow).removeClass(pfx + 'datatable-row-loading');
7186						}
7187					}
7188				};
7189
7190				var columns = options.columns;
7191				$(datatable.tableBody).find('.' + pfx + 'datatable-row').each(function(tri, tr) {
7192					$(tr).find('.' + pfx + 'datatable-cell').each(function(tdi, td) {
7193						// get column settings by field
7194						var column = $.grep(columns, function(n, i) {
7195							return $(td).data('field') === n.field;
7196						})[0];
7197						if (typeof column !== 'undefined') {
7198							var value = $(td).text();
7199							// enable column subtable toggle
7200							if (typeof column.subtable !== 'undefined' && column.subtable) {
7201								// check if subtable toggle exist
7202								if ($(td).find('.' + pfx + 'datatable-toggle-subtable').length > 0) return;
7203								// append subtable toggle
7204								$(td).
7205									html($('<a/>').
7206										addClass(pfx + 'datatable-toggle-subtable').
7207										attr('href', '#').
7208										attr('data-value', value).
7209										attr('title', Plugin.getOption('detail.title')).
7210										on('click', toggleSubTable).
7211										append($('<i/>').css('width', $(td).data('width')).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'))));
7212							}
7213						}
7214					});
7215				});
7216
7217				// $(datatable.tableHead).find('.'+pfx+'-datatable-row').first()
7218			},
7219
7220			/**
7221			 * Datasource mapping callback
7222			 */
7223			dataMapCallback: function(raw) {
7224				// static dataset array
7225				var dataSet = raw;
7226				// dataset mapping callback
7227				if (typeof Plugin.getOption('data.source.read.map') === 'function') {
7228					return Plugin.getOption('data.source.read.map')(raw);
7229				} else {
7230					// default data mapping fallback
7231					if (typeof raw !== 'undefined' && typeof raw.data !== 'undefined') {
7232						dataSet = raw.data;
7233					}
7234				}
7235				return dataSet;
7236			},
7237
7238			isSpinning: false,
7239			/**
7240			 * BlockUI spinner callback
7241			 * @param block
7242			 * @param target
7243			 */
7244			spinnerCallback: function(block, target) {
7245				if (typeof target === 'undefined') target = datatable;
7246				// get spinner options
7247				var spinnerOptions = Plugin.getOption('layout.spinner');
7248				// spinner is disabled
7249				if (typeof spinnerOptions === 'undefined' || !spinnerOptions) {
7250					return;
7251				}
7252				if (block) {
7253					if (!Plugin.isSpinning) {
7254						if (typeof spinnerOptions.message !== 'undefined' && spinnerOptions.message === true) {
7255							// use default spinner message from translation
7256							spinnerOptions.message = Plugin.getOption('translate.records.processing');
7257						}
7258						Plugin.isSpinning = true;
7259						if (typeof app !== 'undefined') {
7260							app.block(target, spinnerOptions);
7261						}
7262					}
7263				} else {
7264					Plugin.isSpinning = false;
7265					if (typeof app !== 'undefined') {
7266						app.unblock(target);
7267					}
7268				}
7269			},
7270
7271			/**
7272			 * Default sort callback function
7273			 * @param data
7274			 * @param sort
7275			 * @param column
7276			 * @returns {*|Array.<T>|{sort, field}|{asc, desc}}
7277			 */
7278			sortCallback: function(data, sort, column) {
7279				var type = column['type'] || 'string';
7280				var format = column['format'] || '';
7281				var field = column['field'];
7282
7283				return $(data).sort(function(a, b) {
7284					var aField = a[field];
7285					var bField = b[field];
7286
7287					switch (type) {
7288						case 'date':
7289							if (typeof moment === 'undefined') {
7290								throw new Error('Moment.js is required.');
7291							}
7292							var diff = moment(aField, format).diff(moment(bField, format));
7293							if (sort === 'asc') {
7294								return diff > 0 ? 1 : diff < 0 ? -1 : 0;
7295							} else {
7296								return diff < 0 ? 1 : diff > 0 ? -1 : 0;
7297							}
7298							break;
7299
7300						case 'number':
7301							if (isNaN(parseFloat(aField)) && aField != null) {
7302								aField = Number(aField.replace(/[^0-9\.-]+/g, ''));
7303							}
7304							if (isNaN(parseFloat(bField)) && bField != null) {
7305								bField = Number(bField.replace(/[^0-9\.-]+/g, ''));
7306							}
7307							aField = parseFloat(aField);
7308							bField = parseFloat(bField);
7309							if (sort === 'asc') {
7310								return aField > bField ? 1 : aField < bField ? -1 : 0;
7311							} else {
7312								return aField < bField ? 1 : aField > bField ? -1 : 0;
7313							}
7314							break;
7315
7316						case 'html':
7317							return $(data).sort(function(a, b) {
7318								// get the text only from html
7319								aField = $(a[field]).text();
7320								bField = $(b[field]).text();
7321								// sort
7322								if (sort === 'asc') {
7323									return aField > bField ? 1 : aField < bField ? -1 : 0;
7324								} else {
7325									return aField < bField ? 1 : aField > bField ? -1 : 0;
7326								}
7327							});
7328							break;
7329
7330						case 'string':
7331						default:
7332							if (sort === 'asc') {
7333								return aField > bField ? 1 : aField < bField ? -1 : 0;
7334							} else {
7335								return aField < bField ? 1 : aField > bField ? -1 : 0;
7336							}
7337							break;
7338					}
7339				});
7340			},
7341
7342			/**
7343			 * Custom debug log
7344			 * @param text
7345			 * @param obj
7346			 */
7347			log: function(text, obj) {
7348				if (typeof obj === 'undefined') obj = '';
7349				if (datatable.debug) {
7350					console.log(text, obj);
7351				}
7352			},
7353
7354			/**
7355			 * Auto hide columnds overflow in row
7356			 */
7357			autoHide: function() {
7358				var hiddenExist = false;
7359				// force hide enabled
7360				var hidDefault = $(datatable.table).find('[data-autohide-enabled]');
7361				if (hidDefault.length) {
7362					hiddenExist = true;
7363					hidDefault.hide();
7364				}
7365
7366				var toggleHiddenColumns = function(e) {
7367					e.preventDefault();
7368
7369					var row = $(this).closest('.' + pfx + 'datatable-row');
7370					var detailRow = $(row).next();
7371
7372					if (!$(detailRow).hasClass(pfx + 'datatable-row-detail')) {
7373						$(this).find('i').removeClass(Plugin.getOption('layout.icons.rowDetail.collapse')).addClass(Plugin.getOption('layout.icons.rowDetail.expand'));
7374
7375						var hiddenCells = $(row).find('.' + pfx + 'datatable-cell:hidden');
7376						var clonedCells = hiddenCells.clone().show();
7377
7378						detailRow = $('<tr/>').addClass(pfx + 'datatable-row-detail').insertAfter(row);
7379						var detailRowTd = $('<td/>').addClass(pfx + 'datatable-detail').attr('colspan', Plugin.getTotalColumns()).appendTo(detailRow);
7380
7381						var detailSubTable = $('<table/>');
7382						$(clonedCells).each(function() {
7383							var field = $(this).data('field');
7384							var column = $.grep(options.columns, function(n, i) {
7385								return field === n.field;
7386							})[0];
7387							if (typeof column === 'undefined' || column.visible !== false) {
7388								$(detailSubTable).
7389										append($('<tr class="' + pfx + 'datatable-row"></tr>').
7390												append($('<td class="' + pfx + 'datatable-cell"></td>').append($('<span/>').append(column.title))).
7391												append(this));
7392							}
7393						});
7394						$(detailRowTd).append(detailSubTable);
7395
7396					} else {
7397						$(this).find('i').removeClass(Plugin.getOption('layout.icons.rowDetail.expand')).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'));
7398						$(detailRow).remove();
7399					}
7400				};
7401
7402				setTimeout(function () {
7403					$(datatable.table).find('.' + pfx + 'datatable-cell').show();
7404					$(datatable.tableBody).each(function() {
7405						var recursive = 0;
7406						var offsetWidth = $(this)[0].offsetWidth;
7407						var scrollWidth = $(this)[0].scrollWidth;
7408
7409						while (offsetWidth < scrollWidth && (scrollWidth - offsetWidth) > Plugin.cellOffset && recursive < options.columns.length) {
7410
7411							$(datatable.table).find('.' + pfx + 'datatable-row').each(function(i) {
7412								var cell = $(this).find('.' + pfx + 'datatable-cell:not(:hidden):not([data-autohide-disabled])').last();
7413									if (cell.length) {
7414										$(cell).hide();
7415										hiddenExist = true;
7416									}
7417							});
7418							recursive++;
7419
7420							offsetWidth = $(this)[0].offsetWidth;
7421							scrollWidth = $(this)[0].scrollWidth;
7422						}
7423					});
7424
7425					if (hiddenExist) {
7426						// toggle show hidden columns
7427						$(datatable.tableBody).find('.' + pfx + 'datatable-row').each(function() {
7428							// if no toggle yet
7429							if($(this).find('.' + pfx + 'datatable-toggle-detail').length === 0) {
7430								// add toggle
7431								$(this).prepend($('<td/>').
7432										addClass(pfx + 'datatable-cell ' + pfx + 'datatable-toggle-detail').
7433										append($('<a/>').
7434											addClass(pfx + 'datatable-toggle-detail').
7435											attr('href', '').
7436											on('click', toggleHiddenColumns).
7437											append('<i class="' + Plugin.getOption('layout.icons.rowDetail.collapse') + '"></i>')));
7438							}
7439
7440							// check if subtable toggle exist
7441							if ($(datatable.tableHead).find('.' + pfx + 'datatable-toggle-detail').length === 0) {
7442								// add empty column to the header and footer
7443								$(datatable.tableHead).
7444									find('.' + pfx + 'datatable-row').
7445									first().
7446									prepend('<th class="' + pfx + 'datatable-cell ' + pfx + 'datatable-toggle-detail"><span></span></th>');
7447								$(datatable.tableFoot).
7448									find('.' + pfx + 'datatable-row').
7449									first().
7450									prepend('<th class="' + pfx + 'datatable-cell ' + pfx + 'datatable-toggle-detail"><span></span></th>');
7451							} else {
7452								$(datatable.tableHead).find('.' + pfx + 'datatable-toggle-detail').find('span');
7453							}
7454						});
7455					}
7456				});
7457
7458				Plugin.adjustCellsWidth.call();
7459			},
7460
7461			/**
7462			 * To enable auto columns features for remote data source
7463			 */
7464			setAutoColumns: function() {
7465				if (Plugin.getOption('data.autoColumns')) {
7466					$.each(datatable.dataSet[0], function(k, v) {
7467						var found = $.grep(options.columns, function(n, i) {
7468							return k === n.field;
7469						});
7470						if (found.length === 0) {
7471							options.columns.push({field: k, title: k});
7472						}
7473					});
7474					$(datatable.tableHead).find('.' + pfx + 'datatable-row').remove();
7475					Plugin.setHeadTitle();
7476					if (Plugin.getOption('layout.footer')) {
7477						$(datatable.tableFoot).find('.' + pfx + 'datatable-row').remove();
7478						Plugin.setHeadTitle(datatable.tableFoot);
7479					}
7480				}
7481			},
7482
7483			/********************
7484			 ** HELPERS
7485			 ********************/
7486
7487			/**
7488			 * Check if table is a locked colums table
7489			 */
7490			isLocked: function() {
7491				var isLocked = Plugin.lockEnabledColumns();
7492				return isLocked.left.length > 0 || isLocked.right.length > 0;
7493			},
7494
7495			isSubtable: function() {
7496				return util.hasClass(datatable.wrap[0], pfx + 'datatable-subtable') || false;
7497			},
7498
7499			/**
7500			 * Get total extra space of an element for width calculation,
7501			 * including padding, margin, border
7502			 * @param element
7503			 * @returns {number}
7504			 */
7505			getExtraSpace: function(element) {
7506				var padding = parseInt($(element).css('paddingRight')) +
7507					parseInt($(element).css('paddingLeft'));
7508				var margin = parseInt($(element).css('marginRight')) +
7509					parseInt($(element).css('marginLeft'));
7510				var border = Math.ceil(
7511					$(element).css('border-right-width').replace('px', ''));
7512				return padding + margin + border;
7513			},
7514
7515			/**
7516			 * Insert data of array into {{ }} template placeholder
7517			 * @param template
7518			 * @param data
7519			 * @returns {*}
7520			 */
7521			dataPlaceholder: function(template, data) {
7522				var result = template;
7523				$.each(data, function(key, val) {
7524					result = result.replace('{{' + key + '}}', val);
7525				});
7526				return result;
7527			},
7528
7529			/**
7530			 * Get table unique ID
7531			 * Note: table unique change each time refreshed
7532			 * @param suffix
7533			 * @returns {*}
7534			 */
7535			getTableId: function(suffix) {
7536				if (typeof suffix === 'undefined') suffix = '';
7537				var id = $(datatable).attr('id');
7538				if (typeof id === 'undefined') {
7539					id = $(datatable).attr('class').split(' ')[0];
7540				}
7541				return id + suffix;
7542			},
7543
7544			/**
7545			 * Get table prefix with depth number
7546			 */
7547			getTablePrefix: function(suffix) {
7548				if (typeof suffix !== 'undefined') suffix = '-' + suffix;
7549				return Plugin.getTableId() + '-' + Plugin.getDepth() + suffix;
7550			},
7551
7552			/**
7553			 * Get current table depth of sub table
7554			 * @returns {number}
7555			 */
7556			getDepth: function() {
7557				var depth = 0;
7558				var table = datatable.table;
7559				do {
7560					table = $(table).parents('.' + pfx + 'datatable-table');
7561					depth++;
7562				} while ($(table).length > 0);
7563				return depth;
7564			},
7565
7566			/**
7567			 * Keep state item
7568			 * @param key
7569			 * @param value
7570			 */
7571			stateKeep: function(key, value) {
7572				key = Plugin.getTablePrefix(key);
7573				if (Plugin.getOption('data.saveState') === false) return;
7574				if (localStorage) {
7575					localStorage.setItem(key, JSON.stringify(value));
7576				}
7577			},
7578
7579			/**
7580			 * Get state item
7581			 * @param key
7582			 * @param defValue
7583			 */
7584			stateGet: function(key, defValue) {
7585				key = Plugin.getTablePrefix(key);
7586				if (Plugin.getOption('data.saveState') === false) return;
7587				var value = null;
7588				if (localStorage) {
7589					value = localStorage.getItem(key);
7590				}
7591				if (typeof value !== 'undefined' && value !== null) {
7592					return JSON.parse(value);
7593				}
7594			},
7595
7596			/**
7597			 * Update data in state without clear existing
7598			 * @param key
7599			 * @param value
7600			 */
7601			stateUpdate: function(key, value) {
7602				var ori = Plugin.stateGet(key);
7603				if (typeof ori === 'undefined' || ori === null) ori = {};
7604				Plugin.stateKeep(key, $.extend({}, ori, value));
7605			},
7606
7607			/**
7608			 * Remove state item
7609			 * @param key
7610			 */
7611			stateRemove: function(key) {
7612				key = Plugin.getTablePrefix(key);
7613				if (localStorage) {
7614					localStorage.removeItem(key);
7615				}
7616			},
7617
7618			/**
7619			 * Get total columns.
7620			 */
7621			getTotalColumns: function(tablePart) {
7622				if (typeof tablePart === 'undefined') tablePart = datatable.tableBody;
7623				return $(tablePart).find('.' + pfx + 'datatable-row').first().find('.' + pfx + 'datatable-cell').length;
7624			},
7625
7626			/**
7627			 * Get table row. Useful to get row when current table is in lock
7628			 * mode. Can be used for both lock and normal table mode. By
7629			 * default, returning result will be in a list of <td>.
7630			 * @param tablePart
7631			 * @param row 1-based index
7632			 * @param tdOnly Optional. Default true
7633			 * @returns {*}
7634			 */
7635			getOneRow: function(tablePart, row, tdOnly) {
7636				if (typeof tdOnly === 'undefined') tdOnly = true;
7637				// get list of <tr>
7638				var result = $(tablePart).find('.' + pfx + 'datatable-row:not(.' + pfx + 'datatable-row-detail):nth-child(' + row + ')');
7639				if (tdOnly) {
7640					// get list of <td> or <th>
7641					result = result.find('.' + pfx + 'datatable-cell');
7642				}
7643				return result;
7644			},
7645
7646			/**
7647			 * Sort table row at HTML level by column index.
7648			 * todo; Not in use.
7649			 * @param header Header sort clicked
7650			 * @param sort asc|desc. Optional. Default asc
7651			 * @param int Boolean. Optional. Comparison value parse to integer.
7652			 *     Default false
7653			 */
7654			sortColumn: function(header, sort, int) {
7655				if (typeof sort === 'undefined') sort = 'asc'; // desc
7656				if (typeof int === 'undefined') int = false;
7657
7658				var column = $(header).index();
7659				var rows = $(datatable.tableBody).find('.' + pfx + 'datatable-row');
7660				var hIndex = $(header).closest('.' + pfx + 'datatable-lock').index();
7661				if (hIndex !== -1) {
7662					rows = $(datatable.tableBody).find('.' + pfx + 'datatable-lock:nth-child(' + (hIndex + 1) + ')').find('.' + pfx + 'datatable-row');
7663				}
7664
7665				var container = $(rows).parent();
7666				$(rows).sort(function(a, b) {
7667					var tda = $(a).find('td:nth-child(' + column + ')').text();
7668					var tdb = $(b).find('td:nth-child(' + column + ')').text();
7669
7670					if (int) {
7671						// useful for integer type sorting
7672						tda = parseInt(tda);
7673						tdb = parseInt(tdb);
7674					}
7675
7676					if (sort === 'asc') {
7677						return tda > tdb ? 1 : tda < tdb ? -1 : 0;
7678					} else {
7679						return tda < tdb ? 1 : tda > tdb ? -1 : 0;
7680					}
7681				}).appendTo(container);
7682			},
7683
7684			/**
7685			 * Perform sort remote and local
7686			 */
7687			sorting: function() {
7688				var sortObj = {
7689					init: function() {
7690						if (options.sortable) {
7691							$(datatable.tableHead).
7692								find('.' + pfx + 'datatable-cell:not(.' + pfx + 'datatable-cell-check)').
7693								addClass(pfx + 'datatable-cell-sort').
7694								off('click').
7695								on('click', sortObj.sortClick);
7696							// first init
7697							sortObj.setIcon();
7698						}
7699					},
7700					setIcon: function() {
7701						var meta = Plugin.getDataSourceParam('sort');
7702						if ($.isEmptyObject(meta)) return;
7703
7704						var column = Plugin.getColumnByField(meta.field);
7705						// sort is disabled for this column
7706						if (typeof column === 'undefined') return;
7707						if (typeof column.sortable !== 'undefined' && column.sortable === false) return;
7708						if (typeof column.selector !== 'undefined' && column.selector === true) return;
7709
7710						// sort icon beside column header
7711						var td = $(datatable.tableHead).find('.' + pfx + 'datatable-cell[data-field="' + meta.field + '"]').attr('data-sort', meta.sort);
7712						var sorting = $(td).find('span');
7713						var icon = $(sorting).find('i');
7714
7715						var icons = Plugin.getOption('layout.icons.sort');
7716						// update sort icon; desc & asc
7717						if ($(icon).length > 0) {
7718							$(icon).removeAttr('class').addClass(icons[meta.sort]);
7719						} else {
7720							$(sorting).append($('<i/>').addClass(icons[meta.sort]));
7721						}
7722
7723						// set sorted class to header on init
7724						$(td).addClass(pfx + 'datatable-cell-sorted');
7725					},
7726					sortClick: function(e) {
7727						var meta = Plugin.getDataSourceParam('sort');
7728						var field = $(this).data('field');
7729						var column = Plugin.getColumnByField(field);
7730						// sort is disabled for this column
7731						if (typeof column === 'undefined') return;
7732						if (typeof column.sortable !== 'undefined' && column.sortable === false) return;
7733						if (typeof column.selector !== 'undefined' && column.selector === true) return;
7734
7735						// set sorted class to header
7736						$(datatable.tableHead).find('th').removeClass(pfx + 'datatable-cell-sorted');
7737						util.addClass(this, pfx + 'datatable-cell-sorted');
7738
7739						$(datatable.tableHead).find('.' + pfx + 'datatable-cell > span > i').remove();
7740
7741						if (options.sortable) {
7742							Plugin.spinnerCallback(true);
7743
7744							var sort = 'desc';
7745							if (Plugin.getObject('field', meta) === field) {
7746								sort = Plugin.getObject('sort', meta);
7747							}
7748
7749							// toggle sort
7750							sort = typeof sort === 'undefined' || sort === 'desc'
7751								? 'asc'
7752								: 'desc';
7753
7754							// update field and sort params
7755							meta = {field: field, sort: sort};
7756							Plugin.setDataSourceParam('sort', meta);
7757
7758							sortObj.setIcon();
7759
7760							setTimeout(function() {
7761								Plugin.dataRender('sort');
7762								$(datatable).trigger(pfx + 'datatable-on-sort', meta);
7763							}, 300);
7764						}
7765					},
7766				};
7767				sortObj.init();
7768			},
7769
7770			/**
7771			 * Update JSON data list linked with sort, filter and pagination.
7772			 * Call this method, before using dataSet variable.
7773			 * @returns {*|null}
7774			 */
7775			localDataUpdate: function() {
7776				var params = Plugin.getDataSourceParam();
7777				if (typeof datatable.originalDataSet === 'undefined') {
7778					datatable.originalDataSet = datatable.dataSet;
7779				}
7780
7781				var field = Plugin.getObject('sort.field', params);
7782				var sort = Plugin.getObject('sort.sort', params);
7783				var column = Plugin.getColumnByField(field);
7784				if (typeof column !== 'undefined' && Plugin.getOption('data.serverSorting') !== true) {
7785					if (typeof column.sortCallback === 'function') {
7786						datatable.dataSet = column.sortCallback(datatable.originalDataSet, sort, column);
7787					} else {
7788						datatable.dataSet = Plugin.sortCallback(datatable.originalDataSet, sort, column);
7789					}
7790				} else {
7791					datatable.dataSet = datatable.originalDataSet;
7792				}
7793
7794				// if server filter enable, don't pass local filter
7795				if (typeof params.query === 'object' && !Plugin.getOption('data.serverFiltering')) {
7796					params.query = params.query || {};
7797
7798					var nestedSearch = function(obj) {
7799						for (var field in obj) {
7800							if (!obj.hasOwnProperty(field)) continue;
7801							if (typeof obj[field] === 'string') {
7802								if (obj[field].toLowerCase() == search || obj[field].toLowerCase().indexOf(search) !== -1) {
7803									return true;
7804								}
7805							} else if (typeof obj[field] === 'number') {
7806								if (obj[field] === search) {
7807									return true;
7808								}
7809							} else if (typeof obj[field] === 'object') {
7810								if (nestedSearch(obj[field])) {
7811									return true;
7812								}
7813							}
7814						}
7815						return false;
7816					};
7817
7818					var search = $(Plugin.getOption('search.input')).val();
7819					if (typeof search !== 'undefined' && search !== '') {
7820						search = search.toLowerCase();
7821						datatable.dataSet = $.grep(datatable.dataSet, nestedSearch);
7822						// remove generalSearch as we don't need this for next columns filter
7823						delete params.query[Plugin.getGeneralSearchKey()];
7824					}
7825
7826					// remove empty element from array
7827					$.each(params.query, function(k, v) {
7828						if (v === '') {
7829							delete params.query[k];
7830						}
7831					});
7832
7833					// filter array by query
7834					datatable.dataSet = Plugin.filterArray(datatable.dataSet, params.query);
7835
7836					// reset array index
7837					datatable.dataSet = datatable.dataSet.filter(function() {
7838						return true;
7839					});
7840				}
7841
7842				return datatable.dataSet;
7843			},
7844
7845			/**
7846			 * Utility helper to filter array by object pair of {key:value}
7847			 * @param list
7848			 * @param args
7849			 * @param operator
7850			 * @returns {*}
7851			 */
7852			filterArray: function(list, args, operator) {
7853				if (typeof list !== 'object') {
7854					return [];
7855				}
7856
7857				if (typeof operator === 'undefined') operator = 'AND';
7858
7859				if (typeof args !== 'object') {
7860					return list;
7861				}
7862
7863				operator = operator.toUpperCase();
7864
7865				if ($.inArray(operator, ['AND', 'OR', 'NOT']) === -1) {
7866					return [];
7867				}
7868
7869				var count = Object.keys(args).length;
7870				var filtered = [];
7871
7872				$.each(list, function(key, obj) {
7873					var to_match = obj;
7874
7875					var matched = 0;
7876					$.each(args, function(m_key, m_value) {
7877						m_value = m_value instanceof Array ? m_value : [m_value];
7878						var match_property = Plugin.getObject(m_key, to_match);
7879						if (typeof match_property !== 'undefined' && match_property) {
7880							var lhs = match_property.toString().toLowerCase();
7881							m_value.forEach(function(item, index) {
7882								if (item.toString().toLowerCase() == lhs || lhs.indexOf(item.toString().toLowerCase()) !== -1) {
7883									matched++;
7884								}
7885							});
7886						}
7887					});
7888
7889					if (('AND' == operator && matched == count) ||
7890						('OR' == operator && matched > 0) ||
7891						('NOT' == operator && 0 == matched)) {
7892						filtered[key] = obj;
7893					}
7894				});
7895
7896				list = filtered;
7897
7898				return list;
7899			},
7900
7901			/**
7902			 * Reset lock column scroll to 0 when resize
7903			 */
7904			resetScroll: function() {
7905				if (typeof options.detail === 'undefined' && Plugin.getDepth() === 1) {
7906					$(datatable.table).find('.' + pfx + 'datatable-row').css('left', 0);
7907					$(datatable.table).find('.' + pfx + 'datatable-lock').css('top', 0);
7908					$(datatable.tableBody).scrollTop(0);
7909				}
7910			},
7911
7912			/**
7913			 * Get column options by field
7914			 * @param field
7915			 * @returns {boolean}
7916			 */
7917			getColumnByField: function(field) {
7918				if (typeof field === 'undefined') return;
7919				var result;
7920				$.each(options.columns, function(i, column) {
7921					if (field === column.field) {
7922						result = column;
7923						return false;
7924					}
7925				});
7926				return result;
7927			},
7928
7929			/**
7930			 * Get default sort column
7931			 */
7932			getDefaultSortColumn: function() {
7933				var result;
7934				$.each(options.columns, function(i, column) {
7935					if (typeof column.sortable !== 'undefined'
7936						&& $.inArray(column.sortable, ['asc', 'desc']) !== -1) {
7937						result = {sort: column.sortable, field: column.field};
7938						return false;
7939					}
7940				});
7941				return result;
7942			},
7943
7944			/**
7945			 * Helper to get element dimensions, when the element is hidden
7946			 * @param element
7947			 * @param includeMargin
7948			 * @returns {{width: number, height: number, innerWidth: number,
7949			 *     innerHeight: number, outerWidth: number, outerHeight:
7950			 *     number}}
7951			 */
7952			getHiddenDimensions: function(element, includeMargin) {
7953				var props = {
7954						position: 'absolute',
7955						visibility: 'hidden',
7956						display: 'block',
7957					},
7958					dim = {
7959						width: 0,
7960						height: 0,
7961						innerWidth: 0,
7962						innerHeight: 0,
7963						outerWidth: 0,
7964						outerHeight: 0,
7965					},
7966					hiddenParents = $(element).parents().addBack().not(':visible');
7967				includeMargin = (typeof includeMargin === 'boolean')
7968					? includeMargin
7969					: false;
7970
7971				var oldProps = [];
7972				hiddenParents.each(function() {
7973					var old = {};
7974
7975					for (var name in props) {
7976						old[name] = this.style[name];
7977						this.style[name] = props[name];
7978					}
7979
7980					oldProps.push(old);
7981				});
7982
7983				dim.width = $(element).width();
7984				dim.outerWidth = $(element).outerWidth(includeMargin);
7985				dim.innerWidth = $(element).innerWidth();
7986				dim.height = $(element).height();
7987				dim.innerHeight = $(element).innerHeight();
7988				dim.outerHeight = $(element).outerHeight(includeMargin);
7989
7990				hiddenParents.each(function(i) {
7991					var old = oldProps[i];
7992					for (var name in props) {
7993						this.style[name] = old[name];
7994					}
7995				});
7996
7997				return dim;
7998			},
7999
8000			getGeneralSearchKey: function() {
8001				var searchInput = $(Plugin.getOption('search.input'));
8002				return Plugin.getOption('search.key') || $(searchInput).prop('name');
8003			},
8004
8005			/**
8006			 * Get value by dot notation path string and to prevent undefined
8007			 * errors
8008			 * @param path String Dot notation path in string
8009			 * @param object Object to iterate
8010			 * @returns {*}
8011			 */
8012			getObject: function(path, object) {
8013				return path.split('.').reduce(function(obj, i) {
8014					return obj !== null && typeof obj[i] !== 'undefined' ? obj[i] : null;
8015				}, object);
8016			},
8017
8018			/**
8019			 * Extend object
8020			 * @param obj
8021			 * @param path
8022			 * @param value
8023			 * @returns {*}
8024			 */
8025			extendObj: function(obj, path, value) {
8026				var levels = path.split('.'),
8027					i = 0;
8028
8029				function createLevel(child) {
8030					var name = levels[i++];
8031					if (typeof child[name] !== 'undefined' && child[name] !== null) {
8032						if (typeof child[name] !== 'object' &&
8033							typeof child[name] !== 'function') {
8034							child[name] = {};
8035						}
8036					} else {
8037						child[name] = {};
8038					}
8039					if (i === levels.length) {
8040						child[name] = value;
8041					} else {
8042						createLevel(child[name]);
8043					}
8044				}
8045
8046				createLevel(obj);
8047				return obj;
8048			},
8049
8050			rowEvenOdd: function() {
8051				// row even class
8052				$(datatable.tableBody).find('.' + pfx + 'datatable-row').removeClass(pfx + 'datatable-row-even');
8053				if ($(datatable.wrap).hasClass(pfx + 'datatable-subtable')) {
8054					$(datatable.tableBody).find('.' + pfx + 'datatable-row:not(.' + pfx + 'datatable-row-detail):even').addClass(pfx + 'datatable-row-even');
8055				} else {
8056					$(datatable.tableBody).find('.' + pfx + 'datatable-row:nth-child(even)').addClass(pfx + 'datatable-row-even');
8057				}
8058			},
8059
8060			/********************
8061			 ** PUBLIC API METHODS
8062			 ********************/
8063
8064			// delay timer
8065			timer: 0,
8066
8067			/**
8068			 * Redraw datatable by recalculating its DOM elements, etc.
8069			 * @returns {jQuery}
8070			 */
8071			redraw: function() {
8072				Plugin.adjustCellsWidth.call();
8073				if (Plugin.isLocked()) {
8074					// fix hiding cell width issue
8075					Plugin.scrollbar();
8076					Plugin.resetScroll();
8077					Plugin.adjustCellsHeight.call();
8078				}
8079				Plugin.adjustLockContainer.call();
8080				Plugin.initHeight.call();
8081				return datatable;
8082			},
8083
8084			/**
8085			 * Shortcode to reload
8086			 * @returns {jQuery}
8087			 */
8088			load: function() {
8089				Plugin.reload();
8090				return datatable;
8091			},
8092
8093			/**
8094			 * Datasource reload
8095			 * @returns {jQuery}
8096			 */
8097			reload: function() {
8098				var delay = (function() {
8099					return function(callback, ms) {
8100						clearTimeout(Plugin.timer);
8101						Plugin.timer = setTimeout(callback, ms);
8102					};
8103				})();
8104				delay(function() {
8105					// local only. remote pagination will skip this block
8106					if (!options.data.serverFiltering) {
8107						Plugin.localDataUpdate();
8108					}
8109					Plugin.dataRender();
8110					$(datatable).trigger(pfx + 'datatable-on-reloaded');
8111				}, Plugin.getOption('search.delay'));
8112				return datatable;
8113			},
8114
8115			/**
8116			 * Get record by record ID
8117			 * @param id
8118			 * @returns {jQuery}
8119			 */
8120			getRecord: function(id) {
8121				if (typeof datatable.tableBody === 'undefined') datatable.tableBody = $(datatable.table).children('tbody');
8122				$(datatable.tableBody).find('.' + pfx + 'datatable-cell:first-child').each(function(i, cell) {
8123					if (id == $(cell).text()) {
8124						var rowNumber = $(cell).closest('.' + pfx + 'datatable-row').index() + 1;
8125						datatable.API.record = datatable.API.value = Plugin.getOneRow(datatable.tableBody, rowNumber);
8126						return datatable;
8127					}
8128				});
8129				return datatable;
8130			},
8131
8132			/**
8133			 * @deprecated in v5.0.6
8134			 * Get column of current record ID
8135			 * @param columnName
8136			 * @returns {jQuery}
8137			 */
8138			getColumn: function(columnName) {
8139				Plugin.setSelectedRecords();
8140				datatable.API.value = $(datatable.API.record).find('[data-field="' + columnName + '"]');
8141				return datatable;
8142			},
8143
8144			/**
8145			 * Destroy datatable to original DOM state before datatable was
8146			 * initialized
8147			 * @returns {jQuery}
8148			 */
8149			destroy: function() {
8150				$(datatable).parent().find('.' + pfx + 'datatable-pager').remove();
8151				var initialDatatable = $(datatable.initialDatatable).addClass(pfx + 'datatable-destroyed').show();
8152				$(datatable).replaceWith(initialDatatable);
8153				datatable = initialDatatable;
8154				$(datatable).trigger(pfx + 'datatable-on-destroy');
8155				Plugin.isInit = false;
8156
8157				// clean up variables
8158				initialDatatable = null;
8159				datatable.dataSet = null;
8160				datatable.originalDataSet = null;
8161				datatable.tableHead = null;
8162				datatable.tableBody = null;
8163				datatable.table = null;
8164				datatable.wrap = null;
8165				datatable.API = {
8166					record: null,
8167					value: null,
8168					params: null,
8169				};
8170
8171				Plugin.ajaxParams = {};
8172				Plugin.pagingObject = {};
8173				Plugin.nodeTr = [];
8174				Plugin.nodeTd = [];
8175				Plugin.nodeCols = [];
8176				Plugin.recentNode = [];
8177
8178				return initialDatatable;
8179			},
8180
8181			/**
8182			 * Sort by column field
8183			 * @param field
8184			 * @param sort
8185			 */
8186			sort: function(field, sort) {
8187				// toggle sort
8188				sort = typeof sort === 'undefined' ? 'asc' : sort;
8189
8190				Plugin.spinnerCallback(true);
8191
8192				// update field and sort params
8193				var meta = {field: field, sort: sort};
8194				Plugin.setDataSourceParam('sort', meta);
8195
8196				setTimeout(function() {
8197					Plugin.dataRender('sort');
8198					$(datatable).trigger(pfx + 'datatable-on-sort', meta);
8199					$(datatable.tableHead).find('.' + pfx + 'datatable-cell > span > i').remove();
8200				}, 300);
8201
8202				return datatable;
8203			},
8204
8205			/**
8206			 * @deprecated in v5.0.6
8207			 * Get current selected column value
8208			 * @returns {jQuery}
8209			 */
8210			getValue: function() {
8211				return $(datatable.API.value).text();
8212			},
8213
8214			/**
8215			 * Set checkbox active
8216			 * @param cell JQuery selector or checkbox ID
8217			 */
8218			setActive: function(cell) {
8219				if (typeof cell === 'string') {
8220					// set by checkbox id
8221					cell = $(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"][value="' + cell + '"]');
8222				}
8223
8224				$(cell).prop('checked', true);
8225
8226				var ids = [];
8227				$(cell).each(function(i, td) {
8228					// normal table
8229					var row = $(td).closest('tr').addClass(pfx + 'datatable-row-active');
8230
8231					var id = $(td).attr('value');
8232					if (typeof id !== 'undefined') {
8233						ids.push(id);
8234					}
8235				});
8236
8237				$(datatable).trigger(pfx + 'datatable-on-check', [ids]);
8238			},
8239
8240			/**
8241			 * Set checkbox inactive
8242			 * @param cell JQuery selector or checkbox ID
8243			 */
8244			setInactive: function(cell) {
8245				if (typeof cell === 'string') {
8246					// set by checkbox id
8247					cell = $(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"][value="' + cell + '"]');
8248				}
8249
8250				$(cell).prop('checked', false);
8251
8252				var ids = [];
8253				$(cell).each(function(i, td) {
8254					// normal table
8255					var row = $(td).closest('tr').removeClass(pfx + 'datatable-row-active');
8256
8257					var id = $(td).attr('value');
8258					if (typeof id !== 'undefined') {
8259						ids.push(id);
8260					}
8261				});
8262
8263				$(datatable).trigger(pfx + 'datatable-on-uncheck', [ids]);
8264			},
8265
8266			/**
8267			 * Set all checkboxes active or inactive
8268			 * @param active
8269			 */
8270			setActiveAll: function(active) {
8271				var checkboxes = $(datatable.table).
8272					find('> tbody, > thead').
8273					find('tr').not('.' + pfx + 'datatable-row-subtable').
8274					find('.' + pfx + 'datatable-cell-check [type="checkbox"]');
8275				if (active) {
8276					Plugin.setActive(checkboxes);
8277				} else {
8278					Plugin.setInactive(checkboxes);
8279				}
8280			},
8281
8282			/**
8283			 * @deprecated in v5.0.6
8284			 * Get selected rows which are active
8285			 * @returns {jQuery}
8286			 */
8287			setSelectedRecords: function() {
8288				datatable.API.record = $(datatable.tableBody).find('.' + pfx + 'datatable-row-active');
8289				return datatable;
8290			},
8291
8292			/**
8293			 * Get selected records
8294			 * @returns {null}
8295			 */
8296			getSelectedRecords: function() {
8297				// support old method
8298				Plugin.setSelectedRecords();
8299				datatable.API.record = datatable.rows('.' + pfx + 'datatable-row-active').nodes();
8300				return datatable.API.record;
8301			},
8302
8303			/**
8304			 * Get options by dots notation path
8305			 * @param path String Dot notation path in string
8306			 * @returns {*}
8307			 */
8308			getOption: function(path) {
8309				return Plugin.getObject(path, options);
8310			},
8311
8312			/**
8313			 * Set global options nodes by dots notation path
8314			 * @param path
8315			 * @param object
8316			 */
8317			setOption: function(path, object) {
8318				options = Plugin.extendObj(options, path, object);
8319			},
8320
8321			/**
8322			 * Search filter for local & remote
8323			 * @param value
8324			 * @param columns. Optional list of columns to be filtered.
8325			 */
8326			search: function(value, columns) {
8327				if (typeof columns !== 'undefined') columns = $.makeArray(columns);
8328				var delay = (function() {
8329					return function(callback, ms) {
8330						clearTimeout(Plugin.timer);
8331						Plugin.timer = setTimeout(callback, ms);
8332					};
8333				})();
8334
8335				delay(function() {
8336					// get query parameters
8337					var query = Plugin.getDataSourceQuery();
8338
8339					// search not by columns
8340					if (typeof columns === 'undefined' && typeof value !== 'undefined') {
8341						var key = Plugin.getGeneralSearchKey();
8342						query[key] = value;
8343					}
8344
8345					// search by columns, support multiple columns
8346					if (typeof columns === 'object') {
8347						$.each(columns, function(k, column) {
8348							query[column] = value;
8349						});
8350						// remove empty element from arrays
8351						$.each(query, function(k, v) {
8352							if (v === '' || $.isEmptyObject(v)) {
8353								delete query[k];
8354							}
8355						});
8356					}
8357
8358					Plugin.setDataSourceQuery(query);
8359
8360					// reset pagination to 1 when doing seearching
8361					datatable.setDataSourceParam('pagination', Object.assign({}, datatable.getDataSourceParam('pagination'), {page: 1}));
8362
8363					// local filter only. remote pagination will skip this block
8364					if (!options.data.serverFiltering) {
8365						Plugin.localDataUpdate();
8366					}
8367					Plugin.dataRender('search');
8368				}, Plugin.getOption('search.delay'));
8369			},
8370
8371			/**
8372			 * Set datasource params extract
8373			 * @param param
8374			 * @param value
8375			 */
8376			setDataSourceParam: function(param, value) {
8377				datatable.API.params = $.extend({}, {
8378					pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')},
8379					sort: Plugin.getDefaultSortColumn(),
8380					query: {},
8381				}, datatable.API.params, Plugin.stateGet(Plugin.stateId));
8382
8383				datatable.API.params = Plugin.extendObj(datatable.API.params, param, value);
8384
8385				Plugin.stateKeep(Plugin.stateId, datatable.API.params);
8386			},
8387
8388			/**
8389			 * Get datasource params
8390			 * @param param
8391			 */
8392			getDataSourceParam: function(param) {
8393				datatable.API.params = $.extend({}, {
8394					pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')},
8395					sort: Plugin.getDefaultSortColumn(),
8396					query: {},
8397				}, datatable.API.params, Plugin.stateGet(Plugin.stateId));
8398
8399				if (typeof param === 'string') {
8400					return Plugin.getObject(param, datatable.API.params);
8401				}
8402
8403				return datatable.API.params;
8404			},
8405
8406			/**
8407			 * Shortcode to datatable.getDataSourceParam('query');
8408			 * @returns {*}
8409			 */
8410			getDataSourceQuery: function() {
8411				return Plugin.getDataSourceParam('query') || {};
8412			},
8413
8414			/**
8415			 * Shortcode to datatable.setDataSourceParam('query', query);
8416			 * @param query
8417			 */
8418			setDataSourceQuery: function(query) {
8419				Plugin.setDataSourceParam('query', query);
8420			},
8421
8422			/**
8423			 * Get current page number
8424			 * @returns {number}
8425			 */
8426			getCurrentPage: function() {
8427				return $(datatable.table).
8428					siblings('.' + pfx + 'datatable-pager').
8429					last().
8430					find('.' + pfx + 'datatable-pager-nav').
8431					find('.' + pfx + 'datatable-pager-link.' + pfx + 'datatable-pager-link-active').
8432					data('page') || 1;
8433			},
8434
8435			/**
8436			 * Get selected dropdown page size
8437			 * @returns {*|number}
8438			 */
8439			getPageSize: function() {
8440				return $(datatable.table).siblings('.' + pfx + 'datatable-pager').last().find('select.' + pfx + 'datatable-pager-size').val() || 10;
8441			},
8442
8443			/**
8444			 * Get total rows
8445			 */
8446			getTotalRows: function() {
8447				return datatable.API.params.pagination.total;
8448			},
8449
8450			/**
8451			 * Get full dataset in grid
8452			 * @returns {*|null|Array}
8453			 */
8454			getDataSet: function() {
8455				return datatable.originalDataSet;
8456			},
8457
8458			nodeTr: [],
8459			nodeTd: [],
8460			nodeCols: [],
8461			recentNode: [],
8462
8463			table: function() {
8464				if (typeof datatable.table !== 'undefined') {
8465					return datatable.table;
8466				}
8467			},
8468
8469			/**
8470			 * Select a single row from the table
8471			 * @param selector
8472			 * @returns {jQuery}
8473			 */
8474			row: function(selector) {
8475				Plugin.rows(selector);
8476				Plugin.nodeTr = Plugin.recentNode = $(Plugin.nodeTr).first();
8477				return datatable;
8478			},
8479
8480			/**
8481			 * Select multiple rows from the table
8482			 * @param selector
8483			 * @returns {jQuery}
8484			 */
8485			rows: function(selector) {
8486				if (Plugin.isLocked()) {
8487					Plugin.nodeTr = Plugin.recentNode = $(datatable.tableBody).find(selector).filter('.' + pfx + 'datatable-lock-scroll > .' + pfx + 'datatable-row');
8488				} else {
8489					Plugin.nodeTr = Plugin.recentNode = $(datatable.tableBody).find(selector).filter('.' + pfx + 'datatable-row');
8490				}
8491				return datatable;
8492			},
8493
8494			/**
8495			 * Select a single column from the table
8496			 * @param index zero-based index
8497			 * @returns {jQuery}
8498			 */
8499			column: function(index) {
8500				Plugin.nodeCols = Plugin.recentNode = $(datatable.tableBody).find('.' + pfx + 'datatable-cell:nth-child(' + (index + 1) + ')');
8501				return datatable;
8502			},
8503
8504			/**
8505			 * Select multiple columns from the table
8506			 * @param selector
8507			 * @returns {jQuery}
8508			 */
8509			columns: function(selector) {
8510				var context = datatable.table;
8511				if (Plugin.nodeTr === Plugin.recentNode) {
8512					context = Plugin.nodeTr;
8513				}
8514				var columns = $(context).find('.' + pfx + 'datatable-cell[data-field="' + selector + '"]');
8515				if (columns.length > 0) {
8516					Plugin.nodeCols = Plugin.recentNode = columns;
8517				} else {
8518					Plugin.nodeCols = Plugin.recentNode = $(context).find(selector).filter('.' + pfx + 'datatable-cell');
8519				}
8520				return datatable;
8521			},
8522
8523			cell: function(selector) {
8524				Plugin.cells(selector);
8525				Plugin.nodeTd = Plugin.recentNode = $(Plugin.nodeTd).first();
8526				return datatable;
8527			},
8528
8529			cells: function(selector) {
8530				var cells = $(datatable.tableBody).find('.' + pfx + 'datatable-cell');
8531				if (typeof selector !== 'undefined') {
8532					cells = $(cells).filter(selector);
8533				}
8534				Plugin.nodeTd = Plugin.recentNode = cells;
8535				return datatable;
8536			},
8537
8538			/**
8539			 * Delete the selected row from the table
8540			 * @returns {jQuery}
8541			 */
8542			remove: function() {
8543				if ($(Plugin.nodeTr.length) && Plugin.nodeTr === Plugin.recentNode) {
8544					$(Plugin.nodeTr).remove();
8545				}
8546				Plugin.layoutUpdate();
8547				return datatable;
8548			},
8549
8550			/**
8551			 * Show or hide the columns or rows
8552			 */
8553			visible: function(bool) {
8554				if ($(Plugin.recentNode.length)) {
8555					var locked = Plugin.lockEnabledColumns();
8556					if (Plugin.recentNode === Plugin.nodeCols) {
8557						var index = Plugin.recentNode.index();
8558
8559						if (Plugin.isLocked()) {
8560							var scrollColumns = $(Plugin.recentNode).closest('.' + pfx + 'datatable-lock-scroll').length;
8561							if (scrollColumns) {
8562								// is at center of scrollable area
8563								index += locked.left.length + 1;
8564							} else if ($(Plugin.recentNode).closest('.' + pfx + 'datatable-lock-right').length) {
8565								// is at the right locked table
8566								index += locked.left.length + scrollColumns + 1;
8567							}
8568						}
8569					}
8570
8571					if (bool) {
8572						if (Plugin.recentNode === Plugin.nodeCols) {
8573							delete options.columns[index].visible;
8574						}
8575						$(Plugin.recentNode).show();
8576					} else {
8577						if (Plugin.recentNode === Plugin.nodeCols) {
8578							Plugin.setOption('columns.' + (index) + '.visible', false);
8579						}
8580						$(Plugin.recentNode).hide();
8581					}
8582					Plugin.columnHide();
8583					Plugin.redraw();
8584				}
8585			},
8586
8587			/**
8588			 * Get the the DOM element for the selected rows or columns
8589			 * @returns {Array}
8590			 */
8591			nodes: function() {
8592				return Plugin.recentNode;
8593			},
8594
8595			/**
8596			 * will be implemented soon
8597			 * @returns {jQuery}
8598			 */
8599			dataset: function() {
8600				return datatable;
8601			},
8602
8603			/**
8604			 * Open page by number
8605			 * @param page number
8606			 */
8607			gotoPage: function (page) {
8608				if (typeof Plugin.pagingObject !== 'undefined') {
8609					Plugin.isInit = true;
8610					Plugin.pagingObject.openPage(page);
8611				}
8612			},
8613
8614		};
8615
8616		/**
8617		 * Public API methods can be used directly by datatable
8618		 */
8619		$.each(Plugin, function(funcName, func) {
8620			datatable[funcName] = func;
8621		});
8622
8623		// initialize main datatable plugin
8624		if (typeof options !== 'undefined') {
8625			if (typeof options === 'string') {
8626				var method = options;
8627				datatable = $(this).data(pluginName);
8628				if (typeof datatable !== 'undefined') {
8629					options = datatable.options;
8630					Plugin[method].apply(this, Array.prototype.slice.call(arguments, 1));
8631				}
8632			} else {
8633				if (!datatable.data(pluginName) && !$(this).hasClass(pfx + 'datatable-loaded')) {
8634					datatable.dataSet = null;
8635					datatable.textAlign = {
8636						left: pfx + 'datatable-cell-left',
8637						center: pfx + 'datatable-cell-center',
8638						right: pfx + 'datatable-cell-right',
8639					};
8640
8641					// merge default and user defined options
8642					options = $.extend(true, {}, $.fn[pluginName].defaults, options);
8643
8644					datatable.options = options;
8645
8646					// init plugin process
8647					Plugin.init.apply(this, [options]);
8648
8649					$(datatable.wrap).data(pluginName, datatable);
8650				}
8651			}
8652		} else {
8653			// get existing instance datatable
8654			datatable = $(this).data(pluginName);
8655			if (typeof datatable === 'undefined') {
8656				$.error(pluginName + ' not initialized');
8657			}
8658			options = datatable.options;
8659		}
8660
8661		return datatable;
8662	};
8663
8664	// default options
8665	$.fn[pluginName].defaults = {
8666		// datasource definition
8667		data: {
8668			type: 'local',
8669			source: null,
8670			pageSize: 10, // display records per page
8671			saveState: true,
8672
8673			serverPaging: false,
8674			serverFiltering: false,
8675			serverSorting: false,
8676
8677			autoColumns: false,
8678			attr: {
8679				rowProps: [],
8680			},
8681		},
8682
8683		// layout definition
8684		layout: {
8685			theme: 'default', // datatable will support multiple themes and designs
8686			class: pfx + 'datatable-primary', // custom wrapper class
8687			scroll: false, // enable/disable datatable scroll both horizontal and vertical when needed.
8688			height: null, // datatable's body's fixed height
8689			minHeight: null,
8690			footer: false, // display/hide footer
8691			header: true, // display/hide header
8692			customScrollbar: true, // set false to disable custom scrollbar
8693
8694			// datatable spinner
8695			spinner: {
8696				overlayColor: '#000000',
8697				opacity: 0,
8698				type: 'loader',
8699				state: 'primary',
8700				message: true,
8701			},
8702
8703			// datatable UI icons
8704			icons: {
8705				sort: {asc: 'flaticon2-arrow-up', desc: 'flaticon2-arrow-down'},
8706				pagination: {
8707					next: 'flaticon2-next',
8708					prev: 'flaticon2-back',
8709					first: 'flaticon2-fast-back',
8710					last: 'flaticon2-fast-next',
8711					more: 'flaticon-more-1',
8712				},
8713				rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'},
8714			},
8715		},
8716
8717		// column sorting
8718		sortable: true,
8719
8720		// resize column size with mouse drag coming soon)
8721		resizable: false,
8722
8723		// column based filtering (coming soon)
8724		filterable: false,
8725
8726		pagination: true,
8727
8728		// inline and bactch editing (cooming soon)
8729		editable: false,
8730
8731		// columns definition
8732		columns: [],
8733
8734		search: {
8735			// enable trigger search by keyup enter
8736			onEnter: false,
8737			// input text for search
8738			input: null,
8739			// search delay in milliseconds
8740			delay: 400,
8741			//	remote server search key value
8742			key: null
8743		},
8744
8745		rows: {
8746			// deprecated
8747			callback: function() {
8748			},
8749			// call before row template
8750			beforeTemplate: function() {
8751			},
8752			// call after row template
8753			afterTemplate: function() {
8754			},
8755			autoHide: true,
8756		},
8757
8758		// toolbar
8759		toolbar: {
8760			// place pagination and displayInfo blocks according to the array order
8761			layout: ['pagination', 'info'],
8762
8763			// toolbar placement can be at top or bottom or both top and bottom repeated
8764			placement: ['bottom'],  //'top', 'bottom'
8765
8766			// toolbar items
8767			items: {
8768				// pagination
8769				pagination: {
8770					// pagination type(default or scroll)
8771					type: 'default',
8772
8773					// number of pages to display by breakpoints
8774					pages: {
8775						desktop: {
8776							layout: 'default',
8777							pagesNumber: 5,
8778						},
8779						tablet: {
8780							layout: 'default',
8781							pagesNumber: 3,
8782						},
8783						mobile: {
8784							layout: 'compact',
8785						},
8786					},
8787
8788					// navigation buttons
8789					navigation: {
8790						prev: true, // display prev button
8791						next: true, // display next button
8792						first: true, // display first button
8793						last: true, // display last button
8794						more: false // display more button
8795					},
8796
8797					// page size select
8798					pageSizeSelect: [], // display dropdown to select pagination size. -1 is used for "ALl" option
8799				},
8800
8801				// records info
8802				info: true,
8803			},
8804		},
8805
8806		// here we will keep all strings and message used by datatable UI so developer can easiliy translate to any language.
8807		// By default the stirngs will be in the plugin source and here can override it
8808		translate: {
8809			records: {
8810				processing: 'Please wait...',
8811				noRecords: 'No records found',
8812			},
8813			toolbar: {
8814				pagination: {
8815					items: {
8816						default: {
8817							first: 'First',
8818							prev: 'Previous',
8819							next: 'Next',
8820							last: 'Last',
8821							more: 'More pages',
8822							input: 'Page number',
8823							select: 'Select page size',
8824							all: 'all',
8825						},
8826						info: 'Showing {{start}} - {{end}} of {{total}}',
8827					},
8828				},
8829			},
8830		},
8831
8832		extensions: {},
8833	};
8834
8835}(jQuery));
8836
8837"use strict";
8838(function($) {
8839
8840	var pluginName = 'KTDatatable';
8841	var pfx = '';
8842
8843	$.fn[pluginName] = $.fn[pluginName] || {};
8844
8845	/**
8846	 * @param datatable Main datatable plugin instance
8847	 * @param options Extension options
8848	 * @returns {*}
8849	 */
8850	$.fn[pluginName].checkbox = function(datatable, options) {
8851		var Extension = {
8852			selectedAllRows: false,
8853			selectedRows: [],
8854			unselectedRows: [],
8855
8856			init: function() {
8857				if (Extension.selectorEnabled()) {
8858					// reset
8859					datatable.setDataSourceParam(options.vars.selectedAllRows, false);
8860					datatable.stateRemove('checkbox');
8861
8862					// requestIds is not null
8863					if (options.vars.requestIds) {
8864						// request ids in response
8865						datatable.setDataSourceParam(options.vars.requestIds, true);
8866					}
8867
8868					// remove selected checkbox on datatable reload
8869					$(datatable).on(pfx + 'datatable-on-reloaded', function() {
8870						datatable.stateRemove('checkbox');
8871						datatable.setDataSourceParam(options.vars.selectedAllRows, false);
8872						Extension.selectedAllRows = false;
8873						Extension.selectedRows = [];
8874						Extension.unselectedRows = [];
8875					});
8876
8877					// select all on extension init
8878					Extension.selectedAllRows = datatable.getDataSourceParam(options.vars.selectedAllRows);
8879
8880					$(datatable).on(pfx + 'datatable-on-layout-updated', function(e, args) {
8881						if (args.table != $(datatable.wrap).attr('id')) {
8882							return;
8883						}
8884						datatable.ready(function() {
8885							Extension.initVars();
8886							Extension.initEvent();
8887							Extension.initSelect();
8888						});
8889					});
8890
8891					$(datatable).on(pfx + 'datatable-on-check', function(e, ids) {
8892						ids.forEach(function(id) {
8893							Extension.selectedRows.push(id);
8894							// // remove from unselected rows
8895							Extension.unselectedRows = Extension.remove(Extension.unselectedRows, id);
8896						});
8897						var storage = {};
8898						storage['selectedRows'] = Extension.selectedRows.filter(Extension.unique);
8899						storage['unselectedRows'] = Extension.unselectedRows.filter(Extension.unique);
8900						datatable.stateKeep('checkbox', storage);
8901					});
8902					$(datatable).on(pfx + 'datatable-on-uncheck', function(e, ids) {
8903						ids.forEach(function(id) {
8904							Extension.unselectedRows.push(id);
8905							// // remove from selected rows
8906							Extension.selectedRows = Extension.remove(Extension.selectedRows, id);
8907						});
8908						var storage = {};
8909						storage['selectedRows'] = Extension.selectedRows.filter(Extension.unique);
8910						storage['unselectedRows'] = Extension.unselectedRows.filter(Extension.unique);
8911						storage['unselectedRows'] = Extension.unselectedRows.filter(Extension.unique);
8912						datatable.stateKeep('checkbox', storage);
8913					});
8914				}
8915			},
8916
8917			/**
8918			 * Init checkbox clicks event
8919			 */
8920			initEvent: function() {
8921				// select all checkbox click
8922				$(datatable.tableHead).find('.' + pfx + 'checkbox-all > [type="checkbox"]').click(function(e) {
8923					// clear selected and unselected rows
8924					Extension.selectedRows = Extension.unselectedRows = [];
8925					datatable.stateRemove('checkbox');
8926
8927					// select all rows
8928					Extension.selectedAllRows = !!$(this).is(':checked');
8929
8930					// local select all current page rows
8931					if (!options.vars.requestIds) {
8932						if ($(this).is(':checked')) {
8933							Extension.selectedRows = $.makeArray($(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"]').map(function(i, chk) {
8934								return $(chk).val();
8935							}));
8936						}
8937						var storage = {};
8938						storage['selectedRows'] = Extension.selectedRows.filter(Extension.unique);
8939						datatable.stateKeep('checkbox', storage);
8940					}
8941
8942					// keep selectedAllRows in datasource params
8943					datatable.setDataSourceParam(options.vars.selectedAllRows, Extension.selectedAllRows);
8944
8945					$(datatable).trigger(pfx + 'datatable-on-click-checkbox', [$(this)]);
8946				});
8947
8948				// single row checkbox click
8949				$(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"]').click(function(e) {
8950					var id = $(this).val();
8951					if ($(this).is(':checked')) {
8952						Extension.selectedRows.push(id);
8953						// remove from unselected rows
8954						Extension.unselectedRows = Extension.remove(Extension.unselectedRows, id);
8955					}
8956					else {
8957						Extension.unselectedRows.push(id);
8958						// remove from selected rows
8959						Extension.selectedRows = Extension.remove(Extension.selectedRows, id);
8960					}
8961
8962					// local checkbox header check
8963					if (!options.vars.requestIds && Extension.selectedRows.length < 1) {
8964						// remove select all checkbox, if there is no checked checkbox left
8965						$(datatable.tableHead).find('.' + pfx + 'checkbox-all > [type="checkbox"]').prop('checked', false);
8966					}
8967
8968					var storage = {};
8969					storage['selectedRows'] = Extension.selectedRows.filter(Extension.unique);
8970					storage['unselectedRows'] = Extension.unselectedRows.filter(Extension.unique);
8971					datatable.stateKeep('checkbox', storage);
8972
8973					$(datatable).trigger(pfx + 'datatable-on-click-checkbox', [$(this)]);
8974				});
8975			},
8976
8977			unique: function(value, index, self) {
8978				return self.indexOf(value) === index;
8979			},
8980
8981			initSelect: function() {
8982				// selected all rows from server
8983				if (Extension.selectedAllRows && options.vars.requestIds) {
8984					if (!datatable.hasClass(pfx + 'datatable-error')) {
8985						// set header select all checkbox checked
8986						$(datatable.tableHead).find('.' + pfx + 'checkbox-all > [type="checkbox"]').prop('checked', true);
8987					}
8988
8989					// set all checkbox in table body
8990					datatable.setActiveAll(true);
8991
8992					// remove unselected rows
8993					Extension.unselectedRows.forEach(function(id) {
8994						datatable.setInactive(id);
8995					});
8996
8997				}
8998				else {
8999					// single check for server and local
9000					Extension.selectedRows.forEach(function(id) {
9001						datatable.setActive(id);
9002					});
9003
9004					// local checkbox; check if all checkboxes of currect page are checked
9005					if (!datatable.hasClass(pfx + 'datatable-error') && $(datatable.tableBody).find('.' + pfx + 'checkbox-single > [type="checkbox"]').not(':checked').length < 1) {
9006						// set header select all checkbox checked
9007						$(datatable.tableHead).find('.' + pfx + 'checkbox-all > [type="checkbox"]').prop('checked', true);
9008					}
9009				}
9010			},
9011
9012			/**
9013			 * Check if selector is enabled from options
9014			 */
9015			selectorEnabled: function() {
9016				return $.grep(datatable.options.columns, function(n, i) {
9017					return n.selector || false;
9018				})[0];
9019			},
9020
9021			initVars: function() {
9022				// get single select/unselect from localstorage
9023				var storage = datatable.stateGet('checkbox');
9024				if (typeof storage !== 'undefined') {
9025					Extension.selectedRows = storage['selectedRows'] || [];
9026					Extension.unselectedRows = storage['unselectedRows'] || [];
9027				}
9028			},
9029
9030			getSelectedId: function(path) {
9031				Extension.initVars();
9032
9033				// server selected all rows
9034				if (Extension.selectedAllRows && options.vars.requestIds) {
9035					if (typeof path === 'undefined') {
9036						path = options.vars.rowIds;
9037					}
9038
9039					// if selected all rows, return id from response meta
9040					var selectedAllRows = datatable.getObject(path, datatable.lastResponse) || [];
9041
9042					if (selectedAllRows.length > 0) {
9043						// remove single unselected rows from selectedAllRows ids from server response emta
9044						Extension.unselectedRows.forEach(function(id) {
9045							selectedAllRows = Extension.remove(selectedAllRows, parseInt(id));
9046						});
9047					}
9048					return selectedAllRows.filter(Extension.unique);
9049				}
9050
9051				// else return single checked selected rows
9052				return Extension.selectedRows.filter(Extension.unique);
9053			},
9054
9055			remove: function(array, element) {
9056				return array.filter(function(e) {
9057					return e !== element;
9058				});
9059			},
9060		};
9061
9062		// make the extension accessible from datatable init
9063		datatable.checkbox = function() {
9064			return Extension;
9065		};
9066
9067		if (typeof options === 'object') {
9068			options = $.extend(true, {}, $.fn[pluginName].checkbox.default, options);
9069			Extension.init.apply(this, [options]);
9070		}
9071
9072		return datatable;
9073	};
9074
9075	$.fn[pluginName].checkbox.default = {
9076		vars: {
9077			// select all rows flag to be sent to the server
9078			selectedAllRows: 'selectedAllRows',
9079			// request id parameter's name
9080			requestIds: 'requestIds',
9081			// response path to all rows id
9082			rowIds: 'meta.rowIds',
9083		},
9084	};
9085
9086}(jQuery));
9087
9088var defaults = {
9089	layout: {
9090		icons: {
9091			pagination: {
9092				next: 'flaticon2-next',
9093				prev: 'flaticon2-back',
9094				first: 'flaticon2-fast-back',
9095				last: 'flaticon2-fast-next',
9096				more: 'flaticon-more-1',
9097			},
9098			rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'},
9099		}
9100	}
9101};
9102
9103if (KTUtil.isRTL()) {
9104	defaults = {
9105		layout: {
9106			icons: {
9107				pagination: {
9108					next: 'flaticon2-back',
9109					prev: 'flaticon2-next',
9110					first: 'flaticon2-fast-next',
9111					last: 'flaticon2-fast-back',
9112				},
9113				rowDetail: {collapse: 'fa fa-caret-down', expand: 'fa fa-caret-right'},
9114			}
9115		}
9116	}
9117}
9118
9119$.extend(true, $.fn.KTDatatable.defaults, defaults);
9120
9121"use strict";
9122
9123// Initialization
9124KTUtil.ready(function() {
9125    ////////////////////////////////////////////////////
9126    // Layout Base Partials(mandatory for core layout)//
9127    ////////////////////////////////////////////////////
9128
9129    // Init Desktop & Mobile Headers
9130    if (typeof KTLayoutHeader !== 'undefined') {
9131        KTLayoutHeader.init('kt_header', 'kt_header_mobile');
9132    }
9133
9134    // Init Header Menu
9135    if (typeof KTLayoutHeaderMenu !== 'undefined') {
9136        KTLayoutHeaderMenu.init('kt_header_menu', 'kt_header_menu_wrapper');
9137    }
9138
9139    // Init Header Topbar For Mobile Mode
9140    if (typeof KTLayoutHeaderTopbar !== 'undefined') {
9141        KTLayoutHeaderTopbar.init('kt_header_mobile_topbar_toggle');
9142    }
9143
9144    // Init Brand Panel For Logo
9145    if (typeof KTLayoutBrand !== 'undefined') {
9146        KTLayoutBrand.init('kt_brand');
9147    }
9148
9149    // Init Aside
9150    if (typeof KTLayoutAside !== 'undefined') {
9151        KTLayoutAside.init('kt_aside');
9152    }
9153
9154    // Init Aside Menu Toggle
9155    if (typeof KTLayoutAsideToggle !== 'undefined') {
9156        KTLayoutAsideToggle.init('kt_aside_toggle');
9157    }
9158
9159    // Init Aside Menu
9160    if (typeof KTLayoutAsideMenu !== 'undefined') {
9161        KTLayoutAsideMenu.init('kt_aside_menu');
9162    }
9163
9164    // Init Subheader
9165    if (typeof KTLayoutSubheader !== 'undefined') {
9166        KTLayoutSubheader.init('kt_subheader');
9167    }
9168
9169    // Init Content
9170    if (typeof KTLayoutContent !== 'undefined') {
9171        KTLayoutContent.init('kt_content');
9172    }
9173
9174    // Init Footer
9175    if (typeof KTLayoutFooter !== 'undefined') {
9176        KTLayoutFooter.init('kt_footer');
9177    }
9178
9179
9180    //////////////////////////////////////////////
9181    // Layout Extended Partials(optional to use)//
9182    //////////////////////////////////////////////
9183
9184    // Init Scrolltop
9185    if (typeof KTLayoutScrolltop !== 'undefined') {
9186        KTLayoutScrolltop.init('kt_scrolltop');
9187    }
9188
9189    // Init Sticky Card
9190    if (typeof KTLayoutStickyCard !== 'undefined') {
9191        KTLayoutStickyCard.init('kt_page_sticky_card');
9192    }
9193
9194    // Init Stretched Card
9195    if (typeof KTLayoutStretchedCard !== 'undefined') {
9196        KTLayoutStretchedCard.init('kt_page_stretched_card');
9197    }
9198
9199    // Init Code Highlighter & Preview Blocks(used to demonstrate the theme features)
9200    if (typeof KTLayoutExamples !== 'undefined') {
9201        KTLayoutExamples.init();
9202    }
9203
9204    // Init Demo Selection Panel
9205    if (typeof KTLayoutDemoPanel !== 'undefined') {
9206        KTLayoutDemoPanel.init('kt_demo_panel');
9207    }
9208
9209    // Init Chat App(quick modal chat)
9210    if (typeof KTLayoutChat !== 'undefined') {
9211        KTLayoutChat.init('kt_chat_modal');
9212    }
9213
9214    // Init Quick Actions Offcanvas Panel
9215    if (typeof KTLayoutQuickActions !== 'undefined') {
9216        KTLayoutQuickActions.init('kt_quick_actions');
9217    }
9218
9219    // Init Quick Notifications Offcanvas Panel
9220    if (typeof KTLayoutQuickNotifications !== 'undefined') {
9221        KTLayoutQuickNotifications.init('kt_quick_notifications');
9222    }
9223
9224    // Init Quick Offcanvas Panel
9225    if (typeof KTLayoutQuickPanel!== 'undefined') {
9226        KTLayoutQuickPanel.init('kt_quick_panel');
9227    }
9228
9229    // Init Quick User Panel
9230    if (typeof KTLayoutQuickUser !== 'undefined') {
9231        KTLayoutQuickUser.init('kt_quick_user');
9232    }
9233
9234    // Init Quick Search Panel
9235    if (typeof KTLayoutQuickSearch !== 'undefined') {
9236        KTLayoutQuickSearch.init('kt_quick_search');
9237    }
9238
9239    // Init Quick Cart Panel
9240    if (typeof KTLayoutQuickCartPanel !== 'undefined') {
9241        KTLayoutQuickCartPanel.init('kt_quick_cart');
9242    }
9243
9244    // Init Search For Quick Search Dropdown
9245    if (typeof KTLayoutSearch !== 'undefined') {
9246        KTLayoutSearch().init('kt_quick_search_dropdown');
9247    }
9248
9249    // Init Search For Quick Search Offcanvas Panel
9250    if (typeof KTLayoutSearchOffcanvas !== 'undefined') {
9251        KTLayoutSearchOffcanvas().init('kt_quick_search_offcanvas');
9252    }
9253});
9254
9255"use strict";
9256
9257var KTLayoutAsideMenu = function() {
9258    // Private properties
9259    var _body;
9260    var _element;
9261    var _menuObject;
9262
9263	// Initialize
9264	var _init = function() {
9265		var menuDesktopMode = (KTUtil.attr(_element, 'data-menu-dropdown') === '1' ? 'dropdown' : 'accordion');
9266        var scroll;
9267
9268		if (KTUtil.attr(_element, 'data-menu-scroll') === '1') {
9269			scroll = {
9270				rememberPosition: true, // remember position on page reload
9271				height: function() { // calculate available scrollable area height
9272					var height = parseInt(KTUtil.getViewPort().height);
9273
9274					if (KTUtil.isBreakpointUp('lg')) {
9275						height = height - KTLayoutBrand.getHeight();
9276					}
9277
9278					height = height - (parseInt(KTUtil.css(_element, 'marginBottom')) + parseInt(KTUtil.css(_element, 'marginTop')));
9279
9280					return height;
9281				}
9282			};
9283		}
9284
9285		_menuObject = new KTMenu(_element, {
9286			// Vertical scroll
9287			scroll: scroll,
9288
9289			// Submenu setup
9290			submenu: {
9291				desktop: menuDesktopMode,
9292				tablet: 'accordion', // menu set to accordion in tablet mode
9293				mobile: 'accordion' // menu set to accordion in mobile mode
9294			},
9295
9296			// Accordion setup
9297			accordion: {
9298				expandAll: false // allow having multiple expanded accordions in the menu
9299			}
9300		});
9301	}
9302
9303    var _initHover = function() {
9304        // Handle Minimized Aside Hover
9305		if (KTUtil.hasClass(_body, 'aside-fixed') && KTUtil.hasClass(_body, 'aside-minimize-hoverable')) {
9306			var insideTm;
9307			var outsideTm;
9308
9309            // Handle Aside Hover Mode
9310			KTUtil.addEvent(_element, 'mouseenter', function(e) {
9311				e.preventDefault();
9312
9313				if (KTUtil.isBreakpointUp('lg') === false) {
9314					return;
9315				}
9316
9317				if (outsideTm) {
9318					clearTimeout(outsideTm);
9319					outsideTm = null;
9320				}
9321
9322                if (insideTm) {
9323					clearTimeout(insideTm);
9324					insideTm = null;
9325				}
9326
9327				insideTm = setTimeout(function() {
9328					if (KTUtil.hasClass(_body, 'aside-minimize') && KTUtil.isBreakpointUp('lg')) {
9329						// Hover class
9330						KTUtil.addClass(_body, 'aside-minimize-hover');
9331
9332						KTLayoutAsideMenu.getMenu().scrollUpdate();
9333						KTLayoutAsideMenu.getMenu().scrollTop();
9334					}
9335				}, 50);
9336			});
9337
9338			KTUtil.addEvent(KTLayoutAside.getElement(), 'mouseleave', function(e) {
9339				e.preventDefault();
9340
9341				if (KTUtil.isBreakpointUp('lg') === false) {
9342					return;
9343				}
9344
9345				if (insideTm) {
9346					clearTimeout(insideTm);
9347					insideTm = null;
9348				}
9349
9350                if (outsideTm) {
9351					clearTimeout(outsideTm);
9352					outsideTm = null;
9353				}
9354
9355				outsideTm = setTimeout(function() {
9356				    if (KTUtil.hasClass(_body, 'aside-minimize-hover') && KTUtil.isBreakpointUp('lg')) {
9357					    KTUtil.removeClass(_body, 'aside-minimize-hover');
9358
9359						// Hover class
9360                        KTLayoutAsideMenu.getMenu().scrollUpdate();
9361						KTLayoutAsideMenu.getMenu().scrollTop();
9362					}
9363				}, 100);
9364			});
9365		}
9366	}
9367
9368    // Public methods
9369	return {
9370		init: function(id) {
9371            _body = KTUtil.getBody();
9372            _element = KTUtil.getById(id);
9373
9374            if (!_element) {
9375                return;
9376            }
9377
9378            // Initialize menu
9379            _init();
9380            _initHover();
9381		},
9382
9383		getElement: function() {
9384			return _element;
9385		},
9386
9387        getMenu: function() {
9388			return _menuObject;
9389		},
9390
9391        pauseDropdownHover: function(time) {
9392			if (_menuObject) {
9393				_menuObject.pauseDropdownHover(time);
9394			}
9395		},
9396
9397		closeMobileOffcanvas: function() {
9398			if (_menuObject && KTUtil.isMobileDevice()) {
9399				_menuObject.hide();
9400			}
9401		}
9402	};
9403}();
9404
9405// Webpack support
9406if (typeof module !== 'undefined') {
9407	module.exports = KTLayoutAsideMenu;
9408}
9409
9410"use strict";
9411
9412var KTLayoutAsideToggle = function() {
9413    // Private properties
9414    var _body;
9415    var _element;
9416    var _toggleObject;
9417
9418	// Initialize
9419	var _init = function() {
9420		_toggleObject = new KTToggle(_element, _body, {
9421			targetState: 'aside-minimize',
9422			toggleState: 'active'
9423		});
9424
9425		_toggleObject.on('toggle', function(toggle) {
9426            // Update sticky card
9427            if (typeof KTLayoutStickyCard !== 'undefined') {
9428                KTLayoutStickyCard.update();
9429            }
9430
9431            // Pause header menu dropdowns
9432            if (typeof KTLayoutHeaderMenu !== 'undefined') {
9433                KTLayoutHeaderMenu.pauseDropdownHover(800);
9434            }
9435
9436            // Pause aside menu dropdowns
9437            if (typeof KTLayoutAsideMenu !== 'undefined') {
9438                KTLayoutAsideMenu.pauseDropdownHover(800);
9439            }
9440
9441            // Remember state in cookie
9442			KTCookie.setCookie('kt_aside_toggle_state', toggle.getState());
9443			// to set default minimized left aside use this cookie value in y
9443our
9444			// server side code and add "kt-primary--minimize aside-minimize" classes to
9445			// the body tag in order to initialize the minimized left aside mode during page loading.
9446		});
9447
9448		_toggleObject.on('beforeToggle', function(toggle) {
9449			if (KTUtil.hasClass(_body, 'aside-minimize') === false && KTUtil.hasClass(_body, 'aside-minimize-hover')) {
9450				KTUtil.removeClass(_body, 'aside-minimize-hover');
9451			}
9452		});
9453	}
9454
9455    // Public methods
9456	return {
9457		init: function(id) {
9458            _element = KTUtil.getById(id);
9459            _body = KTUtil.getBody();
9460
9461            if (!_element) {
9462                return;
9463            }
9464
9465            // Initialize
9466            _init();
9467		},
9468
9469        getElement: function() {
9470            return _element;
9471        },
9472
9473        getToggle: function() {
9474			return _toggleObject;
9475		},
9476
9477		onToggle: function(handler) {
9478			if (typeof _toggleObject.element !== 'undefined') {
9479				_toggleObject.on('toggle', handler);
9480			}
9481		}
9482	};
9483}();
9484
9485// Webpack support
9486if (typeof module !== 'undefined') {
9487	module.exports = KTLayoutAsideToggle;
9488}
9489
9490"use strict";
9491
9492var KTLayoutAside = function() {
9493    // Private properties
9494    var _body;
9495    var _element;
9496    var _offcanvasObject;
9497
9498    // Private functions
9499	// Initialize
9500	var _init = function() {
9501		var offcanvasClass = KTUtil.hasClass(_element, 'aside-offcanvas-default') ? 'aside-offcanvas-default' : 'aside';
9502
9503        // Initialize mobile aside offcanvas
9504		_offcanvasObject = new KTOffcanvas(_element, {
9505			baseClass: offcanvasClass,
9506			overlay: true,
9507			closeBy: 'kt_aside_close_btn',
9508			toggleBy: {
9509				target: 'kt_aside_mobile_toggle',
9510				state: 'mobile-toggle-active'
9511			}
9512		});
9513	}
9514
9515    // Public methods
9516	return {
9517		init: function(id) {
9518            _element = KTUtil.getById(id);
9519            _body = KTUtil.getBody();
9520
9521            if (!_element) {
9522                return;
9523            }
9524
9525            // Initialize
9526            _init();
9527        },
9528
9529        getElement: function() {
9530            return _element;
9531        },
9532
9533        getOffcanvas: function() {
9534            return _offcanvasObject;
9535        },
9536
9537        isFixed: function() {
9538            return KTUtil.hasClass(_body, 'aside-fixed');
9539        },
9540
9541        isMinimized: function() {
9542            return (KTUtil.hasClass(_body, 'aside-fixed') && KTUtil.hasClass(_body, 'aside-minimize'));
9543        },
9544
9545        isHoverable: function() {
9546            return (KTUtil.hasClass(_body, 'aside-fixed') && KTUtil.hasClass(_body, 'aside-minimize-hoverable'));
9547        }
9548	};
9549}();
9550
9551// Webpack support
9552if (typeof module !== 'undefined') {
9553	module.exports = KTLayoutAside;
9554}
9555
9556"use strict";
9557
9558var KTLayoutBrand = function() {
9559    // Private properties
9560    var _element;
9561
9562    // Private functions
9563    var _getHeight = function() {
9564        var height = 0;
9565
9566        if (_element) {
9567            height = KTUtil.actualHeight(_element);
9568        }
9569
9570        return height;
9571    }
9572
9573    // Public methods
9574	return {
9575		init: function(id) {
9576            _element = KTUtil.getById(id);
9577
9578            if (!_element) {
9579                return;
9580            }
9581		},
9582
9583        getElement: function() {
9584            return _element;
9585        },
9586
9587        getHeight: function() {
9588            return _getHeight();
9589        }
9590	};
9591}();
9592
9593// Webpack support
9594if (typeof module !== 'undefined') {
9595	module.exports = KTLayoutBrand;
9596}
9597
9598"use strict";
9599
9600var KTLayoutContent = function() {
9601    // Private properties
9602    var _element;
9603
9604	// Private functions
9605	var _getHeight = function() {
9606		var height;
9607
9608		height = KTUtil.getViewPort().height;
9609
9610        if (_element) {
9611            height = height - parseInt(KTUtil.css(_element, 'paddingTop')) - parseInt(KTUtil.css(_element, 'paddingBottom'));
9612        }
9613
9614        height = height - KTLayoutHeader.getHeight();
9615        height = height - KTLayoutSubheader.getHeight();
9616        height = height - KTLayoutFooter.getHeight();
9617
9618		return height;
9619	}
9620
9621    // Public methods
9622	return {
9623		init: function(id) {
9624            _element = KTUtil.getById(id);
9625		},
9626
9627		getHeight: function() {
9628			return _getHeight();
9629		},
9630
9631        getElement: function() {
9632            return _element;
9633        }
9634	};
9635}();
9636
9637// Webpack support
9638if (typeof module !== 'undefined') {
9639	module.exports = KTLayoutContent;
9640}
9641
9642"use strict";
9643
9644var KTLayoutFooter = function() {
9645    // Private properties
9646    var _element;
9647
9648	// Private functions
9649	var _getHeight = function() {
9650		var height = 0;
9651
9652        if (_element) {
9653            height = KTUtil.actualHeight(_element);
9654        }
9655
9656		return height;
9657	}
9658
9659    // Public methods
9660	return {
9661		init: function(id) {
9662            _element = KTUtil.getById(id);
9663		},
9664
9665		getHeight: function() {
9666			return _getHeight();
9667		},
9668
9669        getElement: function() {
9670            return _element;
9671        }
9672	};
9673}();
9674
9675// Webpack support
9676if (typeof module !== 'undefined') {
9677	module.exports = KTLayoutFooter;
9678}
9679
9680"use strict";
9681
9682var KTLayoutHeaderMenu = function() {
9683    // Private properties
9684	var _menuElement;
9685    var _menuObject;
9686    var _offcanvasElement;
9687    var _offcanvasObject;
9688
9689    // Private functions
9690	var _init = function() {
9691		_offcanvasObject = new KTOffcanvas(_offcanvasElement, {
9692			overlay: true,
9693			baseClass: 'header-menu-wrapper',
9694			closeBy: 'kt_header_menu_mobile_close_btn',
9695			toggleBy: {
9696				target: 'kt_header_mobile_toggle',
9697				state: 'mobile-toggle-active'
9698			}
9699		});
9700		
9701		_menuObject = new KTMenu(_menuElement, {
9702			submenu: {
9703				desktop: 'dropdown',
9704				tablet: 'accordion',
9705				mobile: 'accordion'
9706			},
9707			accordion: {
9708				slideSpeed: 200, // accordion toggle slide speed in milliseconds
9709				expandAll: false // allow having multiple expanded accordions in the menu
9710			}
9711		});
9712
9713		// Close aside offcanvas panel before page reload On tablet and mobile
9714        _menuObject.on('linkClick', function(menu) {
9715            if (KTUtil.isBreakpointDown('lg')) { // Tablet and mobile mode
9716                _offcanvasObject.hide(); // Hide offcanvas after general link click
9717            }
9718        });
9719	}
9720
9721    // Public methods
9722	return {
9723        init: function(menuId, offcanvasId) {
9724            _menuElement = KTUtil.getById(menuId);
9725            _offcanvasElement = KTUtil.getById(offcanvasId);
9726
9727            if (!_menuElement) {
9728                return;
9729            }
9730
9731            // Initialize menu
9732            _init();
9733		},
9734
9735		getMenuElement: function() {
9736			return _menuElement;
9737		},
9738
9739        getOffcanvasElement: function() {
9740			return _offcanvasElement;
9741		},
9742
9743        getMenu: function() {
9744			return _menuObject;
9745		},
9746
9747		pauseDropdownHover: function(time) {
9748			if (_menuObject) {
9749				_menuObject.pauseDropdownHover(time);
9750			}
9751		},
9752
9753        getOffcanvas: function() {
9754			return _offcanvasObject;
9755		},
9756
9757		closeMobileOffcanvas: function() {
9758			if (_menuObject && KTUtil.isMobileDevice()) {
9759				_offcanvasObject.hide();
9760			}
9761		}
9762	};
9763}();
9764
9765// Webpack support
9766if (typeof module !== 'undefined') {
9767	module.exports = KTLayoutHeaderMenu;
9768}
9769
9770"use strict";
9771
9772var KTLayoutHeaderTopbar = function() {
9773    // Private properties
9774	var _toggleElement;
9775    var _toggleObject;
9776
9777    // Private functions
9778    var _init = function() {
9779        _toggleObject = new KTToggle(_toggleElement, KTUtil.getBody(), {
9780            targetState: 'topbar-mobile-on',
9781            toggleState: 'active',
9782        });
9783    }
9784
9785    // Public methods
9786	return {
9787		init: function(id) {
9788            _toggleElement = KTUtil.getById(id);
9789
9790			if (!_toggleElement) {
9791                return;
9792            }
9793
9794            // Initialize
9795            _init();
9796		},
9797
9798        getToggleElement: function() {
9799            return _toggleElement;
9800        }
9801	};
9802}();
9803
9804// Webpack support
9805if (typeof module !== 'undefined') {
9806	module.exports = KTLayoutHeaderTopbar;
9807}
9808
9809"use strict";
9810
9811var KTLayoutHeader = function() {
9812    // Private properties
9813    var _element;
9814    var _elementForMobile;
9815    var _object;
9816
9817	// Private functions
9818    // Get Height
9819    var _getHeight = function() {
9820        var height = 0;
9821
9822        if (_element) {
9823            height = KTUtil.actualHeight(_element) + 1;
9824        }
9825
9826        return height;
9827    }
9828
9829    // Get Height
9830    var _getHeightForMobile = function() {
9831        var height;
9832
9833        height = KTUtil.actualHeight(_elementForMobile);
9834
9835        return height;
9836    }
9837
9838    // Public Methods
9839	return {
9840		init: function(id, idForMobile) {
9841            _element = KTUtil.getById(id);
9842            _elementForMobile = KTUtil.getById(idForMobile);
9843
9844            if (!_element) {
9845                return;
9846            }
9847		},
9848
9849        isFixed: function() {
9850            return KTUtil.hasClass(KTUtil.getBody(), 'header-fixed')
9851        },
9852
9853        isFixedForMobile: function() {
9854            return KTUtil.hasClass(KTUtil.getBody(), 'header-mobile-fixed')
9855        },
9856
9857        getElement: function() {
9858            return _element;
9859        },
9860
9861        getElementForMobile: function() {
9862            return _elementForMobile;
9863        },
9864
9865        getHeader: function() {
9866            return _object;
9867        },
9868
9869        getHeight: function() {
9870            return _getHeight();
9871        },
9872
9873        getHeightForMobile: function() {
9874            return _getHeightForMobile();
9875        }
9876	};
9877}();
9878
9879// Webpack support
9880if (typeof module !== 'undefined') {
9881	module.exports = KTLayoutHeader;
9882}
9883
9884"use strict";
9885
9886var KTLayoutStickyCard = function() {
9887    // Private properties
9888	var _element;
9889    var _object;
9890
9891	// Private functions
9892	var _init = function() {
9893		var offset = 300;
9894
9895		if (typeof KTLayoutHeader !== 'undefined') {
9896			offset = KTLayoutHeader.getHeight();
9897		}
9898
9899        _object = new KTCard(_element, {
9900			sticky: {
9901				offset: offset,
9902				zIndex: 90,
9903				position: {
9904					top: function() {
9905						var pos = 0;
9906                        var body = KTUtil.getBody();
9907
9908						if (KTUtil.isBreakpointUp('lg')) {
9909							if (typeof KTLayoutHeader !== 'undefined' && KTLayoutHeader.isFixed()) {
9910								pos = pos + KTLayoutHeader.getHeight();
9911							}
9912
9913							if (typeof KTLayoutSubheader !== 'undefined' && KTLayoutSubheader.isFixed()) {
9914								pos = pos + KTLayoutSubheader.getHeight();
9915							}
9916						} else {
9917							if (typeof KTLayoutHeader !== 'undefined' && KTLayoutHeader.isFixedForMobile()) {
9918								pos = pos + KTLayoutHeader.getHeightForMobile();
9919							}
9920						}
9921
9922						pos = pos - 1; // remove header border width
9923
9924						return pos;
9925					},
9926					left: function(card) {
9927						return KTUtil.offset(_element).left;
9928					},
9929					right: function(card) {
9930						var body = KTUtil.getBody();
9931
9932						var cardWidth = parseInt(KTUtil.css(_element, 'width'));
9933						var bodyWidth = parseInt(KTUtil.css(body, 'width'));
9934						var cardOffsetLeft = KTUtil.offset(_element).left;
9935
9936						return bodyWidth - cardWidth - cardOffsetLeft;
9937					}
9938				}
9939			}
9940		});
9941
9942		_object.initSticky();
9943
9944		KTUtil.addResizeHandler(function() {
9945			_object.updateSticky();
9946		});
9947	}
9948
9949    // Public methods
9950	return {
9951		init: function(id) {
9952            _element = KTUtil.getById(id);
9953
9954            if (!_element) {
9955                return;
9956            }
9957
9958            // Initialize
9959			_init();
9960		},
9961
9962		update: function() {
9963			if (_object) {
9964				_object.updateSticky();
9965			}
9966		}
9967	};
9968}();
9969
9970// Webpack support
9971if (typeof module !== 'undefined') {
9972	module.exports = KTLayoutStickyCard;
9973}
9974
9975"use strict";
9976
9977var KTLayoutStretchedCard = function() {
9978    // Private properties
9979	var _element;
9980
9981	// Private functions
9982	var _init = function() {
9983		var scroll = KTUtil.find(_element, '.card-scroll');
9984		var cardBody = KTUtil.find(_element, '.card-body');
9985		var cardHeader = KTUtil.find(_element, '.card-header');
9986
9987		var height = KTLayoutContent.getHeight();
9988
9989		height = height - parseInt(KTUtil.actualHeight(cardHeader));
9990
9991		height = height - parseInt(KTUtil.css(_element, 'marginTop')) - parseInt(KTUtil.css(_element, 'marginBottom'));
9992		height = height - parseInt(KTUtil.css(_element, 'paddingTop')) - parseInt(KTUtil.css(_element, 'paddingBottom'));
9993
9994		height = height - parseInt(KTUtil.css(cardBody, 'paddingTop')) - parseInt(KTUtil.css(cardBody, 'paddingBottom'));
9995		height = height - parseInt(KTUtil.css(cardBody, 'marginTop')) - parseInt(KTUtil.css(cardBody, 'marginBottom'));
9996
9997		height = height - 3;
9998
9999		KTUtil.css(scroll, 'height', height + 'px');
10000	}
10001
10002    // Public methods
10003	return {
10004		init: function(id) {
10005            _element = KTUtil.getById(id);
10006
10007            if (!_element) {
10008                return;
10009            }
10010
10011            // Initialize
10012			_init();
10013
10014            // Re-calculate on window resize
10015            KTUtil.addResizeHandler(function() {
10016				_init();
10017			});
10018		},
10019
10020		update: function() {
10021			_init();
10022		}
10023	};
10024}();
10025
10026// Webpack support
10027if (typeof module !== 'undefined') {
10028	module.exports = KTLayoutStretchedCard;
10029}
10030
10031"use strict";
10032
10033var KTLayoutSubheader = function() {
10034    // Private properties
10035    var _element;
10036
10037    // Private functions
10038    var _getHeight = function() {
10039        var height = 0;
10040
10041        if (_element) {
10042            height = KTUtil.actualHeight(_element);
10043        }
10044
10045        return height;
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
10058        isFixed: function() {
10059            return KTUtil.hasClass(KTUtil.getBody(), 'subheader-fixed');
10060        },
10061
10062        getElement: function() {
10063            return _element;
10064        },
10065
10066        getHeight: function() {
10067            return _getHeight();
10068        }
10069	};
10070}();
10071
10072// Webpack support
10073if (typeof module !== 'undefined') {
10074	module.exports = KTLayoutSubheader;
10075}
10076
10077"use strict";
10078
10079// Class definition
10080var KTLayoutChat = function () {
10081	// Private functions
10082	var _init = function (element) {
10083		var scrollEl = KTUtil.find(element, '.scroll');
10084		var cardBodyEl = KTUtil.find(element, '.card-body');
10085		var cardHeaderEl = KTUtil.find(element, '.card-header');
10086		var cardFooterEl = KTUtil.find(element, '.card-footer');
10087
10088		if (!scrollEl) {
10089			return;
10090		}
10091
10092		// initialize perfect scrollbar(see:  https://github.com/utatti/perfect-scrollbar)
10093		KTUtil.scrollInit(scrollEl, {
10094			windowScroll: false, // allow browser scroll when the scroll reaches the end of the side
10095			mobileNativeScroll: true,  // enable native scroll for mobile
10096			desktopNativeScroll: false, // disable native scroll and use custom scroll for desktop
10097			resetHeightOnDestroy: true,  // reset css height on scroll feature destroyed
10098			handleWindowResize: true, // recalculate hight on window resize
10099			rememberPosition: true, // remember scroll position in cookie
10100			height: function() {  // calculate height
10101				var height;
10102
10103				if (KTUtil.isBreakpointDown('lg')) { // Mobile mode
10104					return KTUtil.hasAttr(scrollEl, 'data-mobile-height') ? parseInt(KTUtil.attr(scrollEl, 'data-mobile-height')) : 400;
10105				} else if (KTUtil.isBreakpointUp('lg') && KTUtil.hasAttr(scrollEl, 'data-height')) { // Desktop Mode
10106					return parseInt(KTUtil.attr(scrollEl, 'data-height'));
10107				} else {
10108					height = KTLayoutContent.getHeight();
10109
10110					if (scrollEl) {
10111						height = height - parseInt(KTUtil.css(scrollEl, 'margin-top')) - parseInt(KTUtil.css(scrollEl, 'margin-bottom'));
10112					}
10113
10114					if (cardHeaderEl) {
10115						height = height - parseInt(KTUtil.css(cardHeaderEl, 'height'));
10116						height = height - parseInt(KTUtil.css(cardHeaderEl, 'margin-top')) - parseInt(KTUtil.css(cardHeaderEl, 'margin-bottom'));
10117					}
10118
10119					if (cardBodyEl) {
10120						height = height - parseInt(KTUtil.css(cardBodyEl, 'padding-top')) - parseInt(KTUtil.css(cardBodyEl, 'padding-bottom'));
10121					}
10122
10123					if (cardFooterEl) {
10124						height = height - parseInt(KTUtil.css(cardFooterEl, 'height'));
10125						height = height - parseInt(KTUtil.css(cardFooterEl, 'margin-top')) - parseInt(KTUtil.css(cardFooterEl, 'margin-bottom'));
10126					}
10127				}
10128
10129				// Remove additional space
10130				height = height - 2;
10131
10132				return height;
10133			}
10134		});
10135
10136		// attach events
10137		KTUtil.on(element, '.card-footer textarea', 'keydown', function(e) {
10138			if (e.keyCode == 13) {
10139				_handeMessaging(element);
10140				e.preventDefault();
10141
10142				return false;
10143			}
10144		});
10145
10146		KTUtil.on(element, '.card-footer .chat-send', 'click', function(e) {
10147			_handeMessaging(element);
10148		});
10149	}
10150
10151	var _handeMessaging = function(element) {
10152		var messagesEl = KTUtil.find(element, '.messages');
10153		var scrollEl = KTUtil.find(element, '.scroll');
10154        var textarea = KTUtil.find(element, 'textarea');
10155
10156        if (textarea.value.length === 0 ) {
10157            return;
10158        }
10159
10160		var node = document.createElement("DIV");
10161		KTUtil.addClass(node, 'd-flex flex-column mb-5 align-items-end');
10162
10163		var html = '';
10164		html += '<div class="d-flex align-items-center">';
10165		html += '	<div>';
10166		html += '		<span class="text-muted font-size-sm">2 Hours</span>';
10167		html += '		<a href="#" class="text-dark-75 text-hover-primary font-weight-bold font-size-h6">You</a>';
10168		html += '	</div>';
10169		html += '	<div class="symbol symbol-circle symbol-40 ml-3">';
10170		html += '		<img alt="Pic" src="assets/media/users/300_12.jpg"/>';
10171		html += '	</div>';
10172		html += '</div>';
10173		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>';
10174
10175		KTUtil.setHTML(node, html);
10176		messagesEl.appendChild(node);
10177		textarea.value = '';
10178		scrollEl.scrollTop = parseInt(KTUtil.css(messagesEl, 'height'));
10179
10180		var ps;
10181		if (ps = KTUtil.data(scrollEl).get('ps')) {
10182			ps.update();
10183		}
10184
10185		setTimeout(function() {
10186			var node = document.createElement("DIV");
10187			KTUtil.addClass(node, 'd-flex flex-column mb-5 align-items-start');
10188
10189			var html = '';
10190			html += '<div class="d-flex align-items-center">';
10191			html += '	<div class="symbol symbol-circle symbol-40 mr-3">';
10192			html += '		<img alt="Pic" src="assets/media/users/300_12.jpg"/>';
10193			html += '	</div>';
10194			html += '	<div>';
10195			html += '		<a href="#" class="text-dark-75 text-hover-primary font-weight-bold font-size-h6">Matt Pears</a>';
10196			html += '		<span class="text-muted font-size-sm">Just now</span>';
10197			html += '	</div>';
10198			html += '</div>';
10199			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">';
10200			html += 'Right before vacation season we have the next Big Deal for you.';
10201			html += '</div>';
10202
10203			KTUtil.setHTML(node, html);
10204			messagesEl.appendChild(node);
10205			textarea.value = '';
10206			scrollEl.scrollTop = parseInt(KTUtil.css(messagesEl, 'height'));
10207
10208			var ps;
10209			if (ps = KTUtil.data(scrollEl).get('ps')) {
10210				ps.update();
10211			}
10212		}, 2000);
10213	}
10214
10215	// Public methods
10216	return {
10217		init: function(id) {
10218			// Init modal chat example
10219			_init(KTUtil.getById(id));
10220
10221			// Trigger click to show popup modal chat on page load
10222			if (encodeURI(window.location.hostname) == 'keenthemes.com' || encodeURI(window.location.hostname) == 'www.keenthemes.com') {
10223				setTimeout(function() {
10224		            if (!KTCookie.getCookie('kt_app_chat_shown')) {
10225		                var expires = new Date(new Date().getTime() + 60 * 60 * 1000); // expire in 60 minutes from now
10226
10227						KTCookie.setCookie('kt_app_chat_shown', 1, { expires: expires });
10228
10229						if (KTUtil.getById('kt_app_chat_launch_btn')) {
10230							KTUtil.getById('kt_app_chat_launch_btn').click();
10231						}
10232		            }
10233		        }, 2000);
10234	        }
10235        },
10236
10237        setup: function(element) {
10238            _init(element);
10239        }
10240	};
10241}();
10242
10243// Webpack support
10244if (typeof module !== 'undefined') {
10245	module.exports = KTLayoutChat;
10246}
10247
10248"use strict";
10249
10250var KTLayoutDemoPanel = function() {
10251    // Private properties
10252    var _element;
10253    var _offcanvasObject;
10254
10255    // Private functions
10256    var _init = function() {
10257        _offcanvasObject = new KTOffcanvas(_element, {
10258            overlay: true,
10259            baseClass: 'offcanvas',
10260            placement: 'right',
10261            closeBy: 'kt_demo_panel_close',
10262            toggleBy: 'kt_demo_panel_toggle'
10263        });
10264
10265        var header = KTUtil.find(_element, '.offcanvas-header');
10266        var content = KTUtil.find(_element, '.offcanvas-content');
10267        var wrapper = KTUtil.find(_element, '.offcanvas-wrapper');
10268        var footer = KTUtil.find(_element, '.offcanvas-footer');
10269
10270        KTUtil.scrollInit(wrapper, {
10271            disableForMobile: true,
10272            resetHeightOnDestroy: true,
10273            handleWindowResize: true,
10274            height: function() {
10275                var height = parseInt(KTUtil.getViewPort().height);
10276
10277                if (header) {
10278                    height = height - parseInt(KTUtil.actualHeight(header));
10279                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10280                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10281                }
10282
10283                if (content) {
10284                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10285                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10286                }
10287
10288                if (wrapper) {
10289                    height = height - parseInt(KTUtil.css(wrapper, 'marginTop'));
10290                    height = height - parseInt(KTUtil.css(wrapper, 'marginBottom'));
10291                }
10292
10293                if (footer) {
10294                    height = height - parseInt(KTUtil.actualHeight(footer));
10295                    height = height - parseInt(KTUtil.css(footer, 'marginTop'));
10296                    height = height - parseInt(KTUtil.css(footer, 'marginBottom'));
10297                }
10298
10299                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10300                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10301
10302                height = height - 2;
10303
10304                return height;
10305            }
10306        });
10307
10308        if (typeof offcanvas !== 'undefined' && offcanvas.length === 0) {
10309            offcanvas.on('hide', function() {
10310                var expires = new Date(new Date().getTime() + 60 * 60 * 1000); // expire in 60 minutes from now
10311                KTCookie.setCookie('kt_demo_panel_shown', 1, {expires: expires});
10312            });
10313        }
10314    }
10315
10316    var _remind = function() {
10317        if (!(encodeURI(window.location.hostname) == 'keenthemes.com' || encodeURI(window.location.hostname) == 'www.keenthemes.com')) {
10318            return;
10319        }
10320
10321        setTimeout(function() {
10322            if (!KTCookie.getCookie('kt_demo_panel_shown')) {
10323                var expires = new Date(new Date().getTime() + 15 * 60 * 1000); // expire in 15 minutes from now
10324                KTCookie.setCookie('kt_demo_panel_shown', 1, { expires: expires });
10325                if (typeof _offcanvasObject !== 'undefined') {
10326                    _offcanvasObject.show();
10327                }
10328            }
10329        }, 4000);
10330    }
10331
10332    // Public methods
10333    return {
10334        init: function(id) {
10335            _element = KTUtil.getById(id);
10336
10337            if (!_element) {
10338                return;
10339            }
10340
10341            // Initialize
10342            _init();
10343
10344            // Remind
10345            _remind();
10346        }
10347    };
10348}();
10349
10350// Webpack support
10351if (typeof module !== 'undefined') {
10352	module.exports = KTLayoutDemoPanel;
10353}
10354
10355"use strict";
10356
10357var KTLayoutExamples = function() {
10358
10359    var initDefaultMode = function(element) {
10360        var elements = element;
10361        if (typeof elements === 'undefined') {
10362            elements = document.querySelectorAll('.example:not(.example-compact):not(.example-hover):not(.example-basic)');
10363        }
10364
10365        if (elements && elements.length > 0 ) {
10366            for (var i = 0; i < elements.length; ++i) {
10367                var example = elements[i];
10368                var copy = KTUtil.find(example, '.example-copy');
10369
10370                if (copy) {
10371                    var clipboard = new ClipboardJS(copy, {
10372                        target: function(trigger) {
10373                            var example = trigger.closest('.example');
10374                            var el = KTUtil.find(example, '.example-code .tab-pane.active');
10375
10376                            if (!el) {
10377                                el = KTUtil.find(example, '.example-code');
10378                            }
10379
10380                            return el;
10381                        }
10382                    });
10383
10384                    clipboard.on('success', function(e) {
10385                        KTUtil.addClass(e.trigger, 'example-copied');
10386                        e.clearSelection();
10387
10388                        setTimeout(function() {
10389                            KTUtil.removeClass(e.trigger, 'example-copied');
10390                        }, 2000);
10391                    });
10392                }
10393            }
10394        }
10395    }
10396
10397    var initCompactMode = function(element) {
10398        var example,code,toggle,copy, clipboard;
10399
10400        var elements = element;
10401        if (typeof elements === 'undefined') {
10402            var elements = document.querySelectorAll('.example.example-compact');
10403        }
10404
10405        if (elements && elements.length > 0 ) {
10406            for (var i = 0; i < elements.length; ++i) {
10407                var example = elements[i];
10408                var toggle = KTUtil.find(example, '.example-toggle');
10409                var copy = KTUtil.find(example, '.example-copy');
10410
10411                // Handle toggle
10412                KTUtil.addEvent(toggle, 'click', function() {
10413                    var example = this.closest('.example');
10414                    var code =  KTUtil.find(example, '.example-code');
10415                    var the = this;
10416
10417                    if (KTUtil.hasClass(this, 'example-toggled')) {
10418                        KTUtil.slideUp(code, 300, function() {
10419                            KTUtil.removeClass(the, 'example-toggled');
10420                            KTUtil.removeClass(code, 'example-code-on');
10421                            KTUtil.hide(code);
10422                        });
10423                    } else {
10424                        KTUtil.addClass(code, 'example-code-on');
10425                        KTUtil.addClass(this, 'example-toggled');
10426                        KTUtil.slideDown(code, 300, function() {
10427                            KTUtil.show(code);
10428                        });
10429                    }
10430                });
10431
10432                // Handle copy
10433                if (copy) {
10434                    var clipboard = new ClipboardJS(copy, {
10435                        target: function(trigger) {
10436                            var example = trigger.closest('.example');
10437                            var el = KTUtil.find(example, '.example-code .tab-pane.active');
10438
10439                            if (!el) {
10440                                el = KTUtil.find(example, '.example-code');
10441                            }
10442
10443                            return el;
10444                        }
10445                    });
10446
10447                    clipboard.on('success', function(e) {
10448                        KTUtil.addClass(e.trigger, 'example-copied');
10449                        e.clearSelection();
10450
10451                        setTimeout(function() {
10452                            KTUtil.removeClass(e.trigger, 'example-copied');
10453                        }, 2000);
10454                    });
10455                }
10456            }
10457        }
10458    }
10459
10460    return {
10461        init: function(element, options) {
10462            initDefaultMode(element);
10463            initCompactMode(element);
10464        }
10465    };
10466}();
10467
10468// webpack support
10469if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
10470    module.exports = KTLayoutExamples;
10471}
10472
10473"use strict";
10474
10475var KTLayoutQuickActions = function() {
10476    // Private properties
10477    var _element;
10478    var _offcanvasObject;
10479
10480    // Private functions
10481    var _init = function() {
10482        var header = KTUtil.find(_element, '.offcanvas-header');
10483        var content = KTUtil.find(_element, '.offcanvas-content');
10484
10485        _offcanvasObject = new KTOffcanvas(_element, {
10486            overlay: true,
10487            baseClass: 'offcanvas',
10488            placement: 'right',
10489            closeBy: 'kt_quick_actions_close',
10490            toggleBy: 'kt_quick_actions_toggle'
10491        });
10492
10493        KTUtil.scrollInit(content, {
10494            disableForMobile: true,
10495            resetHeightOnDestroy: true,
10496            handleWindowResize: true,
10497            height: function() {
10498                var height = parseInt(KTUtil.getViewPort().height);
10499
10500                if (header) {
10501                    height = height - parseInt(KTUtil.actualHeight(header));
10502                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10503                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10504                }
10505
10506                if (content) {
10507                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10508                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10509                }
10510
10511                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10512                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10513
10514                height = height - 2;
10515
10516                return height;
10517            }
10518        });
10519    }
10520
10521    // Public methods
10522    return {
10523        init: function(id) {
10524            _element = KTUtil.getById(id);
10525
10526            if (!_element) {
10527                return;
10528            }
10529
10530            // Initialize
10531            _init();
10532        },
10533
10534        getElement: function() {
10535            return _element;
10536        }
10537    };
10538}();
10539
10540// Webpack support
10541if (typeof module !== 'undefined') {
10542	module.exports = KTLayoutQuickActions;
10543}
10544
10545"use strict";
10546
10547var KTLayoutQuickCartPanel = function() {
10548    // Private properties
10549    var _element;
10550    var _offcanvasObject;
10551
10552    // Private functions
10553    var _init = function() {
10554        _offcanvasObject = new KTOffcanvas(_element, {
10555            overlay: true,
10556            baseClass: 'offcanvas',
10557            placement: 'right',
10558            closeBy: 'kt_quick_cart_close',
10559            toggleBy: 'kt_quick_cart_toggle'
10560        });
10561
10562        var header = KTUtil.find(_element, '.offcanvas-header');
10563        var content = KTUtil.find(_element, '.offcanvas-content');
10564        var wrapper = KTUtil.find(_element, '.offcanvas-wrapper');
10565        var footer = KTUtil.find(_element, '.offcanvas-footer');
10566
10567        KTUtil.scrollInit(wrapper, {
10568            disableForMobile: true,
10569            resetHeightOnDestroy: true,
10570            handleWindowResize: true,
10571            height: function() {
10572                var height = parseInt(KTUtil.getViewPort().height);
10573
10574                if (header) {
10575                    height = height - parseInt(KTUtil.actualHeight(header));
10576                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10577                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10578                }
10579
10580                if (content) {
10581                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10582                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10583                }
10584
10585                if (wrapper) {
10586                    height = height - parseInt(KTUtil.css(wrapper, 'marginTop'));
10587                    height = height - parseInt(KTUtil.css(wrapper, 'marginBottom'));
10588                }
10589
10590                if (footer) {
10591                    height = height - parseInt(KTUtil.actualHeight(footer));
10592                    height = height - parseInt(KTUtil.css(footer, 'marginTop'));
10593                    height = height - parseInt(KTUtil.css(footer, 'marginBottom'));
10594                }
10595
10596                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10597                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10598
10599                height = height - 2;
10600
10601                return height;
10602            }
10603        });
10604    }
10605
10606    // Public methods
10607    return {
10608        init: function(id) {
10609            _element = KTUtil.getById(id);
10610
10611            if (!_element) {
10612                return;
10613            }
10614
10615            // Initialize
10616            _init();
10617        }
10618    };
10619}();
10620
10621// Webpack support
10622if (typeof module !== 'undefined') {
10623	module.exports = KTLayoutQuickCartPanel;
10624}
10625
10626"use strict";
10627
10628var KTLayoutQuickNotifications = function() {
10629    // Private properties
10630    var _element;
10631    var _offcanvasObject;
10632
10633    // Private functions
10634    var _init = function() {
10635        var header = KTUtil.find(_element, '.offcanvas-header');
10636        var content = KTUtil.find(_element, '.offcanvas-content');
10637
10638        _offcanvasObject = new KTOffcanvas(_element, {
10639            overlay: true,
10640            baseClass: 'offcanvas',
10641            placement: 'right',
10642            closeBy: 'kt_quick_notifications_close',
10643            toggleBy: 'kt_quick_notifications_toggle'
10644        });
10645
10646        KTUtil.scrollInit(content, {
10647            disableForMobile: true,
10648            resetHeightOnDestroy: true,
10649            handleWindowResize: true,
10650            height: function() {
10651                var height = parseInt(KTUtil.getViewPort().height);
10652
10653                if (header) {
10654                    height = height - parseInt(KTUtil.actualHeight(header));
10655                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10656                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10657                }
10658
10659                if (content) {
10660                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10661                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10662                }
10663
10664                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10665                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10666
10667                height = height - 2;
10668
10669                return height;
10670            }
10671        });
10672    }
10673
10674    // Public methods
10675    return {
10676        init: function(id) {
10677            _element = KTUtil.getById(id);
10678
10679            if (!_element) {
10680                return;
10681            }
10682
10683            // Initialize
10684            _init();
10685        },
10686
10687        getElement: function() {
10688            return _element;
10689        }
10690    };
10691}();
10692
10693// Webpack support
10694if (typeof module !== 'undefined') {
10695	module.exports = KTLayoutQuickNotifications;
10696}
10697
10698"use strict";
10699
10700var KTLayoutQuickPanel = function() {
10701    // Private properties
10702    var _element;
10703    var _offcanvasObject;
10704    var _notificationsElement;
10705    var _logsElement;
10706    var _settingsElement;
10707
10708    // Private functions
10709    var _getContentHeight = function() {
10710        var height;
10711
10712        var header = KTUtil.find(_element, '.offcanvas-header');
10713        var content = KTUtil.find(_element, '.offcanvas-content');
10714
10715        var height = parseInt(KTUtil.getViewPort().height);
10716
10717        if (header) {
10718            height = height - parseInt(KTUtil.actualHeight(header));
10719            height = height - parseInt(KTUtil.css(header, 'marginTop'));
10720            height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10721        }
10722
10723        if (content) {
10724            height = height - parseInt(KTUtil.css(content, 'marginTop'));
10725            height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10726        }
10727
10728        height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10729        height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10730
10731        height = height - 2;
10732
10733        return height;
10734    }
10735
10736    var _init = function() {
10737        _offcanvasObject = new KTOffcanvas(_element, {
10738            overlay: true,
10739            baseClass: 'offcanvas',
10740            placement: 'right',
10741            closeBy: 'kt_quick_panel_close',
10742            toggleBy: 'kt_quick_panel_toggle'
10743        });
10744    }
10745
10746    var _initNotifications = function() {
10747        KTUtil.scrollInit(_notificationsElement, {
10748            mobileNativeScroll: true,
10749            resetHeightOnDestroy: true,
10750            handleWindowResize: true,
10751            height: function() {
10752                return _getContentHeight();
10753            }
10754        });
10755    }
10756
10757    var _initLogs = function() {
10758        KTUtil.scrollInit(_logsElement, {
10759            mobileNativeScroll: true,
10760            resetHeightOnDestroy: true,
10761            handleWindowResize: true,
10762            height: function() {
10763                return _getContentHeight();
10764            }
10765        });
10766    }
10767
10768    var _initSettings = function() {
10769        KTUtil.scrollInit(_settingsElement, {
10770            mobileNativeScroll: true,
10771            resetHeightOnDestroy: true,
10772            handleWindowResize: true,
10773            height: function() {
10774                return _getContentHeight();
10775            }
10776        });
10777    }
10778
10779    var _updateScrollbars = function() {
10780        $(_element).find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
10781            KTUtil.scrollUpdate(_notificationsElement);
10782            KTUtil.scrollUpdate(_logsElement);
10783            KTUtil.scrollUpdate(_settingsElement);
10784        });
10785    }
10786
10787    // Public methods
10788    return {
10789        init: function(id) {
10790            _element = KTUtil.getById(id);
10791            _notificationsElement = KTUtil.getById('kt_quick_panel_notifications');
10792            _logsElement = KTUtil.getById('kt_quick_panel_logs');
10793            _settingsElement = KTUtil.getById('kt_quick_panel_settings');
10794
10795            _init();
10796            _initNotifications();
10797            _initLogs();
10798            _initSettings();
10799
10800            _updateScrollbars();
10801        }
10802    };
10803}();
10804
10805// Webpack support
10806if (typeof module !== 'undefined') {
10807	module.exports = KTLayoutQuickPanel;
10808}
10809
10810"use strict";
10811
10812var KTLayoutQuickSearch = function() {
10813    // Private properties
10814    var _element;
10815    var _offcanvasObject;
10816
10817    // Private functions
10818    var _init = function() {
10819        var header = KTUtil.find(_element, '.offcanvas-header');
10820        var content = KTUtil.find(_element, '.offcanvas-content');
10821        var form = KTUtil.find(_element, '.quick-search-form');
10822        var results = KTUtil.find(_element, '.quick-search-wrapper');
10823
10824        _offcanvasObject = new KTOffcanvas(_element, {
10825            overlay: true,
10826            baseClass: 'offcanvas',
10827            placement: 'right',
10828            closeBy: 'kt_quick_search_close',
10829            toggleBy: 'kt_quick_search_toggle'
10830        });
10831
10832        KTUtil.scrollInit(results, {
10833            disableForMobile: true,
10834            resetHeightOnDestroy: true,
10835            handleWindowResize: true,
10836            height: function() {
10837                var height = parseInt(KTUtil.getViewPort().height);
10838
10839                if (header) {
10840                    height = height - parseInt(KTUtil.actualHeight(header));
10841                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10842                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10843                }
10844
10845                if (content) {
10846                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10847                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10848                }
10849
10850                if (results) {
10851                    height = height - parseInt(KTUtil.actualHeight(form));
10852                    height = height - parseInt(KTUtil.css(form, 'marginTop'));
10853                    height = height - parseInt(KTUtil.css(form, 'marginBottom'));
10854
10855                    height = heig
10855ht - parseInt(KTUtil.css(results, 'marginTop'));
10856                    height = height - parseInt(KTUtil.css(results, 'marginBottom'));
10857                }
10858
10859                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10860                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10861
10862                height = height - 2;
10863
10864                return height;
10865            }
10866        });
10867    }
10868
10869    // Public methods
10870    return {
10871        init: function(id) {
10872            _element = KTUtil.getById(id);
10873
10874            if (!_element) {
10875                return;
10876            }
10877
10878            // Initialize
10879            _init();
10880        },
10881
10882        getElement: function() {
10883            return _element;
10884        }
10885    };
10886}();
10887
10888// Webpack support
10889if (typeof module !== 'undefined') {
10890	module.exports = KTLayoutQuickSearch;
10891}
10892
10893"use strict";
10894
10895var KTLayoutQuickUser = function() {
10896    // Private properties
10897    var _element;
10898    var _offcanvasObject;
10899
10900    // Private functions
10901    var _init = function() {
10902        var header = KTUtil.find(_element, '.offcanvas-header');
10903        var content = KTUtil.find(_element, '.offcanvas-content');
10904
10905        _offcanvasObject = new KTOffcanvas(_element, {
10906            overlay: true,
10907            baseClass: 'offcanvas',
10908            placement: 'right',
10909            closeBy: 'kt_quick_user_close',
10910            toggleBy: 'kt_quick_user_toggle'
10911        });
10912
10913        KTUtil.scrollInit(content, {
10914            disableForMobile: true,
10915            resetHeightOnDestroy: true,
10916            handleWindowResize: true,
10917            height: function() {
10918                var height = parseInt(KTUtil.getViewPort().height);
10919
10920                if (header) {
10921                    height = height - parseInt(KTUtil.actualHeight(header));
10922                    height = height - parseInt(KTUtil.css(header, 'marginTop'));
10923                    height = height - parseInt(KTUtil.css(header, 'marginBottom'));
10924                }
10925
10926                if (content) {
10927                    height = height - parseInt(KTUtil.css(content, 'marginTop'));
10928                    height = height - parseInt(KTUtil.css(content, 'marginBottom'));
10929                }
10930
10931                height = height - parseInt(KTUtil.css(_element, 'paddingTop'));
10932                height = height - parseInt(KTUtil.css(_element, 'paddingBottom'));
10933
10934                height = height - 2;
10935
10936                return height;
10937            }
10938        });
10939    }
10940
10941    // Public methods
10942    return {
10943        init: function(id) {
10944            _element = KTUtil.getById(id);
10945
10946            if (!_element) {
10947                return;
10948            }
10949
10950            // Initialize
10951            _init();
10952        },
10953
10954        getElement: function() {
10955            return _element;
10956        }
10957    };
10958}();
10959
10960// Webpack support
10961if (typeof module !== 'undefined') {
10962	module.exports = KTLayoutQuickUser;
10963}
10964
10965"use strict";
10966
10967var KTLayoutScrolltop = function() {
10968    // Private properties
10969    var _element;
10970    var _object;
10971
10972    // Private functions
10973    var _init = function() {
10974        _object = new KTScrolltop(_element, {
10975          offset: 300,
10976          speed: 600,
10977        });
10978    }
10979
10980    // Public methods
10981	return {
10982		init: function(id) {
10983            _element = KTUtil.getById(id);
10984
10985            if (!_element) {
10986                return;
10987            }
10988
10989            // Initialize
10990            _init();
10991		},
10992
10993        getElement: function() {
10994            return _element;
10995        }
10996	};
10997}();
10998
10999// Webpack support
11000if (typeof module !== 'undefined') {
11001	module.exports = KTLayoutScrolltop;
11002}
11003
11004"use strict";
11005//
11006// Handle User Quick Search For Dropdown, Inline and Offcanvas Search Panels
11007//
11008
11009var KTLayoutSearch = function() {
11010    // Private properties
11011    var _target;
11012    var _form;
11013    var _input;
11014    var _closeIcon;
11015    var _resultWrapper;
11016    var _resultDropdown;
11017    var _resultDropdownToggle;
11018    var _closeIconContainer;
11019    var _inputGroup;
11020    var _query = '';
11021
11022    var _hasResult = false;
11023    var _timeout = false;
11024    var _isProcessing = false;
11025    var _requestTimeout = 200; // ajax request fire timeout in milliseconds
11026    var _spinnerClass = 'spinner spinner-sm spinner-primary';
11027    var _resultClass = 'quick-search-has-result';
11028    var _minLength = 2;
11029
11030    // Private functions
11031    var _showProgress = function() {
11032        _isProcessing = true;
11033        KTUtil.addClass(_closeIconContainer, _spinnerClass);
11034
11035        if (_closeIcon) {
11036            KTUtil.hide(_closeIcon);
11037        }
11038    }
11039
11040    var _hideProgress = function() {
11041        _isProcessing = false;
11042        KTUtil.removeClass(_closeIconContainer, _spinnerClass);
11043
11044        if (_closeIcon) {
11045            if (_input.value.length < _minLength) {
11046                KTUtil.hide(_closeIcon);
11047            } else {
11048                KTUtil.show(_closeIcon, 'flex');
11049            }
11050        }
11051    }
11052
11053    var _showDropdown = function() {
11054        if (_resultDropdownToggle && !KTUtil.hasClass(_resultDropdown, 'show')) {
11055            $(_resultDropdownToggle).dropdown('toggle');
11056            $(_resultDropdownToggle).dropdown('update');
11057        }
11058    }
11059
11060    var _hideDropdown = function() {
11061        if (_resultDropdownToggle && KTUtil.hasClass(_resultDropdown, 'show')) {
11062            $(_resultDropdownToggle).dropdown('toggle');
11063        }
11064    }
11065
11066    var _processSearch = function() {
11067        if (_hasResult && _query === _input.value) {
11068            _hideProgress();
11069            KTUtil.addClass(_target, _resultClass);
11070            _showDropdown();
11071            KTUtil.scrollUpdate(_resultWrapper);
11072
11073            return;
11074        }
11075
11076        _query = _input.value;
11077
11078        KTUtil.removeClass(_target, _resultClass);
11079        _showProgress();
11080        _hideDropdown();
11081
11082        setTimeout(function() {
11083            $.ajax({
11084                url: HOST_URL + '/api/quick_search.php',
11085                data: {
11086                    query: _query
11087                },
11088                dataType: 'html',
11089                success: function(res) {
11090                    _hasResult = true;
11091                    _hideProgress();
11092                    KTUtil.addClass(_target, _resultClass);
11093                    KTUtil.setHTML(_resultWrapper, res);
11094                    _showDropdown();
11095                    KTUtil.scrollUpdate(_resultWrapper);
11096                },
11097                error: function(res) {
11098                    _hasResult = false;
11099                    _hideProgress();
11100                    KTUtil.addClass(_target, _resultClass);
11101                    KTUtil.setHTML(_resultWrapper, '<span class="font-weight-bold text-muted">Connection error. Please try again later..</div>');
11102                    _showDropdown();
11103                    KTUtil.scrollUpdate(_resultWrapper);
11104                }
11105            });
11106        }, 1000);
11107    }
11108
11109    var _handleCancel = function(e) {
11110        _input.value = '';
11111        _query = '';
11112        _hasResult = false;
11113        KTUtil.hide(_closeIcon);
11114        KTUtil.removeClass(_target, _resultClass);
11115        _hideDropdown();
11116    }
11117
11118    var _handleSearch = function() {
11119        if (_input.value.length < _minLength) {
11120            _hideProgress();
11121            _hideDropdown();
11122
11123            return;
11124        }
11125
11126        if (_isProcessing == true) {
11127            return;
11128        }
11129
11130        if (_timeout) {
11131            clearTimeout(_timeout);
11132        }
11133
11134        _timeout = setTimeout(function() {
11135            _processSearch();
11136        }, _requestTimeout);
11137    }
11138
11139    // Public methods
11140    return {
11141        init: function(id) {
11142            _target = KTUtil.getById(id);
11143
11144            if (!_target) {
11145                return;
11146            }
11147
11148            _form = KTUtil.find(_target, '.quick-search-form');
11149            _input = KTUtil.find(_target, '.form-control');
11150            _closeIcon = KTUtil.find(_target, '.quick-search-close');
11151            _resultWrapper = KTUtil.find(_target, '.quick-search-wrapper');
11152            _resultDropdown = KTUtil.find(_target, '.dropdown-menu');
11153            _resultDropdownToggle = KTUtil.find(_target, '[data-toggle="dropdown"]');
11154            _inputGroup = KTUtil.find(_target, '.input-group');
11155            _closeIconContainer = KTUtil.find(_target, '.input-group .input-group-append');
11156
11157            // Attach input keyup handler
11158            KTUtil.addEvent(_input, 'keyup', _handleSearch);
11159            KTUtil.addEvent(_input, 'focus', _handleSearch);
11160
11161            // Prevent enter click
11162            _form.onkeypress = function(e) {
11163                var key = e.charCode || e.keyCode || 0;
11164                if (key == 13) {
11165                    e.preventDefault();
11166                }
11167            }
11168
11169            KTUtil.addEvent(_closeIcon, 'click', _handleCancel);
11170        }
11171    };
11172};
11173
11174// Webpack support
11175if (typeof module !== 'undefined') {
11176    module.exports = KTLayoutSearch;
11177}
11178
11179var KTLayoutSearchInline = KTLayoutSearch;
11180var KTLayoutSearchOffcanvas = KTLayoutSearch;

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