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