├── LICENSE ├── README.md ├── bootstrap ├── bootstrap.css ├── bootstrap.css.map └── bootstrap.js ├── css └── app.css ├── index.html ├── js ├── README.md ├── angular-cookie.min.js ├── angular-ui-router.min.js ├── angular.js ├── app.js ├── jquery.min.js └── ng-ckeditor.js └── partials ├── createAccountModal.html ├── main.html └── navbar.html /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Scotho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | What's it do? 3 | --------------------- 4 | *Firebased was designed to be a starting point for any AngularFire (AngularJS+Firebase) web application. Here are a few feature highlights...* 5 | 6 | - Account handling (includes cookie session storage) 7 | - [Dead simple three way data binding](https://www.firebase.com/blog/2013-10-04-firebase-angular-data-binding.html) on user-specific arrays. *(Confused? Open 2 demo pages simultaneously and modify some text)* 8 | - A functional and responsive bootstrap template 9 | - Implements a wide range of Angular, Firebase, and MVC concepts out of the box. 10 | 11 | Depends on [Bootstrap](http://getbootstrap.com/), [jQuery](https://jquery.com/), [firebase](https://www.firebase.com/), [angularfire](https://www.firebase.com/docs/web/libraries/angular/), and [angular-cookie](https://github.com/ivpusic/angular-cookie) 12 | 13 | [Click here to see the demo](http://craigryansmith.com/firebased/) 14 | 15 | 16 | How do I get started? 17 | --------------------- 18 | *To get started, simply change "appName" at the top of app.js to your [firebase](https://www.firebase.com) appName and run index.html. Currently, all logic is contained in the controllers found in app.js* 19 | 20 | - Please note that this is a beta version of which is still under developmet. Any and all contributions are greatly appreciated! 21 | 22 | *Documentation coming soon!* 23 | 24 | -------------------------------------------------------------------------------- /bootstrap/bootstrap.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.2 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | if (typeof jQuery === 'undefined') { 8 | throw new Error('Bootstrap\'s JavaScript requires jQuery') 9 | } 10 | 11 | +function ($) { 12 | 'use strict'; 13 | var version = $.fn.jquery.split(' ')[0].split('.') 14 | if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { 15 | throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') 16 | } 17 | }(jQuery); 18 | 19 | /* ======================================================================== 20 | * Bootstrap: transition.js v3.3.2 21 | * http://getbootstrap.com/javascript/#transitions 22 | * ======================================================================== 23 | * Copyright 2011-2015 Twitter, Inc. 24 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 25 | * ======================================================================== */ 26 | 27 | 28 | +function ($) { 29 | '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 | return false // explicit for ie8 ( ._.) 51 | } 52 | 53 | // http://blog.alexmaccaw.com/css-transitions 54 | $.fn.emulateTransitionEnd = function (duration) { 55 | var called = false 56 | var $el = this 57 | $(this).one('bsTransitionEnd', function () { called = true }) 58 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 59 | setTimeout(callback, duration) 60 | return this 61 | } 62 | 63 | $(function () { 64 | $.support.transition = transitionEnd() 65 | 66 | if (!$.support.transition) return 67 | 68 | $.event.special.bsTransitionEnd = { 69 | bindType: $.support.transition.end, 70 | delegateType: $.support.transition.end, 71 | handle: function (e) { 72 | if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 73 | } 74 | } 75 | }) 76 | 77 | }(jQuery); 78 | 79 | /* ======================================================================== 80 | * Bootstrap: alert.js v3.3.2 81 | * http://getbootstrap.com/javascript/#alerts 82 | * ======================================================================== 83 | * Copyright 2011-2015 Twitter, Inc. 84 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 85 | * ======================================================================== */ 86 | 87 | 88 | +function ($) { 89 | 'use strict'; 90 | 91 | // ALERT CLASS DEFINITION 92 | // ====================== 93 | 94 | var dismiss = '[data-dismiss="alert"]' 95 | var Alert = function (el) { 96 | $(el).on('click', dismiss, this.close) 97 | } 98 | 99 | Alert.VERSION = '3.3.2' 100 | 101 | Alert.TRANSITION_DURATION = 150 102 | 103 | Alert.prototype.close = function (e) { 104 | var $this = $(this) 105 | var selector = $this.attr('data-target') 106 | 107 | if (!selector) { 108 | selector = $this.attr('href') 109 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 110 | } 111 | 112 | var $parent = $(selector) 113 | 114 | if (e) e.preventDefault() 115 | 116 | if (!$parent.length) { 117 | $parent = $this.closest('.alert') 118 | } 119 | 120 | $parent.trigger(e = $.Event('close.bs.alert')) 121 | 122 | if (e.isDefaultPrevented()) return 123 | 124 | $parent.removeClass('in') 125 | 126 | function removeElement() { 127 | // detach from parent, fire event then clean up data 128 | $parent.detach().trigger('closed.bs.alert').remove() 129 | } 130 | 131 | $.support.transition && $parent.hasClass('fade') ? 132 | $parent 133 | .one('bsTransitionEnd', removeElement) 134 | .emulateTransitionEnd(Alert.TRANSITION_DURATION) : 135 | removeElement() 136 | } 137 | 138 | 139 | // ALERT PLUGIN DEFINITION 140 | // ======================= 141 | 142 | function Plugin(option) { 143 | return this.each(function () { 144 | var $this = $(this) 145 | var data = $this.data('bs.alert') 146 | 147 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 148 | if (typeof option == 'string') data[option].call($this) 149 | }) 150 | } 151 | 152 | var old = $.fn.alert 153 | 154 | $.fn.alert = Plugin 155 | $.fn.alert.Constructor = Alert 156 | 157 | 158 | // ALERT NO CONFLICT 159 | // ================= 160 | 161 | $.fn.alert.noConflict = function () { 162 | $.fn.alert = old 163 | return this 164 | } 165 | 166 | 167 | // ALERT DATA-API 168 | // ============== 169 | 170 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 171 | 172 | }(jQuery); 173 | 174 | /* ======================================================================== 175 | * Bootstrap: button.js v3.3.2 176 | * http://getbootstrap.com/javascript/#buttons 177 | * ======================================================================== 178 | * Copyright 2011-2015 Twitter, Inc. 179 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 180 | * ======================================================================== */ 181 | 182 | 183 | +function ($) { 184 | 'use strict'; 185 | 186 | // BUTTON PUBLIC CLASS DEFINITION 187 | // ============================== 188 | 189 | var Button = function (element, options) { 190 | this.$element = $(element) 191 | this.options = $.extend({}, Button.DEFAULTS, options) 192 | this.isLoading = false 193 | } 194 | 195 | Button.VERSION = '3.3.2' 196 | 197 | Button.DEFAULTS = { 198 | loadingText: 'loading...' 199 | } 200 | 201 | Button.prototype.setState = function (state) { 202 | var d = 'disabled' 203 | var $el = this.$element 204 | var val = $el.is('input') ? 'val' : 'html' 205 | var data = $el.data() 206 | 207 | state = state + 'Text' 208 | 209 | if (data.resetText == null) $el.data('resetText', $el[val]()) 210 | 211 | // push to event loop to allow forms to submit 212 | setTimeout($.proxy(function () { 213 | $el[val](data[state] == null ? this.options[state] : data[state]) 214 | 215 | if (state == 'loadingText') { 216 | this.isLoading = true 217 | $el.addClass(d).attr(d, d) 218 | } else if (this.isLoading) { 219 | this.isLoading = false 220 | $el.removeClass(d).removeAttr(d) 221 | } 222 | }, this), 0) 223 | } 224 | 225 | Button.prototype.toggle = function () { 226 | var changed = true 227 | var $parent = this.$element.closest('[data-toggle="buttons"]') 228 | 229 | if ($parent.length) { 230 | var $input = this.$element.find('input') 231 | if ($input.prop('type') == 'radio') { 232 | if ($input.prop('checked') && this.$element.hasClass('active')) changed = false 233 | else $parent.find('.active').removeClass('active') 234 | } 235 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 236 | } else { 237 | this.$element.attr('aria-pressed', !this.$element.hasClass('active')) 238 | } 239 | 240 | if (changed) this.$element.toggleClass('active') 241 | } 242 | 243 | 244 | // BUTTON PLUGIN DEFINITION 245 | // ======================== 246 | 247 | function Plugin(option) { 248 | return this.each(function () { 249 | var $this = $(this) 250 | var data = $this.data('bs.button') 251 | var options = typeof option == 'object' && option 252 | 253 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 254 | 255 | if (option == 'toggle') data.toggle() 256 | else if (option) data.setState(option) 257 | }) 258 | } 259 | 260 | var old = $.fn.button 261 | 262 | $.fn.button = Plugin 263 | $.fn.button.Constructor = Button 264 | 265 | 266 | // BUTTON NO CONFLICT 267 | // ================== 268 | 269 | $.fn.button.noConflict = function () { 270 | $.fn.button = old 271 | return this 272 | } 273 | 274 | 275 | // BUTTON DATA-API 276 | // =============== 277 | 278 | $(document) 279 | .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 280 | var $btn = $(e.target) 281 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 282 | Plugin.call($btn, 'toggle') 283 | e.preventDefault() 284 | }) 285 | .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { 286 | $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) 287 | }) 288 | 289 | }(jQuery); 290 | 291 | /* ======================================================================== 292 | * Bootstrap: carousel.js v3.3.2 293 | * http://getbootstrap.com/javascript/#carousel 294 | * ======================================================================== 295 | * Copyright 2011-2015 Twitter, Inc. 296 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 297 | * ======================================================================== */ 298 | 299 | 300 | +function ($) { 301 | '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.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) 317 | 318 | this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element 319 | .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) 320 | .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) 321 | } 322 | 323 | Carousel.VERSION = '3.3.2' 324 | 325 | Carousel.TRANSITION_DURATION = 600 326 | 327 | Carousel.DEFAULTS = { 328 | interval: 5000, 329 | pause: 'hover', 330 | wrap: true, 331 | keyboard: true 332 | } 333 | 334 | Carousel.prototype.keydown = function (e) { 335 | if (/input|textarea/i.test(e.target.tagName)) return 336 | switch (e.which) { 337 | case 37: this.prev(); break 338 | case 39: this.next(); break 339 | default: return 340 | } 341 | 342 | e.preventDefault() 343 | } 344 | 345 | Carousel.prototype.cycle = function (e) { 346 | e || (this.paused = false) 347 | 348 | this.interval && clearInterval(this.interval) 349 | 350 | this.options.interval 351 | && !this.paused 352 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 353 | 354 | return this 355 | } 356 | 357 | Carousel.prototype.getItemIndex = function (item) { 358 | this.$items = item.parent().children('.item') 359 | return this.$items.index(item || this.$active) 360 | } 361 | 362 | Carousel.prototype.getItemForDirection = function (direction, active) { 363 | var activeIndex = this.getItemIndex(active) 364 | var willWrap = (direction == 'prev' && activeIndex === 0) 365 | || (direction == 'next' && activeIndex == (this.$items.length - 1)) 366 | if (willWrap && !this.options.wrap) return active 367 | var delta = direction == 'prev' ? -1 : 1 368 | var itemIndex = (activeIndex + delta) % this.$items.length 369 | return this.$items.eq(itemIndex) 370 | } 371 | 372 | Carousel.prototype.to = function (pos) { 373 | var that = this 374 | var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) 375 | 376 | if (pos > (this.$items.length - 1) || pos < 0) return 377 | 378 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" 379 | if (activeIndex == pos) return this.pause().cycle() 380 | 381 | return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) 382 | } 383 | 384 | Carousel.prototype.pause = function (e) { 385 | e || (this.paused = true) 386 | 387 | if (this.$element.find('.next, .prev').length && $.support.transition) { 388 | this.$element.trigger($.support.transition.end) 389 | this.cycle(true) 390 | } 391 | 392 | this.interval = clearInterval(this.interval) 393 | 394 | return this 395 | } 396 | 397 | Carousel.prototype.next = function () { 398 | if (this.sliding) return 399 | return this.slide('next') 400 | } 401 | 402 | Carousel.prototype.prev = function () { 403 | if (this.sliding) return 404 | return this.slide('prev') 405 | } 406 | 407 | Carousel.prototype.slide = function (type, next) { 408 | var $active = this.$element.find('.item.active') 409 | var $next = next || this.getItemForDirection(type, $active) 410 | var isCycling = this.interval 411 | var direction = type == 'next' ? 'left' : 'right' 412 | var that = this 413 | 414 | if ($next.hasClass('active')) return (this.sliding = false) 415 | 416 | var relatedTarget = $next[0] 417 | var slideEvent = $.Event('slide.bs.carousel', { 418 | relatedTarget: relatedTarget, 419 | direction: direction 420 | }) 421 | this.$element.trigger(slideEvent) 422 | if (slideEvent.isDefaultPrevented()) return 423 | 424 | this.sliding = true 425 | 426 | isCycling && this.pause() 427 | 428 | if (this.$indicators.length) { 429 | this.$indicators.find('.active').removeClass('active') 430 | var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) 431 | $nextIndicator && $nextIndicator.addClass('active') 432 | } 433 | 434 | var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" 435 | if ($.support.transition && this.$element.hasClass('slide')) { 436 | $next.addClass(type) 437 | $next[0].offsetWidth // force reflow 438 | $active.addClass(direction) 439 | $next.addClass(direction) 440 | $active 441 | .one('bsTransitionEnd', function () { 442 | $next.removeClass([type, direction].join(' ')).addClass('active') 443 | $active.removeClass(['active', direction].join(' ')) 444 | that.sliding = false 445 | setTimeout(function () { 446 | that.$element.trigger(slidEvent) 447 | }, 0) 448 | }) 449 | .emulateTransitionEnd(Carousel.TRANSITION_DURATION) 450 | } else { 451 | $active.removeClass('active') 452 | $next.addClass('active') 453 | this.sliding = false 454 | this.$element.trigger(slidEvent) 455 | } 456 | 457 | isCycling && this.cycle() 458 | 459 | return this 460 | } 461 | 462 | 463 | // CAROUSEL PLUGIN DEFINITION 464 | // ========================== 465 | 466 | function Plugin(option) { 467 | return this.each(function () { 468 | var $this = $(this) 469 | var data = $this.data('bs.carousel') 470 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 471 | var action = typeof option == 'string' ? option : options.slide 472 | 473 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 474 | if (typeof option == 'number') data.to(option) 475 | else if (action) data[action]() 476 | else if (options.interval) data.pause().cycle() 477 | }) 478 | } 479 | 480 | var old = $.fn.carousel 481 | 482 | $.fn.carousel = Plugin 483 | $.fn.carousel.Constructor = Carousel 484 | 485 | 486 | // CAROUSEL NO CONFLICT 487 | // ==================== 488 | 489 | $.fn.carousel.noConflict = function () { 490 | $.fn.carousel = old 491 | return this 492 | } 493 | 494 | 495 | // CAROUSEL DATA-API 496 | // ================= 497 | 498 | var clickHandler = function (e) { 499 | var href 500 | var $this = $(this) 501 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 502 | if (!$target.hasClass('carousel')) return 503 | var options = $.extend({}, $target.data(), $this.data()) 504 | var slideIndex = $this.attr('data-slide-to') 505 | if (slideIndex) options.interval = false 506 | 507 | Plugin.call($target, options) 508 | 509 | if (slideIndex) { 510 | $target.data('bs.carousel').to(slideIndex) 511 | } 512 | 513 | e.preventDefault() 514 | } 515 | 516 | $(document) 517 | .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) 518 | .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) 519 | 520 | $(window).on('load', function () { 521 | $('[data-ride="carousel"]').each(function () { 522 | var $carousel = $(this) 523 | Plugin.call($carousel, $carousel.data()) 524 | }) 525 | }) 526 | 527 | }(jQuery); 528 | 529 | /* ======================================================================== 530 | * Bootstrap: collapse.js v3.3.2 531 | * http://getbootstrap.com/javascript/#collapse 532 | * ======================================================================== 533 | * Copyright 2011-2015 Twitter, Inc. 534 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 535 | * ======================================================================== */ 536 | 537 | 538 | +function ($) { 539 | 'use strict'; 540 | 541 | // COLLAPSE PUBLIC CLASS DEFINITION 542 | // ================================ 543 | 544 | var Collapse = function (element, options) { 545 | this.$element = $(element) 546 | this.options = $.extend({}, Collapse.DEFAULTS, options) 547 | this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]') 548 | this.transitioning = null 549 | 550 | if (this.options.parent) { 551 | this.$parent = this.getParent() 552 | } else { 553 | this.addAriaAndCollapsedClass(this.$element, this.$trigger) 554 | } 555 | 556 | if (this.options.toggle) this.toggle() 557 | } 558 | 559 | Collapse.VERSION = '3.3.2' 560 | 561 | Collapse.TRANSITION_DURATION = 350 562 | 563 | Collapse.DEFAULTS = { 564 | toggle: true, 565 | trigger: '[data-toggle="collapse"]' 566 | } 567 | 568 | Collapse.prototype.dimension = function () { 569 | var hasWidth = this.$element.hasClass('width') 570 | return hasWidth ? 'width' : 'height' 571 | } 572 | 573 | Collapse.prototype.show = function () { 574 | if (this.transitioning || this.$element.hasClass('in')) return 575 | 576 | var activesData 577 | var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') 578 | 579 | if (actives && actives.length) { 580 | activesData = actives.data('bs.collapse') 581 | if (activesData && activesData.transitioning) return 582 | } 583 | 584 | var startEvent = $.Event('show.bs.collapse') 585 | this.$element.trigger(startEvent) 586 | if (startEvent.isDefaultPrevented()) return 587 | 588 | if (actives && actives.length) { 589 | Plugin.call(actives, 'hide') 590 | activesData || actives.data('bs.collapse', null) 591 | } 592 | 593 | var dimension = this.dimension() 594 | 595 | this.$element 596 | .removeClass('collapse') 597 | .addClass('collapsing')[dimension](0) 598 | .attr('aria-expanded', true) 599 | 600 | this.$trigger 601 | .removeClass('collapsed') 602 | .attr('aria-expanded', true) 603 | 604 | this.transitioning = 1 605 | 606 | var complete = function () { 607 | this.$element 608 | .removeClass('collapsing') 609 | .addClass('collapse in')[dimension]('') 610 | this.transitioning = 0 611 | this.$element 612 | .trigger('shown.bs.collapse') 613 | } 614 | 615 | if (!$.support.transition) return complete.call(this) 616 | 617 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 618 | 619 | this.$element 620 | .one('bsTransitionEnd', $.proxy(complete, this)) 621 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) 622 | } 623 | 624 | Collapse.prototype.hide = function () { 625 | if (this.transitioning || !this.$element.hasClass('in')) return 626 | 627 | var startEvent = $.Event('hide.bs.collapse') 628 | this.$element.trigger(startEvent) 629 | if (startEvent.isDefaultPrevented()) return 630 | 631 | var dimension = this.dimension() 632 | 633 | this.$element[dimension](this.$element[dimension]())[0].offsetHeight 634 | 635 | this.$element 636 | .addClass('collapsing') 637 | .removeClass('collapse in') 638 | .attr('aria-expanded', false) 639 | 640 | this.$trigger 641 | .addClass('collapsed') 642 | .attr('aria-expanded', false) 643 | 644 | this.transitioning = 1 645 | 646 | var complete = function () { 647 | this.transitioning = 0 648 | this.$element 649 | .removeClass('collapsing') 650 | .addClass('collapse') 651 | .trigger('hidden.bs.collapse') 652 | } 653 | 654 | if (!$.support.transition) return complete.call(this) 655 | 656 | this.$element 657 | [dimension](0) 658 | .one('bsTransitionEnd', $.proxy(complete, this)) 659 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION) 660 | } 661 | 662 | Collapse.prototype.toggle = function () { 663 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 664 | } 665 | 666 | Collapse.prototype.getParent = function () { 667 | return $(this.options.parent) 668 | .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') 669 | .each($.proxy(function (i, element) { 670 | var $element = $(element) 671 | this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) 672 | }, this)) 673 | .end() 674 | } 675 | 676 | Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { 677 | var isOpen = $element.hasClass('in') 678 | 679 | $element.attr('aria-expanded', isOpen) 680 | $trigger 681 | .toggleClass('collapsed', !isOpen) 682 | .attr('aria-expanded', isOpen) 683 | } 684 | 685 | function getTargetFromTrigger($trigger) { 686 | var href 687 | var target = $trigger.attr('data-target') 688 | || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 689 | 690 | return $(target) 691 | } 692 | 693 | 694 | // COLLAPSE PLUGIN DEFINITION 695 | // ========================== 696 | 697 | function Plugin(option) { 698 | return this.each(function () { 699 | var $this = $(this) 700 | var data = $this.data('bs.collapse') 701 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 702 | 703 | if (!data && options.toggle && option == 'show') options.toggle = false 704 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 705 | if (typeof option == 'string') data[option]() 706 | }) 707 | } 708 | 709 | var old = $.fn.collapse 710 | 711 | $.fn.collapse = Plugin 712 | $.fn.collapse.Constructor = Collapse 713 | 714 | 715 | // COLLAPSE NO CONFLICT 716 | // ==================== 717 | 718 | $.fn.collapse.noConflict = function () { 719 | $.fn.collapse = old 720 | return this 721 | } 722 | 723 | 724 | // COLLAPSE DATA-API 725 | // ================= 726 | 727 | $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 728 | var $this = $(this) 729 | 730 | if (!$this.attr('data-target')) e.preventDefault() 731 | 732 | var $target = getTargetFromTrigger($this) 733 | var data = $target.data('bs.collapse') 734 | var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this }) 735 | 736 | Plugin.call($target, option) 737 | }) 738 | 739 | }(jQuery); 740 | 741 | /* ======================================================================== 742 | * Bootstrap: dropdown.js v3.3.2 743 | * http://getbootstrap.com/javascript/#dropdowns 744 | * ======================================================================== 745 | * Copyright 2011-2015 Twitter, Inc. 746 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 747 | * ======================================================================== */ 748 | 749 | 750 | +function ($) { 751 | 'use strict'; 752 | 753 | // DROPDOWN CLASS DEFINITION 754 | // ========================= 755 | 756 | var backdrop = '.dropdown-backdrop' 757 | var toggle = '[data-toggle="dropdown"]' 758 | var Dropdown = function (element) { 759 | $(element).on('click.bs.dropdown', this.toggle) 760 | } 761 | 762 | Dropdown.VERSION = '3.3.2' 763 | 764 | Dropdown.prototype.toggle = function (e) { 765 | var $this = $(this) 766 | 767 | if ($this.is('.disabled, :disabled')) return 768 | 769 | var $parent = getParent($this) 770 | var isActive = $parent.hasClass('open') 771 | 772 | clearMenus() 773 | 774 | if (!isActive) { 775 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 776 | // if mobile we use a backdrop because click events don't delegate 777 | $('