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