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