1/*! 2 * SmartMenus jQuery Plugin - v1.0.0 - January 27, 2016 3 * http://www.smartmenus.org/ 4 * 5 * Copyright Vasil Dinkov, Vadikom Web Ltd. 6 * http://vadikom.com 7 * 8 * Licensed MIT 9 */ 10 11(function(factory) { 12 if (typeof define === 'function' && define.amd) { 13 // AMD 14 define(['jquery'], factory); 15 } else if (typeof module === 'object' && typeof module.exports === 'object') { 16 // CommonJS 17 module.exports = factory(require('jquery')); 18 } else { 19 // Global jQuery 20 factory(jQuery); 21 } 22} (function($) { 23 24 var menuTrees = [], 25 IE = !!window.createPopup, // detect it for the iframe shim 26 mouse = false, // optimize for touch by default - we will detect for mouse input 27 touchEvents = 'ontouchstart' in window, // we use this just to choose between toucn and pointer events, not for touch screen detection 28 mouseDetectionEnabled = false, 29 requestAnimationFrame = window.requestAnimationFrame || function(callback) { return setTimeout(callback, 1000 / 60); }, 30 cancelAnimationFrame = window.cancelAnimationFrame || function(id) { clearTimeout(id); }; 31 32 // Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.) 33 function initMouseDetection(disable) { 34 var eNS = '.smartmenus_mouse'; 35 if (!mouseDetectionEnabled && !disable) { 36 // if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present 37 // in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events) 38 var firstTime = true, 39 lastMove = null; 40 $(document).bind(getEventsNS([ 41 ['mousemove', function(e) { 42 var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() }; 43 if (lastMove) { 44 var deltaX = Math.abs(lastMove.x - thisMove.x), 45 deltaY = Math.abs(lastMove.y - thisMove.y); 46 if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) { 47 mouse = true; 48 // if this is the first check after page load, check if we are not over some item by chance and call the mouseenter handler if yes 49 if (firstTime) { 50 var $a = $(e.target).closest('a'); 51 if ($a.is('a')) { 52 $.each(menuTrees, function() { 53 if ($.contains(this.$root[0], $a[0])) { 54 this.itemEnter({ currentTarget: $a[0] }); 55 return false; 56 } 57 }); 58 } 59 firstTime = false; 60 } 61 } 62 } 63 lastMove = thisMove; 64 }], 65 [touchEvents ? 'touchstart' : 'pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut', function(e) { 66 if (isTouchEvent(e.originalEvent)) { 67 mouse = false; 68 } 69 }] 70 ], eNS)); 71 mouseDetectionEnabled = true; 72 } else if (mouseDetectionEnabled && disable) { 73 $(document).unbind(eNS); 74 mouseDetectionEnabled = false; 75 } 76 } 77 78 function isTouchEvent(e) { 79 return !/^(4|mouse)$/.test(e.pointerType); 80 } 81 82 // returns a jQuery bind() ready object 83 function getEventsNS(defArr, eNS) { 84 if (!eNS) { 85 eNS = ''; 86 } 87 var obj = {}; 88 $.each(defArr, function(index, value) { 89 obj[value[0].split(' ').join(eNS + ' ') + eNS] = value[1]; 90 }); 91 return obj; 92 } 93 94 $.SmartMenus = function(elm, options) { 95 this.$root = $(elm); 96 this.opts = options; 97 this.rootId = ''; // internal 98 this.accessIdPrefix = ''; 99 this.$subArrow = null; 100 this.activatedItems = []; // stores last activated A's for each level 101 this.visibleSubMenus = []; // stores visible sub menus UL's (might be in no particular order) 102 this.showTimeout = 0; 103 this.hideTimeout = 0; 104 this.scrollTimeout = 0; 105 this.clickActivated = false; 106 this.focusActivated = false; 107 this.zIndexInc = 0; 108 this.idInc = 0; 109 this.$firstLink = null; // we'll use these for some tests 110 this.$firstSub = null; // at runtime so we'll cache them 111 this.disabled = false; 112 this.$disableOverlay = null; 113 this.$touchScrollingSub = null; 114 this.cssTransforms3d = 'perspective' in elm.style || 'webkitPerspective' in elm.style; 115 this.wasCollapsible = false;
116 this.init(); 117 }; 118 119 $.extend($.SmartMenus, { 120 hideAll: function() { 121 $.each(menuTrees, function() { 122 this.menuHideAll(); 123 }); 124 }, 125 destroy: function() { 126 while (menuTrees.length) { 127 menuTrees[0].destroy(); 128 } 129 initMouseDetection(true); 130 }, 131 prototype: { 132 init: function(refresh) { 133 var self = this; 134 135 if (!refresh) { 136 menuTrees.push(this); 137 138 this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, ''); 139 this.accessIdPrefix = 'sm-' + this.rootId + '-'; 140 141 if (this.$root.hasClass('sm-rtl')) { 142 this.opts.rightToLeftSubMenus = true; 143 } 144 145 // init root (main menu) 146 var eNS = '.smartmenus'; 147 this.$root 148 .data('smartmenus', this) 149 .attr('data-smartmenus-id', this.rootId) 150 .dataSM('level', 1) 151 .bind(getEventsNS([ 152 ['mouseover focusin', $.proxy(this.rootOver, this)], 153 ['mouseout focusout', $.proxy(this.rootOut, this)], 154 ['keydown', $.proxy(this.rootKeyDown, this)] 155 ], eNS)) 156 .delegate('a', getEventsNS([ 157 ['mouseenter', $.proxy(this.itemEnter, this)], 158 ['mouseleave', $.proxy(this.itemLeave, this)], 159 ['mousedown', $.proxy(this.itemDown, this)], 160 ['focus', $.proxy(this.itemFocus, this)], 161 ['blur', $.proxy(this.itemBlur, this)], 162 ['click', $.proxy(this.itemClick, this)] 163 ], eNS)); 164 165 // hide menus on tap or click outside the root UL 166 eNS += this.rootId; 167 if (this.opts.hideOnClick) { 168 $(document).bind(getEventsNS([ 169 ['touchstart', $.proxy(this.docTouchStart, this)], 170 ['touchmove', $.proxy(this.docTouchMove, this)], 171 ['touchend', $.proxy(this.docTouchEnd, this)], 172 // for Opera Mobile < 11.5, webOS browser, etc. we'll check click too 173 ['click', $.proxy(this.docClick, this)] 174 ], eNS)); 175 } 176 // hide sub menus on resize 177 $(window).bind(getEventsNS([['resize orientationchange', $.proxy(this.winResize, this)]], eNS)); 178 179 if (this.opts.subIndicators) { 180 this.$subArrow = $('<span/>').addClass('sub-arrow'); 181 if (this.opts.subIndicatorsText) { 182 this.$subArrow.html(this.opts.subIndicatorsText); 183 } 184 } 185 186 // make sure mouse detection is enabled 187 initMouseDetection(); 188 } 189 190 // init sub menus 191 this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0); 192 193 this.$firstLink = this.$root.find('a').eq(0); 194 195 // find current item 196 if (this.opts.markCurrentItem) { 197 var reDefaultDoc = /(index|default)\.[^#\?\/]*/i, 198 reHash = /#.*/, 199 locHref = window.location.href.replace(reDefaultDoc, ''), 200 locHrefNoHash = locHref.replace(reHash, ''); 201 this.$root.find('a').each(function() { 202 var href = this.href.replace(reDefaultDoc, ''), 203 $this = $(this); 204 if (href == locHref || href == locHrefNoHash) { 205 $this.addClass('current'); 206 if (self.opts.markCurrentTree) { 207 $this.parentsUntil('[data-smartmenus-id]', 'ul').each(function() { 208 $(this).dataSM('parent-a').addClass('current'); 209 }); 210 } 211 } 212 }); 213 } 214 215 // save initial state 216 this.wasCollapsible = this.isCollapsible(); 217 }, 218 destroy: function(refresh) { 219 if (!refresh) { 220 var eNS = '.smartmenus'; 221 this.$root 222 .removeData('smartmenus') 223 .removeAttr('data-smartmenus-id') 224 .removeDataSM('level') 225 .unbind(eNS) 226 .undelegate(eNS); 227 eNS += this.rootId; 228 $(document).unbind(eNS); 229 $(window).unbind(eNS); 230 if (this.opts.subIndicators) { 231 this.$subArrow = null; 232 } 233 } 234 this.menuHideAll(); 235 var self = this; 236 this.$root.find('ul').each(function() { 237 var $this = $(this); 238 if ($this.dataSM('scroll-arrows')) { 239 $this.dataSM('scroll-arrows').remove(); 240 } 241 if ($this.dataSM('shown-before')) { 242 if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) { 243 $this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap'); 244 } 245 if ($this.dataSM('scroll-arrows')) { 246 $this.dataSM('scroll-arrows').remove(); 247 } 248 $this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' }); 249 } 250 if (($this.attr('id') || '').indexOf(self.accessIdPrefix) == 0) { 251 $this.removeAttr('id'); 252 } 253 }) 254 .removeDataSM('in-mega') 255 .removeDataSM('shown-before') 256 .removeDataSM('ie-shim') 257 .removeDataSM('scroll-arrows') 258 .removeDataSM('parent-a') 259 .removeDataSM('level') 260 .removeDataSM('beforefirstshowfired') 261 .removeAttr('role') 262 .removeAttr('aria-hidden') 263 .removeAttr('aria-labelledby') 264 .removeAttr('aria-expanded'); 265 this.$root.find('a.has-submenu').each(function() { 266 var $this = $(this); 267 if ($this.attr('id').indexOf(self.accessIdPrefix) == 0) { 268 $this.removeAttr('id'); 269 } 270 }) 271 .removeClass('has-submenu') 272 .removeDataSM('sub') 273 .removeAttr('aria-haspopup') 274 .removeAttr('aria-controls') 275 .removeAttr('aria-expanded') 276 .closest('li').removeDataSM('sub'); 277 if (this.opts.subIndicators) { 278 this.$root.find('span.sub-arrow').remove(); 279 } 280 if (this.opts.markCurrentItem) { 281 this.$root.find('a.current').removeClass('current'); 282 } 283 if (!refresh) { 284 this.$root = null; 285 this.$firstLink = null; 286 this.$firstSub = null; 287 if (this.$disableOverlay) { 288 this.$disableOverlay.remove(); 289 this.$disableOverlay = null; 290 } 291 menuTrees.splice($.inArray(this, menuTrees), 1); 292 } 293 }, 294 disable: function(noOverlay) { 295 if (!this.disabled) { 296 this.menuHideAll(); 297 // display overlay over the menu to prevent interaction 298 if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) { 299 var pos = this.$root.offset(); 300 this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({ 301 position: 'absolute', 302 top: pos.top, 303 left: pos.left, 304 width: this.$root.outerWidth(), 305 height: this.$root.outerHeight(),
306 zIndex: this.getStartZIndex(true), 307 opacity: 0 308 }).appendTo(document.body); 309 } 310 this.disabled = true; 311 } 312 }, 313 docClick: function(e) { 314 if (this.$touchScrollingSub) { 315 this.$touchScrollingSub = null; 316 return; 317 } 318 // hide on any click outside the menu or on a menu link 319 if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) { 320 this.menuHideAll(); 321 } 322 }, 323 docTouchEnd: function(e) { 324 if (!this.lastTouch) { 325 return; 326 } 327 if (this.visibleSubMenus.length && (this.lastTouch.x2 === undefined || this.lastTouch.x1 == this.lastTouch.x2) && (this.lastTouch.y2 === undefined || this.lastTouch.y1 == this.lastTouch.y2) && (!this.lastTouch.target || !$.contains(this.$root[0], this.lastTouch.target))) { 328 if (this.hideTimeout) { 329 clearTimeout(this.hideTimeout); 330 this.hideTimeout = 0; 331 } 332 // hide with a delay to prevent triggering accidental unwanted click on some page element 333 var self = this; 334 this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, 350); 335 } 336 this.lastTouch = null; 337 }, 338 docTouchMove: function(e) { 339 if (!this.lastTouch) { 340 return; 341 } 342 var touchPoint = e.originalEvent.touches[0]; 343 this.lastTouch.x2 = touchPoint.pageX; 344 this.lastTouch.y2 = touchPoint.pageY; 345 }, 346 docTouchStart: function(e) { 347 var touchPoint = e.originalEvent.touches[0]; 348 this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target }; 349 }, 350 enable: function() { 351 if (this.disabled) { 352 if (this.$disableOverlay) { 353 this.$disableOverlay.remove(); 354 this.$disableOverlay = null; 355 } 356 this.disabled = false; 357 } 358 }, 359 getClosestMenu: function(elm) { 360 var $closestMenu = $(elm).closest('ul'); 361 while ($closestMenu.dataSM('in-mega')) { 362 $closestMenu = $closestMenu.parent().closest('ul'); 363 } 364 return $closestMenu[0] || null; 365 }, 366 getHeight: function($elm) { 367 return this.getOffset($elm, true); 368 }, 369 // returns precise width/height float values 370 getOffset: function($elm, height) { 371 var old; 372 if ($elm.css('display') == 'none') { 373 old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility }; 374 $elm.css({ position: 'absolute', visibility: 'hidden' }).show(); 375 } 376 var box = $elm[0].getBoundingClientRect && $elm[0].getBoundingClientRect(), 377 val = box && (height ? box.height || box.bottom - box.top : box.width || box.right - box.left); 378 if (!val && val !== 0) { 379 val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth; 380 } 381 if (old) { 382 $elm.hide().css(old); 383 } 384 return val; 385 }, 386 getStartZIndex: function(root) { 387 var zIndex = parseInt(this[root ? '$root' : '$firstSub'].css('z-index')); 388 if (!root && isNaN(zIndex)) { 389 zIndex = parseInt(this.$root.css('z-index')); 390 } 391 return !isNaN(zIndex) ? zIndex : 1; 392 }, 393 getTouchPoint: function(e) { 394 return e.touches && e.touches[0] || e.changedTouches && e.changedTouches[0] || e; 395 }, 396 getViewport: function(height) { 397 var name = height ? 'Height' : 'Width', 398 val = document.documentElement['client' + name], 399 val2 = window['inner' + name]; 400 if (val2) { 401 val = Math.min(val, val2); 402 } 403 return val; 404 }, 405 getViewportHeight: function() { 406 return this.getViewport(true); 407 }, 408 getViewportWidth: function() { 409 return this.getViewport(); 410 }, 411 getWidth: function($elm) { 412 return this.getOffset($elm); 413 }, 414 handleEvents: function() { 415 return !this.disabled && this.isCSSOn(); 416 }, 417 handleItemEvents: function($a) { 418 return this.handleEvents() && !this.isLinkInMegaMenu($a); 419 }, 420 isCollapsible: function() { 421 return this.$firstSub.css('position') == 'static'; 422 }, 423 isCSSOn: function() { 424 return this.$firstLink.css('display') == 'block'; 425 }, 426 isFixed: function() { 427 var isFixed = this.$root.css('position') == 'fixed'; 428 if (!isFixed) { 429 this.$root.parentsUntil('body').each(function() { 430 if ($(this).css('position') == 'fixed') { 431 isFixed = true; 432 return false;
433 } 434 }); 435 } 436 return isFixed; 437 }, 438 isLinkInMegaMenu: function($a) { 439 return $(this.getClosestMenu($a[0])).hasClass('mega-menu'); 440 }, 441 isTouchMode: function() { 442 return !mouse || this.opts.noMouseOver || this.isCollapsible(); 443 }, 444 itemActivate: function($a, focus) { 445 var $ul = $a.closest('ul'), 446 level = $ul.dataSM('level'); 447 // if for some reason the parent item is not activated (e.g. this is an API call to activate the item), activate all parent items first 448 if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) { 449 var self = this; 450 $($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() { 451 self.itemActivate($(this).dataSM('parent-a')); 452 }); 453 } 454 // hide any visible deeper level sub menus 455 if (!this.isCollapsible() || focus) { 456 this.menuHideSubMenus(!this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level); 457 } 458 // save new active item for this level 459 this.activatedItems[level - 1] = $a; 460 if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) { 461 return; 462 } 463 // show the sub menu if this item has one 464 var $sub = $a.dataSM('sub'); 465 if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) { 466 this.menuShow($sub); 467 } 468 }, 469 itemBlur: function(e) { 470 var $a = $(e.currentTarget); 471 if (!this.handleItemEvents($a)) { 472 return; 473 } 474 this.$root.triggerHandler('blur.smapi', $a[0]); 475 }, 476 itemClick: function(e) { 477 var $a = $(e.currentTarget); 478 if (!this.handleItemEvents($a)) { 479 return; 480 } 481 if (this.$touchScrollingSub && this.$touchScrollingSub[0] == $a.closest('ul')[0]) { 482 this.$touchScrollingSub = null; 483 e.stopPropagation(); 484 return false; 485 } 486 if (this.$root.triggerHandler('click.smapi', $a[0]) === false) { 487 return false; 488 } 489 var subArrowClicked = $(e.target).is('span.sub-arrow'), 490 $sub = $a.dataSM('sub'), 491 firstLevelSub = $sub ? $sub.dataSM('level') == 2 : false; 492 // if the sub is not visible 493 if ($sub && !$sub.is(':visible')) { 494 if (this.opts.showOnClick && firstLevelSub) { 495 this.clickActivated = true; 496 } 497 // try to activate the item and show the sub 498 this.itemActivate($a); 499 // if "itemActivate" showed the sub, prevent the click so that the link is not loaded 500 // if it couldn't show it, then the sub menus are disabled with an !important declaration (e.g. via mobile styles) so let the link get loaded 501 if ($sub.is(':visible')) { 502 this.focusActivated = true; 503 return false; 504 } 505 } else if (this.isCollapsible() && subArrowClicked) { 506 this.itemActivate($a); 507 this.menuHide($sub); 508 return false; 509 } 510 if (this.opts.showOnClick && firstLevelSub || $a.hasClass('disabled') || this.$root.triggerHandler('select.smapi', $a[0]) === false) { 511 return false; 512 } 513 }, 514 itemDown: function(e) { 515 var $a = $(e.currentTarget); 516 if (!this.handleItemEvents($a)) { 517 return; 518 } 519 $a.dataSM('mousedown', true); 520 }, 521 itemEnter: function(e) { 522 var $a = $(e.currentTarget); 523 if (!this.handleItemEvents($a)) { 524 return; 525 } 526 if (!this.isTouchMode()) { 527 if (this.showTimeout) { 528 clearTimeout(this.showTimeout); 529 this.showTimeout = 0; 530 } 531 var self = this; 532 this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.closest('ul').dataSM('level') == 1 ? 1 : this.opts.showTimeout); 533 } 534 this.$root.triggerHandler('mouseenter.smapi', $a[0]); 535 }, 536 itemFocus: function(e) { 537 var $a = $(e.currentTarget); 538 if (!this.handleItemEvents($a)) { 539 return; 540 } 541 // fix (the mousedown check): in some browsers a tap/click produces consecutive focus + click events so we don't need to activate the item on focus 542 if (this.focusActivated && (!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) { 543 this.itemActivate($a, true); 544 } 545 this.$root.triggerHandler('focus.smapi', $a[0]); 546 }, 547 itemLeave: function(e) { 548 var $a = $(e.currentTarget); 549 if (!this.handleItemEvents($a)) { 550 return; 551 } 552 if (!this.isTouchMode()) { 553 $a[0].blur(); 554 if (this.showTimeout) { 555 clearTimeout(this.showTimeout); 556 this.showTimeout = 0; 557 } 558 } 559 $a.removeDataSM('mousedown');
560 this.$root.triggerHandler('mouseleave.smapi', $a[0]); 561 }, 562 menuHide: function($sub) { 563 if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) { 564 return; 565 } 566 $sub.stop(true, true); 567 if ($sub.css('display') != 'none') { 568 var complete = function() { 569 // unset z-index 570 $sub.css('z-index', ''); 571 }; 572 // if sub is collapsible (mobile view) 573 if (this.isCollapsible()) { 574 if (this.opts.collapsibleHideFunction) { 575 this.opts.collapsibleHideFunction.call(this, $sub, complete); 576 } else { 577 $sub.hide(this.opts.collapsibleHideDuration, complete); 578 } 579 } else { 580 if (this.opts.hideFunction) { 581 this.opts.hideFunction.call(this, $sub, complete); 582 } else { 583 $sub.hide(this.opts.hideDuration, complete); 584 } 585 } 586 // remove IE iframe shim 587 if ($sub.dataSM('ie-shim')) { 588 $sub.dataSM('ie-shim').remove().css({ '-webkit-transform': '', transform: '' }); 589 } 590 // deactivate scrolling if it is activated for this sub 591 if ($sub.dataSM('scroll')) { 592 this.menuScrollStop($sub); 593 $sub.css({ 'touch-action': '', '-ms-touch-action': '', '-webkit-transform': '', transform: '' }) 594 .unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide(); 595 } 596 // unhighlight parent item + accessibility 597 $sub.dataSM('parent-a').removeClass('highlighted').attr('aria-expanded', 'false'); 598 $sub.attr({ 599 'aria-expanded': 'false', 600 'aria-hidden': 'true' 601 }); 602 var level = $sub.dataSM('level'); 603 this.activatedItems.splice(level - 1, 1); 604 this.visibleSubMenus.splice($.inArray($sub, this.visibleSubMenus), 1); 605 this.$root.triggerHandler('hide.smapi', $sub[0]); 606 } 607 }, 608 menuHideAll: function() { 609 if (this.showTimeout) { 610 clearTimeout(this.showTimeout); 611 this.showTimeout = 0; 612 } 613 // hide all subs 614 // if it's a popup, this.visibleSubMenus[0] is the root UL 615 var level = this.opts.isPopup ? 1 : 0; 616 for (var i = this.visibleSubMenus.length - 1; i >= level; i--) { 617 this.menuHide(this.visibleSubMenus[i]); 618 } 619 // hide root if it's popup 620 if (this.opts.isPopup) { 621 this.$root.stop(true, true); 622 if (this.$root.is(':visible')) { 623 if (this.opts.hideFunction) { 624 this.opts.hideFunction.call(this, this.$root); 625 } else { 626 this.$root.hide(this.opts.hideDuration); 627 } 628 // remove IE iframe shim 629 if (this.$root.dataSM('ie-shim')) { 630 this.$root.dataSM('ie-shim').remove(); 631 } 632 } 633 } 634 this.activatedItems = []; 635 this.visibleSubMenus = []; 636 this.clickActivated = false; 637 this.focusActivated = false; 638 // reset z-index increment 639 this.zIndexInc = 0; 640 this.$root.triggerHandler('hideAll.smapi'); 641 }, 642 menuHideSubMenus: function(level) { 643 for (var i = this.activatedItems.length - 1; i >= level; i--) { 644 var $sub = this.activatedItems[i].dataSM('sub'); 645 if ($sub) { 646 this.menuHide($sub); 647 } 648 } 649 }, 650 menuIframeShim: function($ul) { 651 // create iframe shim for the menu 652 if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) { 653 $ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 }) 654 .css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' }) 655 ); 656 } 657 }, 658 menuInit: function($ul) { 659 if (!$ul.dataSM('in-mega')) { 660 // mark UL's in mega drop downs (if any) so we can neglect them 661 if ($ul.hasClass('mega-menu')) { 662 $ul.find('ul').dataSM('in-mega', true); 663 } 664 // get level (much faster than, for example, using parentsUntil) 665 var level = 2, 666 par = $ul[0]; 667 while ((par = par.parentNode.parentNode) != this.$root[0]) { 668 level++; 669 } 670 // cache stuff for quick access 671 var $a = $ul.prevAll('a').eq(-1); 672 // if the link is nested (e.g. in a heading) 673 if (!$a.length) { 674 $a = $ul.prevAll().find('a').eq(-1); 675 } 676 $a.addClass('has-submenu').dataSM('sub', $ul); 677 $ul.dataSM('parent-a', $a) 678 .dataSM('level', level) 679 .parent().dataSM('sub', $ul); 680 // accessibility 681 var aId = $a.attr('id') || this.accessIdPrefix + (++this.idInc), 682 ulId = $ul.attr('id') || this.accessIdPrefix + (++this.idInc); 683 $a.attr({ 684 id: aId, 685 'aria-haspopup': 'true', 686 'aria-controls': ulId, 687 'aria-expanded': 'false' 688 }); 689 $ul.attr({ 690 id: ulId, 691 'role': 'group', 692 'aria-hidden': 'true', 693 'aria-labelledby': aId, 694 'aria-expanded': 'false' 695 }); 696 // add sub indicator to parent item 697 if (this.opts.subIndicators) { 698 $a[this.opts.subIndicatorsPos](this.$subArrow.clone()); 699 } 700 } 701 }, 702 menuPosition: function($sub) { 703 var $a = $sub.dataSM('parent-a'), 704 $li = $a.closest('li'), 705 $ul = $li.parent(), 706 level = $sub.dataSM('level'), 707 subW = this.getWidth($sub), 708 subH = this.getHeight($sub), 709 itemOffset = $a.offset(), 710 itemX = itemOffset.left, 711 itemY = itemOffset.top, 712 itemW = this.getWidth($a), 713 itemH = this.getHeight($a), 714 $win = $(window), 715 winX = $win.scrollLeft(), 716 winY = $win.scrollTop(), 717 winW = this.getViewportWidth(),
718 winH = this.getViewportHeight(), 719 horizontalParent = $ul.parent().is('[data-sm-horizontal-sub]') || level == 2 && !$ul.hasClass('sm-vertical'), 720 rightToLeft = this.opts.rightToLeftSubMenus && !$li.is('[data-sm-reverse]') || !this.opts.rightToLeftSubMenus && $li.is('[data-sm-reverse]'), 721 subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX, 722 subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY, 723 x, y; 724 if (horizontalParent) { 725 x = rightToLeft ? itemW - subW - subOffsetX : subOffsetX; 726 y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY; 727 } else { 728 x = rightToLeft ? subOffsetX - subW : itemW - subOffsetX; 729 y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY; 730 } 731 if (this.opts.keepInViewport) { 732 var absX = itemX + x, 733 absY = itemY + y; 734 if (rightToLeft && absX < winX) { 735 x = horizontalParent ? winX - absX + x : itemW - subOffsetX; 736 } else if (!rightToLeft && absX + subW > winX + winW) { 737 x = horizontalParent ? winX + winW - subW - absX + x : subOffsetX - subW; 738 } 739 if (!horizontalParent) { 740 if (subH < winH && absY + subH > winY + winH) { 741 y += winY + winH - subH - absY; 742 } else if (subH >= winH || absY < winY) { 743 y += winY - absY; 744 } 745 } 746 // do we need scrolling? 747 // 0.49 used for better precision when dealing with float values 748 if (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49) { 749 var self = this; 750 if (!$sub.dataSM('scroll-arrows')) { 751 $sub.dataSM('scroll-arrows', $([$('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0], $('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]]) 752 .bind({ 753 mouseenter: function() { 754 $sub.dataSM('scroll').up = $(this).hasClass('scroll-up'); 755 self.menuScroll($sub); 756 }, 757 mouseleave: function(e) { 758 self.menuScrollStop($sub); 759 self.menuScrollOut($sub, e); 760 }, 761 'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); } 762 }) 763 .insertAfter($sub) 764 ); 765 } 766 // bind scroll events and save scroll data for this sub 767 var eNS = '.smartmenus_scroll'; 768 $sub.dataSM('scroll', { 769 y: this.cssTransforms3d ? 0 : y - itemH, 770 step: 1, 771 // cache stuff for faster recalcs later 772 itemH: itemH, 773 subH: subH, 774 arrowDownH: this.getHeight($sub.dataSM('scroll-arrows').eq(1)) 775 }) 776 .bind(getEventsNS([ 777 ['mouseover', function(e) { self.menuScrollOver($sub, e); }], 778 ['mouseout', function(e) { self.menuScrollOut($sub, e); }], 779 ['mousewheel DOMMouseScroll', function(e) { self.menuScrollMousewheel($sub, e); }] 780 ], eNS)) 781 .dataSM('scroll-arrows').css({ top: 'auto', left: '0', marginLeft: x + (parseInt($sub.css('border-left-width')) || 0), width: subW - (parseInt($sub.css('border-left-width')) || 0) - (parseInt($sub.css('border-right-width')) || 0), zIndex: $sub.css('z-index') }) 782 .eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show(); 783 // when a menu tree is fixed positioned we allow scrolling via touch too 784 // since there is no other way to access such long sub menus if no mouse is present 785 if (this.isFixed()) { 786 $sub.css({ 'touch-action': 'none', '-ms-touch-action': 'none' }) 787 .bind(getEventsNS([ 788 [touchEvents ? 'touchstart touchmove touchend' : 'pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp', function(e) { 789 self.menuScrollTouch($sub, e); 790 }] 791 ], eNS)); 792 } 793 } 794 } 795 $sub.css({ top: 'auto', left: '0', marginLeft: x, marginTop: y - itemH }); 796 // IE iframe shim 797 this.menuIframeShim($sub); 798 if ($sub.dataSM('ie-shim')) { 799 $sub.dataSM('ie-shim').css({ zIndex: $sub.css('z-index'), width: subW, height: subH, marginLeft: x, marginTop: y - itemH }); 800 } 801 }, 802 menuScroll: function($sub, once, step) { 803 var data = $sub.dataSM('scroll'), 804 $arrows = $sub.dataSM('scroll-arrows'), 805 end = data.up ? data.upEnd : data.downEnd, 806 diff; 807 if (!once && data.momentum) { 808 data.momentum *= 0.92; 809 diff = data.momentum; 810 if (diff < 0.5) { 811 this.menuScrollStop($sub); 812 return; 813 } 814 } else { 815 diff = step || (once || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor(data.step)); 816 } 817 // hide any visible deeper level sub menus 818 var level = $sub.dataSM('level'); 819 if (this.activatedItems[level - 1] && this.activatedItems[level - 1].dataSM('sub') && this.activatedItems[level - 1].dataSM('sub').is(':visible')) {
820 this.menuHideSubMenus(level - 1); 821 } 822 data.y = data.up && end <= data.y || !data.up && end >= data.y ? data.y : (Math.abs(end - data.y) > diff ? data.y + (data.up ? diff : -diff) : end); 823 $sub.add($sub.dataSM('ie-shim')).css(this.cssTransforms3d ? { '-webkit-transform': 'translate3d(0, ' + data.y + 'px, 0)', transform: 'translate3d(0, ' + data.y + 'px, 0)' } : { marginTop: data.y }); 824 // show opposite arrow if appropriate 825 if (mouse && (data.up && data.y > data.downEnd || !data.up && data.y < data.upEnd)) { 826 $arrows.eq(data.up ? 1 : 0).show(); 827 } 828 // if we've reached the end 829 if (data.y == end) { 830 if (mouse) { 831 $arrows.eq(data.up ? 0 : 1).hide(); 832 } 833 this.menuScrollStop($sub); 834 } else if (!once) { 835 if (this.opts.scrollAccelerate && data.step < this.opts.scrollStep) { 836 data.step += 0.2; 837 } 838 var self = this; 839 this.scrollTimeout = requestAnimationFrame(function() { self.menuScroll($sub); }); 840 } 841 }, 842 menuScrollMousewheel: function($sub, e) { 843 if (this.getClosestMenu(e.target) == $sub[0]) { 844 e = e.originalEvent; 845 var up = (e.wheelDelta || -e.detail) > 0; 846 if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) { 847 $sub.dataSM('scroll').up = up; 848 this.menuScroll($sub, true); 849 } 850 } 851 e.preventDefault(); 852 }, 853 menuScrollOut: function($sub, e) { 854 if (mouse) { 855 if (!/^scroll-(up|down)/.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || this.getClosestMenu(e.relatedTarget) != $sub[0])) { 856 $sub.dataSM('scroll-arrows').css('visibility', 'hidden'); 857 } 858 } 859 }, 860 menuScrollOver: function($sub, e) { 861 if (mouse) { 862 if (!/^scroll-(up|down)/.test(e.target.className) && this.getClosestMenu(e.target) == $sub[0]) { 863 this.menuScrollRefreshData($sub); 864 var data = $sub.dataSM('scroll'), 865 upEnd = $(window).scrollTop() - $sub.dataSM('parent-a').offset().top - data.itemH; 866 $sub.dataSM('scroll-arrows').eq(0).css('margin-top', upEnd).end() 867 .eq(1).css('margin-top', upEnd + this.getViewportHeight() - data.arrowDownH).end() 868 .css('visibility', 'visible'); 869 } 870 } 871 }, 872 menuScrollRefreshData: function($sub) { 873 var data = $sub.dataSM('scroll'), 874 upEnd = $(window).scrollTop() - $sub.dataSM('parent-a').offset().top - data.itemH; 875 if (this.cssTransforms3d) { 876 upEnd = -(parseFloat($sub.css('margin-top')) - upEnd); 877 } 878 $.extend(data, { 879 upEnd: upEnd, 880 downEnd: upEnd + this.getViewportHeight() - data.subH 881 }); 882 }, 883 menuScrollStop: function($sub) { 884 if (this.scrollTimeout) { 885 cancelAnimationFrame(this.scrollTimeout); 886 this.scrollTimeout = 0; 887 $sub.dataSM('scroll').step = 1; 888 return true; 889 } 890 }, 891 menuScrollTouch: function($sub, e) { 892 e = e.originalEvent; 893 if (isTouchEvent(e)) { 894 var touchPoint = this.getTouchPoint(e); 895 // neglect event if we touched a visible deeper level sub menu 896 if (this.getClosestMenu(touchPoint.target) == $sub[0]) { 897 var data = $sub.dataSM('scroll'); 898 if (/(start|down)$/i.test(e.type)) { 899 if (this.menuScrollStop($sub)) { 900 // if we were scrolling, just stop and don't activate any link on the first touch 901 e.preventDefault(); 902 this.$touchScrollingSub = $sub; 903 } else { 904 this.$touchScrollingSub = null; 905 } 906 // update scroll data since the user might have zoomed, etc. 907 this.menuScrollRefreshData($sub); 908 // extend it with the touch properties 909 $.extend(data, { 910 touchStartY: touchPoint.pageY, 911 touchStartTime: e.timeStamp 912 }); 913 } else if (/move$/i.test(e.type)) { 914 var prevY = data.touchY !== undefined ? data.touchY : data.touchStartY; 915 if (prevY !== undefined && prevY != touchPoint.pageY) { 916 this.$touchScrollingSub = $sub; 917 var up = prevY < touchPoint.pageY; 918 // changed direction? reset... 919 if (data.up !== undefined && data.up != up) { 920 $.extend(data, { 921 touchStartY: touchPoint.pageY, 922 touchStartTime: e.timeStamp 923 }); 924 } 925 $.extend(data, { 926 up: up, 927 touchY: touchPoint.pageY 928 }); 929 this.menuScroll($sub, true, Math.abs(touchPoint.pageY - prevY)); 930 } 931 e.preventDefault(); 932 } else { // touchend/pointerup 933 if (data.touchY !== undefined) { 934 if (data.momentum = Math.pow(Math.abs(touchPoint.pageY - data.touchStartY) / (e.timeStamp - data.touchStartTime), 2) * 15) { 935 this.menuScrollStop($sub); 936 this.menuScroll($sub); 937 e.preventDefault(); 938 } 939 delete data.touchY; 940 } 941 } 942 } 943 } 944 }, 945 menuShow: function($sub) { 946 if (!$sub.dataSM('beforefirstshowfired')) { 947 $sub.dataSM('beforefirstshowfired', true); 948 if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) { 949 return; 950 } 951 } 952 if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) { 953 return; 954 } 955 $sub.dataSM('shown-before', true) 956 .stop(true, true); 957 if (!$sub.is(':visible')) { 958 // highlight parent item 959 var $a = $sub.dataSM('parent-a'); 960 if (this.opts.keepHighlighted || this.isCollapsible()) { 961 $a.addClass('highlighted'); 962 } 963 if (this.isCollapsible()) { 964 $sub.removeClass('sm-nowrap').css({ zIndex: '', width: 'auto', minWidth: '', maxWidth: '', top: '', left: '', marginLeft: '', marginTop: '' }); 965 } else { 966 // set z-index 967 $sub.css('z-index', this.zIndexInc = (this.zIndexInc || this.get
967StartZIndex()) + 1); 968 // min/max-width fix - no way to rely purely on CSS as all UL's are nested 969 if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) { 970 $sub.css({ width: 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 971 if (this.opts.subMenusMinWidth) { 972 $sub.css('min-width', this.opts.subMenusMinWidth); 973 } 974 if (this.opts.subMenusMaxWidth) { 975 var noMaxWidth = this.getWidth($sub); 976 $sub.css('max-width', this.opts.subMenusMaxWidth); 977 if (noMaxWidth > this.getWidth($sub)) { 978 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 979 } 980 } 981 } 982 this.menuPosition($sub); 983 // insert IE iframe shim 984 if ($sub.dataSM('ie-shim')) { 985 $sub.dataSM('ie-shim').insertBefore($sub); 986 } 987 } 988 var complete = function() { 989 // fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used 990 $sub.css('overflow', ''); 991 }; 992 // if sub is collapsible (mobile view) 993 if (this.isCollapsible()) { 994 if (this.opts.collapsibleShowFunction) { 995 this.opts.collapsibleShowFunction.call(this, $sub, complete); 996 } else { 997 $sub.show(this.opts.collapsibleShowDuration, complete); 998 } 999 } else { 1000 if (this.opts.showFunction) { 1001 this.opts.showFunction.call(this, $sub, complete); 1002 } else { 1003 $sub.show(this.opts.showDuration, complete); 1004 } 1005 } 1006 // accessibility 1007 $a.attr('aria-expanded', 'true'); 1008 $sub.attr({ 1009 'aria-expanded': 'true', 1010 'aria-hidden': 'false' 1011 }); 1012 // store sub menu in visible array 1013 this.visibleSubMenus.push($sub); 1014 this.$root.triggerHandler('show.smapi', $sub[0]); 1015 } 1016 }, 1017 popupHide: function(noHideTimeout) { 1018 if (this.hideTimeout) { 1019 clearTimeout(this.hideTimeout); 1020 this.hideTimeout = 0; 1021 } 1022 var self = this; 1023 this.hideTimeout = setTimeout(function() { 1024 self.menuHideAll(); 1025 }, noHideTimeout ? 1 : this.opts.hideTimeout); 1026 }, 1027 popupShow: function(left, top) { 1028 if (!this.opts.isPopup) { 1029 alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'); 1030 return; 1031 } 1032 if (this.hideTimeout) { 1033 clearTimeout(this.hideTimeout); 1034 this.hideTimeout = 0; 1035 } 1036 this.$root.dataSM('shown-before', true) 1037 .stop(true, true); 1038 if (!this.$root.is(':visible')) { 1039 this.$root.css({ left: left, top: top }); 1040 // IE iframe shim 1041 this.menuIframeShim(this.$root); 1042 if (this.$root.dataSM('ie-shim')) { 1043 this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left: left, top: top }).insertBefore(this.$root); 1044 } 1045 // show menu 1046 var self = this, 1047 complete = function() { 1048 self.$root.css('overflow', ''); 1049 }; 1050 if (this.opts.showFunction) { 1051 this.opts.showFunction.call(this, this.$root, complete); 1052 } else { 1053 this.$root.show(this.opts.showDuration, complete); 1054 } 1055 this.visibleSubMenus[0] = this.$root; 1056 } 1057 }, 1058 refresh: function() { 1059 this.destroy(true); 1060 this.init(true); 1061 }, 1062 rootKeyDown: function(e) { 1063 if (!this.handleEvents()) { 1064 return; 1065 } 1066 switch (e.keyCode) { 1067 case 27: // reset on Esc 1068 var $activeTopItem = this.activatedItems[0]; 1069 if ($activeTopItem) { 1070 this.menuHideAll(); 1071 $activeTopItem[0].focus(); 1072 var $sub = $activeTopItem.dataSM('sub'); 1073 if ($sub) { 1074 this.menuHide($sub); 1075 } 1076 } 1077 break; 1078 case 32: // activate item's sub on Space 1079 var $target = $(e.target); 1080 if ($target.is('a') && this.handleItemEvents($target)) { 1081 var $sub = $target.dataSM('sub'); 1082 if ($sub && !$sub.is(':visible')) { 1083 this.itemClick({ currentTarget: e.target }); 1084 e.preventDefault(); 1085 } 1086 } 1087 break; 1088 } 1089 }, 1090 rootOut: function(e) { 1091 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 1092 return; 1093 } 1094 if (this.hideTimeout) { 1095 clearTimeout(this.hideTimeout); 1096 this.hideTimeout = 0; 1097 } 1098 if (!this.opts.showOnClick || !this.opts.hideOnClick) { 1099 var self = this; 1100 this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout); 1101 } 1102 }, 1103 rootOver: function(e) { 1104 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 1105 return; 1106 } 1107 if (this.hideTimeout) { 1108 clearTimeout(this.hideTimeout); 1109 this.hideTimeout = 0; 1110 } 1111 }, 1112 winResize: function(e) { 1113 if (!this.handleEvents()) { 1114 // we still need to resize the disable overlay if it's visible 1115 if (this.$disableOverlay) { 1116 var pos = this.$root.offset(); 1117 this.$disableOverlay.css({ 1118 top: pos.top, 1119 left: pos.left, 1120 width: this.$root.outerWidth(), 1121 height: this.$root.outerHeight() 1122 }); 1123 } 1124 return; 1125 } 1126 // hide sub menus on resize - on mobile do it only on orientation change 1127 if (!('onorientationchange' in window) || e.type == 'orientationchange') { 1128 var isCollapsible = this.isCollapsible(); 1129 // if it was collapsible before resize and still is, don't do it 1130 if (!(this.wasCollapsible && isCollapsible)) { 1131 if (this.activatedItems.length) { 1132 this.activatedItems[this.activatedItems.length - 1][0].blur(); 1133 } 1134 this.menuHideAll(); 1135 } 1136 this.wasCollapsible = isCollapsible; 1137 } 1138 } 1139 } 1140 }); 1141 1142 $.fn.dataSM = function(key, val) { 1143 if (val) { 1144 return this.data(key + '_smartmenus', val); 1145 } 1146 return this.data(key + '_smartmenus'); 1147 } 1148 1149 $.fn.removeDataSM = function(key) { 1150 return this.removeData(key + '_smartmenus'); 1151 } 1152 1153 $.fn.smartmenus = function(options) { 1154 if (typeof options == 'string') { 1155 var args = arguments, 1156 method = options; 1157 Array.prototype.shift.call(args); 1158 return this.each(function() { 1159 var smartmenus = $(this).data('smartmenus'); 1160 if (smartmenus && smartmenus[method]) { 1161 smartmenus[method].apply(smartmenus, args); 1162 } 1163 }); 1164 } 1165 var opts = $.extend({}, $.fn.smartmenus.defaults, options); 1166 return this.each(function() { 1167 new $.SmartMenus(this, opts); 1168 }); 1169 } 1170 1171 // default settings 1172 $.fn.smartmenus.defaults = { 1173 isPopup: false, // is this a popup menu (can be shown via the popupS
1173how/popupHide methods) or a permanent menu bar 1174 mainMenuSubOffsetX: 0, // pixels offset from default position 1175 mainMenuSubOffsetY: 0, // pixels offset from default position 1176 subMenusSubOffsetX: 0, // pixels offset from default position 1177 subMenusSubOffsetY: 0, // pixels offset from default position 1178 subMenusMinWidth: '10em', // min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 1179 subMenusMaxWidth: '20em', // max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 1180 subIndicators: true, // create sub menu indicators - creates a SPAN and inserts it in the A 1181 subIndicatorsPos: 'prepend', // position of the SPAN relative to the menu item content ('prepend', 'append') 1182 subIndicatorsText: '+', // [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too) 1183 scrollStep: 30, // pixels step when scrolling long sub menus that do not fit in the viewport height 1184 scrollAccelerate: true, // accelerate scrolling or use a fixed step 1185 showTimeout: 250, // timeout before showing the sub menus 1186 hideTimeout: 500, // timeout before hiding the sub menus 1187 showDuration: 0, // duration for show animation - set to 0 for no animation - matters only if showFunction:null 1188 showFunction: null, // custom function to use when showing a sub menu (the default is the jQuery 'show') 1189 // don't forget to call complete() at the end of whatever you do 1190 // e.g.: function($ul, complete) { $ul.fadeIn(250, complete); } 1191 hideDuration: 0, // duration for hide animation - set to 0 for no animation - matters only if hideFunction:null 1192 hideFunction: function($ul, complete) { $ul.fadeOut(200, complete); }, // custom function to use when hiding a sub menu (the default is the jQuery 'hide') 1193 // don't forget to call complete() at the end of whatever you do 1194 // e.g.: function($ul, complete) { $ul.fadeOut(250, complete); } 1195 collapsibleShowDuration:0, // duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null 1196 collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); }, // custom function to use when showing a collapsible sub menu 1197 // (i.e. when mobile styles are used to make the sub menus collapsible) 1198 collapsibleHideDuration:0, // duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null 1199 collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); }, // custom function to use when hiding a collapsible sub menu 1200 // (i.e. when mobile styles are used to make the sub menus collapsible) 1201 showOnClick: false, // show the first-level sub menus onclick instead of onmouseover (i.e. mimic desktop app menus) (matters only for mouse input) 1202 hideOnClick: true, // hide the sub menus on click/tap anywhere on the page 1203 noMouseOver: false, // disable sub menus activation onmouseover (i.e. behave like in touch mode - use just mouse clicks) (matters only for mouse input) 1204 keepInViewport: true, // reposition the sub menus if needed to make sure they always appear inside the viewport 1205 keepHighlighted: true, // keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's) 1206 markCurrentItem: false, // automatically add the 'current' class to the A element of the item linking to the current URL 1207 markCurrentTree: true, // add the 'current' class also to the A elements of all ancestor items of the current item 1208 rightToLeftSubMenus: false, // right to left display of the sub menus (check the CSS for the sub indicators' position) 1209 bottomToTopSubMenus: false, // bottom to top display of the sub menus 1210 overlapControlsInIE: true // make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.) 1211 }; 1212 1213 return $; 1214}));; 1215/*! 1216 * SmartMenus jQuery Plugin Bootstrap Addon - v0.3.0 - January 27, 2016 1217 * http://www.smartmenus.org/ 1218 * 1219 * Copyright Vasil Dinkov, Vadikom Web Ltd. 1220 * http://vadikom.com 1221 * 1222 * Licensed MIT 1223 */ 1224 1225(function(factory) { 1226 if (typeof define === 'function' && define.amd) { 1227 // AMD 1228 define(['jquery', 'jquery.smartmenus'], factory); 1229 } else if (typeof module === 'object' && typeof module.exports === 'object') { 1230 // CommonJS 1231 module.exports = factory(require('jquery')); 1232 } else { 1233 // Global jQuery 1234 factory(jQuery); 1235 } 1236} (function($) { 1237 1238 $.extend($.SmartMenus.Bootstrap = {}, { 1239 keydownFix: false, 1240 init: function() { 1241 // init all navbars that don't have the "data-sm-skip" attribute set
1242 var $navbars = $('ul.navbar-nav:not([data-sm-skip])'); 1243 $navbars.each(function() { 1244 var $this = $(this), 1245 obj = $this.data('smartmenus'); 1246 // if this navbar is not initialized 1247 if (!obj) { 1248 $this.smartmenus({ 1249 1250 // these are some good default options that should work for all 1251 // you can, of course, tweak these as you like 1252 subMenusSubOffsetX: 2, 1253 subMenusSubOffsetY: -6, 1254 subIndicators: false, 1255 collapsibleShowFunction: null, 1256 collapsibleHideFunction: null, 1257 rightToLeftSubMenus: $this.hasClass('navbar-right'), 1258 bottomToTopSubMenus: $this.closest('.navbar').hasClass('navbar-fixed-bottom') 1259 }) 1260 .bind({ 1261 // set/unset proper Bootstrap classes for some menu elements 1262 'show.smapi': function(e, menu) { 1263 var $menu = $(menu), 1264 $scrollArrows = $menu.dataSM('scroll-arrows'); 1265 if ($scrollArrows) { 1266 // they inherit border-color from body, so we can use its background-color too 1267 $scrollArrows.css('background-color', $(document.body).css('background-color')); 1268 } 1269 $menu.parent().addClass('open'); 1270 }, 1271 'hide.smapi': function(e, menu) { 1272 $(menu).parent().removeClass('open'); 1273 } 1274 }); 1275 1276 function onInit() { 1277 // set Bootstrap's "active" class to SmartMenus "current" items (should someone decide to enable markCurrentItem: true) 1278 $this.find('a.current').parent().addClass('active'); 1279 // remove any Bootstrap required attributes that might cause conflicting issues with the SmartMenus script 1280 $this.find('a.has-submenu').each(function() { 1281 var $this = $(this); 1282 if ($this.is('[data-toggle="dropdown"]')) { 1283 $this.dataSM('bs-data-toggle-dropdown', true).removeAttr('data-toggle'); 1284 } 1285 if ($this.is('[role="button"]')) { 1286 $this.dataSM('bs-role-button', true).removeAttr('role'); 1287 } 1288 }); 1289 } 1290 1291 onInit(); 1292 1293 function onBeforeDestroy() { 1294 $this.find('a.current').parent().removeClass('active'); 1295 $this.find('a.has-submenu').each(function() { 1296 var $this = $(this); 1297 if ($this.dataSM('bs-data-toggle-dropdown')) { 1298 $this.attr('data-toggle', 'dropdown').removeDataSM('bs-data-toggle-dropdown'); 1299 } 1300 if ($this.dataSM('bs-role-button')) { 1301 $this.attr('role', 'button').removeDataSM('bs-role-button'); 1302 } 1303 }); 1304 } 1305 1306 obj = $this.data('smartmenus'); 1307 1308 // custom "isCollapsible" method for Bootstrap 1309 obj.isCollapsible = function() { 1310 return !/^(left|right)$/.test(this.$firstLink.parent().css('float')); 1311 }; 1312 1313 // custom "refresh" method for Bootstrap 1314 obj.refresh = function() { 1315 $.SmartMenus.prototype.refresh.call(this); 1316 onInit(); 1317 // update collapsible detection 1318 detectCollapsible(true); 1319 } 1320 1321 // custom "destroy" method for Bootstrap 1322 obj.destroy = function(refresh) { 1323 onBeforeDestroy(); 1324 $.SmartMenus.prototype.destroy.call(this, refresh); 1325 } 1326 1327 // keep Bootstrap's default behavior for parent items when the "data-sm-skip-collapsible-behavior" attribute is set to the ul.navbar-nav 1328 // i.e. use the whole item area just as a sub menu toggle and don't customize the carets 1329 if ($this.is('[data-sm-skip-collapsible-behavior]')) { 1330 $this.bind({ 1331 // click the parent item to toggle the sub menus (and reset deeper levels and other branches on click) 1332 'click.smapi': function(e, item) { 1333 if (obj.isCollapsible()) { 1334 var $item = $(item), 1335 $sub = $item.parent().dataSM('sub'); 1336 if ($sub && $sub.dataSM('shown-before') && $sub.is(':visible')) { 1337 obj.itemActivate($item); 1338 obj.menuHide($sub); 1339 return false; 1340 } 1341 } 1342 } 1343 }); 1344 } 1345 1346 // onresize detect when the navbar becomes collapsible and add it the "sm-collapsible" class 1347 var winW; 1348 function detectCollapsible(force) { 1349 var newW = obj.getViewportWidth(); 1350 if (newW != winW || force) { 1351 var $carets = $this.find('.caret'); 1352 if (obj.isCollapsible()) { 1353 $this.addClass('sm-collapsible'); 1354 // set "navbar-toggle" class to carets (so they look like a button) if the "data-sm-skip-collapsible-behavior" attribute is not set to the ul.navbar-nav 1355 if (!$this.is('[data-sm-skip-collapsible-behavior]')) { 1356 $carets.addClass('navbar-toggle sub-arrow'); 1357 } 1358 } else { 1359 $this.removeClass('sm-collapsible'); 1360 if (!$this.is('[data-sm-skip-collapsible-behavior]')) { 1361 $carets.removeClass('navbar-toggle sub-arrow'); 1362 } 1363 } 1364 winW = newW; 1365 } 1366 }; 1367 detectCollapsible(); 1368 $(window).bind('resize.smartmenus' + obj.rootId, detectCollapsible); 1369 } 1370 }); 1371 // keydown fix for Bootstrap 3.3.5+ conflict 1372 if ($navbars.length && !$.SmartMenus.Bootstrap.keydownFix) { 1373 // unhook BS keydown handler for all dropdowns 1374 $(document).off('keydown.bs.dropdown.data-api', '.dropdown-menu'); 1375 // restore BS keydown handler for dropdowns that are not inside SmartMenus navbars 1376 if ($.fn.dropdown && $.fn.dropdown.Constructor) { 1377 $(document).on('keydown.bs.dropdown.data-api', '.dropdown-menu:not([id^="sm-"])', $.fn.dropdown.Constructor.prototype.keydown); 1378 } 1379 $.SmartMenus.Bootstrap.keydownFix = true; 1380 } 1381 } 1382 }); 1383 1384 // init ondomready 1385 $($.SmartMenus.Bootstrap.init); 1386 1387 return $; 1388}));; 1389/* ======================================================================== 1390 * Bootstrap: affix.js v3.3.5 1391 * http://getbootstrap.com/javascript/#affix 1392 * ======================================================================== 1393 * Copyright 2011-2015 Twitter, Inc. 1394 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1395 * ======================================================================== */ 1396 1397 1398+function ($) { 1399 'use strict'; 1400 1401 // AFFIX CLASS DEFINITION 1402 // ====================== 1403 1404 var Affix = function (element, options) { 1405 this.options = $.extend({}, Affix.DEFAULTS, options) 1406 1407 this.$target = $(this.options.target) 1408 .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 1409 .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 1410 1411 this.$element = $(element) 1412 this.affixed = null 1413 this.unpin = null 1414 this.pinnedOffset = null 1415 1416 this.checkPosition() 1417 } 1418 1419 Affix.VERSION = '3.3.5' 1420 1421 Affix.RESET = 'affix affix-top affix-bottom' 1422 1423 Affix.DEFAULTS = { 1424 offset: 0, 1425 target: window 1426 } 1427 1428 Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { 1429 var scrollTop = this.$target.scrollTop() 1430 var position = this.$element.offset() 1431 var targetHeight = this.$target.height() 1432 1433 if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false 1434 1435 if (this.affixed == 'bottom') { 1436 if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' 1437 return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' 1438 } 1439 1440 var initializing = this.affixed == null 1441 var colliderTop = initializing ? scrollTop : position.top 1442 var colliderHeight = initializing ? targetHeight : height 1443 1444 if (offsetTop != null && scrollTop <= offsetTop) return 'top' 1445 if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' 1446 1447 return false 1448 } 1449 1450 Affix.prototype.getPinnedOffset = function () { 1451 if (this.pinnedOffset) return this.pinnedOffset 1452 this.$element.removeClass(Affix.RESET).addClass('affix') 1453 var scrollTop = this.$target.scrollTop() 1454 var position = this.$element.offset() 1455 return (this.pinnedOffset = position.top - scrollTop) 1456 } 1457 1458 Affix.prototype.checkPositionWithEventLoop = function () { 1459 setTimeout($.proxy(this.checkPosition, this), 1) 1460 } 1461 1462 Affix.prototype.checkPosition = function () { 1463 if (!this.$element.is(':visible')) return 1464 1465 var height = this.$element.height() 1466 var offset = this.options.offset 1467 var offsetTop = offset.top 1468 var offsetBottom = offset.bottom 1469 var scrollHeight = Math.max($(document).height(), $(document.body).height()) 1470 1471 if (typeof offset != 'object') offsetBottom = offsetTop = offset 1472 if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) 1473 if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) 1474
vendor: 35,367 bytes, lines 1475-2721
1475 var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) 1476 1477 if (this.affixed != affix) { 1478 if (this.unpin != null) this.$element.css('top', '') 1479 1480 var affixType = 'affix' + (affix ? '-' + affix : '') 1481 var e = $.Event(affixType + '.bs.affix') 1482 1483 this.$element.trigger(e) 1484 1485 if (e.isDefaultPrevented()) return 1486 1487 this.affixed = affix 1488 this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null 1489 1490 this.$element 1491 .removeClass(Affix.RESET) 1492 .addClass(affixType) 1493 .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') 1494 } 1495 1496 if (affix == 'bottom') { 1497 this.$element.offset({ 1498 top: scrollHeight - height - offsetBottom 1499 }) 1500 } 1501 } 1502 1503 1504 // AFFIX PLUGIN DEFINITION 1505 // ======================= 1506 1507 function Plugin(option) { 1508 return this.each(function () { 1509 var $this = $(this) 1510 var data = $this.data('bs.affix') 1511 var options = typeof option == 'object' && option 1512 1513 if (!data) $this.data('bs.affix', (data = new Affix(this, options))) 1514 if (typeof option == 'string') data[option]() 1515 }) 1516 } 1517 1518 var old = $.fn.affix 1519 1520 $.fn.affix = Plugin 1521 $.fn.affix.Constructor = Affix 1522 1523 1524 // AFFIX NO CONFLICT 1525 // ================= 1526 1527 $.fn.affix.noConflict = function () { 1528 $.fn.affix = old 1529 return this 1530 } 1531 1532 1533 // AFFIX DATA-API 1534 // ============== 1535 1536 $(window).on('load', function () { 1537 $('[data-spy="affix"]').each(function () { 1538 var $spy = $(this) 1539 var data = $spy.data() 1540 1541 data.offset = data.offset || {} 1542 1543 if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom 1544 if (data.offsetTop != null) data.offset.top = data.offsetTop 1545 1546 Plugin.call($spy, data) 1547 }) 1548 }) 1549 1550}(jQuery); 1551; 1552/* ======================================================================== 1553 * Bootstrap: alert.js v3.3.5 1554 * http://getbootstrap.com/javascript/#alerts 1555 * ======================================================================== 1556 * Copyright 2011-2015 Twitter, Inc. 1557 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1558 * ======================================================================== */ 1559 1560 1561+function ($) { 1562 'use strict'; 1563 1564 // ALERT CLASS DEFINITION 1565 // ====================== 1566 1567 var dismiss = '[data-dismiss="alert"]' 1568 var Alert = function (el) { 1569 $(el).on('click', dismiss, this.close) 1570 } 1571 1572 Alert.VERSION = '3.3.5' 1573 1574 Alert.TRANSITION_DURATION = 150 1575 1576 Alert.prototype.close = function (e) { 1577 var $this = $(this) 1578 var selector = $this.attr('data-target') 1579 1580 if (!selector) { 1581 selector = $this.attr('href') 1582 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 1583 } 1584 1585 var $parent = $(selector) 1586 1587 if (e) e.preventDefault() 1588 1589 if (!$parent.length) { 1590 $parent = $this.closest('.alert') 1591 } 1592 1593 $parent.trigger(e = $.Event('close.bs.alert')) 1594 1595 if (e.isDefaultPrevented()) return 1596 1597 $parent.removeClass('in') 1598 1599 function removeElement() { 1600 // detach from parent, fire event then clean up data 1601 $parent.detach().trigger('closed.bs.alert').remove() 1602 } 1603 1604 $.support.transition && $parent.hasClass('fade') ? 1605 $parent 1606 .one('bsTransitionEnd', removeElement) 1607 .emulateTransitionEnd(Alert.TRANSITION_DURATION) : 1608 removeElement() 1609 } 1610 1611 1612 // ALERT PLUGIN DEFINITION 1613 // ======================= 1614 1615 function Plugin(option) { 1616 return this.each(function () { 1617 var $this = $(this) 1618 var data = $this.data('bs.alert') 1619 1620 if (!data) $this.data('bs.alert', (data = new Alert(this))) 1621 if (typeof option == 'string') data[option].call($this) 1622 }) 1623 } 1624 1625 var old = $.fn.alert 1626 1627 $.fn.alert = Plugin 1628 $.fn.alert.Constructor = Alert 1629 1630 1631 // ALERT NO CONFLICT 1632 // ================= 1633 1634 $.fn.alert.noConflict = function () { 1635 $.fn.alert = old 1636 return this 1637 } 1638 1639 1640 // ALERT DATA-API 1641 // ============== 1642 1643 $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 1644 1645}(jQuery); 1646; 1647/* ======================================================================== 1648 * Bootstrap: button.js v3.3.5 1649 * http://getbootstrap.com/javascript/#buttons 1650 * ======================================================================== 1651 * Copyright 2011-2015 Twitter, Inc. 1652 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1653 * ======================================================================== */ 1654 1655 1656+function ($) { 1657 'use strict'; 1658 1659 // BUTTON PUBLIC CLASS DEFINITION 1660 // ============================== 1661 1662 var Button = function (element, options) { 1663 this.$element = $(element) 1664 this.options = $.extend({}, Button.DEFAULTS, options) 1665 this.isLoading = false 1666 } 1667 1668 Button.VERSION = '3.3.5' 1669 1670 Button.DEFAULTS = { 1671 loadingText: 'loading...' 1672 } 1673 1674 Button.prototype.setState = function (state) { 1675 var d = 'disabled' 1676 var $el = this.$element 1677 var val = $el.is('input') ? 'val' : 'html' 1678 var data = $el.data() 1679 1680 state += 'Text' 1681 1682 if (data.resetText == null) $el.data('resetText', $el[val]()) 1683 1684 // push to event loop to allow forms to submit 1685 setTimeout($.proxy(function () { 1686 $el[val](data[state] == null ? this.options[state] : data[state]) 1687 1688 if (state == 'loadingText') { 1689 this.isLoading = true 1690 $el.addClass(d).attr(d, d) 1691 } else if (this.isLoading) { 1692 this.isLoading = false 1693 $el.removeClass(d).removeAttr(d) 1694 } 1695 }, this), 0) 1696 } 1697 1698 Button.prototype.toggle = function () { 1699 var changed = true 1700 var $parent = this.$element.closest('[data-toggle="buttons"]') 1701 1702 if ($parent.length) { 1703 var $input = this.$element.find('input') 1704 if ($input.prop('type') == 'radio') { 1705 if ($input.prop('checked')) changed = false 1706 $parent.find('.active').removeClass('active') 1707 this.$element.addClass('active') 1708 } else if ($input.prop('type') == 'checkbox') { 1709 if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false 1710 this.$element.toggleClass('active') 1711 } 1712 $input.prop('checked', this.$element.hasClass('active')) 1713 if (changed) $input.trigger('change') 1714 } else { 1715 this.$element.attr('aria-pressed', !this.$element.hasClass('active')) 1716 this.$element.toggleClass('active') 1717 } 1718 } 1719 1720 1721 // BUTTON PLUGIN DEFINITION 1722 // ======================== 1723 1724 function Plugin(option) { 1725 return this.each(function () { 1726 var $this = $(this) 1727 var data = $this.data('bs.button') 1728 var options = typeof option == 'object' && option 1729 1730 if (!data) $this.data('bs.button', (data = new Button(this, options))) 1731 1732 if (option == 'toggle') data.toggle() 1733 else if (option) data.setState(option) 1734 }) 1735 } 1736 1737 var old = $.fn.button 1738 1739 $.fn.button = Plugin 1740 $.fn.button.Constructor = Button 1741 1742 1743 // BUTTON NO CONFLICT 1744 // ================== 1745 1746 $.fn.button.noConflict = function () { 1747 $.fn.button = old 1748 return this 1749 } 1750 1751 1752 // BUTTON DATA-API 1753 // =============== 1754 1755 $(document) 1756 .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 1757 var $btn = $(e.target) 1758 if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 1759 Plugin.call($btn, 'toggle') 1760 if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault() 1761 }) 1762 .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { 1763 $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) 1764 }) 1765 1766}(jQuery); 1767; 1768/* ======================================================================== 1769 * Bootstrap: carousel.js v3.3.5 1770 * http://getbootstrap.com/javascript/#carousel 1771 * ======================================================================== 1772 * Copyright 2011-2015 Twitter, Inc. 1773 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1774 * ======================================================================== */ 1775 1776 1777+function ($) { 1778 'use strict'; 1779 1780 // CAROUSEL CLASS DEFINITION 1781 // ========================= 1782 1783 var Carousel = function (element, options) { 1784 this.$element = $(element) 1785 this.$indicators = this.$element.find('.carousel-indicators') 1786 this.options = options 1787 this.paused = null 1788 this.sliding = null 1789 this.interval = null 1790 this.$active = null 1791 this.$items = null 1792 1793 this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) 1794 1795 this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element 1796 .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) 1797 .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) 1798 } 1799 1800 Carousel.VERSION = '3.3.5' 1801 1802 Carousel.TRANSITION_DURATION = 600 1803 1804 Carousel.DEFAULTS = { 1805 interval: 5000, 1806 pause: 'hover', 1807 wrap: true, 1808 keyboard: true 1809 } 1810 1811 Carousel.prototype.keydown = function (e) { 1812 if (/input|textarea/i.test(e.target.tagName)) return 1813 switch (e.which) { 1814 case 37: this.prev(); break 1815 case 39: this.next(); break 1816 default: return 1817 } 1818 1819 e.preventDefault() 1820 } 1821 1822 Carousel.prototype.cycle = function (e) { 1823 e || (this.paused = false) 1824 1825 this.interval && clearInterval(this.interval) 1826 1827 this.options.interval 1828 && !this.paused 1829 && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 1830 1831 return this 1832 } 1833 1834 Carousel.prototype.getItemIndex = function (item) { 1835 this.$items = item.parent().children('.item') 1836 return this.$items.index(item || this.$active) 1837 } 1838 1839 Carousel.prototype.getItemForDirection = function (direction, active) { 1840 var activeIndex = this.getItemIndex(active) 1841 var willWrap = (direction == 'prev' && activeIndex === 0) 1842 || (direction == 'next' && activeIndex == (this.$items.length - 1)) 1843 if (willWrap && !this.options.wrap) return active 1844 var delta = direction == 'prev' ? -1 : 1 1845 var itemIndex = (activeIndex + delta) % this.$items.length 1846 return this.$items.eq(itemIndex) 1847 } 1848 1849 Carousel.prototype.to = function (pos) { 1850 var that = this 1851 var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) 1852 1853 if (pos > (this.$items.length - 1) || pos < 0) return 1854 1855 if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" 1856 if (activeIndex == pos) return this.pause().cycle() 1857 1858 return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) 1859 } 1860 1861 Carousel.prototype.pause = function (e) { 1862 e || (this.paused = true) 1863 1864 if (this.$element.find('.next, .prev').length && $.support.transition) { 1865 this.$element.trigger($.support.transition.end) 1866 this.cycle(true) 1867 } 1868 1869 this.interval = clearInterval(this.interval) 1870 1871 return this 1872 } 1873 1874 Carousel.prototype.next = function () { 1875 if (this.sliding) return 1876 return this.slide('next') 1877 } 1878 1879 Carousel.prototype.prev = function () { 1880 if (this.sliding) return 1881 return this.slide('prev') 1882 } 1883 1884 Carousel.prototype.slide = function (type, next) { 1885 var $active = this.$element.find('.item.active') 1886 var $next = next || this.getItemForDirection(type, $active) 1887 var isCycling = this.interval 1888 var direction = type == 'next' ? 'left' : 'right' 1889 var that = this 1890 1891 if ($next.hasClass('active')) return (this.sliding = false) 1892 1893 var relatedTarget = $next[0] 1894 var slideEvent = $.Event('slide.bs.carousel', { 1895 relatedTarget: relatedTarget, 1896 direction: direction 1897 }) 1898 this.$element.trigger(slideEvent) 1899 if (slideEvent.isDefaultPrevented()) return 1900 1901 this.sliding = true 1902 1903 isCycling && this.pause() 1904 1905 if (this.$indicators.length) { 1906 this.$indicators.find('.active').removeClass('active') 1907 var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) 1908 $nextIndicator && $nextIndicator.addClass('active') 1909 } 1910 1911 var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" 1912 if ($.support.transition && this.$element.hasClass('slide')) { 1913 $next.addClass(type) 1914 $next[0].offsetWidth // force reflow 1915 $active.addClass(direction) 1916 $next.addClass(direction) 1917 $active 1918 .one('bsTransitionEnd', function () { 1919 $next.removeClass([type, direction].join(' ')).addClass('active') 1920 $active.removeClass(['active', direction].join(' ')) 1921 that.sliding = false 1922 setTimeout(function () { 1923 that.$element.trigger(slidEvent) 1924 }, 0) 1925 }) 1926 .emulateTransitionEnd(Carousel.TRANSITION_DURATION) 1927 } else { 1928 $active.removeClass('active') 1929 $next.addClass('active') 1930 this.sliding = false 1931 this.$element.trigger(slidEvent) 1932 } 1933 1934 isCycling && this.cycle() 1935 1936 return this 1937 } 1938 1939 1940 // CAROUSEL PLUGIN DEFINITION 1941 // ========================== 1942 1943 function Plugin(option) { 1944 return this.each(function () { 1945 var $this = $(this) 1946 var data = $this.data('bs.carousel') 1947 var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 1948 var action = typeof option == 'string' ? option : options.slide 1949 1950 if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 1951 if (typeof option == 'number') data.to(option) 1952 else if (action) data[action]() 1953 else if (options.interval) data.pause().cycle() 1954 }) 1955 } 1956 1957 var old = $.fn.carousel 1958 1959 $.fn.carousel = Plugin 1960 $.fn.carousel.Constructor = Carousel 1961 1962 1963 // CAROUSEL NO CONFLICT 1964 // ==================== 1965 1966 $.fn.carousel.noConflict = function () { 1967 $.fn.carousel = old 1968 return this 1969 } 1970 1971 1972 // CAROUSEL DATA-API 1973 // ================= 1974 1975 var clickHandler = function (e) { 1976 var href 1977 var $this = $(this) 1978 var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 1979 if (!$target.hasClass('carousel')) return 1980 var options = $.extend({}, $target.data(), $this.data()) 1981 var slideIndex = $this.attr('data-slide-to') 1982 if (slideIndex) options.interval = false 1983 1984 Plugin.call($target, options) 1985 1986 if (slideIndex) { 1987 $target.data('bs.carousel').to(slideIndex) 1988 } 1989 1990 e.preventDefault() 1991 } 1992 1993 $(document) 1994 .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) 1995 .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) 1996 1997 $(window).on('load', function () { 1998 $('[data-ride="carousel"]').each(function () { 1999 var $carousel = $(this) 2000 Plugin.call($carousel, $carousel.data()) 2001 }) 2002 }) 2003 2004}(jQuery); 2005; 2006/* ======================================================================== 2007 * Bootstrap: collapse.js v3.3.5 2008 * http://getbootstrap.com/javascript/#collapse 2009 * ======================================================================== 2010 * Copyright 2011-2015 Twitter, Inc. 2011 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2012 * ======================================================================== */ 2013 2014 2015+function ($) { 2016 'use strict'; 2017 2018 // COLLAPSE PUBLIC CLASS DEFINITION 2019 // ================================ 2020 2021 var Collapse = function (element, options) { 2022 this.$element = $(element) 2023 this.options = $.extend({}, Collapse.DEFAULTS, options) 2024 this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + 2025 '[data-toggle="collapse"][data-target="#' + element.id + '"]') 2026 this.transitioning = null 2027 2028 if (this.options.parent) { 2029 this.$parent = this.getParent() 2030 } else { 2031 this.addAriaAndCollapsedClass(this.$element, this.$trigger) 2032 } 2033 2034 if (this.options.toggle) this.toggle() 2035 } 2036 2037 Collapse.VERSION = '3.3.5' 2038 2039 Collapse.TRANSITION_DURATION = 350 2040 2041 Collapse.DEFAULTS = { 2042 toggle: true 2043 } 2044 2045 Collapse.prototype.dimension = function () { 2046 var hasWidth = this.$element.hasClass('width') 2047 return hasWidth ? 'width' : 'height' 2048 } 2049 2050 Collapse.prototype.show = function () { 2051 if (this.transitioning || this.$element.hasClass('in')) return 2052 2053 var activesData 2054 var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') 2055 2056 if (actives && actives.length) { 2057 activesData = actives.data('bs.collapse') 2058 if (activesData && activesData.transitioning) return 2059 } 2060 2061 var startEvent = $.Event('show.bs.collapse') 2062 this.$element.trigger(startEvent) 2063 if (startEvent.isDefaultPrevented()) return 2064 2065 if (actives && actives.length) { 2066 Plugin.call(actives, 'hide') 2067 activesData || actives.data('bs.collapse', null) 2068 } 2069 2070 var dimension = this.dimension() 2071 2072 this.$element 2073 .removeClass('collapse') 2074 .addClass('collapsing')[dimension](0) 2075 .attr('aria-expanded', true) 2076 2077 this.$trigger 2078 .removeClass('collapsed') 2079 .attr('aria-expanded', true) 2080 2081 this.transitioning = 1 2082 2083 var complete = function () { 2084 this.$element 2085 .removeClass('collapsing') 2086 .addClass('collapse in')[dimension]('') 2087 this.transitioning = 0 2088 this.$element 2089 .trigger('shown.bs.collapse') 2090 } 2091 2092 if (!$.support.transition) return complete.call(this) 2093 2094 var scrollSize = $.camelCase(['scroll', dimension].join('-')) 2095 2096 this.$element 2097 .one('bsTransitionEnd', $.proxy(complete, this)) 2098 .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) 2099 } 2100 2101 Collapse.prototype.hide = function () { 2102 if (this.transitioning || !this.$element.hasClass('in')) return 2103 2104 var startEvent = $.Event('hide.bs.collapse') 2105 this.$element.trigger(startEvent) 2106 if (startEvent.isDefaultPrevented()) return 2107 2108 var dimension = this.dimension() 2109 2110 this.$element[dimension](this.$element[dimension]())[0].offsetHeight 2111 2112 this.$element 2113 .addClass('collapsing') 2114 .removeClass('collapse in') 2115 .attr('aria-expanded', false) 2116 2117 this.$trigger 2118 .addClass('collapsed') 2119 .attr('aria-expanded', false) 2120 2121 this.transitioning = 1 2122 2123 var complete = function () { 2124 this.transitioning = 0 2125 this.$element 2126 .removeClass('collapsing') 2127 .addClass('collapse') 2128 .trigger('hidden.bs.collapse') 2129 } 2130 2131 if (!$.support.transition) return complete.call(this) 2132 2133 this.$element 2134 [dimension](0) 2135 .one('bsTransitionEnd', $.proxy(complete, this)) 2136 .emulateTransitionEnd(Collapse.TRANSITION_DURATION) 2137 } 2138 2139 Collapse.prototype.toggle = function () { 2140 this[this.$element.hasClass('in') ? 'hide' : 'show']() 2141 } 2142 2143 Collapse.prototype.getParent = function () { 2144 return $(this.options.parent) 2145 .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') 2146 .each($.proxy(function (i, element) { 2147 var $element = $(element) 2148 this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) 2149 }, this)) 2150 .end() 2151 } 2152 2153 Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { 2154 var isOpen = $element.hasClass('in') 2155 2156 $element.attr('aria-expanded', isOpen) 2157 $trigger 2158 .toggleClass('collapsed', !isOpen) 2159 .attr('aria-expanded', isOpen) 2160 } 2161 2162 function getTargetFromTrigger($trigger) { 2163 var href 2164 var target = $trigger.attr('data-target') 2165 || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 2166 2167 return $(target) 2168 } 2169 2170 2171 // COLLAPSE PLUGIN DEFINITION 2172 // ========================== 2173 2174 function Plugin(option) { 2175 return this.each(function () { 2176 var $this = $(this) 2177 var data = $this.data('bs.collapse') 2178 var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 2179 2180 if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false 2181 if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 2182 if (typeof option == 'string') data[option]() 2183 }) 2184 } 2185 2186 var old = $.fn.collapse 2187 2188 $.fn.collapse = Plugin 2189 $.fn.collapse.Constructor = Collapse 2190 2191 2192 // COLLAPSE NO CONFLICT 2193 // ==================== 2194 2195 $.fn.collapse.noConflict = function () { 2196 $.fn.collapse = old 2197 return this 2198 } 2199 2200 2201 // COLLAPSE DATA-API 2202 // ================= 2203 2204 $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 2205 var $this = $(this) 2206 2207 if (!$this.attr('data-target')) e.preventDefault() 2208 2209 var $target = getTargetFromTrigger($this) 2210 var data = $target.data('bs.collapse') 2211 var option = data ? 'toggle' : $this.data() 2212 2213 Plugin.call($target, option) 2214 }) 2215 2216}(jQuery); 2217; 2218/* ======================================================================== 2219 * Bootstrap: dropdown.js v3.3.5 2220 * http://getbootstrap.com/javascript/#dropdowns 2221 * ======================================================================== 2222 * Copyright 2011-2015 Twitter, Inc. 2223 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2224 * ======================================================================== */ 2225 2226 2227+function ($) { 2228 'use strict'; 2229 2230 // DROPDOWN CLASS DEFINITION 2231 // ========================= 2232 2233 var backdrop = '.dropdown-backdrop' 2234 var toggle = '[data-toggle="dropdown"]' 2235 var Dropdown = function (element) { 2236 $(element).on('click.bs.dropdown', this.toggle) 2237 } 2238 2239 Dropdown.VERSION = '3.3.5' 2240 2241 function getParent($this) { 2242 var selector = $this.attr('data-target') 2243 2244 if (!selector) { 2245 selector = $this.attr('href') 2246 selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 2247 } 2248 2249 var $parent = selector && $(selector) 2250 2251 return $parent && $parent.length ? $parent : $this.parent() 2252 } 2253 2254 function clearMenus(e) { 2255 if (e && e.which === 3) return 2256 $(backdrop).remove() 2257 $(toggle).each(function () { 2258 var $this = $(this) 2259 var $parent = getParent($this) 2260 var relatedTarget = { relatedTarget: this } 2261 2262 if (!$parent.hasClass('open')) return 2263 2264 if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return 2265 2266 $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) 2267 2268 if (e.isDefaultPrevented()) return 2269 2270 $this.attr('aria-expanded', 'false') 2271 $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget) 2272 }) 2273 } 2274 2275 Dropdown.prototype.toggle = function (e) { 2276 var $this = $(this) 2277 2278 if ($this.is('.disabled, :disabled')) return 2279 2280 var $parent = getParent($this) 2281 var isActive = $parent.hasClass('open') 2282 2283 clearMenus() 2284 2285 if (!isActive) { 2286 if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 2287 // if mobile we use a backdrop because click events don't delegate 2288 $(document.createElement('div')) 2289 .addClass('dropdown-backdrop') 2290 .insertAfter($(this)) 2291 .on('click', clearMenus) 2292 } 2293 2294 var relatedTarget = { relatedTarget: this } 2295 $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) 2296 2297 if (e.isDefaultPrevented()) return 2298 2299 $this 2300 .trigger('focus') 2301 .attr('aria-expanded', 'true') 2302 2303 $parent 2304 .toggleClass('open') 2305 .trigger('shown.bs.dropdown', relatedTarget) 2306 } 2307 2308 return false 2309 } 2310 2311 Dropdown.prototype.keydown = function (e) { 2312 if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return 2313 2314 var $this = $(this) 2315 2316 e.preventDefault() 2317 e.stopPropagation() 2318 2319 if ($this.is('.disabled, :disabled')) return 2320 2321 var $parent = getParent($this) 2322 var isActive = $parent.hasClass('open') 2323 2324 if (!isActive && e.which != 27 || isActive && e.which == 27) { 2325 if (e.which == 27) $parent.find(toggle).trigger('focus') 2326 return $this.trigger('click') 2327 } 2328 2329 var desc = ' li:not(.disabled):visible a' 2330 var $items = $parent.find('.dropdown-menu' + desc) 2331 2332 if (!$items.length) return 2333 2334 var index = $items.index(e.target) 2335 2336 if (e.which == 38 && index > 0) index-- // up 2337 if (e.which == 40 && index < $items.length - 1) index++ // down 2338 if (!~index) index = 0 2339 2340 $items.eq(index).trigger('focus') 2341 } 2342 2343 2344 // DROPDOWN PLUGIN DEFINITION 2345 // ========================== 2346 2347 function Plugin(option) { 2348 return this.each(function () { 2349 var $this = $(this) 2350 var data = $this.data('bs.dropdown') 2351 2352 if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) 2353 if (typeof option == 'string') data[option].call($this) 2354 }) 2355 } 2356 2357 var old = $.fn.dropdown 2358 2359 $.fn.dropdown = Plugin 2360 $.fn.dropdown.Constructor = Dropdown 2361 2362 2363 // DROPDOWN NO CONFLICT 2364 // ==================== 2365 2366 $.fn.dropdown.noConflict = function () { 2367 $.fn.dropdown = old 2368 return this 2369 } 2370 2371 2372 // APPLY TO STANDARD DROPDOWN ELEMENTS 2373 // =================================== 2374 2375 $(document) 2376 .on('click.bs.dropdown.data-api', clearMenus) 2377 .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) 2378 .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) 2379 .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) 2380 .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown) 2381 2382}(jQuery); 2383; 2384/* ======================================================================== 2385 * Bootstrap: modal.js v3.3.5 2386 * http://getbootstrap.com/javascript/#modals 2387 * ======================================================================== 2388 * Copyright 2011-2015 Twitter, Inc. 2389 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2390 * ======================================================================== */ 2391 2392 2393+function ($) { 2394 'use strict'; 2395 2396 // MODAL CLASS DEFINITION 2397 // ====================== 2398 2399 var Modal = function (element, options) { 2400 this.options = options 2401 this.$body = $(document.body) 2402 this.$element = $(element) 2403 this.$dialog = this.$element.find('.modal-dialog') 2404 this.$backdrop = null 2405 this.isShown = null 2406 this.originalBodyPad = null 2407 this.scrollbarWidth = 0 2408 this.ignoreBackdropClick = false 2409 2410 if (this.options.remote) { 2411 this.$element 2412 .find('.modal-content') 2413 .load(this.options.remote, $.proxy(function () { 2414 this.$element.trigger('loaded.bs.modal') 2415 }, this)) 2416 } 2417 } 2418 2419 Modal.VERSION = '3.3.5' 2420 2421 Modal.TRANSITION_DURATION = 300 2422 Modal.BACKDROP_TRANSITION_DURATION = 150 2423 2424 Modal.DEFAULTS = { 2425 backdrop: true, 2426 keyboard: true, 2427 show: true 2428 } 2429 2430 Modal.prototype.toggle = function (_relatedTarget) { 2431 return this.isShown ? this.hide() : this.show(_relatedTarget) 2432 } 2433 2434 Modal.prototype.show = function (_relatedTarget) { 2435 var that = this 2436 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) 2437 2438 this.$element.trigger(e) 2439 2440 if (this.isShown || e.isDefaultPrevented()) return 2441 2442 this.isShown = true 2443 2444 this.checkScrollbar() 2445 this.setScrollbar() 2446 this.$body.addClass('modal-open') 2447 2448 this.escape() 2449 this.resize() 2450 2451 this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) 2452 2453 this.$dialog.on('mousedown.dismiss.bs.modal', function () { 2454 that.$element.one('mouseup.dismiss.bs.modal', function (e) { 2455 if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true 2456 }) 2457 }) 2458 2459 this.backdrop(function () { 2460 var transition = $.support.transition && that.$element.hasClass('fade') 2461 2462 if (!that.$element.parent().length) { 2463 that.$element.appendTo(that.$body) // don't move modals dom position 2464 } 2465 2466 that.$element 2467 .show() 2468 .scrollTop(0) 2469 2470 that.adjustDialog() 2471 2472 if (transition) { 2473 that.$element[0].offsetWidth // force reflow 2474 } 2475 2476 that.$element.addClass('in') 2477 2478 that.enforceFocus() 2479 2480 var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) 2481 2482 transition ? 2483 that.$dialog // wait for modal to slide in 2484 .one('bsTransitionEnd', function () { 2485 that.$element.trigger('focus').trigger(e) 2486 }) 2487 .emulateTransitionEnd(Modal.TRANSITION_DURATION) : 2488 that.$element.trigger('focus').trigger(e) 2489 }) 2490 } 2491 2492 Modal.prototype.hide = function (e) { 2493 if (e) e.preventDefault() 2494 2495 e = $.Event('hide.bs.modal') 2496 2497 this.$element.trigger(e) 2498 2499 if (!this.isShown || e.isDefaultPrevented()) return 2500 2501 this.isShown = false 2502 2503 this.escape() 2504 this.resize() 2505 2506 $(document).off('focusin.bs.modal') 2507 2508 this.$element 2509 .removeClass('in') 2510 .off('click.dismiss.bs.modal') 2511 .off('mouseup.dismiss.bs.modal') 2512 2513 this.$dialog.off('mousedown.dismiss.bs.modal') 2514 2515 $.support.transition && this.$element.hasClass('fade') ? 2516 this.$element 2517 .one('bsTransitionEnd', $.proxy(this.hideModal, this)) 2518 .emulateTransitionEnd(Modal.TRANSITION_DURATION) : 2519 this.hideModal() 2520 } 2521 2522 Modal.prototype.enforceFocus = function () { 2523 $(document) 2524 .off('focusin.bs.modal') // guard against infinite focus loop 2525 .on('focusin.bs.modal', $.proxy(function (e) { 2526 if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { 2527 this.$element.trigger('focus') 2528 } 2529 }, this)) 2530 } 2531 2532 Modal.prototype.escape = function () { 2533 if (this.isShown && this.options.keyboard) { 2534 this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { 2535 e.which == 27 && this.hide() 2536 }, this)) 2537 } else if (!this.isShown) { 2538 this.$element.off('keydown.dismiss.bs.modal') 2539 } 2540 } 2541 2542 Modal.prototype.resize = function () { 2543 if (this.isShown) { 2544 $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) 2545 } else { 2546 $(window).off('resize.bs.modal') 2547 } 2548 } 2549 2550 Modal.prototype.hideModal = function () { 2551 var that = this 2552 this.$element.hide() 2553 this.backdrop(function () { 2554 that.$body.removeClass('modal-open') 2555 that.resetAdjustments() 2556 that.resetScrollbar() 2557 that.$element.trigger('hidden.bs.modal') 2558 }) 2559 } 2560 2561 Modal.prototype.removeBackdrop = function () { 2562 this.$backdrop && this.$backdrop.remove() 2563 this.$backdrop = null 2564 } 2565 2566 Modal.prototype.backdrop = function (callback) { 2567 var that = this 2568 var animate = this.$element.hasClass('fade') ? 'fade' : '' 2569 2570 if (this.isShown && this.options.backdrop) { 2571 var doAnimate = $.support.transition && animate 2572 2573 this.$backdrop = $(document.createElement('div')) 2574 .addClass('modal-backdrop ' + animate) 2575 .appendTo(this.$body) 2576 2577 this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { 2578 if (this.ignoreBackdropClick) { 2579 this.ignoreBackdropClick = false 2580 return 2581 } 2582 if (e.target !== e.currentTarget) return 2583 this.options.backdrop == 'static' 2584 ? this.$element[0].focus() 2585 : this.hide() 2586 }, this)) 2587 2588 if (doAnimate) this.$backdrop[0].offsetWidth // force reflow 2589 2590 this.$backdrop.addClass('in') 2591 2592 if (!callback) return 2593 2594 doAnimate ? 2595 this.$backdrop 2596 .one('bsTransitionEnd', callback) 2597 .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : 2598 callback() 2599 2600 } else if (!this.isShown && this.$backdrop) { 2601 this.$backdrop.removeClass('in') 2602 2603 var callbackRemove = function () { 2604 that.removeBackdrop() 2605 callback && callback() 2606 } 2607 $.support.transition && this.$element.hasClass('fade') ? 2608 this.$backdrop 2609 .one('bsTransitionEnd', callbackRemove) 2610 .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : 2611 callbackRemove() 2612 2613 } else if (callback) { 2614 callback() 2615 } 2616 } 2617 2618 // these following methods are used to handle overflowing modals 2619 2620 Modal.prototype.handleUpdate = function () { 2621 this.adjustDialog() 2622 } 2623 2624 Modal.prototype.adjustDialog = function () { 2625 var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight 2626 2627 this.$element.css({ 2628 paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', 2629 paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' 2630 }) 2631 } 2632 2633 Modal.prototype.resetAdjustments = function () { 2634 this.$element.css({ 2635 paddingLeft: '', 2636 paddingRight: '' 2637 }) 2638 } 2639 2640 Modal.prototype.checkScrollbar = function () { 2641 var fullWindowWidth = window.innerWidth 2642 if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 2643 var documentElementRect = document.documentElement.getBoundingClientRect() 2644 fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) 2645 } 2646 this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth 2647 this.scrollbarWidth = this.measureScrollbar() 2648 } 2649 2650 Modal.prototype.setScrollbar = function () { 2651 var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) 2652 this.originalBodyPad = document.body.style.paddingRight || '' 2653 if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) 2654 } 2655 2656 Modal.prototype.resetScrollbar = function () { 2657 this.$body.css('padding-right', this.originalBodyPad) 2658 } 2659 2660 Modal.prototype.measureScrollbar = function () { // thx walsh 2661 var scrollDiv = document.createElement('div') 2662 scrollDiv.className = 'modal-scrollbar-measure' 2663 this.$body.append(scrollDiv) 2664 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth 2665 this.$body[0].removeChild(scrollDiv) 2666 return scrollbarWidth 2667 } 2668 2669 2670 // MODAL PLUGIN DEFINITION 2671 // ======================= 2672 2673 function Plugin(option, _relatedTarget) { 2674 return this.each(function () { 2675 var $this = $(this) 2676 var data = $this.data('bs.modal') 2677 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) 2678 2679 if (!data) $this.data('bs.modal', (data = new Modal(this, options))) 2680 if (typeof option == 'string') data[option](_relatedTarget) 2681 else if (options.show) data.show(_relatedTarget) 2682 }) 2683 } 2684 2685 var old = $.fn.modal 2686 2687 $.fn.modal = Plugin 2688 $.fn.modal.Constructor = Modal 2689 2690 2691 // MODAL NO CONFLICT 2692 // ================= 2693 2694 $.fn.modal.noConflict = function () { 2695 $.fn.modal = old 2696 return this 2697 } 2698 2699 2700 // MODAL DATA-API 2701 // ============== 2702 2703 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { 2704 var $this = $(this) 2705 var href = $this.attr('href') 2706 var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 2707 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) 2708 2709 if ($this.is('a')) e.preventDefault() 2710 2711 $target.one('show.bs.modal', function (showEvent) { 2712 if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown 2713 $target.one('hidden.bs.modal', function () { 2714 $this.is(':visible') && $this.trigger('focus') 2715 }) 2716 }) 2717 Plugin.call($target, option, this) 2718 }) 2719 2720}(jQuery); 2721;
vendor: 16,346 bytes, lines 2721-3235
2721 2722/* ======================================================================== 2723 * Bootstrap: tooltip.js v3.3.5 2724 * http://getbootstrap.com/javascript/#tooltip 2725 * Inspired by the original jQuery.tipsy by Jason Frame 2726 * ======================================================================== 2727 * Copyright 2011-2015 Twitter, Inc. 2728 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2729 * ======================================================================== */ 2730 2731 2732+function ($) { 2733 'use strict'; 2734 2735 // TOOLTIP PUBLIC CLASS DEFINITION 2736 // =============================== 2737 2738 var Tooltip = function (element, options) { 2739 this.type = null 2740 this.options = null 2741 this.enabled = null 2742 this.timeout = null 2743 this.hoverState = null 2744 this.$element = null 2745 this.inState = null 2746 2747 this.init('tooltip', element, options) 2748 } 2749 2750 Tooltip.VERSION = '3.3.5' 2751 2752 Tooltip.TRANSITION_DURATION = 150 2753 2754 Tooltip.DEFAULTS = { 2755 animation: true, 2756 placement: 'top', 2757 selector: false, 2758 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 2759 trigger: 'hover focus', 2760 title: '', 2761 delay: 0, 2762 html: false, 2763 container: false, 2764 viewport: { 2765 selector: 'body', 2766 padding: 0 2767 } 2768 } 2769 2770 Tooltip.prototype.init = function (type, element, options) { 2771 this.enabled = true 2772 this.type = type 2773 this.$element = $(element) 2774 this.options = this.getOptions(options) 2775 this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) 2776 this.inState = { click: false, hover: false, focus: false } 2777 2778 if (this.$element[0] instanceof document.constructor && !this.options.selector) { 2779 throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!') 2780 } 2781 2782 var triggers = this.options.trigger.split(' ') 2783 2784 for (var i = triggers.length; i--;) { 2785 var trigger = triggers[i] 2786 2787 if (trigger == 'click') { 2788 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 2789 } else if (trigger != 'manual') { 2790 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 2791 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 2792 2793 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 2794 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 2795 } 2796 } 2797 2798 this.options.selector ? 2799 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 2800 this.fixTitle() 2801 } 2802 2803 Tooltip.prototype.getDefaults = function () { 2804 return Tooltip.DEFAULTS 2805 } 2806 2807 Tooltip.prototype.getOptions = function (options) { 2808 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 2809 2810 if (options.delay && typeof options.delay == 'number') { 2811 options.delay = { 2812 show: options.delay, 2813 hide: options.delay 2814 } 2815 } 2816 2817 return options 2818 } 2819 2820 Tooltip.prototype.getDelegateOptions = function () { 2821 var options = {} 2822 var defaults = this.getDefaults() 2823 2824 this._options && $.each(this._options, function (key, value) { 2825 if (defaults[key] != value) options[key] = value 2826 }) 2827 2828 return options 2829 } 2830 2831 Tooltip.prototype.enter = function (obj) { 2832 var self = obj instanceof this.constructor ? 2833 obj : $(obj.currentTarget).data('bs.' + this.type) 2834 2835 if (!self) { 2836 self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 2837 $(obj.currentTarget).data('bs.' + this.type, self) 2838 } 2839 2840 if (obj instanceof $.Event) { 2841 self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true 2842 } 2843 2844 if (self.tip().hasClass('in') || self.hoverState == 'in') { 2845 self.hoverState = 'in' 2846 return 2847 } 2848 2849 clearTimeout(self.timeout) 2850 2851 self.hoverState = 'in' 2852 2853 if (!self.options.delay || !self.options.delay.show) return self.show() 2854 2855 self.timeout = setTimeout(function () { 2856 if (self.hoverState == 'in') self.show() 2857 }, self.options.delay.show) 2858 } 2859 2860 Tooltip.prototype.isInStateTrue = function () { 2861 for (var key in this.inState) { 2862 if (this.inState[key]) return true 2863 } 2864 2865 return false 2866 } 2867 2868 Tooltip.prototype.leave = function (obj) { 2869 var self = obj instanceof this.constructor ? 2870 obj : $(obj.currentTarget).data('bs.' + this.type) 2871 2872 if (!self) { 2873 self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 2874 $(obj.currentTarget).data('bs.' + this.type, self) 2875 } 2876 2877 if (obj instanceof $.Event) { 2878 self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false 2879 } 2880 2881 if (self.isInStateTrue()) return 2882 2883 clearTimeout(self.timeout) 2884 2885 self.hoverState = 'out' 2886 2887 if (!self.options.delay || !self.options.delay.hide) return self.hide() 2888 2889 self.timeout = setTimeout(function () { 2890 if (self.hoverState == 'out') self.hide() 2891 }, self.options.delay.hide) 2892 } 2893 2894 Tooltip.prototype.show = function () { 2895 var e = $.Event('show.bs.' + this.type) 2896 2897 if (this.hasContent() && this.enabled) { 2898 this.$element.trigger(e) 2899 2900 var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) 2901 if (e.isDefaultPrevented() || !inDom) return 2902 var that = this 2903 2904 var $tip = this.tip() 2905 2906 var tipId = this.getUID(this.type) 2907 2908 this.setContent() 2909 $tip.attr('id', tipId) 2910 this.$element.attr('aria-describedby', tipId) 2911 2912 if (this.options.animation) $tip.addClass('fade') 2913 2914 var placement = typeof this.options.placement == 'function' ? 2915 this.options.placement.call(this, $tip[0], this.$element[0]) : 2916 this.options.placement 2917 2918 var autoToken = /\s?auto?\s?/i 2919 var autoPlace = autoToken.test(placement) 2920 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 2921 2922 $tip 2923 .detach() 2924 .css({ top: 0, left: 0, display: 'block' }) 2925 .addClass(placement) 2926 .data('bs.' + this.type, this) 2927 2928 this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) 2929 this.$element.trigger('inserted.bs.' + this.type) 2930 2931 var pos = this.getPosition() 2932 var actualWidth = $tip[0].offsetWidth 2933 var actualHeight = $tip[0].offsetHeight 2934 2935 if (autoPlace) { 2936 var orgPlacement = placement 2937 var viewportDim = this.getPosition(this.$viewport) 2938 2939 placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' : 2940 placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' : 2941 placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' : 2942 placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' : 2943 placement 2944 2945 $tip 2946 .removeClass(orgPlacement) 2947 .addClass(placement) 2948 } 2949 2950 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 2951 2952 this.applyPlacement(calculatedOffset, placement) 2953 2954 var complete = function () { 2955 var prevHoverState = that.hoverState 2956 that.$element.trigger('shown.bs.' + that.type) 2957 that.hoverState = null 2958 2959 if (prevHoverState == 'out') that.leave(that) 2960 } 2961 2962 $.support.transition && this.$tip.hasClass('fade') ? 2963 $tip 2964 .one('bsTransitionEnd', complete) 2965 .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 2966 complete() 2967 } 2968 } 2969 2970 Tooltip.prototype.applyPlacement = function (offset, placement) { 2971 var $tip = this.tip() 2972 var width = $tip[0].offsetWidth 2973 var height = $tip[0].offsetHeight 2974 2975 // manually read margins because getBoundingClientRect includes difference 2976 var marginTop = parseInt($tip.css('margin-top'), 10) 2977 var marginLeft = parseInt($tip.css('margin-left'), 10) 2978 2979 // we must check for NaN for ie 8/9 2980 if (isNaN(marginTop)) marginTop = 0 2981 if (isNaN(marginLeft)) marginLeft = 0 2982 2983 offset.top += marginTop 2984 offset.left += marginLeft 2985 2986 // $.fn.offset doesn't round pixel values 2987 // so we use setOffset directly with our own function B-0 2988 $.offset.setOffset($tip[0], $.extend({ 2989 using: function (props) { 2990 $tip.css({ 2991 top: Math.round(props.top), 2992 left: Math.round(props.left) 2993 }) 2994 } 2995 }, offset), 0) 2996 2997 $tip.addClass('in') 2998 2999 // check to see if placing tip in new offset caused the tip to resize itself 3000 var actualWidth = $tip[0].offsetWidth 3001 var actualHeight = $tip[0].offsetHeight 3002 3003 if (placement == 'top' && actualHeight != height) { 3004 offset.top = offset.top + height - actualHeight 3005 } 3006 3007 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 3008 3009 if (delta.left) offset.left += delta.left 3010 else offset.top += delta.top 3011 3012 var isVertical = /top|bottom/.test(placement) 3013 var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 3014 var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' 3015 3016 $tip.offset(offset) 3017 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) 3018 } 3019 3020 Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) { 3021 this.arrow() 3022 .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') 3023 .css(isVertical ? 'top' : 'left', '') 3024 } 3025 3026 Tooltip.prototype.setContent = function () { 3027 var $tip = this.tip() 3028 var title = this.getTitle() 3029 3030 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 3031 $tip.removeClass('fade in top bottom left right') 3032 } 3033 3034 Tooltip.prototype.hide = function (callback) { 3035 var that = this 3036 var $tip = $(this.$tip) 3037 var e = $.Event('hide.bs.' + this.type) 3038 3039 function complete() { 3040 if (that.hoverState != 'in') $tip.detach() 3041 that.$element 3042 .removeAttr('aria-describedby') 3043 .trigger('hidden.bs.' + that.type) 3044 callback && callback() 3045 } 3046 3047 this.$element.trigger(e) 3048 3049 if (e.isDefaultPrevented()) return 3050 3051 $tip.removeClass('in') 3052 3053 $.support.transition && $tip.hasClass('fade') ? 3054 $tip 3055 .one('bsTransitionEnd', complete) 3056 .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 3057 complete() 3058 3059 this.hoverState = null 3060 3061 return this 3062 } 3063 3064 Tooltip.prototype.fixTitle = function () { 3065 var $e = this.$element 3066 if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') { 3067 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 3068 } 3069 } 3070 3071 Tooltip.prototype.hasContent = function () { 3072 return this.getTitle() 3073 } 3074 3075 Tooltip.prototype.getPosition = function ($element) { 3076 $element = $element || this.$element 3077 3078 var el = $element[0] 3079 var isBody = el.tagName == 'BODY' 3080 3081 var elRect = el.getBoundingClientRect() 3082 if (elRect.width == null) { 3083 // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 3084 elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) 3085 } 3086 var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() 3087 var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } 3088 var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null 3089 3090 return $.extend({}, elRect, scroll, outerDims, elOffset) 3091 } 3092 3093 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 3094 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 3095 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 3096 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 3097 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 3098 3099 } 3100 3101 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 3102 var delta = { top: 0, left: 0 } 3103 if (!this.$viewport) return delta 3104 3105 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 3106 var viewportDimensions = this.getPosition(this.$viewport) 3107 3108 if (/right|left/.test(placement)) { 3109 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 3110 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 3111 if (topEdgeOffset < viewportDimensions.top) { // top overflow 3112 delta.top = viewportDimensions.top - topEdgeOffset 3113 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 3114 delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset 3115 } 3116 } else { 3117 var leftEdgeOffset = pos.left - viewportPadding 3118 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 3119 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 3120 delta.left = viewportDimensions.left - leftEdgeOffset 3121 } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow 3122 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 3123 } 3124 } 3125 3126 return delta 3127 } 3128 3129 Tooltip.prototype.getTitle = function () { 3130 var title 3131 var $e = this.$element 3132 var o = this.options 3133 3134 title = $e.attr('data-original-title') 3135 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 3136 3137 return title 3138 } 3139 3140 Tooltip.prototype.getUID = function (prefix) { 3141 do prefix += ~~(Math.random() * 1000000) 3142 while (document.getElementById(prefix)) 3143 return prefix 3144 } 3145 3146 Tooltip.prototype.tip = function () { 3147 if (!this.$tip) { 3148 this.$tip = $(this.options.template) 3149 if (this.$tip.length != 1) { 3150 throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!') 3151 } 3152 } 3153 return this.$tip 3154 } 3155 3156 Tooltip.prototype.arrow = function () { 3157 return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) 3158 } 3159 3160 Tooltip.prototype.enable = function () { 3161 this.enabled = true 3162 } 3163 3164 Tooltip.prototype.disable = function () { 3165 this.enabled = false 3166 } 3167 3168 Tooltip.prototype.toggleEnabled = function () { 3169 this.enabled = !this.enabled 3170 } 3171 3172 Tooltip.prototype.toggle = function (e) { 3173 var self = this 3174 if (e) { 3175 self = $(e.currentTarget).data('bs.' + this.type) 3176 if (!self) { 3177 self = new this.constructor(e.currentTarget, this.getDelegateOptions()) 3178 $(e.currentTarget).data('bs.' + this.type, self) 3179 } 3180 } 3181 3182 if (e) { 3183 self.inState.click = !self.inState.click 3184 if (self.isInStateTrue()) self.enter(self) 3185 else self.leave(self) 3186 } else { 3187 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 3188 } 3189 } 3190 3191 Tooltip.prototype.destroy = function () { 3192 var that = this 3193 clearTimeout(this.timeout) 3194 this.hide(function () { 3195 that.$element.off('.' + that.type).removeData('bs.' + that.type) 3196 if (that.$tip) { 3197 that.$tip.detach() 3198 } 3199 that.$tip = null 3200 that.$arrow = null 3201 that.$viewport = null 3202 }) 3203 } 3204 3205 3206 // TOOLTIP PLUGIN DEFINITION 3207 // ========================= 3208 3209 function Plugin(option) { 3210 return this.each(function () { 3211 var $this = $(this) 3212 var data = $this.data('bs.tooltip') 3213 var options = typeof option == 'object' && option 3214 3215 if (!data && /destroy|hide/.test(option)) return 3216 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 3217 if (typeof option == 'string') data[option]() 3218 }) 3219 } 3220 3221 var old = $.fn.tooltip 3222 3223 $.fn.tooltip = Plugin 3224 $.fn.tooltip.Constructor = Tooltip 3225 3226 3227 // TOOLTIP NO CONFLICT 3228 // =================== 3229 3230 $.fn.tooltip.noConflict = function () { 3231 $.fn.tooltip = old 3232 return this 3233 } 3234 3235}(jQuery);
vendor: 12,250 bytes, lines 3236-3686
3236; 3237/* ======================================================================== 3238 * Bootstrap: popover.js v3.3.5 3239 * http://getbootstrap.com/javascript/#popovers 3240 * ======================================================================== 3241 * Copyright 2011-2015 Twitter, Inc. 3242 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 3243 * ======================================================================== */ 3244 3245 3246+function ($) { 3247 'use strict'; 3248 3249 // POPOVER PUBLIC CLASS DEFINITION 3250 // =============================== 3251 3252 var Popover = function (element, options) { 3253 this.init('popover', element, options) 3254 } 3255 3256 if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') 3257 3258 Popover.VERSION = '3.3.5' 3259 3260 Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { 3261 placement: 'right', 3262 trigger: 'click', 3263 content: '', 3264 template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' 3265 }) 3266 3267 3268 // NOTE: POPOVER EXTENDS tooltip.js 3269 // ================================ 3270 3271 Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) 3272 3273 Popover.prototype.constructor = Popover 3274 3275 Popover.prototype.getDefaults = function () { 3276 return Popover.DEFAULTS 3277 } 3278 3279 Popover.prototype.setContent = function () { 3280 var $tip = this.tip() 3281 var title = this.getTitle() 3282 var content = this.getContent() 3283 3284 $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) 3285 $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events 3286 this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' 3287 ](content) 3288 3289 $tip.removeClass('fade top bottom left right in') 3290 3291 // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do 3292 // this manually by checking the contents. 3293 if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() 3294 } 3295 3296 Popover.prototype.hasContent = function () { 3297 return this.getTitle() || this.getContent() 3298 } 3299 3300 Popover.prototype.getContent = function () { 3301 var $e = this.$element 3302 var o = this.options 3303 3304 return $e.attr('data-content') 3305 || (typeof o.content == 'function' ? 3306 o.content.call($e[0]) : 3307 o.content) 3308 } 3309 3310 Popover.prototype.arrow = function () { 3311 return (this.$arrow = this.$arrow || this.tip().find('.arrow')) 3312 } 3313 3314 3315 // POPOVER PLUGIN DEFINITION 3316 // ========================= 3317 3318 function Plugin(option) { 3319 return this.each(function () { 3320 var $this = $(this) 3321 var data = $this.data('bs.popover') 3322 var options = typeof option == 'object' && option 3323 3324 if (!data && /destroy|hide/.test(option)) return 3325 if (!data) $this.data('bs.popover', (data = new Popover(this, options))) 3326 if (typeof option == 'string') data[option]() 3327 }) 3328 } 3329 3330 var old = $.fn.popover 3331 3332 $.fn.popover = Plugin 3333 $.fn.popover.Constructor = Popover 3334 3335 3336 // POPOVER NO CONFLICT 3337 // =================== 3338 3339 $.fn.popover.noConflict = function () { 3340 $.fn.popover = old 3341 return this 3342 } 3343 3344}(jQuery); 3345; 3346/* ======================================================================== 3347 * Bootstrap: scrollspy.js v3.3.5 3348 * http://getbootstrap.com/javascript/#scrollspy 3349 * ======================================================================== 3350 * Copyright 2011-2015 Twitter, Inc. 3351 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 3352 * ======================================================================== */ 3353 3354 3355+function ($) { 3356 'use strict'; 3357 3358 // SCROLLSPY CLASS DEFINITION 3359 // ========================== 3360 3361 function ScrollSpy(element, options) { 3362 this.$body = $(document.body) 3363 this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) 3364 this.options = $.extend({}, ScrollSpy.DEFAULTS, options) 3365 this.selector = (this.options.target || '') + ' .nav li > a' 3366 this.offsets = [] 3367 this.targets = [] 3368 this.activeTarget = null 3369 this.scrollHeight = 0 3370 3371 this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) 3372 this.refresh() 3373 this.process() 3374 } 3375 3376 ScrollSpy.VERSION = '3.3.5' 3377 3378 ScrollSpy.DEFAULTS = { 3379 offset: 10 3380 } 3381 3382 ScrollSpy.prototype.getScrollHeight = function () { 3383 return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) 3384 } 3385 3386 ScrollSpy.prototype.refresh = function () { 3387 var that = this 3388 var offsetMethod = 'offset' 3389 var offsetBase = 0 3390 3391 this.offsets = [] 3392 this.targets = [] 3393 this.scrollHeight = this.getScrollHeight() 3394 3395 if (!$.isWindow(this.$scrollElement[0])) { 3396 offsetMethod = 'position' 3397 offsetBase = this.$scrollElement.scrollTop() 3398 } 3399 3400 this.$body 3401 .find(this.selector) 3402 .map(function () { 3403 var $el = $(this) 3404 var href = $el.data('target') || $el.attr('href') 3405 var $href = /^#./.test(href) && $(href) 3406 3407 return ($href 3408 && $href.length 3409 && $href.is(':visible') 3410 && [[$href[offsetMethod]().top + offsetBase, href]]) || null 3411 }) 3412 .sort(function (a, b) { return a[0] - b[0] }) 3413 .each(function () { 3414 that.offsets.push(this[0]) 3415 that.targets.push(this[1]) 3416 }) 3417 } 3418 3419 ScrollSpy.prototype.process = function () { 3420 var scrollTop = this.$scrollElement.scrollTop() + this.options.offset 3421 var scrollHeight = this.getScrollHeight() 3422 var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() 3423 var offsets = this.offsets 3424 var targets = this.targets 3425 var activeTarget = this.activeTarget 3426 var i 3427 3428 if (this.scrollHeight != scrollHeight) { 3429 this.refresh() 3430 } 3431 3432 if (scrollTop >= maxScroll) { 3433 return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) 3434 } 3435 3436 if (activeTarget && scrollTop < offsets[0]) { 3437 this.activeTarget = null 3438 return this.clear() 3439 } 3440 3441 for (i = offsets.length; i--;) { 3442 activeTarget != targets[i] 3443 && scrollTop >= offsets[i] 3444 && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1]) 3445 && this.activate(targets[i]) 3446 } 3447 } 3448 3449 ScrollSpy.prototype.activate = function (target) { 3450 this.activeTarget = target 3451 3452 this.clear() 3453 3454 var selector = this.selector + 3455 '[data-target="' + target + '"],' + 3456 this.selector + '[href="' + target + '"]' 3457 3458 var active = $(selector) 3459 .parents('li') 3460 .addClass('active') 3461 3462 if (active.parent('.dropdown-menu').length) { 3463 active = active 3464 .closest('li.dropdown') 3465 .addClass('active') 3466 } 3467 3468 active.trigger('activate.bs.scrollspy') 3469 } 3470 3471 ScrollSpy.prototype.clear = function () { 3472 $(this.selector) 3473 .parentsUntil(this.options.target, '.active') 3474 .removeClass('active') 3475 } 3476 3477 3478 // SCROLLSPY PLUGIN DEFINITION 3479 // =========================== 3480 3481 function Plugin(option) { 3482 return this.each(function () { 3483 var $this = $(this) 3484 var data = $this.data('bs.scrollspy') 3485 var options = typeof option == 'object' && option 3486 3487 if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) 3488 if (typeof option == 'string') data[option]() 3489 }) 3490 } 3491 3492 var old = $.fn.scrollspy 3493 3494 $.fn.scrollspy = Plugin 3495 $.fn.scrollspy.Constructor = ScrollSpy 3496 3497 3498 // SCROLLSPY NO CONFLICT 3499 // ===================== 3500 3501 $.fn.scrollspy.noConflict = function () { 3502 $.fn.scrollspy = old 3503 return this 3504 } 3505 3506 3507 // SCROLLSPY DATA-API 3508 // ================== 3509 3510 $(window).on('load.bs.scrollspy.data-api', function () { 3511 $('[data-spy="scroll"]').each(function () { 3512 var $spy = $(this) 3513 Plugin.call($spy, $spy.data()) 3514 }) 3515 }) 3516 3517}(jQuery); 3518; 3519/* ======================================================================== 3520 * Bootstrap: tab.js v3.3.5 3521 * http://getbootstrap.com/javascript/#tabs 3522 * ======================================================================== 3523 * Copyright 2011-2015 Twitter, Inc. 3524 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 3525 * ======================================================================== */ 3526 3527 3528+function ($) { 3529 'use strict'; 3530 3531 // TAB CLASS DEFINITION 3532 // ==================== 3533 3534 var Tab = function (element) { 3535 // jscs:disable requireDollarBeforejQueryAssignment 3536 this.element = $(element) 3537 // jscs:enable requireDollarBeforejQueryAssignment 3538 } 3539 3540 Tab.VERSION = '3.3.5' 3541 3542 Tab.TRANSITION_DURATION = 150 3543 3544 Tab.prototype.show = function () { 3545 var $this = this.element 3546 var $ul = $this.closest('ul:not(.dropdown-menu)') 3547 var selector = $this.data('target') 3548 3549 if (!selector) { 3550 selector = $this.attr('href') 3551 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 3552 } 3553 3554 if ($this.parent('li').hasClass('active')) return 3555 3556 var $previous = $ul.find('.active:last a') 3557 var hideEvent = $.Event('hide.bs.tab', { 3558 relatedTarget: $this[0] 3559 }) 3560 var showEvent = $.Event('show.bs.tab', { 3561 relatedTarget: $previous[0] 3562 }) 3563 3564 $previous.trigger(hideEvent) 3565 $this.trigger(showEvent) 3566 3567 if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return 3568 3569 var $target = $(selector) 3570 3571 this.activate($this.closest('li'), $ul) 3572 this.activate($target, $target.parent(), function () { 3573 $previous.trigger({ 3574 type: 'hidden.bs.tab', 3575 relatedTarget: $this[0] 3576 }) 3577 $this.trigger({ 3578 type: 'shown.bs.tab', 3579 relatedTarget: $previous[0] 3580 }) 3581 }) 3582 } 3583 3584 Tab.prototype.activate = function (element, container, callback) { 3585 var $active = container.find('> .active') 3586 var transition = callback 3587 && $.support.transition 3588 && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length) 3589 3590 function next() { 3591 $active 3592 .removeClass('active') 3593 .find('> .dropdown-menu > .active') 3594 .removeClass('active') 3595 .end() 3596 .find('[data-toggle="tab"]') 3597 .attr('aria-expanded', false) 3598 3599 element 3600 .addClass('active') 3601 .find('[data-toggle="tab"]') 3602 .attr('aria-expanded', true) 3603 3604 if (transition) { 3605 element[0].offsetWidth // reflow for transition 3606 element.addClass('in') 3607 } else { 3608 element.removeClass('fade') 3609 } 3610 3611 if (element.parent('.dropdown-menu').length) { 3612 element 3613 .closest('li.dropdown') 3614 .addClass('active') 3615 .end() 3616 .find('[data-toggle="tab"]') 3617 .attr('aria-expanded', true) 3618 } 3619 3620 callback && callback() 3621 } 3622 3623 $active.length && transition ? 3624 $active 3625 .one('bsTransitionEnd', next) 3626 .emulateTransitionEnd(Tab.TRANSITION_DURATION) : 3627 next() 3628 3629 $active.removeClass('in') 3630 } 3631 3632 3633 // TAB PLUGIN DEFINITION 3634 // ===================== 3635 3636 function Plugin(option) { 3637 return this.each(function () { 3638 var $this = $(this) 3639 var data = $this.data('bs.tab') 3640 3641 if (!data) $this.data('bs.tab', (data = new Tab(this))) 3642 if (typeof option == 'string') data[option]() 3643 }) 3644 } 3645 3646 var old = $.fn.tab 3647 3648 $.fn.tab = Plugin 3649 $.fn.tab.Constructor = Tab 3650 3651 3652 // TAB NO CONFLICT 3653 // =============== 3654 3655 $.fn.tab.noConflict = function () { 3656 $.fn.tab = old 3657 return this 3658 } 3659 3660 3661 // TAB DATA-API 3662 // ============ 3663 3664 var clickHandler = function (e) { 3665 e.preventDefault() 3666 Plugin.call($(this), 'show') 3667 } 3668 3669 $(document) 3670 .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler) 3671 .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler) 3672 3673}(jQuery); 3674; 3675/* ======================================================================== 3676 * Bootstrap: transition.js v3.3.5 3677 * http://getbootstrap.com/javascript/#transitions 3678 * ======================================================================== 3679 * Copyright 2011-2015 Twitter, Inc. 3680 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 3681 * ======================================================================== */ 3682 3683 3684+function ($) { 3685 'use strict'; 3686
vendor: 1,366 bytes, lines 3687-3734
3687 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 3688 // ============================================================ 3689 3690 function transitionEnd() { 3691 var el = document.createElement('bootstrap') 3692 3693 var transEndEventNames = { 3694 WebkitTransition : 'webkitTransitionEnd', 3695 MozTransition : 'transitionend', 3696 OTransition : 'oTransitionEnd otransitionend', 3697 transition : 'transitionend' 3698 } 3699 3700 for (var name in transEndEventNames) { 3701 if (el.style[name] !== undefined) { 3702 return { end: transEndEventNames[name] } 3703 } 3704 } 3705 3706 return false // explicit for ie8 ( ._.) 3707 } 3708 3709 // http://blog.alexmaccaw.com/css-transitions 3710 $.fn.emulateTransitionEnd = function (duration) { 3711 var called = false 3712 var $el = this 3713 $(this).one('bsTransitionEnd', function () { called = true }) 3714 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 3715 setTimeout(callback, duration) 3716 return this 3717 } 3718 3719 $(function () { 3720 $.support.transition = transitionEnd() 3721 3722 if (!$.support.transition) return 3723 3724 $.event.special.bsTransitionEnd = { 3725 bindType: $.support.transition.end, 3726 delegateType: $.support.transition.end, 3727 handle: function (e) { 3728 if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 3729 } 3730 } 3731 }) 3732 3733}(jQuery); 3734;
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.