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