1(function($){ 2 3 var NAME = 'navDropdown'; 4 var DATA_KEY = 'bs.nav-dropdown'; 5 var EVENT_KEY = '.' + DATA_KEY; 6 var DATA_API_KEY = '.data-api'; 7 var JQUERY_NO_CONFLICT = $.fn[NAME]; 8 9 var Event = { 10 HIDE: 'hide' + EVENT_KEY, 11 HIDDEN: 'hidden' + EVENT_KEY, 12 SHOW: 'show' + EVENT_KEY, 13 SHOWN: 'shown' + EVENT_KEY, 14 CLICK: 'click' + EVENT_KEY, 15 READY: 'ready' + EVENT_KEY, 16 COLLAPSE: 'collapse' + EVENT_KEY, 17 LOAD_DATA_API: 'ready' + EVENT_KEY + DATA_API_KEY, 18 CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY, 19 RESIZE_DATA_API: 'resize' + EVENT_KEY + DATA_API_KEY, 20 KEYDOWN_DATA_API: 'keydown' + EVENT_KEY + DATA_API_KEY, 21 NAVBAR_COLLAPSE: 'collapse.bs.navbar-dropdown' 22 }; 23 24 var Hotkeys = { 25 ESC: 27, 26 LEFT: 37, 27 UP: 38, 28 RIGHT: 39, 29 DOWN: 40 30 }; 31 32 var Breakpoints = { 33 XS: 544, 34 SM: 768, 35 MD: 992, 36 LG: 1200, 37 XL: Infinity 38 }; 39 40 var ClassName = { 41 BACKDROP: 'dropdown-backdrop', 42 DISABLED: 'disabled', 43 OPEN: 'open', 44 SM: 'nav-dropdown-sm' 45 }; 46 47 var Selector = { 48 BASE: '.nav-dropdown', 49 DROPDOWN: '.dropdown', 50 DROPDOWN_MENU: '.dropdown-menu', 51 BACKDROP: '.' + ClassName.BACKDROP, 52 DATA_BUTTON: '[data-button]', 53 DATA_TOGGLE: '[data-toggle="dropdown-submenu"]', 54 FORM_CHILD: '.dropdown form' 55 }; 56 57 58 59 var $$ = (function(){ 60 61 function Item(elements, prevItem) { 62 if (!('length' in elements)) elements = [elements]; 63 this.props = {}; 64 this.length = elements.length; 65 if (prevItem) { 66 this.prevItem = prevItem; 67 $.extend(this.props, prevItem.props); 68 } 69 for (var i = 0; i < elements.length; i++) { 70 this[i] = elements[i]; 71 } 72 } 73 74 Item.prototype.eq = function(index) { 75 return new Item(this[index] ? this[index] : [], this); 76 }; 77 78 Item.prototype.parent = function() { 79 return new Item( 80 81 $(this).map(function(){ 82 83 var $$this = new Item(this); 84 85 if ($$this.is(':upper')) return null; 86 87 return $( $$this.is(':toggle') ? this.parentNode.parentNode : this ) 88 .closest(Selector.DROPDOWN) 89 .find('>' + Selector.DATA_TOGGLE)[0]; 90 91 }), 92 93 this 94 95 ); 96 }; 97 98 Item.prototype.parents = function(selector) { 99 var elements = $(this).map(function(){ 100 101 return (new Item(this)).is(':toggle') ? this.parentNode : this; 102 103 }).parentsUntil(Selector.BASE, Selector.DROPDOWN); 104 105 if (selector === ':upper') elements = elements.last(); 106 107 elements = elements.find('>' + Selector.DATA_TOGGLE); 108 109 return new Item(elements, this); 110 }; 111 112 Item.prototype.children = function(deepSearch) { 113 114 var elements = []; 115 116 $(this).each(function(){ 117 118 var $parent, $items, $$item = new Item(this); 119 120 if ($$item.is(':root')) { 121 $parent = $(this); 122 } else if ($$item.is(':toggle')) { 123 $parent = $(this).parent().find('>' + Selector.DROPDOWN_MENU); 124 } else { 125 return; 126 } 127 128 if (deepSearch) { 129 $items = $parent.find('a'); 130 } else if ($$item.is(':root')) { 131 $items = $parent.find('>li>a'); 132 } else { 133 $items = $parent.find('>a, >' + Selector.DROPDOWN + '>a'); 134 } 135 136 $items.each(function(){ 137 138 if ((deepSearch && !this.offsetWidth && !this.offsetHeight) 139 || this.disabled || $(this).is(Selector.DATA_BUTTON) || $(this).hasClass(ClassName.DISABLED) || ~$.inArray(this, elements)) { 140 return; 141 } 142 143 elements.push(this); 144 145 }); 146 147 }); 148 149 return new Item(elements, this); 150 151 }; 152 153 Item.prototype.root = function() { 154 return new Item( 155 $(this).closest(Selector.BASE), 156 this 157 ); 158 }; 159 160 Item.prototype.jump = function(step) { 161 step = step || 'next'; 162 163 if (!this.length) { 164 return new Item([], this); 165 } 166 167 var children, $$item = this.eq(0); 168 if (this.is(':flat') || $$item.is(':upper')) { 169 children = $$item.root().children( this.is(':flat') ); 170 } else { 171 children = $$item.parent().children(); 172 } 173 174 var index = $.inArray(this[0], children); 175 if (!children.length || !~index) { 176 return new Item([], this); 177 } 178 179 if (step == 'next') { 180 index += 1; 181 if (index < children.length) { 182 return new Item(children[index], this); 183 } 184 step = 'first'; 185 } else if (step == 'prev') { 186 index -= 1; 187 if (index >= 0) { 188 return new Item(children[index], this); 189 } 190 step = 'last'; 191 } 192 193 if (step == 'first') return new Item(children[0], this); 194 if (step == 'last') return new Item(children[ children.length - 1 ], this); 195 196 return new Item([], this); 197 }; 198 199 Item.prototype.next = function() { 200 return this.jump('next'); 201 }; 202 203 Item.prototype.prev = function() { 204 return this.jump('prev'); 205 }; 206 207 Item.prototype.first = function() { 208 return this.jump('first'); 209 }; 210 211 Item.prototype.last = function() { 212 return this.jump('last'); 213 }; 214 215 Item.prototype.prop = function(name, value) { 216 if (arguments.length) { 217 if (arguments.length > 1) { 218 this.props[name] = value; 219 return this; 220 } 221 if (typeof arguments[0] == 'object') { 222 $.extend(this.props, arguments[0]); 223 return this; 224 } 225 return (name in this.props) ? 226 this.props[name] : null; 227 } 228 return $.extend({}, this.props); 229 }; 230 231 Item.prototype.removeProp = function(name) { 232 delete this.props[name]; 233 return this; 234 }; 235 236 Item.prototype.is = function(selector) { 237 var $this = $(this), 238 selectors = (selector || '').split(/(?=[*#.\[:\s])/); 239 240 while (selector = selectors.pop()){ 241 242 switch (selector){ 243 244 case ':root': 245 if (!$this.is(Selector.BASE)) 246 return false;
247 break; 248 249 case ':upper': 250 if (!$this.parent().parent().is(Selector.BASE)) 251 return false; 252 break; 253 254 case ':opened': 255 case ':closed': 256 if ((selector == ':opened') != $this.parent().hasClass(ClassName.OPEN)) 257 return false; 258 case ':toggle': 259 if (!$this.is(Selector.DATA_TOGGLE)) 260 return false; 261 break; 262 263 default: 264 if (!this.props[selector]) 265 return false; 266 break; 267 268 } 269 270 } 271 272 return true; 273 }; 274 275 Item.prototype.open = function() { 276 if (this.is(':closed')) { 277 this.click(); 278 } 279 return this; 280 }; 281 282 Item.prototype.close = function() { 283 if (this.is(':opened')) { 284 this.click(); 285 } 286 return this; 287 }; 288 289 Item.prototype.focus = function() { 290 if (this.length) { 291 this[0].focus(); 292 } 293 return this; 294 }; 295 296 Item.prototype.click = function() { 297 if (this.length) { 298 $(this[0]).trigger('click'); 299 } 300 return this; 301 } 302 303 return function(element) { 304 return new Item(element); 305 }; 306 307 })(); 308 309 310 311 var NavDropdown = function(element){ 312 this._element = element; 313 $(this._element).on(Event.CLICK, this.toggle); 314 }; 315 316 NavDropdown.prototype.toggle = function(event) { 317 if (this.disabled || $(this).hasClass(ClassName.DISABLED)) { 318 return false; 319 } 320 321 var $parent = $(this.parentNode); 322 var isActive = $parent.hasClass(ClassName.OPEN); 323 var isCollapsed = NavDropdown._isCollapsed( $(this).closest(Selector.BASE) ); 324 325 NavDropdown._clearMenus( 326 $.Event('click', { 327 target: this, 328 data: { 329 toggles: isCollapsed ? [this] : null 330 } 331 }) 332 ); 333 334 if (isActive) { 335 return false; 336 } 337 338 if ('ontouchstart' in document.documentElement 339 && !$parent.closest(Selector.DROPDOWN + '.' + ClassName.OPEN).length) { 340 341 // if mobile we use a backdrop because click events don't delegate 342 var dropdown = document.createElement('div'); 343 dropdown.className = ClassName.BACKDROP; 344 $(dropdown).insertBefore( $(this).closest(Selector.BASE) ); 345 $(dropdown).on('click', NavDropdown._clearMenus); 346 347 } 348 349 var relatedTarget = { relatedTarget: this }; 350 var showEvent = $.Event(Event.SHOW, relatedTarget); 351 352 $parent.trigger(showEvent); 353 354 if (showEvent.isDefaultPrevented()) { 355 return false; 356 } 357 358 this.focus(); 359 this.setAttribute('aria-expanded', 'true'); 360 361 $parent.toggleClass(ClassName.OPEN); 362 $parent.trigger( $.Event(Event.SHOWN, relatedTarget) ); 363 364 return false; 365 }; 366 367 NavDropdown.prototype.dispose = function() { 368 $.removeData(this._element, DATA_KEY); 369 $(this._element).off(EVENT_KEY); 370 this._element = null; 371 }; 372 373 NavDropdown._clearMenus = function(event) { 374 event = event || {}; 375 376 if (event.which === 3) { 377 return; 378 } 379 380 var collapseEvent; 381 var filter = function(){ return false; }; 382 383 if (event.target) { 384 385 if (this === document) { 386 387 if ( $(event.target).is('a:not([disabled], .' + ClassName.DISABLED + ')') ) { 388 collapseEvent = $.Event(Event.COLLAPSE, { relatedTarget: event.target }) 389 } else { 390 391 var $rootNode = (event.targetWrapper && $(event.targetWrapper).find(Selector.BASE)) || $(event.target).closest(Selector.BASE); 392 393 if (NavDropdown._isCollapsed($rootNode)) return; 394 } 395 396 } else { 397 398 if ($(event.target).hasClass(ClassName.BACKDROP)) { 399 var $nextNode = $(event.target).next(); 400 if ($nextNode.is(Selector.BASE) && NavDropdown._isCollapsed($nextNode)) { 401 return; 402 } 403 } 404 405 } 406 407 if ($(event.target).is(Selector.DATA_TOGGLE)) { 408 filter = $(event.target.parentNode).parents(Selector.DROPDOWN).find('>' + Selector.DATA_TOGGLE); 409 } else { 410 $(Selector.BACKDROP).remove(); 411 } 412 413 } 414 415 var toggles = (event.data && event.data.toggles && $(event.data.toggles).parent().find(Selector.DATA_TOGGLE)) || $.makeArray( $(Selector.DATA_TOGGLE).not(filter) ); 416 417 for (var i = 0; i < toggles.length; i++) { 418 419 var parent = toggles[i].parentNode; 420 var relatedTarget = { relatedTarget: toggles[i] }; 421 422 if (!$(parent).hasClass(ClassName.OPEN)) { 423 continue; 424 } 425 426 if (event.type === 'click' && 427 (/input|textarea/i.test(event.target.tagName)) && 428 ($.contains(parent, event.target))) { 429 continue; 430 } 431 432 var hideEvent = $.Event(Event.HIDE, relatedTarget); 433 $(parent).trigger(hideEvent); 434 if (hideEvent.isDefaultPrevented()) { 435 continue; 436 } 437 438 toggles[i].setAttribute('aria-expanded', 'false'); 439 440 $(parent) 441 .removeClass(ClassName.OPEN) 442 .trigger( $.Event(Event.HIDDEN, relatedTarget) ); 443 444 } 445 446 if (collapseEvent) { 447 $(document).trigger(collapseEvent); 448 } 449 450 }; 451 452 // static 453 NavDropdown._dataApiKeydownHandler = function(event) { 454 455 if (/input|textarea/i.test(event.target.tagName)) { 456 return; 457 } 458 459 // ???? 460 var found; 461 for (var k in Hotkeys) { 462 if (found = (Hotkeys[k] === event.which)) { 463 break; 464 } 465 } 466 if (!found) return; 467 468 event.preventDefault(); 469 event.stopPropagation(); 470 471 if (event.which == Hotkeys.ESC) { 472 473 if (NavDropdown._isCollapsed(this)) { 474 return; 475 } 476 477 var toggle = $(event.target).parents(Selector.DROPDOWN + '.' + ClassName.OPEN) 478 .last().find('>' + Selector.DATA_TOGGLE); 479 NavDropdown._clearMenus(); 480 toggle.trigger('focus'); 481 return; 482 483 } 484 485 if (event.target.tagName != 'A') { 486 return; 487 } 488 489 var $$item = $$(event.target); 490 491 $$item.prop(':flat', NavDropdown._isCollapsed($$item.root())); 492 493 if ($$item.is(':flat')){ 494 495 if (event.which === Hotkeys.DOWN || event.which === Hotkeys.UP) { 496 497 $$item[ event.which === Hotkeys.UP ? 'prev' : 'next' ]().focus(); 498 499 } else if (event.which === Hotkeys.LEFT) { 500 501 if ($$item.is(':opened')) { 502 $$item.close(); 503 } else { 504 $$item.parent().close().focus(); 505 } 506 507 } else if (event.which === Hotkeys.RIGHT && $$item.is(':toggle')) { 508 $$item.open(); 509 } 510 511 } else if ($$item.is(':upper')) { 512 513 if (event.which === Hotkeys.LEFT || event.which === Hotkeys.RIGHT) { 514 515 $$item[event.which === Hotkeys.LEFT ? 'prev' : 'next']().focus().open(); 516 if ($$item.is(':toggle')) $$item.close(); 517 518 } else if ((event.which === Hotkeys.DOWN || event.which === Hotkeys.UP) && $$item.is(':toggle')) { 519 520 $$item.children()[ event.which === Hotkeys.DOWN ? 'first' : 'last' ]().focus(); 521 522 } 523 524 } else { 525 526 if (event.which === Hotkeys.LEFT) { 527 528 var $$parent = $$item.parent(); 529 530 if ($$parent.is(':upper')) { 531 $$parent.close().prev().focus().open(); 532 } else { 533 $$parent.focus().close(); 534 } 535 536 } else if (event.which === Hotkeys.RIGHT) { 537 538 var $$children = $$item.children(); 539 if ($$children.length) { 540 $$item.open(); 541 $$children.first().focus(); 542 } else { 543 $$item.parents(':upper').close().next().focus().open(); 544 } 545 546 } else if (event.which === Hotkeys.DOWN || event.which === Hotkeys.UP) { 547 548 $$item[ event.which === Hotkeys.UP ? 'prev' : 'next' ]().focus(); 549 550 } 551 552 } 553 554 }; 555 556 // static 557 NavDropdown._isCollapsed = function(rootNode) { 558 var match; 559 if (rootNode.length) rootNode = rootNode[0]; 560 return rootNode && (match = /navbar-toggleable-(xs|sm|md|lg|xl)/.exec(rootNode.className))
561 && (window.innerWidth < Breakpoints[ match[1].toUpperCase() ]); 562 }; 563 564 // static 565 NavDropdown._dataApiResizeHandler = function() { 566 567 $(Selector.BASE).each(function(){ 568 569 var isCollapsed = NavDropdown._isCollapsed(this); 570 571 $(this).find(Selector.DROPDOWN).removeClass(ClassName.OPEN); 572 $(this).find('[aria-expanded="true"]').attr('aria-expanded', 'false'); 573 574 var backdrop = $(Selector.BACKDROP)[0]; 575 if (backdrop) { 576 backdrop.parentNode.removeChild(backdrop); // ??? 577 } 578 579 if (isCollapsed == $(this).hasClass(ClassName.SM)) { 580 return; 581 } 582 583 if (isCollapsed) { 584 $(this).addClass(ClassName.SM); 585 } else { 586 $(this).removeClass(ClassName.SM); 587 588 // $(this).removeClass(ClassName.SM + ' in'); /// ??? 589 // NavDropdown._clearMenus(); 590 } 591 592 }); 593 }; 594 595 /** 596 * ------------------------------------------------------------------------ 597 * jQuery 598 * ------------------------------------------------------------------------ 599 */ 600 601 $.fn[NAME] = function(config) { 602 return this.each(function(){ 603 604 var data = $(this).data(DATA_KEY); 605 606 if (!data) { 607 $(this).data(DATA_KEY, (data = new NavDropdown(this))); 608 } 609 610 if (typeof config === 'string') { 611 if (data[config] === undefined) { 612 throw new Error('No method named "' + config + '"'); 613 } 614 data[config].call(this); 615 } 616 617 }); 618 }; 619 $.fn[NAME].noConflict = function() { 620 $.fn[NAME] = JQUERY_NO_CONFLICT; 621 return this; 622 }; 623 $.fn[NAME].Constructor = NavDropdown; 624 $.fn[NAME].$$ = $$; 625 626 627 $(window) 628 .on(Event.RESIZE_DATA_API + ' ' + Event.LOAD_DATA_API, NavDropdown._dataApiResizeHandler); 629 630 $(document) 631 .on(Event.KEYDOWN_DATA_API, Selector.BASE, NavDropdown._dataApiKeydownHandler) 632 .on(Event.NAVBAR_COLLAPSE, NavDropdown._clearMenus) 633 .on(Event.CLICK_DATA_API, NavDropdown._clearMenus) 634 .on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, NavDropdown.prototype.toggle) 635 .on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function(e){ 636 e.stopPropagation(); 637 }); 638 639 $(window) 640 .trigger(Event.READY); 641 642 643})(jQuery);
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.