├── README.md ├── bootstrap.js ├── style.css └── wp-bootstrap-navwalker.php /README.md: -------------------------------------------------------------------------------- 1 | Utilizing the wp-bootstrap-navwalker class by Edward McIntyre (https://github.com/twittem/wp-bootstrap-navwalker), added support 2 | for multi level dropdown menus. This solution works for both WordPress or as 3 | a standalone solution. 4 | 5 | For details visit http://www.jeffmould.com/2014/01/09/responsive-multi-level-bootstrap-menu/ 7 | 8 | 9 | -------------------------------------------------------------------------------- /bootstrap.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.0.3 (http://getbootstrap.com) 3 | * Copyright 2013 Twitter, Inc. 4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0 5 | */ 6 | 7 | if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") } 8 | 9 | /* ======================================================================== 10 | * Bootstrap: transition.js v3.0.3 11 | * http://getbootstrap.com/javascript/#transitions 12 | * ======================================================================== 13 | * Copyright 2013 Twitter, Inc. 14 | * 15 | * Licensed under the Apache License, Version 2.0 (the "License"); 16 | * you may not use this file except in compliance with the License. 17 | * You may obtain a copy of the License at 18 | * 19 | * http://www.apache.org/licenses/LICENSE-2.0 20 | * 21 | * Unless required by applicable law or agreed to in writing, software 22 | * distributed under the License is distributed on an "AS IS" BASIS, 23 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | * See the License for the specific language governing permissions and 25 | * limitations under the License. 26 | * ======================================================================== */ 27 | 28 | 29 | +function ($) { "use strict"; 30 | 31 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 32 | // ============================================================ 33 | 34 | function transitionEnd() { 35 | var el = document.createElement('bootstrap') 36 | 37 | var transEndEventNames = { 38 | 'WebkitTransition' : 'webkitTransitionEnd' 39 | , 'MozTransition' : 'transitionend' 40 | , 'OTransition' : 'oTransitionEnd otransitionend' 41 | , 'transition' : 'transitionend' 42 | } 43 | 44 | for (var name in transEndEventNames) { 45 | if (el.style[name] !== undefined) { 46 | return { end: transEndEventNames[name] } 47 | } 48 | } 49 | } 50 | 51 | // http://blog.alexmaccaw.com/css-transitions 52 | $.fn.emulateTransitionEnd = function (duration) { 53 | var called = false, $el = this 54 | $(this).one($.support.transition.end, function () { called = true }) 55 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 56 | setTimeout(callback, duration) 57 | return this 58 | } 59 | 60 | $(function () { 61 | $.support.transition = transitionEnd() 62 | }) 63 | 64 | }(jQuery); 65 | 66 | /* ======================================================================== 67 | * Bootstrap: alert.js v3.0.3 68 | * http://getbootstrap.com/javascript/#alerts 69 | * ======================================================================== 70 | * Copyright 2013 Twitter, Inc. 71 | * 72 | * Licensed under the Apache License, Version 2.0 (the "License"); 73 | * you may not use this file except in compliance with the License. 74 | * You may obtain a copy of the License at 75 | * 76 | * http://www.apache.org/licenses/LICENSE-2.0 77 | * 78 | * Unless required by applicable law or agreed to in writing, software 79 | * distributed under the License is distributed on an "AS IS" BASIS, 80 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 81 | * See the License for the specific language governing permissions and 82 | * limitations under the License. 83 | * ======================================================================== */ 84 | 85 | 86 | +function ($) { "use strict"; 87 | 88 | // ALERT CLASS DEFINITION 89 | // ====================== 90 | 91 | var dismiss = '[data-dismiss="alert"]' 92 | var Alert = function (el) { 93 | $(el).on('click', dismiss, this.close) 94 | } 95 | 96 | Alert.prototype.close = function (e) { 97 | var $this = $(this) 98 | var selector = $this.attr('data-target') 99 | 100 | if (!selector) { 101 | selector = $this.attr('href') 102 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 103 | } 104 | 105 | var $parent = $(selector) 106 | 107 | if (e) e.preventDefault() 108 | 109 | if (!$parent.length) { 110 | $parent = $this.hasClass('alert') ? $this : $this.parent() 111 | } 112 | 113 | $parent.trigger(e = $.Event('close.bs.alert')) 114 | 115 | if (e.isDefaultPrevented()) return 116 | 117 | $parent.removeClass('in') 118 | 119 | function removeElement() { 120 | $parent.trigger('closed.bs.alert').remove() 121 | } 122 | 123 | $.support.transition && $parent.hasClass('fade') ? 124 | $parent 125 | .one($.support.transition.end, removeElement) 126 | .emulateTransitionEnd(150) : 127 | removeElement() 128 | } 129 | 130 | 131 | // ALERT PLUGIN DEFINITION 132 | // ======================= 133 | 134 | var old = $.fn.alert 135 | 136 | $.fn.alert = function (option) { 137 | return this.each(function () { 138 | var $this = $(this) 139 | var data = $this.data('bs.alert') 140 | 141 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 142 | if (typeof option == 'string') data[option].call($this) 143 | }) 144 | } 145 | 146 | $.fn.alert.Constructor = Alert 147 | 148 | 149 | // ALERT NO CONFLICT 150 | // ================= 151 | 152 | $.fn.alert.noConflict = function () { 153 | $.fn.alert = old 154 | return this 155 | } 156 | 157 | 158 | // ALERT DATA-API 159 | // ============== 160 | 161 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 162 | 163 | }(jQuery); 164 | 165 | /* ======================================================================== 166 | * Bootstrap: button.js v3.0.3 167 | * http://getbootstrap.com/javascript/#buttons 168 | * ======================================================================== 169 | * Copyright 2013 Twitter, Inc. 170 | * 171 | * Licensed under the Apache License, Version 2.0 (the "License"); 172 | * you may not use this file except in compliance with the License. 173 | * You may obtain a copy of the License at 174 | * 175 | * http://www.apache.org/licenses/LICENSE-2.0 176 | * 177 | * Unless required by applicable law or agreed to in writing, software 178 | * distributed under the License is distributed on an "AS IS" BASIS, 179 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 180 | * See the License for the specific language governing permissions and 181 | * limitations under the License. 182 | * ======================================================================== */ 183 | 184 | 185 | +function ($) { "use strict"; 186 | 187 | // BUTTON PUBLIC CLASS DEFINITION 188 | // ============================== 189 | 190 | var Button = function (element, options) { 191 | this.$element = $(element) 192 | this.options = $.extend({}, Button.DEFAULTS, options) 193 | } 194 | 195 | Button.DEFAULTS = { 196 | loadingText: 'loading...' 197 | } 198 | 199 | Button.prototype.setState = function (state) { 200 | var d = 'disabled' 201 | var $el = this.$element 202 | var val = $el.is('input') ? 'val' : 'html' 203 | var data = $el.data() 204 | 205 | state = state + 'Text' 206 | 207 | if (!data.resetText) $el.data('resetText', $el[val]()) 208 | 209 | $el[val](data[state] || this.options[state]) 210 | 211 | // push to event loop to allow forms to submit 212 | setTimeout(function () { 213 | state == 'loadingText' ? 214 | $el.addClass(d).attr(d, d) : 215 | $el.removeClass(d).removeAttr(d); 216 | }, 0) 217 | } 218 | 219 | Button.prototype.toggle = function () { 220 | var $parent = this.$element.closest('[data-toggle="buttons"]') 221 | var changed = true 222 | 223 | if ($parent.length) { 224 | var $input = this.$element.find('input') 225 | if ($input.prop('type') === 'radio') { 226 | // see if clicking on current one 227 | if ($input.prop('checked') && this.$element.hasClass('active')) 228 | changed = false 229 | else 230 | $parent.find('.active').removeClass('active') 231 | } 232 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 233 | } 234 | 235 | if (changed) this.$element.toggleClass('active') 236 | } 237 | 238 | 239 | // BUTTON PLUGIN DEFINITION 240 | // ======================== 241 | 242 | var old = $.fn.button 243 | 244 | $.fn.button = function (option) { 245 | return this.each(function () { 246 | var $this = $(this) 247 | var data = $this.data('bs.button') 248 | var options = typeof option == 'object' && option 249 | 250 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 251 | 252 | if (option == 'toggle') data.toggle() 253 | else if (option) data.setState(option) 254 | }) 255 | } 256 | 257 | $.fn.button.Constructor = Button 258 | 259 | 260 | // BUTTON NO CONFLICT 261 | // ================== 262 | 263 | $.fn.button.noConflict = function () { 264 | $.fn.button = old 265 | return this 266 | } 267 | 268 | 269 | // BUTTON DATA-API 270 | // =============== 271 | 272 | $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { 273 | var $btn = $(e.target) 274 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 275 | $btn.button('toggle') 276 | e.preventDefault() 277 | }) 278 | 279 | }(jQuery); 280 | 281 | /* ======================================================================== 282 | * Bootstrap: carousel.js v3.0.3 283 | * http://getbootstrap.com/javascript/#carousel 284 | * ======================================================================== 285 | * Copyright 2013 Twitter, Inc. 286 | * 287 | * Licensed under the Apache License, Version 2.0 (the "License"); 288 | * you may not use this file except in compliance with the License. 289 | * You may obtain a copy of the License at 290 | * 291 | * http://www.apache.org/licenses/LICENSE-2.0 292 | * 293 | * Unless required by applicable law or agreed to in writing, software 294 | * distributed under the License is distributed on an "AS IS" BASIS, 295 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 296 | * See the License for the specific language governing permissions and 297 | * limitations under the License. 298 | * ======================================================================== */ 299 | 300 | 301 | +function ($) { "use strict"; 302 | 303 | // CAROUSEL CLASS DEFINITION 304 | // ========================= 305 | 306 | var Carousel = function (element, options) { 307 | this.$element = $(element) 308 | this.$indicators = this.$element.find('.carousel-indicators') 309 | this.options = options 310 | this.paused = 311 | this.sliding = 312 | this.interval = 313 | this.$active = 314 | this.$items = null 315 | 316 | this.options.pause == 'hover' && this.$element 317 | .on('mouseenter', $.proxy(this.pause, this)) 318 | .on('mouseleave', $.proxy(this.cycle, this)) 319 | } 320 | 321 | Carousel.DEFAULTS = { 322 | interval: 5000 323 | , pause: 'hover' 324 | , wrap: true 325 | } 326 | 327 | Carousel.prototype.cycle = function (e) { 328 | e || (this.paused = false) 329 | 330 | this.interval && clearInterval(this.interval) 331 | 332 | this.options.interval 333 | && !this.paused 334 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 335 | 336 | return this 337 | } 338 | 339 | Carousel.prototype.getActiveIndex = function () { 340 | this.$active = this.$element.find('.item.active') 341 | this.$items = this.$active.parent().children() 342 | 343 | return this.$items.index(this.$active) 344 | } 345 | 346 | Carousel.prototype.to = function (pos) { 347 | var that = this 348 | var activeIndex = this.getActiveIndex() 349 | 350 | if (pos > (this.$items.length - 1) || pos < 0) return 351 | 352 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) 353 | if (activeIndex == pos) return this.pause().cycle() 354 | 355 | return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) 356 | } 357 | 358 | Carousel.prototype.pause = function (e) { 359 | e || (this.paused = true) 360 | 361 | if (this.$element.find('.next, .prev').length && $.support.transition.end) { 362 | this.$element.trigger($.support.transition.end) 363 | this.cycle(true) 364 | } 365 | 366 | this.interval = clearInterval(this.interval) 367 | 368 | return this 369 | } 370 | 371 | Carousel.prototype.next = function () { 372 | if (this.sliding) return 373 | return this.slide('next') 374 | } 375 | 376 | Carousel.prototype.prev = function () { 377 | if (this.sliding) return 378 | return this.slide('prev') 379 | } 380 | 381 | Carousel.prototype.slide = function (type, next) { 382 | var $active = this.$element.find('.item.active') 383 | var $next = next || $active[type]() 384 | var isCycling = this.interval 385 | var direction = type == 'next' ? 'left' : 'right' 386 | var fallback = type == 'next' ? 'first' : 'last' 387 | var that = this 388 | 389 | if (!$next.length) { 390 | if (!this.options.wrap) return 391 | $next = this.$element.find('.item')[fallback]() 392 | } 393 | 394 | this.sliding = true 395 | 396 | isCycling && this.pause() 397 | 398 | var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) 399 | 400 | if ($next.hasClass('active')) return 401 | 402 | if (this.$indicators.length) { 403 | this.$indicators.find('.active').removeClass('active') 404 | this.$element.one('slid.bs.carousel', function () { 405 | var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) 406 | $nextIndicator && $nextIndicator.addClass('active') 407 | }) 408 | } 409 | 410 | if ($.support.transition && this.$element.hasClass('slide')) { 411 | this.$element.trigger(e) 412 | if (e.isDefaultPrevented()) return 413 | $next.addClass(type) 414 | $next[0].offsetWidth // force reflow 415 | $active.addClass(direction) 416 | $next.addClass(direction) 417 | $active 418 | .one($.support.transition.end, function () { 419 | $next.removeClass([type, direction].join(' ')).addClass('active') 420 | $active.removeClass(['active', direction].join(' ')) 421 | that.sliding = false 422 | setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) 423 | }) 424 | .emulateTransitionEnd(600) 425 | } else { 426 | this.$element.trigger(e) 427 | if (e.isDefaultPrevented()) return 428 | $active.removeClass('active') 429 | $next.addClass('active') 430 | this.sliding = false 431 | this.$element.trigger('slid.bs.carousel') 432 | } 433 | 434 | isCycling && this.cycle() 435 | 436 | return this 437 | } 438 | 439 | 440 | // CAROUSEL PLUGIN DEFINITION 441 | // ========================== 442 | 443 | var old = $.fn.carousel 444 | 445 | $.fn.carousel = function (option) { 446 | return this.each(function () { 447 | var $this = $(this) 448 | var data = $this.data('bs.carousel') 449 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 450 | var action = typeof option == 'string' ? option : options.slide 451 | 452 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 453 | if (typeof option == 'number') data.to(option) 454 | else if (action) data[action]() 455 | else if (options.interval) data.pause().cycle() 456 | }) 457 | } 458 | 459 | $.fn.carousel.Constructor = Carousel 460 | 461 | 462 | // CAROUSEL NO CONFLICT 463 | // ==================== 464 | 465 | $.fn.carousel.noConflict = function () { 466 | $.fn.carousel = old 467 | return this 468 | } 469 | 470 | 471 | // CAROUSEL DATA-API 472 | // ================= 473 | 474 | $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { 475 | var $this = $(this), href 476 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 477 | var options = $.extend({}, $target.data(), $this.data()) 478 | var slideIndex = $this.attr('data-slide-to') 479 | if (slideIndex) options.interval = false 480 | 481 | $target.carousel(options) 482 | 483 | if (slideIndex = $this.attr('data-slide-to')) { 484 | $target.data('bs.carousel').to(slideIndex) 485 | } 486 | 487 | e.preventDefault() 488 | }) 489 | 490 | $(window).on('load', function () { 491 | $('[data-ride="carousel"]').each(function () { 492 | var $carousel = $(this) 493 | $carousel.carousel($carousel.data()) 494 | }) 495 | }) 496 | 497 | }(jQuery); 498 | 499 | /* ======================================================================== 500 | * Bootstrap: collapse.js v3.0.3 501 | * http://getbootstrap.com/javascript/#collapse 502 | * ======================================================================== 503 | * Copyright 2013 Twitter, Inc. 504 | * 505 | * Licensed under the Apache License, Version 2.0 (the "License"); 506 | * you may not use this file except in compliance with the License. 507 | * You may obtain a copy of the License at 508 | * 509 | * http://www.apache.org/licenses/LICENSE-2.0 510 | * 511 | * Unless required by applicable law or agreed to in writing, software 512 | * distributed under the License is distributed on an "AS IS" BASIS, 513 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 514 | * See the License for the specific language governing permissions and 515 | * limitations under the License. 516 | * ======================================================================== */ 517 | 518 | 519 | +function ($) { "use strict"; 520 | 521 | // COLLAPSE PUBLIC CLASS DEFINITION 522 | // ================================ 523 | 524 | var Collapse = function (element, options) { 525 | this.$element = $(element) 526 | this.options = $.extend({}, Collapse.DEFAULTS, options) 527 | this.transitioning = null 528 | 529 | if (this.options.parent) this.$parent = $(this.options.parent) 530 | if (this.options.toggle) this.toggle() 531 | } 532 | 533 | Collapse.DEFAULTS = { 534 | toggle: true 535 | } 536 | 537 | Collapse.prototype.dimension = function () { 538 | var hasWidth = this.$element.hasClass('width') 539 | return hasWidth ? 'width' : 'height' 540 | } 541 | 542 | Collapse.prototype.show = function () { 543 | if (this.transitioning || this.$element.hasClass('in')) return 544 | 545 | var startEvent = $.Event('show.bs.collapse') 546 | this.$element.trigger(startEvent) 547 | if (startEvent.isDefaultPrevented()) return 548 | 549 | var actives = this.$parent && this.$parent.find('> .panel > .in') 550 | 551 | if (actives && actives.length) { 552 | var hasData = actives.data('bs.collapse') 553 | if (hasData && hasData.transitioning) return 554 | actives.collapse('hide') 555 | hasData || actives.data('bs.collapse', null) 556 | } 557 | 558 | var dimension = this.dimension() 559 | 560 | this.$element 561 | .removeClass('collapse') 562 | .addClass('collapsing') 563 | [dimension](0) 564 | 565 | this.transitioning = 1 566 | 567 | var complete = function () { 568 | this.$element 569 | .removeClass('collapsing') 570 | .addClass('in') 571 | [dimension]('auto') 572 | this.transitioning = 0 573 | this.$element.trigger('shown.bs.collapse') 574 | } 575 | 576 | if (!$.support.transition) return complete.call(this) 577 | 578 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 579 | 580 | this.$element 581 | .one($.support.transition.end, $.proxy(complete, this)) 582 | .emulateTransitionEnd(350) 583 | [dimension](this.$element[0][scrollSize]) 584 | } 585 | 586 | Collapse.prototype.hide = function () { 587 | if (this.transitioning || !this.$element.hasClass('in')) return 588 | 589 | var startEvent = $.Event('hide.bs.collapse') 590 | this.$element.trigger(startEvent) 591 | if (startEvent.isDefaultPrevented()) return 592 | 593 | var dimension = this.dimension() 594 | 595 | this.$element 596 | [dimension](this.$element[dimension]()) 597 | [0].offsetHeight 598 | 599 | this.$element 600 | .addClass('collapsing') 601 | .removeClass('collapse') 602 | .removeClass('in') 603 | 604 | this.transitioning = 1 605 | 606 | var complete = function () { 607 | this.transitioning = 0 608 | this.$element 609 | .trigger('hidden.bs.collapse') 610 | .removeClass('collapsing') 611 | .addClass('collapse') 612 | } 613 | 614 | if (!$.support.transition) return complete.call(this) 615 | 616 | this.$element 617 | [dimension](0) 618 | .one($.support.transition.end, $.proxy(complete, this)) 619 | .emulateTransitionEnd(350) 620 | } 621 | 622 | Collapse.prototype.toggle = function () { 623 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 624 | } 625 | 626 | 627 | // COLLAPSE PLUGIN DEFINITION 628 | // ========================== 629 | 630 | var old = $.fn.collapse 631 | 632 | $.fn.collapse = function (option) { 633 | return this.each(function () { 634 | var $this = $(this) 635 | var data = $this.data('bs.collapse') 636 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 637 | 638 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 639 | if (typeof option == 'string') data[option]() 640 | }) 641 | } 642 | 643 | $.fn.collapse.Constructor = Collapse 644 | 645 | 646 | // COLLAPSE NO CONFLICT 647 | // ==================== 648 | 649 | $.fn.collapse.noConflict = function () { 650 | $.fn.collapse = old 651 | return this 652 | } 653 | 654 | 655 | // COLLAPSE DATA-API 656 | // ================= 657 | 658 | $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { 659 | var $this = $(this), href 660 | var target = $this.attr('data-target') 661 | || e.preventDefault() 662 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 663 | var $target = $(target) 664 | var data = $target.data('bs.collapse') 665 | var option = data ? 'toggle' : $this.data() 666 | var parent = $this.attr('data-parent') 667 | var $parent = parent && $(parent) 668 | 669 | if (!data || !data.transitioning) { 670 | if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') 671 | $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 672 | } 673 | 674 | $target.collapse(option) 675 | }) 676 | 677 | }(jQuery); 678 | 679 | /* ======================================================================== 680 | * Bootstrap: dropdown.js v3.0.3 681 | * http://getbootstrap.com/javascript/#dropdowns 682 | * ======================================================================== 683 | * Copyright 2013 Twitter, Inc. 684 | * 685 | * Licensed under the Apache License, Version 2.0 (the "License"); 686 | * you may not use this file except in compliance with the License. 687 | * You may obtain a copy of the License at 688 | * 689 | * http://www.apache.org/licenses/LICENSE-2.0 690 | * 691 | * Unless required by applicable law or agreed to in writing, software 692 | * distributed under the License is distributed on an "AS IS" BASIS, 693 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 694 | * See the License for the specific language governing permissions and 695 | * limitations under the License. 696 | * ======================================================================== */ 697 | 698 | 699 | !function ($) { 700 | 701 | "use strict"; // jshint ;_; 702 | 703 | 704 | /* DROPDOWN CLASS DEFINITION 705 | * ========================= */ 706 | 707 | var toggle = '[data-toggle=dropdown]' 708 | , Dropdown = function (element) { 709 | var $el = $(element).on('click.dropdown.data-api', this.toggle) 710 | $('html').on('click.dropdown.data-api', function () { 711 | $el.parent().removeClass('open') 712 | }) 713 | } 714 | 715 | Dropdown.prototype = { 716 | 717 | constructor: Dropdown 718 | 719 | , toggle: function (e) { 720 | var $this = $(this) 721 | , $parent 722 | , isActive 723 | 724 | if ($this.is('.disabled, :disabled')) return 725 | 726 | $parent = getParent($this) 727 | 728 | isActive = $parent.hasClass('open') 729 | 730 | clearMenus() 731 | 732 | if (!isActive) { 733 | if ('ontouchstart' in document.documentElement) { 734 | // if mobile we we use a backdrop because click events don't delegate 735 | $('