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 var duration = duration ? duration : 500; 4402 var 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 (targetPos > scrollPos) { 4408 from = targetPos; 4409 to = scrollPos; 4410 } else { 4411 from = scrollPos; 4412 to = targetPos; 4413 } 4414 4415 if (offset) { 4416 to += offset; 4417 } 4418 4419 KTUtil.animate(from, to, duration, function(value) { 4420 document.documentElement.scrollTop = value; 4421 document.body.parentNode.scrollTop = value; 4422 document.body.scrollTop = value; 4423 }); //, easing, done 4424 }, 4425 4426 scrollTop: function(offset, duration) { 4427 KTUtil.scrollTo(null, offset, duration); 4428 }, 4429 4430 isArray: function(obj) { 4431 return obj && Array.isArray(obj); 4432 }, 4433 4434 ready: function(callback) { 4435 if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") { 4436 callback(); 4437 } else { 4438 document.addEventListener('DOMContentLoaded', callback); 4439 } 4440 }, 4441 4442 isEmpty: function(obj) { 4443 for (var prop in obj) { 4444 if (obj.hasOwnProperty(prop)) { 4445 return false; 4446 } 4447 } 4448 4449 return true; 4450 }, 4451 4452 numberString: function(nStr) { 4453 nStr += ''; 4454 var x = nStr.split('.'); 4455 var x1 = x[0]; 4456 var x2 = x.length > 1 ? '.' + x[1] : ''; 4457 var rgx = /(\d+)(\d{3})/; 4458 while (rgx.test(x1)) { 4459 x1 = x1.replace(rgx, '$1' + ',' + '$2'); 4460 } 4461 return x1 + x2; 4462 }, 4463 4464 detectIE: function() { 4465 var ua = window.navigator.userAgent; 4466 4467 // Test values; Uncomment to check result … 4468 4469 // IE 10 4470 // ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'; 4471 4472 // IE 11 4473 // ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko'; 4474 4475 // Edge 12 (Spartan) 4476 // 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'; 4477 4478 // Edge 13 4479 // 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'; 4480 4481 var msie = ua.indexOf('MSIE '); 4482 if (msie > 0) { 4483 // IE 10 or older => return version number 4484 return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); 4485 } 4486 4487 var trident = ua.indexOf('Trident/'); 4488 if (trident > 0) { 4489 // IE 11 => return version number 4490 var rv = ua.indexOf('rv:'); 4491 return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); 4492 } 4493 4494 var edge = ua.indexOf('Edge/'); 4495 if (edge > 0) { 4496 // Edge (IE 12+) => return version number
4497 return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); 4498 } 4499 4500 // other browser 4501 return false; 4502 }, 4503 4504 isRTL: function() { 4505 return (KTUtil.attr(KTUtil.get('html'), 'direction') == 'rtl'); 4506 }, 4507 4508 // 4509 4510 // Scroller 4511 scrollInit: function(element, options) { 4512 if(!element) return; 4513 // Define init function 4514 function init() { 4515 var ps; 4516 var height; 4517 4518 if (options.height instanceof Function) { 4519 height = parseInt(options.height.call()); 4520 } else { 4521 height = parseInt(options.height); 4522 } 4523 4524 // Destroy scroll on table and mobile modes 4525 if ((options.mobileNativeScroll || options.disableForMobile) && KTUtil.isInResponsiveRange('tablet-and-mobile')) { 4526 ps = KTUtil.data(element).get('ps'); 4527 if (ps) { 4528 if (options.resetHeightOnDestroy) { 4529 KTUtil.css(element, 'height', 'auto'); 4530 } else { 4531 KTUtil.css(element, 'overflow', 'auto'); 4532 if (height > 0) { 4533 KTUtil.css(element, 'height', height + 'px'); 4534 } 4535 } 4536 4537 ps.destroy(); 4538 ps = KTUtil.data(element).remove('ps'); 4539 } else if (height > 0){ 4540 KTUtil.css(element, 'overflow', 'auto'); 4541 KTUtil.css(element, 'height', height + 'px'); 4542 } 4543 4544 return; 4545 } 4546 4547 if (height > 0) { 4548 KTUtil.css(element, 'height', height + 'px'); 4549 } 4550 4551 if (options.desktopNativeScroll) { 4552 KTUtil.css(element, 'overflow', 'auto'); 4553 return; 4554 } 4555 4556 // Init scroll 4557 KTUtil.css(element, 'overflow', 'hidden'); 4558 4559 ps = KTUtil.data(element).get('ps'); 4560 if (ps) { 4561 ps.update(); 4562 } else { 4563 KTUtil.addClass(element, 'kt-scroll'); 4564 ps = new PerfectScrollbar(element, { 4565 wheelSpeed: 0.5, 4566 swipeEasing: true, 4567 wheelPropagation: (options.windowScroll === false ? false : true), 4568 minScrollbarLength: 40, 4569 maxScrollbarLength: 300, 4570 suppressScrollX: KTUtil.attr(element, 'data-scroll-x') != 'true' ? true : false 4571 }); 4572 4573 KTUtil.data(element).set('ps', ps); 4574 } 4575 4576 // Remember scroll position in cookie 4577 var uid = KTUtil.attr(element, 'id'); 4578 4579 if (options.rememberPosition === true && Cookies && uid) { 4580 if (Cookies.get(uid)) { 4581 var pos = parseInt(Cookies.get(uid)); 4582 4583 if (pos > 0) { 4584 element.scrollTop = pos; 4585 } 4586 } 4587 4588 element.addEventListener('ps-scroll-y', function() { 4589 Cookies.set(uid, element.scrollTop); 4590 }); 4591 } 4592 } 4593 4594 // Init 4595 init(); 4596 4597 // Handle window resize 4598 if (options.handleWindowResize) { 4599 KTUtil.addResizeHandler(function() { 4600 init(); 4601 }); 4602 } 4603 }, 4604 4605 scrollUpdate: function(element) { 4606 var ps = KTUtil.data(element).get('ps'); 4607 if (ps) { 4608 ps.update(); 4609 } 4610 }, 4611 4612 scrollUpdateAll: function(parent) { 4613 var scrollers = KTUtil.findAll(parent, '.ps'); 4614 for (var i = 0, len = scrollers.length; i < len; i++) { 4615 KTUtil.scrollUpdate(scrollers[i]); 4616 } 4617 }, 4618 4619 scrollDestroy: function(element) { 4620 var ps = KTUtil.data(element).get('ps'); 4621 if (ps) { 4622 ps.destroy(); 4623 ps = KTUtil.data(element).remove('ps'); 4624 } 4625 }, 4626 4627 setHTML: function(el, html) { 4628 if (KTUtil.get(el)) { 4629 KTUtil.get(el).innerHTML = html; 4630 } 4631 }, 4632 4633 getHTML: function(el) { 4634 if (KTUtil.get(el)) { 4635 return KTUtil.get(el).innerHTML; 4636 } 4637 }, 4638 4639 getDocumentHeight: function() { 4640 var body = document.body; 4641 var html = document.documentElement; 4642 4643 return Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ); 4644 }, 4645 4646 getScrollTop: function() {
4647 return (document.scrollingElement || document.documentElement).scrollTop; 4648 } 4649 } 4650}(); 4651 4652// webpack support 4653if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { 4654 module.exports = KTUtil; 4655} 4656 4657// Initialize KTUtil class on document ready 4658KTUtil.ready(function() { 4659 KTUtil.init(); 4660}); 4661 4662// CSS3 Transitions only after page load(.kt-page-loading class added to body tag and remove with JS on page load) 4663window.onload = function() { 4664 KTUtil.removeClass(KTUtil.get('body'), 'kt-page--loading'); 4665} 4666 4667// plugin setup 4668var KTWizard = function(elementId, options) { 4669 // Main object 4670 var the = this; 4671 var init = false; 4672 4673 // Get element object 4674 var element = KTUtil.get(elementId); 4675 var body = KTUtil.get('body'); 4676 4677 if (!element) { 4678 return; 4679 } 4680 4681 // Default options 4682 var defaultOptions = { 4683 startStep: 1, 4684 clickableSteps: true 4685 }; 4686 4687 //////////////////////////// 4688 // ** Private Methods ** // 4689 //////////////////////////// 4690 4691 var Plugin = { 4692 /** 4693 * Construct 4694 */ 4695 4696 construct: function(options) { 4697 if (KTUtil.data(element).has('wizard')) { 4698 the = KTUtil.data(element).get('wizard'); 4699 } else { 4700 // reset menu 4701 Plugin.init(options); 4702 4703 // build menu 4704 Plugin.build(); 4705 4706 KTUtil.data(element).set('wizard', the); 4707 } 4708 4709 return the; 4710 }, 4711 4712 /** 4713 * Init wizard 4714 */ 4715 init: function(options) { 4716 the.element = element; 4717 the.events = []; 4718 4719 // merge default and user defined options 4720 the.options = KTUtil.deepExtend({}, defaultOptions, options); 4721 4722 // Elements 4723 the.steps = KTUtil.findAll(element, '[data-ktwizard-type="step"]'); 4724 4725 the.btnSubmit = KTUtil.find(element, '[data-ktwizard-type="action-submit"]'); 4726 the.btnNext = KTUtil.find(element, '[data-ktwizard-type="action-next"]'); 4727 the.btnPrev = KTUtil.find(element, '[data-ktwizard-type="action-prev"]'); 4728 the.btnLast = KTUtil.find(element, '[data-ktwizard-type="action-last"]'); 4729 the.btnFirst = KTUtil.find(element, '[data-ktwizard-type="action-first"]'); 4730 4731 // Variables 4732 the.events = []; 4733 the.currentStep = 1; 4734 the.stopped = false; 4735 the.totalSteps = the.steps.length; 4736 4737 // Init current step 4738 if (the.options.startStep > 1) { 4739 Plugin.goTo(the.options.startStep); 4740 } 4741 4742 // Init UI 4743 Plugin.updateUI(); 4744 }, 4745 4746 /** 4747 * Build Form Wizard 4748 */ 4749 build: function() { 4750 // Next button event handler 4751 KTUtil.addEvent(the.btnNext, 'click', function(e) { 4752 e.preventDefault(); 4753 Plugin.goTo(Plugin.getNextStep(), true); 4754 }); 4755 4756 // Prev button event handler 4757 KTUtil.addEvent(the.btnPrev, 'click', function(e) { 4758 e.preventDefault(); 4759 Plugin.goTo(Plugin.getPrevStep(), true); 4760 }); 4761 4762 // First button event handler 4763 KTUtil.addEvent(the.btnFirst, 'click', function(e) { 4764 e.preventDefault(); 4765 Plugin.goTo(1, true); 4766 }); 4767 4768 // Last button event handler 4769 KTUtil.addEvent(the.btnLast, 'click', function(e) { 4770 e.preventDefault(); 4771 Plugin.goTo(the.totalSteps, true); 4772 }); 4773 4774 if (the.options.clickableSteps === true) { 4775 KTUtil.on(element, '[data-ktwizard-type="step"]', 'click', function() { 4776 var index = Array.prototype.indexOf.call(the.steps, this) + 1; 4777 if (index !== the.currentStep) { 4778 Plugin.goTo(index, true); 4779 } 4780 }); 4781 } 4782 }, 4783 4784 /** 4785 * Handles wizard click wizard 4786 */ 4787 goTo: function(number, eventHandle) { 4788 // Skip if this step is already shown 4789 if (number === the.currentStep || number > the.totalSteps || number < 0) { 4790 return; 4791 } 4792 4793 // Validate step number 4794 if (number) { 4795 number = parseInt(number); 4796 } else { 4797 number = Plugin.getNextStep(); 4798 } 4799 4800 // Before next and prev events 4801 var callback; 4802 4803 if (eventHandle === true) { 4804 if (number > the.currentStep) { 4805 callback = Plugin.eventTrigger('beforeNext'); 4806 } else { 4807 callback = Plugin.eventTrigger('beforePrev'); 4808 } 4809 } 4810 4811 // Skip if stopped 4812 if (the.stopped === true) { 4813 the.stopped = false; 4814 return; 4815 } 4816 4817 // Continue if no exit 4818 if (callback !== false) { 4819 // Before change 4820 if (eventHandle === true) { 4821 Plugin.eventTrigger('beforeChange'); 4822 } 4823 4824 // Set current step 4825 the.currentStep = number; 4826 4827 Plugin.updateUI(); 4828 4829 // Trigger change event 4830 if (eventHandle === true) { 4831 Plugin.eventTrigger('change'); 4832 } 4833 } 4834 4835 // After next and prev events 4836 if (eventHandle === true) { 4837 if (number > the.startStep) { 4838 Plugin.eventTrigger('afterNext'); 4839 } else { 4840 Plugin.eventTrigger('afterPrev'); 4841 } 4842 } else { 4843 // this function called by method, stop for the next call 4844 the.stopped = true; 4845 } 4846 4847 return the; 4848 }, 4849 4850 /** 4851 * Cancel 4852 */ 4853 stop: function() { 4854 the.stopped = true; 4855 }, 4856 4857 /** 4858 * Resume 4859 */ 4860 start: function() { 4861 the.stopped = false; 4862 }, 4863 4864 /** 4865 * Check last step 4866 */ 4867 isLastStep: function() { 4868 return the.currentStep === the.totalSteps; 4869 }, 4870 4871 /** 4872 * Check first step 4873 */ 4874 isFirstStep: function() { 4875 return the.currentStep === 1; 4876 }, 4877 4878 /** 4879 * Check between step 4880 */ 4881 isBetweenStep: function() { 4882 return Plugin.isLastStep() === false && Plugin.isFirstStep() === false; 4883 }, 4884 4885 /** 4886 * Go to the first step 4887 */ 4888 updateUI: function() { 4889 var stepType = ''; 4890 var index = the.currentStep - 1; 4891 4892 if (Plugin.isLastStep()) { 4893 stepType = 'last'; 4894 } else if (Plugin.isFirstStep()) { 4895 stepType = 'first'; 4896 } else { 4897 stepType = 'between'; 4898 } 4899 4900 KTUtil.attr(the.element, 'data-ktwizard-state', stepType); 4901 4902 // Steps 4903 var steps = KTUtil.findAll(the.element, '[data-ktwizard-type="step"]'); 4904 4905 if (steps && steps.length > 0) { 4906 for (var i = 0, len = steps.length; i < len; i++) { 4907 if (i == index) { 4908 KTUtil.attr(steps[i], 'data-ktwizard-state', 'current'); 4909 } else { 4910 if (i < index) { 4911 KTUtil.attr(steps[i], 'data-ktwizard-state', 'done'); 4912 } else { 4913 KTUtil.attr(steps[i], 'data-ktwizard-state', 'pending'); 4914 } 4915 } 4916 } 4917 } 4918 4919 // Steps Info 4920 var stepsInfo = KTUtil.findAll(the.element, '[data-ktwizard-type="step-info"]'); 4921 if (stepsInfo &&stepsInfo.length > 0) { 4922 for (var i = 0, len = stepsInfo.length; i < len; i++) { 4923 if (i == index) { 4924 KTUtil.attr(stepsInfo[i], 'data-ktwizard-state', 'current'); 4925 } else { 4926 KTUtil.removeAttr(stepsInfo[i], 'data-ktwizard-state'); 4927 } 4928 } 4929 } 4930 4931 // Steps Content 4932 var stepsContent = KTUtil.findAll(the.element, '[data-ktwizard-type="step-content"]'); 4933 if (stepsContent&& stepsContent.length > 0) { 4934 for (var i = 0, len = stepsContent.length; i < len; i++) { 4935 if (i == index) { 4936 KTUtil.attr(stepsContent[i], 'data-ktwizard-state', 'current'); 4937 } else { 4938 KTUtil.removeAttr(stepsContent[i], 'data-ktwizard-state'); 4939 } 4940 } 4941 } 4942 }, 4943 4944 /** 4945 * Get next step 4946 */ 4947 getNextStep: function() { 4948 if (the.totalSteps >= (the.currentStep + 1)) { 4949 return the.currentStep + 1; 4950 } else { 4951 return the.totalSteps; 4952 } 4953 }, 4954 4955 /** 4956 * Get prev step 4957 */ 4958 getPrevStep: function() { 4959 if ((the.currentStep - 1) >= 1) { 4960 return the.currentStep - 1; 4961 } else { 4962 return 1; 4963 } 4964 }, 4965 4966 /** 4967 * Trigger events 4968 */ 4969 eventTrigger: function(name, nested) { 4970 //KTUtil.triggerCustomEvent(name); 4971 for (var i = 0; i < the.events.length; i++) { 4972 var event = the.events[i]; 4973 if (event.name == name) { 4974 if (event.one == true) { 4975 if (event.fired == false) { 4976 the.events[i].fired = true; 4977 return event.handler.call(this, the); 4978 } 4979 } else { 4980 return event.handler.call(this, the); 4981 } 4982 } 4983 } 4984 }, 4985 4986 addEvent: function(name, handler, one) { 4987 the.events.push({ 4988 name: name, 4989 handler: handler, 4990 one: one, 4991 fired: false 4992 }); 4993 4994 return the; 4995 } 4996 }; 4997
4998 ////////////////////////// 4999 // ** Public Methods ** // 5000 ////////////////////////// 5001 5002 /** 5003 * Set default options 5004 */ 5005 5006 the.setDefaults = function(options) { 5007 defaultOptions = options; 5008 }; 5009 5010 /** 5011 * Go to the next step 5012 */ 5013 the.goNext = function(eventHandle) { 5014 return Plugin.goTo(Plugin.getNextStep(), eventHandle); 5015 }; 5016 5017 /** 5018 * Go to the prev step 5019 */ 5020 the.goPrev = function(eventHandle) { 5021 return Plugin.goTo(Plugin.getPrevStep(),eventHandle); 5022 }; 5023 5024 /** 5025 * Go to the last step 5026 */ 5027 the.goLast = function(eventHandle) { 5028 return Plugin.goTo(the.totalSteps, eventHandle); 5029 }; 5030 5031 /** 5032 * Go to the first step 5033 */ 5034 the.goFirst = function(eventHandle) { 5035 return Plugin.goTo(1, eventHandle); 5036 }; 5037 5038 /** 5039 * Go to a step 5040 */ 5041 the.goTo = function(number, eventHandle) { 5042 return Plugin.goTo(number, eventHandle); 5043 }; 5044 5045 /** 5046 * Cancel step 5047 */ 5048 the.stop = function() { 5049 return Plugin.stop(); 5050 }; 5051 5052 /** 5053 * Resume step 5054 */ 5055 the.start = function() { 5056 return Plugin.start(); 5057 }; 5058 5059 /** 5060 * Get current step number 5061 */ 5062 the.getStep = function() { 5063 return the.currentStep; 5064 }; 5065 5066 /** 5067 * Check last step 5068 */ 5069 the.isLastStep = function() { 5070 return Plugin.isLastStep(); 5071 }; 5072 5073 /** 5074 * Check first step 5075 */ 5076 the.isFirstStep = function() { 5077 return Plugin.isFirstStep(); 5078 }; 5079 5080 /** 5081 * Attach event 5082 */ 5083 the.on = function(name, handler) { 5084 return Plugin.addEvent(name, handler); 5085 }; 5086 5087 /** 5088 * Attach event that will be fired once 5089 */ 5090 the.one = function(name, handler) { 5091 return Plugin.addEvent(name, handler, true); 5092 }; 5093 5094 // Construct plugin 5095 Plugin.construct.apply(the, [options]); 5096 5097 return the; 5098}; 5099 5100// webpack support 5101if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { 5102 module.exports = KTWizard; 5103} 5104 5105'use strict'; 5106(function($) { 5107 5108 var pluginName = 'KTDatatable'; 5109 var pfx = 'kt-'; 5110 var util = KTUtil; 5111 var app = KTApp; 5112 5113 if (typeof util === 'undefined') throw new Error('Util class is required and must be included before ' + pluginName); 5114 5115 // plugin setup 5116 $.fn[pluginName] = function(options) { 5117 if ($(this).length === 0) { 5118 console.warn('No ' + pluginName + ' element exist.'); 5119 return; 5120 } 5121 5122 // global variables 5123 var datatable = this; 5124 5125 // debug enabled? 5126 // 1) state will be cleared on each refresh 5127 // 2) enable some logs 5128 // 3) etc. 5129 datatable.debug = false; 5130 5131 datatable.API = { 5132 record: null, 5133 value: null, 5134 params: null, 5135 }; 5136 5137 var Plugin = { 5138 /******************** 5139 ** PRIVATE METHODS 5140 ********************/ 5141 isInit: false, 5142 cellOffset: 110, 5143 iconOffset: 15, 5144 stateId: 'meta', 5145 ajaxParams: {}, 5146 pagingObject: {}, 5147 5148 init: function(options) { 5149 var isHtmlTable = false; 5150 // data source option empty is normal table 5151 if (options.data.source === null) { 5152 Plugin.extractTable(); 5153 isHtmlTable = true; 5154 } 5155 5156 Plugin.setupBaseDOM.call(); 5157 Plugin.setupDOM(datatable.table); 5158 5159 // set custom query from options 5160 Plugin.setDataSourceQuery(Plugin.getOption('data.source.read.params.query')); 5161 5162 // on event after layout had done setup, show datatable 5163 $(datatable).on(pfx + 'datatable--on-layout-updated', Plugin.afterRender); 5164 5165 if (datatable.debug) { 5166 Plugin.stateRemove(Plugin.stateId); 5167 } 5168 5169 // initialize extensions 5170 $.each(Plugin.getOption('extensions'), function(extName, extOptions) { 5171 if (typeof $.fn[pluginName][extName] === 'function') { 5172 new $.fn[pluginName][extName](datatable, extOptions); 5173 } 5174 }); 5175 5176 Plugin.spinnerCallback(true); 5177 // get data 5178 if (options.data.type === 'remote' || options.data.type === 'local') { 5179 if (options.data.saveState === false 5180 || options.data.saveState.cookie === false 5181 && options.data.saveState.webstorage === false) { 5182 Plugin.stateRemove(Plugin.stateId); 5183 } 5184 // get data for local datatable and local table 5185 if (options.data.type === 'local' && typeof options.data.source === 'object') { 5186 datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(options.data.source); 5187 } 5188 Plugin.dataRender(); 5189 } 5190 5191 // if html table, remove and setup a new header 5192 if (isHtmlTable) { 5193 $(datatable.tableHead).find('tr').remove(); 5194 $(datatable.tableFoot).find('tr').remove(); 5195 } 5196 5197 Plugin.setHeadTitle(); 5198 if (Plugin.getOption('layout.footer')) { 5199 Plugin.setHeadTitle(datatable.tableFoot); 5200 } 5201 5202 // hide header 5203 if (typeof options.layout.header !== 'undefined' && 5204 options.layout.header === false) { 5205 $(datatable.table).find('thead').remove(); 5206 } 5207 5208 // hide footer 5209 if (typeof options.layout.footer !== 'undefined' && 5210 options.layout.footer === false) { 5211 $(datatable.table).find('tfoot').remove(); 5212 } 5213 5214 // for normal and local data type, run layoutUpdate 5215 if (options.data.type === null || 5216 options.data.type === 'local') { 5217 Plugin.setupCellField.call(); 5218 Plugin.setupTemplateCell.call(); 5219 5220 // setup nested datatable, if option enabled 5221 Plugin.setupSubDatatable.call(); 5222 5223 // setup extra system column properties 5224 Plugin.setupSystemColumn.call(); 5225 Plugin.redraw(); 5226 } 5227 5228 var width; 5229 var initialWidth = false; 5230 $(window).resize(function() { 5231 // issue: URL Bar Resizing on mobile, https://developers.google.com/web/updates/2016/12/url-bar-resizing 5232 // trigger datatable resize on width change only 5233 if ($(this).width() !== width) { 5234 width = $(this).width(); 5235 Plugin.fullRender(); 5236 } 5237 // get initial width 5238 if (!initialWidth) { 5239 width = $(this).width(); 5240 initialWidth = true; 5241 } 5242 }); 5243 5244 $(datatable).height(''); 5245 5246 $(Plugin.getOption('search.input')).on('keyup', function(e) { 5247 if (Plugin.getOption('search.onEnter') && e.which !== 13) return; 5248 Plugin.search($(this).val()); 5249 }); 5250 5251 return datatable; 5252 }, 5253 5254 /** 5255 * Extract static HTML table content into datasource 5256 */ 5257 extractTable: function() { 5258 var columns = []; 5259 var headers = $(datatable).find('tr:first-child th').get().map(function(cell, i) { 5260 var field = $(cell).data('field'); 5261 if (typeof field === 'undefined') { 5262 field = $(cell).text().trim(); 5263 } 5264 var column = {field: field, title: field}; 5265 for (var ii in options.columns) { 5266 if (options.columns[ii].field === field) { 5267 column = $.extend(true, {}, options.columns[ii], column); 5268 } 5269 } 5270 columns.push(column); 5271 return field; 5272 }); 5273 // auto create columns config 5274 options.columns = columns; 5275 5276 var rowProp = []; 5277 var source = []; 5278 5279 $(datatable).find('tr').each(function() { 5280 if ($(this).find('td').length) { 5281 rowProp.push($(this).prop('attributes')); 5282 } 5283 var td = {}; 5284 $(this).find('td').each(function(i, cell) { 5285 td[headers[i]] = cell.innerHTML.trim(); 5286 });
5287 if (!util.isEmpty(td)) { 5288 source.push(td); 5289 } 5290 }); 5291 5292 options.data.attr.rowProps = rowProp; 5293 options.data.source = source; 5294 }, 5295 5296 /** 5297 * One time layout update on init 5298 */ 5299 layoutUpdate: function() { 5300 // setup nested datatable, if option enabled 5301 Plugin.setupSubDatatable.call(); 5302 5303 // setup extra system column properties 5304 Plugin.setupSystemColumn.call(); 5305 5306 // setup cell hover event 5307 Plugin.setupHover.call(); 5308 5309 if (typeof options.detail === 'undefined' 5310 // temporary disable lock column in subtable 5311 && Plugin.getDepth() === 1) { 5312 // lock columns handler 5313 Plugin.lockTable.call(); 5314 } 5315 5316 Plugin.resetScroll(); 5317 5318 // check if not is a locked column 5319 if (!Plugin.isLocked()) { 5320 Plugin.redraw.call(); 5321 // check if its not a subtable and has autoHide option enabled 5322 if (!Plugin.isSubtable() && Plugin.getOption('rows.autoHide') === true) { 5323 Plugin.autoHide(); 5324 } 5325 // reset row 5326 $(datatable.table).find('.' + pfx + 'datatable__row').css('height', ''); 5327 } 5328 5329 Plugin.columnHide.call(); 5330 5331 Plugin.rowEvenOdd.call(); 5332 5333 Plugin.sorting.call(); 5334 5335 Plugin.scrollbar.call(); 5336 5337 if (!Plugin.isInit) { 5338 // run once dropdown inside datatable 5339 Plugin.dropdownFix(); 5340 $(datatable).trigger(pfx + 'datatable--on-init', {table: $(datatable.wrap).attr('id'), options: options}); 5341 Plugin.isInit = true; 5342 } 5343 5344 $(datatable).trigger(pfx + 'datatable--on-layout-updated', {table: $(datatable.wrap).attr('id')}); 5345 }, 5346 5347 dropdownFix: function() { 5348 var dropdownMenu; 5349 $('body').on('show.bs.dropdown', '.' + pfx + 'datatable .' + pfx + 'datatable__body', function(e) { 5350 dropdownMenu = $(e.target).find('.dropdown-menu'); 5351 $('body').append(dropdownMenu.detach()); 5352 dropdownMenu.css('display', 'block'); 5353 dropdownMenu.position({ 5354 'my': 'right top', 5355 'at': 'right bottom', 5356 'of': $(e.relatedTarget), 5357 }); 5358 // if datatable is inside modal 5359 if (datatable.closest('.modal').length) { 5360 // increase dropdown z-index 5361 dropdownMenu.css('z-index', '2000'); 5362 } 5363 }).on('hide.bs.dropdown', '.' + pfx + 'datatable .' + pfx + 'datatable__body', function(e) { 5364 $(e.target).append(dropdownMenu.detach()); 5365 dropdownMenu.hide(); 5366 }); 5367 }, 5368 5369 lockTable: function() { 5370 var lock = { 5371 lockEnabled: false, 5372 init: function() { 5373 // check if table should be locked columns 5374 lock.lockEnabled = Plugin.lockEnabledColumns(); 5375 if (lock.lockEnabled.left.length === 0 && 5376 lock.lockEnabled.right.length === 0) { 5377 return; 5378 } 5379 lock.enable(); 5380 }, 5381 enable: function() { 5382 var enableLock = function(tablePart) { 5383 // check if already has lock column 5384 if ($(tablePart).find('.' + pfx + 'datatable__lock').length > 0) { 5385 Plugin.log('Locked container already exist in: ', tablePart); 5386 return; 5387 } 5388 // check if no rows exists 5389 if ($(tablePart).find('.' + pfx + 'datatable__row').length === 0) { 5390 Plugin.log('No row exist in: ', tablePart); 5391 return; 5392 } 5393 5394 // locked div container 5395 var lockLeft = $('<div/>').addClass(pfx + 'datatable__lock ' + pfx + 'datatable__lock--left'); 5396 var lockScroll = $('<div/>').addClass(pfx + 'datatable__lock ' + pfx + 'datatable__lock--scroll'); 5397 var lockRight = $('<div/>').addClass(pfx + 'datatable__lock ' + pfx + 'datatable__lock--right'); 5398 5399 $(tablePart).find('.' + pfx + 'datatable__row').each(function() { 5400 // create new row for lock columns and pass the data 5401 var rowLeft = $('<tr/>').addClass(pfx + 'datatable__row').data('obj', $(this).data('obj')).appendTo(lockLeft); 5402 var rowScroll = $('<tr/>').addClass(pfx + 'datatable__row').data('obj', $(this).data('obj')).appendTo(lockScroll); 5403 var rowRight = $('<tr/>').addClass(pfx + 'datatable__row').data('obj', $(this).data('obj')).appendTo(lockRight); 5404 $(this).find('.' + pfx + 'datatable__cell').each(function() { 5405 var locked = $(this).data('locked'); 5406 if (typeof locked !== 'undefined') { 5407 if (typeof locked.left !== 'undefined' || locked === true) { 5408 // default locked to left 5409 $(this).appendTo(rowLeft); 5410 } 5411 if (typeof locked.right !== 'undefined') { 5412 $(this).appendTo(rowRight); 5413 } 5414 } else { 5415 $(this).appendTo(rowScroll); 5416 } 5417 });
5418 // remove old row 5419 $(this).remove(); 5420 }); 5421 5422 if (lock.lockEnabled.left.length > 0) { 5423 $(datatable.wrap).addClass(pfx + 'datatable--lock'); 5424 $(lockLeft).appendTo(tablePart); 5425 } 5426 if (lock.lockEnabled.left.length > 0 || lock.lockEnabled.right.length > 0) { 5427 $(lockScroll).appendTo(tablePart); 5428 } 5429 if (lock.lockEnabled.right.length > 0) { 5430 $(datatable.wrap).addClass(pfx + 'datatable--lock'); 5431 $(lockRight).appendTo(tablePart); 5432 } 5433 }; 5434 5435 $(datatable.table).find('thead,tbody,tfoot').each(function() { 5436 var tablePart = this; 5437 if ($(this).find('.' + pfx + 'datatable__lock').length === 0) { 5438 $(this).ready(function() { 5439 enableLock(tablePart); 5440 }); 5441 } 5442 }); 5443 }, 5444 }; 5445 lock.init(); 5446 return lock; 5447 }, 5448 5449 /** 5450 * Render everything for resize 5451 */ 5452 fullRender: function() { 5453 $(datatable.tableHead).empty(); 5454 Plugin.setHeadTitle(); 5455 if (Plugin.getOption('layout.footer')) { 5456 $(datatable.tableFoot).empty(); 5457 Plugin.setHeadTitle(datatable.tableFoot); 5458 } 5459 5460 Plugin.spinnerCallback(true); 5461 $(datatable.wrap).removeClass(pfx + 'datatable--loaded'); 5462 5463 Plugin.insertData(); 5464 }, 5465 5466 lockEnabledColumns: function() { 5467 var screen = $(window).width(); 5468 var columns = options.columns; 5469 var enabled = {left: [], right: []}; 5470 $.each(columns, function(i, column) { 5471 if (typeof column.locked !== 'undefined') { 5472 if (typeof column.locked.left !== 'undefined') { 5473 if (util.getBreakpoint(column.locked.left) <= screen) { 5474 enabled['left'].push(column.locked.left); 5475 } 5476 } 5477 if (typeof column.locked.right !== 'undefined') { 5478 if (util.getBreakpoint(column.locked.right) <= screen) { 5479 enabled['right'].push(column.locked.right); 5480 } 5481 } 5482 } 5483 }); 5484 return enabled; 5485 }, 5486 5487 /** 5488 * After render event, called by 5489 * '+pfx+'-datatable--on-layout-updated 5490 * @param e 5491 * @param args 5492 */ 5493 afterRender: function(e, args) { 5494 $(datatable).ready(function() { 5495 // redraw locked columns table 5496 if (Plugin.isLocked()) { 5497 Plugin.redraw(); 5498 } 5499 5500 $(datatable.tableBody).css('visibility', ''); 5501 $(datatable.wrap).addClass(pfx + 'datatable--loaded'); 5502 5503 Plugin.spinnerCallback(false); 5504 }); 5505 }, 5506 5507 hoverTimer: 0, 5508 isScrolling: false, 5509 setupHover: function() { 5510 $(window).scroll(function(e) { 5511 // stop hover when scrolling 5512 clearTimeout(Plugin.hoverTimer); 5513 Plugin.isScrolling = true; 5514 }); 5515 5516 $(datatable.tableBody).find('.' + pfx + 'datatable__cell').off('mouseenter', 'mouseleave').on('mouseenter', function() { 5517 // reset scroll timer to hover class 5518 Plugin.hoverTimer = setTimeout(function() { 5519 Plugin.isScrolling = false; 5520 }, 200); 5521 if (Plugin.isScrolling) return; 5522 5523 // normal table 5524 var row = $(this).closest('.' + pfx + 'datatable__row').addClass(pfx + 'datatable__row--hover'); 5525 var index = $(row).index() + 1; 5526 5527 // lock table 5528 $(row).closest('.' + pfx + 'datatable__lock').parent().find('.' + pfx + 'datatable__row:nth-child(' + index + ')').addClass(pfx + 'datatable__row--hover'); 5529 }).on('mouseleave', function() { 5530 // normal table 5531 var row = $(this).closest('.' + pfx + 'datatable__row').removeClass(pfx + 'datatable__row--hover'); 5532 var index = $(row).index() + 1; 5533 5534 // look table 5535 $(row).closest('.' + pfx + 'datatable__lock').parent().find('.' + pfx + 'datatable__row:nth-child(' + index + ')').removeClass(pfx + 'datatable__row--hover'); 5536 }); 5537 }, 5538 5539 /** 5540 * Adjust width of locked table containers by resize handler 5541 * @returns {number} 5542 */ 5543 adjustLockContainer: function() { 5544 if (!Plugin.isLocked()) return 0; 5545 5546 // refer to head dimension 5547 var containerWidth = $(datatable.tableHead).width(); 5548 var lockLeft = $(datatable.tableHead).find('.' + pfx + 'datatable__lock--left').width(); 5549 var lockRight = $(datatable.tableHead).find('.' + pfx + 'datatable__lock--right').width(); 5550 5551 if (typeof lockLeft === 'undefined') lockLeft = 0; 5552 if (typeof lockRight === 'undefined') lockRight = 0; 5553 5554 var lockScroll = Math.floor(containerWidth - lockLeft - lockRight); 5555 $(datatable.table).find('.' + pfx + 'datatable__lock--scroll').css('width', lockScroll); 5556 5557 return lockScroll; 5558 }, 5559 5560 /** 5561 * todo; not in use 5562 */ 5563 dragResize: function() { 5564 var pressed = false; 5565 var start = undefined; 5566 var startX, startWidth; 5567 $(datatable.tableHead).find('.' + pfx + 'datatable__cell').mou
5567sedown(function(e) { 5568 start = $(this); 5569 pressed = true; 5570 startX = e.pageX; 5571 startWidth = $(this).width(); 5572 $(start).addClass(pfx + 'datatable__cell--resizing'); 5573 5574 }).mousemove(function(e) { 5575 if (pressed) { 5576 var i = $(start).index(); 5577 var tableBody = $(datatable.tableBody); 5578 var ifLocked = $(start).closest('.' + pfx + 'datatable__lock'); 5579 5580 if (ifLocked) { 5581 var lockedIndex = $(ifLocked).index(); 5582 tableBody = $(datatable.tableBody).find('.' + pfx + 'datatable__lock').eq(lockedIndex); 5583 } 5584 5585 $(tableBody).find('.' + pfx + 'datatable__row').each(function(tri, tr) { 5586 $(tr).find('.' + pfx + 'datatable__cell').eq(i).width(startWidth + (e.pageX - startX)).children().width(startWidth + (e.pageX - startX)); 5587 }); 5588 5589 $(start).children().css('width', startWidth + (e.pageX - startX)); 5590 } 5591 5592 }).mouseup(function() { 5593 $(start).removeClass(pfx + 'datatable__cell--resizing'); 5594 pressed = false; 5595 }); 5596 5597 $(document).mouseup(function() { 5598 $(start).removeClass(pfx + 'datatable__cell--resizing'); 5599 pressed = false; 5600 }); 5601 }, 5602 5603 /** 5604 * To prepare placeholder for table before content is loading 5605 */ 5606 initHeight: function() { 5607 if (options.layout.height && options.layout.scroll) { 5608 var theadHeight = $(datatable.tableHead).find('.' + pfx + 'datatable__row').outerHeight(); 5609 var tfootHeight = $(datatable.tableFoot).find('.' + pfx + 'datatable__row').outerHeight(); 5610 var bodyHeight = options.layout.height; 5611 if (theadHeight > 0) { 5612 bodyHeight -= theadHeight; 5613 } 5614 if (tfootHeight > 0) { 5615 bodyHeight -= tfootHeight; 5616 } 5617 5618 // scrollbar offset 5619 bodyHeight -= 2; 5620 5621 $(datatable.tableBody).css('max-height', Math.floor(parseFloat(bodyHeight))); 5622 5623 // set scrollable area fixed height 5624 // $(datatable.tableBody).find('.' + pfx + 'datatable__lock--scroll').css('height', Math.floor(parseFloat(bodyHeight))); 5625 } 5626 }, 5627 5628 /** 5629 * Setup base DOM (table, thead, tbody, tfoot) and create if not 5630 * exist. 5631 */ 5632 setupBaseDOM: function() { 5633 // keep original state before datatable initialize 5634 datatable.initialDatatable = $(datatable).clone(); 5635 5636 // main element 5637 if ($(datatable).prop('tagName') === 'TABLE') { 5638 // if main init element is <table>, wrap with div 5639 datatable.table = $(datatable).removeClass(pfx + 'datatable').addClass(pfx + 'datatable__table'); 5640 if ($(datatable.table).parents('.' + pfx + 'datatable').length === 0) { 5641 datatable.table.wrap($('<div/>').addClass(pfx + 'datatable').addClass(pfx + 'datatable--' + options.layout.theme)); 5642 datatable.wrap = $(datatable.table).parent(); 5643 } 5644 } else { 5645 // create table 5646 datatable.wrap = $(datatable).addClass(pfx + 'datatable').addClass(pfx + 'datatable--' + options.layout.theme); 5647 datatable.table = $('<table/>').addClass(pfx + 'datatable__table').appendTo(datatable); 5648 } 5649 5650 if (typeof options.layout.class !== 'undefined') { 5651 $(datatable.wrap).addClass(options.layout.class); 5652 } 5653 5654 $(datatable.table).removeClass(pfx + 'datatable--destroyed').css('display', 'block'); 5655 5656 // force disable save state 5657 if (typeof $(datatable).attr('id') === 'undefined') { 5658 Plugin.setOption('data.saveState', false); 5659 $(datatable.table).attr('id', util.getUniqueID(pfx + 'datatable--')); 5660 } 5661 5662 // predefine table height 5663 if (Plugin.getOption('layout.minHeight')) 5664 $(datatable.table).css('min-height', Plugin.getOption('layout.minHeight')); 5665 5666 if (Plugin.getOption('layout.height')) 5667 $(datatable.table).css('max-height', Plugin.getOption('layout.height')); 5668 5669 // for normal table load 5670 if (options.data.type === null) { 5671 $(datatable.table).css('width', '').css('display', ''); 5672 } 5673 5674 // create table head element 5675 datatable.tableHead = $(datatable.table).find('thead'); 5676 if ($(datatable.tableHead).length === 0) { 5677 datatable.tableHead = $('<thead/>').prependTo(datatable.table); 5678 } 5679 5680 // create table head element 5681 datatable.tableBody = $(datatable.table).find('tbody'); 5682 if ($(datatable.tableBody).length === 0) { 5683 datatable.tableBody = $('<tbody/>').appendTo(datatable.table); 5684 } 5685 5686 if (typeof options.layout.footer !== 'undefined' && 5687 options.layout.footer) { 5688 // create table foot element 5689 datatable.tableFoot = $(datatable.table).find('tfoot'); 5690 if ($(datatable.tableFoot).length === 0) { 5691 datatable.tableFoot = $('<tfoot/>').appendTo(datatable.table); 5692 } 5693 } 5694 }, 5695 5696 /** 5697 * Set column data before table manipulation. 5698 */ 5699 setupCellField: function(tableParts) { 5700 if (typeof tableParts === 'undefined') tableParts = $(datatable.table).children();
5701 var columns = options.columns; 5702 $.each(tableParts, function(part, tablePart) { 5703 $(tablePart).find('.' + pfx + 'datatable__row').each(function(tri, tr) { 5704 // prepare data 5705 $(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) { 5706 if (typeof columns[tdi] !== 'undefined') { 5707 $(td).data(columns[tdi]); 5708 } 5709 }); 5710 }); 5711 }); 5712 }, 5713 5714 /** 5715 * Set column template callback 5716 * @param tablePart 5717 */ 5718 setupTemplateCell: function(tablePart) { 5719 if (typeof tablePart === 'undefined') tablePart = datatable.tableBody; 5720 var columns = options.columns; 5721 $(tablePart).find('.' + pfx + 'datatable__row').each(function(tri, tr) { 5722 // row data object, if any 5723 var obj = $(tr).data('obj'); 5724 if (typeof obj === 'undefined') { 5725 return; 5726 } 5727 5728 // @deprecated in v5.0.6 5729 // obj['getIndex'] = function() { 5730 // return tri; 5731 // }; 5732 // @deprecated in v5.0.6 5733 // obj['getDatatable'] = function() { 5734 // return datatable; 5735 // }; 5736 5737 // @deprecated in v5.0.6 5738 var rowCallback = Plugin.getOption('rows.callback'); 5739 if (typeof rowCallback === 'function') { 5740 rowCallback($(tr), obj, tri); 5741 } 5742 // before template row callback 5743 var beforeTemplate = Plugin.getOption('rows.beforeTemplate'); 5744 if (typeof beforeTemplate === 'function') { 5745 beforeTemplate($(tr), obj, tri); 5746 } 5747 // if data object is undefined, collect from table 5748 if (typeof obj === 'undefined') { 5749 obj = {}; 5750 $(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) { 5751 // get column settings by field 5752 var column = $.grep(columns, function(n, i) { 5753 return $(td).data('field') === n.field; 5754 })[0]; 5755 if (typeof column !== 'undefined') { 5756 obj[column['field']] = $(td).text(); 5757 } 5758 }); 5759 } 5760 5761 $(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) { 5762 // get column settings by field 5763 var column = $.grep(columns, function(n, i) { 5764 return $(td).data('field') === n.field; 5765 })[0]; 5766 if (typeof column !== 'undefined') { 5767 // column template 5768 if (typeof column.template !== 'undefined') { 5769 var finalValue = ''; 5770 // template string 5771 if (typeof column.template === 'string') { 5772 finalValue = Plugin.dataPlaceholder(column.template, obj); 5773 } 5774 // template callback function 5775 if (typeof column.template === 'function') { 5776 finalValue = column.template(obj, tri, datatable); 5777 } 5778 5779 // sanitize using DOMPurify if installed 5780 if (typeof DOMPurify !== 'undefined') { 5781 finalValue = DOMPurify.sanitize(finalValue); 5782 } 5783 5784 var span = document.createElement('span'); 5785 span.innerHTML = finalValue; 5786 5787 // insert to cell, wrap with span 5788 $(td).html(span); 5789 5790 // set span overflow 5791 if (typeof column.overflow !== 'undefined') { 5792 $(span).css('overflow', column.overflow); 5793 $(span).css('position', 'relative'); 5794 } 5795 } 5796 } 5797 }); 5798 5799 // after template row callback 5800 var afterTemplate = Plugin.getOption('rows.afterTemplate'); 5801 if (typeof afterTemplate === 'function') { 5802 afterTemplate($(tr), obj, tri); 5803 } 5804 }); 5805 }, 5806 5807 /** 5808 * Setup extra system column properties 5809 * Note: selector checkbox, subtable toggle 5810 */ 5811 setupSystemColumn: function() { 5812 datatable.dataSet = datatable.dataSet || []; 5813 // no records available 5814 if (datatable.dataSet.length === 0) return; 5815 5816 var columns = options.columns; 5817 $(datatable.tableBody).find('.' + pfx + 'datatable__row').each(function(tri, tr) { 5818 $(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) { 5819 // get column settings by field 5820 var column = $.grep(columns, function(n, i) { 5821 return $(td).data('field') === n.field; 5822 })[0]; 5823 if (typeof column !== 'undefined') { 5824 var value = $(td).text(); 5825 5826 // enable column selector 5827 if (typeof column.selector !== 'undefined' && column.selector !== false) { 5828 // check if checkbox exist 5829 if ($(td).find('.' + pfx + 'checkbox [type="checkbox"]').length > 0) return; 5830 5831 $(td).addClass(pfx + 'datatable__cell--check'); 5832 5833 // append checkbox 5834 var chk = $('<label/>'). 5835 addClass(pfx + 'checkbox ' + pfx + 'checkbox--single'). 5836 append($('<input/>').attr('type', 'checkbox').attr('value', value).on('click', function() { 5837 if ($(this).is(':checked')) { 5838 // add checkbox active row class 5839 Plugin.setActive(this); 5840 } else { 5841 // add checkbox active row class 5842 Plugin.setInactive(this); 5843 } 5844 })). 5845 append(' <span></span>'); 5846 5847 // checkbox selector has outline style 5848 if (typeof column.selector.class !== 'undefined') { 5849 $(chk).addClass(column.selector.class); 5850 } 5851 5852 $(td).children().html(chk); 5853 } 5854 5855 // enable column subtable toggle 5856 if (typeof column.subtable !== 'undefined' && column.subtable) { 5857 // check if subtable toggle exist 5858 if ($(td).find('.' + pfx + 'datatable__toggle-subtable').length > 0) return; 5859 // append subtable toggle 5860 $(td). 5861 children(). 5862 html($('<a/>'). 5863 addClass(pfx + 'datatable__toggle-subtable'). 5864 attr('href', '#'). 5865 attr('data-value', value). 5866 append($('<i/>').addClass(Plugin.getOption('layout.icons.rowDetail.collapse')))); 5867 } 5868 } 5869 });
5870 }); 5871 5872 // init checkbox for header/footer 5873 var initCheckbox = function(tr) { 5874 // get column settings by field 5875 var column = $.grep(columns, function(n, i) { 5876 return typeof n.selector !== 'undefined' && n.selector !== false; 5877 })[0]; 5878 5879 if (typeof column !== 'undefined') { 5880 // enable column selector 5881 if (typeof column.selector !== 'undefined' && column.selector !== false) { 5882 var td = $(tr).find('[data-field="' + column.field + '"]'); 5883 // check if checkbox exist 5884 if ($(td).find('.' + pfx + 'checkbox [type="checkbox"]').length > 0) return; 5885 5886 $(td).addClass(pfx + 'datatable__cell--check'); 5887 5888 // append checkbox 5889 var chk = $('<label/>'). 5890 addClass(pfx + 'checkbox ' + pfx + 'checkbox--single ' + pfx + 'checkbox--all'). 5891 append($('<input/>').attr('type', 'checkbox').on('click', function() { 5892 if ($(this).is(':checked')) { 5893 Plugin.setActiveAll(true); 5894 } else { 5895 Plugin.setActiveAll(false); 5896 } 5897 })). 5898 append(' <span></span>'); 5899 5900 // checkbox selector has outline style 5901 if (typeof column.selector.class !== 'undefined') { 5902 $(chk).addClass(column.selector.class); 5903 } 5904 5905 $(td).children().html(chk); 5906 } 5907 } 5908 }; 5909 5910 if (options.layout.header) {
5911 initCheckbox($(datatable.tableHead).find('.' + pfx + 'datatable__row').first()); 5912 } 5913 if (options.layout.footer) { 5914 initCheckbox($(datatable.tableFoot).find('.' + pfx + 'datatable__row').first()); 5915 } 5916 }, 5917 5918 maxWidthList: {}, 5919 5920 /** 5921 * Adjust width to match container size 5922 */ 5923 adjustCellsWidth: function() { 5924 // get table width 5925 var containerWidth = $(datatable.tableBody).innerWidth() - Plugin.iconOffset; 5926 5927 // get total number of columns 5928 var columns = $(datatable.tableBody). 5929 find('.' + pfx + 'datatable__row:first-child'). 5930 find('.' + pfx + 'datatable__cell'). 5931 // exclude expand icon 5932 not('.' + pfx + 'datatable__toggle-detail'). 5933 not(':hidden').length; 5934 5935 if (columns > 0) { 5936 // remove reserved sort icon width 5937 containerWidth = containerWidth - (Plugin.iconOffset * columns); 5938 var minWidth = Math.floor(containerWidth / columns); 5939 5940 // minimum width 5941 if (minWidth <= Plugin.cellOffset) { 5942 minWidth = Plugin.cellOffset; 5943 } 5944 5945 $(datatable.table).find('.' + pfx + 'datatable__row'). 5946 find('.' + pfx + 'datatable__cell').
5947 // exclude expand icon 5948 not('.' + pfx + 'datatable__toggle-detail'). 5949 not(':hidden').each(function(tdi, td) { 5950 5951 var width = minWidth; 5952 var dataWidth = $(td).data('width'); 5953 5954 if (typeof dataWidth !== 'undefined') { 5955 if (dataWidth === 'auto') { 5956 var field = $(td).data('field'); 5957 if (Plugin.maxWidthList[field]) { 5958 width = Plugin.maxWidthList[field]; 5959 } 5960 else { 5961 var cells = $(datatable.table).find('.' + pfx + 'datatable__cell[data-field="' + field + '"]'); 5962 width = Plugin.maxWidthList[field] = Math.max.apply(null, 5963 $(cells).map(function() { 5964 return $(this).outerWidth(); 5965 }).get()); 5966 } 5967 } 5968 else { 5969 width = dataWidth; 5970 } 5971 } 5972 $(td).children().css('width', Math.ceil(width)); 5973 }); 5974 } 5975 5976 return datatable; 5977 }, 5978 5979 /** 5980 * Adjust height to match container size 5981 */ 5982 adjustCellsHeight: function() { 5983 $.each($(datatable.table).children(), function(part, tablePart) { 5984 var totalRows = $(tablePart).find('.' + pfx + 'datatable__row').first().parent().find('.' + pfx + 'datatable__row').length; 5985 for (var i = 1; i <= totalRows; i++) { 5986 var rows = $(tablePart).find('.' + pfx + 'datatable__row:nth-child(' + i + ')'); 5987 if ($(rows).length > 0) { 5988 var maxHeight = Math.max.apply(null, $(rows).map(function() { 5989 return $(this).outerHeight(); 5990 }).get()); 5991 $(rows).css('height', Math.ceil(maxHeight)); 5992 } 5993 } 5994 }); 5995 }, 5996 5997 /** 5998 * Setup table DOM and classes 5999 */ 6000 setupDOM: function(table) { 6001 // set table classes 6002 $(table).find('> thead').addClass(pfx + 'datatable__head'); 6003 $(table).find('> tbody').addClass(pfx + 'datatable__body'); 6004 $(table).find('> tfoot').addClass(pfx + 'datatable__foot'); 6005 $(table).find('tr').addClass(pfx + 'datatable__row'); 6006 $(table).find('tr > th, tr > td').addClass(pfx + 'datatable__cell'); 6007 $(table).find('tr > th, tr > td').each(function(i, td) { 6008 if ($(td).find('span').length === 0) { 6009 $(td).wrapInner($('<span/>').css('width', Plugin.cellOffset)); 6010 } 6011 }); 6012 }, 6013 6014 /** 6015 * Default scrollbar 6016 * @returns {{tableLocked: null, init: init, onScrolling: 6017 * onScrolling}} 6018 */ 6019 scrollbar: function() { 6020 var scroll = { 6021 scrollable: null, 6022 tableLocked: null, 6023 initPosition: null, 6024 init: function() { 6025 var screen = util.getViewPort().width; 6026 // setup scrollable datatable 6027 if (options.layout.scroll) { 6028 // add scrollable datatable class 6029 $(datatable.wrap).addClass(pfx + 'datatable--scroll'); 6030 6031 var scrollable = $(datatable.tableBody).find('.' + pfx + 'datatable__lock--scroll'); 6032 6033 // check if scrollable area have rows 6034 if ($(scrollable).find('.' + pfx + 'datatable__row').length > 0 && $(scrollable).length > 0) { 6035 scroll.scrollHead = $(datatable.tableHead).find('> .' + pfx + 'datatable__lock--scroll > .' + pfx + 'datatable__row'); 6036 scroll.scrollFoot = $(datatable.tableFoot).find('> .' + pfx + 'datatable__lock--scroll > .' + pfx + 'datatable__row'); 6037 scroll.tableLocked = $(datatable.tableBody).find('.' + pfx + 'datatable__lock:not(.' + pfx + 'datatable__lock--scroll)'); 6038 if (Plugin.getOption('layout.customScrollbar') && util.detectIE() != 10 && screen > util.getBreakpoint('lg')) { 6039 scroll.initCustomScrollbar(scrollable[0]); 6040 } else { 6041 scroll.initDefaultScrollbar(scrollable); 6042 } 6043 } else if ($(datatable.tableBody).find('.' + pfx + 'datatable__row').length > 0) { 6044 scroll.scrollHead = $(datatable.tableHead).find('> .' + pfx + 'datatable__row'); 6045 scroll.scrollFoot = $(datatable.tableFoot).find('> .' + pfx + 'datatable__row'); 6046 if (Plugin.getOption('layout.customScrollbar') && util.detectIE() != 10 && screen > util.getBreakpoint('lg')) { 6047 scroll.initCustomScrollbar(datatable.tableBody); 6048 } else { 6049 scroll.initDefaultScrollbar(datatable.tableBody); 6050 } 6051 } 6052 } 6053 }, 6054 initDefaultScrollbar: function(scrollable) { 6055 // get initial scroll position 6056 scroll.initPosition = $(scrollable).scrollLeft(); 6057 $(scrollable).css('overflow-y', 'auto').off().on('scroll', scroll.onScrolling); 6058 $(scrollable).css('overflow-x', 'auto'); 6059 }, 6060 onScrolling: function(e) { 6061 var left = $(this).scrollLeft(); 6062 var top = $(this).scrollTop(); 6063 if (util.isRTL()) {
6064 // deduct initial position for RTL 6065 left = left - scroll.initPosition; 6066 } 6067 $(scroll.scrollHead).css('left', -left); 6068 $(scroll.scrollFoot).css('left', -left); 6069 $(scroll.tableLocked).each(function(i, table) { 6070 if (Plugin.isLocked()) { 6071 // scrollbar offset 6072 top -= 1; 6073 } 6074 $(table).css('top', -top); 6075 }); 6076 }, 6077 initCustomScrollbar: function(scrollable) { 6078 scroll.scrollable = scrollable; 6079 // create a new instance for table body with scrollbar 6080 Plugin.initScrollbar(scrollable); 6081 // get initial scroll position 6082 scroll.initPosition = $(scrollable).scrollLeft(); 6083 $(scrollable).off().on('scroll', scroll.onScrolling); 6084 }, 6085 }; 6086 scroll.init(); 6087 return scroll; 6088 }, 6089 6090 /** 6091 * Init custom scrollbar and reset position 6092 * @param element 6093 * @param options 6094 */ 6095 initScrollbar: function(element, options) { 6096 if (!element || !element.nodeName) { 6097 return; 6098 } 6099 $(datatable.tableBody).css('overflow', ''); 6100 var ps = $(element).data('ps'); 6101 if (util.hasClass(element, 'ps') && typeof ps !== 'undefined') { 6102 ps.update(); 6103 } else { 6104 ps = new PerfectScrollbar(element, Object.assign({}, { 6105 wheelSpeed: 0.5, 6106 swipeEasing: true, 6107 // wheelPropagation: false, 6108 minScrollbarLength: 40, 6109 maxScrollbarLength: 300, 6110 suppressScrollX: Plugin.getOption('rows.autoHide') && !Plugin.isLocked() 6111 }, options)); 6112 $(element).data('ps', ps); 6113 } 6114 6115 // reset perfect scrollbar on resize 6116 $(window).resize(function() { 6117 ps.update(); 6118 }); 6119 }, 6120 6121 /** 6122 * Set column title from options.columns settings 6123 */ 6124 setHeadTitle: function(tablePart) { 6125 if (typeof tablePart === 'undefined') tablePart = datatable.tableHead; 6126 tablePart = $(tablePart)[0]; 6127 var columns = options.columns; 6128 var row = tablePart.getElementsByTagName('tr')[0]; 6129 var ths = tablePart.getElementsByTagName('td'); 6130 6131 if (typeof row === 'undefined') { 6132 row = document.createElement('tr'); 6133 tablePart.appendChild(row); 6134 } 6135 6136 $.each(columns, function(i, column) { 6137 var th = ths[i]; 6138 if (typeof th === 'undefined') { 6139 th = document.createElement('th'); 6140 row.appendChild(th); 6141 } 6142 6143 // set column title 6144 if (typeof column['title'] !== 'undefined') { 6145 th.innerHTML = column.title; 6146 th.setAttribute('data-field', column.field); 6147 util.addClass(th, column.class); 6148 // set disable autoHide or force enable 6149 if (typeof column.autoHide !== 'undefined') { 6150 if (column.autoHide !== true) { 6151 th.setAttribute('data-autohide-disabled', column.autoHide); 6152 } else { 6153 th.setAttribute('data-autohide-enabled', column.autoHide); 6154 } 6155 } 6156 $(th).data(column); 6157 } 6158 6159 // set header attr option 6160 if (typeof column.attr !== 'undefined') { 6161 $.each(column.attr, function(key, val) { 6162 th.setAttribute(key, val); 6163 }); 6164 } 6165 6166 // apply text align to thead/tfoot 6167 if (typeof column.textAlign !== 'undefined') { 6168 var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : ''; 6169 util.addClass(th, align); 6170 } 6171 }); 6172 Plugin.setupDOM(tablePart); 6173 }, 6174 6175 /** 6176 * Initiate to get remote or local data via ajax 6177 */ 6178 dataRender: function(action) { 6179 $(datatable.table).siblings('.' + pfx + 'datatable__pager').removeClass(pfx + 'datatable--paging-loaded'); 6180 6181 var buildMeta = function() { 6182 datatable.dataSet = datatable.dataSet || []; 6183 Plugin.localDataUpdate(); 6184 // local pagination meta 6185 var meta = Plugin.getDataSourceParam('pagination'); 6186 if (meta.perpage === 0) { 6187 meta.perpage = options.data.pageSize || 10; 6188 } 6189 meta.total = datatable.dataSet.length; 6190 var start = Math.max(meta.perpage * (meta.page - 1), 0); 6191 var end = Math.min(start + meta.perpage, meta.total); 6192 datatable.dataSet = $(datatable.dataSet).slice(start, end); 6193 return meta; 6194 }; 6195 6196 var afterGetData = function(result) { 6197 var localPagingCallback = function(ctx, meta) { 6198 if (!$(ctx.pager).hasClass(pfx + 'datatable--paging-loaded')) { 6199 $(ctx.pager).remove(); 6200 ctx.init(meta); 6201 } 6202 $(ctx.pager).off().on(pfx + 'datatable--on-goto-page', function(e) { 6203 $(ctx.pager).remove(); 6204 ctx.init(meta); 6205 });
6206 6207 var start = Math.max(meta.perpage * (meta.page - 1), 0); 6208 var end = Math.min(start + meta.perpage, meta.total); 6209 6210 Plugin.localDataUpdate(); 6211 datatable.dataSet = $(datatable.dataSet).slice(start, end); 6212 6213 // insert data into table content 6214 Plugin.insertData(); 6215 }; 6216 6217 $(datatable.wrap).removeClass(pfx + 'datatable--error'); 6218 // pagination enabled 6219 if (options.pagination) { 6220 if (options.data.serverPaging && options.data.type !== 'local') { 6221 // server pagination 6222 var serverMeta = Plugin.getObject('meta', result || null); 6223 if (serverMeta !== null) { 6224 Plugin.pagingObject = Plugin.paging(serverMeta); 6225 } else { 6226 // no meta object from server response, fallback to local pagination 6227 Plugin.pagingObject = Plugin.paging(buildMeta(), localPagingCallback); 6228 } 6229 } else { 6230 // local pagination can be used by remote data also 6231 Plugin.pagingObject = Plugin.paging(buildMeta(), localPagingCallback); 6232 } 6233 } else { 6234 // pagination is disabled 6235 Plugin.localDataUpdate(); 6236 } 6237 // insert data into table content 6238 Plugin.insertData(); 6239 }; 6240 6241 // get local datasource 6242 if (options.data.type === 'local' 6243 // for remote json datasource 6244 // || typeof options.data.source.read === 'undefined' && datatable.dataSet !== null 6245 // for remote datasource, server sorting is disabled and data already received from remote 6246 || options.data.serverSorting === false && action === 'sort' 6247 || options.data.serverFiltering === false && action === 'search' 6248 ) { 6249 setTimeout(function() { 6250 afterGetData(); 6251 Plugin.setAutoColumns(); 6252 }); 6253 return; 6254 } 6255 6256 // getting data from remote only 6257 Plugin.getData().done(afterGetData); 6258 }, 6259 6260 /** 6261 * Process ajax data 6262 */ 6263 insertData: function() { 6264 datatable.dataSet = datatable.dataSet || []; 6265 var params = Plugin.getDataSourceParam(); 6266 6267 // get row attributes 6268 var pagination = params.pagination; 6269 var start = (Math.max(pagination.page, 1) - 1) * pagination.perpage; 6270 var end = Math.min(pagination.page, pagination.pages) * pagination.perpage; 6271 var rowProps = {}; 6272 if (typeof options.data.attr.rowProps !== 'undefined' && options.data.attr.rowProps.length) { 6273 rowProps = options.data.attr.rowProps.slice(start, end); 6274 } 6275 6276 var tableBody = document.createElement('tbody'); 6277 tableBody.style.visibility = 'hidden'; 6278 var colLength = options.columns.length; 6279 6280 $.each(datatable.dataSet, function(rowIndex, row) { 6281 var tr = document.createElement('tr'); 6282 tr.setAttribute('data-row', rowIndex); 6283 // keep data object to row 6284 $(tr).data('obj', row); 6285 6286 if (typeof rowProps[rowIndex] !== 'undefined') { 6287 $.each(rowProps[rowIndex], function() { 6288 tr.setAttribute(this.name, this.value); 6289 }); 6290 } 6291 6292 var cellIndex = 0; 6293 var tds = []; 6294 for (var a = 0; a < colLength; a += 1) { 6295 var column = options.columns[a]; 6296 var classes = []; 6297 // add sorted class to cells 6298 if (Plugin.getObject('sort.field', params) === column.field) { 6299 classes.push(pfx + 'datatable__cell--sorted'); 6300 } 6301 6302 // apply text align 6303 if (typeof column.textAlign !== 'undefined') { 6304 var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : ''; 6305 classes.push(align); 6306 } 6307 6308 // var classAttr = ''; 6309 if (typeof column.class !== 'undefined') { 6310 classes.push(column.class); 6311 } 6312 6313 var td = document.createElement('td'); 6314 util.addClass(td, classes.join(' ')); 6315 td.setAttribute('data-field', column.field); 6316 // set disable autoHide or force enable 6317 if (typeof column.autoHide !== 'undefined') { 6318 if (column.autoHide !== true) { 6319 td.setAttribute('data-autohide-disabled', column.autoHide); 6320 } else { 6321 td.setAttribute('data-autohide-enabled', column.autoHide); 6322 } 6323 } 6324 td.innerHTML = Plugin.getObject(column.field, row); 6325 tr.appendChild(td); 6326 } 6327 6328 tableBody.appendChild(tr); 6329 }); 6330 6331 // display no records message 6332 if (datatable.dataSet.length === 0) { 6333 var errorSpan = document.createElement('span'); 6334 util.addClass(errorSpan, pfx + 'datatable--error'); 6335 errorSpan.innerHTML = Plugin.getOption('translate.records.noRecords'); 6336 tableBody.appendChild(errorSpan); 6337 $(datatable.wrap).addClass(pfx + 'datatable--error ' + pfx + 'datatable--loaded'); 6338 Plugin.spinnerCallback(false); 6339 } 6340 6341 // replace existing table body 6342 $(datatable.tableBody).replaceWith(tableBody); 6343 datatable.tableBody = tableBody; 6344 6345 // layout update 6346 Plugin.setupDOM(datatable.table); 6347 Plugin.setupCellField([datatable.tableBody]); 6348 Plugin.setupTemplateCell(datatable.tableBody); 6349 Plugin.layoutUpdate(); 6350 }, 6351 6352 updateTableComponents: function() { 6353 datatable.tableHead = $(datatable.table).children('thead').get(0); 6354 datatable.tableBody = $(datatable.table).children('tbody').get(0); 6355 datatable.tableFoot = $(datatable.table).children('tfoot').get(0); 6356 }, 6357 6358 /** 6359 * Call ajax for raw JSON data 6360 */ 6361 getData: function() { 6362 // Plugin.spinnerCallback(true); 6363 6364 var ajaxParams = { 6365 dataType: 'json', 6366 method: 'POST', 6367 data: {}, 6368 timeout: Plugin.getOption('data.source.read.timeout') || 30000, 6369 }; 6370 6371 if (options.data.type === 'local') { 6372 ajaxParams.url = options.data.source; 6373 } 6374 6375 if (options.data.type === 'remote') { 6376 var data = Plugin.getDataSourceParam(); 6377 // remove if server params is not enabled 6378 if (!Plugin.getOption('data.serverPaging')) { 6379 delete data['pagination']; 6380 } 6381 if (!Plugin.getOption('data.serverSorting')) { 6382 delete data['sort']; 6383 } 6384 ajaxParams.data = $.extend({}, ajaxParams.data, Plugin.getOption('data.source.read.params'), data); 6385 ajaxParams = $.extend({}, ajaxParams, Plugin.getOption('data.source.read')); 6386 6387 if (typeof ajaxParams.url !== 'string') ajaxParams.url = Plugin.getOption('data.source.read'); 6388 if (typeof ajaxParams.url !== 'string') ajaxParams.url = Plugin.getOption('data.source'); 6389 // ajaxParams.data = $.extend(ajaxParams.data, data.pagination); 6390 } 6391 6392 return $.ajax(ajaxParams).done(function(response, textStatus, jqXHR) { 6393 datatable.lastResponse = response; 6394 // extendible data map callback for custom datasource 6395 datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(response); 6396 Plugin.setAutoColumns(); 6397 $(datatable).trigger(pfx + 'datatable--on-ajax-done', [datatable.dataSet]); 6398 }).fail(function(jqXHR, textStatus, errorThrown) { 6399 $(datatable).trigger(pfx + 'datatable--on-ajax-fail', [jqXHR]); 6400 $(datatable.tableBody).html($('<span/>').addClass(pfx + 'datatable--error').html(Plugin.getOption('translate.records.noRecords'))); 6401 $(datatable.wrap).addClass(pfx + 'datatable--error ' + pfx + 'datatable--loaded'); 6402 Plugin.spinnerCallback(false); 6403 }).always(function() { 6404 }); 6405 }, 6406 6407 /** 6408 * Pagination object 6409 * @param meta if null, local pagination, otherwise remote 6410 * pagination 6411 * @param callback for update data when navigating page 6412 */ 6413 paging: function(meta, callback) { 6414 var pg = { 6415 meta: null, 6416 pager: null, 6417 paginateEvent: null, 6418 pagerLayout: {pagination: null, info: null}, 6419 callback: null, 6420 init: function(meta) { 6421 pg.meta = meta; 6422 6423 // parse pagination meta to integer 6424 pg.meta.page = parseInt(pg.meta.page); 6425 pg.meta.pages = parseInt(pg.meta.pages); 6426 pg.meta.perpage = parseInt(pg.meta.perpage); 6427 pg.meta.total = parseInt(pg.meta.total); 6428
6429 // always recount total pages 6430 pg.meta.pages = Math.max(Math.ceil(pg.meta.total / pg.meta.perpage), 1); 6431 6432 // current page must be not over than total pages 6433 if (pg.meta.page > pg.meta.pages) pg.meta.page = pg.meta.pages; 6434 6435 // set unique event name between tables 6436 pg.paginateEvent = Plugin.getTablePrefix('paging'); 6437 6438 pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable__pager'); 6439 if ($(pg.pager).hasClass(pfx + 'datatable--paging-loaded')) return; 6440 6441 // if class .'+pfx+'datatable--paging-loaded not exist, recreate pagination 6442 $(pg.pager).remove(); 6443 6444 // if no pages available 6445 if (pg.meta.pages === 0) return; 6446 6447 // update datasource params 6448 Plugin.setDataSourceParam('pagination', { 6449 page: pg.meta.page, 6450 pages: pg.meta.pages, 6451 perpage: pg.meta.perpage, 6452 total: pg.meta.total, 6453 }); 6454 6455 // default callback function, contains remote pagination handler 6456 pg.callback = pg.serverCallback; 6457 // custom callback function 6458 if (typeof callback === 'function') pg.callback = callback; 6459 6460 pg.addPaginateEvent(); 6461 pg.populate(); 6462 6463 pg.meta.page = Math.max(pg.meta.page || 1, pg.meta.page); 6464 6465 $(datatable).trigger(pg.paginateEvent, pg.meta); 6466 6467 pg.pagingBreakpoint.call(); 6468 $(window).resize(pg.pagingBreakpoint); 6469 }, 6470 serverCallback: function(ctx, meta) { 6471 Plugin.dataRender(); 6472 }, 6473 populate: function() { 6474 var icons = Plugin.getOption('layout.icons.pagination'); 6475 var title = Plugin.getOption('translate.toolbar.pagination.items.default'); 6476 // pager root element 6477 pg.pager = $('<div/>').addClass(pfx + 'datatable__pager ' + pfx + 'datatable--paging-loaded'); 6478 // numbering links 6479 var pagerNumber = $('<ul/>').addClass(pfx + 'datatable__pager-nav'); 6480 pg.pagerLayout['pagination'] = pagerNumber; 6481 6482 // pager first/previous button 6483 $('<li/>'). 6484 append($('<a/>'). 6485 attr('title', title.first). 6486 addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--first'). 6487 append($('<i/>').addClass(icons.first)). 6488 on('click', pg.gotoMorePage). 6489 attr('data-page', 1)). 6490 appendTo(pagerNumber); 6491 $('<li/>'). 6492 append($('<a/>'). 6493 attr('title', title.prev). 6494 addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--prev'). 6495 append($('<i/>').addClass(icons.prev)). 6496 on('click', pg.gotoMorePage)). 6497 appendTo(pagerNumber); 6498 6499 // more previous pages 6500 $('<li/>'). 6501 append($('<a/>'). 6502 attr('title', title.more). 6503 addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--more-prev'). 6504 html($('<i/>').addClass(icons.more)). 6505 on('click', pg.gotoMorePage)). 6506 appendTo(pagerNumber); 6507 6508 $('<li/>').append($('<input/>').attr('type', 'text').addClass(pfx + 'pager-input form-control').attr('title', title.input).on('keyup', function() { 6509 // on keyup update [data-page] 6510 $(this).attr('data-page', Math.abs($(this).val())); 6511 }).on('keypress', function(e) { 6512 // on keypressed enter button 6513 if (e.which === 13) pg.gotoMorePage(e); 6514 })).appendTo(pagerNumber); 6515 6516 var pagesNumber = Plugin.getOption('toolbar.items.pagination.pages.desktop.pagesNumber'); 6517 var end = Math.ceil(pg.meta.page / pagesNumber) * pagesNumber; 6518 var start = end - pagesNumber; 6519 if (end > pg.meta.pages) { 6520 end = pg.meta.pages; 6521 } 6522 for (var x = start; x < end; x++) { 6523 var pageNumber = x + 1; 6524 $('<li/>'). 6525 append($('<a/>'). 6526 addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link-number'). 6527 text(pageNumber). 6528 attr('data-page', pageNumber). 6529 attr('title', pageNumber). 6530 on('click', pg.gotoPage)). 6531 appendTo(pagerNumber); 6532 } 6533 6534 // more next pages 6535 $('<li/>'). 6536 append($('<a/>'). 6537 attr('title', title.more). 6538 addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--more-next'). 6539 html($('<i/>').addClass(icons.more)). 6540 on('click', pg.gotoMorePage)). 6541 appendTo(pagerNumber); 6542 6543 // pager next/last button 6544 $('<li/>'). 6545 append($('<a/>'). 6546 attr('title', title.next). 6547 addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--next'). 6548 append($('<i/>').addClass(icons.next)). 6549 on('click', pg.gotoMorePage)). 6550 appendTo(pagerNumber); 6551 $('<li/>'). 6552 append($('<a/>'). 6553 attr('title', title.last). 6554 addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--last'). 6555 append($('<i/>').addClass(icons.last)). 6556 on('click', pg.gotoMorePage). 6557 attr('data-page', pg.meta.pages)). 6558 appendTo(pagerNumber); 6559 6560 // page info 6561 if (Plugin.getOption('toolbar.items.info')) { 6562 pg.pagerLayout['info'] = $('<div/>').addClass(pfx + 'datatable__pager-info').append($('<span/>').addClass(pfx + 'datatable__pager-detail')); 6563 } 6564 6565 $.each(Plugin.getOption('toolbar.layout'), function(i, layout) { 6566 $(pg.pagerLayout[layout]).appendTo(pg.pager); 6567 });
6568 6569 // page size select 6570 var pageSizeSelect = $('<select/>'). 6571 addClass('selectpicker ' + pfx + 'datatable__pager-size'). 6572 attr('title', Plugin.getOption('translate.toolbar.pagination.items.default.select')). 6573 attr('data-width', '60px'). 6574 attr('data-container', 'body'). 6575 val(pg.meta.perpage). 6576 on('change', pg.updatePerpage). 6577 prependTo(pg.pagerLayout['info']); 6578 6579 var pageSizes = Plugin.getOption('toolbar.items.pagination.pageSizeSelect'); 6580 // default value here, to fix override option by user 6581 if (pageSizes.length == 0) pageSizes = [10, 20, 30, 50, 100]; 6582 $.each(pageSizes, function(i, size) { 6583 var display = size; 6584 if (size === -1) display = Plugin.getOption('translate.toolbar.pagination.items.default.all'); 6585 $('<option/>').attr('value', size).html(display).appendTo(pageSizeSelect); 6586 }); 6587 6588 // init selectpicker to dropdown 6589 $(datatable).ready(function() { 6590 $('.selectpicker'). 6591 selectpicker(). 6592 on('hide.bs.select', function() { 6593 // fix dropup arrow icon on hide 6594 $(this).closest('.bootstrap-select').removeClass('dropup'); 6595 }). 6596 siblings('.dropdown-toggle'). 6597 attr('title', Plugin.getOption('translate.toolbar.pagination.items.default.select')); 6598 }); 6599 6600 pg.paste(); 6601 }, 6602 paste: function() { 6603 // insert pagination based on placement position, top|bottom 6604 $.each($.unique(Plugin.getOption('toolbar.placement')), 6605 function(i, position) { 6606 if (position === 'bottom') { 6607 $(pg.pager).clone(true).insertAfter(datatable.table); 6608 } 6609 if (position === 'top') { 6610 // pager top need some extra space 6611 $(pg.pager).clone(true).addClass(pfx + 'datatable__pager--top').insertBefore(datatable.table); 6612 } 6613 }); 6614 }, 6615 gotoMorePage: function(e) { 6616 e.preventDefault(); 6617 // $(this) is a link of .'+pfx+'datatable__pager-link 6618 6619 if ($(this).attr('disabled') === 'disabled') return false; 6620 6621 var page = $(this).attr('data-page'); 6622 6623 // event from text input 6624 if (typeof page === 'undefined') { 6625 page = $(e.target).attr('data-page'); 6626 } 6627 6628 pg.openPage(parseInt(page)); 6629 return false; 6630 }, 6631 gotoPage: function(e) { 6632 e.preventDefault(); 6633 // prevent from click same page number 6634 if ($(this).hasClass(pfx + 'datatable__pager-link--active')) return; 6635 6636 pg.openPage(parseInt($(this).data('page'))); 6637 }, 6638 openPage: function(page) { 6639 // currentPage is 1-based index 6640 pg.meta.page = parseInt(page); 6641 6642 $(datatable).trigger(pg.paginateEvent, pg.meta); 6643 pg.callback(pg, pg.meta); 6644 6645 // update page callback function 6646 $(pg.pager).trigger(pfx + 'datatable--on-goto-page', pg.meta); 6647 }, 6648 updatePerpage: function(e) { 6649 e.preventDefault(); 6650 // if (Plugin.getOption('layout.height') === null) { 6651 // fix white space, when perpage is set from many records to less records 6652 // $('html, body').animate({scrollTop: $(datatable).position().top}); 6653 // } 6654 6655 pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable__pager').removeClass(pfx + 'datatable--paging-loaded'); 6656 6657 // on change select page size 6658 if (e.originalEvent) { 6659 pg.meta.perpage = parseInt($(this).val()); 6660 } 6661 6662 $(pg.pager).find('select.' + pfx + 'datatable__pager-size').val(pg.meta.perpage).attr('data-selected', pg.meta.perpage); 6663 6664 // update datasource params 6665 Plugin.setDataSourceParam('pagination', { 6666 page: pg.meta.page, 6667 pages: pg.meta.pages, 6668 perpage: pg.meta.perpage, 6669 total: pg.meta.total, 6670 }); 6671 6672 // update page callback function 6673 $(pg.pager).trigger(pfx + 'datatable--on-update-perpage', pg.meta); 6674 $(datatable).trigger(pg.paginateEvent, pg.meta); 6675 pg.callback(pg, pg.meta); 6676 6677 // update pagination info 6678 pg.updateInfo.call(); 6679 }, 6680 addPaginateEvent: function(e) { 6681 // pagination event 6682 $(datatable).off(pg.paginateEvent).on(pg.paginateEvent, function(e, meta) { 6683 Plugin.spinnerCallback(true); 6684 6685 pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable__pager'); 6686 var pagerNumber = $(pg.pager).find('.' + pfx + 'datatable__pager-nav'); 6687 6688 // set sync active page class 6689 $(pagerNumber).find('.' + pfx + 'datatable__pager-link--active').removeClass(pfx + 'datatable__pager-link--active'); 6690 $(pagerNumber).find('.' + pfx + 'datatable__pager-link-number[data-page="' + meta.page + '"]').addClass(pfx + 'datatable__pager-link--active'); 6691 6692 // set next and previous link page number 6693 $(pagerNumber).find('.' + pfx + 'datatable__pager-link--prev').attr('data-page', Math.max(meta.page - 1, 1)); 6694 $(pagerNumber).find('.' + pfx + 'datatable__pager-link--next').attr('data-page', Math.min(meta.page + 1, meta.pages)); 6695 6696 // current page input value sync 6697 $(pg.pager).each(function() { 6698 $(this).find('.' + pfx + 'pager-input[type="text"]').prop('value', meta.page); 6699 });
6700 6701 $(pg.pager).find('.' + pfx + 'datatable__pager-nav').show(); 6702 if (meta.pages <= 1) { 6703 // hide pager if has 1 page 6704 $(pg.pager).find('.' + pfx + 'datatable__pager-nav').hide(); 6705 } 6706 6707 // update datasource params 6708 Plugin.setDataSourceParam('pagination', { 6709 page: pg.meta.page, 6710 pages: pg.meta.pages, 6711 perpage: pg.meta.perpage, 6712 total: pg.meta.total, 6713 }); 6714 6715 $(pg.pager).find('select.' + pfx + 'datatable__pager-size').val(meta.perpage).attr('data-selected', meta.perpage); 6716 6717 // clear active rows 6718 $(datatable.table).find('.' + pfx + 'checkbox > [type="checkbox"]').prop('checked', false); 6719 $(datatable.table).find('.' + pfx + 'datatable__row--active').removeClass(pfx + 'datatable__row--active'); 6720 6721 pg.updateInfo.call(); 6722 pg.pagingBreakpoint.call(); 6723 // Plugin.resetScroll(); 6724 }); 6725 }, 6726 updateInfo: function() { 6727 var start = Math.max(pg.meta.perpage * (pg.meta.page - 1) + 1, 1); 6728 var end = Math.min(start + pg.meta.perpage - 1, pg.meta.total); 6729 // page info update 6730 $(pg.pager).find('.' + pfx + 'datatable__pager-info').find('.' + pfx + 'datatable__pager-detail').html(Plugin.dataPlaceholder( 6731 Plugin.getOption('translate.toolbar.pagination.items.info'), { 6732 // set start page 0 if the is no records. eg. Showing 0 - 0 of 0 6733 start: pg.meta.total === 0 ? 0 : start, 6734 end: pg.meta.perpage === -1 ? pg.meta.total : end, 6735 pageSize: pg.meta.perpage === -1 || 6736 pg.meta.perpage >= pg.meta.total 6737 ? pg.meta.total 6738 : pg.meta.perpage, 6739 total: pg.meta.total, 6740 })); 6741 }, 6742 6743 /** 6744 * Update pagination layout breakpoint 6745 */ 6746 pagingBreakpoint: function() { 6747 // keep page links reference 6748 var pagerNumber = $(datatable.table).siblings('.' + pfx + 'datatable__pager').find('.' + pfx + 'datatable__pager-nav'); 6749 if ($(pagerNumber).length === 0) return; 6750 6751 var currentPage = Plugin.getCurrentPage(); 6752 var pagerInput = $(pagerNumber).find('.' + pfx + 'pager-input').closest('li'); 6753 6754 // reset 6755 $(pagerNumber).find('li').show(); 6756 6757 // pagination update 6758 $.each(Plugin.getOption('toolbar.items.pagination.pages'), 6759 function(mode, option) { 6760 if (util.isInResponsiveRange(mode)) { 6761 switch (mode) { 6762 case 'desktop': 6763 case 'tablet': 6764 var end = Math.ceil(currentPage / option.pagesNumber) * 6765 option.pagesNumber; 6766 var start = end - option.pagesNumber; 6767 $(pagerInput).hide(); 6768 pg.meta = Plugin.getDataSourceParam('pagination'); 6769 pg.paginationUpdate(); 6770 break; 6771 6772 case 'mobile': 6773 $(pagerInput).show(); 6774 $(pagerNumber).find('.' + pfx + 'datatable__pager-link--more-prev').closest('li').hide(); 6775 $(pagerNumber).find('.' + pfx + 'datatable__pager-link--more-next').closest('li').hide(); 6776 $(pagerNumber).find('.' + pfx + 'datatable__pager-link-number').closest('li').hide(); 6777 break; 6778 } 6779 6780 return false; 6781 } 6782 }); 6783 }, 6784 6785 /** 6786 * Update pagination number and button display 6787 */ 6788 paginationUpdate: function() { 6789 var pager = $(datatable.table).siblings('.' + pfx + 'datatable__pager').find('.' + pfx + 'datatable__pager-nav'), 6790 pagerMorePrev = $(pager).find('.' + pfx + 'datatable__pager-link--more-prev'), 6791 pagerMoreNext = $(pager).find('.' + pfx + 'datatable__pager-link--more-next'), 6792 pagerFirst = $(pager).find('.' + pfx + 'datatable__pager-link--first'), 6793 pagerPrev = $(pager).find('.' + pfx + 'datatable__pager-link--prev'), 6794 pagerNext = $(pager).find('.' + pfx + 'datatable__pager-link--next'), 6795 pagerLast = $(pager).find('.' + pfx + 'datatable__pager-link--last'); 6796 6797 // get visible page 6798 var pagerNumber = $(pager).find('.' + pfx + 'datatable__pager-link-number'); 6799 // get page before of first visible 6800 var morePrevPage = Math.max($(pagerNumber).first().data('page') - 1, 1); 6801 $(pagerMorePrev).each(function(i, prev) { 6802 $(prev).attr('data-page', morePrevPage); 6803 });
6804 // show/hide <li> 6805 if (morePrevPage === 1) { 6806 $(pagerMorePrev).parent().hide(); 6807 } else { 6808 $(pagerMorePrev).parent().show(); 6809 } 6810 6811 // get page after of last visible 6812 var moreNextPage = Math.min($(pagerNumber).last().data('page') + 1, 6813 pg.meta.pages); 6814 $(pagerMoreNext).each(function(i, prev) { 6815 $(pagerMoreNext).attr('data-page', moreNextPage).show(); 6816 }); 6817 6818 // show/hide <li> 6819 if (moreNextPage === pg.meta.pages 6820 // missing dot fix when last hidden page is one left 6821 && moreNextPage === $(pagerNumber).last().data('page')) { 6822 $(pagerMoreNext).parent().hide(); 6823 } else { 6824 $(pagerMoreNext).parent().show(); 6825 } 6826 6827 // begin/end of pages 6828 if (pg.meta.page === 1) { 6829 $(pagerFirst).attr('disabled', true).addClass(pfx + 'datatable__pager-link--disabled'); 6830 $(pagerPrev).attr('disabled', true).addClass(pfx + 'datatable__pager-link--disabled'); 6831 } else { 6832 $(pagerFirst).removeAttr('disabled').removeClass(pfx + 'datatable__pager-link--disabled'); 6833 $(pagerPrev).removeAttr('disabled').removeClass(pfx + 'datatable__pager-link--disabled'); 6834 } 6835 if (pg.meta.page === pg.meta.pages) { 6836 $(pagerNext).attr('disabled', true).addClass(pfx + 'datatable__pager-link--disabled'); 6837 $(pagerLast).attr('disabled', true).addClass(pfx + 'datatable__pager-link--disabled'); 6838 } else { 6839 $(pagerNext).removeAttr('disabled').removeClass(pfx + 'datatable__pager-link--disabled'); 6840 $(pagerLast).removeAttr('disabled').removeClass(pfx + 'datatable__pager-link--disabled'); 6841 } 6842 6843 // display more buttons 6844 var nav = Plugin.getOption('toolbar.items.pagination.navigation'); 6845 if (!nav.first) $(pagerFirst).remove(); 6846 if (!nav.prev) $(pagerPrev).remove(); 6847 if (!nav.next) $(pagerNext).remove(); 6848 if (!nav.last) $(pagerLast).remove(); 6849 if (!nav.more) { 6850 $(pagerMorePrev).remove(); 6851 $(pagerMoreNext).remove(); 6852 } 6853 }, 6854 }; 6855 pg.init(meta); 6856 return pg; 6857 }, 6858 6859 /** 6860 * Hide/show table cell defined by 6861 * options[columns][i][responsive][visible/hidden] 6862 */ 6863 columnHide: function() { 6864 var screen = util.getViewPort().width; 6865 // foreach columns setting 6866 $.each(options.columns, function(i, column) { 6867 if (typeof column.responsive !== 'undefined' || typeof column.visible !== 'undefined') { 6868 var field = column.field; 6869 var tds = $.grep($(datatable.table).find('.' + pfx + 'datatable__cell'), function(n, i) { 6870 return field === $(n).data('field'); 6871 }); 6872 6873 setTimeout(function () { 6874 // hide by force 6875 if (Plugin.getObject('visible', column) === false) { 6876 $(tds).hide(); 6877 } else { 6878 // show/hide by responsive breakpoint 6879 if (util.getBreakpoint(Plugin.getObject('responsive.hidden', column)) >= screen) { 6880 $(tds).hide(); 6881 } else { 6882 $(tds).show(); 6883 } 6884 if (util.getBreakpoint(Plugin.getObject('responsive.visible', column)) <= screen) { 6885 $(tds).show(); 6886 } else { 6887 $(tds).hide(); 6888 } 6889 } 6890 }); 6891 } 6892 }); 6893 }, 6894 6895 /** 6896 * Setup sub datatable 6897 */ 6898 setupSubDatatable: function() { 6899 var subTableCallback = Plugin.getOption('detail.content'); 6900 if (typeof subTableCallback !== 'function') return; 6901 6902 // subtable already exist 6903 if ($(datatable.table).find('.' + pfx + 'datatable__subtable').length > 0) return; 6904 6905 $(datatable.wrap).addClass(pfx + 'datatable--subtable'); 6906 6907 options.columns[0]['subtable'] = true; 6908 6909 // toggle on open sub table 6910 var toggleSubTable = function(e) { 6911 e.preventDefault(); 6912 // get parent row of this subtable 6913 var parentRow = $(this).closest('.' + pfx + 'datatable__row'); 6914 6915 // get subtable row for sub table 6916 var subTableRow = $(parentRow).next('.' + pfx + 'datatable__row-subtable'); 6917 if ($(subTableRow).length === 0) { 6918 // prepare DOM for sub table, each <tr> as parent and add <tr> as child table 6919 subTableRow = $('<tr/>'). 6920 addClass(pfx + 'datatable__row-subtable ' + pfx + 'datatable__row-loading'). 6921 hide(). 6922 append($('<td/>').addClass(pfx + 'datatable__subtable').attr('colspan', Plugin.getTotalColumns())); 6923 $(parentRow).after(subTableRow); 6924 // add class to even row 6925 if ($(parentRow).hasClass(pfx + 'datatable__row--even')) { 6926 $(subTableRow).addClass(pfx + 'datatable__row-subtable--even'); 6927 } 6928 } 6929 6930 $(subTableRow).toggle(); 6931 6932 var subTable = $(subTableRow).find('.' + pfx + 'datatable__subtable'); 6933 6934 // get id from first column of parent row 6935 var primaryKey = $(this).closest('[data-field]:first-child').find('.' + pfx + 'datatable__toggle-subtable').data('value'); 6936 6937 var icon = $(this).find('i').removeAttr('class'); 6938 6939 // prevent duplicate datatable init 6940 if ($(parentRow).hasClass(pfx + 'datatable__row--subtable-expanded')) { 6941 $(icon).addClass(Plugin.getOption('layout.icons.rowDetail.collapse')); 6942 // remove expand class from parent row 6943 $(parentRow).removeClass(pfx + 'datatable__row--subtable-expanded'); 6944 // trigger event on collapse 6945 $(datatable).trigger(pfx + 'datatable--on-collapse-subtable', [parentRow]); 6946 } else { 6947 // expand and run callback function 6948 $(icon).addClass(Plugin.getOption('layout.icons.rowDetail.expand')); 6949 // add expand class to parent row 6950 $(parentRow).addClass(pfx + 'datatable__row--subtable-expanded'); 6951 // trigger event on expand 6952 $(datatable).trigger(pfx + 'datatable--on-expand-subtable', [parentRow]); 6953 } 6954 6955 // prevent duplicate datatable init 6956 if ($(subTable).find('.' + pfx + 'datatable').length === 0) { 6957 // get data by primary id 6958 $.map(datatable.dataSet, function(n, i) { 6959 // primary id must be at the first column, otherwise e.data will be undefined 6960 if (primaryKey === n[options.columns[0].field]) { 6961 e.data = n; 6962 return true; 6963 } 6964 return false; 6965 });
6966 6967 // deprecated in v5.0.6 6968 e.detailCell = subTable; 6969 6970 e.parentRow = parentRow; 6971 e.subTable = subTable; 6972 6973 // run callback with event 6974 subTableCallback(e); 6975 6976 $(subTable).children('.' + pfx + 'datatable').on(pfx + 'datatable--on-init', function(e) { 6977 $(subTableRow).removeClass(pfx + 'datatable__row-loading'); 6978 }); 6979 if (Plugin.getOption('data.type') === 'local') { 6980 $(subTableRow).removeClass(pfx + 'datatable__row-loading'); 6981 } 6982 } 6983 }; 6984 6985 var columns = options.columns; 6986 $(datatable.tableBody).find('.' + pfx + 'datatable__row').each(function(tri, tr) { 6987 $(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) { 6988 // get column settings by field 6989 var column = $.grep(columns, function(n, i) { 6990 return $(td).data('field') === n.field; 6991 })[0]; 6992 if (typeof column !== 'undefined') { 6993 var value = $(td).text(); 6994 // enable column subtable toggle 6995 if (typeof column.subtable !== 'undefined' && column.subtable) { 6996 // check if subtable toggle exist 6997 if ($(td).find('.' + pfx + 'datatable__toggle-subtable').length > 0) return; 6998 // append subtable toggle 6999 $(td). 7000 html($('<a/>'). 7001 addClass(pfx + 'datatable__toggle-subtable'). 7002 attr('href', '#'). 7003 attr('data-value', value). 7004 attr('title', Plugin.getOption('detail.title')). 7005 on('click', toggleSubTable). 7006 append($('<i/>').css('width', $(td).data('width')).addClass(Plugin.getOption('layout.icons.rowDetail.collapse')))); 7007 } 7008 } 7009 }); 7010 }); 7011 7012 // $(datatable.tableHead).find('.'+pfx+'-datatable__row').first() 7013 }, 7014 7015 /** 7016 * Datasource mapping callback 7017 */ 7018 dataMapCallback: function(raw) { 7019 // static dataset array 7020 var dataSet = raw; 7021 // dataset mapping callback 7022 if (typeof Plugin.getOption('data.source.read.map') === 'function') { 7023 return Plugin.getOption('data.source.read.map')(raw); 7024 } else { 7025 // default data mapping fallback 7026 if (typeof raw !== 'undefined' && typeof raw.data !== 'undefined') { 7027 dataSet = raw.data; 7028 } 7029 } 7030 return dataSet; 7031 }, 7032 7033 isSpinning: false, 7034 /** 7035 * BlockUI spinner callback 7036 * @param block 7037 * @param target 7038 */ 7039 spinnerCallback: function(block, target) { 7040 if (typeof target === 'undefined') target = datatable; 7041 // get spinner options 7042 var spinnerOptions = Plugin.getOption('layout.spinner'); 7043 // spinner is disabled 7044 if (typeof spinnerOptions === 'undefined' || !spinnerOptions) { 7045 return; 7046 } 7047 if (block) { 7048 if (!Plugin.isSpinning) { 7049 if (typeof spinnerOptions.message !== 'undefined' && spinnerOptions.message === true) { 7050 // use default spinner message from translation 7051 spinnerOptions.message = Plugin.getOption('translate.records.processing'); 7052 } 7053 Plugin.isSpinning = true; 7054 if (typeof app !== 'undefined') { 7055 app.block(target, spinnerOptions); 7056 } 7057 } 7058 } else { 7059 Plugin.isSpinning = false; 7060 if (typeof app !== 'undefined') { 7061 app.unblock(target); 7062 } 7063 } 7064 }, 7065 7066 /** 7067 * Default sort callback function 7068 * @param data 7069 * @param sort 7070 * @param column 7071 * @returns {*|Array.<T>|{sort, field}|{asc, desc}} 7072 */ 7073 sortCallback: function(data, sort, column) { 7074 var type = column['type'] || 'string'; 7075 var format = column['format'] || ''; 7076 var field = column['field']; 7077 7078 return $(data).sort(function(a, b) { 7079 var aField = a[field]; 7080 var bField = b[field]; 7081 7082 switch (type) { 7083 case 'date': 7084 if (typeof moment === 'undefined') { 7085 throw new Error('Moment.js is required.'); 7086 } 7087 var diff = moment(aField, format).diff(moment(bField, format)); 7088 if (sort === 'asc') { 7089 return diff > 0 ? 1 : diff < 0 ? -1 : 0; 7090 } else { 7091 return diff < 0 ? 1 : diff > 0 ? -1 : 0; 7092 } 7093 break; 7094 7095 case 'number': 7096 if (isNaN(parseFloat(aField)) && aField != null) { 7097 aField = Number(aField.replace(/[^0-9\.-]+/g, '')); 7098 } 7099 if (isNaN(parseFloat(bField)) && bField != null) { 7100 bField = Number(bField.replace(/[^0-9\.-]+/g, '')); 7101 } 7102 aField = parseFloat(aField); 7103 bField = parseFloat(bField); 7104 if (sort === 'asc') { 7105 return aField > bField ? 1 : aField < bField ? -1 : 0; 7106 } else { 7107 return aField < bField ? 1 : aField > bField ? -1 : 0; 7108 } 7109 break; 7110 7111 case 'html': 7112 return $(data).sort(function(a, b) { 7113 // get the text only from html 7114 aField = $(a[field]).text(); 7115 bField = $(b[field]).text(); 7116 // sort 7117 if (sort === 'asc') { 7118 return aField > bField ? 1 : aField < bField ? -1 : 0; 7119 } else { 7120 return aField < bField ? 1 : aField > bField ? -1 : 0; 7121 } 7122 });
7123 break; 7124 7125 case 'string': 7126 default: 7127 if (sort === 'asc') { 7128 return aField > bField ? 1 : aField < bField ? -1 : 0; 7129 } else { 7130 return aField < bField ? 1 : aField > bField ? -1 : 0; 7131 } 7132 break; 7133 } 7134 }); 7135 }, 7136 7137 /** 7138 * Custom debug log 7139 * @param text 7140 * @param obj 7141 */ 7142 log: function(text, obj) { 7143 if (typeof obj === 'undefined') obj = ''; 7144 if (datatable.debug) { 7145 console.log(text, obj); 7146 } 7147 }, 7148 7149 /** 7150 * Auto hide columnds overflow in row 7151 */ 7152 autoHide: function() { 7153 var hiddenExist = false; 7154 // force hide enabled 7155 var hidDefault = $(datatable.table).find('[data-autohide-enabled]'); 7156 if (hidDefault.length) { 7157 hiddenExist = true; 7158 hidDefault.hide(); 7159 } 7160 7161 var toggleHiddenColumns = function(e) { 7162 e.preventDefault(); 7163 7164 var row = $(this).closest('.' + pfx + 'datatable__row'); 7165 var detailRow = $(row).next(); 7166 7167 if (!$(detailRow).hasClass(pfx + 'datatable__row-detail')) { 7168 $(this).find('i').removeClass(Plugin.getOption('layout.icons.rowDetail.collapse')).addClass(Plugin.getOption('layout.icons.rowDetail.expand')); 7169 7170 var hiddenCells = $(row).find('.' + pfx + 'datatable__cell:hidden'); 7171 var clonedCells = hiddenCells.clone().show(); 7172 7173 detailRow = $('<tr/>').addClass(pfx + 'datatable__row-detail').insertAfter(row); 7174 var detailRowTd = $('<td/>').addClass(pfx + 'datatable__detail').attr('colspan', Plugin.getTotalColumns()).appendTo(detailRow); 7175 7176 var detailSubTable = $('<table/>'); 7177 $(clonedCells).each(function() { 7178 var field = $(this).data('field'); 7179 var column = $.grep(options.columns, function(n, i) { 7180 return field === n.field; 7181 })[0]; 7182 if (typeof column === 'undefined' || column.visible !== false) { 7183 $(detailSubTable). 7184 append($('<tr class="' + pfx + 'datatable__row"></tr>'). 7185 append($('<td class="' + pfx + 'datatable__cell"></td>').append($('<span/>').append(column.title))). 7186 append(this)); 7187 } 7188 }); 7189 $(detailRowTd).append(detailSubTable); 7190 7191 } else { 7192 $(this).find('i').removeClass(Plugin.getOption('layout.icons.rowDetail.expand')).addClass(Plugin.getOption('layout.icons.rowDetail.collapse')); 7193 $(detailRow).remove(); 7194 } 7195 }; 7196 7197 setTimeout(function () { 7198 $(datatable.table).find('.' + pfx + 'datatable__cell').show(); 7199 $(datatable.tableBody).each(function() { 7200 var recursive = 0; 7201 while ($(this)[0].offsetWidth < $(this)[0].scrollWidth && recursive < options.columns.length) { 7202 $(datatable.table).find('.' + pfx + 'datatable__row').each(function(i) { 7203 var cell = $(this).find('.' + pfx + 'datatable__cell:not(:hidden):not([data-autohide-disabled])').last(); 7204 $(cell).hide(); 7205 hiddenExist = true; 7206 }); 7207 recursive++; 7208 } 7209 }); 7210 7211 if (hiddenExist) { 7212 // toggle show hidden columns 7213 $(datatable.tableBody).find('.' + pfx + 'datatable__row').each(function() { 7214 // if no toggle yet 7215 if($(this).find('.' + pfx + 'datatable__toggle-detail').length === 0) { 7216 // add toggle 7217 $(this).prepend($('<td/>'). 7218 addClass(pfx + 'datatable__cell ' + pfx + 'datatable__toggle-detail'). 7219 append($('<a/>'). 7220 addClass(pfx + 'datatable__toggle-detail'). 7221 attr('href', ''). 7222 on('click', toggleHiddenColumns). 7223 append('<i class="' + Plugin.getOption('layout.icons.rowDetail.collapse') + '"></i>'))); 7224 } 7225 7226 // check if subtable toggle exist 7227 if ($(datatable.tableHead).find('.' + pfx + 'datatable__toggle-detail').length === 0) { 7228 // add empty column to the header and footer 7229 $(datatable.tableHead). 7230 find('.' + pfx + 'datatable__row'). 7231 first(). 7232 prepend('<th class="' + pfx + 'datatable__cell ' + pfx + 'datatable__toggle-detail"><span></span></th>'); 7233 $(datatable.tableFoot). 7234 find('.' + pfx + 'datatable__row'). 7235 first(). 7236 prepend('<th class="' + pfx + 'datatable__cell ' + pfx + 'datatable__toggle-detail"><span></span></th>'); 7237 } else { 7238 $(datatable.tableHead).find('.' + pfx + 'datatable__toggle-detail').find('span'); 7239 } 7240 });
7241 } 7242 }); 7243 7244 Plugin.adjustCellsWidth.call(); 7245 }, 7246 7247 /** 7248 * To enable auto columns features for remote data source 7249 */ 7250 setAutoColumns: function() { 7251 if (Plugin.getOption('data.autoColumns')) { 7252 $.each(datatable.dataSet[0], function(k, v) { 7253 var found = $.grep(options.columns, function(n, i) { 7254 return k === n.field; 7255 }); 7256 if (found.length === 0) { 7257 options.columns.push({field: k, title: k}); 7258 } 7259 }); 7260 $(datatable.tableHead).find('.' + pfx + 'datatable__row').remove(); 7261 Plugin.setHeadTitle(); 7262 if (Plugin.getOption('layout.footer')) { 7263 $(datatable.tableFoot).find('.' + pfx + 'datatable__row').remove(); 7264 Plugin.setHeadTitle(datatable.tableFoot); 7265 } 7266 } 7267 }, 7268 7269 /******************** 7270 ** HELPERS 7271 ********************/ 7272 7273 /** 7274 * Check if table is a locked colums table 7275 */ 7276 isLocked: function() { 7277 var isLocked = Plugin.lockEnabledColumns(); 7278 return isLocked.left.length > 0 || isLocked.right.length > 0; 7279 }, 7280 7281 isSubtable: function() { 7282 return util.hasClass(datatable.wrap[0], pfx + 'datatable--subtable') || false; 7283 }, 7284 7285 /** 7286 * Get total extra space of an element for width calculation, 7287 * including padding, margin, border 7288 * @param element 7289 * @returns {number} 7290 */ 7291 getExtraSpace: function(element) { 7292 var padding = parseInt($(element).css('paddingRight')) + 7293 parseInt($(element).css('paddingLeft')); 7294 var margin = parseInt($(element).css('marginRight')) + 7295 parseInt($(element).css('marginLeft')); 7296 var border = Math.ceil( 7297 $(element).css('border-right-width').replace('px', '')); 7298 return padding + margin + border; 7299 }, 7300 7301 /** 7302 * Insert data of array into {{ }} template placeholder 7303 * @param template 7304 * @param data 7305 * @returns {*} 7306 */ 7307 dataPlaceholder: function(template, data) { 7308 var result = template; 7309 $.each(data, function(key, val) { 7310 result = result.replace('{{' + key + '}}', val); 7311 }); 7312 return result; 7313 }, 7314 7315 /** 7316 * Get table unique ID 7317 * Note: table unique change each time refreshed 7318 * @param suffix 7319 * @returns {*} 7320 */ 7321 getTableId: function(suffix) { 7322 if (typeof suffix === 'undefined') suffix = ''; 7323 var id = $(datatable).attr('id'); 7324 if (typeof id === 'undefined') { 7325 id = $(datatable).attr('class').split(' ')[0]; 7326 } 7327 return id + suffix; 7328 }, 7329 7330 /** 7331 * Get table prefix with depth number 7332 */ 7333 getTablePrefix: function(suffix) { 7334 if (typeof suffix !== 'undefined') suffix = '-' + suffix; 7335 return Plugin.getTableId() + '-' + Plugin.getDepth() + suffix; 7336 }, 7337 7338 /** 7339 * Get current table depth of sub table 7340 * @returns {number} 7341 */ 7342 getDepth: function() { 7343 var depth = 0; 7344 var table = datatable.table; 7345 do { 7346 table = $(table).parents('.' + pfx + 'datatable__table'); 7347 depth++; 7348 } while ($(table).length > 0); 7349 return depth; 7350 }, 7351 7352 /** 7353 * Keep state item 7354 * @param key 7355 * @param value 7356 */ 7357 stateKeep: function(key, value) { 7358 key = Plugin.getTablePrefix(key); 7359 if (Plugin.getOption('data.saveState') === false) return; 7360 if (Plugin.getOption('data.saveState.webstorage') && localStorage) { 7361 localStorage.setItem(key, JSON.stringify(value)); 7362 } 7363 if (Plugin.getOption('data.saveState.cookie')) { 7364 Cookies.set(key, JSON.stringify(value)); 7365 } 7366 }, 7367 7368 /** 7369 * Get state item 7370 * @param key 7371 * @param defValue 7372 */ 7373 stateGet: function(key, defValue) { 7374 key = Plugin.getTablePrefix(key); 7375 if (Plugin.getOption('data.saveState') === false) return; 7376 var value = null; 7377 if (Plugin.getOption('data.saveState.webstorage') && localStorage) { 7378 value = localStorage.getItem(key); 7379 } else { 7380 value = Cookies.get(key); 7381 } 7382 if (typeof value !== 'undefined' && value !== null) { 7383 return JSON.parse(value); 7384 } 7385 }, 7386 7387 /** 7388 * Update data in state without clear existing 7389 * @param key 7390 * @param value 7391 */ 7392 stateUpdate: function(key, value) { 7393 var ori = Plugin.stateGet(key); 7394 if (typeof ori === 'undefined' || ori === null) ori = {}; 7395 Plugin.stateKeep(key, $.extend({}, ori, value)); 7396 }, 7397 7398 /** 7399 * Remove state item 7400 * @param key 7401 */ 7402 stateRemove: function(key) { 7403 key = Plugin.getTablePrefix(key); 7404 if (localStorage) { 7405 localStorage.removeItem(key); 7406 } 7407 Cookies.remove(key); 7408 }, 7409 7410 /** 7411 * Get total columns. 7412 */ 7413 getTotalColumns: function(tablePart) { 7414 if (typeof tablePart === 'undefined') tablePart = datatable.tableBody; 7415 return $(tablePart).find('.' + pfx + 'datatable__row').first().find('.' + pfx + 'datatable__cell').length; 7416 }, 7417 7418 /** 7419 * Get table row. Useful to get row when current table is in lock 7420 * mode. Can be used for both lock and normal table mode. By 7421 * default, returning result will be in a list of <td>. 7422 * @param tablePart 7423 * @param row 1-based index 7424 * @param tdOnly Optional. Default true 7425 * @returns {*} 7426 */ 7427 getOneRow: function(tablePart, row, tdOnly) { 7428 if (typeof tdOnly === 'undefined') tdOnly = true; 7429 // get list of <tr> 7430 var result = $(tablePart).find('.' + pfx + 'datatable__row:not(.' + pfx + 'datatable__row-detail):nth-child(' + row + ')'); 7431 if (tdOnly) { 7432 // get list of <td> or <th> 7433 result = result.find('.' + pfx + 'datatable__cell'); 7434 } 7435 return result; 7436 }, 7437 7438 /** 7439 * Sort table row at HTML level by column index. 7440 * todo; Not in use. 7441 * @param header Header sort clicked 7442 * @param sort asc|desc. Optional. Default asc 7443 * @param int Boolean. Optional. Comparison value parse to integer. 7444 * Default false 7445 */ 7446 sortColumn: function(header, sort, int) { 7447 if (typeof sort === 'undefined') sort = 'asc'; // desc 7448 if (typeof int === 'undefined') int = false; 7449 7450 var column = $(header).index(); 7451 var rows = $(datatable.tableBody).find('.' + pfx + 'datatable__row');
7452 var hIndex = $(header).closest('.' + pfx + 'datatable__lock').index(); 7453 if (hIndex !== -1) { 7454 rows = $(datatable.tableBody).find('.' + pfx + 'datatable__lock:nth-child(' + (hIndex + 1) + ')').find('.' + pfx + 'datatable__row'); 7455 } 7456 7457 var container = $(rows).parent(); 7458 $(rows).sort(function(a, b) { 7459 var tda = $(a).find('td:nth-child(' + column + ')').text(); 7460 var tdb = $(b).find('td:nth-child(' + column + ')').text(); 7461 7462 if (int) { 7463 // useful for integer type sorting 7464 tda = parseInt(tda); 7465 tdb = parseInt(tdb); 7466 } 7467 7468 if (sort === 'asc') { 7469 return tda > tdb ? 1 : tda < tdb ? -1 : 0; 7470 } else { 7471 return tda < tdb ? 1 : tda > tdb ? -1 : 0; 7472 } 7473 }).appendTo(container); 7474 }, 7475 7476 /** 7477 * Perform sort remote and local 7478 */ 7479 sorting: function() { 7480 var sortObj = { 7481 init: function() { 7482 if (options.sortable) { 7483 $(datatable.tableHead). 7484 find('.' + pfx + 'datatable__cell:not(.' + pfx + 'datatable__cell--check)'). 7485 addClass(pfx + 'datatable__cell--sort'). 7486 off('click'). 7487 on('click', sortObj.sortClick); 7488 // first init 7489 sortObj.setIcon(); 7490 } 7491 }, 7492 setIcon: function() { 7493 var meta = Plugin.getDataSourceParam('sort'); 7494 if ($.isEmptyObject(meta)) return; 7495 7496 var column = Plugin.getColumnByField(meta.field); 7497 // sort is disabled for this column 7498 if (typeof column !== 'undefined' && typeof column.sortable !== 'undefined' && column.sortable === false) return; 7499 7500 // sort icon beside column header 7501 var td = $(datatable.tableHead).find('.' + pfx + 'datatable__cell[data-field="' + meta.field + '"]').attr('data-sort', meta.sort); 7502 var sorting = $(td).find('span'); 7503 var icon = $(sorting).find('i'); 7504 7505 var icons = Plugin.getOption('layout.icons.sort'); 7506 // update sort icon; desc & asc 7507 if ($(icon).length > 0) { 7508 $(icon).removeAttr('class').addClass(icons[meta.sort]); 7509 } else { 7510 $(sorting).append($('<i/>').addClass(icons[meta.sort])); 7511 } 7512 7513 // set sorted class to header on init 7514 $(td).addClass(pfx + 'datatable__cell--sorted'); 7515 }, 7516 sortClick: function(e) { 7517 var meta = Plugin.getDataSourceParam('sort'); 7518 var field = $(this).data('field'); 7519 var column = Plugin.getColumnByField(field); 7520 // sort is disabled for this column 7521 if (typeof column.sortable !== 'undefined' && column.sortable === false) return; 7522 7523 // set sorted class to header 7524 $(datatable.tableHead).find('th').removeClass(pfx + 'datatable__cell--sorted'); 7525 util.addClass(this, pfx + 'datatable__cell--sorted'); 7526 7527 $(datatable.tableHead).find('.' + pfx + 'datatable__cell > span > i').remove(); 7528 7529 if (options.sortable) { 7530 Plugin.spinnerCallback(true); 7531 7532 var sort = 'desc'; 7533 if (Plugin.getObject('field', meta) === field) { 7534 sort = Plugin.getObject('sort', meta); 7535 } 7536 7537 // toggle sort 7538 sort = typeof sort === 'undefined' || sort === 'desc' 7539 ? 'asc' 7540 : 'desc'; 7541 7542 // update field and sort params 7543 meta = {field: field, sort: sort}; 7544 Plugin.setDataSourceParam('sort', meta); 7545 7546 sortObj.setIcon(); 7547 7548 setTimeout(function() { 7549 Plugin.dataRender('sort'); 7550 $(datatable).trigger(pfx + 'datatable--on-sort', meta); 7551 }, 300); 7552 } 7553 }, 7554 }; 7555 sortObj.init(); 7556 }, 7557 7558 /** 7559 * Update JSON data list linked with sort, filter and pagination. 7560 * Call this method, before using dataSet variable. 7561 * @returns {*|null} 7562 */ 7563 localDataUpdate: function() { 7564 var params = Plugin.getDataSourceParam(); 7565 if (typeof datatable.originalDataSet === 'undefined') { 7566 datatable.originalDataSet = datatable.dataSet; 7567 } 7568 7569 var field = Plugin.getObject('sort.field', params); 7570 var sort = Plugin.getObject('sort.sort', params); 7571 var column = Plugin.getColumnByField(field); 7572 if (typeof column !== 'undefined' && Plugin.getOption('data.serverSorting') !== true) { 7573 if (typeof column.sortCallback === 'function') { 7574 datatable.dataSet = column.sortCallback(datatable.originalDataSet, sort, column); 7575 } else { 7576 datatable.dataSet = Plugin.sortCallback(datatable.originalDataSet, sort, column); 7577 } 7578 } else { 7579 datatable.dataSet = datatable.originalDataSet; 7580 } 7581 7582 // if server filter enable, don't pass local filter 7583 if (typeof params.query === 'object' && !Plugin.getOption('data.serverFiltering')) { 7584 params.query = params.query || {}; 7585 7586 var nestedSearch = function(obj) { 7587 for (var field in obj) { 7588 if (!obj.hasOwnProperty(field)) continue; 7589 if (typeof obj[field] === 'string') { 7590 if (obj[field].toLowerCase() == search || obj[field].toLowerCase().indexOf(search) !== -1) { 7591 return true; 7592 } 7593 } else if (typeof obj[field] === 'number') { 7594 if (obj[field] === search) { 7595 return true; 7596 } 7597 } else if (typeof obj[field] === 'object') { 7598 if (nestedSearch(obj[field])) { 7599 return true; 7600 } 7601 } 7602 } 7603 return false; 7604 }; 7605 7606 var search = $(Plugin.getOption('search.input')).val(); 7607 if (typeof search !== 'undefined' && search !== '') { 7608 search = search.toLowerCase(); 7609 datatable.dataSet = $.grep(datatable.dataSet, nestedSearch); 7610 // remove generalSearch as we don't need this for next columns filter 7611 delete params.query[Plugin.getGeneralSearchKey()]; 7612 } 7613 7614 // remove empty element from array 7615 $.each(params.query, function(k, v) { 7616 if (v === '') { 7617 delete params.query[k]; 7618 } 7619 });
7620 7621 // filter array by query 7622 datatable.dataSet = Plugin.filterArray(datatable.dataSet, params.query); 7623 7624 // reset array index 7625 datatable.dataSet = datatable.dataSet.filter(function() { 7626 return true; 7627 }); 7628 } 7629 7630 return datatable.dataSet; 7631 }, 7632 7633 /** 7634 * Utility helper to filter array by object pair of {key:value} 7635 * @param list 7636 * @param args 7637 * @param operator 7638 * @returns {*} 7639 */ 7640 filterArray: function(list, args, operator) { 7641 if (typeof list !== 'object') { 7642 return []; 7643 } 7644 7645 if (typeof operator === 'undefined') operator = 'AND'; 7646 7647 if (typeof args !== 'object') { 7648 return list; 7649 } 7650 7651 operator = operator.toUpperCase(); 7652 7653 if ($.inArray(operator, ['AND', 'OR', 'NOT']) === -1) { 7654 return []; 7655 } 7656 7657 var count = Object.keys(args).length; 7658 var filtered = []; 7659 7660 $.each(list, function(key, obj) { 7661 var to_match = obj; 7662 7663 var matched = 0; 7664 $.each(args, function(m_key, m_value) { 7665 m_value = m_value instanceof Array ? m_value : [m_value]; 7666 var match_property = Plugin.getObject(m_key, to_match); 7667 if (typeof match_property !== 'undefined' && match_property) { 7668 var lhs = match_property.toString().toLowerCase(); 7669 m_value.forEach(function(item, index) { 7670 if (item.toString().toLowerCase() == lhs || lhs.indexOf(item.toString().toLowerCase()) !== -1) { 7671 matched++; 7672 } 7673 }); 7674 } 7675 }); 7676 7677 if (('AND' == operator && matched == count) || 7678 ('OR' == operator && matched > 0) || 7679 ('NOT' == operator && 0 == matched)) { 7680 filtered[key] = obj; 7681 } 7682 }); 7683 7684 list = filtered; 7685 7686 return list; 7687 }, 7688 7689 /** 7690 * Reset lock column scroll to 0 when resize 7691 */ 7692 resetScroll: function() { 7693 if (typeof options.detail === 'undefined' && Plugin.getDepth() === 1) { 7694 $(datatable.table).find('.' + pfx + 'datatable__row').css('left', 0); 7695 $(datatable.table).find('.' + pfx + 'datatable__lock').css('top', 0); 7696 $(datatable.tableBody).scrollTop(0); 7697 } 7698 }, 7699 7700 /** 7701 * Get column options by field 7702 * @param field 7703 * @returns {boolean} 7704 */ 7705 getColumnByField: function(field) { 7706 if (typeof field === 'undefined') return; 7707 var result; 7708 $.each(options.columns, function(i, column) { 7709 if (field === column.field) { 7710 result = column; 7711 return false; 7712 } 7713 }); 7714 return result; 7715 }, 7716 7717 /** 7718 * Get default sort column 7719 */ 7720 getDefaultSortColumn: function() { 7721 var result; 7722 $.each(options.columns, function(i, column) { 7723 if (typeof column.sortable !== 'undefined' 7724 && $.inArray(column.sortable, ['asc', 'desc']) !== -1) { 7725 result = {sort: column.sortable, field: column.field}; 7726 return false; 7727 } 7728 }); 7729 return result; 7730 }, 7731 7732 /** 7733 * Helper to get element dimensions, when the element is hidden 7734 * @param element 7735 * @param includeMargin 7736 * @returns {{width: number, height: number, innerWidth: number, 7737 * innerHeight: number, outerWidth: number, outerHeight: 7738 * number}} 7739 */ 7740 getHiddenDimensions: function(element, includeMargin) { 7741 var props = { 7742 position: 'absolute', 7743 visibility: 'hidden', 7744 display: 'block', 7745 }, 7746 dim = { 7747 width: 0, 7748 height: 0, 7749 innerWidth: 0, 7750 innerHeight: 0, 7751 outerWidth: 0, 7752 outerHeight: 0, 7753 }, 7754 hiddenParents = $(element).parents().addBack().not(':visible'); 7755 includeMargin = (typeof includeMargin === 'boolean') 7756 ? includeMargin 7757 : false; 7758 7759 var oldProps = []; 7760 hiddenParents.each(function() { 7761 var old = {}; 7762 7763 for (var name in props) { 7764 old[name] = this.style[name]; 7765 this.style[name] = props[name]; 7766 } 7767 7768 oldProps.push(old);
7769 }); 7770 7771 dim.width = $(element).width(); 7772 dim.outerWidth = $(element).outerWidth(includeMargin); 7773 dim.innerWidth = $(element).innerWidth(); 7774 dim.height = $(element).height(); 7775 dim.innerHeight = $(element).innerHeight(); 7776 dim.outerHeight = $(element).outerHeight(includeMargin); 7777 7778 hiddenParents.each(function(i) { 7779 var old = oldProps[i]; 7780 for (var name in props) { 7781 this.style[name] = old[name]; 7782 } 7783 }); 7784 7785 return dim; 7786 }, 7787 7788 getGeneralSearchKey: function() { 7789 var searchInput = $(Plugin.getOption('search.input')); 7790 return $(searchInput).prop('name') || $(searchInput).prop('id'); 7791 }, 7792 7793 /** 7794 * Get value by dot notation path string and to prevent undefined 7795 * errors 7796 * @param path String Dot notation path in string 7797 * @param object Object to iterate 7798 * @returns {*} 7799 */ 7800 getObject: function(path, object) { 7801 return path.split('.').reduce(function(obj, i) { 7802 return obj !== null && typeof obj[i] !== 'undefined' ? obj[i] : null; 7803 }, object); 7804 }, 7805 7806 /** 7807 * Extend object 7808 * @param obj 7809 * @param path 7810 * @param value 7811 * @returns {*} 7812 */ 7813 extendObj: function(obj, path, value) { 7814 var levels = path.split('.'), 7815 i = 0; 7816 7817 function createLevel(child) { 7818 var name = levels[i++]; 7819 if (typeof child[name] !== 'undefined' && child[name] !== null) { 7820 if (typeof child[name] !== 'object' && 7821 typeof child[name] !== 'function') { 7822 child[name] = {}; 7823 } 7824 } else { 7825 child[name] = {}; 7826 } 7827 if (i === levels.length) { 7828 child[name] = value; 7829 } else { 7830 createLevel(child[name]); 7831 } 7832 } 7833 7834 createLevel(obj); 7835 return obj; 7836 }, 7837 7838 rowEvenOdd: function() { 7839 // row even class 7840 $(datatable.tableBody).find('.' + pfx + 'datatable__row').removeClass(pfx + 'datatable__row--even'); 7841 if ($(datatable.wrap).hasClass(pfx + 'datatable--subtable')) { 7842 $(datatable.tableBody).find('.' + pfx + 'datatable__row:not(.' + pfx + 'datatable__row-detail):even').addClass(pfx + 'datatable__row--even'); 7843 } else { 7844 $(datatable.tableBody).find('.' + pfx + 'datatable__row:nth-child(even)').addClass(pfx + 'datatable__row--even'); 7845 } 7846 }, 7847 7848 /******************** 7849 ** PUBLIC API METHODS 7850 ********************/ 7851 7852 // delay timer 7853 timer: 0, 7854 7855 /** 7856 * Redraw datatable by recalculating its DOM elements, etc. 7857 * @returns {jQuery} 7858 */ 7859 redraw: function() { 7860 Plugin.adjustCellsWidth.call(); 7861 if (Plugin.isLocked()) { 7862 // fix hiding cell width issue 7863 Plugin.scrollbar(); 7864 Plugin.resetScroll(); 7865 Plugin.adjustCellsHeight.call(); 7866 } 7867 Plugin.adjustLockContainer.call(); 7868 Plugin.initHeight.call(); 7869 return datatable; 7870 }, 7871 7872 /** 7873 * Shortcode to reload 7874 * @returns {jQuery} 7875 */ 7876 load: function() { 7877 Plugin.reload(); 7878 return datatable; 7879 }, 7880 7881 /** 7882 * Datasource reload 7883 * @returns {jQuery} 7884 */ 7885 reload: function() { 7886 var delay = (function() { 7887 return function(callback, ms) { 7888 clearTimeout(Plugin.timer); 7889 Plugin.timer = setTimeout(callback, ms); 7890 }; 7891 })(); 7892 delay(function() { 7893 // local only. remote pagination will skip this block 7894 if (!options.data.serverFiltering) { 7895 Plugin.localDataUpdate(); 7896 } 7897 Plugin.dataRender(); 7898 $(datatable).trigger(pfx + 'datatable--on-reloaded'); 7899 }, Plugin.getOption('search.delay')); 7900 return datatable; 7901 }, 7902 7903 /** 7904 * Get record by record ID 7905 * @param id 7906 * @returns {jQuery} 7907 */ 7908 getRecord: function(id) { 7909 if (typeof datatable.tableBody === 'undefined') datatable.tableBody = $(datatable.table).children('tbody'); 7910 $(datatable.tableBody).find('.' + pfx + 'datatable__cell:first-child').each(function(i, cell) { 7911 if (id == $(cell).text()) { 7912 var rowNumber = $(cell).closest('.' + pfx + 'datatable__row').index() + 1; 7913 datatable.API.record = datatable.API.value = Plugin.getOneRow(datatable.tableBody, rowNumber); 7914 return datatable; 7915 } 7916 }); 7917 return datatable; 7918 }, 7919 7920 /**
7921 * @deprecated in v5.0.6 7922 * Get column of current record ID 7923 * @param columnName 7924 * @returns {jQuery} 7925 */ 7926 getColumn: function(columnName) { 7927 Plugin.setSelectedRecords(); 7928 datatable.API.value = $(datatable.API.record).find('[data-field="' + columnName + '"]'); 7929 return datatable; 7930 }, 7931 7932 /** 7933 * Destroy datatable to original DOM state before datatable was 7934 * initialized 7935 * @returns {jQuery} 7936 */ 7937 destroy: function() { 7938 $(datatable).parent().find('.' + pfx + 'datatable__pager').remove(); 7939 var initialDatatable = $(datatable.initialDatatable).addClass(pfx + 'datatable--destroyed').show(); 7940 $(datatable).replaceWith(initialDatatable); 7941 datatable = initialDatatable; 7942 $(datatable).trigger(pfx + 'datatable--on-destroy'); 7943 Plugin.isInit = false; 7944 initialDatatable = null; 7945 return initialDatatable; 7946 }, 7947 7948 /** 7949 * Sort by column field 7950 * @param field 7951 * @param sort 7952 */ 7953 sort: function(field, sort) { 7954 // toggle sort 7955 sort = typeof sort === 'undefined' ? 'asc' : sort; 7956 7957 Plugin.spinnerCallback(true); 7958 7959 // update field and sort params 7960 var meta = {field: field, sort: sort}; 7961 Plugin.setDataSourceParam('sort', meta); 7962 7963 setTimeout(function() { 7964 Plugin.dataRender('sort'); 7965 $(datatable).trigger(pfx + 'datatable--on-sort', meta); 7966 $(datatable.tableHead).find('.' + pfx + 'datatable__cell > span > i').remove(); 7967 }, 300); 7968 7969 return datatable; 7970 }, 7971 7972 /** 7973 * @deprecated in v5.0.6 7974 * Get current selected column value 7975 * @returns {jQuery} 7976 */ 7977 getValue: function() { 7978 return $(datatable.API.value).text(); 7979 }, 7980 7981 /** 7982 * Set checkbox active 7983 * @param cell JQuery selector or checkbox ID 7984 */ 7985 setActive: function(cell) { 7986 if (typeof cell === 'string') { 7987 // set by checkbox id 7988 cell = $(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"][value="' + cell + '"]'); 7989 } 7990 7991 $(cell).prop('checked', true); 7992 7993 var ids = []; 7994 $(cell).each(function(i, td) { 7995 // normal table 7996 var row = $(td).closest('tr').addClass(pfx + 'datatable__row--active'); 7997 7998 var id = $(td).attr('value'); 7999 if (typeof id !== 'undefined') { 8000 ids.push(id); 8001 } 8002 }); 8003 8004 $(datatable).trigger(pfx + 'datatable--on-check', [ids]); 8005 }, 8006 8007 /** 8008 * Set checkbox inactive 8009 * @param cell JQuery selector or checkbox ID 8010 */ 8011 setInactive: function(cell) { 8012 if (typeof cell === 'string') { 8013 // set by checkbox id 8014 cell = $(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"][value="' + cell + '"]'); 8015 } 8016 8017 $(cell).prop('checked', false); 8018 8019 var ids = []; 8020 $(cell).each(function(i, td) { 8021 // normal table 8022 var row = $(td).closest('tr').removeClass(pfx + 'datatable__row--active'); 8023 8024 var id = $(td).attr('value'); 8025 if (typeof id !== 'undefined') { 8026 ids.push(id); 8027 } 8028 }); 8029 8030 $(datatable).trigger(pfx + 'datatable--on-uncheck', [ids]); 8031 }, 8032 8033 /** 8034 * Set all checkboxes active or inactive 8035 * @param active 8036 */ 8037 setActiveAll: function(active) { 8038 var checkboxes = $(datatable.table). 8039 find('> tbody, > thead'). 8040 find('tr').not('.' + pfx + 'datatable__row-subtable'). 8041 find('.' + pfx + 'datatable__cell--check [type="checkbox"]'); 8042 if (active) { 8043 Plugin.setActive(checkboxes); 8044 } else { 8045 Plugin.setInactive(checkboxes); 8046 } 8047 }, 8048 8049 /** 8050 * @deprecated in v5.0.6 8051 * Get selected rows which are active 8052 * @returns {jQuery} 8053 */ 8054 setSelectedRecords: function() { 8055 datatable.API.record = $(datatable.tableBody).find('.' + pfx + 'datatable__row--active'); 8056 return datatable; 8057 }, 8058 8059 /** 8060 * Get selected records 8061 * @returns {null} 8062 */ 8063 getSelectedRecords: function() { 8064 // support old method 8065 Plugin.setSelectedRecords(); 8066 datatable.API.record = datatable.rows('.' + pfx + 'datatable__row--active').nodes(); 8067 return datatable.API.record; 8068 }, 8069 8070 /** 8071 * Get options by dots notation path 8072 * @param path String Dot notation path in string 8073 * @returns {*} 8074 */ 8075 getOption: function(path) { 8076 return Plugin.getObject(path, options); 8077 }, 8078 8079 /** 8080 * Set global options nodes by dots notation path 8081 * @param path 8082 * @param object 8083 */ 8084 setOption: function(path, object) { 8085 options = Plugin.extendObj(options, path, object); 8086 }, 8087 8088 /**
8089 * Search filter for local & remote 8090 * @param value 8091 * @param columns. Optional list of columns to be filtered. 8092 */ 8093 search: function(value, columns) { 8094 if (typeof columns !== 'undefined') columns = $.makeArray(columns); 8095 var delay = (function() { 8096 return function(callback, ms) { 8097 clearTimeout(Plugin.timer); 8098 Plugin.timer = setTimeout(callback, ms); 8099 }; 8100 })(); 8101 8102 delay(function() { 8103 // get query parameters 8104 var query = Plugin.getDataSourceQuery(); 8105 8106 // search not by columns 8107 if (typeof columns === 'undefined' && typeof value !== 'undefined') { 8108 var key = Plugin.getGeneralSearchKey(); 8109 query[key] = value; 8110 } 8111 8112 // search by columns, support multiple columns 8113 if (typeof columns === 'object') { 8114 $.each(columns, function(k, column) { 8115 query[column] = value; 8116 }); 8117 // remove empty element from arrays 8118 $.each(query, function(k, v) { 8119 if (v === '' || $.isEmptyObject(v)) { 8120 delete query[k]; 8121 } 8122 }); 8123 } 8124 8125 Plugin.setDataSourceQuery(query); 8126 8127 // reset pagination to 1 when doing seearching 8128 datatable.setDataSourceParam('pagination', Object.assign({}, datatable.getDataSourceParam('pagination'), {page: 1})); 8129 8130 // local filter only. remote pagination will skip this block 8131 if (!options.data.serverFiltering) { 8132 Plugin.localDataUpdate(); 8133 } 8134 Plugin.dataRender('search'); 8135 }, Plugin.getOption('search.delay')); 8136 }, 8137 8138 /** 8139 * Set datasource params extract 8140 * @param param 8141 * @param value 8142 */ 8143 setDataSourceParam: function(param, value) { 8144 datatable.API.params = $.extend({}, { 8145 pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')}, 8146 sort: Plugin.getDefaultSortColumn(), 8147 query: {}, 8148 }, datatable.API.params, Plugin.stateGet(Plugin.stateId)); 8149 8150 datatable.API.params = Plugin.extendObj(datatable.API.params, param, value); 8151 8152 Plugin.stateKeep(Plugin.stateId, datatable.API.params); 8153 }, 8154 8155 /** 8156 * Get datasource params 8157 * @param param 8158 */ 8159 getDataSourceParam: function(param) { 8160 datatable.API.params = $.extend({}, { 8161 pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')}, 8162 sort: Plugin.getDefaultSortColumn(), 8163 query: {}, 8164 }, datatable.API.params, Plugin.stateGet(Plugin.stateId)); 8165 8166 if (typeof param === 'string') { 8167 return Plugin.getObject(param, datatable.API.params); 8168 } 8169 8170 return datatable.API.params; 8171 }, 8172 8173 /** 8174 * Shortcode to datatable.getDataSourceParam('query'); 8175 * @returns {*} 8176 */ 8177 getDataSourceQuery: function() { 8178 return Plugin.getDataSourceParam('query') || {}; 8179 }, 8180 8181 /** 8182 * Shortcode to datatable.setDataSourceParam('query', query); 8183 * @param query 8184 */ 8185 setDataSourceQuery: function(query) { 8186 Plugin.setDataSourceParam('query', query); 8187 }, 8188 8189 /** 8190 * Get current page number 8191 * @returns {number} 8192 */ 8193 getCurrentPage: function() { 8194 return $(datatable.table). 8195 siblings('.' + pfx + 'datatable__pager'). 8196 last(). 8197 find('.' + pfx + 'datatable__pager-nav'). 8198 find('.' + pfx + 'datatable__pager-link.' + pfx + 'datatable__pager-link--active'). 8199 data('page') || 1; 8200 }, 8201 8202 /** 8203 * Get selected dropdown page size 8204 * @returns {*|number} 8205 */ 8206 getPageSize: function() { 8207 return $(datatable.table).siblings('.' + pfx + 'datatable__pager').last().find('select.' + pfx + 'datatable__pager-size').val() || 10; 8208 }, 8209 8210 /** 8211 * Get total rows 8212 */ 8213 getTotalRows: function() { 8214 return datatable.API.params.pagination.total; 8215 }, 8216 8217 /** 8218 * Get full dataset in grid 8219 * @returns {*|null|Array} 8220 */ 8221 getDataSet: function() { 8222 return datatable.originalDataSet; 8223 }, 8224 8225 nodeTr: [], 8226 nodeTd: [], 8227 nodeCols: [], 8228 recentNode: [], 8229 8230 table: function() { 8231 if (typeof datatable.table !== 'undefined') { 8232 return datatable.table; 8233 } 8234 }, 8235 8236 /** 8237 * Select a single row from the table 8238 * @param selector 8239 * @returns {jQuery} 8240 */ 8241 row: function(selector) { 8242 Plugin.rows(selector); 8243 Plugin.nodeTr = Plugin.recentNode = $(Plugin.nodeTr).first(); 8244 return datatable; 8245 }, 8246 8247 /** 8248 * Select multiple rows from the table 8249 * @param selector 8250 * @returns {jQuery} 8251 */ 8252 rows: function(selector) { 8253 if (Plugin.isLocked()) { 8254 Plugin.nodeTr = Plugin.recentNode = $(datatable.tableBody).find(selector).filter('.' + pfx + 'datatable__lock--scroll > .' + pfx + 'datatable__row'); 8255 } else { 8256 Plugin.nodeTr = Plugin.recentNode = $(datatable.tableBody).find(selector).filter('.' + pfx + 'datatable__row'); 8257 } 8258 return datatable; 8259 }, 8260 8261 /** 8262 * Select a single column from the table 8263 * @param index zero-based index 8264 * @returns {jQuery} 8265 */ 8266 column: function(index) { 8267 Plugin.nodeCols = Plugin.recentNode = $(datatable.tableBody).find('.' + pfx + 'datatable__cell:nth-child(' + (index + 1) + ')'); 8268 return datatable; 8269 }, 8270 8271 /** 8272 * Select multiple columns from the table 8273 * @param selector 8274 * @returns {jQuery} 8275 */ 8276 columns: function(selector) { 8277 var context = datatable.table; 8278 if (Plugin.nodeTr === Plugin.recentNode) { 8279 context = Plugin.nodeTr; 8280 } 8281 var columns = $(context).find('.' + pfx + 'datatable__cell[data-field="' + selector + '"]'); 8282 if (columns.length > 0) { 8283 Plugin.nodeCols = Plugin.recentNode = columns; 8284 } else { 8285 Plugin.nodeCols = Plugin.recentNode = $(context).find(selector).filter('.' + pfx + 'datatable__cell'); 8286 } 8287 return datatable; 8288 }, 8289 8290 cell: function(selector) { 8291 Plugin.cells(selector); 8292 Plugin.nodeTd = Plugin.recentNode = $(Plugin.nodeTd).first(); 8293 return datatable; 8294 }, 8295 8296 cells: function(selector) { 8297 var cells = $(datatable.tableBody).find('.' + pfx + 'datatable__cell'); 8298 if (typeof selector !== 'undefined') { 8299 cells = $(cells).filter(selector); 8300 } 8301 Plugin.nodeTd = Plugin.recentNode = cells; 8302 return datatable; 8303 }, 8304 8305 /** 8306 * Delete the selected row from the table 8307 * @returns {jQuery} 8308 */ 8309 remove: function() { 8310 if ($(Plugin.nodeTr.length) && Plugin.nodeTr === Plugin.recentNode) { 8311 $(Plugin.nodeTr).remove(); 8312 } 8313 Plugin.layoutUpdate(); 8314 return datatable; 8315 }, 8316 8317 /** 8318 * Show or hide the columns or rows 8319 */ 8320 visible: function(bool) { 8321 if ($(Plugin.recentNode.length)) { 8322 var locked = Plugin.lockEnabledColumns(); 8323 if (Plugin.recentNode === Plugin.nodeCols) { 8324 var index = Plugin.recentNode.index(); 8325 8326 if (Plugin.isLocked()) { 8327 var scrollColumns = $(Plugin.recentNode).closest('.' + pfx + 'datatable__lock--scroll').length; 8328 if (scrollColumns) { 8329 // is at center of scrollable area 8330 index += locked.left.length + 1; 8331 } else if ($(Plugin.recentNode).closest('.' + pfx + 'datatable__lock--right').length) { 8332 // is at the right locked table
8333 index += locked.left.length + scrollColumns + 1; 8334 } 8335 } 8336 } 8337 8338 if (bool) { 8339 if (Plugin.recentNode === Plugin.nodeCols) { 8340 delete options.columns[index].visible; 8341 } 8342 $(Plugin.recentNode).show(); 8343 } else { 8344 if (Plugin.recentNode === Plugin.nodeCols) { 8345 Plugin.setOption('columns.' + (index) + '.visible', false); 8346 } 8347 $(Plugin.recentNode).hide(); 8348 } 8349 Plugin.columnHide(); 8350 Plugin.redraw(); 8351 } 8352 }, 8353 8354 /** 8355 * Get the the DOM element for the selected rows or columns 8356 * @returns {Array} 8357 */ 8358 nodes: function() { 8359 return Plugin.recentNode; 8360 }, 8361 8362 /** 8363 * will be implemented soon 8364 * @returns {jQuery} 8365 */ 8366 dataset: function() { 8367 return datatable; 8368 }, 8369 8370 /** 8371 * Open page by number 8372 * @param page number 8373 */ 8374 gotoPage: function (page) { 8375 if (typeof Plugin.pagingObject !== 'undefined') { 8376 Plugin.isInit = true; 8377 Plugin.pagingObject.openPage(page); 8378 } 8379 }, 8380 8381 }; 8382 8383 /** 8384 * Public API methods can be used directly by datatable 8385 */ 8386 $.each(Plugin, function(funcName, func) { 8387 datatable[funcName] = func; 8388 }); 8389 8390 // initialize main datatable plugin 8391 if (typeof options !== 'undefined') { 8392 if (typeof options === 'string') { 8393 var method = options; 8394 datatable = $(this).data(pluginName); 8395 if (typeof datatable !== 'undefined') { 8396 options = datatable.options; 8397 Plugin[method].apply(this, Array.prototype.slice.call(arguments, 1)); 8398 } 8399 } else { 8400 if (!datatable.data(pluginName) && !$(this).hasClass(pfx + 'datatable--loaded')) { 8401 datatable.dataSet = null; 8402 datatable.textAlign = { 8403 left: pfx + 'datatable__cell--left', 8404 center: pfx + 'datatable__cell--center', 8405 right: pfx + 'datatable__cell--right', 8406 }; 8407 8408 // merge default and user defined options 8409 options = $.extend(true, {}, $.fn[pluginName].defaults, options); 8410 8411 datatable.options = options; 8412 8413 // init plugin process 8414 Plugin.init.apply(this, [options]); 8415 8416 $(datatable.wrap).data(pluginName, datatable); 8417 } 8418 } 8419 } else { 8420 // get existing instance datatable 8421 datatable = $(this).data(pluginName); 8422 if (typeof datatable === 'undefined') { 8423 $.error(pluginName + ' not initialized'); 8424 } 8425 options = datatable.options; 8426 } 8427 8428 return datatable; 8429 }; 8430 8431 // default options 8432 $.fn[pluginName].defaults = { 8433 // datasource definition 8434 data: { 8435 type: 'local', 8436 source: null, 8437 pageSize: 10, // display records per page 8438 saveState: { 8439 // save datatable state(pagination, filtering, sorting, etc) in cookie or browser webstorage 8440 cookie: false, 8441 webstorage: true, 8442 }, 8443 8444 serverPaging: false, 8445 serverFiltering: false, 8446 serverSorting: false, 8447 8448 autoColumns: false, 8449 attr: { 8450 rowProps: [], 8451 }, 8452 }, 8453 8454 // layout definition 8455 layout: { 8456 theme: 'default', // datatable will support multiple themes and designs 8457 class: pfx + 'datatable--brand', // custom wrapper class 8458 scroll: false, // enable/disable datatable scroll both horizontal and vertical when needed. 8459 height: null, // datatable's body's fixed height 8460 minHeight: null, 8461 footer: false, // display/hide footer 8462 header: true, // display/hide header 8463 customScrollbar: true, // set false to disable custom scrollbar 8464 8465 // datatable spinner 8466 spinner: { 8467 overlayColor: '#000000', 8468 opacity: 0, 8469 type: 'loader', 8470 state: 'brand', 8471 message: true, 8472 }, 8473 8474 // datatable UI icons 8475 icons: { 8476 sort: {asc: 'flaticon2-arrow-up', desc: 'flaticon2-arrow-down'}, 8477 pagination: { 8478 next: 'flaticon2-next', 8479 prev: 'flaticon2-back', 8480 first: 'flaticon2-fast-back', 8481 last: 'flaticon2-fast-next', 8482 more: 'flaticon-more-1', 8483 }, 8484 rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'}, 8485 }, 8486 }, 8487 8488 // column sorting 8489 sortable: true, 8490 8491 // resize column size with mouse drag coming soon) 8492 resizable: false, 8493 8494 // column based filtering (coming soon) 8495 filterable: false, 8496 8497 pagination: true, 8498 8499 // inline and bactch editing (cooming soon) 8500 editable: false, 8501 8502 // columns definition 8503 columns: [], 8504 8505 search: { 8506 // enable trigger search by keyup enter 8507 onEnter: false, 8508 // input text for search
8509 input: null, 8510 // search delay in milliseconds 8511 delay: 400, 8512 }, 8513 8514 rows: { 8515 // deprecated 8516 callback: function() { 8517 }, 8518 // call before row template 8519 beforeTemplate: function() { 8520 }, 8521 // call after row template 8522 afterTemplate: function() { 8523 }, 8524 autoHide: true, 8525 }, 8526 8527 // toolbar 8528 toolbar: { 8529 // place pagination and displayInfo blocks according to the array order 8530 layout: ['pagination', 'info'], 8531 8532 // toolbar placement can be at top or bottom or both top and bottom repeated 8533 placement: ['bottom'], //'top', 'bottom' 8534 8535 // toolbar items 8536 items: { 8537 // pagination 8538 pagination: { 8539 // pagination type(default or scroll) 8540 type: 'default', 8541 8542 // number of pages to display by breakpoints 8543 pages: { 8544 desktop: { 8545 layout: 'default', 8546 pagesNumber: 5, 8547 }, 8548 tablet: { 8549 layout: 'default', 8550 pagesNumber: 3, 8551 }, 8552 mobile: { 8553 layout: 'compact', 8554 }, 8555 }, 8556 8557 // navigation buttons 8558 navigation: { 8559 prev: true, // display prev button 8560 next: true, // display next button 8561 first: true, // display first button 8562 last: true, // display last button 8563 more: false // display more button 8564 }, 8565 8566 // page size select 8567 pageSizeSelect: [], // display dropdown to select pagination size. -1 is used for "ALl" option 8568 }, 8569 8570 // records info 8571 info: true, 8572 }, 8573 }, 8574 8575 // here we will keep all strings and message used by datatable UI so developer can easiliy translate to any language. 8576 // By default the stirngs will be in the plugin source and here can override it 8577 translate: { 8578 records: { 8579 processing: 'Please wait...', 8580 noRecords: 'No records found', 8581 }, 8582 toolbar: { 8583 pagination: { 8584 items: { 8585 default: { 8586 first: 'First', 8587 prev: 'Previous', 8588 next: 'Next', 8589 last: 'Last', 8590 more: 'More pages', 8591 input: 'Page number', 8592 select: 'Select page size', 8593 all: 'all', 8594 }, 8595 info: 'Showing {{start}} - {{end}} of {{total}}', 8596 }, 8597 }, 8598 }, 8599 }, 8600 8601 extensions: {}, 8602 }; 8603 8604}(jQuery)); 8605 8606"use strict"; 8607(function($) { 8608 8609 var pluginName = 'KTDatatable'; 8610 var pfx = 'kt-'; 8611 8612 $.fn[pluginName] = $.fn[pluginName] || {}; 8613 8614 /** 8615 * @param datatable Main datatable plugin instance 8616 * @param options Extension options 8617 * @returns {*} 8618 */ 8619 $.fn[pluginName].checkbox = function(datatable, options) { 8620 var Extension = { 8621 selectedAllRows: false, 8622 selectedRows: [], 8623 unselectedRows: [], 8624 8625 init: function() { 8626 if (Extension.selectorEnabled()) { 8627 // reset 8628 datatable.setDataSourceParam(options.vars.selectedAllRows, false); 8629 datatable.stateRemove('checkbox'); 8630 8631 // requestIds is not null 8632 if (options.vars.requestIds) { 8633 // request ids in response 8634 datatable.setDataSourceParam(options.vars.requestIds, true); 8635 } 8636 8637 // remove selected checkbox on datatable reload 8638 $(datatable).on(pfx + 'datatable--on-reloaded', function() { 8639 datatable.stateRemove('checkbox'); 8640 datatable.setDataSourceParam(options.vars.selectedAllRows, false); 8641 Extension.selectedAllRows = false; 8642 Extension.selectedRows = []; 8643 Extension.unselectedRows = []; 8644 }); 8645 8646 // select all on extension init 8647 Extension.selectedAllRows = datatable.getDataSourceParam(options.vars.selectedAllRows); 8648 8649 $(datatable).on(pfx + 'datatable--on-layout-updated', function(e, args) { 8650 if (args.table != $(datatable.wrap).attr('id')) { 8651 return; 8652 } 8653 datatable.ready(function() { 8654 Extension.initVars(); 8655 Extension.initEvent(); 8656 Extension.initSelect(); 8657 }); 8658 }); 8659 8660 $(datatable).on(pfx + 'datatable--on-check', function(e, ids) { 8661 ids.forEach(function(id) { 8662 Extension.selectedRows.push(id); 8663 // // remove from unselected rows 8664 Extension.unselectedRows = Extension.remove(Extension.unselectedRows, id); 8665 }); 8666 var storage = {}; 8667 storage['selectedRows'] = $.unique(Extension.selectedRows); 8668 storage['unselectedRows'] = $.unique(Extension.unselectedRows); 8669 datatable.stateKeep('checkbox', storage); 8670 });
8671 $(datatable).on(pfx + 'datatable--on-uncheck', function(e, ids) { 8672 ids.forEach(function(id) { 8673 Extension.unselectedRows.push(id); 8674 // // remove from selected rows 8675 Extension.selectedRows = Extension.remove(Extension.selectedRows, id); 8676 }); 8677 var storage = {}; 8678 storage['selectedRows'] = $.unique(Extension.selectedRows); 8679 storage['unselectedRows'] = $.unique(Extension.unselectedRows); 8680 datatable.stateKeep('checkbox', storage); 8681 }); 8682 } 8683 }, 8684 8685 /** 8686 * Init checkbox clicks event 8687 */ 8688 initEvent: function() { 8689 // select all checkbox click 8690 $(datatable.tableHead).find('.' + pfx + 'checkbox--all > [type="checkbox"]').click(function(e) { 8691 // clear selected and unselected rows 8692 Extension.selectedRows = Extension.unselectedRows = []; 8693 datatable.stateRemove('checkbox'); 8694 8695 // select all rows 8696 if ($(this).is(':checked')) { 8697 Extension.selectedAllRows = true; 8698 } 8699 else { 8700 Extension.selectedAllRows = false; 8701 } 8702 8703 // local select all current page rows 8704 if (!options.vars.requestIds) { 8705 if ($(this).is(':checked')) { 8706 Extension.selectedRows = $.makeArray($(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"]').map(function(i, chk) { 8707 return $(chk).val(); 8708 })); 8709 } 8710 var storage = {}; 8711 storage['selectedRows'] = $.unique(Extension.selectedRows); 8712 datatable.stateKeep('checkbox', storage); 8713 } 8714 8715 // keep selectedAllRows in datasource params 8716 datatable.setDataSourceParam(options.vars.selectedAllRows, Extension.selectedAllRows); 8717 8718 $(datatable).trigger(pfx + 'datatable--on-click-checkbox', [$(this)]); 8719 }); 8720 8721 // single row checkbox click 8722 $(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"]').click(function(e) { 8723 var id = $(this).val(); 8724 if ($(this).is(':checked')) { 8725 Extension.selectedRows.push(id); 8726 // remove from unselected rows 8727 Extension.unselectedRows = Extension.remove(Extension.unselectedRows, id); 8728 } 8729 else { 8730 Extension.unselectedRows.push(id); 8731 // remove from selected rows 8732 Extension.selectedRows = Extension.remove(Extension.selectedRows, id); 8733 } 8734 8735 // local checkbox header check 8736 if (!options.vars.requestIds && Extension.selectedRows.length < 1) { 8737 // remove select all checkbox, if there is no checked checkbox left 8738 $(datatable.tableHead).find('.' + pfx + 'checkbox--all > [type="checkbox"]').prop('checked', false); 8739 } 8740 8741 var storage = {}; 8742 storage['selectedRows'] = $.unique(Extension.selectedRows); 8743 storage['unselectedRows'] = $.unique(Extension.unselectedRows); 8744 datatable.stateKeep('checkbox', storage); 8745 8746 $(datatable).trigger(pfx + 'datatable--on-click-checkbox', [$(this)]); 8747 }); 8748 }, 8749 8750 initSelect: function() { 8751 // selected all rows from server 8752 if (Extension.selectedAllRows && options.vars.requestIds) { 8753 if (!datatable.hasClass(pfx + 'datatable--error')) { 8754 // set header select all checkbox checked 8755 $(datatable.tableHead).find('.' + pfx + 'checkbox--all > [type="checkbox"]').prop('checked', true); 8756 } 8757 8758 // set all checkbox in table body 8759 datatable.setActiveAll(true); 8760 8761 // remove unselected rows 8762 Extension.unselectedRows.forEach(function(id) { 8763 datatable.setInactive(id); 8764 }); 8765 8766 } 8767 else { 8768 // single check for server and local 8769 Extension.selectedRows.forEach(function(id) { 8770 datatable.setActive(id); 8771 }); 8772 8773 // local checkbox; check if all checkboxes of currect page are checked 8774 if (!datatable.hasClass(pfx + 'datatable--error') && $(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"]').not(':checked').length < 1) { 8775 // set header select all checkbox checked 8776 $(datatable.tableHead).find('.' + pfx + 'checkbox--all > [type="checkbox"]').prop('checked', true); 8777 } 8778 } 8779 }, 8780 8781 /** 8782 * Check if selector is enabled from options 8783 */ 8784 selectorEnabled: function() { 8785 return $.grep(datatable.options.columns, function(n, i) { 8786 return n.selector || false; 8787 })[0]; 8788 }, 8789 8790 initVars: function() { 8791 // get single select/unselect from localstorage 8792 var storage = datatable.stateGet('checkbox'); 8793 if (typeof storage !== 'undefined') { 8794 Extension.selectedRows = storage['selectedRows'] || []; 8795 Extension.unselectedRows = storage['unselectedRows'] || []; 8796 } 8797 }, 8798 8799 getSelectedId: function(path) { 8800 Extension.initVars();
8801 8802 // server selected all rows 8803 if (Extension.selectedAllRows && options.vars.requestIds) { 8804 if (typeof path === 'undefined') { 8805 path = options.vars.rowIds; 8806 } 8807 8808 // if selected all rows, return id from response meta 8809 var selectedAllRows = datatable.getObject(path, datatable.lastResponse) || []; 8810 8811 if (selectedAllRows.length > 0) { 8812 // remove single unselected rows from selectedAllRows ids from server response emta 8813 Extension.unselectedRows.forEach(function(id) { 8814 selectedAllRows = Extension.remove(selectedAllRows, parseInt(id)); 8815 }); 8816 } 8817 return selectedAllRows; 8818 } 8819 8820 // else return single checked selected rows 8821 return Extension.selectedRows; 8822 }, 8823 8824 remove: function(array, element) { 8825 return array.filter(function(e) { 8826 return e !== element; 8827 }); 8828 }, 8829 }; 8830 8831 // make the extension accessible from datatable init 8832 datatable.checkbox = function() { 8833 return Extension; 8834 }; 8835 8836 if (typeof options === 'object') { 8837 options = $.extend(true, {}, $.fn[pluginName].checkbox.default, options); 8838 Extension.init.apply(this, [options]); 8839 } 8840 8841 return datatable; 8842 }; 8843 8844 $.fn[pluginName].checkbox.default = { 8845 vars: { 8846 // select all rows flag to be sent to the server 8847 selectedAllRows: 'selectedAllRows', 8848 // request id parameter's name 8849 requestIds: 'requestIds', 8850 // response path to all rows id 8851 rowIds: 'meta.rowIds', 8852 }, 8853 }; 8854 8855}(jQuery)); 8856var defaults = { 8857 layout: { 8858 icons: { 8859 pagination: { 8860 next: 'flaticon2-next', 8861 prev: 'flaticon2-back', 8862 first: 'flaticon2-fast-back', 8863 last: 'flaticon2-fast-next', 8864 more: 'flaticon-more-1', 8865 }, 8866 rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'}, 8867 } 8868 } 8869}; 8870 8871if (KTUtil.isRTL()) { 8872 defaults = { 8873 layout: { 8874 icons: { 8875 pagination: { 8876 next: 'flaticon2-back', 8877 prev: 'flaticon2-next', 8878 first: 'flaticon2-fast-next', 8879 last: 'flaticon2-fast-back', 8880 }, 8881 rowDetail: {collapse: 'fa fa-caret-down', expand: 'fa fa-caret-right'}, 8882 } 8883 } 8884 } 8885} 8886 8887$.extend(true, $.fn.KTDatatable.defaults, defaults); 8888"use strict"; 8889 8890// Class definition 8891var KTChat = function () { 8892 var initChat = function (parentEl) { 8893 var messageListEl = KTUtil.find(parentEl, '.kt-scroll'); 8894 8895 if (!messageListEl) { 8896 return; 8897 } 8898 8899 // initialize perfect scrollbar(see: https://github.com/utatti/perfect-scrollbar) 8900 KTUtil.scrollInit(messageListEl, { 8901 windowScroll: false, // allow browser scroll when the scroll reaches the end of the side 8902 mobileNativeScroll: true, // enable native scroll for mobile 8903 desktopNativeScroll: false, // disable native scroll and use custom scroll for desktop 8904 resetHeightOnDestroy: true, // reset css height on scroll feature destroyed 8905 handleWindowResize: true, // recalculate hight on window resize 8906 rememberPosition: true, // remember scroll position in cookie 8907 height: function() { // calculate height 8908 var height; 8909 8910 // Mobile mode 8911 if (KTUtil.isInResponsiveRange('tablet-and-mobile')) { 8912 return KTUtil.hasAttr(messageListEl, 'data-mobile-height') ? parseInt(KTUtil.attr(messageListEl, 'data-mobile-height')) : 300; 8913 } 8914 8915 // Desktop mode 8916 if (KTUtil.isInResponsiveRange('desktop') && KTUtil.hasAttr(messageListEl, 'data-height')) { 8917 return parseInt(KTUtil.attr(messageListEl, 'data-height')); 8918 } 8919 8920 var chatEl = KTUtil.find(parentEl, '.kt-chat'); 8921 var portletHeadEl = KTUtil.find(parentEl, '.kt-portlet > .kt-portlet__head'); 8922 var portletBodyEl = KTUtil.find(parentEl, '.kt-portlet > .kt-portlet__body'); 8923 var portletFootEl = KTUtil.find(parentEl, '.kt-portlet > .kt-portlet__foot'); 8924 8925 if (KTUtil.isInResponsiveRange('desktop')) { 8926 height = KTLayout.getContentHeight(); 8927 } else { 8928 height = KTUtil.getViewPort().height; 8929 } 8930 8931 if (chatEl) { 8932 height = height - parseInt(KTUtil.css(chatEl, 'margin-top')) - parseInt(KTUtil.css(chatEl, 'margin-bottom')); 8933 height = height - parseInt(KTUtil.css(chatEl, 'padding-top')) - parseInt(KTUtil.css(chatEl, 'padding-bottom')); 8934 } 8935 8936 if (portletHeadEl) { 8937 height = height - parseInt(KTUtil.css(portletHeadEl, 'height')); 8938 height = height - parseInt(KTUtil.css(portletHeadEl, 'margin-top')) - parseInt(KTUtil.css(portletHeadEl, 'margin-bottom')); 8939 } 8940 8941 if (portletBodyEl) { 8942 height = height - parseInt(KTUtil.css(portletBodyEl, 'margin-top')) - parseInt(KTUtil.css(portletBodyEl, 'margin-bottom')); 8943 height = height - parseInt(KTUtil.css(portletBodyEl, 'padding-top')) - parseInt(KTUtil.css(portletBodyEl, 'padding-bottom')); 8944 } 8945 8946 if (portletFootEl) {
8947 height = height - parseInt(KTUtil.css(portletFootEl, 'height')); 8948 height = height - parseInt(KTUtil.css(portletFootEl, 'margin-top')) - parseInt(KTUtil.css(portletFootEl, 'margin-bottom')); 8949 } 8950 8951 // remove additional space 8952 height = height - 5; 8953 8954 return height; 8955 } 8956 }); 8957 8958 // messaging 8959 var handleMessaging = function() { 8960 var scrollEl = KTUtil.find(parentEl, '.kt-scroll'); 8961 var messagesEl = KTUtil.find(parentEl, '.kt-chat__messages'); 8962 var textarea = KTUtil.find(parentEl, '.kt-chat__input textarea'); 8963 8964 if (textarea.value.length === 0 ) { 8965 return; 8966 } 8967 8968 var node = document.createElement("DIV"); 8969 KTUtil.addClass(node, 'kt-chat__message kt-chat__message--brand kt-chat__message--right'); 8970 8971 var html = 8972 '<div class="kt-chat__user">' + 8973 '<span class="kt-chat__datetime">Just now</span>' + 8974 '<a href="#" class="kt-chat__username">Jason Muller</span></a>' + 8975 '<span class="kt-media kt-media--circle kt-media--sm">' + 8976 '<img src="./assets/media/users/100_12.jpg" alt="image">' + 8977 '</span>' + 8978 '</div>' + 8979 '<div class="kt-chat__text kt-bg-light-brand">' + 8980 textarea.value 8981 '</div>'; 8982 8983 KTUtil.setHTML(node, html); 8984 messagesEl.appendChild(node); 8985 textarea.value = ''; 8986 scrollEl.scrollTop = parseInt(KTUtil.css(messagesEl, 'height')); 8987 8988 var ps; 8989 if (ps = KTUtil.data(scrollEl).get('ps')) { 8990 ps.update(); 8991 } 8992 8993 setTimeout(function() { 8994 var node = document.createElement("DIV"); 8995 KTUtil.addClass(node, 'kt-chat__message kt-chat__message--success'); 8996 8997 var html = 8998 '<div class="kt-chat__user">' + 8999 '<span class="kt-media kt-media--circle kt-media--sm">' + 9000 '<img src="./assets/media/users/100_13.jpg" alt="image">' + 9001 '</span>' + 9002 '<a href="#" class="kt-chat__username">Max Born</span></a>' + 9003 '<span class="kt-chat__datetime">Just now</span>' + 9004 '</div>' + 9005 '<div class="kt-chat__text kt-bg-light-success">' + 9006 '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.' + 9007 '</div>'; 9008 9009 KTUtil.setHTML(node, html); 9010 messagesEl.appendChild(node); 9011 textarea.value = ''; 9012 scrollEl.scrollTop = parseInt(KTUtil.css(messagesEl, 'height')); 9013 9014 var ps; 9015 if (ps = KTUtil.data(scrollEl).get('ps')) { 9016 ps.update(); 9017 } 9018 }, 2000); 9019 } 9020 9021 // attach events 9022 KTUtil.on(parentEl, '.kt-chat__input textarea', 'keydown', function(e) { 9023 if (e.keyCode == 13) { 9024 handleMessaging(); 9025 e.preventDefault(); 9026 9027 return false; 9028 } 9029 }); 9030 9031 KTUtil.on(parentEl, '.kt-chat__input .kt-chat__reply', 'click', function(e) { 9032 handleMessaging(); 9033 }); 9034 } 9035 9036 return { 9037 // public functions 9038 init: function() { 9039 // init modal chat example 9040 initChat( KTUtil.getByID('kt_chat_modal')); 9041 9042 // trigger click to show popup modal chat on page load 9043 if (encodeURI(window.location.hostname) == 'keenthemes.com' || encodeURI(window.location.hostname) == 'www.keenthemes.com') { 9044 setTimeout(function() { 9045 if (!Cookies.get('kt_app_chat_shown')) { 9046 var expires = new Date(new Date().getTime() + 60 * 60 * 1000); // expire in 60 minutes from now 9047 Cookies.set('kt_app_chat_shown', 1, { expires: expires }); 9048 KTUtil.getByID('kt_app_chat_launch_btn').click(); 9049 } 9050 }, 2000); 9051 } 9052 }, 9053 9054 setup: function(element) { 9055 initChat(element); 9056 } 9057 }; 9058}(); 9059 9060// webpack support 9061if (typeof module !== 'undefined') { 9062 module.exports = KTChat; 9063} 9064 9065KTUtil.ready(function() { 9066 KTChat.init(); 9067}); 9068 9069"use strict"; 9070 9071var KTDemoPanel = function() { 9072 var demoPanel; 9073 var offcanvas; 9074 9075 var init = function() { 9076 offcanvas = new KTOffcanvas(demoPanel, { 9077 overlay: true, 9078 baseClass: 'kt-demo-panel', 9079 closeBy: 'kt_demo_panel_close', 9080 toggleBy: 'kt_demo_panel_toggle' 9081 }); 9082 9083 var head = KTUtil.find(demoPanel, '.kt-demo-panel__head'); 9084 var body = KTUtil.find(demoPanel, '.kt-demo-panel__body'); 9085 9086 KTUtil.scrollInit(body, { 9087 disableForMobile: true, 9088 resetHeightOnDestroy: true, 9089 handleWindowResize: true, 9090 height: function() { 9091 var height = parseInt(KTUtil.getViewPort().height); 9092 9093 if (head) { 9094 height = height - parseInt(KTUtil.actualHeight(head)); 9095 height = height - parseInt(KTUtil.css(head, 'marginBottom')); 9096 } 9097 9098 height = height - parseInt(KTUtil.css(demoPanel, 'paddingTop')); 9099 height = height - parseInt(KTUtil.css(demoPanel, 'paddingBottom')); 9100 9101 return height; 9102 } 9103 }); 9104 9105 if (typeof offcanvas !== 'undefined' && offcanvas.length === 0) { 9106 offcanvas.on('hide', function() { 9107 var expires = new Date(new Date().getTime() + 60 * 60 * 1000); // expire in 60 minutes from now 9108 Cookies.set('kt_demo_panel_shown', 1, {expires: expires}); 9109 }); 9110 } 9111 } 9112 9113 var remind = function() { 9114 if (!(encodeURI(window.location.hostname) == 'keenthemes.com' || encodeURI(window.location.hostname) == 'www.keenthemes.com')) { 9115 return; 9116 } 9117 9118 setTimeout(function() { 9119 if (!Cookies.get('kt_demo_panel_shown')) { 9120 var expires = new Date(new Date().getTime() + 15 * 60 * 1000); // expire in 15 minutes from now 9121 Cookies.set('kt_demo_panel_shown', 1, { expires: expires }); 9122 offcanvas.show(); 9123 } 9124 }, 4000); 9125 } 9126 9127 return { 9128 init: function() { 9129 demoPanel = KTUtil.getByID('kt_demo_panel'); 9130 9131 init(); 9132 remind(); 9133 } 9134 }; 9135}(); 9136 9137$(document).ready(function() { 9138 KTDemoPanel.init(); 9139}); 9140 9141"use strict"; 9142 9143var KTLayout = function() { 9144 var body; 9145 9146 var header; 9147 var headerMenu; 9148 var headerMenuOffcanvas; 9149 var mobileHeaderTopbarToggle; 9150 9151 var asideMenu; 9152 var asideMenuOffcanvas; 9153 9154 var scrollTop; 9155 9156 var pageStickyPortlet; 9157 9158 // Header 9159 var initHeader = function() { 9160 var tmp; 9161 var headerEl = KTUtil.get('kt_header'); 9162 var options = { 9163 classic: { 9164 desktop: true, 9165 mobile: false 9166 }, 9167 offset: {}, 9168 minimize: {} 9169 }; 9170 9171 options.minimize.mobile = false; 9172 9173 if (KTUtil.attr(headerEl, 'data-ktheader-minimize') == 'on') { 9174 options.minimize.desktop = {}; 9175 options.minimize.desktop.on = 'kt-header--minimize'; 9176 options.offset.desktop = parseInt(KTUtil.css(headerEl, 'height')) - 10; 9177 } else { 9178 options.minimize.desktop = false; 9179 } 9180 9181 header = new KTHeader('kt_header', options); 9182 9183 if (asideMenu) { 9184 header.on('minimizeOn', function() { 9185 asideMenu.scrollReInit(); 9186 }); 9187 9188 header.on('minimizeOff', function() { 9189 asideMenu.scrollReInit(); 9190 }); 9191 } 9192 } 9193 9194 // Header Menu 9195 var initHeaderMenu = function() { 9196 // init aside left offcanvas 9197 headerMenuOffcanvas = new KTOffcanvas('kt_header_menu_wrapper', { 9198 overlay: true, 9199 baseClass: 'kt-header-menu-wrapper', 9200 closeBy: 'kt_header_menu_mobile_close_btn', 9201 toggleBy: { 9202 target: 'kt_header_mobile_toggler', 9203 state: 'kt-header-mobile__toolbar-toggler--active' 9204 } 9205 }); 9206 9207 headerMenu = new KTMenu('kt_header_menu', { 9208 submenu: { 9209 desktop: 'dropdown', 9210 tablet: 'accordion', 9211 mobile: 'accordion' 9212 }, 9213 accordion: { 9214 slideSpeed: 200, // accordion toggle slide speed in milliseconds 9215 expandAll: false // allow having multiple expanded accordions in the menu 9216 } 9217 }); 9218 } 9219 9220 // Header Topbar 9221 var initHeaderTopbar = function() { 9222 mobileHeaderTopbarToggle = new KTToggle('kt_header_mobile_topbar_toggler', { 9223 target: 'body', 9224 targetState: 'kt-header__topbar--mobile-on', 9225 togglerState: 'kt-header-mobile__toolbar-topbar-toggler--active' 9226 }); 9227 } 9228 9229 // Aside 9230 var initAside = function() { 9231 // init aside left offcanvas 9232 var asidBrandHover = false; 9233 var aside = KTUtil.get('kt_aside'); 9234 var asideBrand = KTUtil.get('kt_aside_brand'); 9235 var asideOffcanvasClass = KTUtil.hasClass(aside, 'kt-aside--offcanvas-default') ? 'kt-aside--offcanvas-default' : 'kt-aside'; 9236 9237 var asideMenuOffcanvas = new KTOffcanvas('kt_aside', { 9238 baseClass: asideOffcanvasClass, 9239 overlay: true, 9240 closeBy: 'kt_aside_close_btn', 9241 toggleBy: [{ 9242 target: 'kt_aside_mobile_toggler', 9243 state: 'kt-aside-toggler--active' 9244 },{ 9245 target: 'kt_aside_toggler', 9246 state: 'kt-aside-toggler--active' 9247 }] 9248 }); 9249 } 9250 9251 // Aside menu 9252 var initAsideMenu = function() { 9253 // Init aside menu 9254 var menu = KTUtil.get('kt_aside_menu'); 9255 var menuDesktopMode = (KTUtil.attr(menu, 'data-ktmenu-dropdown') === '1' ? 'dropdown' : 'accordion'); 9256 9257 // Init scrollable menu container 9258 var scroll; 9259 if (KTUtil.attr(menu, 'data-ktmenu-scroll') === '1') { 9260 scroll = { 9261 rememberPosition: true, // remember position on page reload 9262 height: function() { // calculate available scrollable area height 9263 var height; 9264 9265 if (KTUtil.isInResponsiveRange('desktop')) { 9266 height = parseInt(KTUtil.getViewPort().height); 9267 height = height - parseInt(KTUtil.css(menu, 'marginTop')) - parseInt(KTUtil.css(menu, 'marginBottom')); 9268 } else { 9269 height = parseInt(KTUtil.getViewPort().height); 9270 } 9271 9272 return height; 9273 } 9274 }; 9275 } 9276 9277 // Init aside menu 9278 asideMenu = new KTMenu('kt_aside_menu', { 9279 // vertical scroll 9280 scroll: scroll, 9281 9282 // submenu setup 9283 submenu: { 9284 desktop: menuDesktopMode, 9285 tablet: 'accordion', // menu set to accordion in tablet mode 9286 mobile: 'accordion' // menu set to accordion in mobile mode 9287 }, 9288 9289 //accordion setup 9290 accordion: { 9291 expandAll: false // allow having multiple expanded accordions in the menu 9292 } 9293 }); 9294 } 9295 9296 // Scrolltop 9297 var initScrolltop = function() { 9298 var scrolltop = new KTScrolltop('kt_scrolltop', { 9299 offset: 200, 9300 speed: 400 9301 }); 9302 } 9303 9304 // Init page sticky portlet 9305 var initPageStickyPortlet = function() { 9306 return new KTPortlet('kt_page_portlet', { 9307 sticky: { 9308 offset: parseInt(KTUtil.css( KTUtil.get('kt_header'), 'height')) + 200, 9309 zIndex: 90, 9310 position: { 9311 top: function() { 9312 if (KTUtil.isInResponsiveRange('desktop')) { 9313 return 60;
9313 //parseInt(KTUtil.actualHeight( KTUtil.get('kt_header'), 'height') ); 9314 } else { 9315 return parseInt(KTUtil.css( KTUtil.get('kt_header_mobile'), 'height') ); 9316 } 9317 }, 9318 left: function(portlet) { 9319 var porletEl = portlet.getSelf(); 9320 9321 return KTUtil.offset(porletEl).left; 9322 }, 9323 right: function(portlet) { 9324 var porletEl = portlet.getSelf(); 9325 9326 var portletWidth = parseInt(KTUtil.css(porletEl, 'width')); 9327 var bodyWidth = parseInt(KTUtil.css(KTUtil.get('body'), 'width')); 9328 var portletOffsetLeft = KTUtil.offset(porletEl).left; 9329 9330 return bodyWidth - portletWidth - portletOffsetLeft; 9331 } 9332 } 9333 } 9334 }); 9335 } 9336 9337 // Calculate content available full height 9338 var getContentHeight = function() { 9339 var height; 9340 9341 height = KTUtil.getViewPort().height; 9342 9343 if (KTUtil.getByID('kt_header')) { 9344 height = height - KTUtil.actualHeight('kt_header'); 9345 } 9346 9347 if (KTUtil.getByID('kt_subheader')) { 9348 height = height - KTUtil.actualHeight('kt_subheader'); 9349 } 9350 9351 if (KTUtil.getByID('kt_footer')) { 9352 height = height - parseInt(KTUtil.css('kt_footer', 'height')); 9353 } 9354 9355 if (KTUtil.getByID('kt_content')) { 9356 height = height - parseInt(KTUtil.css('kt_content', 'padding-top')) - parseInt(KTUtil.css('kt_content', 'padding-bottom')); 9357 } 9358 9359 return height; 9360 } 9361 9362 return { 9363 init: function() { 9364 body = KTUtil.get('body'); 9365 9366 this.initHeader(); 9367 this.initAside(); 9368 this.initPageStickyPortlet(); 9369 9370 // Non functional links notice(can be removed in production) 9371 $('#kt_aside_menu, #kt_header_menu').on('click', '.kt-menu__link[href="#"]', function(e) { 9372 swal.fire("", "You have clicked on a non-functional dummy link!"); 9373 9374 e.preventDefault(); 9375 }); 9376 }, 9377 9378 initHeader: function() { 9379 initHeader(); 9380 initHeaderMenu(); 9381 initHeaderTopbar(); 9382 initScrolltop(); 9383 }, 9384 9385 initAside: function() { 9386 initAside(); 9387 initAsideMenu(); 9388 }, 9389 9390 getAsideMenu: function() { 9391 return asideMenu; 9392 }, 9393 9394 initPageStickyPortlet: function() { 9395 if (!KTUtil.get('kt_page_portlet')) { 9396 return; 9397 } 9398 9399 pageStickyPortlet = initPageStickyPortlet(); 9400 pageStickyPortlet.initSticky(); 9401 9402 KTUtil.addResizeHandler(function(){ 9403 pageStickyPortlet.updateSticky(); 9404 }); 9405 9406 initPageStickyPortlet(); 9407 }, 9408 9409 closeMobileAsideMenuOffcanvas: function() { 9410 if (KTUtil.isMobileDevice()) { 9411 asideMenuOffcanvas.hide(); 9412 } 9413 }, 9414 9415 closeMobileHeaderMenuOffcanvas: function() { 9416 if (KTUtil.isMobileDevice()) { 9417 headerMenuOffcanvas.hide(); 9418 } 9419 }, 9420 9421 getContentHeight: function() { 9422 return getContentHeight(); 9423 } 9424 }; 9425}(); 9426 9427// webpack support 9428if (typeof module !== 'undefined') { 9429 module.exports = KTLayout; 9430} 9431 9432$(document).ready(function() { 9433 KTLayout.init(); 9434}); 9435 9436"use strict"; 9437 9438var KTOffcanvasPanel = function() { 9439 var notificationPanel; 9440 var quickActionsPanel; 9441 var profilePanel; 9442 var searchPanel; 9443 9444 var initNotifications = function() { 9445 var head = KTUtil.find(notificationPanel, '.kt-offcanvas-panel__head'); 9446 var body = KTUtil.find(notificationPanel, '.kt-offcanvas-panel__body'); 9447 9448 var offcanvas = new KTOffcanvas(notificationPanel, { 9449 overlay: true, 9450 baseClass: 'kt-offcanvas-panel', 9451 closeBy: 'kt_offcanvas_toolbar_notifications_close', 9452 toggleBy: 'kt_offcanvas_toolbar_notifications_toggler_btn' 9453 }); 9454 9455 KTUtil.scrollInit(body, { 9456 disableForMobile: true, 9457 resetHeightOnDestroy: true, 9458 handleWindowResize: true, 9459 height: function() { 9460 var height = parseInt(KTUtil.getViewPort().height); 9461 9462 if (head) { 9463 height = height - parseInt(KTUtil.actualHeight(head)); 9464 height = height - parseInt(KTUtil.css(head, 'marginBottom')); 9465 } 9466 9467 height = height - parseInt(KTUtil.css(notificationPanel, 'paddingTop')); 9468 height = height - parseInt(KTUtil.css(notificationPanel, 'paddingBottom')); 9469 9470 return height; 9471 } 9472 }); 9473 } 9474 9475 var initQucikActions = function() { 9476 var head = KTUtil.find(quickActionsPanel, '.kt-offcanvas-panel__head'); 9477 var body = KTUtil.find(quickActionsPanel, '.kt-offcanvas-panel__body'); 9478 9479 var offcanvas = new KTOffcanvas(quickActionsPanel, { 9480 overlay: true, 9481 baseClass: 'kt-offcanvas-panel', 9482 closeBy: 'kt_offcanvas_toolbar_quick_actions_close', 9483 toggleBy: 'kt_offcanvas_toolbar_quick_actions_toggler_btn' 9484 }); 9485 9486 KTUtil.scrollInit(body, { 9487 disableForMobile: true, 9488 resetHeightOnDestroy: true, 9489 handleWindowResize: true, 9490 height: function() { 9491 var height = parseInt(KTUtil.getViewPort().height); 9492 9493 if (head) { 9494 height = height - parseInt(KTUtil.actualHeight(head)); 9495 height = height - parseInt(KTUtil.css(head, 'marginBottom')); 9496 } 9497 9498 height = height - parseInt(KTUtil.css(quickActionsPanel, 'paddingTop')); 9499 height = height - parseInt(KTUtil.css(quickActionsPanel, 'paddingBottom')); 9500 9501 return height; 9502 } 9503 }); 9504 } 9505 9506 var initProfile = function() { 9507 var head = KTUtil.find(profilePanel, '.kt-offcanvas-panel__head'); 9508 var body = KTUtil.find(profilePanel, '.kt-offcanvas-panel__body'); 9509 9510 var offcanvas = new KTOffcanvas(profilePanel, { 9511 overlay: true, 9512 baseClass: 'kt-offcanvas-panel', 9513 closeBy: 'kt_offcanvas_toolbar_profile_close', 9514 toggleBy: 'kt_offcanvas_toolbar_profile_toggler_btn' 9515 }); 9516 9517 KTUtil.scrollInit(body, { 9518 disableForMobile: true, 9519 resetHeightOnDestroy: true, 9520 handleWindowResize: true, 9521 height: function() { 9522 var height = parseInt(KTUtil.getViewPort().height); 9523 9524 if (head) { 9525 height = height - parseInt(KTUtil.actualHeight(head)); 9526 height = height - parseInt(KTUtil.css(head, 'marginBottom')); 9527 } 9528 9529 height = height - parseInt(KTUtil.css(profilePanel, 'paddingTop')); 9530 height = height - parseInt(KTUtil.css(profilePanel, 'paddingBottom')); 9531 9532 return height; 9533 } 9534 }); 9535 } 9536 9537 var initSearch = function() { 9538 var head = KTUtil.find(searchPanel, '.kt-offcanvas-panel__head'); 9539 var body = KTUtil.find(searchPanel, '.kt-offcanvas-panel__body'); 9540 var search = KTUtil.get('kt_quick_search_offcanvas'); 9541 var form = KTUtil.find(search, '.kt-quick-search__form'); 9542 var wrapper = KTUtil.find(search, '.kt-quick-search__wrapper'); 9543 9544 var offcanvas = new KTOffcanvas(searchPanel, { 9545 overlay: true, 9546 baseClass: 'kt-offcanvas-panel', 9547 closeBy: 'kt_offcanvas_toolbar_search_close', 9548 toggleBy: 'kt_offcanvas_toolbar_search_toggler_btn' 9549 }); 9550 9551 KTUtil.scrollInit(wrapper, { 9552 disableForMobile: true, 9553 resetHeightOnDestroy: true, 9554 handleWindowResize: true, 9555 height: function() { 9556 var height = parseInt(KTUtil.getViewPort().height); 9557 9558 height = height - parseInt(KTUtil.actualHeight(form)); 9559 height = height - parseInt(KTUtil.css(form, 'marginBottom')); 9560 9561 if (head) { 9562 height = height - parseInt(KTUtil.actualHeight(head)); 9563 height = height - parseInt(KTUtil.css(head, 'marginBottom')); 9564 } 9565 9566 height = height - parseInt(KTUtil.css(searchPanel, 'paddingTop')); 9567 height = height - parseInt(KTUtil.css(searchPanel, 'paddingBottom')); 9568 9569 return height; 9570 } 9571 }); 9572 } 9573 9574 return { 9575 init: function() { 9576 notificationPanel = KTUtil.get('kt_offcanvas_toolbar_notifications'); 9577 quickActionsPanel = KTUtil.get('kt_offcanvas_toolbar_quick_actions'); 9578 profilePanel = KTUtil.get('kt_offcanvas_toolbar_profile'); 9579 searchPanel = KTUtil.get('kt_offcanvas_toolbar_search'); 9580 9581 initNotifications(); 9582 initQucikActions(); 9583 initProfile(); 9584 initSearch(); 9585 } 9586 }; 9587}(); 9588 9589// Init on page load completed 9590KTUtil.ready(function() { 9591 KTOffcanvasPanel.init(); 9592}); 9593 9594"use strict"; 9595 9596var KTQuickPanel = function() { 9597 var panel; 9598 var notificationPanel; 9599 var logsPanel; 9600 var settingsPanel; 9601 9602 var getContentHeight = function() { 9603 var height; 9604 var nav = KTUtil.find(panel, '.kt-quick-panel__nav'); 9605 var content = KTUtil.find(panel, '.kt-quick-panel__content'); 9606 9607 height = parseInt(KTUtil.getViewPort().height) - parseInt(KTUtil.actualHeight(nav)) - (2 * parseInt(KTUtil.css(nav, 'padding-top'))) - 10; 9608 9609 return height; 9610 } 9611 9612 var initOffcanvas = function() { 9613 new KTOffcanvas(panel, { 9614 overlay: true, 9615 baseClass: 'kt-quick-panel', 9616 closeBy: 'kt_quick_panel_close_btn', 9617 toggleBy: 'kt_quick_panel_toggler_btn' 9618 }); 9619 } 9620 9621 var initNotifications = function() { 9622 KTUtil.scrollInit(notificationPanel, { 9623 mobileNativeScroll: true, 9624 resetHeightOnDestroy: true, 9625 handleWindowResize: true, 9626 height: function() { 9627 return getContentHeight(); 9628 } 9629 }); 9630 } 9631 9632 var initLogs = function() { 9633 KTUtil.scrollInit(logsPanel, { 9634 mobileNativeScroll: true, 9635 resetHeightOnDestroy: true, 9636 handleWindowResize: true, 9637 height: function() { 9638 return getContentHeight(); 9639 } 9640 }); 9641 } 9642 9643 var initSettings = function() { 9644 KTUtil.scrollInit(settingsPanel, { 9645 mobileNativeScroll: true, 9646 resetHeightOnDestroy: true, 9647 handleWindowResize: true, 9648 height: function() { 9649 return getContentHeight(); 9650 } 9651 }); 9652 } 9653 9654 var updatePerfectScrollbars = function() { 9655 $(panel).find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { 9656 KTUtil.scrollUpdate(notificationPanel); 9657 KTUtil.scrollUpdate(logsPanel); 9658 KTUtil.scrollUpdate(settingsPanel); 9659 }); 9660 } 9661 9662 return { 9663 init: function() { 9664 panel = KTUtil.get('kt_quick_panel'); 9665 notificationPanel = KTUtil.get('kt_quick_panel_tab_notifications'); 9666 logsPanel = KTUtil.get('kt_quick_panel_tab_logs'); 9667 settingsPanel = KTUtil.get('kt_quick_panel_tab_settings'); 9668 9669 initOffcanvas(); 9670 initNotifications(); 9671 initLogs(); 9672 initSettings();
9673 updatePerfectScrollbars(); 9674 } 9675 }; 9676}(); 9677 9678$(document).ready(function() { 9679 KTQuickPanel.init(); 9680}); 9681 9682"use strict"; 9683 9684var KTQuickSearch = function() { 9685 var target; 9686 var form; 9687 var input; 9688 var closeIcon; 9689 var resultWrapper; 9690 var resultDropdown; 9691 var resultDropdownToggle; 9692 var inputGroup; 9693 var query = ''; 9694 9695 var hasResult = false; 9696 var timeout = false; 9697 var isProcessing = false; 9698 var requestTimeout = 200; // ajax request fire timeout in milliseconds 9699 var spinnerClass = 'kt-spinner kt-spinner--input kt-spinner--sm kt-spinner--brand kt-spinner--right'; 9700 var resultClass = 'kt-quick-search--has-result'; 9701 var minLength = 2; 9702 9703 var showProgress = function() { 9704 isProcessing = true; 9705 KTUtil.addClass(inputGroup, spinnerClass); 9706 9707 if (closeIcon) { 9708 KTUtil.hide(closeIcon); 9709 } 9710 } 9711 9712 var hideProgress = function() { 9713 isProcessing = false; 9714 KTUtil.removeClass(inputGroup, spinnerClass); 9715 9716 if (closeIcon) { 9717 if (input.value.length < minLength) { 9718 KTUtil.hide(closeIcon); 9719 } else { 9720 KTUtil.show(closeIcon, 'flex'); 9721 } 9722 } 9723 } 9724 9725 var showDropdown = function() { 9726 if (resultDropdownToggle && !KTUtil.hasClass(resultDropdown, 'show')) { 9727 $(resultDropdownToggle).dropdown('toggle'); 9728 $(resultDropdownToggle).dropdown('update'); 9729 } 9730 } 9731 9732 var hideDropdown = function() { 9733 if (resultDropdownToggle && KTUtil.hasClass(resultDropdown, 'show')) { 9734 $(resultDropdownToggle).dropdown('toggle'); 9735 } 9736 } 9737 9738 var processSearch = function() { 9739 if (hasResult && query === input.value) { 9740 hideProgress(); 9741 KTUtil.addClass(target, resultClass); 9742 showDropdown(); 9743 KTUtil.scrollUpdate(resultWrapper); 9744 9745 return; 9746 } 9747 9748 query = input.value; 9749 9750 KTUtil.removeClass(target, resultClass); 9751 showProgress(); 9752 hideDropdown(); 9753 9754 setTimeout(function() { 9755 $.ajax({
9756 url: 'https://keenthemes.com/metronic/tools/preview/api/quick_search.php', 9757 data: { 9758 query: query 9759 }, 9760 dataType: 'html', 9761 success: function(res) { 9762 hasResult = true; 9763 hideProgress(); 9764 KTUtil.addClass(target, resultClass); 9765 KTUtil.setHTML(resultWrapper, res); 9766 showDropdown(); 9767 KTUtil.scrollUpdate(resultWrapper); 9768 }, 9769 error: function(res) { 9770 hasResult = false; 9771 hideProgress(); 9772 KTUtil.addClass(target, resultClass); 9773 KTUtil.setHTML(resultWrapper, '<span class="kt-quick-search__message">Connection error. Pleae try again later.</div>'); 9774 showDropdown(); 9775 KTUtil.scrollUpdate(resultWrapper); 9776 } 9777 }); 9778 }, 1000); 9779 } 9780 9781 var handleCancel = function(e) { 9782 input.value = ''; 9783 query = ''; 9784 hasResult = false; 9785 KTUtil.hide(closeIcon); 9786 KTUtil.removeClass(target, resultClass); 9787 hideDropdown(); 9788 } 9789 9790 var handleSearch = function() { 9791 if (input.value.length < minLength) { 9792 hideProgress(); 9793 hideDropdown(); 9794 9795 return; 9796 } 9797 9798 if (isProcessing == true) { 9799 return; 9800 } 9801 9802 if (timeout) { 9803 clearTimeout(timeout); 9804 } 9805 9806 timeout = setTimeout(function() { 9807 processSearch(); 9808 }, requestTimeout); 9809 } 9810 9811 return { 9812 init: function(element) { 9813 // Init 9814 target = element; 9815 form = KTUtil.find(target, '.kt-quick-search__form'); 9816 input = KTUtil.find(target, '.kt-quick-search__input'); 9817 closeIcon = KTUtil.find(target, '.kt-quick-search__close'); 9818 resultWrapper = KTUtil.find(target, '.kt-quick-search__wrapper'); 9819 resultDropdown = KTUtil.find(target, '.dropdown-menu'); 9820 resultDropdownToggle = KTUtil.find(target, '[data-toggle="dropdown"]'); 9821 inputGroup = KTUtil.find(target, '.input-group'); 9822 9823 // Attach input keyup handler 9824 KTUtil.addEvent(input, 'keyup', handleSearch); 9825 KTUtil.addEvent(input, 'focus', handleSearch); 9826 9827 // Prevent enter click 9828 form.onkeypress = function(e) { 9829 var key = e.charCode || e.keyCode || 0; 9830 if (key == 13) { 9831 e.preventDefault(); 9832 } 9833 } 9834 9835 KTUtil.addEvent(closeIcon, 'click', handleCancel); 9836 } 9837 }; 9838};
9839 9840var KTQuickSearchInline = KTQuickSearch; 9841var KTQuickSearchOffcanvas = KTQuickSearch; 9842 9843// Init on page load completed 9844 9845KTUtil.ready(function() { 9846 if (KTUtil.get('kt_quick_search_dropdown')) { 9847 KTQuickSearch().init(KTUtil.get('kt_quick_search_dropdown')); 9848 } 9849 9850 if (KTUtil.get('kt_quick_search_inline')) { 9851 KTQuickSearchInline().init(KTUtil.get('kt_quick_search_inline')); 9852 } 9853 9854 if (KTUtil.get('kt_quick_search_offcanvas')) { 9855 KTQuickSearchOffcanvas().init(KTUtil.get('kt_quick_search_offcanvas')); 9856 } 9857});
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.