aboutsummaryrefslogtreecommitdiff
path: root/dist
diff options
context:
space:
mode:
authorF A T <[email protected]>2015-02-11 11:36:16 -0800
committerF A T <[email protected]>2015-02-11 11:36:16 -0800
commitf483640378c8dfe7fd41f7743dc43d8ad0ea8b1b (patch)
tree19bfdadb0c140df437e7b7034e5e1f5ce58343cc /dist
parentaed1cd31218113d67d2eca3296edf5d1700b19b8 (diff)
parent834220ea20ce5b7cd31edfb624a28b4bf8b29a6a (diff)
downloadbootstrap-f483640378c8dfe7fd41f7743dc43d8ad0ea8b1b.tar.xz
bootstrap-f483640378c8dfe7fd41f7743dc43d8ad0ea8b1b.zip
Merge pull request #57 from twbs/fat-closure
Bootstrap onto closure v2
Diffstat (limited to 'dist')
-rw-r--r--dist/js/bootstrap.js5449
-rw-r--r--dist/js/bootstrap.min.js74
-rw-r--r--dist/js/bootstrap.min.js.gzbin0 -> 10652 bytes
-rw-r--r--dist/js/npm.js8
4 files changed, 3938 insertions, 1593 deletions
diff --git a/dist/js/bootstrap.js b/dist/js/bootstrap.js
index 584fe3ba2..5d3f63040 100644
--- a/dist/js/bootstrap.js
+++ b/dist/js/bootstrap.js
@@ -15,2291 +15,4566 @@ if (typeof jQuery === 'undefined') {
}
}(jQuery);
-/* ========================================================================
- * Bootstrap: transition.js v3.3.2
- * http://getbootstrap.com/javascript/#transitions
+/** =======================================================================
+ * Bootstrap: util.js v4.0.0
+ * http://getbootstrap.com/javascript/#alerts
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Bootstrap's private util helper. Adds private util
+ * helpers for things like accesibility and transitions. These methods are
+ * shared across all bootstrap plugins.
+ * ========================================================================
+ */
+'use strict';
-+function ($) {
- 'use strict';
- // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
- // ============================================================
+/**
+ * @type {Object}
+ */
+var Bootstrap = {}
- function transitionEnd() {
- var el = document.createElement('bootstrap')
- var transEndEventNames = {
- WebkitTransition : 'webkitTransitionEnd',
- MozTransition : 'transitionend',
- OTransition : 'oTransitionEnd otransitionend',
- transition : 'transitionend'
- }
+/**
+ * @const
+ * @type {string}
+ */
+Bootstrap.TRANSITION_END = 'bsTransitionEnd'
- for (var name in transEndEventNames) {
- if (el.style[name] !== undefined) {
- return { end: transEndEventNames[name] }
- }
- }
- return false // explicit for ie8 ( ._.)
- }
+/**
+ * @const
+ * @type {Object}
+ */
+Bootstrap.TransitionEndEvent = {
+ 'WebkitTransition' : 'webkitTransitionEnd',
+ 'MozTransition' : 'transitionend',
+ 'OTransition' : 'oTransitionEnd otransitionend',
+ 'transition' : 'transitionend'
+}
+
+
+/**
+ * @param {Function} childConstructor
+ * @param {Function} parentConstructor
+ */
+Bootstrap.inherits = function(childConstructor, parentConstructor) {
+ /** @constructor */
+ function tempConstructor() {}
+ tempConstructor.prototype = parentConstructor.prototype
+ childConstructor.prototype = new tempConstructor()
+ /** @override */
+ childConstructor.prototype.constructor = childConstructor
+}
+
+
+/**
+ * @param {Element} element
+ * @return {string|null}
+ */
+Bootstrap.getSelectorFromElement = function (element) {
+ var selector = element.getAttribute('data-target')
- // http://blog.alexmaccaw.com/css-transitions
- $.fn.emulateTransitionEnd = function (duration) {
- var called = false
- var $el = this
- $(this).one('bsTransitionEnd', function () { called = true })
- var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
- setTimeout(callback, duration)
- return this
+ if (!selector) {
+ selector = element.getAttribute('href') || ''
+ selector = /^#[a-z]/i.test(selector) ? selector : null
}
- $(function () {
- $.support.transition = transitionEnd()
+ return selector
+}
+
+
+/**
+ * @param {string} prefix
+ * @return {string}
+ */
+Bootstrap.getUID = function (prefix) {
+ do prefix += ~~(Math.random() * 1000000)
+ while (document.getElementById(prefix))
+ return prefix
+}
- if (!$.support.transition) return
- $.event.special.bsTransitionEnd = {
- bindType: $.support.transition.end,
- delegateType: $.support.transition.end,
- handle: function (e) {
- if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
+/**
+ * @return {Object}
+ */
+Bootstrap.getSpecialTransitionEndEvent = function () {
+ return {
+ bindType: Bootstrap.transition.end,
+ delegateType: Bootstrap.transition.end,
+ handle: /** @param {jQuery.Event} event */ (function (event) {
+ if ($(event.target).is(this)) {
+ return event.handleObj.handler.apply(this, arguments)
}
+ })
+ }
+}
+
+
+/**
+ * @param {Element} element
+ */
+Bootstrap.reflow = function (element) {
+ new Function('bs',"return bs")(element.offsetHeight)
+}
+
+
+/**
+ * @return {Object|boolean}
+ */
+Bootstrap.transitionEndTest = function () {
+ if (window['QUnit']) {
+ return false
+ }
+
+ var el = document.createElement('bootstrap')
+ for (var name in Bootstrap.TransitionEndEvent) {
+ if (el.style[name] !== undefined) {
+ return { end: Bootstrap.TransitionEndEvent[name] }
}
+ }
+ return false
+}
+
+
+/**
+ * @param {number} duration
+ * @this {Element}
+ * @return {Object}
+ */
+Bootstrap.transitionEndEmulator = function (duration) {
+ var called = false
+
+ $(this).one(Bootstrap.TRANSITION_END, function () {
+ called = true
})
-}(jQuery);
+ var callback = function () {
+ if (!called) {
+ $(this).trigger(Bootstrap.transition.end)
+ }
+ }.bind(this)
+
+ setTimeout(callback, duration)
+
+ return this
+}
+
+
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface
+ * ------------------------------------------------------------------------
+ */
+
+$.fn.emulateTransitionEnd = Bootstrap.transitionEndEmulator
+
+$(function () {
+ Bootstrap.transition = Bootstrap.transitionEndTest()
+
+ if (!Bootstrap.transition) {
+ return
+ }
-/* ========================================================================
- * Bootstrap: alert.js v3.3.2
+ $.event.special[Bootstrap.TRANSITION_END] = Bootstrap.getSpecialTransitionEndEvent()
+})
+
+$(document).on('mq4hsChange', function (e) {
+ $(document.documentElement).toggleClass('bs-true-hover', e.trueHover)
+})
+
+/*!
+ * mq4-hover-shim v0.1.0
+ * https://github.com/twbs/mq4-hover-shim
+ * Copyright (c) 2014-2015 Christopher Rebert
+ * Licensed under the MIT License (https://github.com/twbs/mq4-hover-shim/blob/master/LICENSE).
+ */
+
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.mq4HoverShim=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+"use strict";
+
+var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { "default": obj }; };
+
+
+
+
+/**
+* Does this UA's primary pointer support true hovering
+* OR does the UA at least not try to quirkily emulate hovering,
+* such that :hover CSS styles are appropriate?
+* Essentially tries to shim the `@media (hover: hover)` CSS media query feature.
+* @public
+* @returns {boolean}
+* @since 0.0.1
+*/
+exports.supportsTrueHover = supportsTrueHover;
+/*eslint-env browser */
+/*eslint no-var:2*/
+/* jshint browser: true, esnext: true */
+/* jshint -W080 */
+/**
+* @module mq4HoverShim
+* @requires jquery
+*/
+var $ = (function () {
+ try {
+ var jQuery = _interopRequireWildcard(require("jquery"));
+
+ return jQuery;
+ } catch (importErr) {
+ var globaljQuery = window.$ || window.jQuery || window.Zepto;
+ if (!globaljQuery) {
+ throw new Error("mq4HoverShim needs jQuery (or similar)");
+ }
+ return globaljQuery;
+ }
+})();
+
+/** @type {boolean|undefined} */
+var canTrulyHover = undefined;
+
+/**
+* @private
+* @fires mq4HoverShim#mq4hsChange
+*/
+function triggerEvent() {
+ $(document).trigger($.Event("mq4hsChange", { bubbles: false, trueHover: canTrulyHover }));
+}
+
+// IIFE so we can use `return`s to avoid deeply-nested if-s
+(function () {
+ if (!window.matchMedia) {
+ // Opera Mini, IE<=9, Android<=2.3, ancient, or obscure; per http://caniuse.com/#feat=matchmedia
+
+ // Opera Mini, Android, and IE Mobile don't support true hovering, so they're what we'll check for.
+ // Other browsers are either:
+ // (a) obscure
+ // (b) touch-based but old enough not to attempt to emulate hovering
+ // (c) old desktop browsers that do support true hovering
+
+ // Explanation of this UA regex:
+ // IE Mobile <9 seems to always have "Windows CE", "Windows Phone", or "IEMobile" in its UA string.
+ // IE Mobile 9 in desktop view doesn't include "IEMobile" or "Windows Phone" in the UA string,
+ // but it instead includes "XBLWP7" and/or "ZuneWP7".
+ canTrulyHover = !/Opera Mini|Android|IEMobile|Windows (Phone|CE)|(XBL|Zune)WP7/.test(navigator.userAgent);
+
+ // Since there won't be any event handlers to fire our events, do the one-and-only firing of it here and now.
+ triggerEvent();
+ return;
+ }
+
+ // CSSWG Media Queries Level 4 draft
+ // http://drafts.csswg.org/mediaqueries/#hover
+ var HOVER_NONE = "(hover: none),(-moz-hover: none),(-ms-hover: none),(-webkit-hover: none)";
+ var HOVER_ON_DEMAND = "(hover: on-demand),(-moz-hover: on-demand),(-ms-hover: on-demand),(-webkit-hover: on-demand)";
+ var HOVER_HOVER = "(hover: hover),(-moz-hover: hover),(-ms-hover: hover),(-webkit-hover: hover)";
+ if (window.matchMedia("" + HOVER_NONE + "," + HOVER_ON_DEMAND + "," + HOVER_HOVER).matches) {
+ // Browser understands the `hover` media feature
+ var hoverCallback = function (mql) {
+ var doesMatch = mql.matches;
+ if (doesMatch !== canTrulyHover) {
+ canTrulyHover = doesMatch;
+ triggerEvent();
+ }
+ };
+ var atHoverQuery = window.matchMedia(HOVER_HOVER);
+ atHoverQuery.addListener(hoverCallback);
+ hoverCallback(atHoverQuery);
+ return;
+ }
+
+ // Check for touch support instead.
+ // Touch generally implies that hovering is merely emulated,
+ // which doesn't count as true hovering support for our purposes
+ // due to the quirkiness of the emulation (e.g. :hover being sticky).
+
+ // W3C Pointer Events PR, 16 December 2014
+ // http://www.w3.org/TR/2014/PR-pointerevents-20141216/
+ // Prefixed in IE10, per http://caniuse.com/#feat=pointer
+ if (window.PointerEvent || window.MSPointerEvent) {
+ // Browser supports Pointer Events
+
+ // Browser supports touch if it has touch points
+ /* jshint -W018 */
+ canTrulyHover = !((window.navigator.maxTouchPoints || window.navigator.msMaxTouchPoints) > 0);
+ /* jshint +W018 */
+ triggerEvent();
+ return;
+ }
+
+ // Mozilla's -moz-touch-enabled
+ // https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries#-moz-touch-enabled
+ var touchEnabledQuery = window.matchMedia("(touch-enabled),(-moz-touch-enabled),(-ms-touch-enabled),(-webkit-touch-enabled)");
+ if (touchEnabledQuery.matches) {
+ canTrulyHover = false;
+ triggerEvent();
+ return;
+ }
+
+ // W3C Touch Events REC, 10 October 2013
+ // http://www.w3.org/TR/2013/REC-touch-events-20131010/
+ if ("ontouchstart" in window) {
+ canTrulyHover = false;
+ triggerEvent();
+ return;
+ }
+
+ // UA's pointer is non-touch and thus likely either supports true hovering or at least does not try to emulate it.
+ canTrulyHover = true;
+ triggerEvent();
+})();function supportsTrueHover() {
+ return canTrulyHover;
+}
+exports.__esModule = true;
+},{"jquery":undefined}]},{},[1])(1)
+});
+/** =======================================================================
+ * Bootstrap: alert.js v4.0.0
* http://getbootstrap.com/javascript/#alerts
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
+ * ========================================================================
+ * @fileoverview - Bootstrap's generic alert component. Add dismiss
+ * functionality to all alert messages with this plugin.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.alert
+ * + $.alert.noConflict
+ * + $.alert.Constructor
+ * + $.alert.Constructor.VERSION
+ * + $.alert.Constructor.prototype.close
+ *
+ * ========================================================================
+ */
-+function ($) {
- 'use strict';
+'use strict';
- // ALERT CLASS DEFINITION
- // ======================
- var dismiss = '[data-dismiss="alert"]'
- var Alert = function (el) {
- $(el).on('click', dismiss, this.close)
+/**
+ * Our Alert class.
+ * @param {Element=} opt_element
+ * @constructor
+ */
+var Alert = function (opt_element) {
+ if (opt_element) {
+ $(opt_element).on('click', Alert._DISMISS_SELECTOR, Alert._handleDismiss(this))
}
+}
- Alert.VERSION = '3.3.2'
- Alert.TRANSITION_DURATION = 150
+/**
+ * @const
+ * @type {string}
+ */
+Alert['VERSION'] = '4.0.0'
- Alert.prototype.close = function (e) {
- var $this = $(this)
- var selector = $this.attr('data-target')
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
- }
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Alert._NAME = 'alert'
- var $parent = $(selector)
- if (e) e.preventDefault()
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Alert._DATA_KEY = 'bs.alert'
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Alert._DISMISS_SELECTOR = '[data-dismiss="alert"]'
- if (!$parent.length) {
- $parent = $this.closest('.alert')
- }
- $parent.trigger(e = $.Event('close.bs.alert'))
+/**
+ * @const
+ * @type {number}
+ * @private
+ */
+Alert._TRANSITION_DURATION = 150
+
+
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Alert._JQUERY_NO_CONFLICT = $.fn[Alert._NAME]
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Alert._Event = {
+ CLOSE : 'close.bs.alert',
+ CLOSED : 'closed.bs.alert'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Alert._ClassName = {
+ ALERT : 'alert',
+ FADE : 'fade',
+ IN : 'in'
+}
+
+
+/**
+ * Provides the jQuery Interface for the alert component.
+ * @param {string=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Alert._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data(Alert._DATA_KEY)
+
+ if (!data) {
+ data = new Alert(this)
+ $this.data(Alert._DATA_KEY, data)
+ }
- if (e.isDefaultPrevented()) return
+ if (opt_config === 'close') {
+ data[opt_config](this)
+ }
+ })
+}
- $parent.removeClass('in')
- function removeElement() {
- // detach from parent, fire event then clean up data
- $parent.detach().trigger('closed.bs.alert').remove()
+/**
+ * Close the alert component
+ * @param {Alert} alertInstance
+ * @return {Function}
+ * @private
+ */
+Alert._handleDismiss = function (alertInstance) {
+ return function (event) {
+ if (event) {
+ event.preventDefault()
}
- $.support.transition && $parent.hasClass('fade') ?
- $parent
- .one('bsTransitionEnd', removeElement)
- .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
- removeElement()
+ alertInstance['close'](this)
}
+}
- // ALERT PLUGIN DEFINITION
- // =======================
+/**
+ * Close the alert component
+ * @param {Element} element
+ */
+Alert.prototype['close'] = function (element) {
+ var rootElement = this._getRootElement(element)
+ var customEvent = this._triggerCloseEvent(rootElement)
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.alert')
+ if (customEvent.isDefaultPrevented()) return
- if (!data) $this.data('bs.alert', (data = new Alert(this)))
- if (typeof option == 'string') data[option].call($this)
- })
+ this._removeElement(rootElement)
+}
+
+
+/**
+ * Tries to get the alert's root element
+ * @return {Element}
+ * @private
+ */
+Alert.prototype._getRootElement = function (element) {
+ var parent = false
+ var selector = Bootstrap.getSelectorFromElement(element)
+
+ if (selector) {
+ parent = $(selector)[0]
}
- var old = $.fn.alert
+ if (!parent) {
+ parent = $(element).closest('.' + Alert._ClassName.ALERT)[0]
+ }
- $.fn.alert = Plugin
- $.fn.alert.Constructor = Alert
+ return parent
+}
- // ALERT NO CONFLICT
- // =================
+/**
+ * Trigger close event on element
+ * @return {$.Event}
+ * @private
+ */
+Alert.prototype._triggerCloseEvent = function (element) {
+ var closeEvent = $.Event(Alert._Event.CLOSE)
+ $(element).trigger(closeEvent)
+ return closeEvent
+}
+
+
+/**
+ * Trigger closed event and remove element from dom
+ * @private
+ */
+Alert.prototype._removeElement = function (element) {
+ $(element).removeClass(Alert._ClassName.IN)
- $.fn.alert.noConflict = function () {
- $.fn.alert = old
- return this
+ if (!Bootstrap.transition || !$(element).hasClass(Alert._ClassName.FADE)) {
+ this._destroyElement(element)
+ return
}
+ $(element)
+ .one(Bootstrap.TRANSITION_END, this._destroyElement.bind(this, element))
+ .emulateTransitionEnd(Alert._TRANSITION_DURATION)
+}
- // ALERT DATA-API
- // ==============
- $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+/**
+ * clean up any lingering jquery data and kill element
+ * @private
+ */
+Alert.prototype._destroyElement = function (element) {
+ $(element)
+ .detach()
+ .trigger(Alert._Event.CLOSED)
+ .remove()
+}
-}(jQuery);
-/* ========================================================================
- * Bootstrap: button.js v3.3.2
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Alert._NAME] = Alert._jQueryInterface
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Alert._NAME]['Constructor'] = Alert
+
+
+/**
+ * @return {Function}
+ */
+$.fn[Alert._NAME]['noConflict'] = function () {
+ $.fn[Alert._NAME] = Alert._JQUERY_NO_CONFLICT
+ return Alert._jQueryInterface
+}
+
+
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+$(document).on('click.bs.alert.data-api', Alert._DISMISS_SELECTOR, Alert._handleDismiss(new Alert))
+
+/** =======================================================================
+ * Bootstrap: button.js v4.0.0
* http://getbootstrap.com/javascript/#buttons
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Bootstrap's generic button component.
+ *
+ * Note (@fat): Deprecated "setState" – imo, better solutions for managing a
+ * buttons state should exist outside this plugin.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.button
+ * + $.button.noConflict
+ * + $.button.Constructor
+ * + $.button.Constructor.VERSION
+ * + $.button.Constructor.prototype.toggle
+ *
+ * ========================================================================
+ */
+'use strict';
-+function ($) {
- 'use strict';
- // BUTTON PUBLIC CLASS DEFINITION
- // ==============================
+/**
+ * Our Button class.
+ * @param {Element!} element
+ * @constructor
+ */
+var Button = function (element) {
- var Button = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, Button.DEFAULTS, options)
- this.isLoading = false
- }
+ /** @private {Element} */
+ this._element = element
- Button.VERSION = '3.3.2'
+}
- Button.DEFAULTS = {
- loadingText: 'loading...'
- }
- Button.prototype.setState = function (state) {
- var d = 'disabled'
- var $el = this.$element
- var val = $el.is('input') ? 'val' : 'html'
- var data = $el.data()
+/**
+ * @const
+ * @type {string}
+ */
+Button['VERSION'] = '4.0.0'
- state = state + 'Text'
- if (data.resetText == null) $el.data('resetText', $el[val]())
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Button._NAME = 'button'
- // push to event loop to allow forms to submit
- setTimeout($.proxy(function () {
- $el[val](data[state] == null ? this.options[state] : data[state])
- if (state == 'loadingText') {
- this.isLoading = true
- $el.addClass(d).attr(d, d)
- } else if (this.isLoading) {
- this.isLoading = false
- $el.removeClass(d).removeAttr(d)
- }
- }, this), 0)
- }
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Button._DATA_KEY = 'bs.button'
- Button.prototype.toggle = function () {
- var changed = true
- var $parent = this.$element.closest('[data-toggle="buttons"]')
- if ($parent.length) {
- var $input = this.$element.find('input')
- if ($input.prop('type') == 'radio') {
- if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
- else $parent.find('.active').removeClass('active')
- }
- if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
- } else {
- this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Button._JQUERY_NO_CONFLICT = $.fn[Button._NAME]
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Button._ClassName = {
+ ACTIVE : 'active',
+ BUTTON : 'btn',
+ FOCUS : 'focus'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Button._Selector = {
+ DATA_TOGGLE_CARROT : '[data-toggle^="button"]',
+ DATA_TOGGLE : '[data-toggle="buttons"]',
+ INPUT : 'input',
+ ACTIVE : '.active',
+ BUTTON : '.btn'
+}
+
+
+/**
+ * Provides the jQuery Interface for the Button component.
+ * @param {string=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Button._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var data = $(this).data(Button._DATA_KEY)
+
+ if (!data) {
+ data = new Button(this)
+ $(this).data(Button._DATA_KEY, data)
}
- if (changed) this.$element.toggleClass('active')
+ if (opt_config === 'toggle') {
+ data[opt_config]()
+ }
+ })
+}
+
+
+/**
+ * Toggle's the button active state
+ */
+Button.prototype['toggle'] = function () {
+ var triggerChangeEvent = true
+ var rootElement = $(this._element).closest(Button._Selector.DATA_TOGGLE)[0]
+
+ if (rootElement) {
+ var input = $(this._element).find(Button._Selector.INPUT)[0]
+ if (input) {
+ if (input.type == 'radio') {
+ if (input.checked && $(this._element).hasClass(Button._ClassName.ACTIVE)) {
+ triggerChangeEvent = false
+ } else {
+ var activeElement = $(rootElement).find(Button._Selector.ACTIVE)[0]
+ if (activeElement) {
+ $(activeElement).removeClass(Button._ClassName.ACTIVE)
+ }
+ }
+ }
+
+ if (triggerChangeEvent) {
+ input.checked = !$(this._element).hasClass(Button._ClassName.ACTIVE)
+ $(this._element).trigger('change')
+ }
+ }
+ } else {
+ this._element.setAttribute('aria-pressed', !$(this._element).hasClass(Button._ClassName.ACTIVE))
}
+ if (triggerChangeEvent) {
+ $(this._element).toggleClass(Button._ClassName.ACTIVE)
+ }
+}
- // BUTTON PLUGIN DEFINITION
- // ========================
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.button')
- var options = typeof option == 'object' && option
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
- if (!data) $this.data('bs.button', (data = new Button(this, options)))
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Button._NAME] = Button._jQueryInterface
- if (option == 'toggle') data.toggle()
- else if (option) data.setState(option)
- })
- }
- var old = $.fn.button
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Button._NAME]['Constructor'] = Button
- $.fn.button = Plugin
- $.fn.button.Constructor = Button
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Button._NAME]['noConflict'] = function () {
+ $.fn[Button._NAME] = Button._JQUERY_NO_CONFLICT
+ return this
+}
- // BUTTON NO CONFLICT
- // ==================
- $.fn.button.noConflict = function () {
- $.fn.button = old
- return this
- }
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+$(document)
+ .on('click.bs.button.data-api', Button._Selector.DATA_TOGGLE_CARROT, function (event) {
+ event.preventDefault()
- // BUTTON DATA-API
- // ===============
+ var button = event.target
- $(document)
- .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
- var $btn = $(e.target)
- if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
- Plugin.call($btn, 'toggle')
- e.preventDefault()
- })
- .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
- $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
- })
+ if (!$(button).hasClass(Button._ClassName.BUTTON)) {
+ button = $(button).closest(Button._Selector.BUTTON)
+ }
-}(jQuery);
+ Button._jQueryInterface.call($(button), 'toggle')
+ })
+ .on('focus.bs.button.data-api blur.bs.button.data-api', Button._Selector.DATA_TOGGLE_CARROT, function (event) {
+ var button = $(event.target).closest(Button._Selector.BUTTON)[0]
+ $(button).toggleClass(Button._ClassName.FOCUS, /^focus(in)?$/.test(event.type))
+ })
-/* ========================================================================
- * Bootstrap: carousel.js v3.3.2
+/** =======================================================================
+ * Bootstrap: carousel.js v4.0.0
* http://getbootstrap.com/javascript/#carousel
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Bootstrap's carousel. A slideshow component for cycling
+ * through elements, like a carousel. Nested carousels are not supported.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.carousel
+ * + $.carousel.noConflict
+ * + $.carousel.Constructor
+ * + $.carousel.Constructor.VERSION
+ * + $.carousel.Constructor.Defaults
+ * + $.carousel.Constructor.Defaults.interval
+ * + $.carousel.Constructor.Defaults.pause
+ * + $.carousel.Constructor.Defaults.wrap
+ * + $.carousel.Constructor.Defaults.keyboard
+ * + $.carousel.Constructor.Defaults.slide
+ * + $.carousel.Constructor.prototype.next
+ * + $.carousel.Constructor.prototype.prev
+ * + $.carousel.Constructor.prototype.pause
+ * + $.carousel.Constructor.prototype.cycle
+ *
+ * ========================================================================
+ */
+'use strict';
-+function ($) {
- 'use strict';
- // CAROUSEL CLASS DEFINITION
- // =========================
+/**
+ * Our carousel class.
+ * @param {Element!} element
+ * @param {Object=} opt_config
+ * @constructor
+ */
+var Carousel = function (element, opt_config) {
+
+ /** @private {Element} */
+ this._element = $(element)[0]
+
+ /** @private {Element} */
+ this._indicatorsElement = $(this._element).find(Carousel._Selector.INDICATORS)[0]
+
+ /** @private {?Object} */
+ this._config = opt_config || null
- var Carousel = function (element, options) {
- this.$element = $(element)
- this.$indicators = this.$element.find('.carousel-indicators')
- this.options = options
- this.paused =
- this.sliding =
- this.interval =
- this.$active =
- this.$items = null
+ /** @private {boolean} */
+ this._isPaused = false
- this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
+ /** @private {boolean} */
+ this._isSliding = false
+
+ /** @private {?number} */
+ this._interval = null
+
+ /** @private {?Element} */
+ this._activeElement = null
+
+ /** @private {?Array} */
+ this._items = null
+
+ this._addEventListeners()
+
+}
+
+
+/**
+ * @const
+ * @type {string}
+ */
+Carousel['VERSION'] = '4.0.0'
- this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
- .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
- .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
+
+/**
+ * @const
+ * @type {Object}
+ */
+Carousel['Defaults'] = {
+ 'interval' : 5000,
+ 'pause' : 'hover',
+ 'wrap' : true,
+ 'keyboard' : true,
+ 'slide' : false
+}
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Carousel._NAME = 'carousel'
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Carousel._DATA_KEY = 'bs.carousel'
+
+
+/**
+ * @const
+ * @type {number}
+ * @private
+ */
+Carousel._TRANSITION_DURATION = 600
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Carousel._Direction = {
+ NEXT : 'next',
+ PREVIOUS : 'prev'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Carousel._Event = {
+ SLIDE : 'slide.bs.carousel',
+ SLID : 'slid.bs.carousel'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Carousel._ClassName = {
+ CAROUSEL : 'carousel',
+ ACTIVE : 'active',
+ SLIDE : 'slide',
+ RIGHT : 'right',
+ LEFT : 'left',
+ ITEM : 'carousel-item'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Carousel._Selector = {
+ ACTIVE : '.active',
+ ACTIVE_ITEM : '.active.carousel-item',
+ ITEM : '.carousel-item',
+ NEXT_PREV : '.next, .prev',
+ INDICATORS : '.carousel-indicators'
+}
+
+
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Carousel._JQUERY_NO_CONFLICT = $.fn[Carousel._NAME]
+
+
+/**
+ * @param {Object=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Carousel._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var data = $(this).data(Carousel._DATA_KEY)
+ var config = $.extend({}, Carousel['Defaults'], $(this).data(), typeof opt_config == 'object' && opt_config)
+ var action = typeof opt_config == 'string' ? opt_config : config.slide
+
+ if (!data) {
+ data = new Carousel(this, config)
+ $(this).data(Carousel._DATA_KEY, data)
+ }
+
+ if (typeof opt_config == 'number') {
+ data.to(opt_config)
+
+ } else if (action) {
+ data[action]()
+
+ } else if (config.interval) {
+ data['pause']()
+ data['cycle']()
+ }
+ })
+}
+
+
+/**
+ * Click handler for data api
+ * @param {Event} event
+ * @this {Element}
+ * @private
+ */
+Carousel._dataApiClickHandler = function (event) {
+ var selector = Bootstrap.getSelectorFromElement(this)
+
+ if (!selector) {
+ return
}
- Carousel.VERSION = '3.3.2'
+ var target = $(selector)[0]
+
+ if (!target || !$(target).hasClass(Carousel._ClassName.CAROUSEL)) {
+ return
+ }
- Carousel.TRANSITION_DURATION = 600
+ var config = $.extend({}, $(target).data(), $(this).data())
- Carousel.DEFAULTS = {
- interval: 5000,
- pause: 'hover',
- wrap: true,
- keyboard: true
+ var slideIndex = this.getAttribute('data-slide-to')
+ if (slideIndex) {
+ config.interval = false
}
- Carousel.prototype.keydown = function (e) {
- if (/input|textarea/i.test(e.target.tagName)) return
- switch (e.which) {
- case 37: this.prev(); break
- case 39: this.next(); break
- default: return
- }
+ Carousel._jQueryInterface.call($(target), config)
- e.preventDefault()
+ if (slideIndex) {
+ $(target).data(Carousel._DATA_KEY).to(slideIndex)
}
- Carousel.prototype.cycle = function (e) {
- e || (this.paused = false)
+ event.preventDefault()
+}
- this.interval && clearInterval(this.interval)
- this.options.interval
- && !this.paused
- && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+/**
+ * Advance the carousel to the next slide
+ */
+Carousel.prototype['next'] = function () {
+ if (!this._isSliding) {
+ this._slide(Carousel._Direction.NEXT)
+ }
+}
- return this
+
+/**
+ * Return the carousel to the previous slide
+ */
+Carousel.prototype['prev'] = function () {
+ if (!this._isSliding) {
+ this._slide(Carousel._Direction.PREVIOUS)
}
+}
+
- Carousel.prototype.getItemIndex = function (item) {
- this.$items = item.parent().children('.carousel-item')
- return this.$items.index(item || this.$active)
+/**
+ * Pause the carousel cycle
+ * @param {Event=} opt_event
+ */
+Carousel.prototype['pause'] = function (opt_event) {
+ if (!opt_event) {
+ this._isPaused = true
}
- Carousel.prototype.getItemForDirection = function (direction, active) {
- var activeIndex = this.getItemIndex(active)
- var willWrap = (direction == 'prev' && activeIndex === 0)
- || (direction == 'next' && activeIndex == (this.$items.length - 1))
- if (willWrap && !this.options.wrap) return active
- var delta = direction == 'prev' ? -1 : 1
- var itemIndex = (activeIndex + delta) % this.$items.length
- return this.$items.eq(itemIndex)
+ if ($(this._element).find(Carousel._Selector.NEXT_PREV)[0] && Bootstrap.transition) {
+ $(this._element).trigger(Bootstrap.transition.end)
+ this['cycle'](true)
}
- Carousel.prototype.to = function (pos) {
- var that = this
- var activeIndex = this.getItemIndex(this.$active = this.$element.find('.carousel-item.active'))
+ clearInterval(this._interval)
+ this._interval = null
+}
- if (pos > (this.$items.length - 1) || pos < 0) return
- if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
- if (activeIndex == pos) return this.pause().cycle()
+/**
+ * Cycle to the next carousel item
+ * @param {Event|boolean=} opt_event
+ */
+Carousel.prototype['cycle'] = function (opt_event) {
+ if (!opt_event) {
+ this._isPaused = false
+ }
- return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
+ if (this._interval) {
+ clearInterval(this._interval)
+ this._interval = null
}
- Carousel.prototype.pause = function (e) {
- e || (this.paused = true)
+ if (this._config['interval'] && !this._isPaused) {
+ this._interval = setInterval(this['next'].bind(this), this._config['interval'])
+ }
+}
+
+
+/**
+ * @return {Object}
+ */
+Carousel.prototype['getConfig'] = function () {
+ return this._config
+}
- if (this.$element.find('.next, .prev').length && $.support.transition) {
- this.$element.trigger($.support.transition.end)
- this.cycle(true)
- }
- this.interval = clearInterval(this.interval)
+/**
+ * Move active carousel item to specified index
+ * @param {number} index
+ */
+Carousel.prototype.to = function (index) {
+ this._activeElement = $(this._element).find(Carousel._Selector.ACTIVE_ITEM)[0]
- return this
+ var activeIndex = this._getItemIndex(this._activeElement)
+
+ if (index > (this._items.length - 1) || index < 0) {
+ return
}
- Carousel.prototype.next = function () {
- if (this.sliding) return
- return this.slide('next')
+ if (this._isSliding) {
+ $(this._element).one(Carousel._Event.SLID, function () { this.to(index) }.bind(this))
+ return
}
- Carousel.prototype.prev = function () {
- if (this.sliding) return
- return this.slide('prev')
+ if (activeIndex == index) {
+ this['pause']()
+ this['cycle']()
+ return
}
- Carousel.prototype.slide = function (type, next) {
- var $active = this.$element.find('.carousel-item.active')
- var $next = next || this.getItemForDirection(type, $active)
- var isCycling = this.interval
- var direction = type == 'next' ? 'left' : 'right'
- var that = this
+ var direction = index > activeIndex ?
+ Carousel._Direction.NEXT :
+ Carousel._Direction.PREVIOUS
- if ($next.hasClass('active')) return (this.sliding = false)
+ this._slide(direction, this._items[index])
+}
- var relatedTarget = $next[0]
- var slideEvent = $.Event('slide.bs.carousel', {
- relatedTarget: relatedTarget,
- direction: direction
- })
- this.$element.trigger(slideEvent)
- if (slideEvent.isDefaultPrevented()) return
-
- this.sliding = true
-
- isCycling && this.pause()
-
- if (this.$indicators.length) {
- this.$indicators.find('.active').removeClass('active')
- var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
- $nextIndicator && $nextIndicator.addClass('active')
- }
-
- var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
- if ($.support.transition && this.$element.hasClass('slide')) {
- $next.addClass(type)
- $next[0].offsetWidth // force reflow
- $active.addClass(direction)
- $next.addClass(direction)
- $active
- .one('bsTransitionEnd', function () {
- $next.removeClass([type, direction].join(' ')).addClass('active')
- $active.removeClass(['active', direction].join(' '))
- that.sliding = false
- setTimeout(function () {
- that.$element.trigger(slidEvent)
- }, 0)
- })
- .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
- } else {
- $active.removeClass('active')
- $next.addClass('active')
- this.sliding = false
- this.$element.trigger(slidEvent)
- }
- isCycling && this.cycle()
+/**
+ * Add event listeners to root element
+ * @private
+ */
+Carousel.prototype._addEventListeners = function () {
+ if (this._config['keyboard']) {
+ $(this._element).on('keydown.bs.carousel', this._keydown.bind(this))
+ }
- return this
+ if (this._config['pause'] == 'hover' && !('ontouchstart' in document.documentElement)) {
+ $(this._element)
+ .on('mouseenter.bs.carousel', this['pause'].bind(this))
+ .on('mouseleave.bs.carousel', this['cycle'].bind(this))
}
+}
- // CAROUSEL PLUGIN DEFINITION
- // ==========================
+/**
+ * Keydown handler
+ * @param {Event} event
+ * @private
+ */
+Carousel.prototype._keydown = function (event) {
+ event.preventDefault()
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.carousel')
- var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
- var action = typeof option == 'string' ? option : options.slide
+ if (/input|textarea/i.test(event.target.tagName)) return
- if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
- if (typeof option == 'number') data.to(option)
- else if (action) data[action]()
- else if (options.interval) data.pause().cycle()
- })
+ switch (event.which) {
+ case 37: this['prev'](); break
+ case 39: this['next'](); break
+ default: return
}
+}
- var old = $.fn.carousel
- $.fn.carousel = Plugin
- $.fn.carousel.Constructor = Carousel
+/**
+ * Get item index
+ * @param {Element} element
+ * @return {number}
+ * @private
+ */
+Carousel.prototype._getItemIndex = function (element) {
+ this._items = $.makeArray($(element).parent().find(Carousel._Selector.ITEM))
+ return this._items.indexOf(element)
+}
- // CAROUSEL NO CONFLICT
- // ====================
- $.fn.carousel.noConflict = function () {
- $.fn.carousel = old
- return this
+/**
+ * Get next displayed item based on direction
+ * @param {Carousel._Direction} direction
+ * @param {Element} activeElement
+ * @return {Element}
+ * @private
+ */
+Carousel.prototype._getItemByDirection = function (direction, activeElement) {
+ var activeIndex = this._getItemIndex(activeElement)
+ var isGoingToWrap = (direction === Carousel._Direction.PREVIOUS && activeIndex === 0) ||
+ (direction === Carousel._Direction.NEXT && activeIndex == (this._items.length - 1))
+
+ if (isGoingToWrap && !this._config['wrap']) {
+ return activeElement
}
+ var delta = direction == Carousel._Direction.PREVIOUS ? -1 : 1
+ var itemIndex = (activeIndex + delta) % this._items.length
- // CAROUSEL DATA-API
- // =================
+ return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex]
+}
- var clickHandler = function (e) {
- var href
- var $this = $(this)
- var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
- if (!$target.hasClass('carousel')) return
- var options = $.extend({}, $target.data(), $this.data())
- var slideIndex = $this.attr('data-slide-to')
- if (slideIndex) options.interval = false
- Plugin.call($target, options)
+/**
+ * Trigger slide event on element
+ * @param {Element} relatedTarget
+ * @param {Carousel._ClassName} directionalClassname
+ * @return {$.Event}
+ * @private
+ */
+Carousel.prototype._triggerSlideEvent = function (relatedTarget, directionalClassname) {
+ var slideEvent = $.Event(Carousel._Event.SLIDE, {
+ relatedTarget: relatedTarget,
+ direction: directionalClassname
+ })
- if (slideIndex) {
- $target.data('bs.carousel').to(slideIndex)
+ $(this._element).trigger(slideEvent)
+
+ return slideEvent
+}
+
+
+/**
+ * Set the active indicator if available
+ * @param {Element} element
+ * @private
+ */
+Carousel.prototype._setActiveIndicatorElement = function (element) {
+ if (this._indicatorsElement) {
+ $(this._indicatorsElement)
+ .find(Carousel._Selector.ACTIVE)
+ .removeClass(Carousel._ClassName.ACTIVE)
+
+ var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)]
+ if (nextIndicator) {
+ $(nextIndicator).addClass(Carousel._ClassName.ACTIVE)
}
+ }
+}
+
+
+/**
+ * Slide the carousel element in a direction
+ * @param {Carousel._Direction} direction
+ * @param {Element=} opt_nextElement
+ */
+Carousel.prototype._slide = function (direction, opt_nextElement) {
+ var activeElement = $(this._element).find(Carousel._Selector.ACTIVE_ITEM)[0]
+ var nextElement = opt_nextElement || activeElement && this._getItemByDirection(direction, activeElement)
+
+ var isCycling = !!this._interval
- e.preventDefault()
+ var directionalClassName = direction == Carousel._Direction.NEXT ?
+ Carousel._ClassName.LEFT :
+ Carousel._ClassName.RIGHT
+
+ if (nextElement && $(nextElement).hasClass(Carousel._ClassName.ACTIVE)) {
+ this._isSliding = false
+ return
}
- $(document)
- .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
- .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
+ var slideEvent = this._triggerSlideEvent(nextElement, directionalClassName)
+ if (slideEvent.isDefaultPrevented()) {
+ return
+ }
- $(window).on('load', function () {
- $('[data-ride="carousel"]').each(function () {
- var $carousel = $(this)
- Plugin.call($carousel, $carousel.data())
- })
- })
+ if (!activeElement || !nextElement) {
+ // some weirdness is happening, so we bail (maybe throw exception here alerting user that they're dom is off
+ return
+ }
-}(jQuery);
+ this._isSliding = true
+
+ if (isCycling) {
+ this['pause']()
+ }
+
+ this._setActiveIndicatorElement(nextElement)
+
+ var slidEvent = $.Event(Carousel._Event.SLID, { relatedTarget: nextElement, direction: directionalClassName })
+
+ if (Bootstrap.transition && $(this._element).hasClass(Carousel._ClassName.SLIDE)) {
+ $(nextElement).addClass(direction)
+
+ Bootstrap.reflow(nextElement)
+
+ $(activeElement).addClass(directionalClassName)
+ $(nextElement).addClass(directionalClassName)
-/* ========================================================================
- * Bootstrap: collapse.js v3.3.2
+ $(activeElement)
+ .one(Bootstrap.TRANSITION_END, function () {
+ $(nextElement)
+ .removeClass(directionalClassName)
+ .removeClass(direction)
+
+ $(nextElement).addClass(Carousel._ClassName.ACTIVE)
+
+ $(activeElement)
+ .removeClass(Carousel._ClassName.ACTIVE)
+ .removeClass(direction)
+ .removeClass(directionalClassName)
+
+ this._isSliding = false
+
+ setTimeout(function () {
+ $(this._element).trigger(slidEvent)
+ }.bind(this), 0)
+ }.bind(this))
+ .emulateTransitionEnd(Carousel._TRANSITION_DURATION)
+
+ } else {
+ $(activeElement).removeClass(Carousel._ClassName.ACTIVE)
+ $(nextElement).addClass(Carousel._ClassName.ACTIVE)
+
+ this._isSliding = false
+ $(this._element).trigger(slidEvent)
+ }
+
+ if (isCycling) {
+ this['cycle']()
+ }
+}
+
+
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Carousel._NAME] = Carousel._jQueryInterface
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Carousel._NAME]['Constructor'] = Carousel
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Carousel._NAME]['noConflict'] = function () {
+ $.fn[Carousel._NAME] = Carousel._JQUERY_NO_CONFLICT
+ return this
+}
+
+
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+$(document)
+ .on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', Carousel._dataApiClickHandler)
+
+$(window).on('load', function () {
+ $('[data-ride="carousel"]').each(function () {
+ var $carousel = $(this)
+ Carousel._jQueryInterface.call($carousel, /** @type {Object} */ ($carousel.data()))
+ })
+})
+
+/** =======================================================================
+ * Bootstrap: collapse.js v4.0.0
* http://getbootstrap.com/javascript/#collapse
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Bootstrap's collapse plugin. Flexible support for
+ * collapsible components like accordions and navigation.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.carousel
+ * + $.carousel.noConflict
+ * + $.carousel.Constructor
+ * + $.carousel.Constructor.VERSION
+ * + $.carousel.Constructor.Defaults
+ * + $.carousel.Constructor.Defaults.toggle
+ * + $.carousel.Constructor.Defaults.trigger
+ * + $.carousel.Constructor.Defaults.parent
+ * + $.carousel.Constructor.prototype.toggle
+ * + $.carousel.Constructor.prototype.show
+ * + $.carousel.Constructor.prototype.hide
+ *
+ * ========================================================================
+ */
+'use strict';
-+function ($) {
- 'use strict';
- // COLLAPSE PUBLIC CLASS DEFINITION
- // ================================
+/**
+ * Our collapse class.
+ * @param {Element!} element
+ * @param {Object=} opt_config
+ * @constructor
+ */
+var Collapse = function (element, opt_config) {
- var Collapse = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, Collapse.DEFAULTS, options)
- this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]')
- this.transitioning = null
+ /** @private {Element} */
+ this._element = element
- if (this.options.parent) {
- this.$parent = this.getParent()
- } else {
- this.addAriaAndCollapsedClass(this.$element, this.$trigger)
- }
+ /** @private {Object} */
+ this._config = $.extend({}, Collapse['Defaults'], opt_config)
- if (this.options.toggle) this.toggle()
- }
+ /** @private {Element} */
+ this._trigger = typeof this._config['trigger'] == 'string' ?
+ $(this._config['trigger'])[0] : this._config['trigger']
- Collapse.VERSION = '3.3.2'
+ /** @private {boolean} */
+ this._isTransitioning = false
- Collapse.TRANSITION_DURATION = 350
+ /** @private {?Element} */
+ this._parent = this._config['parent'] ? this._getParent() : null
- Collapse.DEFAULTS = {
- toggle: true,
- trigger: '[data-toggle="collapse"]'
+ if (!this._config['parent']) {
+ this._addAriaAndCollapsedClass(this._element, this._trigger)
}
- Collapse.prototype.dimension = function () {
- var hasWidth = this.$element.hasClass('width')
- return hasWidth ? 'width' : 'height'
+ if (this._config['toggle']) {
+ this['toggle']()
}
- Collapse.prototype.show = function () {
- if (this.transitioning || this.$element.hasClass('in')) return
+}
- var activesData
- var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
- if (actives && actives.length) {
- activesData = actives.data('bs.collapse')
- if (activesData && activesData.transitioning) return
- }
+/**
+ * @const
+ * @type {string}
+ */
+Collapse['VERSION'] = '4.0.0'
- var startEvent = $.Event('show.bs.collapse')
- this.$element.trigger(startEvent)
- if (startEvent.isDefaultPrevented()) return
- if (actives && actives.length) {
- Plugin.call(actives, 'hide')
- activesData || actives.data('bs.collapse', null)
- }
+/**
+ * @const
+ * @type {Object}
+ */
+Collapse['Defaults'] = {
+ 'toggle' : true,
+ 'trigger' : '[data-toggle="collapse"]',
+ 'parent' : null
+}
- var dimension = this.dimension()
- this.$element
- .removeClass('collapse')
- .addClass('collapsing')[dimension](0)
- .attr('aria-expanded', true)
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Collapse._NAME = 'collapse'
- this.$trigger
- .removeClass('collapsed')
- .attr('aria-expanded', true)
- this.transitioning = 1
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Collapse._DATA_KEY = 'bs.collapse'
- var complete = function () {
- this.$element
- .removeClass('collapsing')
- .addClass('collapse in')[dimension]('')
- this.transitioning = 0
- this.$element
- .trigger('shown.bs.collapse')
+
+/**
+ * @const
+ * @type {number}
+ * @private
+ */
+Collapse._TRANSITION_DURATION = 600
+
+
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Collapse._JQUERY_NO_CONFLICT = $.fn[Collapse._NAME]
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Collapse._Event = {
+ SHOW : 'show.bs.collapse',
+ SHOWN : 'shown.bs.collapse',
+ HIDE : 'hide.bs.collapse',
+ HIDDEN : 'hidden.bs.collapse'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Collapse._ClassName = {
+ IN : 'in',
+ COLLAPSE : 'collapse',
+ COLLAPSING : 'collapsing',
+ COLLAPSED : 'collapsed'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Collapse._Dimension = {
+ WIDTH : 'width',
+ HEIGHT : 'height'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Collapse._Selector = {
+ ACTIVES : '.panel > .in, .panel > .collapsing'
+}
+
+
+/**
+ * Provides the jQuery Interface for the alert component.
+ * @param {Object|string=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Collapse._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data(Collapse._DATA_KEY)
+ var config = $.extend({}, Collapse['Defaults'], $this.data(), typeof opt_config == 'object' && opt_config)
+
+ if (!data && config['toggle'] && opt_config == 'show') {
+ config['toggle'] = false
}
- if (!$.support.transition) return complete.call(this)
+ if (!data) {
+ data = new Collapse(this, config)
+ $this.data(Collapse._DATA_KEY, data)
+ }
- var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+ if (typeof opt_config == 'string') {
+ data[opt_config]()
+ }
+ })
+}
- this.$element
- .one('bsTransitionEnd', $.proxy(complete, this))
- .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
- }
- Collapse.prototype.hide = function () {
- if (this.transitioning || !this.$element.hasClass('in')) return
+/**
+ * Function for getting target element from element
+ * @return {Element}
+ * @private
+ */
+Collapse._getTargetFromElement = function (element) {
+ var selector = Bootstrap.getSelectorFromElement(element)
- var startEvent = $.Event('hide.bs.collapse')
- this.$element.trigger(startEvent)
- if (startEvent.isDefaultPrevented()) return
+ return selector ? $(selector)[0] : null
+}
- var dimension = this.dimension()
- this.$element[dimension](this.$element[dimension]())[0].offsetHeight
+/**
+ * Toggles the collapse element based on the presence of the 'in' class
+ */
+Collapse.prototype['toggle'] = function () {
+ if ($(this._element).hasClass(Collapse._ClassName.IN)) {
+ this['hide']()
+ } else {
+ this['show']()
+ }
+}
- this.$element
- .addClass('collapsing')
- .removeClass('collapse in')
- .attr('aria-expanded', false)
- this.$trigger
- .addClass('collapsed')
- .attr('aria-expanded', false)
+/**
+ * Show's the collapsing element
+ */
+Collapse.prototype['show'] = function () {
+ if (this._isTransitioning || $(this._element).hasClass(Collapse._ClassName.IN)) {
+ return
+ }
- this.transitioning = 1
+ var activesData, actives
- var complete = function () {
- this.transitioning = 0
- this.$element
- .removeClass('collapsing')
- .addClass('collapse')
- .trigger('hidden.bs.collapse')
+ if (this._parent) {
+ actives = $.makeArray($(Collapse._Selector.ACTIVES))
+ if (!actives.length) {
+ actives = null
}
+ }
- if (!$.support.transition) return complete.call(this)
+ if (actives) {
+ activesData = $(actives).data(Collapse._DATA_KEY)
+ if (activesData && activesData._isTransitioning) {
+ return
+ }
+ }
- this.$element
- [dimension](0)
- .one('bsTransitionEnd', $.proxy(complete, this))
- .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
+ var startEvent = $.Event(Collapse._Event.SHOW)
+ $(this._element).trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) {
+ return
}
- Collapse.prototype.toggle = function () {
- this[this.$element.hasClass('in') ? 'hide' : 'show']()
+ if (actives) {
+ Collapse._jQueryInterface.call($(actives), 'hide')
+ if (!activesData) {
+ $(actives).data(Collapse._DATA_KEY, null)
+ }
}
- Collapse.prototype.getParent = function () {
- return $(this.options.parent)
- .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
- .each($.proxy(function (i, element) {
- var $element = $(element)
- this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
- }, this))
- .end()
+ var dimension = this._getDimension()
+
+ $(this._element)
+ .removeClass(Collapse._ClassName.COLLAPSE)
+ .addClass(Collapse._ClassName.COLLAPSING)
+
+ this._element.style[dimension] = 0
+ this._element.setAttribute('aria-expanded', true)
+
+ if (this._trigger) {
+ $(this._trigger).removeClass(Collapse._ClassName.COLLAPSED)
+ this._trigger.setAttribute('aria-expanded', true)
}
- Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
- var isOpen = $element.hasClass('in')
+ this['setTransitioning'](true)
- $element.attr('aria-expanded', isOpen)
- $trigger
- .toggleClass('collapsed', !isOpen)
- .attr('aria-expanded', isOpen)
+ var complete = function () {
+ $(this._element)
+ .removeClass(Collapse._ClassName.COLLAPSING)
+ .addClass(Collapse._ClassName.COLLAPSE)
+ .addClass(Collapse._ClassName.IN)
+
+ this._element.style[dimension] = ''
+
+ this['setTransitioning'](false)
+
+ $(this._element).trigger(Collapse._Event.SHOWN)
+ }.bind(this)
+
+ if (!Bootstrap.transition) {
+ complete()
+ return
}
- function getTargetFromTrigger($trigger) {
- var href
- var target = $trigger.attr('data-target')
- || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+ var scrollSize = 'scroll' + (dimension[0].toUpperCase() + dimension.slice(1))
+
+ $(this._element)
+ .one(Bootstrap.TRANSITION_END, complete)
+ .emulateTransitionEnd(Collapse._TRANSITION_DURATION)
- return $(target)
+ this._element.style[dimension] = this._element[scrollSize] + 'px'
+}
+
+
+/**
+ * Hides's the collapsing element
+ */
+Collapse.prototype['hide'] = function () {
+ if (this._isTransitioning || !$(this._element).hasClass(Collapse._ClassName.IN)) {
+ return
}
+ var startEvent = $.Event(Collapse._Event.HIDE)
+ $(this._element).trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
- // COLLAPSE PLUGIN DEFINITION
- // ==========================
+ var dimension = this._getDimension()
+ var offsetDimension = dimension === Collapse._Dimension.WIDTH ?
+ 'offsetWidth' : 'offsetHeight'
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.collapse')
- var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+ this._element.style[dimension] = this._element[offsetDimension] + 'px'
- if (!data && options.toggle && option == 'show') options.toggle = false
- if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
- if (typeof option == 'string') data[option]()
- })
+ Bootstrap.reflow(this._element)
+
+ $(this._element)
+ .addClass(Collapse._ClassName.COLLAPSING)
+ .removeClass(Collapse._ClassName.COLLAPSE)
+ .removeClass(Collapse._ClassName.IN)
+
+ this._element.setAttribute('aria-expanded', false)
+
+ if (this._trigger) {
+ $(this._trigger).addClass(Collapse._ClassName.COLLAPSED)
+ this._trigger.setAttribute('aria-expanded', false)
}
- var old = $.fn.collapse
+ this['setTransitioning'](true)
- $.fn.collapse = Plugin
- $.fn.collapse.Constructor = Collapse
+ var complete = function () {
+ this['setTransitioning'](false)
+ $(this._element)
+ .removeClass(Collapse._ClassName.COLLAPSING)
+ .addClass(Collapse._ClassName.COLLAPSE)
+ .trigger(Collapse._Event.HIDDEN)
+ }.bind(this)
- // COLLAPSE NO CONFLICT
- // ====================
+ this._element.style[dimension] = 0
- $.fn.collapse.noConflict = function () {
- $.fn.collapse = old
- return this
+ if (!Bootstrap.transition) {
+ return complete()
}
+ $(this._element)
+ .one(Bootstrap.TRANSITION_END, complete)
+ .emulateTransitionEnd(Collapse._TRANSITION_DURATION)
+}
- // COLLAPSE DATA-API
- // =================
- $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
- var $this = $(this)
- if (!$this.attr('data-target')) e.preventDefault()
+/**
+ * @param {boolean} isTransitioning
+ */
+Collapse.prototype['setTransitioning'] = function (isTransitioning) {
+ this._isTransitioning = isTransitioning
+}
- var $target = getTargetFromTrigger($this)
- var data = $target.data('bs.collapse')
- var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })
- Plugin.call($target, option)
- })
+/**
+ * Returns the collapsing dimension
+ * @return {string}
+ * @private
+ */
+Collapse.prototype._getDimension = function () {
+ var hasWidth = $(this._element).hasClass(Collapse._Dimension.WIDTH)
+ return hasWidth ? Collapse._Dimension.WIDTH : Collapse._Dimension.HEIGHT
+}
-}(jQuery);
-/* ========================================================================
- * Bootstrap: dropdown.js v3.3.2
- * http://getbootstrap.com/javascript/#dropdowns
+/**
+ * Returns the parent element
+ * @return {Element}
+ * @private
+ */
+Collapse.prototype._getParent = function () {
+ var selector = '[data-toggle="collapse"][data-parent="' + this._config['parent'] + '"]'
+ var parent = $(this._config['parent'])[0]
+ var elements = /** @type {Array.<Element>} */ ($.makeArray($(parent).find(selector)))
+
+ for (var i = 0; i < elements.length; i++) {
+ this._addAriaAndCollapsedClass(Collapse._getTargetFromElement(elements[i]), elements[i])
+ }
+
+ return parent
+}
+
+
+/**
+ * Returns the parent element
+ * @param {Element} element
+ * @param {Element} trigger
+ * @private
+ */
+Collapse.prototype._addAriaAndCollapsedClass = function (element, trigger) {
+ if (element) {
+ var isOpen = $(element).hasClass(Collapse._ClassName.IN)
+ element.setAttribute('aria-expanded', isOpen)
+
+ if (trigger) {
+ trigger.setAttribute('aria-expanded', isOpen)
+ $(trigger).toggleClass(Collapse._ClassName.COLLAPSED, !isOpen)
+ }
+ }
+}
+
+
+
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Collapse._NAME] = Collapse._jQueryInterface
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Collapse._NAME]['Constructor'] = Collapse
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Collapse._NAME]['noConflict'] = function () {
+ $.fn[Collapse._NAME] = Collapse._JQUERY_NO_CONFLICT
+ return this
+}
+
+
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (event) {
+ event.preventDefault()
+
+ var target = Collapse._getTargetFromElement(this)
+
+ var data = $(target).data(Collapse._DATA_KEY)
+ var config = data ? 'toggle' : $.extend({}, $(this).data(), { trigger: this })
+
+ Collapse._jQueryInterface.call($(target), config)
+})
+
+/** =======================================================================
+ * Bootstrap: dropdown.js v4.0.0
+ * http://getbootstrap.com/javascript/#dropdown
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Add dropdown menus to nearly anything with this simple
+ * plugin, including the navbar, tabs, and pills.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.dropdown
+ * + $.dropdown.noConflict
+ * + $.dropdown.Constructor
+ * + $.dropdown.Constructor.VERSION
+ * + $.dropdown.Constructor.prototype.toggle
+ *
+ * ========================================================================
+ */
+'use strict';
-+function ($) {
- 'use strict';
- // DROPDOWN CLASS DEFINITION
- // =========================
+/**
+ * Our dropdown class.
+ * @param {Element!} element
+ * @constructor
+ */
+var Dropdown = function (element) {
+ $(element).on('click.bs.dropdown', this['toggle'])
+}
- var backdrop = '.dropdown-backdrop'
- var toggle = '[data-toggle="dropdown"]'
- var Dropdown = function (element) {
- $(element).on('click.bs.dropdown', this.toggle)
- }
- Dropdown.VERSION = '3.3.2'
+/**
+ * @const
+ * @type {string}
+ */
+Dropdown['VERSION'] = '4.0.0'
- Dropdown.prototype.toggle = function (e) {
- var $this = $(this)
- if ($this.is('.disabled, :disabled')) return
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Dropdown._NAME = 'dropdown'
- var $parent = getParent($this)
- var isActive = $parent.hasClass('open')
- clearMenus()
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Dropdown._DATA_KEY = 'bs.dropdown'
- if (!isActive) {
- if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
- // if mobile we use a backdrop because click events don't delegate
- $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
- }
- var relatedTarget = { relatedTarget: this }
- $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Dropdown._JQUERY_NO_CONFLICT = $.fn[Dropdown._NAME]
- if (e.isDefaultPrevented()) return
- $this
- .trigger('focus')
- .attr('aria-expanded', 'true')
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Dropdown._Event = {
+ HIDE : 'hide.bs.dropdown',
+ HIDDEN : 'hidden.bs.dropdown',
+ SHOW : 'show.bs.dropdown',
+ SHOWN : 'shown.bs.dropdown'
+}
+
- $parent
- .toggleClass('open')
- .trigger('shown.bs.dropdown', relatedTarget)
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Dropdown._ClassName = {
+ BACKDROP : 'dropdown-backdrop',
+ DISABLED : 'disabled',
+ OPEN : 'open'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Dropdown._Selector = {
+ BACKDROP : '.dropdown-backdrop',
+ DATA_TOGGLE : '[data-toggle="dropdown"]',
+ FORM_CHILD : '.dropdown form',
+ ROLE_MENU : '[role="menu"]',
+ ROLE_LISTBOX : '[role="listbox"]',
+ NAVBAR_NAV : '.navbar-nav',
+ VISIBLE_ITEMS : '[role="menu"] li:not(.divider) a, [role="listbox"] li:not(.divider) a'
+}
+
+
+/**
+ * Provides the jQuery Interface for the alert component.
+ * @param {string=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Dropdown._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var data = $(this).data(Dropdown._DATA_KEY)
+
+ if (!data) {
+ $(this).data(Dropdown._DATA_KEY, (data = new Dropdown(this)))
}
- return false
- }
+ if (typeof opt_config === 'string') {
+ data[opt_config].call(this)
+ }
+ })
+}
- Dropdown.prototype.keydown = function (e) {
- if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
- var $this = $(this)
+/**
+ * @param {Event=} opt_event
+ * @private
+ */
+Dropdown._clearMenus = function (opt_event) {
+ if (opt_event && opt_event.which == 3) {
+ return
+ }
- e.preventDefault()
- e.stopPropagation()
+ var backdrop = $(Dropdown._Selector.BACKDROP)[0]
+ if (backdrop) {
+ backdrop.parentNode.removeChild(backdrop)
+ }
- if ($this.is('.disabled, :disabled')) return
+ var toggles = /** @type {Array.<Element>} */ ($.makeArray($(Dropdown._Selector.DATA_TOGGLE)))
- var $parent = getParent($this)
- var isActive = $parent.hasClass('open')
+ for (var i = 0; i < toggles.length; i++) {
+ var parent = Dropdown._getParentFromElement(toggles[i])
+ var relatedTarget = { 'relatedTarget': toggles[i] }
- if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
- if (e.which == 27) $parent.find(toggle).trigger('focus')
- return $this.trigger('click')
+ if (!$(parent).hasClass(Dropdown._ClassName.OPEN)) {
+ continue
}
- var desc = ' li:not(.divider):visible a'
- var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
+ var hideEvent = $.Event(Dropdown._Event.HIDE, relatedTarget)
+ $(parent).trigger(hideEvent)
+ if (hideEvent.isDefaultPrevented()) {
+ continue
+ }
- if (!$items.length) return
+ toggles[i].setAttribute('aria-expanded', 'false')
- var index = $items.index(e.target)
+ $(parent)
+ .removeClass(Dropdown._ClassName.OPEN)
+ .trigger(Dropdown._Event.HIDDEN, relatedTarget)
+ }
+}
- if (e.which == 38 && index > 0) index-- // up
- if (e.which == 40 && index < $items.length - 1) index++ // down
- if (!~index) index = 0
- $items.eq(index).trigger('focus')
+/**
+ * @param {Element} element
+ * @return {Element}
+ * @private
+ */
+Dropdown._getParentFromElement = function (element) {
+ var selector = Bootstrap.getSelectorFromElement(element)
+
+ if (selector) {
+ var parent = $(selector)[0]
}
- function clearMenus(e) {
- if (e && e.which === 3) return
- $(backdrop).remove()
- $(toggle).each(function () {
- var $this = $(this)
- var $parent = getParent($this)
- var relatedTarget = { relatedTarget: this }
+ return /** @type {Element} */ (parent || element.parentNode)
+}
- if (!$parent.hasClass('open')) return
- $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+/**
+ * @param {Event} event
+ * @this {Element}
+ * @private
+ */
+Dropdown._dataApiKeydownHandler = function (event) {
+ if (!/(38|40|27|32)/.test(event.which) || /input|textarea/i.test(event.target.tagName)) {
+ return
+ }
- if (e.isDefaultPrevented()) return
+ event.preventDefault()
+ event.stopPropagation()
- $this.attr('aria-expanded', 'false')
- $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
- })
+ if (this.disabled || $(this).hasClass(Dropdown._ClassName.DISABLED)) {
+ return
}
- function getParent($this) {
- var selector = $this.attr('data-target')
+ var parent = Dropdown._getParentFromElement(this)
+ var isActive = $(parent).hasClass(Dropdown._ClassName.OPEN)
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ if ((!isActive && event.which != 27) || (isActive && event.which == 27)) {
+ if (event.which == 27) {
+ var toggle = $(parent).find(Dropdown._Selector.DATA_TOGGLE)[0]
+ $(toggle).trigger('focus')
}
+ $(this).trigger('click')
+ return
+ }
- var $parent = selector && $(selector)
+ var items = $.makeArray($(Dropdown._Selector.VISIBLE_ITEMS))
- return $parent && $parent.length ? $parent : $this.parent()
+ items = items.filter(function (item) {
+ return item.offsetWidth || item.offsetHeight
+ })
+
+ if (!items.length) {
+ return
}
+ var index = items.indexOf(event.target)
- // DROPDOWN PLUGIN DEFINITION
- // ==========================
+ if (event.which == 38 && index > 0) index-- // up
+ if (event.which == 40 && index < items.length - 1) index++ // down
+ if (!~index) index = 0
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.dropdown')
+ items[index].focus()
+}
- if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
- if (typeof option == 'string') data[option].call($this)
- })
+
+/**
+ * Toggles the dropdown
+ * @this {Element}
+ * @return {boolean|undefined}
+ */
+Dropdown.prototype['toggle'] = function () {
+ if (this.disabled || $(this).hasClass(Dropdown._ClassName.DISABLED)) {
+ return
}
- var old = $.fn.dropdown
+ var parent = Dropdown._getParentFromElement(this)
+ var isActive = $(parent).hasClass(Dropdown._ClassName.OPEN)
- $.fn.dropdown = Plugin
- $.fn.dropdown.Constructor = Dropdown
+ Dropdown._clearMenus()
+ if (isActive) {
+ return false
+ }
+
+ if ('ontouchstart' in document.documentElement && !$(parent).closest(Dropdown._Selector.NAVBAR_NAV).length) {
+ // if mobile we use a backdrop because click events don't delegate
+ var dropdown = document.createElement('div')
+ dropdown.className = Dropdown._ClassName.BACKDROP
+ this.parentNode.insertBefore(this, dropdown)
+ $(dropdown).on('click', Dropdown._clearMenus)
+ }
- // DROPDOWN NO CONFLICT
- // ====================
+ var relatedTarget = { 'relatedTarget': this }
+ var showEvent = $.Event(Dropdown._Event.SHOW, relatedTarget)
- $.fn.dropdown.noConflict = function () {
- $.fn.dropdown = old
- return this
+ $(parent).trigger(showEvent)
+
+ if (showEvent.isDefaultPrevented()) {
+ return
}
+ this.focus()
+ this.setAttribute('aria-expanded', 'true')
- // APPLY TO STANDARD DROPDOWN ELEMENTS
- // ===================================
+ $(parent).toggleClass(Dropdown._ClassName.OPEN)
- $(document)
- .on('click.bs.dropdown.data-api', clearMenus)
- .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
- .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
- .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
- .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
- .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
+ $(parent).trigger(Dropdown._Event.SHOWN, relatedTarget)
-}(jQuery);
+ return false
+}
-/* ========================================================================
- * Bootstrap: modal.js v3.3.2
- * http://getbootstrap.com/javascript/#modals
+
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Dropdown._NAME] = Dropdown._jQueryInterface
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Dropdown._NAME]['Constructor'] = Dropdown
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Dropdown._NAME]['noConflict'] = function () {
+ $.fn[Dropdown._NAME] = Dropdown._JQUERY_NO_CONFLICT
+ return this
+}
+
+
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+$(document)
+ .on('click.bs.dropdown.data-api', Dropdown._clearMenus)
+ .on('click.bs.dropdown.data-api', Dropdown._Selector.FORM_CHILD, function (e) { e.stopPropagation() })
+ .on('click.bs.dropdown.data-api', Dropdown._Selector.DATA_TOGGLE, Dropdown.prototype['toggle'])
+ .on('keydown.bs.dropdown.data-api', Dropdown._Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler)
+ .on('keydown.bs.dropdown.data-api', Dropdown._Selector.ROLE_MENU, Dropdown._dataApiKeydownHandler)
+ .on('keydown.bs.dropdown.data-api', Dropdown._Selector.ROLE_LISTBOX, Dropdown._dataApiKeydownHandler)
+
+/** =======================================================================
+ * Bootstrap: modal.js v4.0.0
+ * http://getbootstrap.com/javascript/#modal
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Bootstrap's modal plugin. Modals are streamlined, but
+ * flexible, dialog prompts with the minimum required functionality and
+ * smart defaults.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.modal
+ * + $.modal.noConflict
+ * + $.modal.Constructor
+ * + $.modal.Constructor.VERSION
+ * + $.modal.Constructor.Defaults
+ * + $.modal.Constructor.Defaults.backdrop
+ * + $.modal.Constructor.Defaults.keyboard
+ * + $.modal.Constructor.Defaults.show
+ * + $.modal.Constructor.prototype.toggle
+ * + $.modal.Constructor.prototype.show
+ * + $.modal.Constructor.prototype.hide
+ *
+ * ========================================================================
+ */
+'use strict';
-+function ($) {
- 'use strict';
- // MODAL CLASS DEFINITION
- // ======================
+/**
+ * Our modal class.
+ * @param {Element} element
+ * @param {Object} config
+ * @constructor
+ */
+var Modal = function (element, config) {
- var Modal = function (element, options) {
- this.options = options
- this.$body = $(document.body)
- this.$element = $(element)
- this.$backdrop =
- this.isShown = null
- this.scrollbarWidth = 0
+ /** @private {Object} */
+ this._config = config
- if (this.options.remote) {
- this.$element
- .find('.modal-content')
- .load(this.options.remote, $.proxy(function () {
- this.$element.trigger('loaded.bs.modal')
- }, this))
- }
- }
+ /** @private {Element} */
+ this._element = element
- Modal.VERSION = '3.3.2'
+ /** @private {Element} */
+ this._backdrop = null
- Modal.TRANSITION_DURATION = 300
- Modal.BACKDROP_TRANSITION_DURATION = 150
+ /** @private {boolean} */
+ this._isShown = false
- Modal.DEFAULTS = {
- backdrop: true,
- keyboard: true,
- show: true
- }
+ /** @private {boolean} */
+ this._isBodyOverflowing = false
- Modal.prototype.toggle = function (_relatedTarget) {
- return this.isShown ? this.hide() : this.show(_relatedTarget)
- }
+ /** @private {number} */
+ this._scrollbarWidth = 0
- Modal.prototype.show = function (_relatedTarget) {
- var that = this
- var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+}
- this.$element.trigger(e)
- if (this.isShown || e.isDefaultPrevented()) return
+/**
+ * @const
+ * @type {string}
+ */
+Modal['VERSION'] = '4.0.0'
- this.isShown = true
- this.checkScrollbar()
- this.setScrollbar()
- this.$body.addClass('modal-open')
+/**
+ * @const
+ * @type {Object}
+ */
+Modal['Defaults'] = {
+ 'backdrop' : true,
+ 'keyboard' : true,
+ 'show' : true
+}
- this.escape()
- this.resize()
- this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Modal._NAME = 'modal'
- this.backdrop(function () {
- var transition = $.support.transition && that.$element.hasClass('fade')
- if (!that.$element.parent().length) {
- that.$element.appendTo(that.$body) // don't move modals dom position
- }
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Modal._DATA_KEY = 'bs.modal'
- that.$element
- .show()
- .scrollTop(0)
- if (that.options.backdrop) that.adjustBackdrop()
- that.adjustDialog()
+/**
+ * @const
+ * @type {number}
+ * @private
+ */
+Modal._TRANSITION_DURATION = 300
- if (transition) {
- that.$element[0].offsetWidth // force reflow
- }
- that.$element
- .addClass('in')
- .attr('aria-hidden', false)
+/**
+ * @const
+ * @type {number}
+ * @private
+ */
+Modal._BACKDROP_TRANSITION_DURATION = 150
- that.enforceFocus()
- var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Modal._JQUERY_NO_CONFLICT = $.fn[Modal._NAME]
- transition ?
- that.$element.find('.modal-dialog') // wait for modal to slide in
- .one('bsTransitionEnd', function () {
- that.$element.trigger('focus').trigger(e)
- })
- .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
- that.$element.trigger('focus').trigger(e)
- })
- }
- Modal.prototype.hide = function (e) {
- if (e) e.preventDefault()
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Modal._Event = {
+ HIDE : 'hide.bs.modal',
+ HIDDEN : 'hidden.bs.modal',
+ SHOW : 'show.bs.modal',
+ SHOWN : 'shown.bs.modal'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Modal._ClassName = {
+ BACKDROP : 'modal-backdrop',
+ OPEN : 'modal-open',
+ FADE : 'fade',
+ IN : 'in'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Modal._Selector = {
+ DIALOG : '.modal-dialog',
+ DATA_TOGGLE : '[data-toggle="modal"]',
+ DATA_DISMISS : '[data-dismiss="modal"]',
+ SCROLLBAR_MEASURER : 'modal-scrollbar-measure'
+}
- e = $.Event('hide.bs.modal')
- this.$element.trigger(e)
- if (!this.isShown || e.isDefaultPrevented()) return
+/**
+ * Provides the jQuery Interface for the alert component.
+ * @param {Object|string=} opt_config
+ * @param {Element=} opt_relatedTarget
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Modal._jQueryInterface = function Plugin(opt_config, opt_relatedTarget) {
+ return this.each(function () {
+ var data = $(this).data(Modal._DATA_KEY)
+ var config = $.extend({}, Modal['Defaults'], $(this).data(), typeof opt_config == 'object' && opt_config)
+
+ if (!data) {
+ data = new Modal(this, config)
+ $(this).data(Modal._DATA_KEY, data)
+ }
- this.isShown = false
+ if (typeof opt_config == 'string') {
+ data[opt_config](opt_relatedTarget)
+
+ } else if (config['show']) {
+ data['show'](opt_relatedTarget)
+ }
+ })
+}
- this.escape()
- this.resize()
- $(document).off('focusin.bs.modal')
+/**
+ * @param {Element} relatedTarget
+ */
+Modal.prototype['toggle'] = function (relatedTarget) {
+ return this._isShown ? this['hide']() : this['show'](relatedTarget)
+}
- this.$element
- .removeClass('in')
- .attr('aria-hidden', true)
- .off('click.dismiss.bs.modal')
- $.support.transition && this.$element.hasClass('fade') ?
- this.$element
- .one('bsTransitionEnd', $.proxy(this.hideModal, this))
- .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
- this.hideModal()
+/**
+ * @param {Element} relatedTarget
+ */
+Modal.prototype['show'] = function (relatedTarget) {
+ var showEvent = $.Event(Modal._Event.SHOW, { relatedTarget: relatedTarget })
+
+ $(this._element).trigger(showEvent)
+
+ if (this._isShown || showEvent.isDefaultPrevented()) {
+ return
}
- Modal.prototype.enforceFocus = function () {
- $(document)
- .off('focusin.bs.modal') // guard against infinite focus loop
- .on('focusin.bs.modal', $.proxy(function (e) {
- if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
- this.$element.trigger('focus')
- }
- }, this))
+ this._isShown = true
+
+ this._checkScrollbar()
+ this._setScrollbar()
+
+ $(document.body).addClass(Modal._ClassName.OPEN)
+
+ this._escape()
+ this._resize()
+
+ $(this._element).on('click.dismiss.bs.modal', Modal._Selector.DATA_DISMISS, this['hide'].bind(this))
+
+ this._showBackdrop(this._showElement.bind(this, relatedTarget))
+}
+
+
+/**
+ * @param {Event} event
+ */
+Modal.prototype['hide'] = function (event) {
+ if (event) {
+ event.preventDefault()
}
- Modal.prototype.escape = function () {
- if (this.isShown && this.options.keyboard) {
- this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
- e.which == 27 && this.hide()
- }, this))
- } else if (!this.isShown) {
- this.$element.off('keydown.dismiss.bs.modal')
- }
+ var hideEvent = $.Event(Modal._Event.HIDE)
+
+ $(this._element).trigger(hideEvent)
+
+ if (!this._isShown || hideEvent.isDefaultPrevented()) {
+ return
}
- Modal.prototype.resize = function () {
- if (this.isShown) {
- $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
- } else {
- $(window).off('resize.bs.modal')
- }
+ this._isShown = false
+
+ this._escape()
+ this._resize()
+
+ $(document).off('focusin.bs.modal')
+
+ $(this._element).removeClass(Modal._ClassName.IN)
+ this._element.setAttribute('aria-hidden', true)
+
+ $(this._element).off('click.dismiss.bs.modal')
+
+ if (Bootstrap.transition && $(this._element).hasClass(Modal._ClassName.FADE)) {
+ $(this._element)
+ .one(Bootstrap.TRANSITION_END, this._hideModal.bind(this))
+ .emulateTransitionEnd(Modal._TRANSITION_DURATION)
+ } else {
+ this._hideModal()
}
+}
- Modal.prototype.hideModal = function () {
- var that = this
- this.$element.hide()
- this.backdrop(function () {
- that.$body.removeClass('modal-open')
- that.resetAdjustments()
- that.resetScrollbar()
- that.$element.trigger('hidden.bs.modal')
- })
+
+/**
+ * @param {Element} relatedTarget
+ * @private
+ */
+Modal.prototype._showElement = function (relatedTarget) {
+ var transition = Bootstrap.transition && $(this._element).hasClass(Modal._ClassName.FADE)
+
+ if (!this._element.parentNode || this._element.parentNode.nodeType != Node.ELEMENT_NODE) {
+ document.body.appendChild(this._element) // don't move modals dom position
}
- Modal.prototype.removeBackdrop = function () {
- this.$backdrop && this.$backdrop.remove()
- this.$backdrop = null
+ this._element.style.display = 'block'
+ this._element.scrollTop = 0
+
+ if (this._config['backdrop']) {
+ this._adjustBackdrop()
}
- Modal.prototype.backdrop = function (callback) {
- var that = this
- var animate = this.$element.hasClass('fade') ? 'fade' : ''
+ if (transition) {
+ Bootstrap.reflow(this._element)
+ }
- if (this.isShown && this.options.backdrop) {
- var doAnimate = $.support.transition && animate
+ $(this._element).addClass(Modal._ClassName.IN)
+ this._element.setAttribute('aria-hidden', false)
- this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
- .prependTo(this.$element)
- .on('click.dismiss.bs.modal', $.proxy(function (e) {
- if (e.target !== e.currentTarget) return
- this.options.backdrop == 'static'
- ? this.$element[0].focus.call(this.$element[0])
- : this.hide.call(this)
- }, this))
+ this._enforceFocus()
- if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+ var shownEvent = $.Event(Modal._Event.SHOWN, { relatedTarget: relatedTarget })
- this.$backdrop.addClass('in')
+ var transitionComplete = function () {
+ this._element.focus()
+ $(this._element).trigger(shownEvent)
+ }.bind(this)
- if (!callback) return
+ if (transition) {
+ var dialog = $(this._element).find(Modal._Selector.DIALOG)[0]
+ $(dialog)
+ .one(Bootstrap.TRANSITION_END, transitionComplete)
+ .emulateTransitionEnd(Modal._TRANSITION_DURATION)
+ } else {
+ transitionComplete()
+ }
+}
- doAnimate ?
- this.$backdrop
- .one('bsTransitionEnd', callback)
- .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
- callback()
- } else if (!this.isShown && this.$backdrop) {
- this.$backdrop.removeClass('in')
- var callbackRemove = function () {
- that.removeBackdrop()
- callback && callback()
+/**
+ * @private
+ */
+Modal.prototype._enforceFocus = function () {
+ $(document)
+ .off('focusin.bs.modal') // guard against infinite focus loop
+ .on('focusin.bs.modal', function (e) {
+ if (this._element !== e.target && !$(this._element).has(e.target).length) {
+ this._element.focus()
}
- $.support.transition && this.$element.hasClass('fade') ?
- this.$backdrop
- .one('bsTransitionEnd', callbackRemove)
- .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
- callbackRemove()
+ }.bind(this))
+}
- } else if (callback) {
- callback()
- }
- }
- // these following methods are used to handle overflowing modals
+/**
+ * @private
+ */
+Modal.prototype._escape = function () {
+ if (this._isShown && this._config['keyboard']) {
+ $(this._element).on('keydown.dismiss.bs.modal', function (event) {
+ if (event.which === 27) {
+ this['hide']()
+ }
+ }.bind(this))
- Modal.prototype.handleUpdate = function () {
- if (this.options.backdrop) this.adjustBackdrop()
- this.adjustDialog()
+ } else if (!this._isShown) {
+ $(this._element).off('keydown.dismiss.bs.modal')
}
+}
+
- Modal.prototype.adjustBackdrop = function () {
- this.$backdrop
- .css('height', 0)
- .css('height', this.$element[0].scrollHeight)
+/**
+ * @private
+ */
+Modal.prototype._resize = function () {
+ if (this._isShown) {
+ $(window).on('resize.bs.modal', this._handleUpdate.bind(this))
+ } else {
+ $(window).off('resize.bs.modal')
}
+}
- Modal.prototype.adjustDialog = function () {
- var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
- this.$element.css({
- paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
- paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
- })
- }
+/**
+ * @private
+ */
+Modal.prototype._hideModal = function () {
+ this._element.style.display = 'none'
+ this._showBackdrop(function () {
+ $(document.body).removeClass(Modal._ClassName.OPEN)
+ this._resetAdjustments()
+ this._resetScrollbar()
+ $(this._element).trigger(Modal._Event.HIDDEN)
+ }.bind(this))
+}
- Modal.prototype.resetAdjustments = function () {
- this.$element.css({
- paddingLeft: '',
- paddingRight: ''
- })
- }
- Modal.prototype.checkScrollbar = function () {
- this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight
- this.scrollbarWidth = this.measureScrollbar()
+/**
+ * @private
+ */
+Modal.prototype._removeBackdrop = function () {
+ if (this._backdrop) {
+ this._backdrop.parentNode.removeChild(this._backdrop)
+ this._backdrop = null
}
+}
+
+
+/**
+ * @param {Function} callback
+ * @private
+ */
+Modal.prototype._showBackdrop = function (callback) {
+ var animate = $(this._element).hasClass(Modal._ClassName.FADE) ? Modal._ClassName.FADE : ''
+
+ if (this._isShown && this._config['backdrop']) {
+ var doAnimate = Bootstrap.transition && animate
- Modal.prototype.setScrollbar = function () {
- var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
- if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+ this._backdrop = document.createElement('div')
+ this._backdrop.className = Modal._ClassName.BACKDROP
+
+ if (animate) {
+ $(this._backdrop).addClass(animate)
+ }
+
+ $(this._element).prepend(this._backdrop)
+
+ $(this._backdrop).on('click.dismiss.bs.modal', function (event) {
+ if (event.target !== event.currentTarget) return
+ this._config['backdrop'] === 'static'
+ ? this._element.focus()
+ : this['hide']()
+ }.bind(this))
+
+ if (doAnimate) {
+ Bootstrap.reflow(this._backdrop)
+ }
+
+ $(this._backdrop).addClass(Modal._ClassName.IN)
+
+ if (!callback) {
+ return
+ }
+
+ if (!doAnimate) {
+ callback()
+ return
+ }
+
+ $(this._backdrop)
+ .one(Bootstrap.TRANSITION_END, callback)
+ .emulateTransitionEnd(Modal._BACKDROP_TRANSITION_DURATION)
+
+ } else if (!this._isShown && this._backdrop) {
+ $(this._backdrop).removeClass(Modal._ClassName.IN)
+
+ var callbackRemove = function () {
+ this._removeBackdrop()
+ if (callback) {
+ callback()
+ }
+ }.bind(this)
+
+ if (Bootstrap.transition && $(this._element).hasClass(Modal._ClassName.FADE)) {
+ $(this._backdrop)
+ .one(Bootstrap.TRANSITION_END, callbackRemove)
+ .emulateTransitionEnd(Modal._BACKDROP_TRANSITION_DURATION)
+ } else {
+ callbackRemove()
+ }
+
+ } else if (callback) {
+ callback()
}
+}
+
+
+/**
+ * ------------------------------------------------------------------------
+ * the following methods are used to handle overflowing modals
+ * todo (fat): these should probably be refactored into a
+ * ------------------------------------------------------------------------
+ */
+
+
+/**
+ * @private
+ */
+Modal.prototype._handleUpdate = function () {
+ if (this._config['backdrop']) this._adjustBackdrop()
+ this._adjustDialog()
+}
+
+/**
+ * @private
+ */
+Modal.prototype._adjustBackdrop = function () {
+ this._backdrop.style.height = 0 // todo (fat): no clue why we do this
+ this._backdrop.style.height = this._element.scrollHeight + 'px'
+}
+
+
+/**
+ * @private
+ */
+Modal.prototype._adjustDialog = function () {
+ var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight
- Modal.prototype.resetScrollbar = function () {
- this.$body.css('padding-right', '')
+ if (!this._isBodyOverflowing && isModalOverflowing) {
+ this._element.style.paddingLeft = this._scrollbarWidth + 'px'
}
- Modal.prototype.measureScrollbar = function () { // thx walsh
- var scrollDiv = document.createElement('div')
- scrollDiv.className = 'modal-scrollbar-measure'
- this.$body.append(scrollDiv)
- var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
- this.$body[0].removeChild(scrollDiv)
- return scrollbarWidth
+ if (this._isBodyOverflowing && !isModalOverflowing) {
+ this._element.style.paddingRight = this._scrollbarWidth + 'px'
}
+}
- // MODAL PLUGIN DEFINITION
- // =======================
+/**
+ * @private
+ */
+Modal.prototype._resetAdjustments = function () {
+ this._element.style.paddingLeft = ''
+ this._element.style.paddingRight = ''
+}
- function Plugin(option, _relatedTarget) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.modal')
- var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
- if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
- if (typeof option == 'string') data[option](_relatedTarget)
- else if (options.show) data.show(_relatedTarget)
- })
+/**
+ * @private
+ */
+Modal.prototype._checkScrollbar = function () {
+ this._isBodyOverflowing = document.body.scrollHeight > document.documentElement.clientHeight
+ this._scrollbarWidth = this._getScrollbarWidth()
+}
+
+
+/**
+ * @private
+ */
+Modal.prototype._setScrollbar = function () {
+ var bodyPadding = parseInt(($(document.body).css('padding-right') || 0), 10)
+
+ if (this._isBodyOverflowing) {
+ document.body.style.paddingRight = bodyPadding + this._scrollbarWidth + 'px'
}
+}
- var old = $.fn.modal
- $.fn.modal = Plugin
- $.fn.modal.Constructor = Modal
+/**
+ * @private
+ */
+Modal.prototype._resetScrollbar = function () {
+ document.body.style.paddingRight = ''
+}
- // MODAL NO CONFLICT
- // =================
+/**
+ * @private
+ */
+Modal.prototype._getScrollbarWidth = function () { // thx walsh
+ var scrollDiv = document.createElement('div')
+ scrollDiv.className = Modal._Selector.SCROLLBAR_MEASURER
+ document.body.appendChild(scrollDiv)
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+ document.body.removeChild(scrollDiv)
+ return scrollbarWidth
+}
- $.fn.modal.noConflict = function () {
- $.fn.modal = old
- return this
- }
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Modal._NAME] = Modal._jQueryInterface
- // MODAL DATA-API
- // ==============
- $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
- var $this = $(this)
- var href = $this.attr('href')
- var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
- var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Modal._NAME]['Constructor'] = Modal
- if ($this.is('a')) e.preventDefault()
- $target.one('show.bs.modal', function (showEvent) {
- if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
- $target.one('hidden.bs.modal', function () {
- $this.is(':visible') && $this.trigger('focus')
- })
- })
- Plugin.call($target, option, this)
- })
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Modal._NAME]['noConflict'] = function () {
+ $.fn[Modal._NAME] = Modal._JQUERY_NO_CONFLICT
+ return this
+}
-}(jQuery);
-/* ========================================================================
- * Bootstrap: tooltip.js v3.3.2
- * http://getbootstrap.com/javascript/#tooltip
- * Inspired by the original jQuery.tipsy by Jason Frame
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+$(document).on('click.bs.modal.data-api', Modal._Selector.DATA_TOGGLE, function (event) {
+ var selector = Bootstrap.getSelectorFromElement(this)
+
+ if (selector) {
+ var target = $(selector)[0]
+ }
+
+ var config = $(target).data(Modal._DATA_KEY) ? 'toggle' : $.extend({}, $(target).data(), $(this).data())
+
+ if (this.tagName == 'A') {
+ event.preventDefault()
+ }
+
+ var $target = $(target).one(Modal._Event.SHOW, function (showEvent) {
+ if (showEvent.isDefaultPrevented()) {
+ return // only register focus restorer if modal will actually get shown
+ }
+
+ $target.one(Modal._Event.HIDDEN, function () {
+ if ($(this).is(':visible')) {
+ this.focus()
+ }
+ }.bind(this))
+ }.bind(this))
+
+ Modal._jQueryInterface.call($(target), config, this)
+})
+
+/** =======================================================================
+ * Bootstrap: scrollspy.js v4.0.0
+ * http://getbootstrap.com/javascript/#scrollspy
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Bootstrap's scrollspy plugin.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.scrollspy
+ * + $.scrollspy.noConflict
+ * + $.scrollspy.Constructor
+ * + $.scrollspy.Constructor.VERSION
+ * + $.scrollspy.Constructor.Defaults
+ * + $.scrollspy.Constructor.Defaults.offset
+ * + $.scrollspy.Constructor.prototype.refresh
+ *
+ * ========================================================================
+ */
+'use strict';
-+function ($) {
- 'use strict';
- // TOOLTIP PUBLIC CLASS DEFINITION
- // ===============================
+/**
+ * Our scrollspy class.
+ * @param {Element!} element
+ * @param {Object=} opt_config
+ * @constructor
+ */
+function ScrollSpy(element, opt_config) {
+
+ /** @private {Element|Window} */
+ this._scrollElement = element.tagName == 'BODY' ? window : element
- var Tooltip = function (element, options) {
- this.type =
- this.options =
- this.enabled =
- this.timeout =
- this.hoverState =
- this.$element = null
+ /** @private {Object} */
+ this._config = $.extend({}, ScrollSpy['Defaults'], opt_config)
- this.init('tooltip', element, options)
- }
+ /** @private {string} */
+ this._selector = (this._config.target || '') + ' .nav li > a'
+
+ /** @private {Array} */
+ this._offsets = []
+
+ /** @private {Array} */
+ this._targets = []
+
+ /** @private {Element} */
+ this._activeTarget = null
+
+ /** @private {number} */
+ this._scrollHeight = 0
+
+ $(this._scrollElement).on('scroll.bs.scrollspy', this._process.bind(this))
+
+ this['refresh']()
+
+ this._process()
+}
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ScrollSpy['VERSION'] = '4.0.0'
+
+
+/**
+ * @const
+ * @type {Object}
+ */
+ScrollSpy['Defaults'] = {
+ 'offset': 10
+}
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ScrollSpy._NAME = 'scrollspy'
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ScrollSpy._DATA_KEY = 'bs.scrollspy'
+
+
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+ScrollSpy._JQUERY_NO_CONFLICT = $.fn[ScrollSpy._NAME]
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+ScrollSpy._Event = {
+ ACTIVATE: 'activate.bs.scrollspy'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+ScrollSpy._ClassName = {
+ DROPDOWN_MENU : 'dropdown-menu',
+ ACTIVE : 'active'
+}
- Tooltip.VERSION = '3.3.2'
- Tooltip.TRANSITION_DURATION = 150
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+ScrollSpy._Selector = {
+ DATA_SPY : '[data-spy="scroll"]',
+ ACTIVE : '.active',
+ LI_DROPDOWN : 'li.dropdown',
+ LI : 'li'
+}
- Tooltip.DEFAULTS = {
- animation: true,
- placement: 'top',
- selector: false,
- template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
- trigger: 'hover focus',
- title: '',
- delay: 0,
- html: false,
- container: false,
- viewport: {
- selector: 'body',
- padding: 0
+
+/**
+ * @param {Object=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+ScrollSpy._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var data = $(this).data(ScrollSpy._DATA_KEY)
+ var config = typeof opt_config === 'object' && opt_config || null
+
+ if (!data) {
+ data = new ScrollSpy(this, config)
+ $(this).data(ScrollSpy._DATA_KEY, data)
}
+
+ if (typeof opt_config === 'string') {
+ data[opt_config]()
+ }
+ })
+}
+
+
+/**
+ * Refresh the scrollspy target cache
+ */
+ScrollSpy.prototype['refresh'] = function () {
+ var offsetMethod = 'offset'
+ var offsetBase = 0
+
+ if (this._scrollElement !== this._scrollElement.window) {
+ offsetMethod = 'position'
+ offsetBase = this._getScrollTop()
}
- Tooltip.prototype.init = function (type, element, options) {
- this.enabled = true
- this.type = type
- this.$element = $(element)
- this.options = this.getOptions(options)
- this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
+ this._offsets = []
+ this._targets = []
- var triggers = this.options.trigger.split(' ')
+ this._scrollHeight = this._getScrollHeight()
- for (var i = triggers.length; i--;) {
- var trigger = triggers[i]
+ var targets = /** @type {Array.<Element>} */ ($.makeArray($(this._selector)))
- if (trigger == 'click') {
- this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
- } else if (trigger != 'manual') {
- var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
- var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+ targets
+ .map(function (element, index) {
+ var target
+ var targetSelector = Bootstrap.getSelectorFromElement(element)
- this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
- this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ if (targetSelector) {
+ target = $(targetSelector)[0]
}
- }
- this.options.selector ?
- (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
- this.fixTitle()
+ if (target && (target.offsetWidth || target.offsetHeight)) {
+ // todo (fat): remove sketch reliance on jQuery position/offset
+ return [$(target)[offsetMethod]().top + offsetBase, targetSelector]
+ }
+ })
+ .filter(function (item) { return item })
+ .sort(function (a, b) { return a[0] - b[0] })
+ .forEach(function (item, index) {
+ this._offsets.push(item[0])
+ this._targets.push(item[1])
+ }.bind(this))
+}
+
+
+/**
+ * @private
+ */
+ScrollSpy.prototype._getScrollTop = function () {
+ return this._scrollElement === window ?
+ this._scrollElement.scrollY : this._scrollElement.scrollTop
+}
+
+
+/**
+ * @private
+ */
+ScrollSpy.prototype._getScrollHeight = function () {
+ return this._scrollElement.scrollHeight
+ || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)
+}
+
+
+/**
+ * @private
+ */
+ScrollSpy.prototype._process = function () {
+ var scrollTop = this._getScrollTop() + this._config.offset
+ var scrollHeight = this._getScrollHeight()
+ var maxScroll = this._config.offset + scrollHeight - this._scrollElement.offsetHeight
+
+ if (this._scrollHeight != scrollHeight) {
+ this['refresh']()
}
- Tooltip.prototype.getDefaults = function () {
- return Tooltip.DEFAULTS
+ if (scrollTop >= maxScroll) {
+ var target = this._targets[this._targets.length - 1]
+
+ if (this._activeTarget != target) {
+ this._activate(target)
+ }
}
- Tooltip.prototype.getOptions = function (options) {
- options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+ if (this._activeTarget && scrollTop < this._offsets[0]) {
+ this._activeTarget = null
+ this._clear()
+ return
+ }
- if (options.delay && typeof options.delay == 'number') {
- options.delay = {
- show: options.delay,
- hide: options.delay
- }
+ for (var i = this._offsets.length; i--;) {
+ var isActiveTarget = this._activeTarget != this._targets[i]
+ && scrollTop >= this._offsets[i]
+ && (!this._offsets[i + 1] || scrollTop < this._offsets[i + 1])
+
+ if (isActiveTarget) {
+ this._activate(this._targets[i])
}
+ }
+}
+
+
+/**
+ * @param {Element} target
+ * @private
+ */
+ScrollSpy.prototype._activate = function (target) {
+ this._activeTarget = target
+
+ this._clear()
+
+ var selector = this._selector
+ + '[data-target="' + target + '"],'
+ + this._selector + '[href="' + target + '"]'
+
+ // todo (fat): this seems horribly wrong… getting all raw li elements up the tree ,_,
+ var parentListItems = $(selector).parents(ScrollSpy._Selector.LI)
- return options
+ for (var i = parentListItems.length; i--;) {
+ $(parentListItems[i]).addClass(ScrollSpy._ClassName.ACTIVE)
+
+ var itemParent = parentListItems[i].parentNode
+
+ if (itemParent && $(itemParent).hasClass(ScrollSpy._ClassName.DROPDOWN_MENU)) {
+ var closestDropdown = $(itemParent).closest(ScrollSpy._Selector.LI_DROPDOWN)[0]
+ $(closestDropdown).addClass(ScrollSpy._ClassName.ACTIVE)
+ }
}
- Tooltip.prototype.getDelegateOptions = function () {
- var options = {}
- var defaults = this.getDefaults()
+ $(this._scrollElement).trigger(ScrollSpy._Event.ACTIVATE, {
+ relatedTarget: target
+ })
+}
- this._options && $.each(this._options, function (key, value) {
- if (defaults[key] != value) options[key] = value
- })
- return options
+/**
+ * @private
+ */
+ScrollSpy.prototype._clear = function () {
+ var activeParents = $(this._selector).parentsUntil(this._config.target, ScrollSpy._Selector.ACTIVE)
+
+ for (var i = activeParents.length; i--;) {
+ $(activeParents[i]).removeClass(ScrollSpy._ClassName.ACTIVE)
}
+}
- Tooltip.prototype.enter = function (obj) {
- var self = obj instanceof this.constructor ?
- obj : $(obj.currentTarget).data('bs.' + this.type)
- if (self && self.$tip && self.$tip.is(':visible')) {
- self.hoverState = 'in'
- return
- }
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
- if (!self) {
- self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
- $(obj.currentTarget).data('bs.' + this.type, self)
- }
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[ScrollSpy._NAME] = ScrollSpy._jQueryInterface
- clearTimeout(self.timeout)
- self.hoverState = 'in'
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[ScrollSpy._NAME]['Constructor'] = ScrollSpy
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[ScrollSpy._NAME]['noConflict'] = function () {
+ $.fn[ScrollSpy._NAME] = ScrollSpy._JQUERY_NO_CONFLICT
+ return this
+}
- if (!self.options.delay || !self.options.delay.show) return self.show()
- self.timeout = setTimeout(function () {
- if (self.hoverState == 'in') self.show()
- }, self.options.delay.show)
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+$(window).on('load.bs.scrollspy.data-api', function () {
+ var scrollSpys = /** @type {Array.<Element>} */ ($.makeArray($(ScrollSpy._Selector.DATA_SPY)))
+
+ for (var i = scrollSpys.length; i--;) {
+ var $spy = $(scrollSpys[i])
+ ScrollSpy._jQueryInterface.call($spy, /** @type {Object|null} */ ($spy.data()))
}
+})
- Tooltip.prototype.leave = function (obj) {
- var self = obj instanceof this.constructor ?
- obj : $(obj.currentTarget).data('bs.' + this.type)
+/** =======================================================================
+ * Bootstrap: tooltip.js v4.0.0
+ * http://getbootstrap.com/javascript/#tooltip
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ========================================================================
+ * @fileoverview - Bootstrap's tooltip plugin.
+ * (Inspired by jQuery.tipsy by Jason Frame)
+ *
+ * Public Methods & Properties:
+ *
+ * + $.tooltip
+ * + $.tooltip.noConflict
+ * + $.tooltip.Constructor
+ * + $.tooltip.Constructor.VERSION
+ * + $.tooltip.Constructor.Defaults
+ * + $.tooltip.Constructor.Defaults.container
+ * + $.tooltip.Constructor.Defaults.animation
+ * + $.tooltip.Constructor.Defaults.placement
+ * + $.tooltip.Constructor.Defaults.selector
+ * + $.tooltip.Constructor.Defaults.template
+ * + $.tooltip.Constructor.Defaults.trigger
+ * + $.tooltip.Constructor.Defaults.title
+ * + $.tooltip.Constructor.Defaults.delay
+ * + $.tooltip.Constructor.Defaults.html
+ * + $.tooltip.Constructor.Defaults.viewport
+ * + $.tooltip.Constructor.Defaults.viewport.selector
+ * + $.tooltip.Constructor.Defaults.viewport.padding
+ * + $.tooltip.Constructor.prototype.enable
+ * + $.tooltip.Constructor.prototype.disable
+ * + $.tooltip.Constructor.prototype.destroy
+ * + $.tooltip.Constructor.prototype.toggleEnabled
+ * + $.tooltip.Constructor.prototype.toggle
+ * + $.tooltip.Constructor.prototype.show
+ * + $.tooltip.Constructor.prototype.hide
+ *
+ * ========================================================================
+ */
- if (!self) {
- self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
- $(obj.currentTarget).data('bs.' + this.type, self)
- }
+'use strict';
+
+
+/**
+ * Our tooltip class.
+ * @param {Element!} element
+ * @param {Object=} opt_config
+ * @constructor
+ */
+var Tooltip = function (element, opt_config) {
+
+ /** @private {boolean} */
+ this._isEnabled = true
+
+ /** @private {number} */
+ this._timeout = 0
+
+ /** @private {string} */
+ this._hoverState = ''
+
+ /** @protected {Element} */
+ this.element = element
- clearTimeout(self.timeout)
+ /** @protected {Object} */
+ this.config = this._getConfig(opt_config)
- self.hoverState = 'out'
+ /** @protected {Element} */
+ this.tip = null
- if (!self.options.delay || !self.options.delay.hide) return self.hide()
+ /** @protected {Element} */
+ this.arrow = null
+
+ if (this.config['viewport']) {
+
+ /** @private {Element} */
+ this._viewport = $(this.config['viewport']['selector'] || this.config['viewport'])[0]
- self.timeout = setTimeout(function () {
- if (self.hoverState == 'out') self.hide()
- }, self.options.delay.hide)
}
- Tooltip.prototype.show = function () {
- var e = $.Event('show.bs.' + this.type)
+ this._setListeners()
+}
- if (this.hasContent() && this.enabled) {
- this.$element.trigger(e)
- var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
- if (e.isDefaultPrevented() || !inDom) return
- var that = this
+/**
+ * @const
+ * @type {string}
+ */
+Tooltip['VERSION'] = '4.0.0'
- var $tip = this.tip()
- var tipId = this.getUID(this.type)
+/**
+ * @const
+ * @type {Object}
+ */
+Tooltip['Defaults'] = {
+ 'container' : false,
+ 'animation' : true,
+ 'placement' : 'top',
+ 'selector' : false,
+ 'template' : '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+ 'trigger' : 'hover focus',
+ 'title' : '',
+ 'delay' : 0,
+ 'html' : false,
+ 'viewport': {
+ 'selector': 'body',
+ 'padding' : 0
+ }
+}
- this.setContent()
- $tip.attr('id', tipId)
- this.$element.attr('aria-describedby', tipId)
- if (this.options.animation) $tip.addClass('fade')
+/**
+ * @const
+ * @enum {string}
+ * @protected
+ */
+Tooltip.Direction = {
+ TOP: 'top',
+ LEFT: 'left',
+ RIGHT: 'right',
+ BOTTOM: 'bottom'
+}
- var placement = typeof this.options.placement == 'function' ?
- this.options.placement.call(this, $tip[0], this.$element[0]) :
- this.options.placement
- var autoToken = /\s?auto?\s?/i
- var autoPlace = autoToken.test(placement)
- if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Tooltip._NAME = 'tooltip'
- $tip
- .detach()
- .css({ top: 0, left: 0, display: 'block' })
- .addClass(this.type + '-' + placement)
- .data('bs.' + this.type, this)
- this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Tooltip._DATA_KEY = 'bs.tooltip'
- var pos = this.getPosition()
- var actualWidth = $tip[0].offsetWidth
- var actualHeight = $tip[0].offsetHeight
- if (autoPlace) {
- var origPlacement = placement
- var $container = this.options.container ? $(this.options.container) : this.$element.parent()
- var containerDim = this.getPosition($container)
+/**
+ * @const
+ * @type {number}
+ * @private
+ */
+Tooltip._TRANSITION_DURATION = 150
- placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
- placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
- placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
- placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
- placement
- $tip
- .removeClass(this.type + '-' + origPlacement)
- .addClass(this.type + '-' + placement)
- }
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Tooltip._HoverState = {
+ IN: 'in',
+ OUT: 'out'
+}
- var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
- this.applyPlacement(calculatedOffset, placement)
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Tooltip._Event = {
+ HIDE : 'hide.bs.tooltip',
+ HIDDEN : 'hidden.bs.tooltip',
+ SHOW : 'show.bs.tooltip',
+ SHOWN : 'shown.bs.tooltip'
+}
- var complete = function () {
- var prevHoverState = that.hoverState
- that.$element.trigger('shown.bs.' + that.type)
- that.hoverState = null
- if (prevHoverState == 'out') that.leave(that)
- }
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Tooltip._ClassName = {
+ FADE : 'fade',
+ IN : 'in'
+}
- $.support.transition && this.$tip.hasClass('fade') ?
- $tip
- .one('bsTransitionEnd', complete)
- .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
- complete()
- }
- }
- Tooltip.prototype.applyPlacement = function (offset, placement) {
- var $tip = this.tip()
- var width = $tip[0].offsetWidth
- var height = $tip[0].offsetHeight
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Tooltip._Selector = {
+ TOOLTIP : '.tooltip',
+ TOOLTIP_INNER : '.tooltip-inner',
+ TOOLTIP_ARROW : '.tooltip-arrow'
+}
- // manually read margins because getBoundingClientRect includes difference
- var marginTop = parseInt($tip.css('margin-top'), 10)
- var marginLeft = parseInt($tip.css('margin-left'), 10)
- // we must check for NaN for IE9
- if (isNaN(marginTop)) marginTop = 0
- if (isNaN(marginLeft)) marginLeft = 0
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Tooltip._JQUERY_NO_CONFLICT = $.fn[Tooltip._NAME]
- offset.top = offset.top + marginTop
- offset.left = offset.left + marginLeft
- // $.fn.offset doesn't round pixel values
- // so we use setOffset directly with our own function B-0
- $.offset.setOffset($tip[0], $.extend({
- using: function (props) {
- $tip.css({
- top: Math.round(props.top),
- left: Math.round(props.left)
- })
- }
- }, offset), 0)
+/**
+ * @param {Object=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Tooltip._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var data = $(this).data(Tooltip._DATA_KEY)
+ var config = typeof opt_config == 'object' ? opt_config : null
- $tip.addClass('in')
+ if (!data && opt_config == 'destroy') {
+ return
+ }
- // check to see if placing tip in new offset caused the tip to resize itself
- var actualWidth = $tip[0].offsetWidth
- var actualHeight = $tip[0].offsetHeight
+ if (!data) {
+ data = new Tooltip(this, config)
+ $(this).data(Tooltip._DATA_KEY, data)
+ }
- if (placement == 'top' && actualHeight != height) {
- offset.top = offset.top + height - actualHeight
+ if (typeof opt_config === 'string') {
+ data[opt_config]()
}
+ })
+}
- var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
- if (delta.left) offset.left += delta.left
- else offset.top += delta.top
+/**
+ * Enable tooltip
+ */
+Tooltip.prototype['enable'] = function () {
+ this._isEnabled = true
+}
- var isVertical = /top|bottom/.test(placement)
- var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
- var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
- $tip.offset(offset)
- this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
- }
+/**
+ * Disable tooltip
+ */
+Tooltip.prototype['disable'] = function () {
+ this._isEnabled = false
+}
- Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {
- this.arrow()
- .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
- .css(isHorizontal ? 'top' : 'left', '')
- }
- Tooltip.prototype.setContent = function () {
- var $tip = this.tip()
- var title = this.getTitle()
+/**
+ * Toggle the tooltip enable state
+ */
+Tooltip.prototype['toggleEnabled'] = function () {
+ this._isEnabled = !this._isEnabled
+}
- $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
- $tip.removeClass('fade in tooltip-top tooltip-bottom tooltip-left tooltip-right')
- }
+/**
+ * Toggle the tooltips display
+ * @param {Event} opt_event
+ */
+Tooltip.prototype['toggle'] = function (opt_event) {
+ var context = this
+ var dataKey = this.getDataKey()
- Tooltip.prototype.hide = function (callback) {
- var that = this
- var $tip = this.tip()
- var e = $.Event('hide.bs.' + this.type)
+ if (opt_event) {
+ context = $(opt_event.currentTarget).data(dataKey)
- function complete() {
- if (that.hoverState != 'in') $tip.detach()
- that.$element
- .removeAttr('aria-describedby')
- .trigger('hidden.bs.' + that.type)
- callback && callback()
+ if (!context) {
+ context = new this.constructor(opt_event.currentTarget, this._getDelegateConfig())
+ $(opt_event.currentTarget).data(dataKey, context)
}
+ }
- this.$element.trigger(e)
+ $(context.getTipElement()).hasClass(Tooltip._ClassName.IN) ?
+ context._leave(null, context) :
+ context._enter(null, context)
+}
- if (e.isDefaultPrevented()) return
- $tip.removeClass('in')
+/**
+ * Remove tooltip functionality
+ */
+Tooltip.prototype['destroy'] = function () {
+ clearTimeout(this._timeout)
+ this['hide'](function () {
+ $(this.element)
+ .off(Tooltip._Selector.TOOLTIP)
+ .removeData(this.getDataKey())
+ }.bind(this))
+}
- $.support.transition && this.$tip.hasClass('fade') ?
- $tip
- .one('bsTransitionEnd', complete)
- .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
- complete()
- this.hoverState = null
+/**
+ * Show the tooltip
+ * todo (fat): ~fuck~ this is a big function - refactor out all of positioning logic
+ * and replace with external lib
+ */
+Tooltip.prototype['show'] = function () {
+ var showEvent = $.Event(this.getEventObject().SHOW)
- return this
- }
+ if (this.isWithContent() && this._isEnabled) {
+ $(this.element).trigger(showEvent)
- Tooltip.prototype.fixTitle = function () {
- var $e = this.$element
- if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
- $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ var isInTheDom = $.contains(this.element.ownerDocument.documentElement, this.element)
+
+ if (showEvent.isDefaultPrevented() || !isInTheDom) {
+ return
}
- }
- Tooltip.prototype.hasContent = function () {
- return this.getTitle()
- }
+ var tip = this.getTipElement()
+ var tipId = Bootstrap.getUID(this.getName())
- Tooltip.prototype.getPosition = function ($element) {
- $element = $element || this.$element
+ tip.setAttribute('id', tipId)
+ this.element.setAttribute('aria-describedby', tipId)
- var el = $element[0]
- var isBody = el.tagName == 'BODY'
+ this.setContent()
- var elRect = el.getBoundingClientRect()
- if (elRect.width == null) {
- // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
- elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
+ if (this.config['animation']) {
+ $(tip).addClass(Tooltip._ClassName.FADE)
}
- var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
- var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
- var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
- return $.extend({}, elRect, scroll, outerDims, elOffset)
- }
+ var placement = typeof this.config['placement'] == 'function' ?
+ this.config['placement'].call(this, tip, this.element) :
+ this.config['placement']
- Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
- return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
- placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
- placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
- /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+ var autoToken = /\s?auto?\s?/i
+ var isWithAutoPlacement = autoToken.test(placement)
- }
+ if (isWithAutoPlacement) {
+ placement = placement.replace(autoToken, '') || Tooltip.Direction.TOP
+ }
- Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
- var delta = { top: 0, left: 0 }
- if (!this.$viewport) return delta
+ if (tip.parentNode && tip.parentNode.nodeType == Node.ELEMENT_NODE) {
+ tip.parentNode.removeChild(tip)
+ }
- var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
- var viewportDimensions = this.getPosition(this.$viewport)
+ tip.style.top = 0
+ tip.style.left = 0
+ tip.style.display = 'block'
- if (/right|left/.test(placement)) {
- var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
- var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
- if (topEdgeOffset < viewportDimensions.top) { // top overflow
- delta.top = viewportDimensions.top - topEdgeOffset
- } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
- delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
- }
+ $(tip).addClass(Tooltip._NAME + '-' + placement)
+
+ $(tip).data(this.getDataKey(), this)
+
+ if (this.config['container']) {
+ $(this.config['container'])[0].appendChild(tip)
} else {
- var leftEdgeOffset = pos.left - viewportPadding
- var rightEdgeOffset = pos.left + viewportPadding + actualWidth
- if (leftEdgeOffset < viewportDimensions.left) { // left overflow
- delta.left = viewportDimensions.left - leftEdgeOffset
- } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
- delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
- }
+ this.element.parentNode.insertBefore(tip, this.element.nextSibling)
}
- return delta
- }
+ var position = this._getPosition()
+ var actualWidth = tip.offsetWidth
+ var actualHeight = tip.offsetHeight
- Tooltip.prototype.getTitle = function () {
- var title
- var $e = this.$element
- var o = this.options
+ var calculatedPlacement = this._getCalculatedAutoPlacement(isWithAutoPlacement, placement, position, actualWidth, actualHeight)
+ var calculatedOffset = this._getCalculatedOffset(calculatedPlacement, position, actualWidth, actualHeight)
- title = $e.attr('data-original-title')
- || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+ this._applyCalculatedPlacement(calculatedOffset, calculatedPlacement)
- return title
- }
+ var complete = function () {
+ var prevHoverState = this.hoverState
+ $(this.element).trigger(this.getEventObject().SHOWN)
+ this.hoverState = null
- Tooltip.prototype.getUID = function (prefix) {
- do prefix += ~~(Math.random() * 1000000)
- while (document.getElementById(prefix))
- return prefix
- }
+ if (prevHoverState == 'out') this._leave(null, this)
+ }.bind(this)
- Tooltip.prototype.tip = function () {
- return (this.$tip = this.$tip || $(this.options.template))
+ Bootstrap.transition && $(this._tip).hasClass(Tooltip._ClassName.FADE) ?
+ $(this._tip)
+ .one(Bootstrap.TRANSITION_END, complete)
+ .emulateTransitionEnd(Tooltip._TRANSITION_DURATION) :
+ complete()
}
+}
- Tooltip.prototype.arrow = function () {
- return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
- }
- Tooltip.prototype.enable = function () {
- this.enabled = true
- }
+/**
+ * Hide the tooltip breh
+ */
+Tooltip.prototype['hide'] = function (callback) {
+ var tip = this.getTipElement()
+ var hideEvent = $.Event(this.getEventObject().HIDE)
- Tooltip.prototype.disable = function () {
- this.enabled = false
- }
+ var complete = function () {
+ if (this._hoverState != Tooltip._HoverState.IN) {
+ tip.parentNode.removeChild(tip)
+ }
- Tooltip.prototype.toggleEnabled = function () {
- this.enabled = !this.enabled
- }
+ this.element.removeAttribute('aria-describedby')
+ $(this.element).trigger(this.getEventObject().HIDDEN)
- Tooltip.prototype.toggle = function (e) {
- var self = this
- if (e) {
- self = $(e.currentTarget).data('bs.' + this.type)
- if (!self) {
- self = new this.constructor(e.currentTarget, this.getDelegateOptions())
- $(e.currentTarget).data('bs.' + this.type, self)
- }
+ if (callback) {
+ callback()
}
+ }.bind(this)
- self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
- }
+ $(this.element).trigger(hideEvent)
- Tooltip.prototype.destroy = function () {
- var that = this
- clearTimeout(this.timeout)
- this.hide(function () {
- that.$element.off('.' + that.type).removeData('bs.' + that.type)
- })
+ if (hideEvent.isDefaultPrevented()) return
+
+ $(tip).removeClass(Tooltip._ClassName.IN)
+
+ if (Bootstrap.transition && $(this._tip).hasClass(Tooltip._ClassName.FADE)) {
+ $(tip)
+ .one(Bootstrap.TRANSITION_END, complete)
+ .emulateTransitionEnd(Tooltip._TRANSITION_DURATION)
+ } else {
+ complete()
}
+ this._hoverState = ''
+}
- // TOOLTIP PLUGIN DEFINITION
- // =========================
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.tooltip')
- var options = typeof option == 'object' && option
+/**
+ * @return {string}
+ */
+Tooltip.prototype['getHoverState'] = function (callback) {
+ return this._hoverState
+}
- if (!data && option == 'destroy') return
- if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
- var old = $.fn.tooltip
+/**
+ * @return {string}
+ * @protected
+ */
+Tooltip.prototype.getName = function () {
+ return Tooltip._NAME
+}
- $.fn.tooltip = Plugin
- $.fn.tooltip.Constructor = Tooltip
+/**
+ * @return {string}
+ * @protected
+ */
+Tooltip.prototype.getDataKey = function () {
+ return Tooltip._DATA_KEY
+}
- // TOOLTIP NO CONFLICT
- // ===================
- $.fn.tooltip.noConflict = function () {
- $.fn.tooltip = old
- return this
- }
+/**
+ * @return {Object}
+ * @protected
+ */
+Tooltip.prototype.getEventObject = function () {
+ return Tooltip._Event
+}
-}(jQuery);
-/* ========================================================================
- * Bootstrap: popover.js v3.3.2
- * http://getbootstrap.com/javascript/#popovers
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+/**
+ * @return {string}
+ * @protected
+ */
+Tooltip.prototype.getTitle = function () {
+ var title = this.element.getAttribute('data-original-title')
+ if (!title) {
+ title = typeof this.config['title'] === 'function' ?
+ this.config['title'].call(this.element) :
+ this.config['title']
+ }
-+function ($) {
- 'use strict';
+ return /** @type {string} */ (title)
+}
- // POPOVER PUBLIC CLASS DEFINITION
- // ===============================
- var Popover = function (element, options) {
- this.init('popover', element, options)
- }
+/**
+ * @return {Element}
+ * @protected
+ */
+Tooltip.prototype.getTipElement = function () {
+ return (this._tip = this._tip || $(this.config['template'])[0])
+}
- if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
- Popover.VERSION = '3.3.2'
+/**
+ * @return {Element}
+ * @protected
+ */
+Tooltip.prototype.getArrowElement = function () {
+ return (this.arrow = this.arrow || $(this.getTipElement()).find(Tooltip._Selector.TOOLTIP_ARROW)[0])
+}
- Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
- placement: 'right',
- trigger: 'click',
- content: '',
- template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
- })
+
+/**
+ * @return {boolean}
+ * @protected
+ */
+Tooltip.prototype.isWithContent = function () {
+ return !!this.getTitle()
+}
- // NOTE: POPOVER EXTENDS tooltip.js
- // ================================
+/**
+ * @protected
+ */
+Tooltip.prototype.setContent = function () {
+ var tip = this.getTipElement()
+ var title = this.getTitle()
- Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+ $(tip).find(Tooltip._Selector.TOOLTIP_INNER)[0][this.config['html'] ? 'innerHTML' : 'innerText'] = title
- Popover.prototype.constructor = Popover
+ $(tip)
+ .removeClass(Tooltip._ClassName.FADE)
+ .removeClass(Tooltip._ClassName.IN)
- Popover.prototype.getDefaults = function () {
- return Popover.DEFAULTS
+ for (var direction in Tooltip.Direction) {
+ $(tip).removeClass(Tooltip._NAME + '-' + direction)
}
+}
- Popover.prototype.setContent = function () {
- var $tip = this.tip()
- var title = this.getTitle()
- var content = this.getContent()
- $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
- $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
- this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
- ](content)
+/**
+ * @private
+ */
+Tooltip.prototype._setListeners = function () {
+ var triggers = this.config['trigger'].split(' ')
- $tip.removeClass('fade popover-top popover-bottom popover-left popover-right in')
+ triggers.forEach(function (trigger) {
+ if (trigger == 'click') {
+ $(this.element).on('click.bs.tooltip', this.config['selector'], this['toggle'].bind(this))
- // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
- // this manually by checking the contents.
- if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
- }
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
- Popover.prototype.hasContent = function () {
- return this.getTitle() || this.getContent()
+ $(this.element)
+ .on(eventIn + '.bs.tooltip', this.config['selector'], this._enter.bind(this))
+ .on(eventOut + '.bs.tooltip', this.config['selector'], this._leave.bind(this))
+ }
+ }.bind(this))
+
+ if (this.config['selector']) {
+ this.config = $.extend({}, this.config, { 'trigger': 'manual', 'selector': '' })
+ } else {
+ this._fixTitle()
}
+}
- Popover.prototype.getContent = function () {
- var $e = this.$element
- var o = this.options
- return $e.attr('data-content')
- || (typeof o.content == 'function' ?
- o.content.call($e[0]) :
- o.content)
- }
+/**
+ * @param {Object=} opt_config
+ * @return {Object}
+ * @private
+ */
+Tooltip.prototype._getConfig = function (opt_config) {
+ var config = $.extend({}, this.constructor['Defaults'], $(this.element).data(), opt_config)
- Popover.prototype.arrow = function () {
- return (this.$arrow = this.$arrow || this.tip().find('.popover-arrow'))
+ if (config['delay'] && typeof config['delay'] == 'number') {
+ config['delay'] = {
+ 'show': config['delay'],
+ 'hide': config['delay']
+ }
}
- Popover.prototype.tip = function () {
- if (!this.$tip) this.$tip = $(this.options.template)
- return this.$tip
+ return config
+}
+
+
+/**
+ * @return {Object}
+ * @private
+ */
+Tooltip.prototype._getDelegateConfig = function () {
+ var config = {}
+ var defaults = this.constructor['Defaults']
+
+ if (this.config) {
+ for (var key in this.config) {
+ var value = this.config[key]
+ if (defaults[key] != value) config[key] = value
+ }
}
+ return config
+}
- // POPOVER PLUGIN DEFINITION
- // =========================
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.popover')
- var options = typeof option == 'object' && option
- if (!data && option == 'destroy') return
- if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
- if (typeof option == 'string') data[option]()
- })
+/**
+ * @param {boolean} isWithAutoPlacement
+ * @param {string} placement
+ * @param {Object} position
+ * @param {number} actualWidth
+ * @param {number} actualHeight
+ * @return {string}
+ * @private
+ */
+Tooltip.prototype._getCalculatedAutoPlacement = function (isWithAutoPlacement, placement, position, actualWidth, actualHeight) {
+ if (isWithAutoPlacement) {
+ var originalPlacement = placement
+ var container = this.config['container'] ? $(this.config['container'])[0] : this.element.parentNode
+ var containerDim = this._getPosition(/** @type {Element} */ (container))
+
+ placement = placement == Tooltip.Direction.BOTTOM && position.bottom + actualHeight > containerDim.bottom ? Tooltip.Direction.TOP :
+ placement == Tooltip.Direction.TOP && position.top - actualHeight < containerDim.top ? Tooltip.Direction.BOTTOM :
+ placement == Tooltip.Direction.RIGHT && position.right + actualWidth > containerDim.width ? Tooltip.Direction.LEFT :
+ placement == Tooltip.Direction.LEFT && position.left - actualWidth < containerDim.left ? Tooltip.Direction.RIGHT :
+ placement
+
+ $(this._tip)
+ .removeClass(Tooltip._NAME + '-' + originalPlacement)
+ .addClass(Tooltip._NAME + '-' + placement)
}
- var old = $.fn.popover
+ return placement
+}
- $.fn.popover = Plugin
- $.fn.popover.Constructor = Popover
+/**
+ * @param {string} placement
+ * @param {Object} position
+ * @param {number} actualWidth
+ * @param {number} actualHeight
+ * @return {{left: number, top: number}}
+ * @private
+ */
+Tooltip.prototype._getCalculatedOffset = function (placement, position, actualWidth, actualHeight) {
+ return placement == Tooltip.Direction.BOTTOM ? { top: position.top + position.height, left: position.left + position.width / 2 - actualWidth / 2 } :
+ placement == Tooltip.Direction.TOP ? { top: position.top - actualHeight, left: position.left + position.width / 2 - actualWidth / 2 } :
+ placement == Tooltip.Direction.LEFT ? { top: position.top + position.height / 2 - actualHeight / 2, left: position.left - actualWidth } :
+ /* placement == Tooltip.Direction.RIGHT */ { top: position.top + position.height / 2 - actualHeight / 2, left: position.left + position.width }
+}
- // POPOVER NO CONFLICT
- // ===================
- $.fn.popover.noConflict = function () {
- $.fn.popover = old
- return this
+/**
+ * @param {string} placement
+ * @param {Object} position
+ * @param {number} actualWidth
+ * @param {number} actualHeight
+ * @return {Object}
+ * @private
+ */
+Tooltip.prototype._getViewportAdjustedDelta = function (placement, position, actualWidth, actualHeight) {
+ var delta = { top: 0, left: 0 }
+
+ if (!this._viewport) {
+ return delta
}
-}(jQuery);
+ var viewportPadding = this.config['viewport'] && this.config['viewport']['padding'] || 0
+ var viewportDimensions = this._getPosition(this._viewport)
-/* ========================================================================
- * Bootstrap: scrollspy.js v3.3.2
- * http://getbootstrap.com/javascript/#scrollspy
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ if (placement === Tooltip.Direction.RIGHT || placement === Tooltip.Direction.LEFT) {
+ var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll
+ var bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
+ delta.top = viewportDimensions.top - topEdgeOffset
-+function ($) {
- 'use strict';
-
- // SCROLLSPY CLASS DEFINITION
- // ==========================
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+ }
- function ScrollSpy(element, options) {
- var process = $.proxy(this.process, this)
+ } else {
+ var leftEdgeOffset = position.left - viewportPadding
+ var rightEdgeOffset = position.left + viewportPadding + actualWidth
- this.$body = $('body')
- this.$scrollElement = $(element).is('body') ? $(window) : $(element)
- this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
- this.selector = (this.options.target || '') + ' .nav li > a'
- this.offsets = []
- this.targets = []
- this.activeTarget = null
- this.scrollHeight = 0
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+ delta.left = viewportDimensions.left - leftEdgeOffset
- this.$scrollElement.on('scroll.bs.scrollspy', process)
- this.refresh()
- this.process()
+ } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+ }
}
- ScrollSpy.VERSION = '3.3.2'
+ return delta
+}
+
+
+/**
+ * @param {Element=} opt_element
+ * @return {Object}
+ * @private
+ */
+Tooltip.prototype._getPosition = function (opt_element) {
+ var element = opt_element || this.element
+ var isBody = element.tagName == 'BODY'
+ var rect = element.getBoundingClientRect()
+ var offset = isBody ? { top: 0, left: 0 } : $(element).offset()
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : this.element.scrollTop }
+ var outerDims = isBody ? { width: window.innerWidth, height: window.innerHeight } : null
+
+ return $.extend({}, rect, scroll, outerDims, offset)
+}
- ScrollSpy.DEFAULTS = {
- offset: 10
- }
- ScrollSpy.prototype.getScrollHeight = function () {
- return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
+/**
+ * @param {{left: number, top: number}} offset
+ * @param {string} placement
+ * @private
+ */
+Tooltip.prototype._applyCalculatedPlacement = function (offset, placement) {
+ var tip = this.getTipElement()
+ var width = tip.offsetWidth
+ var height = tip.offsetHeight
+
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt(tip.style.marginTop, 10)
+ var marginLeft = parseInt(tip.style.marginLeft, 10)
+
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) {
+ marginTop = 0
+ }
+ if (isNaN(marginLeft)) {
+ marginLeft = 0
}
- ScrollSpy.prototype.refresh = function () {
- var offsetMethod = 'offset'
- var offsetBase = 0
+ offset.top = offset.top + marginTop
+ offset.left = offset.left + marginLeft
- if (!$.isWindow(this.$scrollElement[0])) {
- offsetMethod = 'position'
- offsetBase = this.$scrollElement.scrollTop()
+ // $.fn.offset doesn't round pixel values
+ // so we use setOffset directly with our own function B-0
+ $.offset.setOffset(tip, $.extend({
+ using: function (props) {
+ tip.style.top = Math.round(props.top) + 'px'
+ tip.style.left = Math.round(props.left) + 'px'
}
+ }, offset), 0)
- this.offsets = []
- this.targets = []
- this.scrollHeight = this.getScrollHeight()
-
- var self = this
+ $(tip).addClass(Tooltip._ClassName.IN)
- this.$body
- .find(this.selector)
- .map(function () {
- var $el = $(this)
- var href = $el.data('target') || $el.attr('href')
- var $href = /^#./.test(href) && $(href)
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = tip.offsetWidth
+ var actualHeight = tip.offsetHeight
- return ($href
- && $href.length
- && $href.is(':visible')
- && [[$href[offsetMethod]().top + offsetBase, href]]) || null
- })
- .sort(function (a, b) { return a[0] - b[0] })
- .each(function () {
- self.offsets.push(this[0])
- self.targets.push(this[1])
- })
+ if (placement == Tooltip.Direction.TOP && actualHeight != height) {
+ offset.top = offset.top + height - actualHeight
}
- ScrollSpy.prototype.process = function () {
- var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
- var scrollHeight = this.getScrollHeight()
- var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
- var offsets = this.offsets
- var targets = this.targets
- var activeTarget = this.activeTarget
- var i
+ var delta = this._getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
- if (this.scrollHeight != scrollHeight) {
- this.refresh()
- }
+ if (delta.left) {
+ offset.left += delta.left
+ } else {
+ offset.top += delta.top
+ }
- if (scrollTop >= maxScroll) {
- return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
- }
+ var isVertical = placement === Tooltip.Direction.TOP || placement === Tooltip.Direction.BOTTOM
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
- if (activeTarget && scrollTop < offsets[0]) {
- this.activeTarget = null
- return this.clear()
- }
+ $(tip).offset(offset)
- for (i = offsets.length; i--;) {
- activeTarget != targets[i]
- && scrollTop >= offsets[i]
- && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
- && this.activate(targets[i])
- }
- }
+ this._replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical)
+}
- ScrollSpy.prototype.activate = function (target) {
- this.activeTarget = target
- this.clear()
+/**
+ * @param {number} delta
+ * @param {number} dimension
+ * @param {boolean} isHorizontal
+ * @private
+ */
+Tooltip.prototype._replaceArrow = function (delta, dimension, isHorizontal) {
+ var arrow = this.getArrowElement()
- var selector = this.selector +
- '[data-target="' + target + '"],' +
- this.selector + '[href="' + target + '"]'
+ arrow.style[isHorizontal ? 'left' : 'top'] = 50 * (1 - delta / dimension) + '%'
+ arrow.style[isHorizontal ? 'top' : 'left'] = ''
+}
- var active = $(selector)
- .parents('li')
- .addClass('active')
- if (active.parent('.dropdown-menu').length) {
- active = active
- .closest('li.dropdown')
- .addClass('active')
- }
- active.trigger('activate.bs.scrollspy')
+/**
+ * @private
+ */
+Tooltip.prototype._fixTitle = function () {
+ if (this.element.getAttribute('title') || typeof this.element.getAttribute('data-original-title') != 'string') {
+ this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '')
+ this.element.setAttribute('title', '')
}
+}
+
- ScrollSpy.prototype.clear = function () {
- $(this.selector)
- .parentsUntil(this.options.target, '.active')
- .removeClass('active')
+/**
+ * @param {Event=} opt_event
+ * @param {Object=} opt_context
+ * @private
+ */
+Tooltip.prototype._enter = function (opt_event, opt_context) {
+ var dataKey = this.getDataKey()
+ var context = opt_context || $(opt_event.currentTarget).data(dataKey)
+
+ if (context && context._tip && context._tip.offsetWidth) {
+ context._hoverState = Tooltip._HoverState.IN
+ return
}
+ if (!context) {
+ context = new this.constructor(opt_event.currentTarget, this._getDelegateConfig())
+ $(opt_event.currentTarget).data(dataKey, context)
+ }
- // SCROLLSPY PLUGIN DEFINITION
- // ===========================
+ clearTimeout(context._timeout)
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.scrollspy')
- var options = typeof option == 'object' && option
+ context._hoverState = Tooltip._HoverState.IN
- if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
- if (typeof option == 'string') data[option]()
- })
+ if (!context.config['delay'] || !context.config['delay']['show']) {
+ context['show']()
+ return
}
- var old = $.fn.scrollspy
+ context._timeout = setTimeout(function () {
+ if (context._hoverState == Tooltip._HoverState.IN) {
+ context['show']()
+ }
+ }, context.config['delay']['show'])
+}
- $.fn.scrollspy = Plugin
- $.fn.scrollspy.Constructor = ScrollSpy
+/**
+ * @param {Event=} opt_event
+ * @param {Object=} opt_context
+ * @private
+ */
+Tooltip.prototype._leave = function (opt_event, opt_context) {
+ var dataKey = this.getDataKey()
+ var context = opt_context || $(opt_event.currentTarget).data(dataKey)
- // SCROLLSPY NO CONFLICT
- // =====================
+ if (!context) {
+ context = new this.constructor(opt_event.currentTarget, this._getDelegateConfig())
+ $(opt_event.currentTarget).data(dataKey, context)
+ }
- $.fn.scrollspy.noConflict = function () {
- $.fn.scrollspy = old
- return this
+ clearTimeout(context._timeout)
+
+ context._hoverState = Tooltip._HoverState.OUT
+
+ if (!context.config['delay'] || !context.config['delay']['hide']) {
+ context['hide']()
+ return
}
+ context._timeout = setTimeout(function () {
+ if (context._hoverState == Tooltip._HoverState.OUT) {
+ context['hide']()
+ }
+ }, context.config['delay']['hide'])
+}
- // SCROLLSPY DATA-API
- // ==================
- $(window).on('load.bs.scrollspy.data-api', function () {
- $('[data-spy="scroll"]').each(function () {
- var $spy = $(this)
- Plugin.call($spy, $spy.data())
- })
- })
-}(jQuery);
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
-/* ========================================================================
- * Bootstrap: tab.js v3.3.2
- * http://getbootstrap.com/javascript/#tabs
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Tooltip._NAME] = Tooltip._jQueryInterface
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Tooltip._NAME]['Constructor'] = Tooltip
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Tooltip._NAME]['noConflict'] = function () {
+ $.fn[Tooltip._NAME] = Tooltip._JQUERY_NO_CONFLICT
+ return this
+}
+
+/** =======================================================================
+ * Bootstrap: popover.js v4.0.0
+ * http://getbootstrap.com/javascript/#popovers
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Bootstrap's popover plugin - extends tooltip.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.popover
+ * + $.popover.noConflict
+ * + $.popover.Constructor
+ * + $.popover.Constructor.VERSION
+ * + $.popover.Constructor.Defaults
+ * + $.popover.Constructor.Defaults.container
+ * + $.popover.Constructor.Defaults.animation
+ * + $.popover.Constructor.Defaults.placement
+ * + $.popover.Constructor.Defaults.selector
+ * + $.popover.Constructor.Defaults.template
+ * + $.popover.Constructor.Defaults.trigger
+ * + $.popover.Constructor.Defaults.title
+ * + $.popover.Constructor.Defaults.content
+ * + $.popover.Constructor.Defaults.delay
+ * + $.popover.Constructor.Defaults.html
+ * + $.popover.Constructor.Defaults.viewport
+ * + $.popover.Constructor.Defaults.viewport.selector
+ * + $.popover.Constructor.Defaults.viewport.padding
+ * + $.popover.Constructor.prototype.enable
+ * + $.popover.Constructor.prototype.disable
+ * + $.popover.Constructor.prototype.destroy
+ * + $.popover.Constructor.prototype.toggleEnabled
+ * + $.popover.Constructor.prototype.toggle
+ * + $.popover.Constructor.prototype.show
+ * + $.popover.Constructor.prototype.hide
+ *
+ * ========================================================================
+ */
-+function ($) {
- 'use strict';
+'use strict';
- // TAB CLASS DEFINITION
- // ====================
- var Tab = function (element) {
- this.element = $(element)
- }
+if (!Tooltip) throw new Error('Popover requires tooltip.js')
- Tab.VERSION = '3.3.2'
- Tab.TRANSITION_DURATION = 150
+/**
+ * Our tooltip class.
+ * @param {Element!} element
+ * @param {Object=} opt_config
+ * @constructor
+ * @extends {Tooltip}
+ */
+var Popover = function (element, opt_config) {
+ Tooltip.apply(this, arguments)
+}
+Bootstrap.inherits(Popover, Tooltip)
- Tab.prototype.show = function () {
- var $this = this.element
- var $ul = $this.closest('ul:not(.dropdown-menu)')
- var selector = $this.data('target')
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
- }
+/**
+ * @const
+ * @type {string}
+ */
+Popover['VERSION'] = '4.0.0'
- if ($this.parent('li').hasClass('active')) return
- var $previous = $ul.find('.active:last a')
- var hideEvent = $.Event('hide.bs.tab', {
- relatedTarget: $this[0]
- })
- var showEvent = $.Event('show.bs.tab', {
- relatedTarget: $previous[0]
- })
+/**
+ * @const
+ * @type {Object}
+ */
+Popover['Defaults'] = $.extend({}, $.fn['tooltip']['Constructor']['Defaults'], {
+ 'placement': 'right',
+ 'trigger': 'click',
+ 'content': '',
+ 'template': '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+})
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Popover._NAME = 'popover'
- $previous.trigger(hideEvent)
- $this.trigger(showEvent)
- if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Popover._DATA_KEY = 'bs.popover'
- var $target = $(selector)
- this.activate($this.closest('li'), $ul)
- this.activate($target, $target.parent(), function () {
- $previous.trigger({
- type: 'hidden.bs.tab',
- relatedTarget: $this[0]
- })
- $this.trigger({
- type: 'shown.bs.tab',
- relatedTarget: $previous[0]
- })
- })
- }
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Popover._Event = {
+ HIDE : 'hide.bs.popover',
+ HIDDEN : 'hidden.bs.popover',
+ SHOW : 'show.bs.popover',
+ SHOWN : 'shown.bs.popover'
+}
- Tab.prototype.activate = function (element, container, callback) {
- var $active = container.find('> .active')
- var transition = callback
- && $.support.transition
- && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
-
- function next() {
- $active
- .removeClass('active')
- .find('> .dropdown-menu > .active')
- .removeClass('active')
- .end()
- .find('[data-toggle="tab"]')
- .attr('aria-expanded', false)
-
- element
- .addClass('active')
- .find('[data-toggle="tab"]')
- .attr('aria-expanded', true)
-
- if (transition) {
- element[0].offsetWidth // reflow for transition
- element.addClass('in')
- } else {
- element.removeClass('fade')
- }
- if (element.parent('.dropdown-menu')) {
- element
- .closest('li.dropdown')
- .addClass('active')
- .end()
- .find('[data-toggle="tab"]')
- .attr('aria-expanded', true)
- }
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Popover._ClassName = {
+ FADE : 'fade',
+ IN : 'in'
+}
- callback && callback()
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Popover._Selector = {
+ TITLE : '.popover-title',
+ CONTENT : '.popover-content',
+ ARROW : '.popover-arrow'
+}
+
+
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Popover._JQUERY_NO_CONFLICT = $.fn[Popover._NAME]
+
+
+/**
+ * @param {Object|string=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Popover._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var data = $(this).data(Popover._DATA_KEY)
+ var config = typeof opt_config === 'object' ? opt_config : null
+
+ if (!data && opt_config === 'destroy') {
+ return
}
- $active.length && transition ?
- $active
- .one('bsTransitionEnd', next)
- .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
- next()
+ if (!data) {
+ data = new Popover(this, config)
+ $(this).data(Popover._DATA_KEY, data)
+ }
- $active.removeClass('in')
- }
+ if (typeof opt_config === 'string') {
+ data[opt_config]()
+ }
+ })
+}
- // TAB PLUGIN DEFINITION
- // =====================
+/**
+ * @return {string}
+ * @protected
+ */
+Popover.prototype.getName = function () {
+ return Popover._NAME
+}
+
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.tab')
+/**
+ * @override
+ */
+Popover.prototype.getDataKey = function () {
+ return Popover._DATA_KEY
+}
- if (!data) $this.data('bs.tab', (data = new Tab(this)))
- if (typeof option == 'string') data[option]()
- })
- }
- var old = $.fn.tab
+/**
+ * @override
+ */
+Popover.prototype.getEventObject = function () {
+ return Popover._Event
+}
- $.fn.tab = Plugin
- $.fn.tab.Constructor = Tab
+/**
+ * @override
+ */
+Popover.prototype.getArrowElement = function () {
+ return (this.arrow = this.arrow || $(this.getTipElement()).find(Popover._Selector.ARROW)[0])
+}
- // TAB NO CONFLICT
- // ===============
- $.fn.tab.noConflict = function () {
- $.fn.tab = old
- return this
+/**
+ * @override
+ */
+Popover.prototype.setContent = function () {
+ var tip = this.getTipElement()
+ var title = this.getTitle()
+ var content = this._getContent()
+ var titleElement = $(tip).find(Popover._Selector.TITLE)[0]
+
+ if (titleElement) {
+ titleElement[this.config['html'] ? 'innerHTML' : 'innerText'] = title
}
+ // we use append for html objects to maintain js events
+ $(tip).find(Popover._Selector.CONTENT).children().detach().end()[
+ this.config['html'] ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+ ](content)
- // TAB DATA-API
- // ============
+ $(tip)
+ .removeClass(Popover._ClassName.FADE)
+ .removeClass(Popover._ClassName.IN)
- var clickHandler = function (e) {
- e.preventDefault()
- Plugin.call($(this), 'show')
+ for (var direction in Tooltip.Direction) {
+ $(tip).removeClass(Popover._NAME + '-' + Tooltip.Direction[direction])
}
+}
- $(document)
- .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
- .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
-}(jQuery);
+/**
+ * @override
+ */
+Popover.prototype.isWithContent = function () {
+ return this.getTitle() || this._getContent()
+}
+
+
+/**
+ * @override
+ */
+Popover.prototype.getTipElement = function () {
+ return (this.tip = this.tip || $(this.config['template'])[0])
+}
-/* ========================================================================
- * Bootstrap: affix.js v3.3.2
- * http://getbootstrap.com/javascript/#affix
+
+/**
+ * @private
+ */
+Popover.prototype._getContent = function () {
+ return this.element.getAttribute('data-content')
+ || (typeof this.config['content'] == 'function' ?
+ this.config['content'].call(this.element) :
+ this.config['content'])
+}
+
+
+
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Popover._NAME] = Popover._jQueryInterface
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Popover._NAME]['Constructor'] = Popover
+
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Popover._NAME]['noConflict'] = function () {
+ $.fn[Popover._NAME] = Popover._JQUERY_NO_CONFLICT
+ return this
+}
+
+/** =======================================================================
+ * Bootstrap: tab.js v4.0.0
+ * http://getbootstrap.com/javascript/#tabs
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
+ * ========================================================================
+ * @fileoverview - Bootstrap's tab plugin. Tab O_O
+ *
+ * Public Methods & Properties:
+ *
+ * + $.tab
+ * + $.tab.noConflict
+ * + $.tab.Constructor
+ * + $.tab.Constructor.VERSION
+ * + $.tab.Constructor.prototype.show
+ *
+ * ========================================================================
+ */
-+function ($) {
- 'use strict';
+'use strict';
- // AFFIX CLASS DEFINITION
- // ======================
+/**
+ * Our Tab class.
+ * @param {Element!} element
+ * @constructor
+ */
+var Tab = function (element) {
- var Affix = function (element, options) {
- this.options = $.extend({}, Affix.DEFAULTS, options)
+ /** @type {Element} */
+ this._element = element
- this.$target = $(this.options.target)
- .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
- .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
+}
- this.$element = $(element)
- this.affixed =
- this.unpin =
- this.pinnedOffset = null
- this.checkPosition()
- }
+/**
+ * @const
+ * @type {string}
+ */
+Tab['VERSION'] = '4.0.0'
- Affix.VERSION = '3.3.2'
- Affix.RESET = 'affix affix-top affix-bottom'
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Tab._NAME = 'tab'
- Affix.DEFAULTS = {
- offset: 0,
- target: window
- }
- Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
- var scrollTop = this.$target.scrollTop()
- var position = this.$element.offset()
- var targetHeight = this.$target.height()
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Tab._DATA_KEY = 'bs.tab'
+
- if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
+/**
+ * @const
+ * @type {number}
+ * @private
+ */
+Tab._TRANSITION_DURATION = 150
- if (this.affixed == 'bottom') {
- if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
- return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Tab._Event = {
+ HIDE : 'hide.bs.tab',
+ HIDDEN : 'hidden.bs.tab',
+ SHOW : 'show.bs.tab',
+ SHOWN : 'shown.bs.tab'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Tab._ClassName = {
+ DROPDOWN_MENU : 'dropdown-menu',
+ ACTIVE : 'active',
+ FADE : 'fade',
+ IN : 'in'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Tab._Selector = {
+ A : 'a',
+ LI : 'li',
+ LI_DROPDOWN : 'li.dropdown',
+ UL : 'ul:not(.dropdown-menu)',
+ FADE_CHILD : ':scope > .fade',
+ ACTIVE : '.active',
+ ACTIVE_CHILD : ':scope > .active',
+ DATA_TOGGLE : '[data-toggle="tab"], [data-toggle="pill"]',
+ DROPDOWN_ACTIVE_CHILD : ':scope > .dropdown-menu > .active'
+}
+
+
+/**
+ * @param {Object|string=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Tab._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data(Tab._DATA_KEY)
+
+ if (!data) {
+ data = data = new Tab(this)
+ $this.data(Tab._DATA_KEY, data)
}
- var initializing = this.affixed == null
- var colliderTop = initializing ? scrollTop : position.top
- var colliderHeight = initializing ? targetHeight : height
+ if (typeof opt_config === 'string') {
+ data[opt_config]()
+ }
+ })
+}
- if (offsetTop != null && scrollTop <= offsetTop) return 'top'
- if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
- return false
+/**
+ * Show the tab
+ */
+Tab.prototype['show'] = function () {
+ if ( this._element.parentNode
+ && this._element.parentNode.nodeType == Node.ELEMENT_NODE
+ && $(this._element).parent().hasClass(Tab._ClassName.ACTIVE)) {
+ return
+ }
+
+ var ulElement = $(this._element).closest(Tab._Selector.UL)[0]
+ var selector = Bootstrap.getSelectorFromElement(this._element)
+
+ if (ulElement) {
+ var previous = /** @type {Array.<Element>} */ ($.makeArray($(ulElement).find(Tab._Selector.ACTIVE)))
+ previous = previous[previous.length - 1]
+
+ if (previous) {
+ previous = $(previous).find('a')[0]
+ }
}
- Affix.prototype.getPinnedOffset = function () {
- if (this.pinnedOffset) return this.pinnedOffset
- this.$element.removeClass(Affix.RESET).addClass('affix')
- var scrollTop = this.$target.scrollTop()
- var position = this.$element.offset()
- return (this.pinnedOffset = position.top - scrollTop)
+ var hideEvent = $.Event(Tab._Event.HIDE, {
+ relatedTarget: this._element
+ })
+
+ var showEvent = $.Event(Tab._Event.SHOW, {
+ relatedTarget: previous
+ })
+
+ if (previous) {
+ $(previous).trigger(hideEvent)
}
- Affix.prototype.checkPositionWithEventLoop = function () {
- setTimeout($.proxy(this.checkPosition, this), 1)
+ $(this._element).trigger(showEvent)
+
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
+
+ if (selector) {
+ var target = $(selector)[0]
}
- Affix.prototype.checkPosition = function () {
- if (!this.$element.is(':visible')) return
+ this._activate($(this._element).closest(Tab._Selector.LI)[0], ulElement)
- var height = this.$element.height()
- var offset = this.options.offset
- var offsetTop = offset.top
- var offsetBottom = offset.bottom
- var scrollHeight = $('body').height()
+ var complete = function () {
+ var hiddenEvent = $.Event(Tab._Event.HIDDEN, {
+ relatedTarget: this._element
+ })
- if (typeof offset != 'object') offsetBottom = offsetTop = offset
- if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
- if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+ var shownEvent = $.Event(Tab._Event.SHOWN, {
+ relatedTarget: previous
+ })
- var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
+ $(previous).trigger(hiddenEvent)
+ $(this._element).trigger(shownEvent)
+ }.bind(this)
- if (this.affixed != affix) {
- if (this.unpin != null) this.$element.css('top', '')
+ if (target) {
+ this._activate(target, /** @type {Element} */ (target.parentNode), complete)
+ } else {
+ complete()
+ }
+}
- var affixType = 'affix' + (affix ? '-' + affix : '')
- var e = $.Event(affixType + '.bs.affix')
- this.$element.trigger(e)
+/**
+ * @param {Element} element
+ * @param {Element} container
+ * @param {Function=} opt_callback
+ * @private
+ */
+Tab.prototype._activate = function (element, container, opt_callback) {
+ var active = $(container).find(Tab._Selector.ACTIVE_CHILD)[0]
+ var isTransitioning = opt_callback
+ && Bootstrap.transition
+ && ((active && $(active).hasClass(Tab._ClassName.FADE))
+ || !!$(container).find(Tab._Selector.FADE_CHILD)[0])
+
+ var complete = this._transitionComplete.bind(this, element, active, isTransitioning, opt_callback)
+
+ if (active && isTransitioning) {
+ $(active)
+ .one(Bootstrap.TRANSITION_END, complete)
+ .emulateTransitionEnd(Tab._TRANSITION_DURATION)
+
+ } else {
+ complete()
+ }
+
+ if (active) {
+ $(active).removeClass(Tab._ClassName.IN)
+ }
+}
- if (e.isDefaultPrevented()) return
- this.affixed = affix
- this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+/**
+ * @param {Element} element
+ * @param {Element} active
+ * @param {boolean} isTransitioning
+ * @param {Function=} opt_callback
+ * @private
+ */
+Tab.prototype._transitionComplete = function (element, active, isTransitioning, opt_callback) {
+ if (active) {
+ $(active).removeClass(Tab._ClassName.ACTIVE)
- this.$element
- .removeClass(Affix.RESET)
- .addClass(affixType)
- .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+ var dropdownChild = $(active).find(Tab._Selector.DROPDOWN_ACTIVE_CHILD)[0]
+ if (dropdownChild) {
+ $(dropdownChild).removeClass(Tab._ClassName.ACTIVE)
}
- if (affix == 'bottom') {
- this.$element.offset({
- top: scrollHeight - height - offsetBottom
- })
+ var activeToggle = $(active).find(Tab._Selector.DATA_TOGGLE)[0]
+ if (activeToggle) {
+ activeToggle.setAttribute('aria-expanded', false)
}
}
+ $(element).addClass(Tab._ClassName.ACTIVE)
- // AFFIX PLUGIN DEFINITION
- // =======================
+ var elementToggle = $(element).find(Tab._Selector.DATA_TOGGLE)[0]
+ if (elementToggle) {
+ elementToggle.setAttribute('aria-expanded', true)
+ }
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.affix')
- var options = typeof option == 'object' && option
+ if (isTransitioning) {
+ Bootstrap.reflow(element)
+ $(element).addClass(Tab._ClassName.IN)
+ } else {
+ $(element).removeClass(Tab._ClassName.FADE)
+ }
- if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
- if (typeof option == 'string') data[option]()
- })
+ if (element.parentNode && $(element.parentNode).hasClass(Tab._ClassName.DROPDOWN_MENU)) {
+ var dropdownElement = $(element).closest(Tab._Selector.LI_DROPDOWN)[0]
+ if (dropdownElement) {
+ $(dropdownElement).addClass(Tab._ClassName.ACTIVE)
+ }
+
+ elementToggle = $(element).find(Tab._Selector.DATA_TOGGLE)[0]
+ if (elementToggle) {
+ elementToggle.setAttribute('aria-expanded', true)
+ }
}
- var old = $.fn.affix
+ if (opt_callback) {
+ opt_callback()
+ }
+}
- $.fn.affix = Plugin
- $.fn.affix.Constructor = Affix
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Tab._NAME] = Tab._jQueryInterface
- // AFFIX NO CONFLICT
- // =================
- $.fn.affix.noConflict = function () {
- $.fn.affix = old
- return this
- }
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Tab._NAME]['Constructor'] = Tab
- // AFFIX DATA-API
- // ==============
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Tab._NAME]['noConflict'] = function () {
+ $.fn[Tab._NAME] = Tab._JQUERY_NO_CONFLICT
+ return this
+}
- $(window).on('load', function () {
- $('[data-spy="affix"]').each(function () {
- var $spy = $(this)
- var data = $spy.data()
- data.offset = data.offset || {}
- if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
- if (data.offsetTop != null) data.offset.top = data.offsetTop
+// TAB DATA-API
+// ============
- Plugin.call($spy, data)
- })
- })
+var clickHandler = function (e) {
+ e.preventDefault()
+ Tab._jQueryInterface.call($(this), 'show')
+}
-}(jQuery);
+$(document)
+ .on('click.bs.tab.data-api', Tab._Selector.DATA_TOGGLE, clickHandler)
diff --git a/dist/js/bootstrap.min.js b/dist/js/bootstrap.min.js
index a17f4b3bf..089780400 100644
--- a/dist/js/bootstrap.min.js
+++ b/dist/js/bootstrap.min.js
@@ -3,5 +3,75 @@
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
-if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.2",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.2",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.2",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".carousel-item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".carousel-item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".carousel-item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.2",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.2",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.divider):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="menu"]',g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="listbox"]',g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$backdrop=this.isShown=null,this.scrollbarWidth=0,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.2",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.options.backdrop&&d.adjustBackdrop(),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in").attr("aria-hidden",!1),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$element.find(".modal-dialog").one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('<div class="modal-backdrop '+e+'" />').prependTo(this.$element).on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.options.backdrop&&this.adjustBackdrop(),this.adjustDialog()},c.prototype.adjustBackdrop=function(){this.$backdrop.css("height",0).css("height",this.$element[0].scrollHeight)},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){this.bodyIsOverflowing=document.body.scrollHeight>document.documentElement.clientHeight,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right","")},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.3.2",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(this.type+"-"+h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-m<p.top?"bottom":"right"==h&&k.right+l>p.width?"left":"left"==h&&k.left-l<p.left?"right":h,f.removeClass(this.type+"-"+n).addClass(this.type+"-"+h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in tooltip-top tooltip-bottom tooltip-left tooltip-right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=this.tip(),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.2",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade popover-top popover-bottom popover-left popover-right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".popover-arrow")},c.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){var e=a.proxy(this.process,this);this.$body=a("body"),this.$scrollElement=a(a(c).is("body")?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",e),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.2",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b="offset",c=0;a.isWindow(this.$scrollElement[0])||(b="position",c=this.$scrollElement.scrollTop()),this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight();var d=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+c,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){d.offsets.push(this[0]),d.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.2",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})
-})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.2",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a("body").height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file
+if (typeof jQuery === 'undefined') {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery')
+}
++function ($) {
+ var version = $.fn.jquery.split(' ')[0].split('.')
+ if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
+ }
+}(jQuery);
+
+(function($){var h,k,l={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};function m(a){var b=a.getAttribute("data-target");b||(b=a.getAttribute("href")||"",b=/^#[a-z]/i.test(b)?b:null);return b}function aa(a){do a+=~~(1E6*Math.random());while(document.getElementById(a));return a}function ba(){return{ha:k.end,ia:k.end,handle:function(a){if($(a.target).is(this))return a.handleObj.handler.apply(this,arguments)}}}
+function n(a){(new Function("bs","return bs"))(a.offsetHeight)}function ca(){if(window.QUnit)return!1;var a=document.createElement("bootstrap"),b;for(b in l)if(void 0!==a.style[b])return{end:l[b]};return!1}$.fn.f=function(a){var b=!1;$(this).one("bsTransitionEnd",function(){b=!0});var c=function(){b||$(this).trigger(k.end)}.bind(this);setTimeout(c,a)};$(function(){(k=ca())&&($.event.special.bsTransitionEnd=ba())});function p(a){if(a)$(a).on("click",'[data-dismiss="alert"]',q(this))}p.VERSION="4.0.0";var da=$.fn.alert;function s(a){return this.each(function(){var b=$(this),c=b.data("bs.alert");c||(c=new p(this),b.data("bs.alert",c));if("close"===a)c[a](this)})}function q(a){return function(b){b&&b.preventDefault();a.close(this)}}
+p.prototype.close=function(a){var b=!1,c=m(a);c&&(b=$(c)[0]);b||(b=$(a).closest(".alert")[0]);a=b;b=$.Event("close.bs.alert");$(a).trigger(b);b.isDefaultPrevented()||($(a).removeClass("in"),k&&$(a).hasClass("fade")?$(a).one("bsTransitionEnd",this.N.bind(this,a)).f(150):this.N(a))};p.prototype.N=function(a){$(a).detach().trigger("closed.bs.alert").remove()};$.fn.alert=s;$.fn.alert.Constructor=p;$.fn.alert.noConflict=function(){$.fn.alert=da;return s};
+$(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',q(new p));function t(a){this.a=a}t.VERSION="4.0.0";var ea=$.fn.button;function u(a){return this.each(function(){var b=$(this).data("bs.button");b||(b=new t(this),$(this).data("bs.button",b));if("toggle"===a)b[a]()})}
+t.prototype.toggle=function(){var a=!0,b=$(this.a).closest('[data-toggle="buttons"]')[0];if(b){var c=$(this.a).find("input")[0];c&&("radio"==c.type&&(c.checked&&$(this.a).hasClass("active")?a=!1:(b=$(b).find(".active")[0])&&$(b).removeClass("active")),a&&(c.checked=!$(this.a).hasClass("active"),$(this.a).trigger("change")))}else this.a.setAttribute("aria-pressed",!$(this.a).hasClass("active"));a&&$(this.a).toggleClass("active")};$.fn.button=u;$.fn.button.Constructor=t;
+$.fn.button.noConflict=function(){$.fn.button=ea;return this};$(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(a){a.preventDefault();a=a.target;$(a).hasClass("btn")||(a=$(a).closest(".btn"));u.call($(a),"toggle")}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(a){var b=$(a.target).closest(".btn")[0];$(b).toggleClass("focus",/^focus(in)?$/.test(a.type))});function v(a,b){this.a=$(a)[0];this.F=$(this.a).find(fa)[0];this.c=b||null;this.l=this.G=!1;this.h=this.M=this.k=null;if(this.c.keyboard)$(this.a).on("keydown.bs.carousel",this.Y.bind(this));if("hover"==this.c.pause&&!("ontouchstart"in document.documentElement))$(this.a).on("mouseenter.bs.carousel",this.pause.bind(this)).on("mouseleave.bs.carousel",this.cycle.bind(this))}v.VERSION="4.0.0";v.Defaults={interval:5E3,pause:"hover",wrap:!0,keyboard:!0,slide:!1};var fa=".carousel-indicators",ga=$.fn.carousel;
+function w(a){return this.each(function(){var b=$(this).data("bs.carousel"),c=$.extend({},v.Defaults,$(this).data(),"object"==typeof a&&a),d="string"==typeof a?a:c.ja;b||(b=new v(this,c),$(this).data("bs.carousel",b));if("number"==typeof a)x(b,a);else if(d)b[d]();else c.interval&&(b.pause(),b.cycle())})}v.prototype.next=function(){this.l||z(this,"next")};v.prototype.prev=function(){this.l||z(this,"prev")};
+v.prototype.pause=function(a){a||(this.G=!0);$(this.a).find(".next, .prev")[0]&&k&&($(this.a).trigger(k.end),this.cycle(!0));clearInterval(this.k);this.k=null};v.prototype.cycle=function(a){a||(this.G=!1);this.k&&(clearInterval(this.k),this.k=null);this.c.interval&&!this.G&&(this.k=setInterval(this.next.bind(this),this.c.interval))};v.prototype.getConfig=function(){return this.c};
+function x(a,b){a.M=$(a.a).find(".active.carousel-item")[0];var c=A(a,a.M);if(!(b>a.h.length-1||0>b))if(a.l)$(a.a).one("slid.bs.carousel",function(){x(this,b)}.bind(a));else c==b?(a.pause(),a.cycle()):z(a,b>c?"next":"prev",a.h[b])}v.prototype.Y=function(a){a.preventDefault();if(!/input|textarea/i.test(a.target.tagName))switch(a.which){case 37:this.prev();break;case 39:this.next()}};function A(a,b){a.h=$.makeArray($(b).parent().find(".carousel-item"));return a.h.indexOf(b)}
+function ha(a,b,c){var d=A(a,c);if(("prev"===b&&0===d||"next"===b&&d==a.h.length-1)&&!a.c.wrap)return c;b=(d+("prev"==b?-1:1))%a.h.length;return-1===b?a.h[a.h.length-1]:a.h[b]}function ia(a,b,c){b=$.Event("slide.bs.carousel",{relatedTarget:b,direction:c});$(a.a).trigger(b);return b}function ja(a,b){if(a.F){$(a.F).find(".active").removeClass("active");var c=a.F.children[A(a,b)];c&&$(c).addClass("active")}}
+function z(a,b,c){var d=$(a.a).find(".active.carousel-item")[0],e=c||d&&ha(a,b,d);c=!!a.k;var f="next"==b?"left":"right";if(e&&$(e).hasClass("active"))a.l=!1;else if(!ia(a,e,f).isDefaultPrevented()&&d&&e){a.l=!0;c&&a.pause();ja(a,e);var g=$.Event("slid.bs.carousel",{relatedTarget:e,direction:f});k&&$(a.a).hasClass("slide")?($(e).addClass(b),n(e),$(d).addClass(f),$(e).addClass(f),$(d).one("bsTransitionEnd",function(){$(e).removeClass(f).removeClass(b);$(e).addClass("active");$(d).removeClass("active").removeClass(b).removeClass(f);
+this.l=!1;setTimeout(function(){$(this.a).trigger(g)}.bind(this),0)}.bind(a)).f(600)):($(d).removeClass("active"),$(e).addClass("active"),a.l=!1,$(a.a).trigger(g));c&&a.cycle()}}$.fn.carousel=w;$.fn.carousel.Constructor=v;$.fn.carousel.noConflict=function(){$.fn.carousel=ga;return this};
+$(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(a){var b=m(this);if(b&&(b=$(b)[0])&&$(b).hasClass("carousel")){var c=$.extend({},$(b).data(),$(this).data()),d=this.getAttribute("data-slide-to");d&&(c.interval=!1);w.call($(b),c);d&&x($(b).data("bs.carousel"),d);a.preventDefault()}});$(window).on("load",function(){$('[data-ride="carousel"]').each(function(){var a=$(this);w.call(a,a.data())})});function B(a,b){this.a=a;this.c=$.extend({},B.Defaults,b);this.o="string"==typeof this.c.trigger?$(this.c.trigger)[0]:this.c.trigger;this.A=!1;var c;if(this.c.parent){var d='[data-toggle="collapse"][data-parent="'+this.c.parent+'"]';c=$(this.c.parent)[0];for(var d=$.makeArray($(c).find(d)),e=0;e<d.length;e++)C(D(d[e]),d[e])}else c=null;this.Z=c;this.c.parent||C(this.a,this.o);this.c.toggle&&this.toggle()}B.VERSION="4.0.0";B.Defaults={toggle:!0,trigger:'[data-toggle="collapse"]',parent:null};
+var ka=$.fn.collapse;function E(a){return this.each(function(){var b=$(this),c=b.data("bs.collapse"),d=$.extend({},B.Defaults,b.data(),"object"==typeof a&&a);!c&&d.toggle&&"show"==a&&(d.toggle=!1);c||(c=new B(this,d),b.data("bs.collapse",c));if("string"==typeof a)c[a]()})}function D(a){return(a=m(a))?$(a)[0]:null}B.prototype.toggle=function(){$(this.a).hasClass("in")?this.hide():this.show()};
+B.prototype.show=function(){if(!this.A&&!$(this.a).hasClass("in")){var a,b;this.Z&&(b=$.makeArray($(".panel > .in, .panel > .collapsing")),b.length||(b=null));if(b&&(a=$(b).data("bs.collapse"))&&a.A)return;var c=$.Event("show.bs.collapse");$(this.a).trigger(c);if(!c.isDefaultPrevented()){b&&(E.call($(b),"hide"),a||$(b).data("bs.collapse",null));var d=F(this);$(this.a).removeClass("collapse").addClass("collapsing");this.a.style[d]=0;this.a.setAttribute("aria-expanded",!0);this.o&&($(this.o).removeClass("collapsed"),
+this.o.setAttribute("aria-expanded",!0));this.setTransitioning(!0);a=function(){$(this.a).removeClass("collapsing").addClass("collapse").addClass("in");this.a.style[d]="";this.setTransitioning(!1);$(this.a).trigger("shown.bs.collapse")}.bind(this);k?(b="scroll"+(d[0].toUpperCase()+d.slice(1)),$(this.a).one("bsTransitionEnd",a).f(600),this.a.style[d]=this.a[b]+"px"):a()}}};
+B.prototype.hide=function(){if(!this.A&&$(this.a).hasClass("in")){var a=$.Event("hide.bs.collapse");$(this.a).trigger(a);if(!a.isDefaultPrevented()){a=F(this);this.a.style[a]=this.a["width"===a?"offsetWidth":"offsetHeight"]+"px";n(this.a);$(this.a).addClass("collapsing").removeClass("collapse").removeClass("in");this.a.setAttribute("aria-expanded",!1);this.o&&($(this.o).addClass("collapsed"),this.o.setAttribute("aria-expanded",!1));this.setTransitioning(!0);var b=function(){this.setTransitioning(!1);
+$(this.a).removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")}.bind(this);this.a.style[a]=0;if(!k)return b();$(this.a).one("bsTransitionEnd",b).f(600)}}};B.prototype.setTransitioning=function(a){this.A=a};function F(a){return $(a.a).hasClass("width")?"width":"height"}function C(a,b){if(a){var c=$(a).hasClass("in");a.setAttribute("aria-expanded",c);b&&(b.setAttribute("aria-expanded",c),$(b).toggleClass("collapsed",!c))}}$.fn.collapse=E;$.fn.collapse.Constructor=B;
+$.fn.collapse.noConflict=function(){$.fn.collapse=ka;return this};$(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(a){a.preventDefault();a=D(this);var b=$(a).data("bs.collapse")?"toggle":$.extend({},$(this).data(),{trigger:this});E.call($(a),b)});function G(a){$(a).on("click.bs.dropdown",this.toggle)}G.VERSION="4.0.0";var la=$.fn.dropdown;
+function H(a){if(!a||3!=a.which){(a=$(".dropdown-backdrop")[0])&&a.parentNode.removeChild(a);a=$.makeArray($('[data-toggle="dropdown"]'));for(var b=0;b<a.length;b++){var c=I(a[b]),d={relatedTarget:a[b]};if($(c).hasClass("open")){var e=$.Event("hide.bs.dropdown",d);$(c).trigger(e);e.isDefaultPrevented()||(a[b].setAttribute("aria-expanded","false"),$(c).removeClass("open").trigger("hidden.bs.dropdown",d))}}}}function I(a){var b=m(a);if(b)var c=$(b)[0];return c||a.parentNode}
+function J(a){if(/(38|40|27|32)/.test(a.which)&&!/input|textarea/i.test(a.target.tagName)&&(a.preventDefault(),a.stopPropagation(),!this.disabled&&!$(this).hasClass("disabled"))){var b=I(this),c=$(b).hasClass("open");!c&&27!=a.which||c&&27==a.which?(27==a.which&&(a=$(b).find('[data-toggle="dropdown"]')[0],$(a).trigger("focus")),$(this).trigger("click")):(b=$.makeArray($('[role="menu"] li:not(.divider) a, [role="listbox"] li:not(.divider) a')),b=b.filter(function(a){return a.offsetWidth||a.offsetHeight}),
+b.length&&(c=b.indexOf(a.target),38==a.which&&0<c&&c--,40==a.which&&c<b.length-1&&c++,~c||(c=0),b[c].focus()))}}
+G.prototype.toggle=function(){if(!this.disabled&&!$(this).hasClass("disabled")){var a=I(this),b=$(a).hasClass("open");H();if(b)return!1;"ontouchstart"in document.documentElement&&!$(a).closest(".navbar-nav").length&&(b=document.createElement("div"),b.className="dropdown-backdrop",this.parentNode.insertBefore(this,b),$(b).on("click",H));var b={relatedTarget:this},c=$.Event("show.bs.dropdown",b);$(a).trigger(c);if(!c.isDefaultPrevented())return this.focus(),this.setAttribute("aria-expanded","true"),
+$(a).toggleClass("open"),$(a).trigger("shown.bs.dropdown",b),!1}};$.fn.dropdown=function(a){return this.each(function(){var b=$(this).data("bs.dropdown");b||$(this).data("bs.dropdown",b=new G(this));"string"===typeof a&&b[a].call(this)})};$.fn.dropdown.Constructor=G;$.fn.dropdown.noConflict=function(){$.fn.dropdown=la;return this};
+$(document).on("click.bs.dropdown.data-api",H).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",'[data-toggle="dropdown"]',G.prototype.toggle).on("keydown.bs.dropdown.data-api",'[data-toggle="dropdown"]',J).on("keydown.bs.dropdown.data-api",'[role="menu"]',J).on("keydown.bs.dropdown.data-api",'[role="listbox"]',J);function K(a,b){this.c=b;this.a=a;this.d=null;this.w=this.g=!1;this.B=0}K.VERSION="4.0.0";K.Defaults={backdrop:!0,keyboard:!0,show:!0};var ma=$.fn.modal;function L(a,b){return this.each(function(){var c=$(this).data("bs.modal"),d=$.extend({},K.Defaults,$(this).data(),"object"==typeof a&&a);c||(c=new K(this,d),$(this).data("bs.modal",c));if("string"==typeof a)c[a](b);else d.show&&c.show(b)})}K.prototype.toggle=function(a){return this.g?this.hide():this.show(a)};
+K.prototype.show=function(a){var b=$.Event("show.bs.modal",{relatedTarget:a});$(this.a).trigger(b);if(!this.g&&!b.isDefaultPrevented()){this.g=!0;this.w=document.body.scrollHeight>document.documentElement.clientHeight;b=document.createElement("div");b.className="modal-scrollbar-measure";document.body.appendChild(b);var c=b.offsetWidth-b.clientWidth;document.body.removeChild(b);this.B=c;b=parseInt($(document.body).css("padding-right")||0,10);this.w&&(document.body.style.paddingRight=b+this.B+"px");
+$(document.body).addClass("modal-open");M(this);N(this);$(this.a).on("click.dismiss.bs.modal",'[data-dismiss="modal"]',this.hide.bind(this));O(this,this.$.bind(this,a))}};
+K.prototype.hide=function(a){a&&a.preventDefault();a=$.Event("hide.bs.modal");$(this.a).trigger(a);this.g&&!a.isDefaultPrevented()&&(this.g=!1,M(this),N(this),$(document).off("focusin.bs.modal"),$(this.a).removeClass("in"),this.a.setAttribute("aria-hidden",!0),$(this.a).off("click.dismiss.bs.modal"),k&&$(this.a).hasClass("fade")?$(this.a).one("bsTransitionEnd",this.P.bind(this)).f(300):this.P())};
+K.prototype.$=function(a){var b=k&&$(this.a).hasClass("fade");this.a.parentNode&&this.a.parentNode.nodeType==Node.ELEMENT_NODE||document.body.appendChild(this.a);this.a.style.display="block";this.a.scrollTop=0;this.c.backdrop&&P(this);b&&n(this.a);$(this.a).addClass("in");this.a.setAttribute("aria-hidden",!1);na(this);var c=$.Event("shown.bs.modal",{relatedTarget:a});a=function(){this.a.focus();$(this.a).trigger(c)}.bind(this);b?(b=$(this.a).find(".modal-dialog")[0],$(b).one("bsTransitionEnd",a).f(300)):
+a()};function na(a){$(document).off("focusin.bs.modal").on("focusin.bs.modal",function(a){this.a===a.target||$(this.a).has(a.target).length||this.a.focus()}.bind(a))}function M(a){if(a.g&&a.c.keyboard)$(a.a).on("keydown.dismiss.bs.modal",function(a){27===a.which&&this.hide()}.bind(a));else a.g||$(a.a).off("keydown.dismiss.bs.modal")}function N(a){if(a.g)$(window).on("resize.bs.modal",a.X.bind(a));else $(window).off("resize.bs.modal")}
+K.prototype.P=function(){this.a.style.display="none";O(this,function(){$(document.body).removeClass("modal-open");this.a.style.paddingLeft="";this.a.style.paddingRight="";document.body.style.paddingRight="";$(this.a).trigger("hidden.bs.modal")}.bind(this))};
+function O(a,b){var c=$(a.a).hasClass("fade")?"fade":"";if(a.g&&a.c.backdrop){var d=k&&c;a.d=document.createElement("div");a.d.className="modal-backdrop";c&&$(a.d).addClass(c);$(a.a).prepend(a.d);$(a.d).on("click.dismiss.bs.modal",function(a){a.target===a.currentTarget&&("static"===this.c.backdrop?this.a.focus():this.hide())}.bind(a));d&&n(a.d);$(a.d).addClass("in");b&&(d?$(a.d).one("bsTransitionEnd",b).f(150):b())}else!a.g&&a.d?($(a.d).removeClass("in"),c=function(){this.d&&(this.d.parentNode.removeChild(this.d),
+this.d=null);b&&b()}.bind(a),k&&$(a.a).hasClass("fade")?$(a.d).one("bsTransitionEnd",c).f(150):c()):b&&b()}K.prototype.X=function(){this.c.backdrop&&P(this);var a=this.a.scrollHeight>document.documentElement.clientHeight;!this.w&&a&&(this.a.style.paddingLeft=this.B+"px");this.w&&!a&&(this.a.style.paddingRight=this.B+"px")};function P(a){a.d.style.height=0;a.d.style.height=a.a.scrollHeight+"px"}$.fn.modal=L;$.fn.modal.Constructor=K;$.fn.modal.noConflict=function(){$.fn.modal=ma;return this};
+$(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(a){var b=m(this);if(b)var c=$(b)[0];b=$(c).data("bs.modal")?"toggle":$.extend({},$(c).data(),$(this).data());"A"==this.tagName&&a.preventDefault();var d=$(c).one("show.bs.modal",function(a){if(!a.isDefaultPrevented())d.one("hidden.bs.modal",function(){$(this).is(":visible")&&this.focus()}.bind(this))}.bind(this));L.call($(c),b,this)});function Q(a,b){this.e="BODY"==a.tagName?window:a;this.c=$.extend({},Q.Defaults,b);this.C=(this.c.target||"")+" .nav li > a";this.m=[];this.p=[];this.s=null;this.R=0;$(this.e).on("scroll.bs.scrollspy",this.Q.bind(this));this.refresh();this.Q()}Q.VERSION="4.0.0";Q.Defaults={offset:10};var oa=$.fn.scrollspy;function R(a){return this.each(function(){var b=$(this).data("bs.scrollspy"),c="object"===typeof a&&a||null;b||(b=new Q(this,c),$(this).data("bs.scrollspy",b));if("string"===typeof a)b[a]()})}
+Q.prototype.refresh=function(){var a="offset",b=0;this.e!==this.e.window&&(a="position",b=this.e===window?this.e.scrollY:this.e.scrollTop);this.m=[];this.p=[];this.R=this.e.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight);$.makeArray($(this.C)).map(function(c){var d;(c=m(c))&&(d=$(c)[0]);if(d&&(d.offsetWidth||d.offsetHeight))return[$(d)[a]().top+b,c]}).filter(function(a){return a}).sort(function(a,b){return a[0]-b[0]}).forEach(function(a){this.m.push(a[0]);
+this.p.push(a[1])}.bind(this))};Q.prototype.Q=function(){var a=(this.e===window?this.e.scrollY:this.e.scrollTop)+this.c.offset,b=this.e.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight),c=this.c.offset+b-this.e.offsetHeight;this.R!=b&&this.refresh();a>=c&&(b=this.p[this.p.length-1],this.s!=b&&this.r(b));if(this.s&&a<this.m[0])this.s=null,S(this);else for(b=this.m.length;b--;)this.s!=this.p[b]&&a>=this.m[b]&&(!this.m[b+1]||a<this.m[b+1])&&this.r(this.p[b])};
+Q.prototype.r=function(a){this.s=a;S(this);for(var b=$(this.C+'[data-target="'+a+'"],'+this.C+'[href="'+a+'"]').parents("li"),c=b.length;c--;){$(b[c]).addClass("active");var d=b[c].parentNode;d&&$(d).hasClass("dropdown-menu")&&(d=$(d).closest("li.dropdown")[0],$(d).addClass("active"))}$(this.e).trigger("activate.bs.scrollspy",{relatedTarget:a})};function S(a){a=$(a.C).parentsUntil(a.c.target,".active");for(var b=a.length;b--;)$(a[b]).removeClass("active")}$.fn.scrollspy=R;
+$.fn.scrollspy.Constructor=Q;$.fn.scrollspy.noConflict=function(){$.fn.scrollspy=oa;return this};$(window).on("load.bs.scrollspy.data-api",function(){for(var a=$.makeArray($('[data-spy="scroll"]')),b=a.length;b--;){var c=$(a[b]);R.call(c,c.data())}});function T(a,b){this.t=!0;this.u=0;this.j="";this.element=a;var c=$.extend({},this.constructor.Defaults,$(this.element).data(),b);c.delay&&"number"==typeof c.delay&&(c.delay={show:c.delay,hide:c.delay});this.b=c;this.D=this.W=null;this.b.viewport&&(this.S=$(this.b.viewport.selector||this.b.viewport)[0]);pa(this)}T.VERSION="4.0.0";
+T.Defaults={container:!1,animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,viewport:{selector:"body",padding:0}};var U={fa:"top",da:"left",ea:"right",ca:"bottom"},qa={J:"hide.bs.tooltip",I:"hidden.bs.tooltip",K:"show.bs.tooltip",L:"shown.bs.tooltip"},ra=$.fn.tooltip;T.prototype.enable=function(){this.t=!0};
+T.prototype.disable=function(){this.t=!1};T.prototype.toggleEnabled=function(){this.t=!this.t};T.prototype.toggle=function(a){var b=this,c=this.q();a&&(b=$(a.currentTarget).data(c),b||(b=new this.constructor(a.currentTarget,V(this)),$(a.currentTarget).data(c,b)));$(b.i()).hasClass("in")?b.H(null,b):b.O(null,b)};T.prototype.destroy=function(){clearTimeout(this.u);this.hide(function(){$(this.element).off(".tooltip").removeData(this.q())}.bind(this))};
+T.prototype.show=function(){var a=$.Event(this.v().K);if(this.U()&&this.t){$(this.element).trigger(a);var b=$.contains(this.element.ownerDocument.documentElement,this.element);if(!a.isDefaultPrevented()&&b){a=this.i();b=aa(this.getName());a.setAttribute("id",b);this.element.setAttribute("aria-describedby",b);this.V();this.b.animation&&$(a).addClass("fade");var b="function"==typeof this.b.placement?this.b.placement.call(this,a,this.element):this.b.placement,c=/\s?auto?\s?/i,d=c.test(b);d&&(b=b.replace(c,
+"")||"top");a.parentNode&&a.parentNode.nodeType==Node.ELEMENT_NODE&&a.parentNode.removeChild(a);a.style.top=0;a.style.left=0;a.style.display="block";$(a).addClass("tooltip-"+b);$(a).data(this.q(),this);this.b.container?$(this.b.container)[0].appendChild(a):this.element.parentNode.insertBefore(a,this.element.nextSibling);var c=W(this),e=a.offsetWidth,a=a.offsetHeight,b=sa(this,d,b,c,e,a);ta(this,"bottom"==b?{top:c.top+c.height,left:c.left+c.width/2-e/2}:"top"==b?{top:c.top-a,left:c.left+c.width/2-
+e/2}:"left"==b?{top:c.top+c.height/2-a/2,left:c.left-e}:{top:c.top+c.height/2-a/2,left:c.left+c.width},b);a=function(){var a=this.ba;$(this.element).trigger(this.v().L);this.ba=null;"out"==a&&this.H(null,this)}.bind(this);k&&$(this.n).hasClass("fade")?$(this.n).one("bsTransitionEnd",a).f(150):a()}}};
+T.prototype.hide=function(a){var b=this.i(),c=$.Event(this.v().J),d=function(){"in"!=this.j&&b.parentNode.removeChild(b);this.element.removeAttribute("aria-describedby");$(this.element).trigger(this.v().I);a&&a()}.bind(this);$(this.element).trigger(c);c.isDefaultPrevented()||($(b).removeClass("in"),k&&$(this.n).hasClass("fade")?$(b).one("bsTransitionEnd",d).f(150):d(),this.j="")};T.prototype.getHoverState=function(){return this.j};h=T.prototype;h.getName=function(){return"tooltip"};h.q=function(){return"bs.tooltip"};
+h.v=function(){return qa};function X(a){var b=a.element.getAttribute("data-original-title");b||(b="function"===typeof a.b.title?a.b.title.call(a.element):a.b.title);return b}h.i=function(){return this.n=this.n||$(this.b.template)[0]};h.T=function(){return this.D=this.D||$(this.i()).find(".tooltip-arrow")[0]};h.U=function(){return!!X(this)};
+h.V=function(){var a=this.i(),b=X(this);$(a).find(".tooltip-inner")[0][this.b.html?"innerHTML":"innerText"]=b;$(a).removeClass("fade").removeClass("in");for(var c in U)$(a).removeClass("tooltip-"+c)};
+function pa(a){a.b.trigger.split(" ").forEach(function(a){if("click"==a)$(this.element).on("click.bs.tooltip",this.b.selector,this.toggle.bind(this));else if("manual"!=a){var c="hover"==a?"mouseenter":"focusin";a="hover"==a?"mouseleave":"focusout";$(this.element).on(c+".bs.tooltip",this.b.selector,this.O.bind(this)).on(a+".bs.tooltip",this.b.selector,this.H.bind(this))}}.bind(a));a.b.selector?a.b=$.extend({},a.b,{trigger:"manual",selector:""}):ua(a)}
+function V(a){var b={},c=a.constructor.Defaults;if(a.b)for(var d in a.b){var e=a.b[d];c[d]!=e&&(b[d]=e)}return b}function sa(a,b,c,d,e,f){if(b){b=c;var g=a.b.container?$(a.b.container)[0]:a.element.parentNode,g=W(a,g);c="bottom"==c&&d.bottom+f>g.bottom?"top":"top"==c&&d.top-f<g.top?"bottom":"right"==c&&d.right+e>g.width?"left":"left"==c&&d.left-e<g.left?"right":c;$(a.n).removeClass("tooltip-"+b).addClass("tooltip-"+c)}return c}
+function va(a,b,c,d,e){var f={top:0,left:0};if(!a.S)return f;var g=a.b.viewport&&a.b.viewport.padding||0;a=W(a,a.S);"right"===b||"left"===b?(d=c.top-g-a.scroll,c=c.top+g-a.scroll+e,d<a.top?f.top=a.top-d:c>a.top+a.height&&(f.top=a.top+a.height-c)):(e=c.left-g,c=c.left+g+d,e<a.left?f.left=a.left-e:c>a.width&&(f.left=a.left+a.width-c));return f}
+function W(a,b){var c=b||a.element,d="BODY"==c.tagName,e=c.getBoundingClientRect(),c=d?{top:0,left:0}:$(c).offset();return $.extend({},e,{scroll:d?document.documentElement.scrollTop||document.body.scrollTop:a.element.scrollTop},d?{width:window.innerWidth,height:window.innerHeight}:null,c)}
+function ta(a,b,c){var d=a.i(),e=d.offsetWidth,f=d.offsetHeight,g=parseInt(d.style.marginTop,10),r=parseInt(d.style.marginLeft,10);isNaN(g)&&(g=0);isNaN(r)&&(r=0);b.top+=g;b.left+=r;$.offset.setOffset(d,$.extend({ka:function(a){d.style.top=Math.round(a.top)+"px";d.style.left=Math.round(a.left)+"px"}},b),0);$(d).addClass("in");g=d.offsetWidth;r=d.offsetHeight;"top"==c&&r!=f&&(b.top=b.top+f-r);var y=va(a,c,b,g,r);y.left?b.left+=y.left:b.top+=y.top;e=(c="top"===c||"bottom"===c)?2*y.left-e+g:2*y.top-
+f+r;f=c?"offsetWidth":"offsetHeight";$(d).offset(b);wa(a,e,d[f],c)}function wa(a,b,c,d){a=a.T();a.style[d?"left":"top"]=50*(1-b/c)+"%";a.style[d?"top":"left"]=""}function ua(a){if(a.element.getAttribute("title")||"string"!=typeof a.element.getAttribute("data-original-title"))a.element.setAttribute("data-original-title",a.element.getAttribute("title")||""),a.element.setAttribute("title","")}
+h.O=function(a,b){var c=this.q(),d=b||$(a.currentTarget).data(c);d&&d.n&&d.n.offsetWidth?d.j="in":(d||(d=new this.constructor(a.currentTarget,V(this)),$(a.currentTarget).data(c,d)),clearTimeout(d.u),d.j="in",d.b.delay&&d.b.delay.show?d.u=setTimeout(function(){"in"==d.j&&d.show()},d.b.delay.show):d.show())};
+h.H=function(a,b){var c=this.q(),d=b||$(a.currentTarget).data(c);d||(d=new this.constructor(a.currentTarget,V(this)),$(a.currentTarget).data(c,d));clearTimeout(d.u);d.j="out";d.b.delay&&d.b.delay.hide?d.u=setTimeout(function(){"out"==d.j&&d.hide()},d.b.delay.hide):d.hide()};$.fn.tooltip=function(a){return this.each(function(){var b=$(this).data("bs.tooltip"),c="object"==typeof a?a:null;if(b||"destroy"!=a)if(b||(b=new T(this,c),$(this).data("bs.tooltip",b)),"string"===typeof a)b[a]()})};
+$.fn.tooltip.Constructor=T;$.fn.tooltip.noConflict=function(){$.fn.tooltip=ra;return this};if(!T)throw Error("Popover requires tooltip.js");function Y(a,b){T.apply(this,arguments)}(function(){function a(){}a.prototype=T.prototype;Y.prototype=new a;Y.prototype.constructor=Y})();Y.VERSION="4.0.0";Y.Defaults=$.extend({},$.fn.tooltip.Constructor.Defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'});
+var xa={J:"hide.bs.popover",I:"hidden.bs.popover",K:"show.bs.popover",L:"shown.bs.popover"},ya=$.fn.popover;h=Y.prototype;h.getName=function(){return"popover"};h.q=function(){return"bs.popover"};h.v=function(){return xa};h.T=function(){return this.D=this.D||$(this.i()).find(".popover-arrow")[0]};
+h.V=function(){var a=this.i(),b=X(this),c=za(this),d=$(a).find(".popover-title")[0];d&&(d[this.b.html?"innerHTML":"innerText"]=b);$(a).find(".popover-content").children().detach().end()[this.b.html?"string"==typeof c?"html":"append":"text"](c);$(a).removeClass("fade").removeClass("in");for(var e in U)$(a).removeClass("popover-"+U[e])};h.U=function(){return X(this)||za(this)};h.i=function(){return this.W=this.W||$(this.b.template)[0]};
+function za(a){return a.element.getAttribute("data-content")||("function"==typeof a.b.content?a.b.content.call(a.element):a.b.content)}$.fn.popover=function(a){return this.each(function(){var b=$(this).data("bs.popover"),c="object"===typeof a?a:null;if(b||"destroy"!==a)if(b||(b=new Y(this,c),$(this).data("bs.popover",b)),"string"===typeof a)b[a]()})};$.fn.popover.Constructor=Y;$.fn.popover.noConflict=function(){$.fn.popover=ya;return this};function Z(a){this.a=a}Z.VERSION="4.0.0";function Aa(a){return this.each(function(){var b=$(this),c=b.data("bs.tab");c||(c=c=new Z(this),b.data("bs.tab",c));if("string"===typeof a)c[a]()})}
+Z.prototype.show=function(){if(!this.a.parentNode||this.a.parentNode.nodeType!=Node.ELEMENT_NODE||!$(this.a).parent().hasClass("active")){var a=$(this.a).closest("ul:not(.dropdown-menu)")[0],b=m(this.a);if(a){var c=$.makeArray($(a).find(".active"));(c=c[c.length-1])&&(c=$(c).find("a")[0])}var d=$.Event("hide.bs.tab",{relatedTarget:this.a}),e=$.Event("show.bs.tab",{relatedTarget:c});c&&$(c).trigger(d);$(this.a).trigger(e);if(!e.isDefaultPrevented()&&!d.isDefaultPrevented()){if(b)var f=$(b)[0];this.r($(this.a).closest("li")[0],
+a);a=function(){var a=$.Event("hidden.bs.tab",{relatedTarget:this.a}),b=$.Event("shown.bs.tab",{relatedTarget:c});$(c).trigger(a);$(this.a).trigger(b)}.bind(this);f?this.r(f,f.parentNode,a):a()}}};Z.prototype.r=function(a,b,c){var d=$(b).find(":scope > .active")[0];b=c&&k&&(d&&$(d).hasClass("fade")||!!$(b).find(":scope > .fade")[0]);a=this.aa.bind(this,a,d,b,c);d&&b?$(d).one("bsTransitionEnd",a).f(150):a();d&&$(d).removeClass("in")};
+Z.prototype.aa=function(a,b,c,d){if(b){$(b).removeClass("active");var e=$(b).find(":scope > .dropdown-menu > .active")[0];e&&$(e).removeClass("active");(b=$(b).find('[data-toggle="tab"], [data-toggle="pill"]')[0])&&b.setAttribute("aria-expanded",!1)}$(a).addClass("active");(b=$(a).find('[data-toggle="tab"], [data-toggle="pill"]')[0])&&b.setAttribute("aria-expanded",!0);c?(n(a),$(a).addClass("in")):$(a).removeClass("fade");a.parentNode&&$(a.parentNode).hasClass("dropdown-menu")&&((c=$(a).closest("li.dropdown")[0])&&
+$(c).addClass("active"),(b=$(a).find('[data-toggle="tab"], [data-toggle="pill"]')[0])&&b.setAttribute("aria-expanded",!0));d&&d()};$.fn.tab=Aa;$.fn.tab.Constructor=Z;$.fn.tab.noConflict=function(){$.fn.tab=Z.ga;return this};$(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(a){a.preventDefault();Aa.call($(this),"show")});})(jQuery);
diff --git a/dist/js/bootstrap.min.js.gz b/dist/js/bootstrap.min.js.gz
new file mode 100644
index 000000000..84313c393
--- /dev/null
+++ b/dist/js/bootstrap.min.js.gz
Binary files differ
diff --git a/dist/js/npm.js b/dist/js/npm.js
index bf6aa8060..ed761ca33 100644
--- a/dist/js/npm.js
+++ b/dist/js/npm.js
@@ -1,13 +1,13 @@
// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
-require('../../js/transition.js')
+require('../../js/util.js')
+require('../../node_modules/mq4-hover-shim/dist/browser/mq4-hover-shim.js')
require('../../js/alert.js')
require('../../js/button.js')
require('../../js/carousel.js')
require('../../js/collapse.js')
require('../../js/dropdown.js')
require('../../js/modal.js')
+require('../../js/scrollspy.js')
require('../../js/tooltip.js')
require('../../js/popover.js')
-require('../../js/scrollspy.js')
-require('../../js/tab.js')
-require('../../js/affix.js') \ No newline at end of file
+require('../../js/tab.js') \ No newline at end of file