aboutsummaryrefslogtreecommitdiff
path: root/js/src
diff options
context:
space:
mode:
Diffstat (limited to 'js/src')
-rw-r--r--js/src/alert.js6
-rw-r--r--js/src/button.js18
-rw-r--r--js/src/carousel.js426
-rw-r--r--js/src/util.js6
4 files changed, 442 insertions, 14 deletions
diff --git a/js/src/alert.js b/js/src/alert.js
index 67a1ceda4..e5e8eeacb 100644
--- a/js/src/alert.js
+++ b/js/src/alert.js
@@ -49,16 +49,14 @@ const Alert = (($) => {
class Alert {
constructor(element) {
- if (element) {
- this.element = element
- }
+ this._element = element
}
// public
close(element) {
- element = element || this.element
+ element = element || this._element
let rootElement = this._getRootElement(element)
let customEvent = this._triggerCloseEvent(rootElement)
diff --git a/js/src/button.js b/js/src/button.js
index 7e9344923..0f1dab2af 100644
--- a/js/src/button.js
+++ b/js/src/button.js
@@ -49,24 +49,24 @@ const Button = (($) => {
class Button {
constructor(element) {
- this.element = element
+ this._element = element
}
// public
toggle() {
let triggerChangeEvent = true
- let rootElement = $(this.element).closest(
+ let rootElement = $(this._element).closest(
Selector.DATA_TOGGLE
)[0]
if (rootElement) {
- let input = $(this.element).find(Selector.INPUT)[0]
+ let input = $(this._element).find(Selector.INPUT)[0]
if (input) {
if (input.type === 'radio') {
if (input.checked &&
- $(this.element).hasClass(ClassName.ACTIVE)) {
+ $(this._element).hasClass(ClassName.ACTIVE)) {
triggerChangeEvent = false
} else {
@@ -79,17 +79,17 @@ const Button = (($) => {
}
if (triggerChangeEvent) {
- input.checked = !$(this.element).hasClass(ClassName.ACTIVE)
- $(this.element).trigger('change')
+ input.checked = !$(this._element).hasClass(ClassName.ACTIVE)
+ $(this._element).trigger('change')
}
}
} else {
- this.element.setAttribute('aria-pressed',
- !$(this.element).hasClass(ClassName.ACTIVE))
+ this._element.setAttribute('aria-pressed',
+ !$(this._element).hasClass(ClassName.ACTIVE))
}
if (triggerChangeEvent) {
- $(this.element).toggleClass(ClassName.ACTIVE)
+ $(this._element).toggleClass(ClassName.ACTIVE)
}
}
diff --git a/js/src/carousel.js b/js/src/carousel.js
new file mode 100644
index 000000000..08476d666
--- /dev/null
+++ b/js/src/carousel.js
@@ -0,0 +1,426 @@
+import Util from './util'
+
+
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.0.0): carousel.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+const Carousel = (($) => {
+
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ const NAME = 'carousel'
+ const VERSION = '4.0.0'
+ const DATA_KEY = 'bs.carousel'
+ const JQUERY_NO_CONFLICT = $.fn[NAME]
+ const TRANSITION_DURATION = 600
+
+ const Defaults = {
+ interval : 5000,
+ keyboard : true,
+ slide : false,
+ pause : 'hover',
+ wrap : true
+ }
+
+ const Direction = {
+ NEXT : 'next',
+ PREVIOUS : 'prev'
+ }
+
+ const Event = {
+ SLIDE : 'slide.bs.carousel',
+ SLID : 'slid.bs.carousel',
+ CLICK : 'click.bs.carousel.data-api',
+ LOAD : 'load'
+ }
+
+ const ClassName = {
+ CAROUSEL : 'carousel',
+ ACTIVE : 'active',
+ SLIDE : 'slide',
+ RIGHT : 'right',
+ LEFT : 'left',
+ ITEM : 'carousel-item'
+ }
+
+ const Selector = {
+ ACTIVE : '.active',
+ ACTIVE_ITEM : '.active.carousel-item',
+ ITEM : '.carousel-item',
+ NEXT_PREV : '.next, .prev',
+ INDICATORS : '.carousel-indicators',
+ DATA_SLIDE : '[data-slide], [data-slide-to]',
+ DATA_RIDE : '[data-ride="carousel"]'
+ }
+
+
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ class Carousel {
+
+ constructor(element, config) {
+
+ this._items = null
+ this._interval = null
+ this._activeElement = null
+
+ this._isPaused = false
+ this._isSliding = false
+
+ this._config = config
+ this._element = $(element)[0]
+ this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0]
+
+ this._addEventListeners()
+
+ }
+
+
+ // public
+
+ next() {
+ if (!this._isSliding) {
+ this._slide(Direction.NEXT)
+ }
+ }
+
+ prev() {
+ if (!this._isSliding) {
+ this._slide(Direction.PREVIOUS)
+ }
+ }
+
+ pause(event) {
+ if (!event) {
+ this._isPaused = true
+ }
+
+ if ($(this._element).find(Selector.NEXT_PREV)[0] &&
+ Util.supportsTransitionEnd()) {
+ Util.triggerTransitionEnd(this._element)
+ this.cycle(true)
+ }
+
+ clearInterval(this._interval)
+ this._interval = null
+ }
+
+ cycle(event) {
+ if (!event) {
+ this._isPaused = false
+ }
+
+ if (this._interval) {
+ clearInterval(this._interval)
+ this._interval = null
+ }
+
+ if (this._config.interval && !this._isPaused) {
+ this._interval = setInterval(
+ this.next.bind(this), this._config.interval
+ )
+ }
+ }
+
+ to(index) {
+ this._activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0]
+
+ let activeIndex = this._getItemIndex(this._activeElement)
+
+ if (index > (this._items.length - 1) || index < 0) {
+ return
+ }
+
+ if (this._isSliding) {
+ $(this._element).one(Event.SLID, () => this.to(index))
+ return
+ }
+
+ if (activeIndex == index) {
+ this.pause()
+ this.cycle()
+ return
+ }
+
+ var direction = index > activeIndex ?
+ Direction.NEXT :
+ Direction.PREVIOUS
+
+ this._slide(direction, this._items[index])
+ }
+
+
+ // private
+
+ _addEventListeners() {
+ if (this._config.keyboard) {
+ $(this._element)
+ .on('keydown.bs.carousel', this._keydown.bind(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))
+ }
+ }
+
+ _keydown(event) {
+ event.preventDefault()
+
+ if (/input|textarea/i.test(event.target.tagName)) return
+
+ switch (event.which) {
+ case 37: this.prev(); break
+ case 39: this.next(); break
+ default: return
+ }
+ }
+
+ _getItemIndex(element) {
+ this._items = $.makeArray($(element).parent().find(Selector.ITEM))
+ return this._items.indexOf(element)
+ }
+
+ _getItemByDirection(direction, activeElement) {
+ let isNextDirection = direction === Direction.NEXT
+ let isPrevDirection = direction === Direction.PREVIOUS
+ let activeIndex = this._getItemIndex(activeElement)
+ let lastItemIndex = (this._items.length - 1)
+ let isGoingToWrap = (isPrevDirection && activeIndex === 0) ||
+ (isNextDirection && activeIndex == lastItemIndex)
+
+ if (isGoingToWrap && !this._config.wrap) {
+ return activeElement
+ }
+
+ let delta = direction == Direction.PREVIOUS ? -1 : 1
+ let itemIndex = (activeIndex + delta) % this._items.length
+
+ return itemIndex === -1 ?
+ this._items[this._items.length - 1] : this._items[itemIndex]
+ }
+
+
+ _triggerSlideEvent(relatedTarget, directionalClassname) {
+ let slideEvent = $.Event(Event.SLIDE, {
+ relatedTarget: relatedTarget,
+ direction: directionalClassname
+ })
+
+ $(this._element).trigger(slideEvent)
+
+ return slideEvent
+ }
+
+ _setActiveIndicatorElement(element) {
+ if (this._indicatorsElement) {
+ $(this._indicatorsElement)
+ .find(Selector.ACTIVE)
+ .removeClass(ClassName.ACTIVE)
+
+ let nextIndicator = this._indicatorsElement.children[
+ this._getItemIndex(element)
+ ]
+
+ if (nextIndicator) {
+ $(nextIndicator).addClass(ClassName.ACTIVE)
+ }
+ }
+ }
+
+ _slide(direction, element) {
+ let activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0]
+ let nextElement = element || activeElement &&
+ this._getItemByDirection(direction, activeElement)
+
+ let isCycling = !!this._interval
+
+ let directionalClassName = direction == Direction.NEXT ?
+ ClassName.LEFT :
+ ClassName.RIGHT
+
+ if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) {
+ this._isSliding = false
+ return
+ }
+
+ let slideEvent = this._triggerSlideEvent(nextElement, directionalClassName)
+ if (slideEvent.isDefaultPrevented()) {
+ return
+ }
+
+ if (!activeElement || !nextElement) {
+ // some weirdness is happening, so we bail
+ return
+ }
+
+ this._isSliding = true
+
+ if (isCycling) {
+ this.pause()
+ }
+
+ this._setActiveIndicatorElement(nextElement)
+
+ var slidEvent = $.Event(Event.SLID, {
+ relatedTarget: nextElement,
+ direction: directionalClassName
+ })
+
+ if (Util.supportsTransitionEnd() &&
+ $(this._element).hasClass(ClassName.SLIDE)) {
+
+ $(nextElement).addClass(direction)
+
+ Util.reflow(nextElement)
+
+ $(activeElement).addClass(directionalClassName)
+ $(nextElement).addClass(directionalClassName)
+
+ $(activeElement)
+ .one(Util.TRANSITION_END, () => {
+ $(nextElement)
+ .removeClass(directionalClassName)
+ .removeClass(direction)
+
+ $(nextElement).addClass(ClassName.ACTIVE)
+
+ $(activeElement)
+ .removeClass(ClassName.ACTIVE)
+ .removeClass(direction)
+ .removeClass(directionalClassName)
+
+ this._isSliding = false
+
+ setTimeout(() => $(this._element).trigger(slidEvent), 0)
+
+ })
+ .emulateTransitionEnd(TRANSITION_DURATION)
+
+ } else {
+ $(activeElement).removeClass(ClassName.ACTIVE)
+ $(nextElement).addClass(ClassName.ACTIVE)
+
+ this._isSliding = false
+ $(this._element).trigger(slidEvent)
+ }
+
+ if (isCycling) {
+ this.cycle()
+ }
+ }
+
+
+ // static
+
+ static _jQueryInterface(config) {
+ return this.each(function () {
+ let data = $(this).data(DATA_KEY)
+ let _config = $.extend({}, Defaults, $(this).data())
+
+ if (typeof config === 'object') {
+ $.extend(_config, config)
+ }
+
+ let action = typeof config === 'string' ? config : _config.slide
+
+ if (!data) {
+ data = new Carousel(this, _config)
+ $(this).data(DATA_KEY, data)
+ }
+
+ if (typeof config == 'number') {
+ data.to(config)
+
+ } else if (action) {
+ data[action]()
+
+ } else if (_config.interval) {
+ data.pause()
+ data.cycle()
+ }
+ })
+ }
+
+ static _dataApiClickHandler(event) {
+ let selector = Util.getSelectorFromElement(this)
+
+ if (!selector) {
+ return
+ }
+
+ let target = $(selector)[0]
+
+ if (!target || !$(target).hasClass(ClassName.CAROUSEL)) {
+ return
+ }
+
+ let config = $.extend({}, $(target).data(), $(this).data())
+
+ let slideIndex = this.getAttribute('data-slide-to')
+ if (slideIndex) {
+ config.interval = false
+ }
+
+ Carousel._jQueryInterface.call($(target), config)
+
+ if (slideIndex) {
+ $(target).data(DATA_KEY).to(slideIndex)
+ }
+
+ event.preventDefault()
+ }
+
+ }
+
+
+ /**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+ $(document)
+ .on(Event.CLICK, Selector.DATA_SLIDE, Carousel._dataApiClickHandler)
+
+ $(window).on(Event.LOAD, function () {
+ $(Selector.DATA_RIDE).each(function () {
+ let $carousel = $(this)
+ Carousel._jQueryInterface.call($carousel, $carousel.data())
+ })
+ })
+
+
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME] = Carousel._jQueryInterface
+ $.fn[NAME].Constructor = Carousel
+ $.fn[NAME].noConflict = function () {
+ $.fn[NAME] = JQUERY_NO_CONFLICT
+ return Carousel._jQueryInterface
+ }
+
+ return Carousel
+
+})(jQuery)
+
+export default Carousel
diff --git a/js/src/util.js b/js/src/util.js
index abc548a45..c9ffbe555 100644
--- a/js/src/util.js
+++ b/js/src/util.js
@@ -60,7 +60,7 @@ const Util = (($) => {
setTimeout(() => {
if (!called) {
- $(this).trigger(transition.end)
+ Util.triggerTransitionEnd(this)
}
}, duration)
@@ -109,6 +109,10 @@ const Util = (($) => {
new Function('bs', 'return bs')(element.offsetHeight)
},
+ triggerTransitionEnd(element) {
+ $(element).trigger(transition.end)
+ },
+
supportsTransitionEnd() {
return !!transition
}