").appendTo(i),n=i.uniqueId().attr("id");return this._addClass(s,"ui-tooltip-content"),this._addClass(i,"ui-tooltip","ui-widget ui-widget-content"),i.appendTo(this._appendTo(e)),this.tooltips[n]={element:e,tooltip:i}},_find:function(t){var e=t.data("ui-tooltip-id");return e?this.tooltips[e]:null},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){var e=t.closest(".ui-front, dialog");return e.length||(e=this.document[0].body),e},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur"),o=s.element;n.target=n.currentTarget=o[0],e.close(n,!0),t("#"+i).remove(),o.data("ui-tooltip-title")&&(o.attr("title")||o.attr("title",o.data("ui-tooltip-title")),o.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),t.uiBackCompat!==!1&&t.widget("ui.tooltip",t.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}}),t.ui.tooltip});
/*!
* Bootstrap v3.4.1 (https://getbootstrap.com/)
* Copyright 2011-2019 Twitter, Inc.
* Licensed under the MIT license
*/
if (typeof jQuery === 'undefined') {
throw new Error('Bootstrap\'s JavaScript requires jQuery')
}
+function ($) {
'use strict';
var version = $.fn.jquery.split(' ')[0].split('.')
if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
}
}(jQuery);
/* ========================================================================
* Bootstrap: transition.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#transitions
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
// ============================================================
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
WebkitTransition : 'webkitTransitionEnd',
MozTransition : 'transitionend',
OTransition : 'oTransitionEnd otransitionend',
transition : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false // explicit for ie8 ( ._.)
}
// https://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
}
$(function () {
$.support.transition = transitionEnd()
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)
}
}
})
}(jQuery);
/* ========================================================================
* Bootstrap: alert.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#alerts
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// ALERT CLASS DEFINITION
// ======================
var dismiss = '[data-dismiss="alert"]'
var Alert = function (el) {
$(el).on('click', dismiss, this.close)
}
Alert.VERSION = '3.4.1'
Alert.TRANSITION_DURATION = 150
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
}
selector = selector === '#' ? [] : selector
var $parent = $(document).find(selector)
if (e) e.preventDefault()
if (!$parent.length) {
$parent = $this.closest('.alert')
}
$parent.trigger(e = $.Event('close.bs.alert'))
if (e.isDefaultPrevented()) return
$parent.removeClass('in')
function removeElement() {
// detach from parent, fire event then clean up data
$parent.detach().trigger('closed.bs.alert').remove()
}
$.support.transition && $parent.hasClass('fade') ?
$parent
.one('bsTransitionEnd', removeElement)
.emulateTransitionEnd(Alert.TRANSITION_DURATION) :
removeElement()
}
// ALERT PLUGIN DEFINITION
// =======================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.alert')
if (!data) $this.data('bs.alert', (data = new Alert(this)))
if (typeof option == 'string') data[option].call($this)
})
}
var old = $.fn.alert
$.fn.alert = Plugin
$.fn.alert.Constructor = Alert
// ALERT NO CONFLICT
// =================
$.fn.alert.noConflict = function () {
$.fn.alert = old
return this
}
// ALERT DATA-API
// ==============
$(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
}(jQuery);
/* ========================================================================
* Bootstrap: button.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#buttons
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// BUTTON PUBLIC CLASS DEFINITION
// ==============================
var Button = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Button.DEFAULTS, options)
this.isLoading = false
}
Button.VERSION = '3.4.1'
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()
state += 'Text'
if (data.resetText == null) $el.data('resetText', $el[val]())
// 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).prop(d, true)
} else if (this.isLoading) {
this.isLoading = false
$el.removeClass(d).removeAttr(d).prop(d, false)
}
}, this), 0)
}
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')) changed = false
$parent.find('.active').removeClass('active')
this.$element.addClass('active')
} else if ($input.prop('type') == 'checkbox') {
if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
this.$element.toggleClass('active')
}
$input.prop('checked', this.$element.hasClass('active'))
if (changed) $input.trigger('change')
} else {
this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
this.$element.toggleClass('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
if (!data) $this.data('bs.button', (data = new Button(this, options)))
if (option == 'toggle') data.toggle()
else if (option) data.setState(option)
})
}
var old = $.fn.button
$.fn.button = Plugin
$.fn.button.Constructor = Button
// BUTTON NO CONFLICT
// ==================
$.fn.button.noConflict = function () {
$.fn.button = old
return this
}
// BUTTON DATA-API
// ===============
$(document)
.on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
var $btn = $(e.target).closest('.btn')
Plugin.call($btn, 'toggle')
if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
// Prevent double click on radios, and the double selections (so cancellation) on checkboxes
e.preventDefault()
// The target component still receive the focus
if ($btn.is('input,button')) $btn.trigger('focus')
else $btn.find('input:visible,button:visible').first().trigger('focus')
}
})
.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))
})
}(jQuery);
/* ========================================================================
* Bootstrap: carousel.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#carousel
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CAROUSEL CLASS DEFINITION
// =========================
var Carousel = function (element, options) {
this.$element = $(element)
this.$indicators = this.$element.find('.carousel-indicators')
this.options = options
this.paused = null
this.sliding = null
this.interval = null
this.$active = null
this.$items = null
this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
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))
}
Carousel.VERSION = '3.4.1'
Carousel.TRANSITION_DURATION = 600
Carousel.DEFAULTS = {
interval: 5000,
pause: 'hover',
wrap: true,
keyboard: true
}
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
}
e.preventDefault()
}
Carousel.prototype.cycle = function (e) {
e || (this.paused = false)
this.interval && clearInterval(this.interval)
this.options.interval
&& !this.paused
&& (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
return this
}
Carousel.prototype.getItemIndex = function (item) {
this.$items = item.parent().children('.item')
return this.$items.index(item || this.$active)
}
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)
}
Carousel.prototype.to = function (pos) {
var that = this
var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
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()
return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
}
Carousel.prototype.pause = function (e) {
e || (this.paused = true)
if (this.$element.find('.next, .prev').length && $.support.transition) {
this.$element.trigger($.support.transition.end)
this.cycle(true)
}
this.interval = clearInterval(this.interval)
return this
}
Carousel.prototype.next = function () {
if (this.sliding) return
return this.slide('next')
}
Carousel.prototype.prev = function () {
if (this.sliding) return
return this.slide('prev')
}
Carousel.prototype.slide = function (type, next) {
var $active = this.$element.find('.item.active')
var $next = next || this.getItemForDirection(type, $active)
var isCycling = this.interval
var direction = type == 'next' ? 'left' : 'right'
var that = this
if ($next.hasClass('active')) return (this.sliding = false)
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)
if (typeof $next === 'object' && $next.length) {
$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()
return this
}
// CAROUSEL PLUGIN DEFINITION
// ==========================
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 (!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()
})
}
var old = $.fn.carousel
$.fn.carousel = Plugin
$.fn.carousel.Constructor = Carousel
// CAROUSEL NO CONFLICT
// ====================
$.fn.carousel.noConflict = function () {
$.fn.carousel = old
return this
}
// CAROUSEL DATA-API
// =================
var clickHandler = function (e) {
var $this = $(this)
var href = $this.attr('href')
if (href) {
href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
}
var target = $this.attr('data-target') || href
var $target = $(document).find(target)
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)
if (slideIndex) {
$target.data('bs.carousel').to(slideIndex)
}
e.preventDefault()
}
$(document)
.on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
.on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
$(window).on('load', function () {
$('[data-ride="carousel"]').each(function () {
var $carousel = $(this)
Plugin.call($carousel, $carousel.data())
})
})
}(jQuery);
/* ========================================================================
* Bootstrap: collapse.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#collapse
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
/* jshint latedef: false */
+function ($) {
'use strict';
// COLLAPSE PUBLIC CLASS DEFINITION
// ================================
var Collapse = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Collapse.DEFAULTS, options)
this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
'[data-toggle="collapse"][data-target="#' + element.id + '"]')
this.transitioning = null
if (this.options.parent) {
this.$parent = this.getParent()
} else {
this.addAriaAndCollapsedClass(this.$element, this.$trigger)
}
if (this.options.toggle) this.toggle()
}
Collapse.VERSION = '3.4.1'
Collapse.TRANSITION_DURATION = 350
Collapse.DEFAULTS = {
toggle: true
}
Collapse.prototype.dimension = function () {
var hasWidth = this.$element.hasClass('width')
return hasWidth ? 'width' : 'height'
}
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
}
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)
}
var dimension = this.dimension()
this.$element
.removeClass('collapse')
.addClass('collapsing')[dimension](0)
.attr('aria-expanded', true)
this.$trigger
.removeClass('collapsed')
.attr('aria-expanded', true)
this.transitioning = 1
var complete = function () {
this.$element
.removeClass('collapsing')
.addClass('collapse in')[dimension]('')
this.transitioning = 0
this.$element
.trigger('shown.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
var scrollSize = $.camelCase(['scroll', dimension].join('-'))
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
var startEvent = $.Event('hide.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
var dimension = this.dimension()
this.$element[dimension](this.$element[dimension]())[0].offsetHeight
this.$element
.addClass('collapsing')
.removeClass('collapse in')
.attr('aria-expanded', false)
this.$trigger
.addClass('collapsed')
.attr('aria-expanded', false)
this.transitioning = 1
var complete = function () {
this.transitioning = 0
this.$element
.removeClass('collapsing')
.addClass('collapse')
.trigger('hidden.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
this.$element
[dimension](0)
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)
}
Collapse.prototype.toggle = function () {
this[this.$element.hasClass('in') ? 'hide' : 'show']()
}
Collapse.prototype.getParent = function () {
return $(document).find(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()
}
Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
var isOpen = $element.hasClass('in')
$element.attr('aria-expanded', isOpen)
$trigger
.toggleClass('collapsed', !isOpen)
.attr('aria-expanded', isOpen)
}
function getTargetFromTrigger($trigger) {
var href
var target = $trigger.attr('data-target')
|| (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
return $(document).find(target)
}
// COLLAPSE PLUGIN DEFINITION
// ==========================
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)
if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.collapse
$.fn.collapse = Plugin
$.fn.collapse.Constructor = Collapse
// COLLAPSE NO CONFLICT
// ====================
$.fn.collapse.noConflict = function () {
$.fn.collapse = old
return this
}
// 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()
var $target = getTargetFromTrigger($this)
var data = $target.data('bs.collapse')
var option = data ? 'toggle' : $this.data()
Plugin.call($target, option)
})
}(jQuery);
/* ========================================================================
* Bootstrap: dropdown.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#dropdowns
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// DROPDOWN CLASS DEFINITION
// =========================
var backdrop = '.dropdown-backdrop'
var toggle = '[data-toggle="dropdown"]'
var Dropdown = function (element) {
$(element).on('click.bs.dropdown', this.toggle)
}
Dropdown.VERSION = '3.4.1'
function getParent($this) {
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = selector !== '#' ? $(document).find(selector) : null
return $parent && $parent.length ? $parent : $this.parent()
}
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 }
if (!$parent.hasClass('open')) return
if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$this.attr('aria-expanded', 'false')
$parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
})
}
Dropdown.prototype.toggle = function (e) {
var $this = $(this)
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
clearMenus()
if (!isActive) {
if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
// if mobile we use a backdrop because click events don't delegate
$(document.createElement('div'))
.addClass('dropdown-backdrop')
.insertAfter($(this))
.on('click', clearMenus)
}
var relatedTarget = { relatedTarget: this }
$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$this
.trigger('focus')
.attr('aria-expanded', 'true')
$parent
.toggleClass('open')
.trigger($.Event('shown.bs.dropdown', relatedTarget))
}
return false
}
Dropdown.prototype.keydown = function (e) {
if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
var $this = $(this)
e.preventDefault()
e.stopPropagation()
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
if (!isActive && e.which != 27 || isActive && e.which == 27) {
if (e.which == 27) $parent.find(toggle).trigger('focus')
return $this.trigger('click')
}
var desc = ' li:not(.disabled):visible a'
var $items = $parent.find('.dropdown-menu' + desc)
if (!$items.length) return
var index = $items.index(e.target)
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')
}
// DROPDOWN PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.dropdown')
if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
if (typeof option == 'string') data[option].call($this)
})
}
var old = $.fn.dropdown
$.fn.dropdown = Plugin
$.fn.dropdown.Constructor = Dropdown
// DROPDOWN NO CONFLICT
// ====================
$.fn.dropdown.noConflict = function () {
$.fn.dropdown = old
return this
}
// APPLY TO STANDARD DROPDOWN ELEMENTS
// ===================================
$(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', '.dropdown-menu', Dropdown.prototype.keydown)
}(jQuery);
/* ========================================================================
* Bootstrap: modal.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#modals
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// MODAL CLASS DEFINITION
// ======================
var Modal = function (element, options) {
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$dialog = this.$element.find('.modal-dialog')
this.$backdrop = null
this.isShown = null
this.originalBodyPad = null
this.scrollbarWidth = 0
this.ignoreBackdropClick = false
this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'
if (this.options.remote) {
this.$element
.find('.modal-content')
.load(this.options.remote, $.proxy(function () {
this.$element.trigger('loaded.bs.modal')
}, this))
}
}
Modal.VERSION = '3.4.1'
Modal.TRANSITION_DURATION = 300
Modal.BACKDROP_TRANSITION_DURATION = 150
Modal.DEFAULTS = {
backdrop: true,
keyboard: true,
show: true
}
Modal.prototype.toggle = function (_relatedTarget) {
return this.isShown ? this.hide() : this.show(_relatedTarget)
}
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
this.isShown = true
this.checkScrollbar()
this.setScrollbar()
this.$body.addClass('modal-open')
this.escape()
this.resize()
this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
this.$dialog.on('mousedown.dismiss.bs.modal', function () {
that.$element.one('mouseup.dismiss.bs.modal', function (e) {
if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
})
})
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
}
that.$element
.show()
.scrollTop(0)
that.adjustDialog()
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element.addClass('in')
that.enforceFocus()
var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
transition ?
that.$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()
e = $.Event('hide.bs.modal')
this.$element.trigger(e)
if (!this.isShown || e.isDefaultPrevented()) return
this.isShown = false
this.escape()
this.resize()
$(document).off('focusin.bs.modal')
this.$element
.removeClass('in')
.off('click.dismiss.bs.modal')
.off('mouseup.dismiss.bs.modal')
this.$dialog.off('mousedown.dismiss.bs.modal')
$.support.transition && this.$element.hasClass('fade') ?
this.$element
.one('bsTransitionEnd', $.proxy(this.hideModal, this))
.emulateTransitionEnd(Modal.TRANSITION_DURATION) :
this.hideModal()
}
Modal.prototype.enforceFocus = function () {
$(document)
.off('focusin.bs.modal') // guard against infinite focus loop
.on('focusin.bs.modal', $.proxy(function (e) {
if (document !== e.target &&
this.$element[0] !== e.target &&
!this.$element.has(e.target).length) {
this.$element.trigger('focus')
}
}, this))
}
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')
}
}
Modal.prototype.resize = function () {
if (this.isShown) {
$(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
} else {
$(window).off('resize.bs.modal')
}
}
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')
})
}
Modal.prototype.removeBackdrop = function () {
this.$backdrop && this.$backdrop.remove()
this.$backdrop = null
}
Modal.prototype.backdrop = function (callback) {
var that = this
var animate = this.$element.hasClass('fade') ? 'fade' : ''
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
this.$backdrop = $(document.createElement('div'))
.addClass('modal-backdrop ' + animate)
.appendTo(this.$body)
this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
if (this.ignoreBackdropClick) {
this.ignoreBackdropClick = false
return
}
if (e.target !== e.currentTarget) return
this.options.backdrop == 'static'
? this.$element[0].focus()
: this.hide()
}, this))
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
this.$backdrop.addClass('in')
if (!callback) return
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()
}
$.support.transition && this.$element.hasClass('fade') ?
this.$backdrop
.one('bsTransitionEnd', callbackRemove)
.emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callbackRemove()
} else if (callback) {
callback()
}
}
// these following methods are used to handle overflowing modals
Modal.prototype.handleUpdate = function () {
this.adjustDialog()
}
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 : ''
})
}
Modal.prototype.resetAdjustments = function () {
this.$element.css({
paddingLeft: '',
paddingRight: ''
})
}
Modal.prototype.checkScrollbar = function () {
var fullWindowWidth = window.innerWidth
if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
var documentElementRect = document.documentElement.getBoundingClientRect()
fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
}
this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
this.scrollbarWidth = this.measureScrollbar()
}
Modal.prototype.setScrollbar = function () {
var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
this.originalBodyPad = document.body.style.paddingRight || ''
var scrollbarWidth = this.scrollbarWidth
if (this.bodyIsOverflowing) {
this.$body.css('padding-right', bodyPad + scrollbarWidth)
$(this.fixedContent).each(function (index, element) {
var actualPadding = element.style.paddingRight
var calculatedPadding = $(element).css('padding-right')
$(element)
.data('padding-right', actualPadding)
.css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
})
}
}
Modal.prototype.resetScrollbar = function () {
this.$body.css('padding-right', this.originalBodyPad)
$(this.fixedContent).each(function (index, element) {
var padding = $(element).data('padding-right')
$(element).removeData('padding-right')
element.style.paddingRight = padding ? padding : ''
})
}
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
}
// MODAL PLUGIN DEFINITION
// =======================
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)
})
}
var old = $.fn.modal
$.fn.modal = Plugin
$.fn.modal.Constructor = Modal
// MODAL NO CONFLICT
// =================
$.fn.modal.noConflict = function () {
$.fn.modal = old
return this
}
// 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 $target = $(document).find(target)
var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
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)
})
}(jQuery);
/* ========================================================================
* Bootstrap: tooltip.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#tooltip
* Inspired by the original jQuery.tipsy by Jason Frame
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
var uriAttrs = [
'background',
'cite',
'href',
'itemtype',
'longdesc',
'poster',
'src',
'xlink:href'
]
var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
var DefaultWhitelist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
area: [],
b: [],
br: [],
col: [],
code: [],
div: [],
em: [],
hr: [],
h1: [],
h2: [],
h3: [],
h4: [],
h5: [],
h6: [],
i: [],
img: ['src', 'alt', 'title', 'width', 'height'],
li: [],
ol: [],
p: [],
pre: [],
s: [],
small: [],
span: [],
sub: [],
sup: [],
strong: [],
u: [],
ul: []
}
/**
* A pattern that recognizes a commonly useful subset of URLs that are safe.
*
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
*/
var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
/**
* A pattern that matches safe data URLs. Only matches image, video and audio types.
*
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
*/
var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
function allowedAttribute(attr, allowedAttributeList) {
var attrName = attr.nodeName.toLowerCase()
if ($.inArray(attrName, allowedAttributeList) !== -1) {
if ($.inArray(attrName, uriAttrs) !== -1) {
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
}
return true
}
var regExp = $(allowedAttributeList).filter(function (index, value) {
return value instanceof RegExp
})
// Check if a regular expression validates the attribute.
for (var i = 0, l = regExp.length; i < l; i++) {
if (attrName.match(regExp[i])) {
return true
}
}
return false
}
function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
if (unsafeHtml.length === 0) {
return unsafeHtml
}
if (sanitizeFn && typeof sanitizeFn === 'function') {
return sanitizeFn(unsafeHtml)
}
// IE 8 and below don't support createHTMLDocument
if (!document.implementation || !document.implementation.createHTMLDocument) {
return unsafeHtml
}
var createdDocument = document.implementation.createHTMLDocument('sanitization')
createdDocument.body.innerHTML = unsafeHtml
var whitelistKeys = $.map(whiteList, function (el, i) { return i })
var elements = $(createdDocument.body).find('*')
for (var i = 0, len = elements.length; i < len; i++) {
var el = elements[i]
var elName = el.nodeName.toLowerCase()
if ($.inArray(elName, whitelistKeys) === -1) {
el.parentNode.removeChild(el)
continue
}
var attributeList = $.map(el.attributes, function (el) { return el })
var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
for (var j = 0, len2 = attributeList.length; j < len2; j++) {
if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
el.removeAttribute(attributeList[j].nodeName)
}
}
}
return createdDocument.body.innerHTML
}
// TOOLTIP PUBLIC CLASS DEFINITION
// ===============================
var Tooltip = function (element, options) {
this.type = null
this.options = null
this.enabled = null
this.timeout = null
this.hoverState = null
this.$element = null
this.inState = null
this.init('tooltip', element, options)
}
Tooltip.VERSION = '3.4.1'
Tooltip.TRANSITION_DURATION = 150
Tooltip.DEFAULTS = {
animation: true,
placement: 'top',
selector: false,
template: '
',
trigger: 'hover focus',
title: '',
delay: 0,
html: false,
container: false,
viewport: {
selector: 'body',
padding: 0
},
sanitize : true,
sanitizeFn : null,
whiteList : DefaultWhitelist
}
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 && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
this.inState = { click: false, hover: false, focus: false }
if (this.$element[0] instanceof document.constructor && !this.options.selector) {
throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
}
var triggers = this.options.trigger.split(' ')
for (var i = triggers.length; i--;) {
var trigger = triggers[i]
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'
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))
}
}
this.options.selector ?
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
this.fixTitle()
}
Tooltip.prototype.getDefaults = function () {
return Tooltip.DEFAULTS
}
Tooltip.prototype.getOptions = function (options) {
var dataAttributes = this.$element.data()
for (var dataAttr in dataAttributes) {
if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
delete dataAttributes[dataAttr]
}
}
options = $.extend({}, this.getDefaults(), dataAttributes, options)
if (options.delay && typeof options.delay == 'number') {
options.delay = {
show: options.delay,
hide: options.delay
}
}
if (options.sanitize) {
options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
}
return options
}
Tooltip.prototype.getDelegateOptions = function () {
var options = {}
var defaults = this.getDefaults()
this._options && $.each(this._options, function (key, value) {
if (defaults[key] != value) options[key] = value
})
return options
}
Tooltip.prototype.enter = function (obj) {
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget).data('bs.' + this.type)
if (!self) {
self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
$(obj.currentTarget).data('bs.' + this.type, self)
}
if (obj instanceof $.Event) {
self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
}
if (self.tip().hasClass('in') || self.hoverState == 'in') {
self.hoverState = 'in'
return
}
clearTimeout(self.timeout)
self.hoverState = 'in'
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)
}
Tooltip.prototype.isInStateTrue = function () {
for (var key in this.inState) {
if (this.inState[key]) return true
}
return false
}
Tooltip.prototype.leave = function (obj) {
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget).data('bs.' + this.type)
if (!self) {
self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
$(obj.currentTarget).data('bs.' + this.type, self)
}
if (obj instanceof $.Event) {
self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
}
if (self.isInStateTrue()) return
clearTimeout(self.timeout)
self.hoverState = 'out'
if (!self.options.delay || !self.options.delay.hide) return self.hide()
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)
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
var $tip = this.tip()
var tipId = this.getUID(this.type)
this.setContent()
$tip.attr('id', tipId)
this.$element.attr('aria-describedby', tipId)
if (this.options.animation) $tip.addClass('fade')
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'
$tip
.detach()
.css({ top: 0, left: 0, display: 'block' })
.addClass(placement)
.data('bs.' + this.type, this)
this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
this.$element.trigger('inserted.bs.' + this.type)
var pos = this.getPosition()
var actualWidth = $tip[0].offsetWidth
var actualHeight = $tip[0].offsetHeight
if (autoPlace) {
var orgPlacement = placement
var viewportDim = this.getPosition(this.$viewport)
placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
placement
$tip
.removeClass(orgPlacement)
.addClass(placement)
}
var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
this.applyPlacement(calculatedOffset, placement)
var complete = function () {
var prevHoverState = that.hoverState
that.$element.trigger('shown.bs.' + that.type)
that.hoverState = null
if (prevHoverState == 'out') that.leave(that)
}
$.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
// 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 ie 8/9
if (isNaN(marginTop)) marginTop = 0
if (isNaN(marginLeft)) marginLeft = 0
offset.top += marginTop
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)
$tip.addClass('in')
// 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 (placement == 'top' && actualHeight != height) {
offset.top = offset.top + height - actualHeight
}
var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
if (delta.left) offset.left += delta.left
else offset.top += delta.top
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)
}
Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
this.arrow()
.css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
.css(isVertical ? 'top' : 'left', '')
}
Tooltip.prototype.setContent = function () {
var $tip = this.tip()
var title = this.getTitle()
if (this.options.html) {
if (this.options.sanitize) {
title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn)
}
$tip.find('.tooltip-inner').html(title)
} else {
$tip.find('.tooltip-inner').text(title)
}
$tip.removeClass('fade in top bottom left right')
}
Tooltip.prototype.hide = function (callback) {
var that = this
var $tip = $(this.$tip)
var e = $.Event('hide.bs.' + this.type)
function complete() {
if (that.hoverState != 'in') $tip.detach()
if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
that.$element
.removeAttr('aria-describedby')
.trigger('hidden.bs.' + that.type)
}
callback && callback()
}
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$tip.removeClass('in')
$.support.transition && $tip.hasClass('fade') ?
$tip
.one('bsTransitionEnd', complete)
.emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
complete()
this.hoverState = null
return this
}
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', '')
}
}
Tooltip.prototype.hasContent = function () {
return this.getTitle()
}
Tooltip.prototype.getPosition = function ($element) {
$element = $element || this.$element
var el = $element[0]
var isBody = el.tagName == 'BODY'
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 })
}
var isSvg = window.SVGElement && el instanceof window.SVGElement
// Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
// See https://github.com/twbs/bootstrap/issues/20280
var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $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)
}
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 }
}
Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
var delta = { top: 0, left: 0 }
if (!this.$viewport) return delta
var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
var viewportDimensions = this.getPosition(this.$viewport)
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
}
} 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.right) { // right overflow
delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
}
}
return delta
}
Tooltip.prototype.getTitle = function () {
var title
var $e = this.$element
var o = this.options
title = $e.attr('data-original-title')
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
return title
}
Tooltip.prototype.getUID = function (prefix) {
do prefix += ~~(Math.random() * 1000000)
while (document.getElementById(prefix))
return prefix
}
Tooltip.prototype.tip = function () {
if (!this.$tip) {
this.$tip = $(this.options.template)
if (this.$tip.length != 1) {
throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
}
}
return this.$tip
}
Tooltip.prototype.arrow = function () {
return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
}
Tooltip.prototype.enable = function () {
this.enabled = true
}
Tooltip.prototype.disable = function () {
this.enabled = false
}
Tooltip.prototype.toggleEnabled = function () {
this.enabled = !this.enabled
}
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 (e) {
self.inState.click = !self.inState.click
if (self.isInStateTrue()) self.enter(self)
else self.leave(self)
} else {
self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
}
}
Tooltip.prototype.destroy = function () {
var that = this
clearTimeout(this.timeout)
this.hide(function () {
that.$element.off('.' + that.type).removeData('bs.' + that.type)
if (that.$tip) {
that.$tip.detach()
}
that.$tip = null
that.$arrow = null
that.$viewport = null
that.$element = null
})
}
Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
}
// 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
if (!data && /destroy|hide/.test(option)) return
if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.tooltip
$.fn.tooltip = Plugin
$.fn.tooltip.Constructor = Tooltip
// TOOLTIP NO CONFLICT
// ===================
$.fn.tooltip.noConflict = function () {
$.fn.tooltip = old
return this
}
}(jQuery);
/* ========================================================================
* Bootstrap: popover.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#popovers
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// POPOVER PUBLIC CLASS DEFINITION
// ===============================
var Popover = function (element, options) {
this.init('popover', element, options)
}
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
Popover.VERSION = '3.4.1'
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
placement: 'right',
trigger: 'click',
content: '',
template: '
'
})
// NOTE: POPOVER EXTENDS tooltip.js
// ================================
Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
Popover.prototype.constructor = Popover
Popover.prototype.getDefaults = function () {
return Popover.DEFAULTS
}
Popover.prototype.setContent = function () {
var $tip = this.tip()
var title = this.getTitle()
var content = this.getContent()
if (this.options.html) {
var typeContent = typeof content
if (this.options.sanitize) {
title = this.sanitizeHtml(title)
if (typeContent === 'string') {
content = this.sanitizeHtml(content)
}
}
$tip.find('.popover-title').html(title)
$tip.find('.popover-content').children().detach().end()[
typeContent === 'string' ? 'html' : 'append'
](content)
} else {
$tip.find('.popover-title').text(title)
$tip.find('.popover-content').children().detach().end().text(content)
}
$tip.removeClass('fade top bottom left right in')
// 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()
}
Popover.prototype.hasContent = function () {
return this.getTitle() || this.getContent()
}
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)
}
Popover.prototype.arrow = function () {
return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
}
// 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 && /destroy|hide/.test(option)) return
if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.popover
$.fn.popover = Plugin
$.fn.popover.Constructor = Popover
// POPOVER NO CONFLICT
// ===================
$.fn.popover.noConflict = function () {
$.fn.popover = old
return this
}
}(jQuery);
/* ========================================================================
* Bootstrap: scrollspy.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#scrollspy
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// SCROLLSPY CLASS DEFINITION
// ==========================
function ScrollSpy(element, options) {
this.$body = $(document.body)
this.$scrollElement = $(element).is(document.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
this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
this.refresh()
this.process()
}
ScrollSpy.VERSION = '3.4.1'
ScrollSpy.DEFAULTS = {
offset: 10
}
ScrollSpy.prototype.getScrollHeight = function () {
return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
}
ScrollSpy.prototype.refresh = function () {
var that = this
var offsetMethod = 'offset'
var offsetBase = 0
this.offsets = []
this.targets = []
this.scrollHeight = this.getScrollHeight()
if (!$.isWindow(this.$scrollElement[0])) {
offsetMethod = 'position'
offsetBase = this.$scrollElement.scrollTop()
}
this.$body
.find(this.selector)
.map(function () {
var $el = $(this)
var href = $el.data('target') || $el.attr('href')
var $href = /^#./.test(href) && $(href)
return ($href
&& $href.length
&& $href.is(':visible')
&& [[$href[offsetMethod]().top + offsetBase, href]]) || null
})
.sort(function (a, b) { return a[0] - b[0] })
.each(function () {
that.offsets.push(this[0])
that.targets.push(this[1])
})
}
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
if (this.scrollHeight != scrollHeight) {
this.refresh()
}
if (scrollTop >= maxScroll) {
return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
}
if (activeTarget && scrollTop < offsets[0]) {
this.activeTarget = null
return this.clear()
}
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
&& this.activate(targets[i])
}
}
ScrollSpy.prototype.activate = function (target) {
this.activeTarget = target
this.clear()
var selector = this.selector +
'[data-target="' + target + '"],' +
this.selector + '[href="' + target + '"]'
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')
}
ScrollSpy.prototype.clear = function () {
$(this.selector)
.parentsUntil(this.options.target, '.active')
.removeClass('active')
}
// SCROLLSPY PLUGIN DEFINITION
// ===========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.scrollspy')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.scrollspy
$.fn.scrollspy = Plugin
$.fn.scrollspy.Constructor = ScrollSpy
// SCROLLSPY NO CONFLICT
// =====================
$.fn.scrollspy.noConflict = function () {
$.fn.scrollspy = old
return this
}
// 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);
/* ========================================================================
* Bootstrap: tab.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#tabs
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// TAB CLASS DEFINITION
// ====================
var Tab = function (element) {
// jscs:disable requireDollarBeforejQueryAssignment
this.element = $(element)
// jscs:enable requireDollarBeforejQueryAssignment
}
Tab.VERSION = '3.4.1'
Tab.TRANSITION_DURATION = 150
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
}
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]
})
$previous.trigger(hideEvent)
$this.trigger(showEvent)
if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
var $target = $(document).find(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]
})
})
}
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').length) {
element
.closest('li.dropdown')
.addClass('active')
.end()
.find('[data-toggle="tab"]')
.attr('aria-expanded', true)
}
callback && callback()
}
$active.length && transition ?
$active
.one('bsTransitionEnd', next)
.emulateTransitionEnd(Tab.TRANSITION_DURATION) :
next()
$active.removeClass('in')
}
// TAB PLUGIN DEFINITION
// =====================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.tab')
if (!data) $this.data('bs.tab', (data = new Tab(this)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.tab
$.fn.tab = Plugin
$.fn.tab.Constructor = Tab
// TAB NO CONFLICT
// ===============
$.fn.tab.noConflict = function () {
$.fn.tab = old
return this
}
// TAB DATA-API
// ============
var clickHandler = function (e) {
e.preventDefault()
Plugin.call($(this), 'show')
}
$(document)
.on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
.on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
}(jQuery);
/* ========================================================================
* Bootstrap: affix.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#affix
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// AFFIX CLASS DEFINITION
// ======================
var Affix = function (element, options) {
this.options = $.extend({}, Affix.DEFAULTS, options)
var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
this.$target = 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 = null
this.unpin = null
this.pinnedOffset = null
this.checkPosition()
}
Affix.VERSION = '3.4.1'
Affix.RESET = 'affix affix-top affix-bottom'
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()
if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
if (this.affixed == 'bottom') {
if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
}
var initializing = this.affixed == null
var colliderTop = initializing ? scrollTop : position.top
var colliderHeight = initializing ? targetHeight : height
if (offsetTop != null && scrollTop <= offsetTop) return 'top'
if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
return false
}
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)
}
Affix.prototype.checkPositionWithEventLoop = function () {
setTimeout($.proxy(this.checkPosition, this), 1)
}
Affix.prototype.checkPosition = function () {
if (!this.$element.is(':visible')) return
var height = this.$element.height()
var offset = this.options.offset
var offsetTop = offset.top
var offsetBottom = offset.bottom
var scrollHeight = Math.max($(document).height(), $(document.body).height())
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 affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
if (this.affixed != affix) {
if (this.unpin != null) this.$element.css('top', '')
var affixType = 'affix' + (affix ? '-' + affix : '')
var e = $.Event(affixType + '.bs.affix')
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
this.affixed = affix
this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
this.$element
.removeClass(Affix.RESET)
.addClass(affixType)
.trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
}
if (affix == 'bottom') {
this.$element.offset({
top: scrollHeight - height - offsetBottom
})
}
}
// AFFIX PLUGIN DEFINITION
// =======================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.affix')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.affix
$.fn.affix = Plugin
$.fn.affix.Constructor = Affix
// AFFIX NO CONFLICT
// =================
$.fn.affix.noConflict = function () {
$.fn.affix = old
return this
}
// AFFIX DATA-API
// ==============
$(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
Plugin.call($spy, data)
})
})
}(jQuery);
/*
* Breakpoint jQuery Plugin
*
* Copyright (c) 2012
* Licensed under the MIT license.
*
*/
(function($) {
$.breakpoint = {
els: $(),
init: false
};
$.fn.breakpoint = function() {
$.breakpoint.els = $.breakpoint.els.add(this);
if (!$.breakpoint.init) {
$(window).on('resize.breakpoint', function() {
$.breakpoint.els.trigger('swapres.breakpoint');
});
}
return this.each(function() {
var $el = $(this),
maxWidths = [],
minWidths = [];
if ($el.is('img')) {
$el.data('m1src', $el.attr('src'));
} else {
$el.data('m1src', $el.css('background-image'));
}
// parse breakpoints.
$.each($el.data(), function(key, value) {
if (key && (key.toLowerCase().indexOf('maxwidth') === 0 || key.toLowerCase().indexOf('minwidth') === 0)) {
var width = key.substring(3).match(/\d+/g);
if (width.length === 1) {
var bp = {
key: key,
type: (key.toLowerCase().indexOf('max') === 0 ? 'max' : 'min'),
width: width[0]
};
if (bp.type === 'max') {
maxWidths.push(bp);
} else {
minWidths.push(bp)
}
}
}
});
// sort low to high.
minWidths.sort(function(a, b) {
return a.width - b.width;
});
// sort high to low.
maxWidths.sort(function(a, b) {
return b.width - a.width;
});
$el
.on('swapres.breakpoint', function() {
// if breakpoints are defined just use them and ignore the rest.
if (maxWidths.length > 0 || minWidths.length > 0) {
// loop threw each break point and try apply it.
var windowWidth = window.innerWidth ? window.innerWidth : $(window).width();
var activeBreakpoint = null;
$.each(maxWidths, function(index, bp) {
if (windowWidth <= bp.width) {
// console.log('matched breakpoint: ' + bp.key);
activeBreakpoint = bp;
}
});
$.each(minWidths, function(index, bp) {
if (windowWidth >= bp.width) {
// console.log('matched breakpoint: ' + bp.key);
activeBreakpoint = bp;
}
});
// fallback to mobile first if no matches.
if (activeBreakpoint != null) {
// console.log('using breakpoint: ' + activeBreakpoint.key);
if ($el.is('img')) {
$el.attr('src', $el.data(activeBreakpoint.key));
} else {
$el.css("background-image", "url('" + $el.data(activeBreakpoint.key) + "')");
}
} else {
// console.log('using mobile1st');
if ($el.is('img')) {
$el.attr('src', $el.data('m1src'));
} else {
$el.css("background-image", $el.data('m1src'));
}
}
} else {
// console.log('using mobile1st');
if ($el.is('img')) {
$el.attr('src', $el.data('m1src'));
} else {
$el.css("background-image", $el.data('m1src'));
}
}
})
.trigger('swapres.breakpoint');
});
};
})(jQuery);
/*
Breakpoints.js
version 1.0
Creates handy events for your responsive design breakpoints
Copyright 2011 XOXCO, Inc
http://xoxco.com/
Documentation for this plugin lives here:
http://xoxco.com/projects/code/breakpoints
Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php
*/
(function($) {
var lastSize = 0;
var interval = null;
$.fn.resetBreakpoints = function() {
$(window).unbind('resize');
if (interval) {
clearInterval(interval);
}
lastSize = 0;
};
$.fn.setBreakpoints = function(settings) {
var options = jQuery.extend({
distinct: true,
breakpoints: new Array(320,480,768,1024)
},settings);
interval = setInterval(function() {
var w = $(window).width();
var done = false;
for (var bp in options.breakpoints.sort(function(a,b) { return (b-a) })) {
// fire onEnter when a browser expands into a new breakpoint
// if in distinct mode, remove all other breakpoints first.
if (!done && w >= options.breakpoints[bp] && lastSize < options.breakpoints[bp]) {
if (options.distinct) {
for (var x in options.breakpoints.sort(function(a,b) { return (b-a) })) {
if ($('body').hasClass('breakpoint-' + options.breakpoints[x])) {
$('body').removeClass('breakpoint-' + options.breakpoints[x]);
$(window).trigger('exitBreakpoint' + options.breakpoints[x]);
}
}
done = true;
}
$('body').addClass('breakpoint-' + options.breakpoints[bp]);
$(window).trigger('enterBreakpoint' + options.breakpoints[bp]);
}
// fire onExit when browser contracts out of a larger breakpoint
if (w < options.breakpoints[bp] && lastSize >= options.breakpoints[bp]) {
$('body').removeClass('breakpoint-' + options.breakpoints[bp]);
$(window).trigger('exitBreakpoint' + options.breakpoints[bp]);
}
// if in distinct mode, fire onEnter when browser contracts into a smaller breakpoint
if (
options.distinct && // only one breakpoint at a time
w >= options.breakpoints[bp] && // and we are in this one
w < options.breakpoints[bp-1] && // and smaller than the bigger one
lastSize > w && // and we contracted
lastSize >0 && // and this is not the first time
!$('body').hasClass('breakpoint-' + options.breakpoints[bp]) // and we aren't already in this breakpoint
) {
$('body').addClass('breakpoint-' + options.breakpoints[bp]);
$(window).trigger('enterBreakpoint' + options.breakpoints[bp]);
}
}
// set up for next call
if (lastSize != w) {
lastSize = w;
}
},250);
};
})(jQuery);
/*!
* jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2006, 2014 Klaus Hartl
* Released under the MIT license
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD (Register as an anonymous module)
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var pluses = /\+/g;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch(e) {}
}
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return $.isFunction(converter) ? converter(value) : value;
}
var config = $.cookie = function (key, value, options) {
// Write
if (arguments.length > 1 && !$.isFunction(value)) {
options = $.extend({}, config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
}
return (document.cookie = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// Read
var result = key ? undefined : {},
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling $.cookie().
cookies = document.cookie ? document.cookie.split('; ') : [],
i = 0,
l = cookies.length;
for (; i < l; i++) {
var parts = cookies[i].split('='),
name = decode(parts.shift()),
cookie = parts.join('=');
if (key === name) {
// If second argument (value) is a function it's a converter...
result = read(cookie, value);
break;
}
// Prevent storing a cookie that we couldn't decode.
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
return result;
};
config.defaults = {};
$.removeCookie = function (key, options) {
// Must not alter options, thus extending a fresh object...
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
return !$.cookie(key);
};
}));
!function(i){"use strict";"function"==typeof define&&define.amd?define(["jquery"],i):"undefined"!=typeof exports?module.exports=i(require("jquery")):i(jQuery)}(function(i){"use strict";var e=window.Slick||{};(e=function(){var e=0;return function(t,o){var s,n=this;n.defaults={accessibility:!0,adaptiveHeight:!1,appendArrows:i(t),appendDots:i(t),arrows:!0,asNavFor:null,prevArrow:'
Previous ',nextArrow:'
Next ',autoplay:!1,autoplaySpeed:3e3,centerMode:!1,centerPadding:"50px",cssEase:"ease",customPaging:function(e,t){return i('
').text(t+1)},dots:!1,dotsClass:"slick-dots",draggable:!0,easing:"linear",edgeFriction:.35,fade:!1,focusOnSelect:!1,focusOnChange:!1,infinite:!0,initialSlide:0,lazyLoad:"ondemand",mobileFirst:!1,pauseOnHover:!0,pauseOnFocus:!0,pauseOnDotsHover:!1,respondTo:"window",responsive:null,rows:1,rtl:!1,slide:"",slidesPerRow:1,slidesToShow:1,slidesToScroll:1,speed:500,swipe:!0,swipeToSlide:!1,touchMove:!0,touchThreshold:5,useCSS:!0,useTransform:!0,variableWidth:!1,vertical:!1,verticalSwiping:!1,waitForAnimate:!0,zIndex:1e3},n.initials={animating:!1,dragging:!1,autoPlayTimer:null,currentDirection:0,currentLeft:null,currentSlide:0,direction:1,$dots:null,listWidth:null,listHeight:null,loadIndex:0,$nextArrow:null,$prevArrow:null,scrolling:!1,slideCount:null,slideWidth:null,$slideTrack:null,$slides:null,sliding:!1,slideOffset:0,swipeLeft:null,swiping:!1,$list:null,touchObject:{},transformsEnabled:!1,unslicked:!1},i.extend(n,n.initials),n.activeBreakpoint=null,n.animType=null,n.animProp=null,n.breakpoints=[],n.breakpointSettings=[],n.cssTransitions=!1,n.focussed=!1,n.interrupted=!1,n.hidden="hidden",n.paused=!0,n.positionProp=null,n.respondTo=null,n.rowCount=1,n.shouldClick=!0,n.$slider=i(t),n.$slidesCache=null,n.transformType=null,n.transitionType=null,n.visibilityChange="visibilitychange",n.windowWidth=0,n.windowTimer=null,s=i(t).data("slick")||{},n.options=i.extend({},n.defaults,o,s),n.currentSlide=n.options.initialSlide,n.originalSettings=n.options,void 0!==document.mozHidden?(n.hidden="mozHidden",n.visibilityChange="mozvisibilitychange"):void 0!==document.webkitHidden&&(n.hidden="webkitHidden",n.visibilityChange="webkitvisibilitychange"),n.autoPlay=i.proxy(n.autoPlay,n),n.autoPlayClear=i.proxy(n.autoPlayClear,n),n.autoPlayIterator=i.proxy(n.autoPlayIterator,n),n.changeSlide=i.proxy(n.changeSlide,n),n.clickHandler=i.proxy(n.clickHandler,n),n.selectHandler=i.proxy(n.selectHandler,n),n.setPosition=i.proxy(n.setPosition,n),n.swipeHandler=i.proxy(n.swipeHandler,n),n.dragHandler=i.proxy(n.dragHandler,n),n.keyHandler=i.proxy(n.keyHandler,n),n.instanceUid=e++,n.htmlExpr=/^(?:\s*(<[\w\W]+>)[^>]*)$/,n.registerBreakpoints(),n.init(!0)}}()).prototype.activateADA=function(){this.$slideTrack.find(".slick-active").attr({"aria-hidden":"false"}).find("a, input, button, select").attr({tabindex:"0"})},e.prototype.addSlide=e.prototype.slickAdd=function(e,t,o){var s=this;if("boolean"==typeof t)o=t,t=null;else if(t<0||t>=s.slideCount)return!1;s.unload(),"number"==typeof t?0===t&&0===s.$slides.length?i(e).appendTo(s.$slideTrack):o?i(e).insertBefore(s.$slides.eq(t)):i(e).insertAfter(s.$slides.eq(t)):!0===o?i(e).prependTo(s.$slideTrack):i(e).appendTo(s.$slideTrack),s.$slides=s.$slideTrack.children(this.options.slide),s.$slideTrack.children(this.options.slide).detach(),s.$slideTrack.append(s.$slides),s.$slides.each(function(e,t){i(t).attr("data-slick-index",e)}),s.$slidesCache=s.$slides,s.reinit()},e.prototype.animateHeight=function(){var i=this;if(1===i.options.slidesToShow&&!0===i.options.adaptiveHeight&&!1===i.options.vertical){var e=i.$slides.eq(i.currentSlide).outerHeight(!0);i.$list.animate({height:e},i.options.speed)}},e.prototype.animateSlide=function(e,t){var o={},s=this;s.animateHeight(),!0===s.options.rtl&&!1===s.options.vertical&&(e=-e),!1===s.transformsEnabled?!1===s.options.vertical?s.$slideTrack.animate({left:e},s.options.speed,s.options.easing,t):s.$slideTrack.animate({top:e},s.options.speed,s.options.easing,t):!1===s.cssTransitions?(!0===s.options.rtl&&(s.currentLeft=-s.currentLeft),i({animStart:s.currentLeft}).animate({animStart:e},{duration:s.options.speed,easing:s.options.easing,step:function(i){i=Math.ceil(i),!1===s.options.vertical?(o[s.animType]="translate("+i+"px, 0px)",s.$slideTrack.css(o)):(o[s.animType]="translate(0px,"+i+"px)",s.$slideTrack.css(o))},complete:function(){t&&t.call()}})):(s.applyTransition(),e=Math.ceil(e),!1===s.options.vertical?o[s.animType]="translate3d("+e+"px, 0px, 0px)":o[s.animType]="translate3d(0px,"+e+"px, 0px)",s.$slideTrack.css(o),t&&setTimeout(function(){s.disableTransition(),t.call()},s.options.speed))},e.prototype.getNavTarget=function(){var e=this,t=e.options.asNavFor;return t&&null!==t&&(t=i(t).not(e.$slider)),t},e.prototype.asNavFor=function(e){var t=this.getNavTarget();null!==t&&"object"==typeof t&&t.each(function(){var t=i(this).slick("getSlick");t.unslicked||t.slideHandler(e,!0)})},e.prototype.applyTransition=function(i){var e=this,t={};!1===e.options.fade?t[e.transitionType]=e.transformType+" "+e.options.speed+"ms "+e.options.cssEase:t[e.transitionType]="opacity "+e.options.speed+"ms "+e.options.cssEase,!1===e.options.fade?e.$slideTrack.css(t):e.$slides.eq(i).css(t)},e.prototype.autoPlay=function(){var i=this;i.autoPlayClear(),i.slideCount>i.options.slidesToShow&&(i.autoPlayTimer=setInterval(i.autoPlayIterator,i.options.autoplaySpeed))},e.prototype.autoPlayClear=function(){var i=this;i.autoPlayTimer&&clearInterval(i.autoPlayTimer)},e.prototype.autoPlayIterator=function(){var i=this,e=i.currentSlide+i.options.slidesToScroll;i.paused||i.interrupted||i.focussed||(!1===i.options.infinite&&(1===i.direction&&i.currentSlide+1===i.slideCount-1?i.direction=0:0===i.direction&&(e=i.currentSlide-i.options.slidesToScroll,i.currentSlide-1==0&&(i.direction=1))),i.slideHandler(e))},e.prototype.buildArrows=function(){var e=this;!0===e.options.arrows&&(e.$prevArrow=i(e.options.prevArrow).addClass("slick-arrow"),e.$nextArrow=i(e.options.nextArrow).addClass("slick-arrow"),e.slideCount>e.options.slidesToShow?(e.$prevArrow.removeClass("slick-hidden").removeAttr("aria-hidden tabindex"),e.$nextArrow.removeClass("slick-hidden").removeAttr("aria-hidden tabindex"),e.htmlExpr.test(e.options.prevArrow)&&e.$prevArrow.prependTo(e.options.appendArrows),e.htmlExpr.test(e.options.nextArrow)&&e.$nextArrow.appendTo(e.options.appendArrows),!0!==e.options.infinite&&e.$prevArrow.addClass("slick-disabled").attr("aria-disabled","true")):e.$prevArrow.add(e.$nextArrow).addClass("slick-hidden").attr({"aria-disabled":"true",tabindex:"-1"}))},e.prototype.buildDots=function(){var e,t,o=this;if(!0===o.options.dots){for(o.$slider.addClass("slick-dotted"),t=i("
").addClass(o.options.dotsClass),e=0;e<=o.getDotCount();e+=1)t.append(i("
").append(o.options.customPaging.call(this,o,e)));o.$dots=t.appendTo(o.options.appendDots),o.$dots.find("li").first().addClass("slick-active")}},e.prototype.buildOut=function(){var e=this;e.$slides=e.$slider.children(e.options.slide+":not(.slick-cloned)").addClass("slick-slide"),e.slideCount=e.$slides.length,e.$slides.each(function(e,t){i(t).attr("data-slick-index",e).data("originalStyling",i(t).attr("style")||"")}),e.$slider.addClass("slick-slider"),e.$slideTrack=0===e.slideCount?i('
').appendTo(e.$slider):e.$slides.wrapAll('
').parent(),e.$list=e.$slideTrack.wrap('
').parent(),e.$slideTrack.css("opacity",0),!0!==e.options.centerMode&&!0!==e.options.swipeToSlide||(e.options.slidesToScroll=1),i("img[data-lazy]",e.$slider).not("[src]").addClass("slick-loading"),e.setupInfinite(),e.buildArrows(),e.buildDots(),e.updateDots(),e.setSlideClasses("number"==typeof e.currentSlide?e.currentSlide:0),!0===e.options.draggable&&e.$list.addClass("draggable")},e.prototype.buildRows=function(){var i,e,t,o,s,n,r,l=this;if(o=document.createDocumentFragment(),n=l.$slider.children(),l.options.rows>1){for(r=l.options.slidesPerRow*l.options.rows,s=Math.ceil(n.length/r),i=0;i
r.breakpoints[o]&&(s=r.breakpoints[o]));null!==s?null!==r.activeBreakpoint?(s!==r.activeBreakpoint||t)&&(r.activeBreakpoint=s,"unslick"===r.breakpointSettings[s]?r.unslick(s):(r.options=i.extend({},r.originalSettings,r.breakpointSettings[s]),!0===e&&(r.currentSlide=r.options.initialSlide),r.refresh(e)),l=s):(r.activeBreakpoint=s,"unslick"===r.breakpointSettings[s]?r.unslick(s):(r.options=i.extend({},r.originalSettings,r.breakpointSettings[s]),!0===e&&(r.currentSlide=r.options.initialSlide),r.refresh(e)),l=s):null!==r.activeBreakpoint&&(r.activeBreakpoint=null,r.options=r.originalSettings,!0===e&&(r.currentSlide=r.options.initialSlide),r.refresh(e),l=s),e||!1===l||r.$slider.trigger("breakpoint",[r,l])}},e.prototype.changeSlide=function(e,t){var o,s,n,r=this,l=i(e.currentTarget);switch(l.is("a")&&e.preventDefault(),l.is("li")||(l=l.closest("li")),n=r.slideCount%r.options.slidesToScroll!=0,o=n?0:(r.slideCount-r.currentSlide)%r.options.slidesToScroll,e.data.message){case"previous":s=0===o?r.options.slidesToScroll:r.options.slidesToShow-o,r.slideCount>r.options.slidesToShow&&r.slideHandler(r.currentSlide-s,!1,t);break;case"next":s=0===o?r.options.slidesToScroll:o,r.slideCount>r.options.slidesToShow&&r.slideHandler(r.currentSlide+s,!1,t);break;case"index":var d=0===e.data.index?0:e.data.index||l.index()*r.options.slidesToScroll;r.slideHandler(r.checkNavigable(d),!1,t),l.children().trigger("focus");break;default:return}},e.prototype.checkNavigable=function(i){var e,t;if(e=this.getNavigableIndexes(),t=0,i>e[e.length-1])i=e[e.length-1];else for(var o in e){if(ie.options.slidesToShow&&(e.$prevArrow&&e.$prevArrow.off("click.slick",e.changeSlide),e.$nextArrow&&e.$nextArrow.off("click.slick",e.changeSlide),!0===e.options.accessibility&&(e.$prevArrow&&e.$prevArrow.off("keydown.slick",e.keyHandler),e.$nextArrow&&e.$nextArrow.off("keydown.slick",e.keyHandler))),e.$list.off("touchstart.slick mousedown.slick",e.swipeHandler),e.$list.off("touchmove.slick mousemove.slick",e.swipeHandler),e.$list.off("touchend.slick mouseup.slick",e.swipeHandler),e.$list.off("touchcancel.slick mouseleave.slick",e.swipeHandler),e.$list.off("click.slick",e.clickHandler),i(document).off(e.visibilityChange,e.visibility),e.cleanUpSlideEvents(),!0===e.options.accessibility&&e.$list.off("keydown.slick",e.keyHandler),!0===e.options.focusOnSelect&&i(e.$slideTrack).children().off("click.slick",e.selectHandler),i(window).off("orientationchange.slick.slick-"+e.instanceUid,e.orientationChange),i(window).off("resize.slick.slick-"+e.instanceUid,e.resize),i("[draggable!=true]",e.$slideTrack).off("dragstart",e.preventDefault),i(window).off("load.slick.slick-"+e.instanceUid,e.setPosition)},e.prototype.cleanUpSlideEvents=function(){var e=this;e.$list.off("mouseenter.slick",i.proxy(e.interrupt,e,!0)),e.$list.off("mouseleave.slick",i.proxy(e.interrupt,e,!1))},e.prototype.cleanUpRows=function(){var i,e=this;e.options.rows>1&&((i=e.$slides.children().children()).removeAttr("style"),e.$slider.empty().append(i))},e.prototype.clickHandler=function(i){!1===this.shouldClick&&(i.stopImmediatePropagation(),i.stopPropagation(),i.preventDefault())},e.prototype.destroy=function(e){var t=this;t.autoPlayClear(),t.touchObject={},t.cleanUpEvents(),i(".slick-cloned",t.$slider).detach(),t.$dots&&t.$dots.remove(),t.$prevArrow&&t.$prevArrow.length&&(t.$prevArrow.removeClass("slick-disabled slick-arrow slick-hidden").removeAttr("aria-hidden aria-disabled tabindex").css("display",""),t.htmlExpr.test(t.options.prevArrow)&&t.$prevArrow.remove()),t.$nextArrow&&t.$nextArrow.length&&(t.$nextArrow.removeClass("slick-disabled slick-arrow slick-hidden").removeAttr("aria-hidden aria-disabled tabindex").css("display",""),t.htmlExpr.test(t.options.nextArrow)&&t.$nextArrow.remove()),t.$slides&&(t.$slides.removeClass("slick-slide slick-active slick-center slick-visible slick-current").removeAttr("aria-hidden").removeAttr("data-slick-index").each(function(){i(this).attr("style",i(this).data("originalStyling"))}),t.$slideTrack.children(this.options.slide).detach(),t.$slideTrack.detach(),t.$list.detach(),t.$slider.append(t.$slides)),t.cleanUpRows(),t.$slider.removeClass("slick-slider"),t.$slider.removeClass("slick-initialized"),t.$slider.removeClass("slick-dotted"),t.unslicked=!0,e||t.$slider.trigger("destroy",[t])},e.prototype.disableTransition=function(i){var e=this,t={};t[e.transitionType]="",!1===e.options.fade?e.$slideTrack.css(t):e.$slides.eq(i).css(t)},e.prototype.fadeSlide=function(i,e){var t=this;!1===t.cssTransitions?(t.$slides.eq(i).css({zIndex:t.options.zIndex}),t.$slides.eq(i).animate({opacity:1},t.options.speed,t.options.easing,e)):(t.applyTransition(i),t.$slides.eq(i).css({opacity:1,zIndex:t.options.zIndex}),e&&setTimeout(function(){t.disableTransition(i),e.call()},t.options.speed))},e.prototype.fadeSlideOut=function(i){var e=this;!1===e.cssTransitions?e.$slides.eq(i).animate({opacity:0,zIndex:e.options.zIndex-2},e.options.speed,e.options.easing):(e.applyTransition(i),e.$slides.eq(i).css({opacity:0,zIndex:e.options.zIndex-2}))},e.prototype.filterSlides=e.prototype.slickFilter=function(i){var e=this;null!==i&&(e.$slidesCache=e.$slides,e.unload(),e.$slideTrack.children(this.options.slide).detach(),e.$slidesCache.filter(i).appendTo(e.$slideTrack),e.reinit())},e.prototype.focusHandler=function(){var e=this;e.$slider.off("focus.slick blur.slick").on("focus.slick blur.slick","*",function(t){t.stopImmediatePropagation();var o=i(this);setTimeout(function(){e.options.pauseOnFocus&&(e.focussed=o.is(":focus"),e.autoPlay())},0)})},e.prototype.getCurrent=e.prototype.slickCurrentSlide=function(){return this.currentSlide},e.prototype.getDotCount=function(){var i=this,e=0,t=0,o=0;if(!0===i.options.infinite)if(i.slideCount<=i.options.slidesToShow)++o;else for(;en.options.slidesToShow&&(n.slideOffset=n.slideWidth*n.options.slidesToShow*-1,s=-1,!0===n.options.vertical&&!0===n.options.centerMode&&(2===n.options.slidesToShow?s=-1.5:1===n.options.slidesToShow&&(s=-2)),r=t*n.options.slidesToShow*s),n.slideCount%n.options.slidesToScroll!=0&&i+n.options.slidesToScroll>n.slideCount&&n.slideCount>n.options.slidesToShow&&(i>n.slideCount?(n.slideOffset=(n.options.slidesToShow-(i-n.slideCount))*n.slideWidth*-1,r=(n.options.slidesToShow-(i-n.slideCount))*t*-1):(n.slideOffset=n.slideCount%n.options.slidesToScroll*n.slideWidth*-1,r=n.slideCount%n.options.slidesToScroll*t*-1))):i+n.options.slidesToShow>n.slideCount&&(n.slideOffset=(i+n.options.slidesToShow-n.slideCount)*n.slideWidth,r=(i+n.options.slidesToShow-n.slideCount)*t),n.slideCount<=n.options.slidesToShow&&(n.slideOffset=0,r=0),!0===n.options.centerMode&&n.slideCount<=n.options.slidesToShow?n.slideOffset=n.slideWidth*Math.floor(n.options.slidesToShow)/2-n.slideWidth*n.slideCount/2:!0===n.options.centerMode&&!0===n.options.infinite?n.slideOffset+=n.slideWidth*Math.floor(n.options.slidesToShow/2)-n.slideWidth:!0===n.options.centerMode&&(n.slideOffset=0,n.slideOffset+=n.slideWidth*Math.floor(n.options.slidesToShow/2)),e=!1===n.options.vertical?i*n.slideWidth*-1+n.slideOffset:i*t*-1+r,!0===n.options.variableWidth&&(o=n.slideCount<=n.options.slidesToShow||!1===n.options.infinite?n.$slideTrack.children(".slick-slide").eq(i):n.$slideTrack.children(".slick-slide").eq(i+n.options.slidesToShow),e=!0===n.options.rtl?o[0]?-1*(n.$slideTrack.width()-o[0].offsetLeft-o.width()):0:o[0]?-1*o[0].offsetLeft:0,!0===n.options.centerMode&&(o=n.slideCount<=n.options.slidesToShow||!1===n.options.infinite?n.$slideTrack.children(".slick-slide").eq(i):n.$slideTrack.children(".slick-slide").eq(i+n.options.slidesToShow+1),e=!0===n.options.rtl?o[0]?-1*(n.$slideTrack.width()-o[0].offsetLeft-o.width()):0:o[0]?-1*o[0].offsetLeft:0,e+=(n.$list.width()-o.outerWidth())/2)),e},e.prototype.getOption=e.prototype.slickGetOption=function(i){return this.options[i]},e.prototype.getNavigableIndexes=function(){var i,e=this,t=0,o=0,s=[];for(!1===e.options.infinite?i=e.slideCount:(t=-1*e.options.slidesToScroll,o=-1*e.options.slidesToScroll,i=2*e.slideCount);t-1*o.swipeLeft)return e=n,!1}),Math.abs(i(e).attr("data-slick-index")-o.currentSlide)||1):o.options.slidesToScroll},e.prototype.goTo=e.prototype.slickGoTo=function(i,e){this.changeSlide({data:{message:"index",index:parseInt(i)}},e)},e.prototype.init=function(e){var t=this;i(t.$slider).hasClass("slick-initialized")||(i(t.$slider).addClass("slick-initialized"),t.buildRows(),t.buildOut(),t.setProps(),t.startLoad(),t.loadSlider(),t.initializeEvents(),t.updateArrows(),t.updateDots(),t.checkResponsive(!0),t.focusHandler()),e&&t.$slider.trigger("init",[t]),!0===t.options.accessibility&&t.initADA(),t.options.autoplay&&(t.paused=!1,t.autoPlay())},e.prototype.initADA=function(){var e=this,t=Math.ceil(e.slideCount/e.options.slidesToShow),o=e.getNavigableIndexes().filter(function(i){return i>=0&&ii.options.slidesToShow&&(i.$prevArrow.off("click.slick").on("click.slick",{message:"previous"},i.changeSlide),i.$nextArrow.off("click.slick").on("click.slick",{message:"next"},i.changeSlide),!0===i.options.accessibility&&(i.$prevArrow.on("keydown.slick",i.keyHandler),i.$nextArrow.on("keydown.slick",i.keyHandler)))},e.prototype.initDotEvents=function(){var e=this;!0===e.options.dots&&(i("li",e.$dots).on("click.slick",{message:"index"},e.changeSlide),!0===e.options.accessibility&&e.$dots.on("keydown.slick",e.keyHandler)),!0===e.options.dots&&!0===e.options.pauseOnDotsHover&&i("li",e.$dots).on("mouseenter.slick",i.proxy(e.interrupt,e,!0)).on("mouseleave.slick",i.proxy(e.interrupt,e,!1))},e.prototype.initSlideEvents=function(){var e=this;e.options.pauseOnHover&&(e.$list.on("mouseenter.slick",i.proxy(e.interrupt,e,!0)),e.$list.on("mouseleave.slick",i.proxy(e.interrupt,e,!1)))},e.prototype.initializeEvents=function(){var e=this;e.initArrowEvents(),e.initDotEvents(),e.initSlideEvents(),e.$list.on("touchstart.slick mousedown.slick",{action:"start"},e.swipeHandler),e.$list.on("touchmove.slick mousemove.slick",{action:"move"},e.swipeHandler),e.$list.on("touchend.slick mouseup.slick",{action:"end"},e.swipeHandler),e.$list.on("touchcancel.slick mouseleave.slick",{action:"end"},e.swipeHandler),e.$list.on("click.slick",e.clickHandler),i(document).on(e.visibilityChange,i.proxy(e.visibility,e)),!0===e.options.accessibility&&e.$list.on("keydown.slick",e.keyHandler),!0===e.options.focusOnSelect&&i(e.$slideTrack).children().on("click.slick",e.selectHandler),i(window).on("orientationchange.slick.slick-"+e.instanceUid,i.proxy(e.orientationChange,e)),i(window).on("resize.slick.slick-"+e.instanceUid,i.proxy(e.resize,e)),i("[draggable!=true]",e.$slideTrack).on("dragstart",e.preventDefault),i(window).on("load.slick.slick-"+e.instanceUid,e.setPosition),i(e.setPosition)},e.prototype.initUI=function(){var i=this;!0===i.options.arrows&&i.slideCount>i.options.slidesToShow&&(i.$prevArrow.show(),i.$nextArrow.show()),!0===i.options.dots&&i.slideCount>i.options.slidesToShow&&i.$dots.show()},e.prototype.keyHandler=function(i){var e=this;i.target.tagName.match("TEXTAREA|INPUT|SELECT")||(37===i.keyCode&&!0===e.options.accessibility?e.changeSlide({data:{message:!0===e.options.rtl?"next":"previous"}}):39===i.keyCode&&!0===e.options.accessibility&&e.changeSlide({data:{message:!0===e.options.rtl?"previous":"next"}}))},e.prototype.lazyLoad=function(){function e(e){i("img[data-lazy]",e).each(function(){var e=i(this),t=i(this).attr("data-lazy"),o=i(this).attr("data-srcset"),s=i(this).attr("data-sizes")||n.$slider.attr("data-sizes"),r=document.createElement("img");r.onload=function(){e.animate({opacity:0},100,function(){o&&(e.attr("srcset",o),s&&e.attr("sizes",s)),e.attr("src",t).animate({opacity:1},200,function(){e.removeAttr("data-lazy data-srcset data-sizes").removeClass("slick-loading")}),n.$slider.trigger("lazyLoaded",[n,e,t])})},r.onerror=function(){e.removeAttr("data-lazy").removeClass("slick-loading").addClass("slick-lazyload-error"),n.$slider.trigger("lazyLoadError",[n,e,t])},r.src=t})}var t,o,s,n=this;if(!0===n.options.centerMode?!0===n.options.infinite?s=(o=n.currentSlide+(n.options.slidesToShow/2+1))+n.options.slidesToShow+2:(o=Math.max(0,n.currentSlide-(n.options.slidesToShow/2+1)),s=n.options.slidesToShow/2+1+2+n.currentSlide):(o=n.options.infinite?n.options.slidesToShow+n.currentSlide:n.currentSlide,s=Math.ceil(o+n.options.slidesToShow),!0===n.options.fade&&(o>0&&o--,s<=n.slideCount&&s++)),t=n.$slider.find(".slick-slide").slice(o,s),"anticipated"===n.options.lazyLoad)for(var r=o-1,l=s,d=n.$slider.find(".slick-slide"),a=0;a=n.slideCount-n.options.slidesToShow?e(n.$slider.find(".slick-cloned").slice(0,n.options.slidesToShow)):0===n.currentSlide&&e(n.$slider.find(".slick-cloned").slice(-1*n.options.slidesToShow))},e.prototype.loadSlider=function(){var i=this;i.setPosition(),i.$slideTrack.css({opacity:1}),i.$slider.removeClass("slick-loading"),i.initUI(),"progressive"===i.options.lazyLoad&&i.progressiveLazyLoad()},e.prototype.next=e.prototype.slickNext=function(){this.changeSlide({data:{message:"next"}})},e.prototype.orientationChange=function(){var i=this;i.checkResponsive(),i.setPosition()},e.prototype.pause=e.prototype.slickPause=function(){var i=this;i.autoPlayClear(),i.paused=!0},e.prototype.play=e.prototype.slickPlay=function(){var i=this;i.autoPlay(),i.options.autoplay=!0,i.paused=!1,i.focussed=!1,i.interrupted=!1},e.prototype.postSlide=function(e){var t=this;t.unslicked||(t.$slider.trigger("afterChange",[t,e]),t.animating=!1,t.slideCount>t.options.slidesToShow&&t.setPosition(),t.swipeLeft=null,t.options.autoplay&&t.autoPlay(),!0===t.options.accessibility&&(t.initADA(),t.options.focusOnChange&&i(t.$slides.get(t.currentSlide)).attr("tabindex",0).focus()))},e.prototype.prev=e.prototype.slickPrev=function(){this.changeSlide({data:{message:"previous"}})},e.prototype.preventDefault=function(i){i.preventDefault()},e.prototype.progressiveLazyLoad=function(e){e=e||1;var t,o,s,n,r,l=this,d=i("img[data-lazy]",l.$slider);d.length?(t=d.first(),o=t.attr("data-lazy"),s=t.attr("data-srcset"),n=t.attr("data-sizes")||l.$slider.attr("data-sizes"),(r=document.createElement("img")).onload=function(){s&&(t.attr("srcset",s),n&&t.attr("sizes",n)),t.attr("src",o).removeAttr("data-lazy data-srcset data-sizes").removeClass("slick-loading"),!0===l.options.adaptiveHeight&&l.setPosition(),l.$slider.trigger("lazyLoaded",[l,t,o]),l.progressiveLazyLoad()},r.onerror=function(){e<3?setTimeout(function(){l.progressiveLazyLoad(e+1)},500):(t.removeAttr("data-lazy").removeClass("slick-loading").addClass("slick-lazyload-error"),l.$slider.trigger("lazyLoadError",[l,t,o]),l.progressiveLazyLoad())},r.src=o):l.$slider.trigger("allImagesLoaded",[l])},e.prototype.refresh=function(e){var t,o,s=this;o=s.slideCount-s.options.slidesToShow,!s.options.infinite&&s.currentSlide>o&&(s.currentSlide=o),s.slideCount<=s.options.slidesToShow&&(s.currentSlide=0),t=s.currentSlide,s.destroy(!0),i.extend(s,s.initials,{currentSlide:t}),s.init(),e||s.changeSlide({data:{message:"index",index:t}},!1)},e.prototype.registerBreakpoints=function(){var e,t,o,s=this,n=s.options.responsive||null;if("array"===i.type(n)&&n.length){s.respondTo=s.options.respondTo||"window";for(e in n)if(o=s.breakpoints.length-1,n.hasOwnProperty(e)){for(t=n[e].breakpoint;o>=0;)s.breakpoints[o]&&s.breakpoints[o]===t&&s.breakpoints.splice(o,1),o--;s.breakpoints.push(t),s.breakpointSettings[t]=n[e].settings}s.breakpoints.sort(function(i,e){return s.options.mobileFirst?i-e:e-i})}},e.prototype.reinit=function(){var e=this;e.$slides=e.$slideTrack.children(e.options.slide).addClass("slick-slide"),e.slideCount=e.$slides.length,e.currentSlide>=e.slideCount&&0!==e.currentSlide&&(e.currentSlide=e.currentSlide-e.options.slidesToScroll),e.slideCount<=e.options.slidesToShow&&(e.currentSlide=0),e.registerBreakpoints(),e.setProps(),e.setupInfinite(),e.buildArrows(),e.updateArrows(),e.initArrowEvents(),e.buildDots(),e.updateDots(),e.initDotEvents(),e.cleanUpSlideEvents(),e.initSlideEvents(),e.checkResponsive(!1,!0),!0===e.options.focusOnSelect&&i(e.$slideTrack).children().on("click.slick",e.selectHandler),e.setSlideClasses("number"==typeof e.currentSlide?e.currentSlide:0),e.setPosition(),e.focusHandler(),e.paused=!e.options.autoplay,e.autoPlay(),e.$slider.trigger("reInit",[e])},e.prototype.resize=function(){var e=this;i(window).width()!==e.windowWidth&&(clearTimeout(e.windowDelay),e.windowDelay=window.setTimeout(function(){e.windowWidth=i(window).width(),e.checkResponsive(),e.unslicked||e.setPosition()},50))},e.prototype.removeSlide=e.prototype.slickRemove=function(i,e,t){var o=this;if(i="boolean"==typeof i?!0===(e=i)?0:o.slideCount-1:!0===e?--i:i,o.slideCount<1||i<0||i>o.slideCount-1)return!1;o.unload(),!0===t?o.$slideTrack.children().remove():o.$slideTrack.children(this.options.slide).eq(i).remove(),o.$slides=o.$slideTrack.children(this.options.slide),o.$slideTrack.children(this.options.slide).detach(),o.$slideTrack.append(o.$slides),o.$slidesCache=o.$slides,o.reinit()},e.prototype.setCSS=function(i){var e,t,o=this,s={};!0===o.options.rtl&&(i=-i),e="left"==o.positionProp?Math.ceil(i)+"px":"0px",t="top"==o.positionProp?Math.ceil(i)+"px":"0px",s[o.positionProp]=i,!1===o.transformsEnabled?o.$slideTrack.css(s):(s={},!1===o.cssTransitions?(s[o.animType]="translate("+e+", "+t+")",o.$slideTrack.css(s)):(s[o.animType]="translate3d("+e+", "+t+", 0px)",o.$slideTrack.css(s)))},e.prototype.setDimensions=function(){var i=this;!1===i.options.vertical?!0===i.options.centerMode&&i.$list.css({padding:"0px "+i.options.centerPadding}):(i.$list.height(i.$slides.first().outerHeight(!0)*i.options.slidesToShow),!0===i.options.centerMode&&i.$list.css({padding:i.options.centerPadding+" 0px"})),i.listWidth=i.$list.width(),i.listHeight=i.$list.height(),!1===i.options.vertical&&!1===i.options.variableWidth?(i.slideWidth=Math.ceil(i.listWidth/i.options.slidesToShow),i.$slideTrack.width(Math.ceil(i.slideWidth*i.$slideTrack.children(".slick-slide").length))):!0===i.options.variableWidth?i.$slideTrack.width(5e3*i.slideCount):(i.slideWidth=Math.ceil(i.listWidth),i.$slideTrack.height(Math.ceil(i.$slides.first().outerHeight(!0)*i.$slideTrack.children(".slick-slide").length)));var e=i.$slides.first().outerWidth(!0)-i.$slides.first().width();!1===i.options.variableWidth&&i.$slideTrack.children(".slick-slide").width(i.slideWidth-e)},e.prototype.setFade=function(){var e,t=this;t.$slides.each(function(o,s){e=t.slideWidth*o*-1,!0===t.options.rtl?i(s).css({position:"relative",right:e,top:0,zIndex:t.options.zIndex-2,opacity:0}):i(s).css({position:"relative",left:e,top:0,zIndex:t.options.zIndex-2,opacity:0})}),t.$slides.eq(t.currentSlide).css({zIndex:t.options.zIndex-1,opacity:1})},e.prototype.setHeight=function(){var i=this;if(1===i.options.slidesToShow&&!0===i.options.adaptiveHeight&&!1===i.options.vertical){var e=i.$slides.eq(i.currentSlide).outerHeight(!0);i.$list.css("height",e)}},e.prototype.setOption=e.prototype.slickSetOption=function(){var e,t,o,s,n,r=this,l=!1;if("object"===i.type(arguments[0])?(o=arguments[0],l=arguments[1],n="multiple"):"string"===i.type(arguments[0])&&(o=arguments[0],s=arguments[1],l=arguments[2],"responsive"===arguments[0]&&"array"===i.type(arguments[1])?n="responsive":void 0!==arguments[1]&&(n="single")),"single"===n)r.options[o]=s;else if("multiple"===n)i.each(o,function(i,e){r.options[i]=e});else if("responsive"===n)for(t in s)if("array"!==i.type(r.options.responsive))r.options.responsive=[s[t]];else{for(e=r.options.responsive.length-1;e>=0;)r.options.responsive[e].breakpoint===s[t].breakpoint&&r.options.responsive.splice(e,1),e--;r.options.responsive.push(s[t])}l&&(r.unload(),r.reinit())},e.prototype.setPosition=function(){var i=this;i.setDimensions(),i.setHeight(),!1===i.options.fade?i.setCSS(i.getLeft(i.currentSlide)):i.setFade(),i.$slider.trigger("setPosition",[i])},e.prototype.setProps=function(){var i=this,e=document.body.style;i.positionProp=!0===i.options.vertical?"top":"left","top"===i.positionProp?i.$slider.addClass("slick-vertical"):i.$slider.removeClass("slick-vertical"),void 0===e.WebkitTransition&&void 0===e.MozTransition&&void 0===e.msTransition||!0===i.options.useCSS&&(i.cssTransitions=!0),i.options.fade&&("number"==typeof i.options.zIndex?i.options.zIndex<3&&(i.options.zIndex=3):i.options.zIndex=i.defaults.zIndex),void 0!==e.OTransform&&(i.animType="OTransform",i.transformType="-o-transform",i.transitionType="OTransition",void 0===e.perspectiveProperty&&void 0===e.webkitPerspective&&(i.animType=!1)),void 0!==e.MozTransform&&(i.animType="MozTransform",i.transformType="-moz-transform",i.transitionType="MozTransition",void 0===e.perspectiveProperty&&void 0===e.MozPerspective&&(i.animType=!1)),void 0!==e.webkitTransform&&(i.animType="webkitTransform",i.transformType="-webkit-transform",i.transitionType="webkitTransition",void 0===e.perspectiveProperty&&void 0===e.webkitPerspective&&(i.animType=!1)),void 0!==e.msTransform&&(i.animType="msTransform",i.transformType="-ms-transform",i.transitionType="msTransition",void 0===e.msTransform&&(i.animType=!1)),void 0!==e.transform&&!1!==i.animType&&(i.animType="transform",i.transformType="transform",i.transitionType="transition"),i.transformsEnabled=i.options.useTransform&&null!==i.animType&&!1!==i.animType},e.prototype.setSlideClasses=function(i){var e,t,o,s,n=this;if(t=n.$slider.find(".slick-slide").removeClass("slick-active slick-center slick-current").attr("aria-hidden","true"),n.$slides.eq(i).addClass("slick-current"),!0===n.options.centerMode){var r=n.options.slidesToShow%2==0?1:0;e=Math.floor(n.options.slidesToShow/2),!0===n.options.infinite&&(i>=e&&i<=n.slideCount-1-e?n.$slides.slice(i-e+r,i+e+1).addClass("slick-active").attr("aria-hidden","false"):(o=n.options.slidesToShow+i,t.slice(o-e+1+r,o+e+2).addClass("slick-active").attr("aria-hidden","false")),0===i?t.eq(t.length-1-n.options.slidesToShow).addClass("slick-center"):i===n.slideCount-1&&t.eq(n.options.slidesToShow).addClass("slick-center")),n.$slides.eq(i).addClass("slick-center")}else i>=0&&i<=n.slideCount-n.options.slidesToShow?n.$slides.slice(i,i+n.options.slidesToShow).addClass("slick-active").attr("aria-hidden","false"):t.length<=n.options.slidesToShow?t.addClass("slick-active").attr("aria-hidden","false"):(s=n.slideCount%n.options.slidesToShow,o=!0===n.options.infinite?n.options.slidesToShow+i:i,n.options.slidesToShow==n.options.slidesToScroll&&n.slideCount-is.options.slidesToShow)){for(o=!0===s.options.centerMode?s.options.slidesToShow+1:s.options.slidesToShow,e=s.slideCount;e>s.slideCount-o;e-=1)t=e-1,i(s.$slides[t]).clone(!0).attr("id","").attr("data-slick-index",t-s.slideCount).prependTo(s.$slideTrack).addClass("slick-cloned");for(e=0;ea.getDotCount()*a.options.slidesToScroll))!1===a.options.fade&&(o=a.currentSlide,!0!==t?a.animateSlide(r,function(){a.postSlide(o)}):a.postSlide(o));else if(!1===a.options.infinite&&!0===a.options.centerMode&&(i<0||i>a.slideCount-a.options.slidesToScroll))!1===a.options.fade&&(o=a.currentSlide,!0!==t?a.animateSlide(r,function(){a.postSlide(o)}):a.postSlide(o));else{if(a.options.autoplay&&clearInterval(a.autoPlayTimer),s=o<0?a.slideCount%a.options.slidesToScroll!=0?a.slideCount-a.slideCount%a.options.slidesToScroll:a.slideCount+o:o>=a.slideCount?a.slideCount%a.options.slidesToScroll!=0?0:o-a.slideCount:o,a.animating=!0,a.$slider.trigger("beforeChange",[a,a.currentSlide,s]),n=a.currentSlide,a.currentSlide=s,a.setSlideClasses(a.currentSlide),a.options.asNavFor&&(l=(l=a.getNavTarget()).slick("getSlick")).slideCount<=l.options.slidesToShow&&l.setSlideClasses(a.currentSlide),a.updateDots(),a.updateArrows(),!0===a.options.fade)return!0!==t?(a.fadeSlideOut(n),a.fadeSlide(s,function(){a.postSlide(s)})):a.postSlide(s),void a.animateHeight();!0!==t?a.animateSlide(d,function(){a.postSlide(s)}):a.postSlide(s)}},e.prototype.startLoad=function(){var i=this;!0===i.options.arrows&&i.slideCount>i.options.slidesToShow&&(i.$prevArrow.hide(),i.$nextArrow.hide()),!0===i.options.dots&&i.slideCount>i.options.slidesToShow&&i.$dots.hide(),i.$slider.addClass("slick-loading")},e.prototype.swipeDirection=function(){var i,e,t,o,s=this;return i=s.touchObject.startX-s.touchObject.curX,e=s.touchObject.startY-s.touchObject.curY,t=Math.atan2(e,i),(o=Math.round(180*t/Math.PI))<0&&(o=360-Math.abs(o)),o<=45&&o>=0?!1===s.options.rtl?"left":"right":o<=360&&o>=315?!1===s.options.rtl?"left":"right":o>=135&&o<=225?!1===s.options.rtl?"right":"left":!0===s.options.verticalSwiping?o>=35&&o<=135?"down":"up":"vertical"},e.prototype.swipeEnd=function(i){var e,t,o=this;if(o.dragging=!1,o.swiping=!1,o.scrolling)return o.scrolling=!1,!1;if(o.interrupted=!1,o.shouldClick=!(o.touchObject.swipeLength>10),void 0===o.touchObject.curX)return!1;if(!0===o.touchObject.edgeHit&&o.$slider.trigger("edge",[o,o.swipeDirection()]),o.touchObject.swipeLength>=o.touchObject.minSwipe){switch(t=o.swipeDirection()){case"left":case"down":e=o.options.swipeToSlide?o.checkNavigable(o.currentSlide+o.getSlideCount()):o.currentSlide+o.getSlideCount(),o.currentDirection=0;break;case"right":case"up":e=o.options.swipeToSlide?o.checkNavigable(o.currentSlide-o.getSlideCount()):o.currentSlide-o.getSlideCount(),o.currentDirection=1}"vertical"!=t&&(o.slideHandler(e),o.touchObject={},o.$slider.trigger("swipe",[o,t]))}else o.touchObject.startX!==o.touchObject.curX&&(o.slideHandler(o.currentSlide),o.touchObject={})},e.prototype.swipeHandler=function(i){var e=this;if(!(!1===e.options.swipe||"ontouchend"in document&&!1===e.options.swipe||!1===e.options.draggable&&-1!==i.type.indexOf("mouse")))switch(e.touchObject.fingerCount=i.originalEvent&&void 0!==i.originalEvent.touches?i.originalEvent.touches.length:1,e.touchObject.minSwipe=e.listWidth/e.options.touchThreshold,!0===e.options.verticalSwiping&&(e.touchObject.minSwipe=e.listHeight/e.options.touchThreshold),i.data.action){case"start":e.swipeStart(i);break;case"move":e.swipeMove(i);break;case"end":e.swipeEnd(i)}},e.prototype.swipeMove=function(i){var e,t,o,s,n,r,l=this;return n=void 0!==i.originalEvent?i.originalEvent.touches:null,!(!l.dragging||l.scrolling||n&&1!==n.length)&&(e=l.getLeft(l.currentSlide),l.touchObject.curX=void 0!==n?n[0].pageX:i.clientX,l.touchObject.curY=void 0!==n?n[0].pageY:i.clientY,l.touchObject.swipeLength=Math.round(Math.sqrt(Math.pow(l.touchObject.curX-l.touchObject.startX,2))),r=Math.round(Math.sqrt(Math.pow(l.touchObject.curY-l.touchObject.startY,2))),!l.options.verticalSwiping&&!l.swiping&&r>4?(l.scrolling=!0,!1):(!0===l.options.verticalSwiping&&(l.touchObject.swipeLength=r),t=l.swipeDirection(),void 0!==i.originalEvent&&l.touchObject.swipeLength>4&&(l.swiping=!0,i.preventDefault()),s=(!1===l.options.rtl?1:-1)*(l.touchObject.curX>l.touchObject.startX?1:-1),!0===l.options.verticalSwiping&&(s=l.touchObject.curY>l.touchObject.startY?1:-1),o=l.touchObject.swipeLength,l.touchObject.edgeHit=!1,!1===l.options.infinite&&(0===l.currentSlide&&"right"===t||l.currentSlide>=l.getDotCount()&&"left"===t)&&(o=l.touchObject.swipeLength*l.options.edgeFriction,l.touchObject.edgeHit=!0),!1===l.options.vertical?l.swipeLeft=e+o*s:l.swipeLeft=e+o*(l.$list.height()/l.listWidth)*s,!0===l.options.verticalSwiping&&(l.swipeLeft=e+o*s),!0!==l.options.fade&&!1!==l.options.touchMove&&(!0===l.animating?(l.swipeLeft=null,!1):void l.setCSS(l.swipeLeft))))},e.prototype.swipeStart=function(i){var e,t=this;if(t.interrupted=!0,1!==t.touchObject.fingerCount||t.slideCount<=t.options.slidesToShow)return t.touchObject={},!1;void 0!==i.originalEvent&&void 0!==i.originalEvent.touches&&(e=i.originalEvent.touches[0]),t.touchObject.startX=t.touchObject.curX=void 0!==e?e.pageX:i.clientX,t.touchObject.startY=t.touchObject.curY=void 0!==e?e.pageY:i.clientY,t.dragging=!0},e.prototype.unfilterSlides=e.prototype.slickUnfilter=function(){var i=this;null!==i.$slidesCache&&(i.unload(),i.$slideTrack.children(this.options.slide).detach(),i.$slidesCache.appendTo(i.$slideTrack),i.reinit())},e.prototype.unload=function(){var e=this;i(".slick-cloned",e.$slider).remove(),e.$dots&&e.$dots.remove(),e.$prevArrow&&e.htmlExpr.test(e.options.prevArrow)&&e.$prevArrow.remove(),e.$nextArrow&&e.htmlExpr.test(e.options.nextArrow)&&e.$nextArrow.remove(),e.$slides.removeClass("slick-slide slick-active slick-visible slick-current").attr("aria-hidden","true").css("width","")},e.prototype.unslick=function(i){var e=this;e.$slider.trigger("unslick",[e,i]),e.destroy()},e.prototype.updateArrows=function(){var i=this;Math.floor(i.options.slidesToShow/2),!0===i.options.arrows&&i.slideCount>i.options.slidesToShow&&!i.options.infinite&&(i.$prevArrow.removeClass("slick-disabled").attr("aria-disabled","false"),i.$nextArrow.removeClass("slick-disabled").attr("aria-disabled","false"),0===i.currentSlide?(i.$prevArrow.addClass("slick-disabled").attr("aria-disabled","true"),i.$nextArrow.removeClass("slick-disabled").attr("aria-disabled","false")):i.currentSlide>=i.slideCount-i.options.slidesToShow&&!1===i.options.centerMode?(i.$nextArrow.addClass("slick-disabled").attr("aria-disabled","true"),i.$prevArrow.removeClass("slick-disabled").attr("aria-disabled","false")):i.currentSlide>=i.slideCount-1&&!0===i.options.centerMode&&(i.$nextArrow.addClass("slick-disabled").attr("aria-disabled","true"),i.$prevArrow.removeClass("slick-disabled").attr("aria-disabled","false")))},e.prototype.updateDots=function(){var i=this;null!==i.$dots&&(i.$dots.find("li").removeClass("slick-active").end(),i.$dots.find("li").eq(Math.floor(i.currentSlide/i.options.slidesToScroll)).addClass("slick-active"))},e.prototype.visibility=function(){var i=this;i.options.autoplay&&(document[i.hidden]?i.interrupted=!0:i.interrupted=!1)},i.fn.slick=function(){var i,t,o=this,s=arguments[0],n=Array.prototype.slice.call(arguments,1),r=o.length;for(i=0;i 0) {
name.splice(i - 1, 2);
i -= 2;
}
}
}
//end trimDots
name = name.join('/');
}
//Apply map config if available.
if ((baseParts || starMap) && map) {
nameParts = name.split('/');
for (i = nameParts.length; i > 0; i -= 1) {
nameSegment = nameParts.slice(0, i).join("/");
if (baseParts) {
//Find the longest baseName segment match in the config.
//So, do joins on the biggest to smallest lengths of baseParts.
for (j = baseParts.length; j > 0; j -= 1) {
mapValue = map[baseParts.slice(0, j).join('/')];
//baseName segment has config, find if it has one for
//this name.
if (mapValue) {
mapValue = mapValue[nameSegment];
if (mapValue) {
//Match, update name to the new value.
foundMap = mapValue;
foundI = i;
break;
}
}
}
}
if (foundMap) {
break;
}
//Check for a star map match, but just hold on to it,
//if there is a shorter segment match later in a matching
//config, then favor over this star map.
if (!foundStarMap && starMap && starMap[nameSegment]) {
foundStarMap = starMap[nameSegment];
starI = i;
}
}
if (!foundMap && foundStarMap) {
foundMap = foundStarMap;
foundI = starI;
}
if (foundMap) {
nameParts.splice(0, foundI, foundMap);
name = nameParts.join('/');
}
}
return name;
}
function makeRequire(relName, forceSync) {
return function () {
//A version of a require function that passes a moduleName
//value for items that may need to
//look up paths relative to the moduleName
var args = aps.call(arguments, 0);
//If first arg is not require('string'), and there is only
//one arg, it is the array form without a callback. Insert
//a null so that the following concat is correct.
if (typeof args[0] !== 'string' && args.length === 1) {
args.push(null);
}
return req.apply(undef, args.concat([relName, forceSync]));
};
}
function makeNormalize(relName) {
return function (name) {
return normalize(name, relName);
};
}
function makeLoad(depName) {
return function (value) {
defined[depName] = value;
};
}
function callDep(name) {
if (hasProp(waiting, name)) {
var args = waiting[name];
delete waiting[name];
defining[name] = true;
main.apply(undef, args);
}
if (!hasProp(defined, name) && !hasProp(defining, name)) {
throw new Error('No ' + name);
}
return defined[name];
}
//Turns a plugin!resource to [plugin, resource]
//with the plugin being undefined if the name
//did not have a plugin prefix.
function splitPrefix(name) {
var prefix,
index = name ? name.indexOf('!') : -1;
if (index > -1) {
prefix = name.substring(0, index);
name = name.substring(index + 1, name.length);
}
return [prefix, name];
}
//Creates a parts array for a relName where first part is plugin ID,
//second part is resource ID. Assumes relName has already been normalized.
function makeRelParts(relName) {
return relName ? splitPrefix(relName) : [];
}
/**
* Makes a name map, normalizing the name, and using a plugin
* for normalization if necessary. Grabs a ref to plugin
* too, as an optimization.
*/
makeMap = function (name, relParts) {
var plugin,
parts = splitPrefix(name),
prefix = parts[0],
relResourceName = relParts[1];
name = parts[1];
if (prefix) {
prefix = normalize(prefix, relResourceName);
plugin = callDep(prefix);
}
//Normalize according
if (prefix) {
if (plugin && plugin.normalize) {
name = plugin.normalize(name, makeNormalize(relResourceName));
} else {
name = normalize(name, relResourceName);
}
} else {
name = normalize(name, relResourceName);
parts = splitPrefix(name);
prefix = parts[0];
name = parts[1];
if (prefix) {
plugin = callDep(prefix);
}
}
//Using ridiculous property names for space reasons
return {
f: prefix ? prefix + '!' + name : name, //fullName
n: name,
pr: prefix,
p: plugin
};
};
function makeConfig(name) {
return function () {
return (config && config.config && config.config[name]) || {};
};
}
handlers = {
require: function (name) {
return makeRequire(name);
},
exports: function (name) {
var e = defined[name];
if (typeof e !== 'undefined') {
return e;
} else {
return (defined[name] = {});
}
},
module: function (name) {
return {
id: name,
uri: '',
exports: defined[name],
config: makeConfig(name)
};
}
};
main = function (name, deps, callback, relName) {
var cjsModule, depName, ret, map, i, relParts,
args = [],
callbackType = typeof callback,
usingExports;
//Use name if no relName
relName = relName || name;
relParts = makeRelParts(relName);
//Call the callback to define the module, if necessary.
if (callbackType === 'undefined' || callbackType === 'function') {
//Pull out the defined dependencies and pass the ordered
//values to the callback.
//Default to [require, exports, module] if no deps
deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
for (i = 0; i < deps.length; i += 1) {
map = makeMap(deps[i], relParts);
depName = map.f;
//Fast path CommonJS standard dependencies.
if (depName === "require") {
args[i] = handlers.require(name);
} else if (depName === "exports") {
//CommonJS module spec 1.1
args[i] = handlers.exports(name);
usingExports = true;
} else if (depName === "module") {
//CommonJS module spec 1.1
cjsModule = args[i] = handlers.module(name);
} else if (hasProp(defined, depName) ||
hasProp(waiting, depName) ||
hasProp(defining, depName)) {
args[i] = callDep(depName);
} else if (map.p) {
map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
args[i] = defined[depName];
} else {
throw new Error(name + ' missing ' + depName);
}
}
ret = callback ? callback.apply(defined[name], args) : undefined;
if (name) {
//If setting exports via "module" is in play,
//favor that over return value and exports. After that,
//favor a non-undefined return value over exports use.
if (cjsModule && cjsModule.exports !== undef &&
cjsModule.exports !== defined[name]) {
defined[name] = cjsModule.exports;
} else if (ret !== undef || !usingExports) {
//Use the return value from the function.
defined[name] = ret;
}
}
} else if (name) {
//May just be an object definition for the module. Only
//worry about defining if have a module name.
defined[name] = callback;
}
};
requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
if (typeof deps === "string") {
if (handlers[deps]) {
//callback in this case is really relName
return handlers[deps](callback);
}
//Just return the module wanted. In this scenario, the
//deps arg is the module name, and second arg (if passed)
//is just the relName.
//Normalize module name, if it contains . or ..
return callDep(makeMap(deps, makeRelParts(callback)).f);
} else if (!deps.splice) {
//deps is a config object, not an array.
config = deps;
if (config.deps) {
req(config.deps, config.callback);
}
if (!callback) {
return;
}
if (callback.splice) {
//callback is an array, which means it is a dependency list.
//Adjust args if there are dependencies
deps = callback;
callback = relName;
relName = null;
} else {
deps = undef;
}
}
//Support require(['a'])
callback = callback || function () {};
//If relName is a function, it is an errback handler,
//so remove it.
if (typeof relName === 'function') {
relName = forceSync;
forceSync = alt;
}
//Simulate async callback;
if (forceSync) {
main(undef, deps, callback, relName);
} else {
//Using a non-zero value because of concern for what old browsers
//do, and latest browsers "upgrade" to 4 if lower value is used:
//http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
//If want a value immediately, use require('id') instead -- something
//that works in almond on the global level, but not guaranteed and
//unlikely to work in other AMD implementations.
setTimeout(function () {
main(undef, deps, callback, relName);
}, 4);
}
return req;
};
/**
* Just drops the config on the floor, but returns req in case
* the config return value is used.
*/
req.config = function (cfg) {
return req(cfg);
};
/**
* Expose module registry for debugging and tooling
*/
requirejs._defined = defined;
define = function (name, deps, callback) {
if (typeof name !== 'string') {
throw new Error('See almond README: incorrect module build, no module name');
}
//This module may not have dependencies
if (!deps.splice) {
//deps is not an array, so probably means
//an object literal or factory function for
//the value. Adjust args.
callback = deps;
deps = [];
}
if (!hasProp(defined, name) && !hasProp(waiting, name)) {
waiting[name] = [name, deps, callback];
}
};
define.amd = {
jQuery: true
};
}());
S2.requirejs = requirejs;S2.require = require;S2.define = define;
}
}());
S2.define("almond", function(){});
/* global jQuery:false, $:false */
S2.define('jquery',[],function () {
var _$ = jQuery || $;
if (_$ == null && console && console.error) {
console.error(
'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
'found. Make sure that you are including jQuery before Select2 on your ' +
'web page.'
);
}
return _$;
});
S2.define('select2/utils',[
'jquery'
], function ($) {
var Utils = {};
Utils.Extend = function (ChildClass, SuperClass) {
var __hasProp = {}.hasOwnProperty;
function BaseConstructor () {
this.constructor = ChildClass;
}
for (var key in SuperClass) {
if (__hasProp.call(SuperClass, key)) {
ChildClass[key] = SuperClass[key];
}
}
BaseConstructor.prototype = SuperClass.prototype;
ChildClass.prototype = new BaseConstructor();
ChildClass.__super__ = SuperClass.prototype;
return ChildClass;
};
function getMethods (theClass) {
var proto = theClass.prototype;
var methods = [];
for (var methodName in proto) {
var m = proto[methodName];
if (typeof m !== 'function') {
continue;
}
if (methodName === 'constructor') {
continue;
}
methods.push(methodName);
}
return methods;
}
Utils.Decorate = function (SuperClass, DecoratorClass) {
var decoratedMethods = getMethods(DecoratorClass);
var superMethods = getMethods(SuperClass);
function DecoratedClass () {
var unshift = Array.prototype.unshift;
var argCount = DecoratorClass.prototype.constructor.length;
var calledConstructor = SuperClass.prototype.constructor;
if (argCount > 0) {
unshift.call(arguments, SuperClass.prototype.constructor);
calledConstructor = DecoratorClass.prototype.constructor;
}
calledConstructor.apply(this, arguments);
}
DecoratorClass.displayName = SuperClass.displayName;
function ctr () {
this.constructor = DecoratedClass;
}
DecoratedClass.prototype = new ctr();
for (var m = 0; m < superMethods.length; m++) {
var superMethod = superMethods[m];
DecoratedClass.prototype[superMethod] =
SuperClass.prototype[superMethod];
}
var calledMethod = function (methodName) {
// Stub out the original method if it's not decorating an actual method
var originalMethod = function () {};
if (methodName in DecoratedClass.prototype) {
originalMethod = DecoratedClass.prototype[methodName];
}
var decoratedMethod = DecoratorClass.prototype[methodName];
return function () {
var unshift = Array.prototype.unshift;
unshift.call(arguments, originalMethod);
return decoratedMethod.apply(this, arguments);
};
};
for (var d = 0; d < decoratedMethods.length; d++) {
var decoratedMethod = decoratedMethods[d];
DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
}
return DecoratedClass;
};
var Observable = function () {
this.listeners = {};
};
Observable.prototype.on = function (event, callback) {
this.listeners = this.listeners || {};
if (event in this.listeners) {
this.listeners[event].push(callback);
} else {
this.listeners[event] = [callback];
}
};
Observable.prototype.trigger = function (event) {
var slice = Array.prototype.slice;
var params = slice.call(arguments, 1);
this.listeners = this.listeners || {};
// Params should always come in as an array
if (params == null) {
params = [];
}
// If there are no arguments to the event, use a temporary object
if (params.length === 0) {
params.push({});
}
// Set the `_type` of the first object to the event
params[0]._type = event;
if (event in this.listeners) {
this.invoke(this.listeners[event], slice.call(arguments, 1));
}
if ('*' in this.listeners) {
this.invoke(this.listeners['*'], arguments);
}
};
Observable.prototype.invoke = function (listeners, params) {
for (var i = 0, len = listeners.length; i < len; i++) {
listeners[i].apply(this, params);
}
};
Utils.Observable = Observable;
Utils.generateChars = function (length) {
var chars = '';
for (var i = 0; i < length; i++) {
var randomChar = Math.floor(Math.random() * 36);
chars += randomChar.toString(36);
}
return chars;
};
Utils.bind = function (func, context) {
return function () {
func.apply(context, arguments);
};
};
Utils._convertData = function (data) {
for (var originalKey in data) {
var keys = originalKey.split('-');
var dataLevel = data;
if (keys.length === 1) {
continue;
}
for (var k = 0; k < keys.length; k++) {
var key = keys[k];
// Lowercase the first letter
// By default, dash-separated becomes camelCase
key = key.substring(0, 1).toLowerCase() + key.substring(1);
if (!(key in dataLevel)) {
dataLevel[key] = {};
}
if (k == keys.length - 1) {
dataLevel[key] = data[originalKey];
}
dataLevel = dataLevel[key];
}
delete data[originalKey];
}
return data;
};
Utils.hasScroll = function (index, el) {
// Adapted from the function created by @ShadowScripter
// and adapted by @BillBarry on the Stack Exchange Code Review website.
// The original code can be found at
// http://codereview.stackexchange.com/q/13338
// and was designed to be used with the Sizzle selector engine.
var $el = $(el);
var overflowX = el.style.overflowX;
var overflowY = el.style.overflowY;
//Check both x and y declarations
if (overflowX === overflowY &&
(overflowY === 'hidden' || overflowY === 'visible')) {
return false;
}
if (overflowX === 'scroll' || overflowY === 'scroll') {
return true;
}
return ($el.innerHeight() < el.scrollHeight ||
$el.innerWidth() < el.scrollWidth);
};
Utils.escapeMarkup = function (markup) {
var replaceMap = {
'\\': '\',
'&': '&',
'<': '<',
'>': '>',
'"': '"',
'\'': ''',
'/': '/'
};
// Do not try to escape the markup if it's not a string
if (typeof markup !== 'string') {
return markup;
}
return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
return replaceMap[match];
});
};
// Append an array of jQuery nodes to a given element.
Utils.appendMany = function ($element, $nodes) {
// jQuery 1.7.x does not support $.fn.append() with an array
// Fall back to a jQuery object collection using $.fn.add()
if ($.fn.jquery.substr(0, 3) === '1.7') {
var $jqNodes = $();
$.map($nodes, function (node) {
$jqNodes = $jqNodes.add(node);
});
$nodes = $jqNodes;
}
$element.append($nodes);
};
// Cache objects in Utils.__cache instead of $.data (see #4346)
Utils.__cache = {};
var id = 0;
Utils.GetUniqueElementId = function (element) {
// Get a unique element Id. If element has no id,
// creates a new unique number, stores it in the id
// attribute and returns the new id.
// If an id already exists, it simply returns it.
var select2Id = element.getAttribute('data-select2-id');
if (select2Id == null) {
// If element has id, use it.
if (element.id) {
select2Id = element.id;
element.setAttribute('data-select2-id', select2Id);
} else {
element.setAttribute('data-select2-id', ++id);
select2Id = id.toString();
}
}
return select2Id;
};
Utils.StoreData = function (element, name, value) {
// Stores an item in the cache for a specified element.
// name is the cache key.
var id = Utils.GetUniqueElementId(element);
if (!Utils.__cache[id]) {
Utils.__cache[id] = {};
}
Utils.__cache[id][name] = value;
};
Utils.GetData = function (element, name) {
// Retrieves a value from the cache by its key (name)
// name is optional. If no name specified, return
// all cache items for the specified element.
// and for a specified element.
var id = Utils.GetUniqueElementId(element);
if (name) {
if (Utils.__cache[id]) {
if (Utils.__cache[id][name] != null) {
return Utils.__cache[id][name];
}
return $(element).data(name); // Fallback to HTML5 data attribs.
}
return $(element).data(name); // Fallback to HTML5 data attribs.
} else {
return Utils.__cache[id];
}
};
Utils.RemoveData = function (element) {
// Removes all cached items for a specified element.
var id = Utils.GetUniqueElementId(element);
if (Utils.__cache[id] != null) {
delete Utils.__cache[id];
}
element.removeAttribute('data-select2-id');
};
return Utils;
});
S2.define('select2/results',[
'jquery',
'./utils'
], function ($, Utils) {
function Results ($element, options, dataAdapter) {
this.$element = $element;
this.data = dataAdapter;
this.options = options;
Results.__super__.constructor.call(this);
}
Utils.Extend(Results, Utils.Observable);
Results.prototype.render = function () {
var $results = $(
''
);
if (this.options.get('multiple')) {
$results.attr('aria-multiselectable', 'true');
}
this.$results = $results;
return $results;
};
Results.prototype.clear = function () {
this.$results.empty();
};
Results.prototype.displayMessage = function (params) {
var escapeMarkup = this.options.get('escapeMarkup');
this.clear();
this.hideLoading();
var $message = $(
' '
);
var message = this.options.get('translations').get(params.message);
$message.append(
escapeMarkup(
message(params.args)
)
);
$message[0].className += ' select2-results__message';
this.$results.append($message);
};
Results.prototype.hideMessages = function () {
this.$results.find('.select2-results__message').remove();
};
Results.prototype.append = function (data) {
this.hideLoading();
var $options = [];
if (data.results == null || data.results.length === 0) {
if (this.$results.children().length === 0) {
this.trigger('results:message', {
message: 'noResults'
});
}
return;
}
data.results = this.sort(data.results);
for (var d = 0; d < data.results.length; d++) {
var item = data.results[d];
var $option = this.option(item);
$options.push($option);
}
this.$results.append($options);
};
Results.prototype.position = function ($results, $dropdown) {
var $resultsContainer = $dropdown.find('.select2-results');
$resultsContainer.append($results);
};
Results.prototype.sort = function (data) {
var sorter = this.options.get('sorter');
return sorter(data);
};
Results.prototype.highlightFirstItem = function () {
var $options = this.$results
.find('.select2-results__option[aria-selected]');
var $selected = $options.filter('[aria-selected=true]');
// Check if there are any selected options
if ($selected.length > 0) {
// If there are selected options, highlight the first
$selected.first().trigger('mouseenter');
} else {
// If there are no selected options, highlight the first option
// in the dropdown
$options.first().trigger('mouseenter');
}
this.ensureHighlightVisible();
};
Results.prototype.setClasses = function () {
var self = this;
this.data.current(function (selected) {
var selectedIds = $.map(selected, function (s) {
return s.id.toString();
});
var $options = self.$results
.find('.select2-results__option[aria-selected]');
$options.each(function () {
var $option = $(this);
var item = Utils.GetData(this, 'data');
// id needs to be converted to a string when comparing
var id = '' + item.id;
if ((item.element != null && item.element.selected) ||
(item.element == null && $.inArray(id, selectedIds) > -1)) {
$option.attr('aria-selected', 'true');
} else {
$option.attr('aria-selected', 'false');
}
});
});
};
Results.prototype.showLoading = function (params) {
this.hideLoading();
var loadingMore = this.options.get('translations').get('searching');
var loading = {
disabled: true,
loading: true,
text: loadingMore(params)
};
var $loading = this.option(loading);
$loading.className += ' loading-results';
this.$results.prepend($loading);
};
Results.prototype.hideLoading = function () {
this.$results.find('.loading-results').remove();
};
Results.prototype.option = function (data) {
var option = document.createElement('li');
option.className = 'select2-results__option';
var attrs = {
'role': 'option',
'aria-selected': 'false'
};
var matches = window.Element.prototype.matches ||
window.Element.prototype.msMatchesSelector ||
window.Element.prototype.webkitMatchesSelector;
if ((data.element != null && matches.call(data.element, ':disabled')) ||
(data.element == null && data.disabled)) {
delete attrs['aria-selected'];
attrs['aria-disabled'] = 'true';
}
if (data.id == null) {
delete attrs['aria-selected'];
}
if (data._resultId != null) {
option.id = data._resultId;
}
if (data.title) {
option.title = data.title;
}
if (data.children) {
attrs.role = 'group';
attrs['aria-label'] = data.text;
delete attrs['aria-selected'];
}
for (var attr in attrs) {
var val = attrs[attr];
option.setAttribute(attr, val);
}
if (data.children) {
var $option = $(option);
var label = document.createElement('strong');
label.className = 'select2-results__group';
var $label = $(label);
this.template(data, label);
var $children = [];
for (var c = 0; c < data.children.length; c++) {
var child = data.children[c];
var $child = this.option(child);
$children.push($child);
}
var $childrenContainer = $('', {
'class': 'select2-results__options select2-results__options--nested'
});
$childrenContainer.append($children);
$option.append(label);
$option.append($childrenContainer);
} else {
this.template(data, option);
}
Utils.StoreData(option, 'data', data);
return option;
};
Results.prototype.bind = function (container, $container) {
var self = this;
var id = container.id + '-results';
this.$results.attr('id', id);
container.on('results:all', function (params) {
self.clear();
self.append(params.data);
if (container.isOpen()) {
self.setClasses();
self.highlightFirstItem();
}
});
container.on('results:append', function (params) {
self.append(params.data);
if (container.isOpen()) {
self.setClasses();
}
});
container.on('query', function (params) {
self.hideMessages();
self.showLoading(params);
});
container.on('select', function () {
if (!container.isOpen()) {
return;
}
self.setClasses();
if (self.options.get('scrollAfterSelect')) {
self.highlightFirstItem();
}
});
container.on('unselect', function () {
if (!container.isOpen()) {
return;
}
self.setClasses();
if (self.options.get('scrollAfterSelect')) {
self.highlightFirstItem();
}
});
container.on('open', function () {
// When the dropdown is open, aria-expended="true"
self.$results.attr('aria-expanded', 'true');
self.$results.attr('aria-hidden', 'false');
self.setClasses();
self.ensureHighlightVisible();
});
container.on('close', function () {
// When the dropdown is closed, aria-expended="false"
self.$results.attr('aria-expanded', 'false');
self.$results.attr('aria-hidden', 'true');
self.$results.removeAttr('aria-activedescendant');
});
container.on('results:toggle', function () {
var $highlighted = self.getHighlightedResults();
if ($highlighted.length === 0) {
return;
}
$highlighted.trigger('mouseup');
});
container.on('results:select', function () {
var $highlighted = self.getHighlightedResults();
if ($highlighted.length === 0) {
return;
}
var data = Utils.GetData($highlighted[0], 'data');
if ($highlighted.attr('aria-selected') == 'true') {
self.trigger('close', {});
} else {
self.trigger('select', {
data: data
});
}
});
container.on('results:previous', function () {
var $highlighted = self.getHighlightedResults();
var $options = self.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
// If we are already at the top, don't move further
// If no options, currentIndex will be -1
if (currentIndex <= 0) {
return;
}
var nextIndex = currentIndex - 1;
// If none are highlighted, highlight the first
if ($highlighted.length === 0) {
nextIndex = 0;
}
var $next = $options.eq(nextIndex);
$next.trigger('mouseenter');
var currentOffset = self.$results.offset().top;
var nextTop = $next.offset().top;
var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
if (nextIndex === 0) {
self.$results.scrollTop(0);
} else if (nextTop - currentOffset < 0) {
self.$results.scrollTop(nextOffset);
}
});
container.on('results:next', function () {
var $highlighted = self.getHighlightedResults();
var $options = self.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
var nextIndex = currentIndex + 1;
// If we are at the last option, stay there
if (nextIndex >= $options.length) {
return;
}
var $next = $options.eq(nextIndex);
$next.trigger('mouseenter');
var currentOffset = self.$results.offset().top +
self.$results.outerHeight(false);
var nextBottom = $next.offset().top + $next.outerHeight(false);
var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
if (nextIndex === 0) {
self.$results.scrollTop(0);
} else if (nextBottom > currentOffset) {
self.$results.scrollTop(nextOffset);
}
});
container.on('results:focus', function (params) {
params.element.addClass('select2-results__option--highlighted');
});
container.on('results:message', function (params) {
self.displayMessage(params);
});
if ($.fn.mousewheel) {
this.$results.on('mousewheel', function (e) {
var top = self.$results.scrollTop();
var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
if (isAtTop) {
self.$results.scrollTop(0);
e.preventDefault();
e.stopPropagation();
} else if (isAtBottom) {
self.$results.scrollTop(
self.$results.get(0).scrollHeight - self.$results.height()
);
e.preventDefault();
e.stopPropagation();
}
});
}
this.$results.on('mouseup', '.select2-results__option[aria-selected]',
function (evt) {
var $this = $(this);
var data = Utils.GetData(this, 'data');
if ($this.attr('aria-selected') === 'true') {
if (self.options.get('multiple')) {
self.trigger('unselect', {
originalEvent: evt,
data: data
});
} else {
self.trigger('close', {});
}
return;
}
self.trigger('select', {
originalEvent: evt,
data: data
});
});
this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
function (evt) {
var data = Utils.GetData(this, 'data');
self.getHighlightedResults()
.removeClass('select2-results__option--highlighted');
self.trigger('results:focus', {
data: data,
element: $(this)
});
});
};
Results.prototype.getHighlightedResults = function () {
var $highlighted = this.$results
.find('.select2-results__option--highlighted');
return $highlighted;
};
Results.prototype.destroy = function () {
this.$results.remove();
};
Results.prototype.ensureHighlightVisible = function () {
var $highlighted = this.getHighlightedResults();
if ($highlighted.length === 0) {
return;
}
var $options = this.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
var currentOffset = this.$results.offset().top;
var nextTop = $highlighted.offset().top;
var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
var offsetDelta = nextTop - currentOffset;
nextOffset -= $highlighted.outerHeight(false) * 2;
if (currentIndex <= 2) {
this.$results.scrollTop(0);
} else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
this.$results.scrollTop(nextOffset);
}
};
Results.prototype.template = function (result, container) {
var template = this.options.get('templateResult');
var escapeMarkup = this.options.get('escapeMarkup');
var content = template(result, container);
if (content == null) {
container.style.display = 'none';
} else if (typeof content === 'string') {
container.innerHTML = escapeMarkup(content);
} else {
$(container).append(content);
}
};
return Results;
});
S2.define('select2/keys',[
], function () {
var KEYS = {
BACKSPACE: 8,
TAB: 9,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
ESC: 27,
SPACE: 32,
PAGE_UP: 33,
PAGE_DOWN: 34,
END: 35,
HOME: 36,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40,
DELETE: 46
};
return KEYS;
});
S2.define('select2/selection/base',[
'jquery',
'../utils',
'../keys'
], function ($, Utils, KEYS) {
function BaseSelection ($element, options) {
this.$element = $element;
this.options = options;
BaseSelection.__super__.constructor.call(this);
}
Utils.Extend(BaseSelection, Utils.Observable);
BaseSelection.prototype.render = function () {
var $selection = $(
'' +
' '
);
this._tabindex = 0;
if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {
this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');
} else if (this.$element.attr('tabindex') != null) {
this._tabindex = this.$element.attr('tabindex');
}
$selection.attr('title', this.$element.attr('title'));
$selection.attr('tabindex', this._tabindex);
$selection.attr('aria-disabled', 'false');
this.$selection = $selection;
return $selection;
};
BaseSelection.prototype.bind = function (container, $container) {
var self = this;
var resultsId = container.id + '-results';
this.container = container;
this.$selection.on('focus', function (evt) {
self.trigger('focus', evt);
});
this.$selection.on('blur', function (evt) {
self._handleBlur(evt);
});
this.$selection.on('keydown', function (evt) {
self.trigger('keypress', evt);
if (evt.which === KEYS.SPACE) {
evt.preventDefault();
}
});
container.on('results:focus', function (params) {
self.$selection.attr('aria-activedescendant', params.data._resultId);
});
container.on('selection:update', function (params) {
self.update(params.data);
});
container.on('open', function () {
// When the dropdown is open, aria-expanded="true"
self.$selection.attr('aria-expanded', 'true');
self.$selection.attr('aria-owns', resultsId);
self._attachCloseHandler(container);
});
container.on('close', function () {
// When the dropdown is closed, aria-expanded="false"
self.$selection.attr('aria-expanded', 'false');
self.$selection.removeAttr('aria-activedescendant');
self.$selection.removeAttr('aria-owns');
self.$selection.trigger('focus');
self._detachCloseHandler(container);
});
container.on('enable', function () {
self.$selection.attr('tabindex', self._tabindex);
self.$selection.attr('aria-disabled', 'false');
});
container.on('disable', function () {
self.$selection.attr('tabindex', '-1');
self.$selection.attr('aria-disabled', 'true');
});
};
BaseSelection.prototype._handleBlur = function (evt) {
var self = this;
// This needs to be delayed as the active element is the body when the tab
// key is pressed, possibly along with others.
window.setTimeout(function () {
// Don't trigger `blur` if the focus is still in the selection
if (
(document.activeElement == self.$selection[0]) ||
($.contains(self.$selection[0], document.activeElement))
) {
return;
}
self.trigger('blur', evt);
}, 1);
};
BaseSelection.prototype._attachCloseHandler = function (container) {
$(document.body).on('mousedown.select2.' + container.id, function (e) {
var $target = $(e.target);
var $select = $target.closest('.select2');
var $all = $('.select2.select2-container--open');
$all.each(function () {
if (this == $select[0]) {
return;
}
var $element = Utils.GetData(this, 'element');
$element.select2('close');
});
});
};
BaseSelection.prototype._detachCloseHandler = function (container) {
$(document.body).off('mousedown.select2.' + container.id);
};
BaseSelection.prototype.position = function ($selection, $container) {
var $selectionContainer = $container.find('.selection');
$selectionContainer.append($selection);
};
BaseSelection.prototype.destroy = function () {
this._detachCloseHandler(this.container);
};
BaseSelection.prototype.update = function (data) {
throw new Error('The `update` method must be defined in child classes.');
};
return BaseSelection;
});
S2.define('select2/selection/single',[
'jquery',
'./base',
'../utils',
'../keys'
], function ($, BaseSelection, Utils, KEYS) {
function SingleSelection () {
SingleSelection.__super__.constructor.apply(this, arguments);
}
Utils.Extend(SingleSelection, BaseSelection);
SingleSelection.prototype.render = function () {
var $selection = SingleSelection.__super__.render.call(this);
$selection.addClass('select2-selection--single');
$selection.html(
' ' +
'' +
' ' +
' '
);
return $selection;
};
SingleSelection.prototype.bind = function (container, $container) {
var self = this;
SingleSelection.__super__.bind.apply(this, arguments);
var id = container.id + '-container';
this.$selection.find('.select2-selection__rendered')
.attr('id', id)
.attr('role', 'textbox')
.attr('aria-readonly', 'true');
this.$selection.attr('aria-labelledby', id);
this.$selection.on('mousedown', function (evt) {
// Only respond to left clicks
if (evt.which !== 1) {
return;
}
self.trigger('toggle', {
originalEvent: evt
});
});
this.$selection.on('focus', function (evt) {
// User focuses on the container
});
this.$selection.on('blur', function (evt) {
// User exits the container
});
container.on('focus', function (evt) {
if (!container.isOpen()) {
self.$selection.trigger('focus');
}
});
};
SingleSelection.prototype.clear = function () {
var $rendered = this.$selection.find('.select2-selection__rendered');
$rendered.empty();
$rendered.removeAttr('title'); // clear tooltip on empty
};
SingleSelection.prototype.display = function (data, container) {
var template = this.options.get('templateSelection');
var escapeMarkup = this.options.get('escapeMarkup');
return escapeMarkup(template(data, container));
};
SingleSelection.prototype.selectionContainer = function () {
return $(' ');
};
SingleSelection.prototype.update = function (data) {
if (data.length === 0) {
this.clear();
return;
}
var selection = data[0];
var $rendered = this.$selection.find('.select2-selection__rendered');
var formatted = this.display(selection, $rendered);
$rendered.empty().append(formatted);
var title = selection.title || selection.text;
if (title) {
$rendered.attr('title', title);
} else {
$rendered.removeAttr('title');
}
};
return SingleSelection;
});
S2.define('select2/selection/multiple',[
'jquery',
'./base',
'../utils'
], function ($, BaseSelection, Utils) {
function MultipleSelection ($element, options) {
MultipleSelection.__super__.constructor.apply(this, arguments);
}
Utils.Extend(MultipleSelection, BaseSelection);
MultipleSelection.prototype.render = function () {
var $selection = MultipleSelection.__super__.render.call(this);
$selection.addClass('select2-selection--multiple');
$selection.html(
''
);
return $selection;
};
MultipleSelection.prototype.bind = function (container, $container) {
var self = this;
MultipleSelection.__super__.bind.apply(this, arguments);
this.$selection.on('click', function (evt) {
self.trigger('toggle', {
originalEvent: evt
});
});
this.$selection.on(
'click',
'.select2-selection__choice__remove',
function (evt) {
// Ignore the event if it is disabled
if (self.options.get('disabled')) {
return;
}
var $remove = $(this);
var $selection = $remove.parent();
var data = Utils.GetData($selection[0], 'data');
self.trigger('unselect', {
originalEvent: evt,
data: data
});
}
);
};
MultipleSelection.prototype.clear = function () {
var $rendered = this.$selection.find('.select2-selection__rendered');
$rendered.empty();
$rendered.removeAttr('title');
};
MultipleSelection.prototype.display = function (data, container) {
var template = this.options.get('templateSelection');
var escapeMarkup = this.options.get('escapeMarkup');
return escapeMarkup(template(data, container));
};
MultipleSelection.prototype.selectionContainer = function () {
var $container = $(
'' +
'' +
'×' +
' ' +
' '
);
return $container;
};
MultipleSelection.prototype.update = function (data) {
this.clear();
if (data.length === 0) {
return;
}
var $selections = [];
for (var d = 0; d < data.length; d++) {
var selection = data[d];
var $selection = this.selectionContainer();
var formatted = this.display(selection, $selection);
$selection.append(formatted);
var title = selection.title || selection.text;
if (title) {
$selection.attr('title', title);
}
Utils.StoreData($selection[0], 'data', selection);
$selections.push($selection);
}
var $rendered = this.$selection.find('.select2-selection__rendered');
Utils.appendMany($rendered, $selections);
};
return MultipleSelection;
});
S2.define('select2/selection/placeholder',[
'../utils'
], function (Utils) {
function Placeholder (decorated, $element, options) {
this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
decorated.call(this, $element, options);
}
Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
if (typeof placeholder === 'string') {
placeholder = {
id: '',
text: placeholder
};
}
return placeholder;
};
Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
var $placeholder = this.selectionContainer();
$placeholder.html(this.display(placeholder));
$placeholder.addClass('select2-selection__placeholder')
.removeClass('select2-selection__choice');
return $placeholder;
};
Placeholder.prototype.update = function (decorated, data) {
var singlePlaceholder = (
data.length == 1 && data[0].id != this.placeholder.id
);
var multipleSelections = data.length > 1;
if (multipleSelections || singlePlaceholder) {
return decorated.call(this, data);
}
this.clear();
var $placeholder = this.createPlaceholder(this.placeholder);
this.$selection.find('.select2-selection__rendered').append($placeholder);
};
return Placeholder;
});
S2.define('select2/selection/allowClear',[
'jquery',
'../keys',
'../utils'
], function ($, KEYS, Utils) {
function AllowClear () { }
AllowClear.prototype.bind = function (decorated, container, $container) {
var self = this;
decorated.call(this, container, $container);
if (this.placeholder == null) {
if (this.options.get('debug') && window.console && console.error) {
console.error(
'Select2: The `allowClear` option should be used in combination ' +
'with the `placeholder` option.'
);
}
}
this.$selection.on('mousedown', '.select2-selection__clear',
function (evt) {
self._handleClear(evt);
});
container.on('keypress', function (evt) {
self._handleKeyboardClear(evt, container);
});
};
AllowClear.prototype._handleClear = function (_, evt) {
// Ignore the event if it is disabled
if (this.options.get('disabled')) {
return;
}
var $clear = this.$selection.find('.select2-selection__clear');
// Ignore the event if nothing has been selected
if ($clear.length === 0) {
return;
}
evt.stopPropagation();
var data = Utils.GetData($clear[0], 'data');
var previousVal = this.$element.val();
this.$element.val(this.placeholder.id);
var unselectData = {
data: data
};
this.trigger('clear', unselectData);
if (unselectData.prevented) {
this.$element.val(previousVal);
return;
}
for (var d = 0; d < data.length; d++) {
unselectData = {
data: data[d]
};
// Trigger the `unselect` event, so people can prevent it from being
// cleared.
this.trigger('unselect', unselectData);
// If the event was prevented, don't clear it out.
if (unselectData.prevented) {
this.$element.val(previousVal);
return;
}
}
this.$element.trigger('change');
this.trigger('toggle', {});
};
AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
if (container.isOpen()) {
return;
}
if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
this._handleClear(evt);
}
};
AllowClear.prototype.update = function (decorated, data) {
decorated.call(this, data);
if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
data.length === 0) {
return;
}
var removeAll = this.options.get('translations').get('removeAllItems');
var $remove = $(
'' +
'×' +
' '
);
Utils.StoreData($remove[0], 'data', data);
this.$selection.find('.select2-selection__rendered').prepend($remove);
};
return AllowClear;
});
S2.define('select2/selection/search',[
'jquery',
'../utils',
'../keys'
], function ($, Utils, KEYS) {
function Search (decorated, $element, options) {
decorated.call(this, $element, options);
}
Search.prototype.render = function (decorated) {
var $search = $(
'' +
' ' +
' '
);
this.$searchContainer = $search;
this.$search = $search.find('input');
var $rendered = decorated.call(this);
this._transferTabIndex();
return $rendered;
};
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
var resultsId = container.id + '-results';
decorated.call(this, container, $container);
container.on('open', function () {
self.$search.attr('aria-controls', resultsId);
self.$search.trigger('focus');
});
container.on('close', function () {
self.$search.val('');
self.$search.removeAttr('aria-controls');
self.$search.removeAttr('aria-activedescendant');
self.$search.trigger('focus');
});
container.on('enable', function () {
self.$search.prop('disabled', false);
self._transferTabIndex();
});
container.on('disable', function () {
self.$search.prop('disabled', true);
});
container.on('focus', function (evt) {
self.$search.trigger('focus');
});
container.on('results:focus', function (params) {
if (params.data._resultId) {
self.$search.attr('aria-activedescendant', params.data._resultId);
} else {
self.$search.removeAttr('aria-activedescendant');
}
});
this.$selection.on('focusin', '.select2-search--inline', function (evt) {
self.trigger('focus', evt);
});
this.$selection.on('focusout', '.select2-search--inline', function (evt) {
self._handleBlur(evt);
});
this.$selection.on('keydown', '.select2-search--inline', function (evt) {
evt.stopPropagation();
self.trigger('keypress', evt);
self._keyUpPrevented = evt.isDefaultPrevented();
var key = evt.which;
if (key === KEYS.BACKSPACE && self.$search.val() === '') {
var $previousChoice = self.$searchContainer
.prev('.select2-selection__choice');
if ($previousChoice.length > 0) {
var item = Utils.GetData($previousChoice[0], 'data');
self.searchRemoveChoice(item);
evt.preventDefault();
}
}
});
this.$selection.on('click', '.select2-search--inline', function (evt) {
if (self.$search.val()) {
evt.stopPropagation();
}
});
// Try to detect the IE version should the `documentMode` property that
// is stored on the document. This is only implemented in IE and is
// slightly cleaner than doing a user agent check.
// This property is not available in Edge, but Edge also doesn't have
// this bug.
var msie = document.documentMode;
var disableInputEvents = msie && msie <= 11;
// Workaround for browsers which do not support the `input` event
// This will prevent double-triggering of events for browsers which support
// both the `keyup` and `input` events.
this.$selection.on(
'input.searchcheck',
'.select2-search--inline',
function (evt) {
// IE will trigger the `input` event when a placeholder is used on a
// search box. To get around this issue, we are forced to ignore all
// `input` events in IE and keep using `keyup`.
if (disableInputEvents) {
self.$selection.off('input.search input.searchcheck');
return;
}
// Unbind the duplicated `keyup` event
self.$selection.off('keyup.search');
}
);
this.$selection.on(
'keyup.search input.search',
'.select2-search--inline',
function (evt) {
// IE will trigger the `input` event when a placeholder is used on a
// search box. To get around this issue, we are forced to ignore all
// `input` events in IE and keep using `keyup`.
if (disableInputEvents && evt.type === 'input') {
self.$selection.off('input.search input.searchcheck');
return;
}
var key = evt.which;
// We can freely ignore events from modifier keys
if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
return;
}
// Tabbing will be handled during the `keydown` phase
if (key == KEYS.TAB) {
return;
}
self.handleSearch(evt);
}
);
};
/**
* This method will transfer the tabindex attribute from the rendered
* selection to the search box. This allows for the search box to be used as
* the primary focus instead of the selection container.
*
* @private
*/
Search.prototype._transferTabIndex = function (decorated) {
this.$search.attr('tabindex', this.$selection.attr('tabindex'));
this.$selection.attr('tabindex', '-1');
};
Search.prototype.createPlaceholder = function (decorated, placeholder) {
this.$search.attr('placeholder', placeholder.text);
};
Search.prototype.update = function (decorated, data) {
var searchHadFocus = this.$search[0] == document.activeElement;
this.$search.attr('placeholder', '');
decorated.call(this, data);
this.$selection.find('.select2-selection__rendered')
.append(this.$searchContainer);
this.resizeSearch();
if (searchHadFocus) {
this.$search.trigger('focus');
}
};
Search.prototype.handleSearch = function () {
this.resizeSearch();
if (!this._keyUpPrevented) {
var input = this.$search.val();
this.trigger('query', {
term: input
});
}
this._keyUpPrevented = false;
};
Search.prototype.searchRemoveChoice = function (decorated, item) {
this.trigger('unselect', {
data: item
});
this.$search.val(item.text);
this.handleSearch();
};
Search.prototype.resizeSearch = function () {
this.$search.css('width', '25px');
var width = '';
if (this.$search.attr('placeholder') !== '') {
width = this.$selection.find('.select2-selection__rendered').width();
} else {
var minimumWidth = this.$search.val().length + 1;
width = (minimumWidth * 0.75) + 'em';
}
this.$search.css('width', width);
};
return Search;
});
S2.define('select2/selection/eventRelay',[
'jquery'
], function ($) {
function EventRelay () { }
EventRelay.prototype.bind = function (decorated, container, $container) {
var self = this;
var relayEvents = [
'open', 'opening',
'close', 'closing',
'select', 'selecting',
'unselect', 'unselecting',
'clear', 'clearing'
];
var preventableEvents = [
'opening', 'closing', 'selecting', 'unselecting', 'clearing'
];
decorated.call(this, container, $container);
container.on('*', function (name, params) {
// Ignore events that should not be relayed
if ($.inArray(name, relayEvents) === -1) {
return;
}
// The parameters should always be an object
params = params || {};
// Generate the jQuery event for the Select2 event
var evt = $.Event('select2:' + name, {
params: params
});
self.$element.trigger(evt);
// Only handle preventable events if it was one
if ($.inArray(name, preventableEvents) === -1) {
return;
}
params.prevented = evt.isDefaultPrevented();
});
};
return EventRelay;
});
S2.define('select2/translation',[
'jquery',
'require'
], function ($, require) {
function Translation (dict) {
this.dict = dict || {};
}
Translation.prototype.all = function () {
return this.dict;
};
Translation.prototype.get = function (key) {
return this.dict[key];
};
Translation.prototype.extend = function (translation) {
this.dict = $.extend({}, translation.all(), this.dict);
};
// Static functions
Translation._cache = {};
Translation.loadPath = function (path) {
if (!(path in Translation._cache)) {
var translations = require(path);
Translation._cache[path] = translations;
}
return new Translation(Translation._cache[path]);
};
return Translation;
});
S2.define('select2/diacritics',[
], function () {
var diacritics = {
'\u24B6': 'A',
'\uFF21': 'A',
'\u00C0': 'A',
'\u00C1': 'A',
'\u00C2': 'A',
'\u1EA6': 'A',
'\u1EA4': 'A',
'\u1EAA': 'A',
'\u1EA8': 'A',
'\u00C3': 'A',
'\u0100': 'A',
'\u0102': 'A',
'\u1EB0': 'A',
'\u1EAE': 'A',
'\u1EB4': 'A',
'\u1EB2': 'A',
'\u0226': 'A',
'\u01E0': 'A',
'\u00C4': 'A',
'\u01DE': 'A',
'\u1EA2': 'A',
'\u00C5': 'A',
'\u01FA': 'A',
'\u01CD': 'A',
'\u0200': 'A',
'\u0202': 'A',
'\u1EA0': 'A',
'\u1EAC': 'A',
'\u1EB6': 'A',
'\u1E00': 'A',
'\u0104': 'A',
'\u023A': 'A',
'\u2C6F': 'A',
'\uA732': 'AA',
'\u00C6': 'AE',
'\u01FC': 'AE',
'\u01E2': 'AE',
'\uA734': 'AO',
'\uA736': 'AU',
'\uA738': 'AV',
'\uA73A': 'AV',
'\uA73C': 'AY',
'\u24B7': 'B',
'\uFF22': 'B',
'\u1E02': 'B',
'\u1E04': 'B',
'\u1E06': 'B',
'\u0243': 'B',
'\u0182': 'B',
'\u0181': 'B',
'\u24B8': 'C',
'\uFF23': 'C',
'\u0106': 'C',
'\u0108': 'C',
'\u010A': 'C',
'\u010C': 'C',
'\u00C7': 'C',
'\u1E08': 'C',
'\u0187': 'C',
'\u023B': 'C',
'\uA73E': 'C',
'\u24B9': 'D',
'\uFF24': 'D',
'\u1E0A': 'D',
'\u010E': 'D',
'\u1E0C': 'D',
'\u1E10': 'D',
'\u1E12': 'D',
'\u1E0E': 'D',
'\u0110': 'D',
'\u018B': 'D',
'\u018A': 'D',
'\u0189': 'D',
'\uA779': 'D',
'\u01F1': 'DZ',
'\u01C4': 'DZ',
'\u01F2': 'Dz',
'\u01C5': 'Dz',
'\u24BA': 'E',
'\uFF25': 'E',
'\u00C8': 'E',
'\u00C9': 'E',
'\u00CA': 'E',
'\u1EC0': 'E',
'\u1EBE': 'E',
'\u1EC4': 'E',
'\u1EC2': 'E',
'\u1EBC': 'E',
'\u0112': 'E',
'\u1E14': 'E',
'\u1E16': 'E',
'\u0114': 'E',
'\u0116': 'E',
'\u00CB': 'E',
'\u1EBA': 'E',
'\u011A': 'E',
'\u0204': 'E',
'\u0206': 'E',
'\u1EB8': 'E',
'\u1EC6': 'E',
'\u0228': 'E',
'\u1E1C': 'E',
'\u0118': 'E',
'\u1E18': 'E',
'\u1E1A': 'E',
'\u0190': 'E',
'\u018E': 'E',
'\u24BB': 'F',
'\uFF26': 'F',
'\u1E1E': 'F',
'\u0191': 'F',
'\uA77B': 'F',
'\u24BC': 'G',
'\uFF27': 'G',
'\u01F4': 'G',
'\u011C': 'G',
'\u1E20': 'G',
'\u011E': 'G',
'\u0120': 'G',
'\u01E6': 'G',
'\u0122': 'G',
'\u01E4': 'G',
'\u0193': 'G',
'\uA7A0': 'G',
'\uA77D': 'G',
'\uA77E': 'G',
'\u24BD': 'H',
'\uFF28': 'H',
'\u0124': 'H',
'\u1E22': 'H',
'\u1E26': 'H',
'\u021E': 'H',
'\u1E24': 'H',
'\u1E28': 'H',
'\u1E2A': 'H',
'\u0126': 'H',
'\u2C67': 'H',
'\u2C75': 'H',
'\uA78D': 'H',
'\u24BE': 'I',
'\uFF29': 'I',
'\u00CC': 'I',
'\u00CD': 'I',
'\u00CE': 'I',
'\u0128': 'I',
'\u012A': 'I',
'\u012C': 'I',
'\u0130': 'I',
'\u00CF': 'I',
'\u1E2E': 'I',
'\u1EC8': 'I',
'\u01CF': 'I',
'\u0208': 'I',
'\u020A': 'I',
'\u1ECA': 'I',
'\u012E': 'I',
'\u1E2C': 'I',
'\u0197': 'I',
'\u24BF': 'J',
'\uFF2A': 'J',
'\u0134': 'J',
'\u0248': 'J',
'\u24C0': 'K',
'\uFF2B': 'K',
'\u1E30': 'K',
'\u01E8': 'K',
'\u1E32': 'K',
'\u0136': 'K',
'\u1E34': 'K',
'\u0198': 'K',
'\u2C69': 'K',
'\uA740': 'K',
'\uA742': 'K',
'\uA744': 'K',
'\uA7A2': 'K',
'\u24C1': 'L',
'\uFF2C': 'L',
'\u013F': 'L',
'\u0139': 'L',
'\u013D': 'L',
'\u1E36': 'L',
'\u1E38': 'L',
'\u013B': 'L',
'\u1E3C': 'L',
'\u1E3A': 'L',
'\u0141': 'L',
'\u023D': 'L',
'\u2C62': 'L',
'\u2C60': 'L',
'\uA748': 'L',
'\uA746': 'L',
'\uA780': 'L',
'\u01C7': 'LJ',
'\u01C8': 'Lj',
'\u24C2': 'M',
'\uFF2D': 'M',
'\u1E3E': 'M',
'\u1E40': 'M',
'\u1E42': 'M',
'\u2C6E': 'M',
'\u019C': 'M',
'\u24C3': 'N',
'\uFF2E': 'N',
'\u01F8': 'N',
'\u0143': 'N',
'\u00D1': 'N',
'\u1E44': 'N',
'\u0147': 'N',
'\u1E46': 'N',
'\u0145': 'N',
'\u1E4A': 'N',
'\u1E48': 'N',
'\u0220': 'N',
'\u019D': 'N',
'\uA790': 'N',
'\uA7A4': 'N',
'\u01CA': 'NJ',
'\u01CB': 'Nj',
'\u24C4': 'O',
'\uFF2F': 'O',
'\u00D2': 'O',
'\u00D3': 'O',
'\u00D4': 'O',
'\u1ED2': 'O',
'\u1ED0': 'O',
'\u1ED6': 'O',
'\u1ED4': 'O',
'\u00D5': 'O',
'\u1E4C': 'O',
'\u022C': 'O',
'\u1E4E': 'O',
'\u014C': 'O',
'\u1E50': 'O',
'\u1E52': 'O',
'\u014E': 'O',
'\u022E': 'O',
'\u0230': 'O',
'\u00D6': 'O',
'\u022A': 'O',
'\u1ECE': 'O',
'\u0150': 'O',
'\u01D1': 'O',
'\u020C': 'O',
'\u020E': 'O',
'\u01A0': 'O',
'\u1EDC': 'O',
'\u1EDA': 'O',
'\u1EE0': 'O',
'\u1EDE': 'O',
'\u1EE2': 'O',
'\u1ECC': 'O',
'\u1ED8': 'O',
'\u01EA': 'O',
'\u01EC': 'O',
'\u00D8': 'O',
'\u01FE': 'O',
'\u0186': 'O',
'\u019F': 'O',
'\uA74A': 'O',
'\uA74C': 'O',
'\u0152': 'OE',
'\u01A2': 'OI',
'\uA74E': 'OO',
'\u0222': 'OU',
'\u24C5': 'P',
'\uFF30': 'P',
'\u1E54': 'P',
'\u1E56': 'P',
'\u01A4': 'P',
'\u2C63': 'P',
'\uA750': 'P',
'\uA752': 'P',
'\uA754': 'P',
'\u24C6': 'Q',
'\uFF31': 'Q',
'\uA756': 'Q',
'\uA758': 'Q',
'\u024A': 'Q',
'\u24C7': 'R',
'\uFF32': 'R',
'\u0154': 'R',
'\u1E58': 'R',
'\u0158': 'R',
'\u0210': 'R',
'\u0212': 'R',
'\u1E5A': 'R',
'\u1E5C': 'R',
'\u0156': 'R',
'\u1E5E': 'R',
'\u024C': 'R',
'\u2C64': 'R',
'\uA75A': 'R',
'\uA7A6': 'R',
'\uA782': 'R',
'\u24C8': 'S',
'\uFF33': 'S',
'\u1E9E': 'S',
'\u015A': 'S',
'\u1E64': 'S',
'\u015C': 'S',
'\u1E60': 'S',
'\u0160': 'S',
'\u1E66': 'S',
'\u1E62': 'S',
'\u1E68': 'S',
'\u0218': 'S',
'\u015E': 'S',
'\u2C7E': 'S',
'\uA7A8': 'S',
'\uA784': 'S',
'\u24C9': 'T',
'\uFF34': 'T',
'\u1E6A': 'T',
'\u0164': 'T',
'\u1E6C': 'T',
'\u021A': 'T',
'\u0162': 'T',
'\u1E70': 'T',
'\u1E6E': 'T',
'\u0166': 'T',
'\u01AC': 'T',
'\u01AE': 'T',
'\u023E': 'T',
'\uA786': 'T',
'\uA728': 'TZ',
'\u24CA': 'U',
'\uFF35': 'U',
'\u00D9': 'U',
'\u00DA': 'U',
'\u00DB': 'U',
'\u0168': 'U',
'\u1E78': 'U',
'\u016A': 'U',
'\u1E7A': 'U',
'\u016C': 'U',
'\u00DC': 'U',
'\u01DB': 'U',
'\u01D7': 'U',
'\u01D5': 'U',
'\u01D9': 'U',
'\u1EE6': 'U',
'\u016E': 'U',
'\u0170': 'U',
'\u01D3': 'U',
'\u0214': 'U',
'\u0216': 'U',
'\u01AF': 'U',
'\u1EEA': 'U',
'\u1EE8': 'U',
'\u1EEE': 'U',
'\u1EEC': 'U',
'\u1EF0': 'U',
'\u1EE4': 'U',
'\u1E72': 'U',
'\u0172': 'U',
'\u1E76': 'U',
'\u1E74': 'U',
'\u0244': 'U',
'\u24CB': 'V',
'\uFF36': 'V',
'\u1E7C': 'V',
'\u1E7E': 'V',
'\u01B2': 'V',
'\uA75E': 'V',
'\u0245': 'V',
'\uA760': 'VY',
'\u24CC': 'W',
'\uFF37': 'W',
'\u1E80': 'W',
'\u1E82': 'W',
'\u0174': 'W',
'\u1E86': 'W',
'\u1E84': 'W',
'\u1E88': 'W',
'\u2C72': 'W',
'\u24CD': 'X',
'\uFF38': 'X',
'\u1E8A': 'X',
'\u1E8C': 'X',
'\u24CE': 'Y',
'\uFF39': 'Y',
'\u1EF2': 'Y',
'\u00DD': 'Y',
'\u0176': 'Y',
'\u1EF8': 'Y',
'\u0232': 'Y',
'\u1E8E': 'Y',
'\u0178': 'Y',
'\u1EF6': 'Y',
'\u1EF4': 'Y',
'\u01B3': 'Y',
'\u024E': 'Y',
'\u1EFE': 'Y',
'\u24CF': 'Z',
'\uFF3A': 'Z',
'\u0179': 'Z',
'\u1E90': 'Z',
'\u017B': 'Z',
'\u017D': 'Z',
'\u1E92': 'Z',
'\u1E94': 'Z',
'\u01B5': 'Z',
'\u0224': 'Z',
'\u2C7F': 'Z',
'\u2C6B': 'Z',
'\uA762': 'Z',
'\u24D0': 'a',
'\uFF41': 'a',
'\u1E9A': 'a',
'\u00E0': 'a',
'\u00E1': 'a',
'\u00E2': 'a',
'\u1EA7': 'a',
'\u1EA5': 'a',
'\u1EAB': 'a',
'\u1EA9': 'a',
'\u00E3': 'a',
'\u0101': 'a',
'\u0103': 'a',
'\u1EB1': 'a',
'\u1EAF': 'a',
'\u1EB5': 'a',
'\u1EB3': 'a',
'\u0227': 'a',
'\u01E1': 'a',
'\u00E4': 'a',
'\u01DF': 'a',
'\u1EA3': 'a',
'\u00E5': 'a',
'\u01FB': 'a',
'\u01CE': 'a',
'\u0201': 'a',
'\u0203': 'a',
'\u1EA1': 'a',
'\u1EAD': 'a',
'\u1EB7': 'a',
'\u1E01': 'a',
'\u0105': 'a',
'\u2C65': 'a',
'\u0250': 'a',
'\uA733': 'aa',
'\u00E6': 'ae',
'\u01FD': 'ae',
'\u01E3': 'ae',
'\uA735': 'ao',
'\uA737': 'au',
'\uA739': 'av',
'\uA73B': 'av',
'\uA73D': 'ay',
'\u24D1': 'b',
'\uFF42': 'b',
'\u1E03': 'b',
'\u1E05': 'b',
'\u1E07': 'b',
'\u0180': 'b',
'\u0183': 'b',
'\u0253': 'b',
'\u24D2': 'c',
'\uFF43': 'c',
'\u0107': 'c',
'\u0109': 'c',
'\u010B': 'c',
'\u010D': 'c',
'\u00E7': 'c',
'\u1E09': 'c',
'\u0188': 'c',
'\u023C': 'c',
'\uA73F': 'c',
'\u2184': 'c',
'\u24D3': 'd',
'\uFF44': 'd',
'\u1E0B': 'd',
'\u010F': 'd',
'\u1E0D': 'd',
'\u1E11': 'd',
'\u1E13': 'd',
'\u1E0F': 'd',
'\u0111': 'd',
'\u018C': 'd',
'\u0256': 'd',
'\u0257': 'd',
'\uA77A': 'd',
'\u01F3': 'dz',
'\u01C6': 'dz',
'\u24D4': 'e',
'\uFF45': 'e',
'\u00E8': 'e',
'\u00E9': 'e',
'\u00EA': 'e',
'\u1EC1': 'e',
'\u1EBF': 'e',
'\u1EC5': 'e',
'\u1EC3': 'e',
'\u1EBD': 'e',
'\u0113': 'e',
'\u1E15': 'e',
'\u1E17': 'e',
'\u0115': 'e',
'\u0117': 'e',
'\u00EB': 'e',
'\u1EBB': 'e',
'\u011B': 'e',
'\u0205': 'e',
'\u0207': 'e',
'\u1EB9': 'e',
'\u1EC7': 'e',
'\u0229': 'e',
'\u1E1D': 'e',
'\u0119': 'e',
'\u1E19': 'e',
'\u1E1B': 'e',
'\u0247': 'e',
'\u025B': 'e',
'\u01DD': 'e',
'\u24D5': 'f',
'\uFF46': 'f',
'\u1E1F': 'f',
'\u0192': 'f',
'\uA77C': 'f',
'\u24D6': 'g',
'\uFF47': 'g',
'\u01F5': 'g',
'\u011D': 'g',
'\u1E21': 'g',
'\u011F': 'g',
'\u0121': 'g',
'\u01E7': 'g',
'\u0123': 'g',
'\u01E5': 'g',
'\u0260': 'g',
'\uA7A1': 'g',
'\u1D79': 'g',
'\uA77F': 'g',
'\u24D7': 'h',
'\uFF48': 'h',
'\u0125': 'h',
'\u1E23': 'h',
'\u1E27': 'h',
'\u021F': 'h',
'\u1E25': 'h',
'\u1E29': 'h',
'\u1E2B': 'h',
'\u1E96': 'h',
'\u0127': 'h',
'\u2C68': 'h',
'\u2C76': 'h',
'\u0265': 'h',
'\u0195': 'hv',
'\u24D8': 'i',
'\uFF49': 'i',
'\u00EC': 'i',
'\u00ED': 'i',
'\u00EE': 'i',
'\u0129': 'i',
'\u012B': 'i',
'\u012D': 'i',
'\u00EF': 'i',
'\u1E2F': 'i',
'\u1EC9': 'i',
'\u01D0': 'i',
'\u0209': 'i',
'\u020B': 'i',
'\u1ECB': 'i',
'\u012F': 'i',
'\u1E2D': 'i',
'\u0268': 'i',
'\u0131': 'i',
'\u24D9': 'j',
'\uFF4A': 'j',
'\u0135': 'j',
'\u01F0': 'j',
'\u0249': 'j',
'\u24DA': 'k',
'\uFF4B': 'k',
'\u1E31': 'k',
'\u01E9': 'k',
'\u1E33': 'k',
'\u0137': 'k',
'\u1E35': 'k',
'\u0199': 'k',
'\u2C6A': 'k',
'\uA741': 'k',
'\uA743': 'k',
'\uA745': 'k',
'\uA7A3': 'k',
'\u24DB': 'l',
'\uFF4C': 'l',
'\u0140': 'l',
'\u013A': 'l',
'\u013E': 'l',
'\u1E37': 'l',
'\u1E39': 'l',
'\u013C': 'l',
'\u1E3D': 'l',
'\u1E3B': 'l',
'\u017F': 'l',
'\u0142': 'l',
'\u019A': 'l',
'\u026B': 'l',
'\u2C61': 'l',
'\uA749': 'l',
'\uA781': 'l',
'\uA747': 'l',
'\u01C9': 'lj',
'\u24DC': 'm',
'\uFF4D': 'm',
'\u1E3F': 'm',
'\u1E41': 'm',
'\u1E43': 'm',
'\u0271': 'm',
'\u026F': 'm',
'\u24DD': 'n',
'\uFF4E': 'n',
'\u01F9': 'n',
'\u0144': 'n',
'\u00F1': 'n',
'\u1E45': 'n',
'\u0148': 'n',
'\u1E47': 'n',
'\u0146': 'n',
'\u1E4B': 'n',
'\u1E49': 'n',
'\u019E': 'n',
'\u0272': 'n',
'\u0149': 'n',
'\uA791': 'n',
'\uA7A5': 'n',
'\u01CC': 'nj',
'\u24DE': 'o',
'\uFF4F': 'o',
'\u00F2': 'o',
'\u00F3': 'o',
'\u00F4': 'o',
'\u1ED3': 'o',
'\u1ED1': 'o',
'\u1ED7': 'o',
'\u1ED5': 'o',
'\u00F5': 'o',
'\u1E4D': 'o',
'\u022D': 'o',
'\u1E4F': 'o',
'\u014D': 'o',
'\u1E51': 'o',
'\u1E53': 'o',
'\u014F': 'o',
'\u022F': 'o',
'\u0231': 'o',
'\u00F6': 'o',
'\u022B': 'o',
'\u1ECF': 'o',
'\u0151': 'o',
'\u01D2': 'o',
'\u020D': 'o',
'\u020F': 'o',
'\u01A1': 'o',
'\u1EDD': 'o',
'\u1EDB': 'o',
'\u1EE1': 'o',
'\u1EDF': 'o',
'\u1EE3': 'o',
'\u1ECD': 'o',
'\u1ED9': 'o',
'\u01EB': 'o',
'\u01ED': 'o',
'\u00F8': 'o',
'\u01FF': 'o',
'\u0254': 'o',
'\uA74B': 'o',
'\uA74D': 'o',
'\u0275': 'o',
'\u0153': 'oe',
'\u01A3': 'oi',
'\u0223': 'ou',
'\uA74F': 'oo',
'\u24DF': 'p',
'\uFF50': 'p',
'\u1E55': 'p',
'\u1E57': 'p',
'\u01A5': 'p',
'\u1D7D': 'p',
'\uA751': 'p',
'\uA753': 'p',
'\uA755': 'p',
'\u24E0': 'q',
'\uFF51': 'q',
'\u024B': 'q',
'\uA757': 'q',
'\uA759': 'q',
'\u24E1': 'r',
'\uFF52': 'r',
'\u0155': 'r',
'\u1E59': 'r',
'\u0159': 'r',
'\u0211': 'r',
'\u0213': 'r',
'\u1E5B': 'r',
'\u1E5D': 'r',
'\u0157': 'r',
'\u1E5F': 'r',
'\u024D': 'r',
'\u027D': 'r',
'\uA75B': 'r',
'\uA7A7': 'r',
'\uA783': 'r',
'\u24E2': 's',
'\uFF53': 's',
'\u00DF': 's',
'\u015B': 's',
'\u1E65': 's',
'\u015D': 's',
'\u1E61': 's',
'\u0161': 's',
'\u1E67': 's',
'\u1E63': 's',
'\u1E69': 's',
'\u0219': 's',
'\u015F': 's',
'\u023F': 's',
'\uA7A9': 's',
'\uA785': 's',
'\u1E9B': 's',
'\u24E3': 't',
'\uFF54': 't',
'\u1E6B': 't',
'\u1E97': 't',
'\u0165': 't',
'\u1E6D': 't',
'\u021B': 't',
'\u0163': 't',
'\u1E71': 't',
'\u1E6F': 't',
'\u0167': 't',
'\u01AD': 't',
'\u0288': 't',
'\u2C66': 't',
'\uA787': 't',
'\uA729': 'tz',
'\u24E4': 'u',
'\uFF55': 'u',
'\u00F9': 'u',
'\u00FA': 'u',
'\u00FB': 'u',
'\u0169': 'u',
'\u1E79': 'u',
'\u016B': 'u',
'\u1E7B': 'u',
'\u016D': 'u',
'\u00FC': 'u',
'\u01DC': 'u',
'\u01D8': 'u',
'\u01D6': 'u',
'\u01DA': 'u',
'\u1EE7': 'u',
'\u016F': 'u',
'\u0171': 'u',
'\u01D4': 'u',
'\u0215': 'u',
'\u0217': 'u',
'\u01B0': 'u',
'\u1EEB': 'u',
'\u1EE9': 'u',
'\u1EEF': 'u',
'\u1EED': 'u',
'\u1EF1': 'u',
'\u1EE5': 'u',
'\u1E73': 'u',
'\u0173': 'u',
'\u1E77': 'u',
'\u1E75': 'u',
'\u0289': 'u',
'\u24E5': 'v',
'\uFF56': 'v',
'\u1E7D': 'v',
'\u1E7F': 'v',
'\u028B': 'v',
'\uA75F': 'v',
'\u028C': 'v',
'\uA761': 'vy',
'\u24E6': 'w',
'\uFF57': 'w',
'\u1E81': 'w',
'\u1E83': 'w',
'\u0175': 'w',
'\u1E87': 'w',
'\u1E85': 'w',
'\u1E98': 'w',
'\u1E89': 'w',
'\u2C73': 'w',
'\u24E7': 'x',
'\uFF58': 'x',
'\u1E8B': 'x',
'\u1E8D': 'x',
'\u24E8': 'y',
'\uFF59': 'y',
'\u1EF3': 'y',
'\u00FD': 'y',
'\u0177': 'y',
'\u1EF9': 'y',
'\u0233': 'y',
'\u1E8F': 'y',
'\u00FF': 'y',
'\u1EF7': 'y',
'\u1E99': 'y',
'\u1EF5': 'y',
'\u01B4': 'y',
'\u024F': 'y',
'\u1EFF': 'y',
'\u24E9': 'z',
'\uFF5A': 'z',
'\u017A': 'z',
'\u1E91': 'z',
'\u017C': 'z',
'\u017E': 'z',
'\u1E93': 'z',
'\u1E95': 'z',
'\u01B6': 'z',
'\u0225': 'z',
'\u0240': 'z',
'\u2C6C': 'z',
'\uA763': 'z',
'\u0386': '\u0391',
'\u0388': '\u0395',
'\u0389': '\u0397',
'\u038A': '\u0399',
'\u03AA': '\u0399',
'\u038C': '\u039F',
'\u038E': '\u03A5',
'\u03AB': '\u03A5',
'\u038F': '\u03A9',
'\u03AC': '\u03B1',
'\u03AD': '\u03B5',
'\u03AE': '\u03B7',
'\u03AF': '\u03B9',
'\u03CA': '\u03B9',
'\u0390': '\u03B9',
'\u03CC': '\u03BF',
'\u03CD': '\u03C5',
'\u03CB': '\u03C5',
'\u03B0': '\u03C5',
'\u03CE': '\u03C9',
'\u03C2': '\u03C3',
'\u2019': '\''
};
return diacritics;
});
S2.define('select2/data/base',[
'../utils'
], function (Utils) {
function BaseAdapter ($element, options) {
BaseAdapter.__super__.constructor.call(this);
}
Utils.Extend(BaseAdapter, Utils.Observable);
BaseAdapter.prototype.current = function (callback) {
throw new Error('The `current` method must be defined in child classes.');
};
BaseAdapter.prototype.query = function (params, callback) {
throw new Error('The `query` method must be defined in child classes.');
};
BaseAdapter.prototype.bind = function (container, $container) {
// Can be implemented in subclasses
};
BaseAdapter.prototype.destroy = function () {
// Can be implemented in subclasses
};
BaseAdapter.prototype.generateResultId = function (container, data) {
var id = container.id + '-result-';
id += Utils.generateChars(4);
if (data.id != null) {
id += '-' + data.id.toString();
} else {
id += '-' + Utils.generateChars(4);
}
return id;
};
return BaseAdapter;
});
S2.define('select2/data/select',[
'./base',
'../utils',
'jquery'
], function (BaseAdapter, Utils, $) {
function SelectAdapter ($element, options) {
this.$element = $element;
this.options = options;
SelectAdapter.__super__.constructor.call(this);
}
Utils.Extend(SelectAdapter, BaseAdapter);
SelectAdapter.prototype.current = function (callback) {
var data = [];
var self = this;
this.$element.find(':selected').each(function () {
var $option = $(this);
var option = self.item($option);
data.push(option);
});
callback(data);
};
SelectAdapter.prototype.select = function (data) {
var self = this;
data.selected = true;
// If data.element is a DOM node, use it instead
if ($(data.element).is('option')) {
data.element.selected = true;
this.$element.trigger('change');
return;
}
if (this.$element.prop('multiple')) {
this.current(function (currentData) {
var val = [];
data = [data];
data.push.apply(data, currentData);
for (var d = 0; d < data.length; d++) {
var id = data[d].id;
if ($.inArray(id, val) === -1) {
val.push(id);
}
}
self.$element.val(val);
self.$element.trigger('change');
});
} else {
var val = data.id;
this.$element.val(val);
this.$element.trigger('change');
}
};
SelectAdapter.prototype.unselect = function (data) {
var self = this;
if (!this.$element.prop('multiple')) {
return;
}
data.selected = false;
if ($(data.element).is('option')) {
data.element.selected = false;
this.$element.trigger('change');
return;
}
this.current(function (currentData) {
var val = [];
for (var d = 0; d < currentData.length; d++) {
var id = currentData[d].id;
if (id !== data.id && $.inArray(id, val) === -1) {
val.push(id);
}
}
self.$element.val(val);
self.$element.trigger('change');
});
};
SelectAdapter.prototype.bind = function (container, $container) {
var self = this;
this.container = container;
container.on('select', function (params) {
self.select(params.data);
});
container.on('unselect', function (params) {
self.unselect(params.data);
});
};
SelectAdapter.prototype.destroy = function () {
// Remove anything added to child elements
this.$element.find('*').each(function () {
// Remove any custom data set by Select2
Utils.RemoveData(this);
});
};
SelectAdapter.prototype.query = function (params, callback) {
var data = [];
var self = this;
var $options = this.$element.children();
$options.each(function () {
var $option = $(this);
if (!$option.is('option') && !$option.is('optgroup')) {
return;
}
var option = self.item($option);
var matches = self.matches(params, option);
if (matches !== null) {
data.push(matches);
}
});
callback({
results: data
});
};
SelectAdapter.prototype.addOptions = function ($options) {
Utils.appendMany(this.$element, $options);
};
SelectAdapter.prototype.option = function (data) {
var option;
if (data.children) {
option = document.createElement('optgroup');
option.label = data.text;
} else {
option = document.createElement('option');
if (option.textContent !== undefined) {
option.textContent = data.text;
} else {
option.innerText = data.text;
}
}
if (data.id !== undefined) {
option.value = data.id;
}
if (data.disabled) {
option.disabled = true;
}
if (data.selected) {
option.selected = true;
}
if (data.title) {
option.title = data.title;
}
var $option = $(option);
var normalizedData = this._normalizeItem(data);
normalizedData.element = option;
// Override the option's data with the combined data
Utils.StoreData(option, 'data', normalizedData);
return $option;
};
SelectAdapter.prototype.item = function ($option) {
var data = {};
data = Utils.GetData($option[0], 'data');
if (data != null) {
return data;
}
if ($option.is('option')) {
data = {
id: $option.val(),
text: $option.text(),
disabled: $option.prop('disabled'),
selected: $option.prop('selected'),
title: $option.prop('title')
};
} else if ($option.is('optgroup')) {
data = {
text: $option.prop('label'),
children: [],
title: $option.prop('title')
};
var $children = $option.children('option');
var children = [];
for (var c = 0; c < $children.length; c++) {
var $child = $($children[c]);
var child = this.item($child);
children.push(child);
}
data.children = children;
}
data = this._normalizeItem(data);
data.element = $option[0];
Utils.StoreData($option[0], 'data', data);
return data;
};
SelectAdapter.prototype._normalizeItem = function (item) {
if (item !== Object(item)) {
item = {
id: item,
text: item
};
}
item = $.extend({}, {
text: ''
}, item);
var defaults = {
selected: false,
disabled: false
};
if (item.id != null) {
item.id = item.id.toString();
}
if (item.text != null) {
item.text = item.text.toString();
}
if (item._resultId == null && item.id && this.container != null) {
item._resultId = this.generateResultId(this.container, item);
}
return $.extend({}, defaults, item);
};
SelectAdapter.prototype.matches = function (params, data) {
var matcher = this.options.get('matcher');
return matcher(params, data);
};
return SelectAdapter;
});
S2.define('select2/data/array',[
'./select',
'../utils',
'jquery'
], function (SelectAdapter, Utils, $) {
function ArrayAdapter ($element, options) {
this._dataToConvert = options.get('data') || [];
ArrayAdapter.__super__.constructor.call(this, $element, options);
}
Utils.Extend(ArrayAdapter, SelectAdapter);
ArrayAdapter.prototype.bind = function (container, $container) {
ArrayAdapter.__super__.bind.call(this, container, $container);
this.addOptions(this.convertToOptions(this._dataToConvert));
};
ArrayAdapter.prototype.select = function (data) {
var $option = this.$element.find('option').filter(function (i, elm) {
return elm.value == data.id.toString();
});
if ($option.length === 0) {
$option = this.option(data);
this.addOptions($option);
}
ArrayAdapter.__super__.select.call(this, data);
};
ArrayAdapter.prototype.convertToOptions = function (data) {
var self = this;
var $existing = this.$element.find('option');
var existingIds = $existing.map(function () {
return self.item($(this)).id;
}).get();
var $options = [];
// Filter out all items except for the one passed in the argument
function onlyItem (item) {
return function () {
return $(this).val() == item.id;
};
}
for (var d = 0; d < data.length; d++) {
var item = this._normalizeItem(data[d]);
// Skip items which were pre-loaded, only merge the data
if ($.inArray(item.id, existingIds) >= 0) {
var $existingOption = $existing.filter(onlyItem(item));
var existingData = this.item($existingOption);
var newData = $.extend(true, {}, item, existingData);
var $newOption = this.option(newData);
$existingOption.replaceWith($newOption);
continue;
}
var $option = this.option(item);
if (item.children) {
var $children = this.convertToOptions(item.children);
Utils.appendMany($option, $children);
}
$options.push($option);
}
return $options;
};
return ArrayAdapter;
});
S2.define('select2/data/ajax',[
'./array',
'../utils',
'jquery'
], function (ArrayAdapter, Utils, $) {
function AjaxAdapter ($element, options) {
this.ajaxOptions = this._applyDefaults(options.get('ajax'));
if (this.ajaxOptions.processResults != null) {
this.processResults = this.ajaxOptions.processResults;
}
AjaxAdapter.__super__.constructor.call(this, $element, options);
}
Utils.Extend(AjaxAdapter, ArrayAdapter);
AjaxAdapter.prototype._applyDefaults = function (options) {
var defaults = {
data: function (params) {
return $.extend({}, params, {
q: params.term
});
},
transport: function (params, success, failure) {
var $request = $.ajax(params);
$request.then(success);
$request.fail(failure);
return $request;
}
};
return $.extend({}, defaults, options, true);
};
AjaxAdapter.prototype.processResults = function (results) {
return results;
};
AjaxAdapter.prototype.query = function (params, callback) {
var matches = [];
var self = this;
if (this._request != null) {
// JSONP requests cannot always be aborted
if ($.isFunction(this._request.abort)) {
this._request.abort();
}
this._request = null;
}
var options = $.extend({
type: 'GET'
}, this.ajaxOptions);
if (typeof options.url === 'function') {
options.url = options.url.call(this.$element, params);
}
if (typeof options.data === 'function') {
options.data = options.data.call(this.$element, params);
}
function request () {
var $request = options.transport(options, function (data) {
var results = self.processResults(data, params);
if (self.options.get('debug') && window.console && console.error) {
// Check to make sure that the response included a `results` key.
if (!results || !results.results || !$.isArray(results.results)) {
console.error(
'Select2: The AJAX results did not return an array in the ' +
'`results` key of the response.'
);
}
}
callback(results);
}, function () {
// Attempt to detect if a request was aborted
// Only works if the transport exposes a status property
if ('status' in $request &&
($request.status === 0 || $request.status === '0')) {
return;
}
self.trigger('results:message', {
message: 'errorLoading'
});
});
self._request = $request;
}
if (this.ajaxOptions.delay && params.term != null) {
if (this._queryTimeout) {
window.clearTimeout(this._queryTimeout);
}
this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
} else {
request();
}
};
return AjaxAdapter;
});
S2.define('select2/data/tags',[
'jquery'
], function ($) {
function Tags (decorated, $element, options) {
var tags = options.get('tags');
var createTag = options.get('createTag');
if (createTag !== undefined) {
this.createTag = createTag;
}
var insertTag = options.get('insertTag');
if (insertTag !== undefined) {
this.insertTag = insertTag;
}
decorated.call(this, $element, options);
if ($.isArray(tags)) {
for (var t = 0; t < tags.length; t++) {
var tag = tags[t];
var item = this._normalizeItem(tag);
var $option = this.option(item);
this.$element.append($option);
}
}
}
Tags.prototype.query = function (decorated, params, callback) {
var self = this;
this._removeOldTags();
if (params.term == null || params.page != null) {
decorated.call(this, params, callback);
return;
}
function wrapper (obj, child) {
var data = obj.results;
for (var i = 0; i < data.length; i++) {
var option = data[i];
var checkChildren = (
option.children != null &&
!wrapper({
results: option.children
}, true)
);
var optionText = (option.text || '').toUpperCase();
var paramsTerm = (params.term || '').toUpperCase();
var checkText = optionText === paramsTerm;
if (checkText || checkChildren) {
if (child) {
return false;
}
obj.data = data;
callback(obj);
return;
}
}
if (child) {
return true;
}
var tag = self.createTag(params);
if (tag != null) {
var $option = self.option(tag);
$option.attr('data-select2-tag', true);
self.addOptions([$option]);
self.insertTag(data, tag);
}
obj.results = data;
callback(obj);
}
decorated.call(this, params, wrapper);
};
Tags.prototype.createTag = function (decorated, params) {
var term = $.trim(params.term);
if (term === '') {
return null;
}
return {
id: term,
text: term
};
};
Tags.prototype.insertTag = function (_, data, tag) {
data.unshift(tag);
};
Tags.prototype._removeOldTags = function (_) {
var $options = this.$element.find('option[data-select2-tag]');
$options.each(function () {
if (this.selected) {
return;
}
$(this).remove();
});
};
return Tags;
});
S2.define('select2/data/tokenizer',[
'jquery'
], function ($) {
function Tokenizer (decorated, $element, options) {
var tokenizer = options.get('tokenizer');
if (tokenizer !== undefined) {
this.tokenizer = tokenizer;
}
decorated.call(this, $element, options);
}
Tokenizer.prototype.bind = function (decorated, container, $container) {
decorated.call(this, container, $container);
this.$search = container.dropdown.$search || container.selection.$search ||
$container.find('.select2-search__field');
};
Tokenizer.prototype.query = function (decorated, params, callback) {
var self = this;
function createAndSelect (data) {
// Normalize the data object so we can use it for checks
var item = self._normalizeItem(data);
// Check if the data object already exists as a tag
// Select it if it doesn't
var $existingOptions = self.$element.find('option').filter(function () {
return $(this).val() === item.id;
});
// If an existing option wasn't found for it, create the option
if (!$existingOptions.length) {
var $option = self.option(item);
$option.attr('data-select2-tag', true);
self._removeOldTags();
self.addOptions([$option]);
}
// Select the item, now that we know there is an option for it
select(item);
}
function select (data) {
self.trigger('select', {
data: data
});
}
params.term = params.term || '';
var tokenData = this.tokenizer(params, this.options, createAndSelect);
if (tokenData.term !== params.term) {
// Replace the search term if we have the search box
if (this.$search.length) {
this.$search.val(tokenData.term);
this.$search.trigger('focus');
}
params.term = tokenData.term;
}
decorated.call(this, params, callback);
};
Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
var separators = options.get('tokenSeparators') || [];
var term = params.term;
var i = 0;
var createTag = this.createTag || function (params) {
return {
id: params.term,
text: params.term
};
};
while (i < term.length) {
var termChar = term[i];
if ($.inArray(termChar, separators) === -1) {
i++;
continue;
}
var part = term.substr(0, i);
var partParams = $.extend({}, params, {
term: part
});
var data = createTag(partParams);
if (data == null) {
i++;
continue;
}
callback(data);
// Reset the term to not include the tokenized portion
term = term.substr(i + 1) || '';
i = 0;
}
return {
term: term
};
};
return Tokenizer;
});
S2.define('select2/data/minimumInputLength',[
], function () {
function MinimumInputLength (decorated, $e, options) {
this.minimumInputLength = options.get('minimumInputLength');
decorated.call(this, $e, options);
}
MinimumInputLength.prototype.query = function (decorated, params, callback) {
params.term = params.term || '';
if (params.term.length < this.minimumInputLength) {
this.trigger('results:message', {
message: 'inputTooShort',
args: {
minimum: this.minimumInputLength,
input: params.term,
params: params
}
});
return;
}
decorated.call(this, params, callback);
};
return MinimumInputLength;
});
S2.define('select2/data/maximumInputLength',[
], function () {
function MaximumInputLength (decorated, $e, options) {
this.maximumInputLength = options.get('maximumInputLength');
decorated.call(this, $e, options);
}
MaximumInputLength.prototype.query = function (decorated, params, callback) {
params.term = params.term || '';
if (this.maximumInputLength > 0 &&
params.term.length > this.maximumInputLength) {
this.trigger('results:message', {
message: 'inputTooLong',
args: {
maximum: this.maximumInputLength,
input: params.term,
params: params
}
});
return;
}
decorated.call(this, params, callback);
};
return MaximumInputLength;
});
S2.define('select2/data/maximumSelectionLength',[
], function (){
function MaximumSelectionLength (decorated, $e, options) {
this.maximumSelectionLength = options.get('maximumSelectionLength');
decorated.call(this, $e, options);
}
MaximumSelectionLength.prototype.bind =
function (decorated, container, $container) {
var self = this;
decorated.call(this, container, $container);
container.on('select', function () {
self._checkIfMaximumSelected();
});
};
MaximumSelectionLength.prototype.query =
function (decorated, params, callback) {
var self = this;
this._checkIfMaximumSelected(function () {
decorated.call(self, params, callback);
});
};
MaximumSelectionLength.prototype._checkIfMaximumSelected =
function (_, successCallback) {
var self = this;
this.current(function (currentData) {
var count = currentData != null ? currentData.length : 0;
if (self.maximumSelectionLength > 0 &&
count >= self.maximumSelectionLength) {
self.trigger('results:message', {
message: 'maximumSelected',
args: {
maximum: self.maximumSelectionLength
}
});
return;
}
if (successCallback) {
successCallback();
}
});
};
return MaximumSelectionLength;
});
S2.define('select2/dropdown',[
'jquery',
'./utils'
], function ($, Utils) {
function Dropdown ($element, options) {
this.$element = $element;
this.options = options;
Dropdown.__super__.constructor.call(this);
}
Utils.Extend(Dropdown, Utils.Observable);
Dropdown.prototype.render = function () {
var $dropdown = $(
'' +
' ' +
' '
);
$dropdown.attr('dir', this.options.get('dir'));
this.$dropdown = $dropdown;
return $dropdown;
};
Dropdown.prototype.bind = function () {
// Should be implemented in subclasses
};
Dropdown.prototype.position = function ($dropdown, $container) {
// Should be implemented in subclasses
};
Dropdown.prototype.destroy = function () {
// Remove the dropdown from the DOM
this.$dropdown.remove();
};
return Dropdown;
});
S2.define('select2/dropdown/search',[
'jquery',
'../utils'
], function ($, Utils) {
function Search () { }
Search.prototype.render = function (decorated) {
var $rendered = decorated.call(this);
var $search = $(
'' +
' ' +
' '
);
this.$searchContainer = $search;
this.$search = $search.find('input');
$rendered.prepend($search);
return $rendered;
};
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
var resultsId = container.id + '-results';
decorated.call(this, container, $container);
this.$search.on('keydown', function (evt) {
self.trigger('keypress', evt);
self._keyUpPrevented = evt.isDefaultPrevented();
});
// Workaround for browsers which do not support the `input` event
// This will prevent double-triggering of events for browsers which support
// both the `keyup` and `input` events.
this.$search.on('input', function (evt) {
// Unbind the duplicated `keyup` event
$(this).off('keyup');
});
this.$search.on('keyup input', function (evt) {
self.handleSearch(evt);
});
container.on('open', function () {
self.$search.attr('tabindex', 0);
self.$search.attr('aria-controls', resultsId);
self.$search.trigger('focus');
window.setTimeout(function () {
self.$search.trigger('focus');
}, 0);
});
container.on('close', function () {
self.$search.attr('tabindex', -1);
self.$search.removeAttr('aria-controls');
self.$search.removeAttr('aria-activedescendant');
self.$search.val('');
self.$search.trigger('blur');
});
container.on('focus', function () {
if (!container.isOpen()) {
self.$search.trigger('focus');
}
});
container.on('results:all', function (params) {
if (params.query.term == null || params.query.term === '') {
var showSearch = self.showSearch(params);
if (showSearch) {
self.$searchContainer.removeClass('select2-search--hide');
} else {
self.$searchContainer.addClass('select2-search--hide');
}
}
});
container.on('results:focus', function (params) {
if (params.data._resultId) {
self.$search.attr('aria-activedescendant', params.data._resultId);
} else {
self.$search.removeAttr('aria-activedescendant');
}
});
};
Search.prototype.handleSearch = function (evt) {
if (!this._keyUpPrevented) {
var input = this.$search.val();
this.trigger('query', {
term: input
});
}
this._keyUpPrevented = false;
};
Search.prototype.showSearch = function (_, params) {
return true;
};
return Search;
});
S2.define('select2/dropdown/hidePlaceholder',[
], function () {
function HidePlaceholder (decorated, $element, options, dataAdapter) {
this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
decorated.call(this, $element, options, dataAdapter);
}
HidePlaceholder.prototype.append = function (decorated, data) {
data.results = this.removePlaceholder(data.results);
decorated.call(this, data);
};
HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
if (typeof placeholder === 'string') {
placeholder = {
id: '',
text: placeholder
};
}
return placeholder;
};
HidePlaceholder.prototype.removePlaceholder = function (_, data) {
var modifiedData = data.slice(0);
for (var d = data.length - 1; d >= 0; d--) {
var item = data[d];
if (this.placeholder.id === item.id) {
modifiedData.splice(d, 1);
}
}
return modifiedData;
};
return HidePlaceholder;
});
S2.define('select2/dropdown/infiniteScroll',[
'jquery'
], function ($) {
function InfiniteScroll (decorated, $element, options, dataAdapter) {
this.lastParams = {};
decorated.call(this, $element, options, dataAdapter);
this.$loadingMore = this.createLoadingMore();
this.loading = false;
}
InfiniteScroll.prototype.append = function (decorated, data) {
this.$loadingMore.remove();
this.loading = false;
decorated.call(this, data);
if (this.showLoadingMore(data)) {
this.$results.append(this.$loadingMore);
this.loadMoreIfNeeded();
}
};
InfiniteScroll.prototype.bind = function (decorated, container, $container) {
var self = this;
decorated.call(this, container, $container);
container.on('query', function (params) {
self.lastParams = params;
self.loading = true;
});
container.on('query:append', function (params) {
self.lastParams = params;
self.loading = true;
});
this.$results.on('scroll', this.loadMoreIfNeeded.bind(this));
};
InfiniteScroll.prototype.loadMoreIfNeeded = function () {
var isLoadMoreVisible = $.contains(
document.documentElement,
this.$loadingMore[0]
);
if (this.loading || !isLoadMoreVisible) {
return;
}
var currentOffset = this.$results.offset().top +
this.$results.outerHeight(false);
var loadingMoreOffset = this.$loadingMore.offset().top +
this.$loadingMore.outerHeight(false);
if (currentOffset + 50 >= loadingMoreOffset) {
this.loadMore();
}
};
InfiniteScroll.prototype.loadMore = function () {
this.loading = true;
var params = $.extend({}, {page: 1}, this.lastParams);
params.page++;
this.trigger('query:append', params);
};
InfiniteScroll.prototype.showLoadingMore = function (_, data) {
return data.pagination && data.pagination.more;
};
InfiniteScroll.prototype.createLoadingMore = function () {
var $option = $(
' '
);
var message = this.options.get('translations').get('loadingMore');
$option.html(message(this.lastParams));
return $option;
};
return InfiniteScroll;
});
S2.define('select2/dropdown/attachBody',[
'jquery',
'../utils'
], function ($, Utils) {
function AttachBody (decorated, $element, options) {
this.$dropdownParent = $(options.get('dropdownParent') || document.body);
decorated.call(this, $element, options);
}
AttachBody.prototype.bind = function (decorated, container, $container) {
var self = this;
decorated.call(this, container, $container);
container.on('open', function () {
self._showDropdown();
self._attachPositioningHandler(container);
// Must bind after the results handlers to ensure correct sizing
self._bindContainerResultHandlers(container);
});
container.on('close', function () {
self._hideDropdown();
self._detachPositioningHandler(container);
});
this.$dropdownContainer.on('mousedown', function (evt) {
evt.stopPropagation();
});
};
AttachBody.prototype.destroy = function (decorated) {
decorated.call(this);
this.$dropdownContainer.remove();
};
AttachBody.prototype.position = function (decorated, $dropdown, $container) {
// Clone all of the container classes
$dropdown.attr('class', $container.attr('class'));
$dropdown.removeClass('select2');
$dropdown.addClass('select2-container--open');
$dropdown.css({
position: 'absolute',
top: -999999
});
this.$container = $container;
};
AttachBody.prototype.render = function (decorated) {
var $container = $(' ');
var $dropdown = decorated.call(this);
$container.append($dropdown);
this.$dropdownContainer = $container;
return $container;
};
AttachBody.prototype._hideDropdown = function (decorated) {
this.$dropdownContainer.detach();
};
AttachBody.prototype._bindContainerResultHandlers =
function (decorated, container) {
// These should only be bound once
if (this._containerResultsHandlersBound) {
return;
}
var self = this;
container.on('results:all', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('results:message', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('select', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('unselect', function () {
self._positionDropdown();
self._resizeDropdown();
});
this._containerResultsHandlersBound = true;
};
AttachBody.prototype._attachPositioningHandler =
function (decorated, container) {
var self = this;
var scrollEvent = 'scroll.select2.' + container.id;
var resizeEvent = 'resize.select2.' + container.id;
var orientationEvent = 'orientationchange.select2.' + container.id;
var $watchers = this.$container.parents().filter(Utils.hasScroll);
$watchers.each(function () {
Utils.StoreData(this, 'select2-scroll-position', {
x: $(this).scrollLeft(),
y: $(this).scrollTop()
});
});
$watchers.on(scrollEvent, function (ev) {
var position = Utils.GetData(this, 'select2-scroll-position');
$(this).scrollTop(position.y);
});
$(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
function (e) {
self._positionDropdown();
self._resizeDropdown();
});
};
AttachBody.prototype._detachPositioningHandler =
function (decorated, container) {
var scrollEvent = 'scroll.select2.' + container.id;
var resizeEvent = 'resize.select2.' + container.id;
var orientationEvent = 'orientationchange.select2.' + container.id;
var $watchers = this.$container.parents().filter(Utils.hasScroll);
$watchers.off(scrollEvent);
$(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
};
AttachBody.prototype._positionDropdown = function () {
var $window = $(window);
var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
var newDirection = null;
var offset = this.$container.offset();
offset.bottom = offset.top + this.$container.outerHeight(false);
var container = {
height: this.$container.outerHeight(false)
};
container.top = offset.top;
container.bottom = offset.top + container.height;
var dropdown = {
height: this.$dropdown.outerHeight(false)
};
var viewport = {
top: $window.scrollTop(),
bottom: $window.scrollTop() + $window.height()
};
var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
var css = {
left: offset.left,
top: container.bottom
};
// Determine what the parent element is to use for calculating the offset
var $offsetParent = this.$dropdownParent;
// For statically positioned elements, we need to get the element
// that is determining the offset
if ($offsetParent.css('position') === 'static') {
$offsetParent = $offsetParent.offsetParent();
}
var parentOffset = {
top: 0,
left: 0
};
if (
$.contains(document.body, $offsetParent[0]) ||
$offsetParent[0].isConnected
) {
parentOffset = $offsetParent.offset();
}
css.top -= parentOffset.top;
css.left -= parentOffset.left;
if (!isCurrentlyAbove && !isCurrentlyBelow) {
newDirection = 'below';
}
if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
newDirection = 'above';
} else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
newDirection = 'below';
}
if (newDirection == 'above' ||
(isCurrentlyAbove && newDirection !== 'below')) {
css.top = container.top - parentOffset.top - dropdown.height;
}
if (newDirection != null) {
this.$dropdown
.removeClass('select2-dropdown--below select2-dropdown--above')
.addClass('select2-dropdown--' + newDirection);
this.$container
.removeClass('select2-container--below select2-container--above')
.addClass('select2-container--' + newDirection);
}
this.$dropdownContainer.css(css);
};
AttachBody.prototype._resizeDropdown = function () {
var css = {
width: this.$container.outerWidth(false) + 'px'
};
if (this.options.get('dropdownAutoWidth')) {
css.minWidth = css.width;
css.position = 'relative';
css.width = 'auto';
}
this.$dropdown.css(css);
};
AttachBody.prototype._showDropdown = function (decorated) {
this.$dropdownContainer.appendTo(this.$dropdownParent);
this._positionDropdown();
this._resizeDropdown();
};
return AttachBody;
});
S2.define('select2/dropdown/minimumResultsForSearch',[
], function () {
function countResults (data) {
var count = 0;
for (var d = 0; d < data.length; d++) {
var item = data[d];
if (item.children) {
count += countResults(item.children);
} else {
count++;
}
}
return count;
}
function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
this.minimumResultsForSearch = options.get('minimumResultsForSearch');
if (this.minimumResultsForSearch < 0) {
this.minimumResultsForSearch = Infinity;
}
decorated.call(this, $element, options, dataAdapter);
}
MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
if (countResults(params.data.results) < this.minimumResultsForSearch) {
return false;
}
return decorated.call(this, params);
};
return MinimumResultsForSearch;
});
S2.define('select2/dropdown/selectOnClose',[
'../utils'
], function (Utils) {
function SelectOnClose () { }
SelectOnClose.prototype.bind = function (decorated, container, $container) {
var self = this;
decorated.call(this, container, $container);
container.on('close', function (params) {
self._handleSelectOnClose(params);
});
};
SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
if (params && params.originalSelect2Event != null) {
var event = params.originalSelect2Event;
// Don't select an item if the close event was triggered from a select or
// unselect event
if (event._type === 'select' || event._type === 'unselect') {
return;
}
}
var $highlightedResults = this.getHighlightedResults();
// Only select highlighted results
if ($highlightedResults.length < 1) {
return;
}
var data = Utils.GetData($highlightedResults[0], 'data');
// Don't re-select already selected resulte
if (
(data.element != null && data.element.selected) ||
(data.element == null && data.selected)
) {
return;
}
this.trigger('select', {
data: data
});
};
return SelectOnClose;
});
S2.define('select2/dropdown/closeOnSelect',[
], function () {
function CloseOnSelect () { }
CloseOnSelect.prototype.bind = function (decorated, container, $container) {
var self = this;
decorated.call(this, container, $container);
container.on('select', function (evt) {
self._selectTriggered(evt);
});
container.on('unselect', function (evt) {
self._selectTriggered(evt);
});
};
CloseOnSelect.prototype._selectTriggered = function (_, evt) {
var originalEvent = evt.originalEvent;
// Don't close if the control key is being held
if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) {
return;
}
this.trigger('close', {
originalEvent: originalEvent,
originalSelect2Event: evt
});
};
return CloseOnSelect;
});
S2.define('select2/i18n/en',[],function () {
// English
return {
errorLoading: function () {
return 'The results could not be loaded.';
},
inputTooLong: function (args) {
var overChars = args.input.length - args.maximum;
var message = 'Please delete ' + overChars + ' character';
if (overChars != 1) {
message += 's';
}
return message;
},
inputTooShort: function (args) {
var remainingChars = args.minimum - args.input.length;
var message = 'Please enter ' + remainingChars + ' or more characters';
return message;
},
loadingMore: function () {
return 'Loading more results…';
},
maximumSelected: function (args) {
var message = 'You can only select ' + args.maximum + ' item';
if (args.maximum != 1) {
message += 's';
}
return message;
},
noResults: function () {
return 'No results found';
},
searching: function () {
return 'Searching…';
},
removeAllItems: function () {
return 'Remove all items';
}
};
});
S2.define('select2/defaults',[
'jquery',
'require',
'./results',
'./selection/single',
'./selection/multiple',
'./selection/placeholder',
'./selection/allowClear',
'./selection/search',
'./selection/eventRelay',
'./utils',
'./translation',
'./diacritics',
'./data/select',
'./data/array',
'./data/ajax',
'./data/tags',
'./data/tokenizer',
'./data/minimumInputLength',
'./data/maximumInputLength',
'./data/maximumSelectionLength',
'./dropdown',
'./dropdown/search',
'./dropdown/hidePlaceholder',
'./dropdown/infiniteScroll',
'./dropdown/attachBody',
'./dropdown/minimumResultsForSearch',
'./dropdown/selectOnClose',
'./dropdown/closeOnSelect',
'./i18n/en'
], function ($, require,
ResultsList,
SingleSelection, MultipleSelection, Placeholder, AllowClear,
SelectionSearch, EventRelay,
Utils, Translation, DIACRITICS,
SelectData, ArrayData, AjaxData, Tags, Tokenizer,
MinimumInputLength, MaximumInputLength, MaximumSelectionLength,
Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
EnglishTranslation) {
function Defaults () {
this.reset();
}
Defaults.prototype.apply = function (options) {
options = $.extend(true, {}, this.defaults, options);
if (options.dataAdapter == null) {
if (options.ajax != null) {
options.dataAdapter = AjaxData;
} else if (options.data != null) {
options.dataAdapter = ArrayData;
} else {
options.dataAdapter = SelectData;
}
if (options.minimumInputLength > 0) {
options.dataAdapter = Utils.Decorate(
options.dataAdapter,
MinimumInputLength
);
}
if (options.maximumInputLength > 0) {
options.dataAdapter = Utils.Decorate(
options.dataAdapter,
MaximumInputLength
);
}
if (options.maximumSelectionLength > 0) {
options.dataAdapter = Utils.Decorate(
options.dataAdapter,
MaximumSelectionLength
);
}
if (options.tags) {
options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
}
if (options.tokenSeparators != null || options.tokenizer != null) {
options.dataAdapter = Utils.Decorate(
options.dataAdapter,
Tokenizer
);
}
if (options.query != null) {
var Query = require(options.amdBase + 'compat/query');
options.dataAdapter = Utils.Decorate(
options.dataAdapter,
Query
);
}
if (options.initSelection != null) {
var InitSelection = require(options.amdBase + 'compat/initSelection');
options.dataAdapter = Utils.Decorate(
options.dataAdapter,
InitSelection
);
}
}
if (options.resultsAdapter == null) {
options.resultsAdapter = ResultsList;
if (options.ajax != null) {
options.resultsAdapter = Utils.Decorate(
options.resultsAdapter,
InfiniteScroll
);
}
if (options.placeholder != null) {
options.resultsAdapter = Utils.Decorate(
options.resultsAdapter,
HidePlaceholder
);
}
if (options.selectOnClose) {
options.resultsAdapter = Utils.Decorate(
options.resultsAdapter,
SelectOnClose
);
}
}
if (options.dropdownAdapter == null) {
if (options.multiple) {
options.dropdownAdapter = Dropdown;
} else {
var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
options.dropdownAdapter = SearchableDropdown;
}
if (options.minimumResultsForSearch !== 0) {
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
MinimumResultsForSearch
);
}
if (options.closeOnSelect) {
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
CloseOnSelect
);
}
if (
options.dropdownCssClass != null ||
options.dropdownCss != null ||
options.adaptDropdownCssClass != null
) {
var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
DropdownCSS
);
}
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
AttachBody
);
}
if (options.selectionAdapter == null) {
if (options.multiple) {
options.selectionAdapter = MultipleSelection;
} else {
options.selectionAdapter = SingleSelection;
}
// Add the placeholder mixin if a placeholder was specified
if (options.placeholder != null) {
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
Placeholder
);
}
if (options.allowClear) {
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
AllowClear
);
}
if (options.multiple) {
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
SelectionSearch
);
}
if (
options.containerCssClass != null ||
options.containerCss != null ||
options.adaptContainerCssClass != null
) {
var ContainerCSS = require(options.amdBase + 'compat/containerCss');
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
ContainerCSS
);
}
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
EventRelay
);
}
// If the defaults were not previously applied from an element, it is
// possible for the language option to have not been resolved
options.language = this._resolveLanguage(options.language);
// Always fall back to English since it will always be complete
options.language.push('en');
var uniqueLanguages = [];
for (var l = 0; l < options.language.length; l++) {
var language = options.language[l];
if (uniqueLanguages.indexOf(language) === -1) {
uniqueLanguages.push(language);
}
}
options.language = uniqueLanguages;
options.translations = this._processTranslations(
options.language,
options.debug
);
return options;
};
Defaults.prototype.reset = function () {
function stripDiacritics (text) {
// Used 'uni range + named function' from http://jsperf.com/diacritics/18
function match(a) {
return DIACRITICS[a] || a;
}
return text.replace(/[^\u0000-\u007E]/g, match);
}
function matcher (params, data) {
// Always return the object if there is nothing to compare
if ($.trim(params.term) === '') {
return data;
}
// Do a recursive check for options with children
if (data.children && data.children.length > 0) {
// Clone the data object if there are children
// This is required as we modify the object to remove any non-matches
var match = $.extend(true, {}, data);
// Check each child of the option
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
var matches = matcher(params, child);
// If there wasn't a match, remove the object in the array
if (matches == null) {
match.children.splice(c, 1);
}
}
// If any children matched, return the new object
if (match.children.length > 0) {
return match;
}
// If there were no matching children, check just the plain object
return matcher(params, match);
}
var original = stripDiacritics(data.text).toUpperCase();
var term = stripDiacritics(params.term).toUpperCase();
// Check if the text contains the term
if (original.indexOf(term) > -1) {
return data;
}
// If it doesn't contain the term, don't return anything
return null;
}
this.defaults = {
amdBase: './',
amdLanguageBase: './i18n/',
closeOnSelect: true,
debug: false,
dropdownAutoWidth: false,
escapeMarkup: Utils.escapeMarkup,
language: {},
matcher: matcher,
minimumInputLength: 0,
maximumInputLength: 0,
maximumSelectionLength: 0,
minimumResultsForSearch: 0,
selectOnClose: false,
scrollAfterSelect: false,
sorter: function (data) {
return data;
},
templateResult: function (result) {
return result.text;
},
templateSelection: function (selection) {
return selection.text;
},
theme: 'default',
width: 'resolve'
};
};
Defaults.prototype.applyFromElement = function (options, $element) {
var optionLanguage = options.language;
var defaultLanguage = this.defaults.language;
var elementLanguage = $element.prop('lang');
var parentLanguage = $element.closest('[lang]').prop('lang');
var languages = Array.prototype.concat.call(
this._resolveLanguage(elementLanguage),
this._resolveLanguage(optionLanguage),
this._resolveLanguage(defaultLanguage),
this._resolveLanguage(parentLanguage)
);
options.language = languages;
return options;
};
Defaults.prototype._resolveLanguage = function (language) {
if (!language) {
return [];
}
if ($.isEmptyObject(language)) {
return [];
}
if ($.isPlainObject(language)) {
return [language];
}
var languages;
if (!$.isArray(language)) {
languages = [language];
} else {
languages = language;
}
var resolvedLanguages = [];
for (var l = 0; l < languages.length; l++) {
resolvedLanguages.push(languages[l]);
if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {
// Extract the region information if it is included
var languageParts = languages[l].split('-');
var baseLanguage = languageParts[0];
resolvedLanguages.push(baseLanguage);
}
}
return resolvedLanguages;
};
Defaults.prototype._processTranslations = function (languages, debug) {
var translations = new Translation();
for (var l = 0; l < languages.length; l++) {
var languageData = new Translation();
var language = languages[l];
if (typeof language === 'string') {
try {
// Try to load it with the original name
languageData = Translation.loadPath(language);
} catch (e) {
try {
// If we couldn't load it, check if it wasn't the full path
language = this.defaults.amdLanguageBase + language;
languageData = Translation.loadPath(language);
} catch (ex) {
// The translation could not be loaded at all. Sometimes this is
// because of a configuration problem, other times this can be
// because of how Select2 helps load all possible translation files
if (debug && window.console && console.warn) {
console.warn(
'Select2: The language file for "' + language + '" could ' +
'not be automatically loaded. A fallback will be used instead.'
);
}
}
}
} else if ($.isPlainObject(language)) {
languageData = new Translation(language);
} else {
languageData = language;
}
translations.extend(languageData);
}
return translations;
};
Defaults.prototype.set = function (key, value) {
var camelKey = $.camelCase(key);
var data = {};
data[camelKey] = value;
var convertedData = Utils._convertData(data);
$.extend(true, this.defaults, convertedData);
};
var defaults = new Defaults();
return defaults;
});
S2.define('select2/options',[
'require',
'jquery',
'./defaults',
'./utils'
], function (require, $, Defaults, Utils) {
function Options (options, $element) {
this.options = options;
if ($element != null) {
this.fromElement($element);
}
if ($element != null) {
this.options = Defaults.applyFromElement(this.options, $element);
}
this.options = Defaults.apply(this.options);
if ($element && $element.is('input')) {
var InputCompat = require(this.get('amdBase') + 'compat/inputData');
this.options.dataAdapter = Utils.Decorate(
this.options.dataAdapter,
InputCompat
);
}
}
Options.prototype.fromElement = function ($e) {
var excludedData = ['select2'];
if (this.options.multiple == null) {
this.options.multiple = $e.prop('multiple');
}
if (this.options.disabled == null) {
this.options.disabled = $e.prop('disabled');
}
if (this.options.dir == null) {
if ($e.prop('dir')) {
this.options.dir = $e.prop('dir');
} else if ($e.closest('[dir]').prop('dir')) {
this.options.dir = $e.closest('[dir]').prop('dir');
} else {
this.options.dir = 'ltr';
}
}
$e.prop('disabled', this.options.disabled);
$e.prop('multiple', this.options.multiple);
if (Utils.GetData($e[0], 'select2Tags')) {
if (this.options.debug && window.console && console.warn) {
console.warn(
'Select2: The `data-select2-tags` attribute has been changed to ' +
'use the `data-data` and `data-tags="true"` attributes and will be ' +
'removed in future versions of Select2.'
);
}
Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags'));
Utils.StoreData($e[0], 'tags', true);
}
if (Utils.GetData($e[0], 'ajaxUrl')) {
if (this.options.debug && window.console && console.warn) {
console.warn(
'Select2: The `data-ajax-url` attribute has been changed to ' +
'`data-ajax--url` and support for the old attribute will be removed' +
' in future versions of Select2.'
);
}
$e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl'));
Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl'));
}
var dataset = {};
function upperCaseLetter(_, letter) {
return letter.toUpperCase();
}
// Pre-load all of the attributes which are prefixed with `data-`
for (var attr = 0; attr < $e[0].attributes.length; attr++) {
var attributeName = $e[0].attributes[attr].name;
var prefix = 'data-';
if (attributeName.substr(0, prefix.length) == prefix) {
// Get the contents of the attribute after `data-`
var dataName = attributeName.substring(prefix.length);
// Get the data contents from the consistent source
// This is more than likely the jQuery data helper
var dataValue = Utils.GetData($e[0], dataName);
// camelCase the attribute name to match the spec
var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter);
// Store the data attribute contents into the dataset since
dataset[camelDataName] = dataValue;
}
}
// Prefer the element's `dataset` attribute if it exists
// jQuery 1.x does not correctly handle data attributes with multiple dashes
if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
dataset = $.extend(true, {}, $e[0].dataset, dataset);
}
// Prefer our internal data cache if it exists
var data = $.extend(true, {}, Utils.GetData($e[0]), dataset);
data = Utils._convertData(data);
for (var key in data) {
if ($.inArray(key, excludedData) > -1) {
continue;
}
if ($.isPlainObject(this.options[key])) {
$.extend(this.options[key], data[key]);
} else {
this.options[key] = data[key];
}
}
return this;
};
Options.prototype.get = function (key) {
return this.options[key];
};
Options.prototype.set = function (key, val) {
this.options[key] = val;
};
return Options;
});
S2.define('select2/core',[
'jquery',
'./options',
'./utils',
'./keys'
], function ($, Options, Utils, KEYS) {
var Select2 = function ($element, options) {
if (Utils.GetData($element[0], 'select2') != null) {
Utils.GetData($element[0], 'select2').destroy();
}
this.$element = $element;
this.id = this._generateId($element);
options = options || {};
this.options = new Options(options, $element);
Select2.__super__.constructor.call(this);
// Set up the tabindex
var tabindex = $element.attr('tabindex') || 0;
Utils.StoreData($element[0], 'old-tabindex', tabindex);
$element.attr('tabindex', '-1');
// Set up containers and adapters
var DataAdapter = this.options.get('dataAdapter');
this.dataAdapter = new DataAdapter($element, this.options);
var $container = this.render();
this._placeContainer($container);
var SelectionAdapter = this.options.get('selectionAdapter');
this.selection = new SelectionAdapter($element, this.options);
this.$selection = this.selection.render();
this.selection.position(this.$selection, $container);
var DropdownAdapter = this.options.get('dropdownAdapter');
this.dropdown = new DropdownAdapter($element, this.options);
this.$dropdown = this.dropdown.render();
this.dropdown.position(this.$dropdown, $container);
var ResultsAdapter = this.options.get('resultsAdapter');
this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
this.$results = this.results.render();
this.results.position(this.$results, this.$dropdown);
// Bind events
var self = this;
// Bind the container to all of the adapters
this._bindAdapters();
// Register any DOM event handlers
this._registerDomEvents();
// Register any internal event handlers
this._registerDataEvents();
this._registerSelectionEvents();
this._registerDropdownEvents();
this._registerResultsEvents();
this._registerEvents();
// Set the initial state
this.dataAdapter.current(function (initialData) {
self.trigger('selection:update', {
data: initialData
});
});
// Hide the original select
$element.addClass('select2-hidden-accessible');
$element.attr('aria-hidden', 'true');
// Synchronize any monitored attributes
this._syncAttributes();
Utils.StoreData($element[0], 'select2', this);
// Ensure backwards compatibility with $element.data('select2').
$element.data('select2', this);
};
Utils.Extend(Select2, Utils.Observable);
Select2.prototype._generateId = function ($element) {
var id = '';
if ($element.attr('id') != null) {
id = $element.attr('id');
} else if ($element.attr('name') != null) {
id = $element.attr('name') + '-' + Utils.generateChars(2);
} else {
id = Utils.generateChars(4);
}
id = id.replace(/(:|\.|\[|\]|,)/g, '');
id = 'select2-' + id;
return id;
};
Select2.prototype._placeContainer = function ($container) {
$container.insertAfter(this.$element);
var width = this._resolveWidth(this.$element, this.options.get('width'));
if (width != null) {
$container.css('width', width);
}
};
Select2.prototype._resolveWidth = function ($element, method) {
var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
if (method == 'resolve') {
var styleWidth = this._resolveWidth($element, 'style');
if (styleWidth != null) {
return styleWidth;
}
return this._resolveWidth($element, 'element');
}
if (method == 'element') {
var elementWidth = $element.outerWidth(false);
if (elementWidth <= 0) {
return 'auto';
}
return elementWidth + 'px';
}
if (method == 'style') {
var style = $element.attr('style');
if (typeof(style) !== 'string') {
return null;
}
var attrs = style.split(';');
for (var i = 0, l = attrs.length; i < l; i = i + 1) {
var attr = attrs[i].replace(/\s/g, '');
var matches = attr.match(WIDTH);
if (matches !== null && matches.length >= 1) {
return matches[1];
}
}
return null;
}
if (method == 'computedstyle') {
var computedStyle = window.getComputedStyle($element[0]);
return computedStyle.width;
}
return method;
};
Select2.prototype._bindAdapters = function () {
this.dataAdapter.bind(this, this.$container);
this.selection.bind(this, this.$container);
this.dropdown.bind(this, this.$container);
this.results.bind(this, this.$container);
};
Select2.prototype._registerDomEvents = function () {
var self = this;
this.$element.on('change.select2', function () {
self.dataAdapter.current(function (data) {
self.trigger('selection:update', {
data: data
});
});
});
this.$element.on('focus.select2', function (evt) {
self.trigger('focus', evt);
});
this._syncA = Utils.bind(this._syncAttributes, this);
this._syncS = Utils.bind(this._syncSubtree, this);
if (this.$element[0].attachEvent) {
this.$element[0].attachEvent('onpropertychange', this._syncA);
}
var observer = window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver
;
if (observer != null) {
this._observer = new observer(function (mutations) {
$.each(mutations, self._syncA);
$.each(mutations, self._syncS);
});
this._observer.observe(this.$element[0], {
attributes: true,
childList: true,
subtree: false
});
} else if (this.$element[0].addEventListener) {
this.$element[0].addEventListener(
'DOMAttrModified',
self._syncA,
false
);
this.$element[0].addEventListener(
'DOMNodeInserted',
self._syncS,
false
);
this.$element[0].addEventListener(
'DOMNodeRemoved',
self._syncS,
false
);
}
};
Select2.prototype._registerDataEvents = function () {
var self = this;
this.dataAdapter.on('*', function (name, params) {
self.trigger(name, params);
});
};
Select2.prototype._registerSelectionEvents = function () {
var self = this;
var nonRelayEvents = ['toggle', 'focus'];
this.selection.on('toggle', function () {
self.toggleDropdown();
});
this.selection.on('focus', function (params) {
self.focus(params);
});
this.selection.on('*', function (name, params) {
if ($.inArray(name, nonRelayEvents) !== -1) {
return;
}
self.trigger(name, params);
});
};
Select2.prototype._registerDropdownEvents = function () {
var self = this;
this.dropdown.on('*', function (name, params) {
self.trigger(name, params);
});
};
Select2.prototype._registerResultsEvents = function () {
var self = this;
this.results.on('*', function (name, params) {
self.trigger(name, params);
});
};
Select2.prototype._registerEvents = function () {
var self = this;
this.on('open', function () {
self.$container.addClass('select2-container--open');
});
this.on('close', function () {
self.$container.removeClass('select2-container--open');
});
this.on('enable', function () {
self.$container.removeClass('select2-container--disabled');
});
this.on('disable', function () {
self.$container.addClass('select2-container--disabled');
});
this.on('blur', function () {
self.$container.removeClass('select2-container--focus');
});
this.on('query', function (params) {
if (!self.isOpen()) {
self.trigger('open', {});
}
this.dataAdapter.query(params, function (data) {
self.trigger('results:all', {
data: data,
query: params
});
});
});
this.on('query:append', function (params) {
this.dataAdapter.query(params, function (data) {
self.trigger('results:append', {
data: data,
query: params
});
});
});
this.on('keypress', function (evt) {
var key = evt.which;
if (self.isOpen()) {
if (key === KEYS.ESC || key === KEYS.TAB ||
(key === KEYS.UP && evt.altKey)) {
self.close();
evt.preventDefault();
} else if (key === KEYS.ENTER) {
self.trigger('results:select', {});
evt.preventDefault();
} else if ((key === KEYS.SPACE && evt.ctrlKey)) {
self.trigger('results:toggle', {});
evt.preventDefault();
} else if (key === KEYS.UP) {
self.trigger('results:previous', {});
evt.preventDefault();
} else if (key === KEYS.DOWN) {
self.trigger('results:next', {});
evt.preventDefault();
}
} else {
if (key === KEYS.ENTER || key === KEYS.SPACE ||
(key === KEYS.DOWN && evt.altKey)) {
self.open();
evt.preventDefault();
}
}
});
};
Select2.prototype._syncAttributes = function () {
this.options.set('disabled', this.$element.prop('disabled'));
if (this.options.get('disabled')) {
if (this.isOpen()) {
this.close();
}
this.trigger('disable', {});
} else {
this.trigger('enable', {});
}
};
Select2.prototype._syncSubtree = function (evt, mutations) {
var changed = false;
var self = this;
// Ignore any mutation events raised for elements that aren't options or
// optgroups. This handles the case when the select element is destroyed
if (
evt && evt.target && (
evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
)
) {
return;
}
if (!mutations) {
// If mutation events aren't supported, then we can only assume that the
// change affected the selections
changed = true;
} else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
for (var n = 0; n < mutations.addedNodes.length; n++) {
var node = mutations.addedNodes[n];
if (node.selected) {
changed = true;
}
}
} else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
changed = true;
}
// Only re-pull the data if we think there is a change
if (changed) {
this.dataAdapter.current(function (currentData) {
self.trigger('selection:update', {
data: currentData
});
});
}
};
/**
* Override the trigger method to automatically trigger pre-events when
* there are events that can be prevented.
*/
Select2.prototype.trigger = function (name, args) {
var actualTrigger = Select2.__super__.trigger;
var preTriggerMap = {
'open': 'opening',
'close': 'closing',
'select': 'selecting',
'unselect': 'unselecting',
'clear': 'clearing'
};
if (args === undefined) {
args = {};
}
if (name in preTriggerMap) {
var preTriggerName = preTriggerMap[name];
var preTriggerArgs = {
prevented: false,
name: name,
args: args
};
actualTrigger.call(this, preTriggerName, preTriggerArgs);
if (preTriggerArgs.prevented) {
args.prevented = true;
return;
}
}
actualTrigger.call(this, name, args);
};
Select2.prototype.toggleDropdown = function () {
if (this.options.get('disabled')) {
return;
}
if (this.isOpen()) {
this.close();
} else {
this.open();
}
};
Select2.prototype.open = function () {
if (this.isOpen()) {
return;
}
this.trigger('query', {});
};
Select2.prototype.close = function () {
if (!this.isOpen()) {
return;
}
this.trigger('close', {});
};
Select2.prototype.isOpen = function () {
return this.$container.hasClass('select2-container--open');
};
Select2.prototype.hasFocus = function () {
return this.$container.hasClass('select2-container--focus');
};
Select2.prototype.focus = function (data) {
// No need to re-trigger focus events if we are already focused
if (this.hasFocus()) {
return;
}
this.$container.addClass('select2-container--focus');
this.trigger('focus', {});
};
Select2.prototype.enable = function (args) {
if (this.options.get('debug') && window.console && console.warn) {
console.warn(
'Select2: The `select2("enable")` method has been deprecated and will' +
' be removed in later Select2 versions. Use $element.prop("disabled")' +
' instead.'
);
}
if (args == null || args.length === 0) {
args = [true];
}
var disabled = !args[0];
this.$element.prop('disabled', disabled);
};
Select2.prototype.data = function () {
if (this.options.get('debug') &&
arguments.length > 0 && window.console && console.warn) {
console.warn(
'Select2: Data can no longer be set using `select2("data")`. You ' +
'should consider setting the value instead using `$element.val()`.'
);
}
var data = [];
this.dataAdapter.current(function (currentData) {
data = currentData;
});
return data;
};
Select2.prototype.val = function (args) {
if (this.options.get('debug') && window.console && console.warn) {
console.warn(
'Select2: The `select2("val")` method has been deprecated and will be' +
' removed in later Select2 versions. Use $element.val() instead.'
);
}
if (args == null || args.length === 0) {
return this.$element.val();
}
var newVal = args[0];
if ($.isArray(newVal)) {
newVal = $.map(newVal, function (obj) {
return obj.toString();
});
}
this.$element.val(newVal).trigger('change');
};
Select2.prototype.destroy = function () {
this.$container.remove();
if (this.$element[0].detachEvent) {
this.$element[0].detachEvent('onpropertychange', this._syncA);
}
if (this._observer != null) {
this._observer.disconnect();
this._observer = null;
} else if (this.$element[0].removeEventListener) {
this.$element[0]
.removeEventListener('DOMAttrModified', this._syncA, false);
this.$element[0]
.removeEventListener('DOMNodeInserted', this._syncS, false);
this.$element[0]
.removeEventListener('DOMNodeRemoved', this._syncS, false);
}
this._syncA = null;
this._syncS = null;
this.$element.off('.select2');
this.$element.attr('tabindex',
Utils.GetData(this.$element[0], 'old-tabindex'));
this.$element.removeClass('select2-hidden-accessible');
this.$element.attr('aria-hidden', 'false');
Utils.RemoveData(this.$element[0]);
this.$element.removeData('select2');
this.dataAdapter.destroy();
this.selection.destroy();
this.dropdown.destroy();
this.results.destroy();
this.dataAdapter = null;
this.selection = null;
this.dropdown = null;
this.results = null;
};
Select2.prototype.render = function () {
var $container = $(
'' +
' ' +
' ' +
' '
);
$container.attr('dir', this.options.get('dir'));
this.$container = $container;
this.$container.addClass('select2-container--' + this.options.get('theme'));
Utils.StoreData($container[0], 'element', this.$element);
return $container;
};
return Select2;
});
S2.define('select2/compat/utils',[
'jquery'
], function ($) {
function syncCssClasses ($dest, $src, adapter) {
var classes, replacements = [], adapted;
classes = $.trim($dest.attr('class'));
if (classes) {
classes = '' + classes; // for IE which returns object
$(classes.split(/\s+/)).each(function () {
// Save all Select2 classes
if (this.indexOf('select2-') === 0) {
replacements.push(this);
}
});
}
classes = $.trim($src.attr('class'));
if (classes) {
classes = '' + classes; // for IE which returns object
$(classes.split(/\s+/)).each(function () {
// Only adapt non-Select2 classes
if (this.indexOf('select2-') !== 0) {
adapted = adapter(this);
if (adapted != null) {
replacements.push(adapted);
}
}
});
}
$dest.attr('class', replacements.join(' '));
}
return {
syncCssClasses: syncCssClasses
};
});
S2.define('select2/compat/containerCss',[
'jquery',
'./utils'
], function ($, CompatUtils) {
// No-op CSS adapter that discards all classes by default
function _containerAdapter (clazz) {
return null;
}
function ContainerCSS () { }
ContainerCSS.prototype.render = function (decorated) {
var $container = decorated.call(this);
var containerCssClass = this.options.get('containerCssClass') || '';
if ($.isFunction(containerCssClass)) {
containerCssClass = containerCssClass(this.$element);
}
var containerCssAdapter = this.options.get('adaptContainerCssClass');
containerCssAdapter = containerCssAdapter || _containerAdapter;
if (containerCssClass.indexOf(':all:') !== -1) {
containerCssClass = containerCssClass.replace(':all:', '');
var _cssAdapter = containerCssAdapter;
containerCssAdapter = function (clazz) {
var adapted = _cssAdapter(clazz);
if (adapted != null) {
// Append the old one along with the adapted one
return adapted + ' ' + clazz;
}
return clazz;
};
}
var containerCss = this.options.get('containerCss') || {};
if ($.isFunction(containerCss)) {
containerCss = containerCss(this.$element);
}
CompatUtils.syncCssClasses($container, this.$element, containerCssAdapter);
$container.css(containerCss);
$container.addClass(containerCssClass);
return $container;
};
return ContainerCSS;
});
S2.define('select2/compat/dropdownCss',[
'jquery',
'./utils'
], function ($, CompatUtils) {
// No-op CSS adapter that discards all classes by default
function _dropdownAdapter (clazz) {
return null;
}
function DropdownCSS () { }
DropdownCSS.prototype.render = function (decorated) {
var $dropdown = decorated.call(this);
var dropdownCssClass = this.options.get('dropdownCssClass') || '';
if ($.isFunction(dropdownCssClass)) {
dropdownCssClass = dropdownCssClass(this.$element);
}
var dropdownCssAdapter = this.options.get('adaptDropdownCssClass');
dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter;
if (dropdownCssClass.indexOf(':all:') !== -1) {
dropdownCssClass = dropdownCssClass.replace(':all:', '');
var _cssAdapter = dropdownCssAdapter;
dropdownCssAdapter = function (clazz) {
var adapted = _cssAdapter(clazz);
if (adapted != null) {
// Append the old one along with the adapted one
return adapted + ' ' + clazz;
}
return clazz;
};
}
var dropdownCss = this.options.get('dropdownCss') || {};
if ($.isFunction(dropdownCss)) {
dropdownCss = dropdownCss(this.$element);
}
CompatUtils.syncCssClasses($dropdown, this.$element, dropdownCssAdapter);
$dropdown.css(dropdownCss);
$dropdown.addClass(dropdownCssClass);
return $dropdown;
};
return DropdownCSS;
});
S2.define('select2/compat/initSelection',[
'jquery'
], function ($) {
function InitSelection (decorated, $element, options) {
if (options.get('debug') && window.console && console.warn) {
console.warn(
'Select2: The `initSelection` option has been deprecated in favor' +
' of a custom data adapter that overrides the `current` method. ' +
'This method is now called multiple times instead of a single ' +
'time when the instance is initialized. Support will be removed ' +
'for the `initSelection` option in future versions of Select2'
);
}
this.initSelection = options.get('initSelection');
this._isInitialized = false;
decorated.call(this, $element, options);
}
InitSelection.prototype.current = function (decorated, callback) {
var self = this;
if (this._isInitialized) {
decorated.call(this, callback);
return;
}
this.initSelection.call(null, this.$element, function (data) {
self._isInitialized = true;
if (!$.isArray(data)) {
data = [data];
}
callback(data);
});
};
return InitSelection;
});
S2.define('select2/compat/inputData',[
'jquery',
'../utils'
], function ($, Utils) {
function InputData (decorated, $element, options) {
this._currentData = [];
this._valueSeparator = options.get('valueSeparator') || ',';
if ($element.prop('type') === 'hidden') {
if (options.get('debug') && console && console.warn) {
console.warn(
'Select2: Using a hidden input with Select2 is no longer ' +
'supported and may stop working in the future. It is recommended ' +
'to use a `` element instead.'
);
}
}
decorated.call(this, $element, options);
}
InputData.prototype.current = function (_, callback) {
function getSelected (data, selectedIds) {
var selected = [];
if (data.selected || $.inArray(data.id, selectedIds) !== -1) {
data.selected = true;
selected.push(data);
} else {
data.selected = false;
}
if (data.children) {
selected.push.apply(selected, getSelected(data.children, selectedIds));
}
return selected;
}
var selected = [];
for (var d = 0; d < this._currentData.length; d++) {
var data = this._currentData[d];
selected.push.apply(
selected,
getSelected(
data,
this.$element.val().split(
this._valueSeparator
)
)
);
}
callback(selected);
};
InputData.prototype.select = function (_, data) {
if (!this.options.get('multiple')) {
this.current(function (allData) {
$.map(allData, function (data) {
data.selected = false;
});
});
this.$element.val(data.id);
this.$element.trigger('change');
} else {
var value = this.$element.val();
value += this._valueSeparator + data.id;
this.$element.val(value);
this.$element.trigger('change');
}
};
InputData.prototype.unselect = function (_, data) {
var self = this;
data.selected = false;
this.current(function (allData) {
var values = [];
for (var d = 0; d < allData.length; d++) {
var item = allData[d];
if (data.id == item.id) {
continue;
}
values.push(item.id);
}
self.$element.val(values.join(self._valueSeparator));
self.$element.trigger('change');
});
};
InputData.prototype.query = function (_, params, callback) {
var results = [];
for (var d = 0; d < this._currentData.length; d++) {
var data = this._currentData[d];
var matches = this.matches(params, data);
if (matches !== null) {
results.push(matches);
}
}
callback({
results: results
});
};
InputData.prototype.addOptions = function (_, $options) {
var options = $.map($options, function ($option) {
return Utils.GetData($option[0], 'data');
});
this._currentData.push.apply(this._currentData, options);
};
return InputData;
});
S2.define('select2/compat/matcher',[
'jquery'
], function ($) {
function oldMatcher (matcher) {
function wrappedMatcher (params, data) {
var match = $.extend(true, {}, data);
if (params.term == null || $.trim(params.term) === '') {
return match;
}
if (data.children) {
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
// Check if the child object matches
// The old matcher returned a boolean true or false
var doesMatch = matcher(params.term, child.text, child);
// If the child didn't match, pop it off
if (!doesMatch) {
match.children.splice(c, 1);
}
}
if (match.children.length > 0) {
return match;
}
}
if (matcher(params.term, data.text, data)) {
return match;
}
return null;
}
return wrappedMatcher;
}
return oldMatcher;
});
S2.define('select2/compat/query',[
], function () {
function Query (decorated, $element, options) {
if (options.get('debug') && window.console && console.warn) {
console.warn(
'Select2: The `query` option has been deprecated in favor of a ' +
'custom data adapter that overrides the `query` method. Support ' +
'will be removed for the `query` option in future versions of ' +
'Select2.'
);
}
decorated.call(this, $element, options);
}
Query.prototype.query = function (_, params, callback) {
params.callback = callback;
var query = this.options.get('query');
query.call(null, params);
};
return Query;
});
S2.define('select2/dropdown/attachContainer',[
], function () {
function AttachContainer (decorated, $element, options) {
decorated.call(this, $element, options);
}
AttachContainer.prototype.position =
function (decorated, $dropdown, $container) {
var $dropdownContainer = $container.find('.dropdown-wrapper');
$dropdownContainer.append($dropdown);
$dropdown.addClass('select2-dropdown--below');
$container.addClass('select2-container--below');
};
return AttachContainer;
});
S2.define('select2/dropdown/stopPropagation',[
], function () {
function StopPropagation () { }
StopPropagation.prototype.bind = function (decorated, container, $container) {
decorated.call(this, container, $container);
var stoppedEvents = [
'blur',
'change',
'click',
'dblclick',
'focus',
'focusin',
'focusout',
'input',
'keydown',
'keyup',
'keypress',
'mousedown',
'mouseenter',
'mouseleave',
'mousemove',
'mouseover',
'mouseup',
'search',
'touchend',
'touchstart'
];
this.$dropdown.on(stoppedEvents.join(' '), function (evt) {
evt.stopPropagation();
});
};
return StopPropagation;
});
S2.define('select2/selection/stopPropagation',[
], function () {
function StopPropagation () { }
StopPropagation.prototype.bind = function (decorated, container, $container) {
decorated.call(this, container, $container);
var stoppedEvents = [
'blur',
'change',
'click',
'dblclick',
'focus',
'focusin',
'focusout',
'input',
'keydown',
'keyup',
'keypress',
'mousedown',
'mouseenter',
'mouseleave',
'mousemove',
'mouseover',
'mouseup',
'search',
'touchend',
'touchstart'
];
this.$selection.on(stoppedEvents.join(' '), function (evt) {
evt.stopPropagation();
});
};
return StopPropagation;
});
/*!
* jQuery Mousewheel 3.1.13
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*/
(function (factory) {
if ( typeof S2.define === 'function' && S2.define.amd ) {
// AMD. Register as an anonymous module.
S2.define('jquery-mousewheel',['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS style for Browserify
module.exports = factory;
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
slice = Array.prototype.slice,
nullLowestDeltaTimeout, lowestDelta;
if ( $.event.fixHooks ) {
for ( var i = toFix.length; i; ) {
$.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
}
}
var special = $.event.special.mousewheel = {
version: '3.1.12',
setup: function() {
if ( this.addEventListener ) {
for ( var i = toBind.length; i; ) {
this.addEventListener( toBind[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
// Store the line height and page height for this particular element
$.data(this, 'mousewheel-line-height', special.getLineHeight(this));
$.data(this, 'mousewheel-page-height', special.getPageHeight(this));
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i = toBind.length; i; ) {
this.removeEventListener( toBind[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
// Clean up the data we added to the element
$.removeData(this, 'mousewheel-line-height');
$.removeData(this, 'mousewheel-page-height');
},
getLineHeight: function(elem) {
var $elem = $(elem),
$parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
if (!$parent.length) {
$parent = $('body');
}
return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
},
getPageHeight: function(elem) {
return $(elem).height();
},
settings: {
adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
normalizeOffset: true // calls getBoundingClientRect for each event
}
};
$.fn.extend({
mousewheel: function(fn) {
return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
},
unmousewheel: function(fn) {
return this.unbind('mousewheel', fn);
}
});
function handler(event) {
var orgEvent = event || window.event,
args = slice.call(arguments, 1),
delta = 0,
deltaX = 0,
deltaY = 0,
absDelta = 0,
offsetX = 0,
offsetY = 0;
event = $.event.fix(orgEvent);
event.type = 'mousewheel';
// Old school scrollwheel delta
if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; }
if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; }
if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; }
if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }
// Firefox < 17 horizontal scrolling related to DOMMouseScroll event
if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaX = deltaY * -1;
deltaY = 0;
}
// Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
delta = deltaY === 0 ? deltaX : deltaY;
// New school wheel delta (wheel event)
if ( 'deltaY' in orgEvent ) {
deltaY = orgEvent.deltaY * -1;
delta = deltaY;
}
if ( 'deltaX' in orgEvent ) {
deltaX = orgEvent.deltaX;
if ( deltaY === 0 ) { delta = deltaX * -1; }
}
// No change actually happened, no reason to go any further
if ( deltaY === 0 && deltaX === 0 ) { return; }
// Need to convert lines and pages to pixels if we aren't already in pixels
// There are three delta modes:
// * deltaMode 0 is by pixels, nothing to do
// * deltaMode 1 is by lines
// * deltaMode 2 is by pages
if ( orgEvent.deltaMode === 1 ) {
var lineHeight = $.data(this, 'mousewheel-line-height');
delta *= lineHeight;
deltaY *= lineHeight;
deltaX *= lineHeight;
} else if ( orgEvent.deltaMode === 2 ) {
var pageHeight = $.data(this, 'mousewheel-page-height');
delta *= pageHeight;
deltaY *= pageHeight;
deltaX *= pageHeight;
}
// Store lowest absolute delta to normalize the delta values
absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
if ( !lowestDelta || absDelta < lowestDelta ) {
lowestDelta = absDelta;
// Adjust older deltas if necessary
if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
lowestDelta /= 40;
}
}
// Adjust older deltas if necessary
if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
// Divide all the things by 40!
delta /= 40;
deltaX /= 40;
deltaY /= 40;
}
// Get a whole, normalized value for the deltas
delta = Math[ delta >= 1 ? 'floor' : 'ceil' ](delta / lowestDelta);
deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
// Normalise offsetX and offsetY properties
if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
var boundingRect = this.getBoundingClientRect();
offsetX = event.clientX - boundingRect.left;
offsetY = event.clientY - boundingRect.top;
}
// Add information to the event object
event.deltaX = deltaX;
event.deltaY = deltaY;
event.deltaFactor = lowestDelta;
event.offsetX = offsetX;
event.offsetY = offsetY;
// Go ahead and set deltaMode to 0 since we converted to pixels
// Although this is a little odd since we overwrite the deltaX/Y
// properties with normalized deltas.
event.deltaMode = 0;
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
// Clearout lowestDelta after sometime to better
// handle multiple device types that give different
// a different lowestDelta
// Ex: trackpad = 3 and mouse wheel = 120
if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
function nullLowestDelta() {
lowestDelta = null;
}
function shouldAdjustOldDeltas(orgEvent, absDelta) {
// If this is an older event and the delta is divisable by 120,
// then we are assuming that the browser is treating this as an
// older mouse wheel event and that we should divide the deltas
// by 40 to try and get a more usable deltaFactor.
// Side note, this actually impacts the reported scroll distance
// in older browsers and can cause scrolling to be slower than native.
// Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
}
}));
S2.define('jquery.select2',[
'jquery',
'jquery-mousewheel',
'./select2/core',
'./select2/defaults',
'./select2/utils'
], function ($, _, Select2, Defaults, Utils) {
if ($.fn.select2 == null) {
// All methods that should return the element
var thisMethods = ['open', 'close', 'destroy'];
$.fn.select2 = function (options) {
options = options || {};
if (typeof options === 'object') {
this.each(function () {
var instanceOptions = $.extend(true, {}, options);
var instance = new Select2($(this), instanceOptions);
});
return this;
} else if (typeof options === 'string') {
var ret;
var args = Array.prototype.slice.call(arguments, 1);
this.each(function () {
var instance = Utils.GetData(this, 'select2');
if (instance == null && window.console && console.error) {
console.error(
'The select2(\'' + options + '\') method was called on an ' +
'element that is not using Select2.'
);
}
ret = instance[options].apply(instance, args);
});
// Check if we should be returning `this`
if ($.inArray(options, thisMethods) > -1) {
return this;
}
return ret;
} else {
throw new Error('Invalid arguments for Select2: ' + options);
}
};
}
if ($.fn.select2.defaults == null) {
$.fn.select2.defaults = Defaults;
}
return Select2;
});
// Return the AMD loader configuration so it can be used outside of this file
return {
define: S2.define,
require: S2.require
};
}());
// Autoload the jQuery bindings
// We know that all of the modules exist above this, so we're safe
var select2 = S2.require('jquery.select2');
// Hold the AMD module references on the jQuery function that was just loaded
// This allows Select2 to use the internal loader outside of this file, such
// as in the language files.
jQuery.fn.select2.amd = S2;
// Return the Select2 instance for anyone who is importing it.
return select2;
}));
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
(function($) {
/*
$(".my-pagination").pagination();
$(".my-pagination").pagination({total_pages: 3, current_page: 1});
$(".my-pagination").pagination({
total_pages: 3,
current_page: 1,
callback: function(event, page) {
alert("Clicked: " + page);
}
});
*/
var PaginationView;
$.fn.pagination = function(options) {
return this.each(function() {
return new PaginationView($(this), options).render();
});
};
return PaginationView = (function() {
function PaginationView(el, options) {
var defaults;
this.el = el;
this.change = __bind(this.change, this);
this.clicked = __bind(this.clicked, this);
this.isValidPage = __bind(this.isValidPage, this);
this.render = __bind(this.render, this);
this.pages = __bind(this.pages, this);
this.buildLink = __bind(this.buildLink, this);
this.buildLi = __bind(this.buildLi, this);
this.buildLinks = __bind(this.buildLinks, this);
defaults = {
current_page: 1,
total_pages: 1,
next: ">",
prev: "<",
first: false,
last: false,
display_max: 8,
ignore_single_page: true,
no_turbolink: false
};
this.settings = $.extend(defaults, options);
if ($(document).on) {
$(this.el).on("click", "a", this.clicked);
} else {
$("a", this.el).live("click", this.clicked);
}
this.el.data("paginationView", this);
}
PaginationView.prototype.buildLinks = function() {
var current_page, links, page, _i, _len, _ref;
current_page = this.settings.current_page;
links = [];
if (this.settings.first) {
links.push(this.buildLi(1, this.settings.first));
}
if (this.settings.prev) {
links.push(this.buildLi(current_page - 1, this.settings.prev));
}
_ref = this.pages();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
page = _ref[_i];
links.push(this.buildLi(page, page));
}
if (this.settings.next) {
links.push(this.buildLi(current_page + 1, this.settings.next));
}
if (this.settings.last) {
links.push(this.buildLi(this.settings.total_pages, this.settings.last));
}
return links;
};
PaginationView.prototype.buildLi = function(page, text) {
if (text == null) {
text = page;
}
return "" + (this.buildLink(page, text)) + " ";
};
PaginationView.prototype.buildLink = function(page, text) {
var data_attr;
if (text == null) {
text = page;
}
if (this.settings.no_turbolink) {
data_attr = " data-no-turbolink='1'";
} else {
data_attr = "";
}
return "" + text + " ";
};
PaginationView.prototype.pages = function() {
var buf, current_page, max, page, pages, total_pages, _i, _j, _k, _l, _m, _ref, _ref1, _ref2, _ref3;
total_pages = this.settings.total_pages;
current_page = this.settings.current_page;
pages = [];
max = this.settings.display_max;
if (total_pages > 10) {
pages.push(1);
if (current_page > max - 1) {
pages.push("..");
}
if (current_page === total_pages) {
for (page = _i = _ref = total_pages - max; _ref <= total_pages ? _i <= total_pages : _i >= total_pages; page = _ref <= total_pages ? ++_i : --_i) {
pages.push(page);
}
}
if (total_pages - current_page < max - 1) {
for (page = _j = _ref1 = total_pages - max; _ref1 <= total_pages ? _j <= total_pages : _j >= total_pages; page = _ref1 <= total_pages ? ++_j : --_j) {
pages.push(page);
}
} else if (current_page > max - 1) {
buf = max / 2;
for (page = _k = _ref2 = current_page - buf, _ref3 = current_page + buf; _ref2 <= _ref3 ? _k <= _ref3 : _k >= _ref3; page = _ref2 <= _ref3 ? ++_k : --_k) {
pages.push(page);
}
} else if (current_page <= max - 1) {
for (page = _l = 2; 2 <= max ? _l <= max : _l >= max; page = 2 <= max ? ++_l : --_l) {
pages.push(page);
}
}
pages = $.grep(pages, function(v, k) {
return $.inArray(v, pages) === k;
});
if (__indexOf.call(pages, total_pages) < 0) {
if (!((total_pages - current_page) < max - 1)) {
pages.push("..");
}
pages.push(total_pages);
}
} else {
for (page = _m = 1; 1 <= total_pages ? _m <= total_pages : _m >= total_pages; page = 1 <= total_pages ? ++_m : --_m) {
pages.push(page);
}
}
return pages;
};
PaginationView.prototype.render = function() {
var html, link, _i, _len, _ref;
this.el.html("");
if (this.settings.total_pages === 1 && this.settings.ignore_single_page) {
return;
}
html = ["");
this.el.html(html.join("\n"));
$("[data-page=" + this.settings.current_page + "]", this.el).closest("li").addClass("active");
$("[data-page='..']", this.el).closest("li").addClass("disabled");
$("[data-page='0']", this.el).closest("li").addClass("disabled");
$("[data-page='" + (this.settings.total_pages + 1) + "']", this.el).closest("li").addClass("disabled");
if (this.settings.current_page === 1 && this.settings.first) {
$("li:first", this.el).removeClass("active").addClass("disabled");
}
if (this.settings.current_page === this.settings.total_pages && this.settings.last) {
return $("li:last", this.el).removeClass("active").addClass("disabled");
}
};
PaginationView.prototype.isValidPage = function(page) {
return page > 0 && page !== this.settings.current_page && page <= this.settings.total_pages;
};
PaginationView.prototype.clicked = function(event) {
var page;
page = parseInt($(event.target).attr("data-page"));
if (!this.isValidPage(page)) {
return;
}
if (this.settings.callback != null) {
this.settings.callback(event, page);
}
return this.change(page);
};
PaginationView.prototype.change = function(page) {
page = parseInt(page);
if (!this.isValidPage(page)) {
return;
}
this.settings.current_page = page;
return this.render();
};
return PaginationView;
})();
})(jQuery);
}).call(this);
/* == jquery mousewheel plugin == Version: 3.1.13, License: MIT License (MIT) */
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});
/* == malihu jquery custom scrollbar plugin == Version: 3.1.5, License: MIT License (MIT) */
!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"undefined"!=typeof module&&module.exports?module.exports=e:e(jQuery,window,document)}(function(e){!function(t){var o="function"==typeof define&&define.amd,a="undefined"!=typeof module&&module.exports,n="https:"==document.location.protocol?"https:":"http:",i="cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js";o||(a?require("jquery-mousewheel")(e):e.event.special.mousewheel||e("head").append(decodeURI("%3Cscript src="+n+"//"+i+"%3E%3C/script%3E"))),t()}(function(){var t,o="mCustomScrollbar",a="mCS",n=".mCustomScrollbar",i={setTop:0,setLeft:0,axis:"y",scrollbarPosition:"inside",scrollInertia:950,autoDraggerLength:!0,alwaysShowScrollbar:0,snapOffset:0,mouseWheel:{enable:!0,scrollAmount:"auto",axis:"y",deltaFactor:"auto",disableOver:["select","option","keygen","datalist","textarea"]},scrollButtons:{scrollType:"stepless",scrollAmount:"auto"},keyboard:{enable:!0,scrollType:"stepless",scrollAmount:"auto"},contentTouchScroll:25,documentTouchScroll:!0,advanced:{autoScrollOnFocus:"input,textarea,select,button,datalist,keygen,a[tabindex],area,object,[contenteditable='true']",updateOnContentResize:!0,updateOnImageLoad:"auto",autoUpdateTimeout:60},theme:"light",callbacks:{onTotalScrollOffset:0,onTotalScrollBackOffset:0,alwaysTriggerOffsets:!0}},r=0,l={},s=window.attachEvent&&!window.addEventListener?1:0,c=!1,d=["mCSB_dragger_onDrag","mCSB_scrollTools_onDrag","mCS_img_loaded","mCS_disabled","mCS_destroyed","mCS_no_scrollbar","mCS-autoHide","mCS-dir-rtl","mCS_no_scrollbar_y","mCS_no_scrollbar_x","mCS_y_hidden","mCS_x_hidden","mCSB_draggerContainer","mCSB_buttonUp","mCSB_buttonDown","mCSB_buttonLeft","mCSB_buttonRight"],u={init:function(t){var t=e.extend(!0,{},i,t),o=f.call(this);if(t.live){var s=t.liveSelector||this.selector||n,c=e(s);if("off"===t.live)return void m(s);l[s]=setTimeout(function(){c.mCustomScrollbar(t),"once"===t.live&&c.length&&m(s)},500)}else m(s);return t.setWidth=t.set_width?t.set_width:t.setWidth,t.setHeight=t.set_height?t.set_height:t.setHeight,t.axis=t.horizontalScroll?"x":p(t.axis),t.scrollInertia=t.scrollInertia>0&&t.scrollInertia<17?17:t.scrollInertia,"object"!=typeof t.mouseWheel&&1==t.mouseWheel&&(t.mouseWheel={enable:!0,scrollAmount:"auto",axis:"y",preventDefault:!1,deltaFactor:"auto",normalizeDelta:!1,invert:!1}),t.mouseWheel.scrollAmount=t.mouseWheelPixels?t.mouseWheelPixels:t.mouseWheel.scrollAmount,t.mouseWheel.normalizeDelta=t.advanced.normalizeMouseWheelDelta?t.advanced.normalizeMouseWheelDelta:t.mouseWheel.normalizeDelta,t.scrollButtons.scrollType=g(t.scrollButtons.scrollType),h(t),e(o).each(function(){var o=e(this);if(!o.data(a)){o.data(a,{idx:++r,opt:t,scrollRatio:{y:null,x:null},overflowed:null,contentReset:{y:null,x:null},bindEvents:!1,tweenRunning:!1,sequential:{},langDir:o.css("direction"),cbOffsets:null,trigger:null,poll:{size:{o:0,n:0},img:{o:0,n:0},change:{o:0,n:0}}});var n=o.data(a),i=n.opt,l=o.data("mcs-axis"),s=o.data("mcs-scrollbar-position"),c=o.data("mcs-theme");l&&(i.axis=l),s&&(i.scrollbarPosition=s),c&&(i.theme=c,h(i)),v.call(this),n&&i.callbacks.onCreate&&"function"==typeof i.callbacks.onCreate&&i.callbacks.onCreate.call(this),e("#mCSB_"+n.idx+"_container img:not(."+d[2]+")").addClass(d[2]),u.update.call(null,o)}})},update:function(t,o){var n=t||f.call(this);return e(n).each(function(){var t=e(this);if(t.data(a)){var n=t.data(a),i=n.opt,r=e("#mCSB_"+n.idx+"_container"),l=e("#mCSB_"+n.idx),s=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")];if(!r.length)return;n.tweenRunning&&Q(t),o&&n&&i.callbacks.onBeforeUpdate&&"function"==typeof i.callbacks.onBeforeUpdate&&i.callbacks.onBeforeUpdate.call(this),t.hasClass(d[3])&&t.removeClass(d[3]),t.hasClass(d[4])&&t.removeClass(d[4]),l.css("max-height","none"),l.height()!==t.height()&&l.css("max-height",t.height()),_.call(this),"y"===i.axis||i.advanced.autoExpandHorizontalScroll||r.css("width",x(r)),n.overflowed=y.call(this),M.call(this),i.autoDraggerLength&&S.call(this),b.call(this),T.call(this);var c=[Math.abs(r[0].offsetTop),Math.abs(r[0].offsetLeft)];"x"!==i.axis&&(n.overflowed[0]?s[0].height()>s[0].parent().height()?B.call(this):(G(t,c[0].toString(),{dir:"y",dur:0,overwrite:"none"}),n.contentReset.y=null):(B.call(this),"y"===i.axis?k.call(this):"yx"===i.axis&&n.overflowed[1]&&G(t,c[1].toString(),{dir:"x",dur:0,overwrite:"none"}))),"y"!==i.axis&&(n.overflowed[1]?s[1].width()>s[1].parent().width()?B.call(this):(G(t,c[1].toString(),{dir:"x",dur:0,overwrite:"none"}),n.contentReset.x=null):(B.call(this),"x"===i.axis?k.call(this):"yx"===i.axis&&n.overflowed[0]&&G(t,c[0].toString(),{dir:"y",dur:0,overwrite:"none"}))),o&&n&&(2===o&&i.callbacks.onImageLoad&&"function"==typeof i.callbacks.onImageLoad?i.callbacks.onImageLoad.call(this):3===o&&i.callbacks.onSelectorChange&&"function"==typeof i.callbacks.onSelectorChange?i.callbacks.onSelectorChange.call(this):i.callbacks.onUpdate&&"function"==typeof i.callbacks.onUpdate&&i.callbacks.onUpdate.call(this)),N.call(this)}})},scrollTo:function(t,o){if("undefined"!=typeof t&&null!=t){var n=f.call(this);return e(n).each(function(){var n=e(this);if(n.data(a)){var i=n.data(a),r=i.opt,l={trigger:"external",scrollInertia:r.scrollInertia,scrollEasing:"mcsEaseInOut",moveDragger:!1,timeout:60,callbacks:!0,onStart:!0,onUpdate:!0,onComplete:!0},s=e.extend(!0,{},l,o),c=Y.call(this,t),d=s.scrollInertia>0&&s.scrollInertia<17?17:s.scrollInertia;c[0]=X.call(this,c[0],"y"),c[1]=X.call(this,c[1],"x"),s.moveDragger&&(c[0]*=i.scrollRatio.y,c[1]*=i.scrollRatio.x),s.dur=ne()?0:d,setTimeout(function(){null!==c[0]&&"undefined"!=typeof c[0]&&"x"!==r.axis&&i.overflowed[0]&&(s.dir="y",s.overwrite="all",G(n,c[0].toString(),s)),null!==c[1]&&"undefined"!=typeof c[1]&&"y"!==r.axis&&i.overflowed[1]&&(s.dir="x",s.overwrite="none",G(n,c[1].toString(),s))},s.timeout)}})}},stop:function(){var t=f.call(this);return e(t).each(function(){var t=e(this);t.data(a)&&Q(t)})},disable:function(t){var o=f.call(this);return e(o).each(function(){var o=e(this);if(o.data(a)){o.data(a);N.call(this,"remove"),k.call(this),t&&B.call(this),M.call(this,!0),o.addClass(d[3])}})},destroy:function(){var t=f.call(this);return e(t).each(function(){var n=e(this);if(n.data(a)){var i=n.data(a),r=i.opt,l=e("#mCSB_"+i.idx),s=e("#mCSB_"+i.idx+"_container"),c=e(".mCSB_"+i.idx+"_scrollbar");r.live&&m(r.liveSelector||e(t).selector),N.call(this,"remove"),k.call(this),B.call(this),n.removeData(a),$(this,"mcs"),c.remove(),s.find("img."+d[2]).removeClass(d[2]),l.replaceWith(s.contents()),n.removeClass(o+" _"+a+"_"+i.idx+" "+d[6]+" "+d[7]+" "+d[5]+" "+d[3]).addClass(d[4])}})}},f=function(){return"object"!=typeof e(this)||e(this).length<1?n:this},h=function(t){var o=["rounded","rounded-dark","rounded-dots","rounded-dots-dark"],a=["rounded-dots","rounded-dots-dark","3d","3d-dark","3d-thick","3d-thick-dark","inset","inset-dark","inset-2","inset-2-dark","inset-3","inset-3-dark"],n=["minimal","minimal-dark"],i=["minimal","minimal-dark"],r=["minimal","minimal-dark"];t.autoDraggerLength=e.inArray(t.theme,o)>-1?!1:t.autoDraggerLength,t.autoExpandScrollbar=e.inArray(t.theme,a)>-1?!1:t.autoExpandScrollbar,t.scrollButtons.enable=e.inArray(t.theme,n)>-1?!1:t.scrollButtons.enable,t.autoHideScrollbar=e.inArray(t.theme,i)>-1?!0:t.autoHideScrollbar,t.scrollbarPosition=e.inArray(t.theme,r)>-1?"outside":t.scrollbarPosition},m=function(e){l[e]&&(clearTimeout(l[e]),$(l,e))},p=function(e){return"yx"===e||"xy"===e||"auto"===e?"yx":"x"===e||"horizontal"===e?"x":"y"},g=function(e){return"stepped"===e||"pixels"===e||"step"===e||"click"===e?"stepped":"stepless"},v=function(){var t=e(this),n=t.data(a),i=n.opt,r=i.autoExpandScrollbar?" "+d[1]+"_expand":"",l=["",""],s="yx"===i.axis?"mCSB_vertical_horizontal":"x"===i.axis?"mCSB_horizontal":"mCSB_vertical",c="yx"===i.axis?l[0]+l[1]:"x"===i.axis?l[1]:l[0],u="yx"===i.axis?"
":"",f=i.autoHideScrollbar?" "+d[6]:"",h="x"!==i.axis&&"rtl"===n.langDir?" "+d[7]:"";i.setWidth&&t.css("width",i.setWidth),i.setHeight&&t.css("height",i.setHeight),i.setLeft="y"!==i.axis&&"rtl"===n.langDir?"989999px":i.setLeft,t.addClass(o+" _"+a+"_"+n.idx+f+h).wrapInner("");var m=e("#mCSB_"+n.idx),p=e("#mCSB_"+n.idx+"_container");"y"===i.axis||i.advanced.autoExpandHorizontalScroll||p.css("width",x(p)),"outside"===i.scrollbarPosition?("static"===t.css("position")&&t.css("position","relative"),t.css("overflow","visible"),m.addClass("mCSB_outside").after(c)):(m.addClass("mCSB_inside").append(c),p.wrap(u)),w.call(this);var g=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")];g[0].css("min-height",g[0].height()),g[1].css("min-width",g[1].width())},x=function(t){var o=[t[0].scrollWidth,Math.max.apply(Math,t.children().map(function(){return e(this).outerWidth(!0)}).get())],a=t.parent().width();return o[0]>a?o[0]:o[1]>a?o[1]:"100%"},_=function(){var t=e(this),o=t.data(a),n=o.opt,i=e("#mCSB_"+o.idx+"_container");if(n.advanced.autoExpandHorizontalScroll&&"y"!==n.axis){i.css({width:"auto","min-width":0,"overflow-x":"scroll"});var r=Math.ceil(i[0].scrollWidth);3===n.advanced.autoExpandHorizontalScroll||2!==n.advanced.autoExpandHorizontalScroll&&r>i.parent().width()?i.css({width:r,"min-width":"100%","overflow-x":"inherit"}):i.css({"overflow-x":"inherit",position:"absolute"}).wrap("
").css({width:Math.ceil(i[0].getBoundingClientRect().right+.4)-Math.floor(i[0].getBoundingClientRect().left),"min-width":"100%",position:"relative"}).unwrap()}},w=function(){var t=e(this),o=t.data(a),n=o.opt,i=e(".mCSB_"+o.idx+"_scrollbar:first"),r=oe(n.scrollButtons.tabindex)?"tabindex='"+n.scrollButtons.tabindex+"'":"",l=[" "," "," "," "],s=["x"===n.axis?l[2]:l[0],"x"===n.axis?l[3]:l[1],l[2],l[3]];n.scrollButtons.enable&&i.prepend(s[0]).append(s[1]).next(".mCSB_scrollTools").prepend(s[2]).append(s[3])},S=function(){var t=e(this),o=t.data(a),n=e("#mCSB_"+o.idx),i=e("#mCSB_"+o.idx+"_container"),r=[e("#mCSB_"+o.idx+"_dragger_vertical"),e("#mCSB_"+o.idx+"_dragger_horizontal")],l=[n.height()/i.outerHeight(!1),n.width()/i.outerWidth(!1)],c=[parseInt(r[0].css("min-height")),Math.round(l[0]*r[0].parent().height()),parseInt(r[1].css("min-width")),Math.round(l[1]*r[1].parent().width())],d=s&&c[1]r&&(r=s),c>l&&(l=c),[r>n.height(),l>n.width()]},B=function(){var t=e(this),o=t.data(a),n=o.opt,i=e("#mCSB_"+o.idx),r=e("#mCSB_"+o.idx+"_container"),l=[e("#mCSB_"+o.idx+"_dragger_vertical"),e("#mCSB_"+o.idx+"_dragger_horizontal")];if(Q(t),("x"!==n.axis&&!o.overflowed[0]||"y"===n.axis&&o.overflowed[0])&&(l[0].add(r).css("top",0),G(t,"_resetY")),"y"!==n.axis&&!o.overflowed[1]||"x"===n.axis&&o.overflowed[1]){var s=dx=0;"rtl"===o.langDir&&(s=i.width()-r.outerWidth(!1),dx=Math.abs(s/o.scrollRatio.x)),r.css("left",s),l[1].css("left",dx),G(t,"_resetX")}},T=function(){function t(){r=setTimeout(function(){e.event.special.mousewheel?(clearTimeout(r),W.call(o[0])):t()},100)}var o=e(this),n=o.data(a),i=n.opt;if(!n.bindEvents){if(I.call(this),i.contentTouchScroll&&D.call(this),E.call(this),i.mouseWheel.enable){var r;t()}P.call(this),U.call(this),i.advanced.autoScrollOnFocus&&H.call(this),i.scrollButtons.enable&&F.call(this),i.keyboard.enable&&q.call(this),n.bindEvents=!0}},k=function(){var t=e(this),o=t.data(a),n=o.opt,i=a+"_"+o.idx,r=".mCSB_"+o.idx+"_scrollbar",l=e("#mCSB_"+o.idx+",#mCSB_"+o.idx+"_container,#mCSB_"+o.idx+"_container_wrapper,"+r+" ."+d[12]+",#mCSB_"+o.idx+"_dragger_vertical,#mCSB_"+o.idx+"_dragger_horizontal,"+r+">a"),s=e("#mCSB_"+o.idx+"_container");n.advanced.releaseDraggableSelectors&&l.add(e(n.advanced.releaseDraggableSelectors)),n.advanced.extraDraggableSelectors&&l.add(e(n.advanced.extraDraggableSelectors)),o.bindEvents&&(e(document).add(e(!A()||top.document)).unbind("."+i),l.each(function(){e(this).unbind("."+i)}),clearTimeout(t[0]._focusTimeout),$(t[0],"_focusTimeout"),clearTimeout(o.sequential.step),$(o.sequential,"step"),clearTimeout(s[0].onCompleteTimeout),$(s[0],"onCompleteTimeout"),o.bindEvents=!1)},M=function(t){var o=e(this),n=o.data(a),i=n.opt,r=e("#mCSB_"+n.idx+"_container_wrapper"),l=r.length?r:e("#mCSB_"+n.idx+"_container"),s=[e("#mCSB_"+n.idx+"_scrollbar_vertical"),e("#mCSB_"+n.idx+"_scrollbar_horizontal")],c=[s[0].find(".mCSB_dragger"),s[1].find(".mCSB_dragger")];"x"!==i.axis&&(n.overflowed[0]&&!t?(s[0].add(c[0]).add(s[0].children("a")).css("display","block"),l.removeClass(d[8]+" "+d[10])):(i.alwaysShowScrollbar?(2!==i.alwaysShowScrollbar&&c[0].css("display","none"),l.removeClass(d[10])):(s[0].css("display","none"),l.addClass(d[10])),l.addClass(d[8]))),"y"!==i.axis&&(n.overflowed[1]&&!t?(s[1].add(c[1]).add(s[1].children("a")).css("display","block"),l.removeClass(d[9]+" "+d[11])):(i.alwaysShowScrollbar?(2!==i.alwaysShowScrollbar&&c[1].css("display","none"),l.removeClass(d[11])):(s[1].css("display","none"),l.addClass(d[11])),l.addClass(d[9]))),n.overflowed[0]||n.overflowed[1]?o.removeClass(d[5]):o.addClass(d[5])},O=function(t){var o=t.type,a=t.target.ownerDocument!==document&&null!==frameElement?[e(frameElement).offset().top,e(frameElement).offset().left]:null,n=A()&&t.target.ownerDocument!==top.document&&null!==frameElement?[e(t.view.frameElement).offset().top,e(t.view.frameElement).offset().left]:[0,0];switch(o){case"pointerdown":case"MSPointerDown":case"pointermove":case"MSPointerMove":case"pointerup":case"MSPointerUp":return a?[t.originalEvent.pageY-a[0]+n[0],t.originalEvent.pageX-a[1]+n[1],!1]:[t.originalEvent.pageY,t.originalEvent.pageX,!1];case"touchstart":case"touchmove":case"touchend":var i=t.originalEvent.touches[0]||t.originalEvent.changedTouches[0],r=t.originalEvent.touches.length||t.originalEvent.changedTouches.length;return t.target.ownerDocument!==document?[i.screenY,i.screenX,r>1]:[i.pageY,i.pageX,r>1];default:return a?[t.pageY-a[0]+n[0],t.pageX-a[1]+n[1],!1]:[t.pageY,t.pageX,!1]}},I=function(){function t(e,t,a,n){if(h[0].idleTimer=d.scrollInertia<233?250:0,o.attr("id")===f[1])var i="x",s=(o[0].offsetLeft-t+n)*l.scrollRatio.x;else var i="y",s=(o[0].offsetTop-e+a)*l.scrollRatio.y;G(r,s.toString(),{dir:i,drag:!0})}var o,n,i,r=e(this),l=r.data(a),d=l.opt,u=a+"_"+l.idx,f=["mCSB_"+l.idx+"_dragger_vertical","mCSB_"+l.idx+"_dragger_horizontal"],h=e("#mCSB_"+l.idx+"_container"),m=e("#"+f[0]+",#"+f[1]),p=d.advanced.releaseDraggableSelectors?m.add(e(d.advanced.releaseDraggableSelectors)):m,g=d.advanced.extraDraggableSelectors?e(!A()||top.document).add(e(d.advanced.extraDraggableSelectors)):e(!A()||top.document);m.bind("contextmenu."+u,function(e){e.preventDefault()}).bind("mousedown."+u+" touchstart."+u+" pointerdown."+u+" MSPointerDown."+u,function(t){if(t.stopImmediatePropagation(),t.preventDefault(),ee(t)){c=!0,s&&(document.onselectstart=function(){return!1}),L.call(h,!1),Q(r),o=e(this);var a=o.offset(),l=O(t)[0]-a.top,u=O(t)[1]-a.left,f=o.height()+a.top,m=o.width()+a.left;f>l&&l>0&&m>u&&u>0&&(n=l,i=u),C(o,"active",d.autoExpandScrollbar)}}).bind("touchmove."+u,function(e){e.stopImmediatePropagation(),e.preventDefault();var a=o.offset(),r=O(e)[0]-a.top,l=O(e)[1]-a.left;t(n,i,r,l)}),e(document).add(g).bind("mousemove."+u+" pointermove."+u+" MSPointerMove."+u,function(e){if(o){var a=o.offset(),r=O(e)[0]-a.top,l=O(e)[1]-a.left;if(n===r&&i===l)return;t(n,i,r,l)}}).add(p).bind("mouseup."+u+" touchend."+u+" pointerup."+u+" MSPointerUp."+u,function(){o&&(C(o,"active",d.autoExpandScrollbar),o=null),c=!1,s&&(document.onselectstart=null),L.call(h,!0)})},D=function(){function o(e){if(!te(e)||c||O(e)[2])return void(t=0);t=1,b=0,C=0,d=1,y.removeClass("mCS_touch_action");var o=I.offset();u=O(e)[0]-o.top,f=O(e)[1]-o.left,z=[O(e)[0],O(e)[1]]}function n(e){if(te(e)&&!c&&!O(e)[2]&&(T.documentTouchScroll||e.preventDefault(),e.stopImmediatePropagation(),(!C||b)&&d)){g=K();var t=M.offset(),o=O(e)[0]-t.top,a=O(e)[1]-t.left,n="mcsLinearOut";if(E.push(o),W.push(a),z[2]=Math.abs(O(e)[0]-z[0]),z[3]=Math.abs(O(e)[1]-z[1]),B.overflowed[0])var i=D[0].parent().height()-D[0].height(),r=u-o>0&&o-u>-(i*B.scrollRatio.y)&&(2*z[3]0&&a-f>-(l*B.scrollRatio.x)&&(2*z[2]30)){_=1e3/(v-p);var n="mcsEaseOut",i=2.5>_,r=i?[E[E.length-2],W[W.length-2]]:[0,0];x=i?[o-r[0],a-r[1]]:[o-h,a-m];var u=[Math.abs(x[0]),Math.abs(x[1])];_=i?[Math.abs(x[0]/4),Math.abs(x[1]/4)]:[_,_];var f=[Math.abs(I[0].offsetTop)-x[0]*l(u[0]/_[0],_[0]),Math.abs(I[0].offsetLeft)-x[1]*l(u[1]/_[1],_[1])];w="yx"===T.axis?[f[0],f[1]]:"x"===T.axis?[null,f[1]]:[f[0],null],S=[4*u[0]+T.scrollInertia,4*u[1]+T.scrollInertia];var y=parseInt(T.contentTouchScroll)||0;w[0]=u[0]>y?w[0]:0,w[1]=u[1]>y?w[1]:0,B.overflowed[0]&&s(w[0],S[0],n,"y",L,!1),B.overflowed[1]&&s(w[1],S[1],n,"x",L,!1)}}}function l(e,t){var o=[1.5*t,2*t,t/1.5,t/2];return e>90?t>4?o[0]:o[3]:e>60?t>3?o[3]:o[2]:e>30?t>8?o[1]:t>6?o[0]:t>4?t:o[2]:t>8?t:o[3]}function s(e,t,o,a,n,i){e&&G(y,e.toString(),{dur:t,scrollEasing:o,dir:a,overwrite:n,drag:i})}var d,u,f,h,m,p,g,v,x,_,w,S,b,C,y=e(this),B=y.data(a),T=B.opt,k=a+"_"+B.idx,M=e("#mCSB_"+B.idx),I=e("#mCSB_"+B.idx+"_container"),D=[e("#mCSB_"+B.idx+"_dragger_vertical"),e("#mCSB_"+B.idx+"_dragger_horizontal")],E=[],W=[],R=0,L="yx"===T.axis?"none":"all",z=[],P=I.find("iframe"),H=["touchstart."+k+" pointerdown."+k+" MSPointerDown."+k,"touchmove."+k+" pointermove."+k+" MSPointerMove."+k,"touchend."+k+" pointerup."+k+" MSPointerUp."+k],U=void 0!==document.body.style.touchAction&&""!==document.body.style.touchAction;I.bind(H[0],function(e){o(e)}).bind(H[1],function(e){n(e)}),M.bind(H[0],function(e){i(e)}).bind(H[2],function(e){r(e)}),P.length&&P.each(function(){e(this).bind("load",function(){A(this)&&e(this.contentDocument||this.contentWindow.document).bind(H[0],function(e){o(e),i(e)}).bind(H[1],function(e){n(e)}).bind(H[2],function(e){r(e)})})})},E=function(){function o(){return window.getSelection?window.getSelection().toString():document.selection&&"Control"!=document.selection.type?document.selection.createRange().text:0}function n(e,t,o){d.type=o&&i?"stepped":"stepless",d.scrollAmount=10,j(r,e,t,"mcsLinearOut",o?60:null)}var i,r=e(this),l=r.data(a),s=l.opt,d=l.sequential,u=a+"_"+l.idx,f=e("#mCSB_"+l.idx+"_container"),h=f.parent();f.bind("mousedown."+u,function(){t||i||(i=1,c=!0)}).add(document).bind("mousemove."+u,function(e){if(!t&&i&&o()){var a=f.offset(),r=O(e)[0]-a.top+f[0].offsetTop,c=O(e)[1]-a.left+f[0].offsetLeft;r>0&&r0&&cr?n("on",38):r>h.height()&&n("on",40)),"y"!==s.axis&&l.overflowed[1]&&(0>c?n("on",37):c>h.width()&&n("on",39)))}}).bind("mouseup."+u+" dragend."+u,function(){t||(i&&(i=0,n("off",null)),c=!1)})},W=function(){function t(t,a){if(Q(o),!z(o,t.target)){var r="auto"!==i.mouseWheel.deltaFactor?parseInt(i.mouseWheel.deltaFactor):s&&t.deltaFactor<100?100:t.deltaFactor||100,d=i.scrollInertia;if("x"===i.axis||"x"===i.mouseWheel.axis)var u="x",f=[Math.round(r*n.scrollRatio.x),parseInt(i.mouseWheel.scrollAmount)],h="auto"!==i.mouseWheel.scrollAmount?f[1]:f[0]>=l.width()?.9*l.width():f[0],m=Math.abs(e("#mCSB_"+n.idx+"_container")[0].offsetLeft),p=c[1][0].offsetLeft,g=c[1].parent().width()-c[1].width(),v="y"===i.mouseWheel.axis?t.deltaY||a:t.deltaX;else var u="y",f=[Math.round(r*n.scrollRatio.y),parseInt(i.mouseWheel.scrollAmount)],h="auto"!==i.mouseWheel.scrollAmount?f[1]:f[0]>=l.height()?.9*l.height():f[0],m=Math.abs(e("#mCSB_"+n.idx+"_container")[0].offsetTop),p=c[0][0].offsetTop,g=c[0].parent().height()-c[0].height(),v=t.deltaY||a;"y"===u&&!n.overflowed[0]||"x"===u&&!n.overflowed[1]||((i.mouseWheel.invert||t.webkitDirectionInvertedFromDevice)&&(v=-v),i.mouseWheel.normalizeDelta&&(v=0>v?-1:1),(v>0&&0!==p||0>v&&p!==g||i.mouseWheel.preventDefault)&&(t.stopImmediatePropagation(),t.preventDefault()),t.deltaFactor<5&&!i.mouseWheel.normalizeDelta&&(h=t.deltaFactor,d=17),G(o,(m-v*h).toString(),{dir:u,dur:d}))}}if(e(this).data(a)){var o=e(this),n=o.data(a),i=n.opt,r=a+"_"+n.idx,l=e("#mCSB_"+n.idx),c=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")],d=e("#mCSB_"+n.idx+"_container").find("iframe");d.length&&d.each(function(){e(this).bind("load",function(){A(this)&&e(this.contentDocument||this.contentWindow.document).bind("mousewheel."+r,function(e,o){t(e,o)})})}),l.bind("mousewheel."+r,function(e,o){t(e,o)})}},R=new Object,A=function(t){var o=!1,a=!1,n=null;if(void 0===t?a="#empty":void 0!==e(t).attr("id")&&(a=e(t).attr("id")),a!==!1&&void 0!==R[a])return R[a];if(t){try{var i=t.contentDocument||t.contentWindow.document;n=i.body.innerHTML}catch(r){}o=null!==n}else{try{var i=top.document;n=i.body.innerHTML}catch(r){}o=null!==n}return a!==!1&&(R[a]=o),o},L=function(e){var t=this.find("iframe");if(t.length){var o=e?"auto":"none";t.css("pointer-events",o)}},z=function(t,o){var n=o.nodeName.toLowerCase(),i=t.data(a).opt.mouseWheel.disableOver,r=["select","textarea"];return e.inArray(n,i)>-1&&!(e.inArray(n,r)>-1&&!e(o).is(":focus"))},P=function(){var t,o=e(this),n=o.data(a),i=a+"_"+n.idx,r=e("#mCSB_"+n.idx+"_container"),l=r.parent(),s=e(".mCSB_"+n.idx+"_scrollbar ."+d[12]);s.bind("mousedown."+i+" touchstart."+i+" pointerdown."+i+" MSPointerDown."+i,function(o){c=!0,e(o.target).hasClass("mCSB_dragger")||(t=1)}).bind("touchend."+i+" pointerup."+i+" MSPointerUp."+i,function(){c=!1}).bind("click."+i,function(a){if(t&&(t=0,e(a.target).hasClass(d[12])||e(a.target).hasClass("mCSB_draggerRail"))){Q(o);var i=e(this),s=i.find(".mCSB_dragger");if(i.parent(".mCSB_scrollTools_horizontal").length>0){if(!n.overflowed[1])return;var c="x",u=a.pageX>s.offset().left?-1:1,f=Math.abs(r[0].offsetLeft)-u*(.9*l.width())}else{if(!n.overflowed[0])return;var c="y",u=a.pageY>s.offset().top?-1:1,f=Math.abs(r[0].offsetTop)-u*(.9*l.height())}G(o,f.toString(),{dir:c,scrollEasing:"mcsEaseInOut"})}})},H=function(){var t=e(this),o=t.data(a),n=o.opt,i=a+"_"+o.idx,r=e("#mCSB_"+o.idx+"_container"),l=r.parent();r.bind("focusin."+i,function(){var o=e(document.activeElement),a=r.find(".mCustomScrollBox").length,i=0;o.is(n.advanced.autoScrollOnFocus)&&(Q(t),clearTimeout(t[0]._focusTimeout),t[0]._focusTimer=a?(i+17)*a:0,t[0]._focusTimeout=setTimeout(function(){var e=[ae(o)[0],ae(o)[1]],a=[r[0].offsetTop,r[0].offsetLeft],s=[a[0]+e[0]>=0&&a[0]+e[0]=0&&a[0]+e[1]a");s.bind("contextmenu."+r,function(e){e.preventDefault()}).bind("mousedown."+r+" touchstart."+r+" pointerdown."+r+" MSPointerDown."+r+" mouseup."+r+" touchend."+r+" pointerup."+r+" MSPointerUp."+r+" mouseout."+r+" pointerout."+r+" MSPointerOut."+r+" click."+r,function(a){function r(e,o){i.scrollAmount=n.scrollButtons.scrollAmount,j(t,e,o)}if(a.preventDefault(),ee(a)){var l=e(this).attr("class");switch(i.type=n.scrollButtons.scrollType,a.type){case"mousedown":case"touchstart":case"pointerdown":case"MSPointerDown":if("stepped"===i.type)return;c=!0,o.tweenRunning=!1,r("on",l);break;case"mouseup":case"touchend":case"pointerup":case"MSPointerUp":case"mouseout":case"pointerout":case"MSPointerOut":if("stepped"===i.type)return;c=!1,i.dir&&r("off",l);break;case"click":if("stepped"!==i.type||o.tweenRunning)return;r("on",l)}}})},q=function(){function t(t){function a(e,t){r.type=i.keyboard.scrollType,r.scrollAmount=i.keyboard.scrollAmount,"stepped"===r.type&&n.tweenRunning||j(o,e,t)}switch(t.type){case"blur":n.tweenRunning&&r.dir&&a("off",null);break;case"keydown":case"keyup":var l=t.keyCode?t.keyCode:t.which,s="on";if("x"!==i.axis&&(38===l||40===l)||"y"!==i.axis&&(37===l||39===l)){if((38===l||40===l)&&!n.overflowed[0]||(37===l||39===l)&&!n.overflowed[1])return;"keyup"===t.type&&(s="off"),e(document.activeElement).is(u)||(t.preventDefault(),t.stopImmediatePropagation(),a(s,l))}else if(33===l||34===l){if((n.overflowed[0]||n.overflowed[1])&&(t.preventDefault(),t.stopImmediatePropagation()),"keyup"===t.type){Q(o);var f=34===l?-1:1;if("x"===i.axis||"yx"===i.axis&&n.overflowed[1]&&!n.overflowed[0])var h="x",m=Math.abs(c[0].offsetLeft)-f*(.9*d.width());else var h="y",m=Math.abs(c[0].offsetTop)-f*(.9*d.height());G(o,m.toString(),{dir:h,scrollEasing:"mcsEaseInOut"})}}else if((35===l||36===l)&&!e(document.activeElement).is(u)&&((n.overflowed[0]||n.overflowed[1])&&(t.preventDefault(),t.stopImmediatePropagation()),"keyup"===t.type)){if("x"===i.axis||"yx"===i.axis&&n.overflowed[1]&&!n.overflowed[0])var h="x",m=35===l?Math.abs(d.width()-c.outerWidth(!1)):0;else var h="y",m=35===l?Math.abs(d.height()-c.outerHeight(!1)):0;G(o,m.toString(),{dir:h,scrollEasing:"mcsEaseInOut"})}}}var o=e(this),n=o.data(a),i=n.opt,r=n.sequential,l=a+"_"+n.idx,s=e("#mCSB_"+n.idx),c=e("#mCSB_"+n.idx+"_container"),d=c.parent(),u="input,textarea,select,datalist,keygen,[contenteditable='true']",f=c.find("iframe"),h=["blur."+l+" keydown."+l+" keyup."+l];f.length&&f.each(function(){e(this).bind("load",function(){A(this)&&e(this.contentDocument||this.contentWindow.document).bind(h[0],function(e){t(e)})})}),s.attr("tabindex","0").bind(h[0],function(e){t(e)})},j=function(t,o,n,i,r){function l(e){u.snapAmount&&(f.scrollAmount=u.snapAmount instanceof Array?"x"===f.dir[0]?u.snapAmount[1]:u.snapAmount[0]:u.snapAmount);var o="stepped"!==f.type,a=r?r:e?o?p/1.5:g:1e3/60,n=e?o?7.5:40:2.5,s=[Math.abs(h[0].offsetTop),Math.abs(h[0].offsetLeft)],d=[c.scrollRatio.y>10?10:c.scrollRatio.y,c.scrollRatio.x>10?10:c.scrollRatio.x],m="x"===f.dir[0]?s[1]+f.dir[1]*(d[1]*n):s[0]+f.dir[1]*(d[0]*n),v="x"===f.dir[0]?s[1]+f.dir[1]*parseInt(f.scrollAmount):s[0]+f.dir[1]*parseInt(f.scrollAmount),x="auto"!==f.scrollAmount?v:m,_=i?i:e?o?"mcsLinearOut":"mcsEaseInOut":"mcsLinear",w=!!e;return e&&17>a&&(x="x"===f.dir[0]?s[1]:s[0]),G(t,x.toString(),{dir:f.dir[0],scrollEasing:_,dur:a,onComplete:w}),e?void(f.dir=!1):(clearTimeout(f.step),void(f.step=setTimeout(function(){l()},a)))}function s(){clearTimeout(f.step),$(f,"step"),Q(t)}var c=t.data(a),u=c.opt,f=c.sequential,h=e("#mCSB_"+c.idx+"_container"),m="stepped"===f.type,p=u.scrollInertia<26?26:u.scrollInertia,g=u.scrollInertia<1?17:u.scrollInertia;switch(o){case"on":if(f.dir=[n===d[16]||n===d[15]||39===n||37===n?"x":"y",n===d[13]||n===d[15]||38===n||37===n?-1:1],Q(t),oe(n)&&"stepped"===f.type)return;l(m);break;case"off":s(),(m||c.tweenRunning&&f.dir)&&l(!0)}},Y=function(t){var o=e(this).data(a).opt,n=[];return"function"==typeof t&&(t=t()),t instanceof Array?n=t.length>1?[t[0],t[1]]:"x"===o.axis?[null,t[0]]:[t[0],null]:(n[0]=t.y?t.y:t.x||"x"===o.axis?null:t,n[1]=t.x?t.x:t.y||"y"===o.axis?null:t),"function"==typeof n[0]&&(n[0]=n[0]()),"function"==typeof n[1]&&(n[1]=n[1]()),n},X=function(t,o){if(null!=t&&"undefined"!=typeof t){var n=e(this),i=n.data(a),r=i.opt,l=e("#mCSB_"+i.idx+"_container"),s=l.parent(),c=typeof t;o||(o="x"===r.axis?"x":"y");var d="x"===o?l.outerWidth(!1)-s.width():l.outerHeight(!1)-s.height(),f="x"===o?l[0].offsetLeft:l[0].offsetTop,h="x"===o?"left":"top";switch(c){case"function":return t();case"object":var m=t.jquery?t:e(t);if(!m.length)return;return"x"===o?ae(m)[1]:ae(m)[0];case"string":case"number":if(oe(t))return Math.abs(t);if(-1!==t.indexOf("%"))return Math.abs(d*parseInt(t)/100);if(-1!==t.indexOf("-="))return Math.abs(f-parseInt(t.split("-=")[1]));if(-1!==t.indexOf("+=")){var p=f+parseInt(t.split("+=")[1]);return p>=0?0:Math.abs(p)}if(-1!==t.indexOf("px")&&oe(t.split("px")[0]))return Math.abs(t.split("px")[0]);if("top"===t||"left"===t)return 0;if("bottom"===t)return Math.abs(s.height()-l.outerHeight(!1));if("right"===t)return Math.abs(s.width()-l.outerWidth(!1));if("first"===t||"last"===t){var m=l.find(":"+t);return"x"===o?ae(m)[1]:ae(m)[0]}return e(t).length?"x"===o?ae(e(t))[1]:ae(e(t))[0]:(l.css(h,t),void u.update.call(null,n[0]))}}},N=function(t){function o(){return clearTimeout(f[0].autoUpdate),0===l.parents("html").length?void(l=null):void(f[0].autoUpdate=setTimeout(function(){return c.advanced.updateOnSelectorChange&&(s.poll.change.n=i(),s.poll.change.n!==s.poll.change.o)?(s.poll.change.o=s.poll.change.n,void r(3)):c.advanced.updateOnContentResize&&(s.poll.size.n=l[0].scrollHeight+l[0].scrollWidth+f[0].offsetHeight+l[0].offsetHeight+l[0].offsetWidth,s.poll.size.n!==s.poll.size.o)?(s.poll.size.o=s.poll.size.n,void r(1)):!c.advanced.updateOnImageLoad||"auto"===c.advanced.updateOnImageLoad&&"y"===c.axis||(s.poll.img.n=f.find("img").length,s.poll.img.n===s.poll.img.o)?void((c.advanced.updateOnSelectorChange||c.advanced.updateOnContentResize||c.advanced.updateOnImageLoad)&&o()):(s.poll.img.o=s.poll.img.n,void f.find("img").each(function(){n(this)}))},c.advanced.autoUpdateTimeout))}function n(t){function o(e,t){return function(){
return t.apply(e,arguments)}}function a(){this.onload=null,e(t).addClass(d[2]),r(2)}if(e(t).hasClass(d[2]))return void r();var n=new Image;n.onload=o(n,a),n.src=t.src}function i(){c.advanced.updateOnSelectorChange===!0&&(c.advanced.updateOnSelectorChange="*");var e=0,t=f.find(c.advanced.updateOnSelectorChange);return c.advanced.updateOnSelectorChange&&t.length>0&&t.each(function(){e+=this.offsetHeight+this.offsetWidth}),e}function r(e){clearTimeout(f[0].autoUpdate),u.update.call(null,l[0],e)}var l=e(this),s=l.data(a),c=s.opt,f=e("#mCSB_"+s.idx+"_container");return t?(clearTimeout(f[0].autoUpdate),void $(f[0],"autoUpdate")):void o()},V=function(e,t,o){return Math.round(e/t)*t-o},Q=function(t){var o=t.data(a),n=e("#mCSB_"+o.idx+"_container,#mCSB_"+o.idx+"_container_wrapper,#mCSB_"+o.idx+"_dragger_vertical,#mCSB_"+o.idx+"_dragger_horizontal");n.each(function(){Z.call(this)})},G=function(t,o,n){function i(e){return s&&c.callbacks[e]&&"function"==typeof c.callbacks[e]}function r(){return[c.callbacks.alwaysTriggerOffsets||w>=S[0]+y,c.callbacks.alwaysTriggerOffsets||-B>=w]}function l(){var e=[h[0].offsetTop,h[0].offsetLeft],o=[x[0].offsetTop,x[0].offsetLeft],a=[h.outerHeight(!1),h.outerWidth(!1)],i=[f.height(),f.width()];t[0].mcs={content:h,top:e[0],left:e[1],draggerTop:o[0],draggerLeft:o[1],topPct:Math.round(100*Math.abs(e[0])/(Math.abs(a[0])-i[0])),leftPct:Math.round(100*Math.abs(e[1])/(Math.abs(a[1])-i[1])),direction:n.dir}}var s=t.data(a),c=s.opt,d={trigger:"internal",dir:"y",scrollEasing:"mcsEaseOut",drag:!1,dur:c.scrollInertia,overwrite:"all",callbacks:!0,onStart:!0,onUpdate:!0,onComplete:!0},n=e.extend(d,n),u=[n.dur,n.drag?0:n.dur],f=e("#mCSB_"+s.idx),h=e("#mCSB_"+s.idx+"_container"),m=h.parent(),p=c.callbacks.onTotalScrollOffset?Y.call(t,c.callbacks.onTotalScrollOffset):[0,0],g=c.callbacks.onTotalScrollBackOffset?Y.call(t,c.callbacks.onTotalScrollBackOffset):[0,0];if(s.trigger=n.trigger,0===m.scrollTop()&&0===m.scrollLeft()||(e(".mCSB_"+s.idx+"_scrollbar").css("visibility","visible"),m.scrollTop(0).scrollLeft(0)),"_resetY"!==o||s.contentReset.y||(i("onOverflowYNone")&&c.callbacks.onOverflowYNone.call(t[0]),s.contentReset.y=1),"_resetX"!==o||s.contentReset.x||(i("onOverflowXNone")&&c.callbacks.onOverflowXNone.call(t[0]),s.contentReset.x=1),"_resetY"!==o&&"_resetX"!==o){if(!s.contentReset.y&&t[0].mcs||!s.overflowed[0]||(i("onOverflowY")&&c.callbacks.onOverflowY.call(t[0]),s.contentReset.x=null),!s.contentReset.x&&t[0].mcs||!s.overflowed[1]||(i("onOverflowX")&&c.callbacks.onOverflowX.call(t[0]),s.contentReset.x=null),c.snapAmount){var v=c.snapAmount instanceof Array?"x"===n.dir?c.snapAmount[1]:c.snapAmount[0]:c.snapAmount;o=V(o,v,c.snapOffset)}switch(n.dir){case"x":var x=e("#mCSB_"+s.idx+"_dragger_horizontal"),_="left",w=h[0].offsetLeft,S=[f.width()-h.outerWidth(!1),x.parent().width()-x.width()],b=[o,0===o?0:o/s.scrollRatio.x],y=p[1],B=g[1],T=y>0?y/s.scrollRatio.x:0,k=B>0?B/s.scrollRatio.x:0;break;case"y":var x=e("#mCSB_"+s.idx+"_dragger_vertical"),_="top",w=h[0].offsetTop,S=[f.height()-h.outerHeight(!1),x.parent().height()-x.height()],b=[o,0===o?0:o/s.scrollRatio.y],y=p[0],B=g[0],T=y>0?y/s.scrollRatio.y:0,k=B>0?B/s.scrollRatio.y:0}b[1]<0||0===b[0]&&0===b[1]?b=[0,0]:b[1]>=S[1]?b=[S[0],S[1]]:b[0]=-b[0],t[0].mcs||(l(),i("onInit")&&c.callbacks.onInit.call(t[0])),clearTimeout(h[0].onCompleteTimeout),J(x[0],_,Math.round(b[1]),u[1],n.scrollEasing),!s.tweenRunning&&(0===w&&b[0]>=0||w===S[0]&&b[0]<=S[0])||J(h[0],_,Math.round(b[0]),u[0],n.scrollEasing,n.overwrite,{onStart:function(){n.callbacks&&n.onStart&&!s.tweenRunning&&(i("onScrollStart")&&(l(),c.callbacks.onScrollStart.call(t[0])),s.tweenRunning=!0,C(x),s.cbOffsets=r())},onUpdate:function(){n.callbacks&&n.onUpdate&&i("whileScrolling")&&(l(),c.callbacks.whileScrolling.call(t[0]))},onComplete:function(){if(n.callbacks&&n.onComplete){"yx"===c.axis&&clearTimeout(h[0].onCompleteTimeout);var e=h[0].idleTimer||0;h[0].onCompleteTimeout=setTimeout(function(){i("onScroll")&&(l(),c.callbacks.onScroll.call(t[0])),i("onTotalScroll")&&b[1]>=S[1]-T&&s.cbOffsets[0]&&(l(),c.callbacks.onTotalScroll.call(t[0])),i("onTotalScrollBack")&&b[1]<=k&&s.cbOffsets[1]&&(l(),c.callbacks.onTotalScrollBack.call(t[0])),s.tweenRunning=!1,h[0].idleTimer=0,C(x,"hide")},e)}}})}},J=function(e,t,o,a,n,i,r){function l(){S.stop||(x||m.call(),x=K()-v,s(),x>=S.time&&(S.time=x>S.time?x+f-(x-S.time):x+f-1,S.time0?(S.currVal=u(S.time,_,b,a,n),w[t]=Math.round(S.currVal)+"px"):w[t]=o+"px",p.call()}function c(){f=1e3/60,S.time=x+f,h=window.requestAnimationFrame?window.requestAnimationFrame:function(e){return s(),setTimeout(e,.01)},S.id=h(l)}function d(){null!=S.id&&(window.requestAnimationFrame?window.cancelAnimationFrame(S.id):clearTimeout(S.id),S.id=null)}function u(e,t,o,a,n){switch(n){case"linear":case"mcsLinear":return o*e/a+t;case"mcsLinearOut":return e/=a,e--,o*Math.sqrt(1-e*e)+t;case"easeInOutSmooth":return e/=a/2,1>e?o/2*e*e+t:(e--,-o/2*(e*(e-2)-1)+t);case"easeInOutStrong":return e/=a/2,1>e?o/2*Math.pow(2,10*(e-1))+t:(e--,o/2*(-Math.pow(2,-10*e)+2)+t);case"easeInOut":case"mcsEaseInOut":return e/=a/2,1>e?o/2*e*e*e+t:(e-=2,o/2*(e*e*e+2)+t);case"easeOutSmooth":return e/=a,e--,-o*(e*e*e*e-1)+t;case"easeOutStrong":return o*(-Math.pow(2,-10*e/a)+1)+t;case"easeOut":case"mcsEaseOut":default:var i=(e/=a)*e,r=i*e;return t+o*(.499999999999997*r*i+-2.5*i*i+5.5*r+-6.5*i+4*e)}}e._mTween||(e._mTween={top:{},left:{}});var f,h,r=r||{},m=r.onStart||function(){},p=r.onUpdate||function(){},g=r.onComplete||function(){},v=K(),x=0,_=e.offsetTop,w=e.style,S=e._mTween[t];"left"===t&&(_=e.offsetLeft);var b=o-_;S.stop=0,"none"!==i&&d(),c()},K=function(){return window.performance&&window.performance.now?window.performance.now():window.performance&&window.performance.webkitNow?window.performance.webkitNow():Date.now?Date.now():(new Date).getTime()},Z=function(){var e=this;e._mTween||(e._mTween={top:{},left:{}});for(var t=["top","left"],o=0;o=0&&a[0]+ae(n)[0]=0&&a[1]+ae(n)[1]=0&&r[1]-i[1]*l[1][0]<0&&r[1]+n[1]-i[1]*l[1][1]>=0},mcsOverflow:e.expr[":"].mcsOverflow||function(t){var o=e(t).data(a);if(o)return o.overflowed[0]||o.overflowed[1]}})})})});
/* =========================================================
* bootstrap-datepicker.js
* Repo: https://github.com/uxsolutions/bootstrap-datepicker/
* Demo: https://eternicode.github.io/bootstrap-datepicker/
* Docs: https://bootstrap-datepicker.readthedocs.org/
* =========================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
(function(factory){
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof exports === 'object') {
factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($, undefined){
function UTCDate(){
return new Date(Date.UTC.apply(Date, arguments));
}
function UTCToday(){
var today = new Date();
return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
}
function isUTCEquals(date1, date2) {
return (
date1.getUTCFullYear() === date2.getUTCFullYear() &&
date1.getUTCMonth() === date2.getUTCMonth() &&
date1.getUTCDate() === date2.getUTCDate()
);
}
function alias(method, deprecationMsg){
return function(){
if (deprecationMsg !== undefined) {
$.fn.datepicker.deprecated(deprecationMsg);
}
return this[method].apply(this, arguments);
};
}
function isValidDate(d) {
return d && !isNaN(d.getTime());
}
var DateArray = (function(){
var extras = {
get: function(i){
return this.slice(i)[0];
},
contains: function(d){
// Array.indexOf is not cross-browser;
// $.inArray doesn't work with Dates
var val = d && d.valueOf();
for (var i=0, l=this.length; i < l; i++)
// Use date arithmetic to allow dates with different times to match
if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000*60*60*24)
return i;
return -1;
},
remove: function(i){
this.splice(i,1);
},
replace: function(new_array){
if (!new_array)
return;
if (!$.isArray(new_array))
new_array = [new_array];
this.clear();
this.push.apply(this, new_array);
},
clear: function(){
this.length = 0;
},
copy: function(){
var a = new DateArray();
a.replace(this);
return a;
}
};
return function(){
var a = [];
a.push.apply(a, arguments);
$.extend(a, extras);
return a;
};
})();
// Picker object
var Datepicker = function(element, options){
$.data(element, 'datepicker', this);
this._events = [];
this._secondaryEvents = [];
this._process_options(options);
this.dates = new DateArray();
this.viewDate = this.o.defaultViewDate;
this.focusDate = null;
this.element = $(element);
this.isInput = this.element.is('input');
this.inputField = this.isInput ? this.element : this.element.find('input');
this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .input-group-append, .input-group-prepend, .btn') : false;
if (this.component && this.component.length === 0)
this.component = false;
this.isInline = !this.component && this.element.is('div');
this.picker = $(DPGlobal.template);
// Checking templates and inserting
if (this._check_template(this.o.templates.leftArrow)) {
this.picker.find('.prev').html(this.o.templates.leftArrow);
}
if (this._check_template(this.o.templates.rightArrow)) {
this.picker.find('.next').html(this.o.templates.rightArrow);
}
this._buildEvents();
this._attachEvents();
if (this.isInline){
this.picker.addClass('datepicker-inline').appendTo(this.element);
}
else {
this.picker.addClass('datepicker-dropdown dropdown-menu');
}
if (this.o.rtl){
this.picker.addClass('datepicker-rtl');
}
if (this.o.calendarWeeks) {
this.picker.find('.datepicker-days .datepicker-switch, thead .datepicker-title, tfoot .today, tfoot .clear')
.attr('colspan', function(i, val){
return Number(val) + 1;
});
}
this._process_options({
startDate: this._o.startDate,
endDate: this._o.endDate,
daysOfWeekDisabled: this.o.daysOfWeekDisabled,
daysOfWeekHighlighted: this.o.daysOfWeekHighlighted,
datesDisabled: this.o.datesDisabled
});
this._allow_update = false;
this.setViewMode(this.o.startView);
this._allow_update = true;
this.fillDow();
this.fillMonths();
this.update();
if (this.isInline){
this.show();
}
};
Datepicker.prototype = {
constructor: Datepicker,
_resolveViewName: function(view){
$.each(DPGlobal.viewModes, function(i, viewMode){
if (view === i || $.inArray(view, viewMode.names) !== -1){
view = i;
return false;
}
});
return view;
},
_resolveDaysOfWeek: function(daysOfWeek){
if (!$.isArray(daysOfWeek))
daysOfWeek = daysOfWeek.split(/[,\s]*/);
return $.map(daysOfWeek, Number);
},
_check_template: function(tmp){
try {
// If empty
if (tmp === undefined || tmp === "") {
return false;
}
// If no html, everything ok
if ((tmp.match(/[<>]/g) || []).length <= 0) {
return true;
}
// Checking if html is fine
var jDom = $(tmp);
return jDom.length > 0;
}
catch (ex) {
return false;
}
},
_process_options: function(opts){
// Store raw options for reference
this._o = $.extend({}, this._o, opts);
// Processed options
var o = this.o = $.extend({}, this._o);
// Check if "de-DE" style date is available, if not language should
// fallback to 2 letter code eg "de"
var lang = o.language;
if (!dates[lang]){
lang = lang.split('-')[0];
if (!dates[lang])
lang = defaults.language;
}
o.language = lang;
// Retrieve view index from any aliases
o.startView = this._resolveViewName(o.startView);
o.minViewMode = this._resolveViewName(o.minViewMode);
o.maxViewMode = this._resolveViewName(o.maxViewMode);
// Check view is between min and max
o.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView));
// true, false, or Number > 0
if (o.multidate !== true){
o.multidate = Number(o.multidate) || false;
if (o.multidate !== false)
o.multidate = Math.max(0, o.multidate);
}
o.multidateSeparator = String(o.multidateSeparator);
o.weekStart %= 7;
o.weekEnd = (o.weekStart + 6) % 7;
var format = DPGlobal.parseFormat(o.format);
if (o.startDate !== -Infinity){
if (!!o.startDate){
if (o.startDate instanceof Date)
o.startDate = this._local_to_utc(this._zero_time(o.startDate));
else
o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);
}
else {
o.startDate = -Infinity;
}
}
if (o.endDate !== Infinity){
if (!!o.endDate){
if (o.endDate instanceof Date)
o.endDate = this._local_to_utc(this._zero_time(o.endDate));
else
o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);
}
else {
o.endDate = Infinity;
}
}
o.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled||[]);
o.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted||[]);
o.datesDisabled = o.datesDisabled||[];
if (!$.isArray(o.datesDisabled)) {
o.datesDisabled = o.datesDisabled.split(',');
}
o.datesDisabled = $.map(o.datesDisabled, function(d){
return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);
});
var plc = String(o.orientation).toLowerCase().split(/\s+/g),
_plc = o.orientation.toLowerCase();
plc = $.grep(plc, function(word){
return /^auto|left|right|top|bottom$/.test(word);
});
o.orientation = {x: 'auto', y: 'auto'};
if (!_plc || _plc === 'auto')
; // no action
else if (plc.length === 1){
switch (plc[0]){
case 'top':
case 'bottom':
o.orientation.y = plc[0];
break;
case 'left':
case 'right':
o.orientation.x = plc[0];
break;
}
}
else {
_plc = $.grep(plc, function(word){
return /^left|right$/.test(word);
});
o.orientation.x = _plc[0] || 'auto';
_plc = $.grep(plc, function(word){
return /^top|bottom$/.test(word);
});
o.orientation.y = _plc[0] || 'auto';
}
if (o.defaultViewDate instanceof Date || typeof o.defaultViewDate === 'string') {
o.defaultViewDate = DPGlobal.parseDate(o.defaultViewDate, format, o.language, o.assumeNearbyYear);
} else if (o.defaultViewDate) {
var year = o.defaultViewDate.year || new Date().getFullYear();
var month = o.defaultViewDate.month || 0;
var day = o.defaultViewDate.day || 1;
o.defaultViewDate = UTCDate(year, month, day);
} else {
o.defaultViewDate = UTCToday();
}
},
_applyEvents: function(evs){
for (var i=0, el, ch, ev; i < evs.length; i++){
el = evs[i][0];
if (evs[i].length === 2){
ch = undefined;
ev = evs[i][1];
} else if (evs[i].length === 3){
ch = evs[i][1];
ev = evs[i][2];
}
el.on(ev, ch);
}
},
_unapplyEvents: function(evs){
for (var i=0, el, ev, ch; i < evs.length; i++){
el = evs[i][0];
if (evs[i].length === 2){
ch = undefined;
ev = evs[i][1];
} else if (evs[i].length === 3){
ch = evs[i][1];
ev = evs[i][2];
}
el.off(ev, ch);
}
},
_buildEvents: function(){
var events = {
keyup: $.proxy(function(e){
if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
this.update();
}, this),
keydown: $.proxy(this.keydown, this),
paste: $.proxy(this.paste, this)
};
if (this.o.showOnFocus === true) {
events.focus = $.proxy(this.show, this);
}
if (this.isInput) { // single input
this._events = [
[this.element, events]
];
}
// component: input + button
else if (this.component && this.inputField.length) {
this._events = [
// For components that are not readonly, allow keyboard nav
[this.inputField, events],
[this.component, {
click: $.proxy(this.show, this)
}]
];
}
else {
this._events = [
[this.element, {
click: $.proxy(this.show, this),
keydown: $.proxy(this.keydown, this)
}]
];
}
this._events.push(
// Component: listen for blur on element descendants
[this.element, '*', {
blur: $.proxy(function(e){
this._focused_from = e.target;
}, this)
}],
// Input: listen for blur on element
[this.element, {
blur: $.proxy(function(e){
this._focused_from = e.target;
}, this)
}]
);
if (this.o.immediateUpdates) {
// Trigger input updates immediately on changed year/month
this._events.push([this.element, {
'changeYear changeMonth': $.proxy(function(e){
this.update(e.date);
}, this)
}]);
}
this._secondaryEvents = [
[this.picker, {
click: $.proxy(this.click, this)
}],
[this.picker, '.prev, .next', {
click: $.proxy(this.navArrowsClick, this)
}],
[this.picker, '.day:not(.disabled)', {
click: $.proxy(this.dayCellClick, this)
}],
[$(window), {
resize: $.proxy(this.place, this)
}],
[$(document), {
'mousedown touchstart': $.proxy(function(e){
// Clicked outside the datepicker, hide it
if (!(
this.element.is(e.target) ||
this.element.find(e.target).length ||
this.picker.is(e.target) ||
this.picker.find(e.target).length ||
this.isInline
)){
this.hide();
}
}, this)
}]
];
},
_attachEvents: function(){
this._detachEvents();
this._applyEvents(this._events);
},
_detachEvents: function(){
this._unapplyEvents(this._events);
},
_attachSecondaryEvents: function(){
this._detachSecondaryEvents();
this._applyEvents(this._secondaryEvents);
},
_detachSecondaryEvents: function(){
this._unapplyEvents(this._secondaryEvents);
},
_trigger: function(event, altdate){
var date = altdate || this.dates.get(-1),
local_date = this._utc_to_local(date);
this.element.trigger({
type: event,
date: local_date,
viewMode: this.viewMode,
dates: $.map(this.dates, this._utc_to_local),
format: $.proxy(function(ix, format){
if (arguments.length === 0){
ix = this.dates.length - 1;
format = this.o.format;
} else if (typeof ix === 'string'){
format = ix;
ix = this.dates.length - 1;
}
format = format || this.o.format;
var date = this.dates.get(ix);
return DPGlobal.formatDate(date, format, this.o.language);
}, this)
});
},
show: function(){
if (this.inputField.is(':disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false))
return;
if (!this.isInline)
this.picker.appendTo(this.o.container);
this.place();
this.picker.show();
this._attachSecondaryEvents();
this._trigger('show');
if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
$(this.element).blur();
}
return this;
},
hide: function(){
if (this.isInline || !this.picker.is(':visible'))
return this;
this.focusDate = null;
this.picker.hide().detach();
this._detachSecondaryEvents();
this.setViewMode(this.o.startView);
if (this.o.forceParse && this.inputField.val())
this.setValue();
this._trigger('hide');
return this;
},
destroy: function(){
this.hide();
this._detachEvents();
this._detachSecondaryEvents();
this.picker.remove();
delete this.element.data().datepicker;
if (!this.isInput){
delete this.element.data().date;
}
return this;
},
paste: function(e){
var dateString;
if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types
&& $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) {
dateString = e.originalEvent.clipboardData.getData('text/plain');
} else if (window.clipboardData) {
dateString = window.clipboardData.getData('Text');
} else {
return;
}
this.setDate(dateString);
this.update();
e.preventDefault();
},
_utc_to_local: function(utc){
if (!utc) {
return utc;
}
var local = new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
if (local.getTimezoneOffset() !== utc.getTimezoneOffset()) {
local = new Date(utc.getTime() + (local.getTimezoneOffset() * 60000));
}
return local;
},
_local_to_utc: function(local){
return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
},
_zero_time: function(local){
return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
},
_zero_utc_time: function(utc){
return utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
},
getDates: function(){
return $.map(this.dates, this._utc_to_local);
},
getUTCDates: function(){
return $.map(this.dates, function(d){
return new Date(d);
});
},
getDate: function(){
return this._utc_to_local(this.getUTCDate());
},
getUTCDate: function(){
var selected_date = this.dates.get(-1);
if (selected_date !== undefined) {
return new Date(selected_date);
} else {
return null;
}
},
clearDates: function(){
this.inputField.val('');
this.update();
this._trigger('changeDate');
if (this.o.autoclose) {
this.hide();
}
},
setDates: function(){
var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
this.update.apply(this, args);
this._trigger('changeDate');
this.setValue();
return this;
},
setUTCDates: function(){
var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
this.setDates.apply(this, $.map(args, this._utc_to_local));
return this;
},
setDate: alias('setDates'),
setUTCDate: alias('setUTCDates'),
remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead'),
setValue: function(){
var formatted = this.getFormattedDate();
this.inputField.val(formatted);
return this;
},
getFormattedDate: function(format){
if (format === undefined)
format = this.o.format;
var lang = this.o.language;
return $.map(this.dates, function(d){
return DPGlobal.formatDate(d, format, lang);
}).join(this.o.multidateSeparator);
},
getStartDate: function(){
return this.o.startDate;
},
setStartDate: function(startDate){
this._process_options({startDate: startDate});
this.update();
this.updateNavArrows();
return this;
},
getEndDate: function(){
return this.o.endDate;
},
setEndDate: function(endDate){
this._process_options({endDate: endDate});
this.update();
this.updateNavArrows();
return this;
},
setDaysOfWeekDisabled: function(daysOfWeekDisabled){
this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
this.update();
return this;
},
setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){
this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});
this.update();
return this;
},
setDatesDisabled: function(datesDisabled){
this._process_options({datesDisabled: datesDisabled});
this.update();
return this;
},
place: function(){
if (this.isInline)
return this;
var calendarWidth = this.picker.outerWidth(),
calendarHeight = this.picker.outerHeight(),
visualPadding = 10,
container = $(this.o.container),
windowWidth = container.width(),
scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),
appendOffset = container.offset();
var parentsZindex = [0];
this.element.parents().each(function(){
var itemZIndex = $(this).css('z-index');
if (itemZIndex !== 'auto' && Number(itemZIndex) !== 0) parentsZindex.push(Number(itemZIndex));
});
var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
var offset = this.component ? this.component.parent().offset() : this.element.offset();
var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
var left = offset.left - appendOffset.left;
var top = offset.top - appendOffset.top;
if (this.o.container !== 'body') {
top += scrollTop;
}
this.picker.removeClass(
'datepicker-orient-top datepicker-orient-bottom '+
'datepicker-orient-right datepicker-orient-left'
);
if (this.o.orientation.x !== 'auto'){
this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
if (this.o.orientation.x === 'right')
left -= calendarWidth - width;
}
// auto x orientation is best-placement: if it crosses a window
// edge, fudge it sideways
else {
if (offset.left < 0) {
// component is outside the window on the left side. Move it into visible range
this.picker.addClass('datepicker-orient-left');
left -= offset.left - visualPadding;
} else if (left + calendarWidth > windowWidth) {
// the calendar passes the widow right edge. Align it to component right side
this.picker.addClass('datepicker-orient-right');
left += width - calendarWidth;
} else {
if (this.o.rtl) {
// Default to right
this.picker.addClass('datepicker-orient-right');
} else {
// Default to left
this.picker.addClass('datepicker-orient-left');
}
}
}
// auto y orientation is best-situation: top or bottom, no fudging,
// decision based on which shows more of the calendar
var yorient = this.o.orientation.y,
top_overflow;
if (yorient === 'auto'){
top_overflow = -scrollTop + top - calendarHeight;
yorient = top_overflow < 0 ? 'bottom' : 'top';
}
this.picker.addClass('datepicker-orient-' + yorient);
if (yorient === 'top')
top -= calendarHeight + parseInt(this.picker.css('padding-top'));
else
top += height;
if (this.o.rtl) {
var right = windowWidth - (left + width);
this.picker.css({
top: top,
right: right,
zIndex: zIndex
});
} else {
this.picker.css({
top: top,
left: left,
zIndex: zIndex
});
}
return this;
},
_allow_update: true,
update: function(){
if (!this._allow_update)
return this;
var oldDates = this.dates.copy(),
dates = [],
fromArgs = false;
if (arguments.length){
$.each(arguments, $.proxy(function(i, date){
if (date instanceof Date)
date = this._local_to_utc(date);
dates.push(date);
}, this));
fromArgs = true;
} else {
dates = this.isInput
? this.element.val()
: this.element.data('date') || this.inputField.val();
if (dates && this.o.multidate)
dates = dates.split(this.o.multidateSeparator);
else
dates = [dates];
delete this.element.data().date;
}
dates = $.map(dates, $.proxy(function(date){
return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);
}, this));
dates = $.grep(dates, $.proxy(function(date){
return (
!this.dateWithinRange(date) ||
!date
);
}, this), true);
this.dates.replace(dates);
if (this.o.updateViewDate) {
if (this.dates.length)
this.viewDate = new Date(this.dates.get(-1));
else if (this.viewDate < this.o.startDate)
this.viewDate = new Date(this.o.startDate);
else if (this.viewDate > this.o.endDate)
this.viewDate = new Date(this.o.endDate);
else
this.viewDate = this.o.defaultViewDate;
}
if (fromArgs){
// setting date by clicking
this.setValue();
this.element.change();
}
else if (this.dates.length){
// setting date by typing
if (String(oldDates) !== String(this.dates) && fromArgs) {
this._trigger('changeDate');
this.element.change();
}
}
if (!this.dates.length && oldDates.length) {
this._trigger('clearDate');
this.element.change();
}
this.fill();
return this;
},
fillDow: function(){
if (this.o.showWeekDays) {
var dowCnt = this.o.weekStart,
html = '';
if (this.o.calendarWeeks){
html += ' ';
}
while (dowCnt < this.o.weekStart + 7){
html += ''+dates[this.o.language].daysMin[(dowCnt++)%7]+' ';
}
html += ' ';
this.picker.find('.datepicker-days thead').append(html);
}
},
fillMonths: function(){
var localDate = this._utc_to_local(this.viewDate);
var html = '';
var focused;
for (var i = 0; i < 12; i++){
focused = localDate && localDate.getMonth() === i ? ' focused' : '';
html += '' + dates[this.o.language].monthsShort[i] + ' ';
}
this.picker.find('.datepicker-months td').html(html);
},
setRange: function(range){
if (!range || !range.length)
delete this.range;
else
this.range = $.map(range, function(d){
return d.valueOf();
});
this.fill();
},
getClassNames: function(date){
var cls = [],
year = this.viewDate.getUTCFullYear(),
month = this.viewDate.getUTCMonth(),
today = UTCToday();
if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
cls.push('old');
} else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
cls.push('new');
}
if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
cls.push('focused');
// Compare internal UTC date with UTC today, not local today
if (this.o.todayHighlight && isUTCEquals(date, today)) {
cls.push('today');
}
if (this.dates.contains(date) !== -1)
cls.push('active');
if (!this.dateWithinRange(date)){
cls.push('disabled');
}
if (this.dateIsDisabled(date)){
cls.push('disabled', 'disabled-date');
}
if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){
cls.push('highlighted');
}
if (this.range){
if (date > this.range[0] && date < this.range[this.range.length-1]){
cls.push('range');
}
if ($.inArray(date.valueOf(), this.range) !== -1){
cls.push('selected');
}
if (date.valueOf() === this.range[0]){
cls.push('range-start');
}
if (date.valueOf() === this.range[this.range.length-1]){
cls.push('range-end');
}
}
return cls;
},
_fill_yearsView: function(selector, cssClass, factor, year, startYear, endYear, beforeFn){
var html = '';
var step = factor / 10;
var view = this.picker.find(selector);
var startVal = Math.floor(year / factor) * factor;
var endVal = startVal + step * 9;
var focusedVal = Math.floor(this.viewDate.getFullYear() / step) * step;
var selected = $.map(this.dates, function(d){
return Math.floor(d.getUTCFullYear() / step) * step;
});
var classes, tooltip, before;
for (var currVal = startVal - step; currVal <= endVal + step; currVal += step) {
classes = [cssClass];
tooltip = null;
if (currVal === startVal - step) {
classes.push('old');
} else if (currVal === endVal + step) {
classes.push('new');
}
if ($.inArray(currVal, selected) !== -1) {
classes.push('active');
}
if (currVal < startYear || currVal > endYear) {
classes.push('disabled');
}
if (currVal === focusedVal) {
classes.push('focused');
}
if (beforeFn !== $.noop) {
before = beforeFn(new Date(currVal, 0, 1));
if (before === undefined) {
before = {};
} else if (typeof before === 'boolean') {
before = {enabled: before};
} else if (typeof before === 'string') {
before = {classes: before};
}
if (before.enabled === false) {
classes.push('disabled');
}
if (before.classes) {
classes = classes.concat(before.classes.split(/\s+/));
}
if (before.tooltip) {
tooltip = before.tooltip;
}
}
html += '' + currVal + ' ';
}
view.find('.datepicker-switch').text(startVal + '-' + endVal);
view.find('td').html(html);
},
fill: function(){
var d = new Date(this.viewDate),
year = d.getUTCFullYear(),
month = d.getUTCMonth(),
startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
todaytxt = dates[this.o.language].today || dates['en'].today || '',
cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
todayDate = UTCToday(),
titleBtnVisible = (this.o.todayBtn === true || this.o.todayBtn === 'linked') && todayDate >= this.o.startDate && todayDate <= this.o.endDate && !this.weekOfDateIsDisabled(todayDate),
tooltip,
before;
if (isNaN(year) || isNaN(month))
return;
this.picker.find('.datepicker-days .datepicker-switch')
.text(DPGlobal.formatDate(d, titleFormat, this.o.language));
this.picker.find('tfoot .today')
.text(todaytxt)
.css('display', titleBtnVisible ? 'table-cell' : 'none');
this.picker.find('tfoot .clear')
.text(cleartxt)
.css('display', this.o.clearBtn === true ? 'table-cell' : 'none');
this.picker.find('thead .datepicker-title')
.text(this.o.title)
.css('display', typeof this.o.title === 'string' && this.o.title !== '' ? 'table-cell' : 'none');
this.updateNavArrows();
this.fillMonths();
var prevMonth = UTCDate(year, month, 0),
day = prevMonth.getUTCDate();
prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
var nextMonth = new Date(prevMonth);
if (prevMonth.getUTCFullYear() < 100){
nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
}
nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
nextMonth = nextMonth.valueOf();
var html = [];
var weekDay, clsName;
while (prevMonth.valueOf() < nextMonth){
weekDay = prevMonth.getUTCDay();
if (weekDay === this.o.weekStart){
html.push('');
if (this.o.calendarWeeks){
// ISO 8601: First week contains first thursday.
// ISO also states week starts on Monday, but we can be more abstract here.
var
// Start of current week: based on weekstart/current date
ws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5),
// Thursday of this week
th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
// First Thursday of year, year from thursday
yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
// Calendar week: ms between thursdays, div ms per day, div 7 days
calWeek = (th - yth) / 864e5 / 7 + 1;
html.push(''+ calWeek +' ');
}
}
clsName = this.getClassNames(prevMonth);
clsName.push('day');
var content = prevMonth.getUTCDate();
if (this.o.beforeShowDay !== $.noop){
before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
if (before === undefined)
before = {};
else if (typeof before === 'boolean')
before = {enabled: before};
else if (typeof before === 'string')
before = {classes: before};
if (before.enabled === false)
clsName.push('disabled');
if (before.classes)
clsName = clsName.concat(before.classes.split(/\s+/));
if (before.tooltip)
tooltip = before.tooltip;
if (before.content)
content = before.content;
}
//Check if uniqueSort exists (supported by jquery >=1.12 and >=2.2)
//Fallback to unique function for older jquery versions
if ($.isFunction($.uniqueSort)) {
clsName = $.uniqueSort(clsName);
} else {
clsName = $.unique(clsName);
}
html.push('' + content + ' ');
tooltip = null;
if (weekDay === this.o.weekEnd){
html.push(' ');
}
prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
}
this.picker.find('.datepicker-days tbody').html(html.join(''));
var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';
var months = this.picker.find('.datepicker-months')
.find('.datepicker-switch')
.text(this.o.maxViewMode < 2 ? monthsTitle : year)
.end()
.find('tbody span').removeClass('active');
$.each(this.dates, function(i, d){
if (d.getUTCFullYear() === year)
months.eq(d.getUTCMonth()).addClass('active');
});
if (year < startYear || year > endYear){
months.addClass('disabled');
}
if (year === startYear){
months.slice(0, startMonth).addClass('disabled');
}
if (year === endYear){
months.slice(endMonth+1).addClass('disabled');
}
if (this.o.beforeShowMonth !== $.noop){
var that = this;
$.each(months, function(i, month){
var moDate = new Date(year, i, 1);
var before = that.o.beforeShowMonth(moDate);
if (before === undefined)
before = {};
else if (typeof before === 'boolean')
before = {enabled: before};
else if (typeof before === 'string')
before = {classes: before};
if (before.enabled === false && !$(month).hasClass('disabled'))
$(month).addClass('disabled');
if (before.classes)
$(month).addClass(before.classes);
if (before.tooltip)
$(month).prop('title', before.tooltip);
});
}
// Generating decade/years picker
this._fill_yearsView(
'.datepicker-years',
'year',
10,
year,
startYear,
endYear,
this.o.beforeShowYear
);
// Generating century/decades picker
this._fill_yearsView(
'.datepicker-decades',
'decade',
100,
year,
startYear,
endYear,
this.o.beforeShowDecade
);
// Generating millennium/centuries picker
this._fill_yearsView(
'.datepicker-centuries',
'century',
1000,
year,
startYear,
endYear,
this.o.beforeShowCentury
);
},
updateNavArrows: function(){
if (!this._allow_update)
return;
var d = new Date(this.viewDate),
year = d.getUTCFullYear(),
month = d.getUTCMonth(),
startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
prevIsDisabled,
nextIsDisabled,
factor = 1;
switch (this.viewMode){
case 4:
factor *= 10;
/* falls through */
case 3:
factor *= 10;
/* falls through */
case 2:
factor *= 10;
/* falls through */
case 1:
prevIsDisabled = Math.floor(year / factor) * factor <= startYear;
nextIsDisabled = Math.floor(year / factor) * factor + factor > endYear;
break;
case 0:
prevIsDisabled = year <= startYear && month <= startMonth;
nextIsDisabled = year >= endYear && month >= endMonth;
break;
}
this.picker.find('.prev').toggleClass('disabled', prevIsDisabled);
this.picker.find('.next').toggleClass('disabled', nextIsDisabled);
},
click: function(e){
e.preventDefault();
e.stopPropagation();
var target, dir, day, year, month;
target = $(e.target);
// Clicked on the switch
if (target.hasClass('datepicker-switch') && this.viewMode !== this.o.maxViewMode){
this.setViewMode(this.viewMode + 1);
}
// Clicked on today button
if (target.hasClass('today') && !target.hasClass('day')){
this.setViewMode(0);
this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');
}
// Clicked on clear button
if (target.hasClass('clear')){
this.clearDates();
}
if (!target.hasClass('disabled')){
// Clicked on a month, year, decade, century
if (target.hasClass('month')
|| target.hasClass('year')
|| target.hasClass('decade')
|| target.hasClass('century')) {
this.viewDate.setUTCDate(1);
day = 1;
if (this.viewMode === 1){
month = target.parent().find('span').index(target);
year = this.viewDate.getUTCFullYear();
this.viewDate.setUTCMonth(month);
} else {
month = 0;
year = Number(target.text());
this.viewDate.setUTCFullYear(year);
}
this._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate);
if (this.viewMode === this.o.minViewMode){
this._setDate(UTCDate(year, month, day));
} else {
this.setViewMode(this.viewMode - 1);
this.fill();
}
}
}
if (this.picker.is(':visible') && this._focused_from){
this._focused_from.focus();
}
delete this._focused_from;
},
dayCellClick: function(e){
var $target = $(e.currentTarget);
var timestamp = $target.data('date');
var date = new Date(timestamp);
if (this.o.updateViewDate) {
if (date.getUTCFullYear() !== this.viewDate.getUTCFullYear()) {
this._trigger('changeYear', this.viewDate);
}
if (date.getUTCMonth() !== this.viewDate.getUTCMonth()) {
this._trigger('changeMonth', this.viewDate);
}
}
this._setDate(date);
},
// Clicked on prev or next
navArrowsClick: function(e){
var $target = $(e.currentTarget);
var dir = $target.hasClass('prev') ? -1 : 1;
if (this.viewMode !== 0){
dir *= DPGlobal.viewModes[this.viewMode].navStep * 12;
}
this.viewDate = this.moveMonth(this.viewDate, dir);
this._trigger(DPGlobal.viewModes[this.viewMode].e, this.viewDate);
this.fill();
},
_toggle_multidate: function(date){
var ix = this.dates.contains(date);
if (!date){
this.dates.clear();
}
if (ix !== -1){
if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){
this.dates.remove(ix);
}
} else if (this.o.multidate === false) {
this.dates.clear();
this.dates.push(date);
}
else {
this.dates.push(date);
}
if (typeof this.o.multidate === 'number')
while (this.dates.length > this.o.multidate)
this.dates.remove(0);
},
_setDate: function(date, which){
if (!which || which === 'date')
this._toggle_multidate(date && new Date(date));
if ((!which && this.o.updateViewDate) || which === 'view')
this.viewDate = date && new Date(date);
this.fill();
this.setValue();
if (!which || which !== 'view') {
this._trigger('changeDate');
}
this.inputField.trigger('change');
if (this.o.autoclose && (!which || which === 'date')){
this.hide();
}
},
moveDay: function(date, dir){
var newDate = new Date(date);
newDate.setUTCDate(date.getUTCDate() + dir);
return newDate;
},
moveWeek: function(date, dir){
return this.moveDay(date, dir * 7);
},
moveMonth: function(date, dir){
if (!isValidDate(date))
return this.o.defaultViewDate;
if (!dir)
return date;
var new_date = new Date(date.valueOf()),
day = new_date.getUTCDate(),
month = new_date.getUTCMonth(),
mag = Math.abs(dir),
new_month, test;
dir = dir > 0 ? 1 : -1;
if (mag === 1){
test = dir === -1
// If going back one month, make sure month is not current month
// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
? function(){
return new_date.getUTCMonth() === month;
}
// If going forward one month, make sure month is as expected
// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
: function(){
return new_date.getUTCMonth() !== new_month;
};
new_month = month + dir;
new_date.setUTCMonth(new_month);
// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
new_month = (new_month + 12) % 12;
}
else {
// For magnitudes >1, move one month at a time...
for (var i=0; i < mag; i++)
// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
new_date = this.moveMonth(new_date, dir);
// ...then reset the day, keeping it in the new month
new_month = new_date.getUTCMonth();
new_date.setUTCDate(day);
test = function(){
return new_month !== new_date.getUTCMonth();
};
}
// Common date-resetting loop -- if date is beyond end of month, make it
// end of month
while (test()){
new_date.setUTCDate(--day);
new_date.setUTCMonth(new_month);
}
return new_date;
},
moveYear: function(date, dir){
return this.moveMonth(date, dir*12);
},
moveAvailableDate: function(date, dir, fn){
do {
date = this[fn](date, dir);
if (!this.dateWithinRange(date))
return false;
fn = 'moveDay';
}
while (this.dateIsDisabled(date));
return date;
},
weekOfDateIsDisabled: function(date){
return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1;
},
dateIsDisabled: function(date){
return (
this.weekOfDateIsDisabled(date) ||
$.grep(this.o.datesDisabled, function(d){
return isUTCEquals(date, d);
}).length > 0
);
},
dateWithinRange: function(date){
return date >= this.o.startDate && date <= this.o.endDate;
},
keydown: function(e){
if (!this.picker.is(':visible')){
if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker
this.show();
e.stopPropagation();
}
return;
}
var dateChanged = false,
dir, newViewDate,
focusDate = this.focusDate || this.viewDate;
switch (e.keyCode){
case 27: // escape
if (this.focusDate){
this.focusDate = null;
this.viewDate = this.dates.get(-1) || this.viewDate;
this.fill();
}
else
this.hide();
e.preventDefault();
e.stopPropagation();
break;
case 37: // left
case 38: // up
case 39: // right
case 40: // down
if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7)
break;
dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1;
if (this.viewMode === 0) {
if (e.ctrlKey){
newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
if (newViewDate)
this._trigger('changeYear', this.viewDate);
} else if (e.shiftKey){
newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
if (newViewDate)
this._trigger('changeMonth', this.viewDate);
} else if (e.keyCode === 37 || e.keyCode === 39){
newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay');
} else if (!this.weekOfDateIsDisabled(focusDate)){
newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek');
}
} else if (this.viewMode === 1) {
if (e.keyCode === 38 || e.keyCode === 40) {
dir = dir * 4;
}
newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
} else if (this.viewMode === 2) {
if (e.keyCode === 38 || e.keyCode === 40) {
dir = dir * 4;
}
newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
}
if (newViewDate){
this.focusDate = this.viewDate = newViewDate;
this.setValue();
this.fill();
e.preventDefault();
}
break;
case 13: // enter
if (!this.o.forceParse)
break;
focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
if (this.o.keyboardNavigation) {
this._toggle_multidate(focusDate);
dateChanged = true;
}
this.focusDate = null;
this.viewDate = this.dates.get(-1) || this.viewDate;
this.setValue();
this.fill();
if (this.picker.is(':visible')){
e.preventDefault();
e.stopPropagation();
if (this.o.autoclose)
this.hide();
}
break;
case 9: // tab
this.focusDate = null;
this.viewDate = this.dates.get(-1) || this.viewDate;
this.fill();
this.hide();
break;
}
if (dateChanged){
if (this.dates.length)
this._trigger('changeDate');
else
this._trigger('clearDate');
this.inputField.trigger('change');
}
},
setViewMode: function(viewMode){
this.viewMode = viewMode;
this.picker
.children('div')
.hide()
.filter('.datepicker-' + DPGlobal.viewModes[this.viewMode].clsName)
.show();
this.updateNavArrows();
this._trigger('changeViewMode', new Date(this.viewDate));
}
};
var DateRangePicker = function(element, options){
$.data(element, 'datepicker', this);
this.element = $(element);
this.inputs = $.map(options.inputs, function(i){
return i.jquery ? i[0] : i;
});
delete options.inputs;
this.keepEmptyValues = options.keepEmptyValues;
delete options.keepEmptyValues;
datepickerPlugin.call($(this.inputs), options)
.on('changeDate', $.proxy(this.dateUpdated, this));
this.pickers = $.map(this.inputs, function(i){
return $.data(i, 'datepicker');
});
this.updateDates();
};
DateRangePicker.prototype = {
updateDates: function(){
this.dates = $.map(this.pickers, function(i){
return i.getUTCDate();
});
this.updateRanges();
},
updateRanges: function(){
var range = $.map(this.dates, function(d){
return d.valueOf();
});
$.each(this.pickers, function(i, p){
p.setRange(range);
});
},
clearDates: function(){
$.each(this.pickers, function(i, p){
p.clearDates();
});
},
dateUpdated: function(e){
// `this.updating` is a workaround for preventing infinite recursion
// between `changeDate` triggering and `setUTCDate` calling. Until
// there is a better mechanism.
if (this.updating)
return;
this.updating = true;
var dp = $.data(e.target, 'datepicker');
if (dp === undefined) {
return;
}
var new_date = dp.getUTCDate(),
keep_empty_values = this.keepEmptyValues,
i = $.inArray(e.target, this.inputs),
j = i - 1,
k = i + 1,
l = this.inputs.length;
if (i === -1)
return;
$.each(this.pickers, function(i, p){
if (!p.getUTCDate() && (p === dp || !keep_empty_values))
p.setUTCDate(new_date);
});
if (new_date < this.dates[j]){
// Date being moved earlier/left
while (j >= 0 && new_date < this.dates[j]){
this.pickers[j--].setUTCDate(new_date);
}
} else if (new_date > this.dates[k]){
// Date being moved later/right
while (k < l && new_date > this.dates[k]){
this.pickers[k++].setUTCDate(new_date);
}
}
this.updateDates();
delete this.updating;
},
destroy: function(){
$.map(this.pickers, function(p){ p.destroy(); });
$(this.inputs).off('changeDate', this.dateUpdated);
delete this.element.data().datepicker;
},
remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead')
};
function opts_from_el(el, prefix){
// Derive options from element data-attrs
var data = $(el).data(),
out = {}, inkey,
replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
prefix = new RegExp('^' + prefix.toLowerCase());
function re_lower(_,a){
return a.toLowerCase();
}
for (var key in data)
if (prefix.test(key)){
inkey = key.replace(replace, re_lower);
out[inkey] = data[key];
}
return out;
}
function opts_from_locale(lang){
// Derive options from locale plugins
var out = {};
// Check if "de-DE" style date is available, if not language should
// fallback to 2 letter code eg "de"
if (!dates[lang]){
lang = lang.split('-')[0];
if (!dates[lang])
return;
}
var d = dates[lang];
$.each(locale_opts, function(i,k){
if (k in d)
out[k] = d[k];
});
return out;
}
var old = $.fn.datepicker;
var datepickerPlugin = function(option){
var args = Array.apply(null, arguments);
args.shift();
var internal_return;
this.each(function(){
var $this = $(this),
data = $this.data('datepicker'),
options = typeof option === 'object' && option;
if (!data){
var elopts = opts_from_el(this, 'date'),
// Preliminary otions
xopts = $.extend({}, defaults, elopts, options),
locopts = opts_from_locale(xopts.language),
// Options priority: js args, data-attrs, locales, defaults
opts = $.extend({}, defaults, locopts, elopts, options);
if ($this.hasClass('input-daterange') || opts.inputs){
$.extend(opts, {
inputs: opts.inputs || $this.find('input').toArray()
});
data = new DateRangePicker(this, opts);
}
else {
data = new Datepicker(this, opts);
}
$this.data('datepicker', data);
}
if (typeof option === 'string' && typeof data[option] === 'function'){
internal_return = data[option].apply(data, args);
}
});
if (
internal_return === undefined ||
internal_return instanceof Datepicker ||
internal_return instanceof DateRangePicker
)
return this;
if (this.length > 1)
throw new Error('Using only allowed for the collection of a single element (' + option + ' function)');
else
return internal_return;
};
$.fn.datepicker = datepickerPlugin;
var defaults = $.fn.datepicker.defaults = {
assumeNearbyYear: false,
autoclose: false,
beforeShowDay: $.noop,
beforeShowMonth: $.noop,
beforeShowYear: $.noop,
beforeShowDecade: $.noop,
beforeShowCentury: $.noop,
calendarWeeks: false,
clearBtn: false,
toggleActive: false,
daysOfWeekDisabled: [],
daysOfWeekHighlighted: [],
datesDisabled: [],
endDate: Infinity,
forceParse: true,
format: 'mm/dd/yyyy',
keepEmptyValues: false,
keyboardNavigation: true,
language: 'en',
minViewMode: 0,
maxViewMode: 4,
multidate: false,
multidateSeparator: ',',
orientation: "auto",
rtl: false,
startDate: -Infinity,
startView: 0,
todayBtn: false,
todayHighlight: false,
updateViewDate: true,
weekStart: 0,
disableTouchKeyboard: false,
enableOnReadonly: true,
showOnFocus: true,
zIndexOffset: 10,
container: 'body',
immediateUpdates: false,
title: '',
templates: {
leftArrow: '«',
rightArrow: '»'
},
showWeekDays: true
};
var locale_opts = $.fn.datepicker.locale_opts = [
'format',
'rtl',
'weekStart'
];
$.fn.datepicker.Constructor = Datepicker;
var dates = $.fn.datepicker.dates = {
en: {
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
today: "Today",
clear: "Clear",
titleFormat: "MM yyyy"
}
};
var DPGlobal = {
viewModes: [
{
names: ['days', 'month'],
clsName: 'days',
e: 'changeMonth'
},
{
names: ['months', 'year'],
clsName: 'months',
e: 'changeYear',
navStep: 1
},
{
names: ['years', 'decade'],
clsName: 'years',
e: 'changeDecade',
navStep: 10
},
{
names: ['decades', 'century'],
clsName: 'decades',
e: 'changeCentury',
navStep: 100
},
{
names: ['centuries', 'millennium'],
clsName: 'centuries',
e: 'changeMillennium',
navStep: 1000
}
],
validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
nonpunctuation: /[^ -\/:-@\u5e74\u6708\u65e5\[-`{-~\t\n\r]+/g,
parseFormat: function(format){
if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')
return format;
// IE treats \0 as a string end in inputs (truncating the value),
// so it's a bad format delimiter, anyway
var separators = format.replace(this.validParts, '\0').split('\0'),
parts = format.match(this.validParts);
if (!separators || !separators.length || !parts || parts.length === 0){
throw new Error("Invalid date format.");
}
return {separators: separators, parts: parts};
},
parseDate: function(date, format, language, assumeNearby){
if (!date)
return undefined;
if (date instanceof Date)
return date;
if (typeof format === 'string')
format = DPGlobal.parseFormat(format);
if (format.toValue)
return format.toValue(date, format, language);
var fn_map = {
d: 'moveDay',
m: 'moveMonth',
w: 'moveWeek',
y: 'moveYear'
},
dateAliases = {
yesterday: '-1d',
today: '+0d',
tomorrow: '+1d'
},
parts, part, dir, i, fn;
if (date in dateAliases){
date = dateAliases[date];
}
if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/i.test(date)){
parts = date.match(/([\-+]\d+)([dmwy])/gi);
date = new Date();
for (i=0; i < parts.length; i++){
part = parts[i].match(/([\-+]\d+)([dmwy])/i);
dir = Number(part[1]);
fn = fn_map[part[2].toLowerCase()];
date = Datepicker.prototype[fn](date, dir);
}
return Datepicker.prototype._zero_utc_time(date);
}
parts = date && date.match(this.nonpunctuation) || [];
function applyNearbyYear(year, threshold){
if (threshold === true)
threshold = 10;
// if year is 2 digits or less, than the user most likely is trying to get a recent century
if (year < 100){
year += 2000;
// if the new year is more than threshold years in advance, use last century
if (year > ((new Date()).getFullYear()+threshold)){
year -= 100;
}
}
return year;
}
var parsed = {},
setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
setters_map = {
yyyy: function(d,v){
return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
},
m: function(d,v){
if (isNaN(d))
return d;
v -= 1;
while (v < 0) v += 12;
v %= 12;
d.setUTCMonth(v);
while (d.getUTCMonth() !== v)
d.setUTCDate(d.getUTCDate()-1);
return d;
},
d: function(d,v){
return d.setUTCDate(v);
}
},
val, filtered;
setters_map['yy'] = setters_map['yyyy'];
setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
setters_map['dd'] = setters_map['d'];
date = UTCToday();
var fparts = format.parts.slice();
// Remove noop parts
if (parts.length !== fparts.length){
fparts = $(fparts).filter(function(i,p){
return $.inArray(p, setters_order) !== -1;
}).toArray();
}
// Process remainder
function match_part(){
var m = this.slice(0, parts[i].length),
p = parts[i].slice(0, m.length);
return m.toLowerCase() === p.toLowerCase();
}
if (parts.length === fparts.length){
var cnt;
for (i=0, cnt = fparts.length; i < cnt; i++){
val = parseInt(parts[i], 10);
part = fparts[i];
if (isNaN(val)){
switch (part){
case 'MM':
filtered = $(dates[language].months).filter(match_part);
val = $.inArray(filtered[0], dates[language].months) + 1;
break;
case 'M':
filtered = $(dates[language].monthsShort).filter(match_part);
val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
break;
}
}
parsed[part] = val;
}
var _date, s;
for (i=0; i < setters_order.length; i++){
s = setters_order[i];
if (s in parsed && !isNaN(parsed[s])){
_date = new Date(date);
setters_map[s](_date, parsed[s]);
if (!isNaN(_date))
date = _date;
}
}
}
return date;
},
formatDate: function(date, format, language){
if (!date)
return '';
if (typeof format === 'string')
format = DPGlobal.parseFormat(format);
if (format.toDisplay)
return format.toDisplay(date, format, language);
var val = {
d: date.getUTCDate(),
D: dates[language].daysShort[date.getUTCDay()],
DD: dates[language].days[date.getUTCDay()],
m: date.getUTCMonth() + 1,
M: dates[language].monthsShort[date.getUTCMonth()],
MM: dates[language].months[date.getUTCMonth()],
yy: date.getUTCFullYear().toString().substring(2),
yyyy: date.getUTCFullYear()
};
val.dd = (val.d < 10 ? '0' : '') + val.d;
val.mm = (val.m < 10 ? '0' : '') + val.m;
date = [];
var seps = $.extend([], format.separators);
for (var i=0, cnt = format.parts.length; i <= cnt; i++){
if (seps.length)
date.push(seps.shift());
date.push(val[format.parts[i]]);
}
return date.join('');
},
headTemplate: ''+
''+
' '+
' '+
''+
''+defaults.templates.leftArrow+' '+
' '+
''+defaults.templates.rightArrow+' '+
' '+
' ',
contTemplate: ' ',
footTemplate: ''+
''+
' '+
' '+
''+
' '+
' '+
' '
};
DPGlobal.template = ''+
'
'+
'
'+
DPGlobal.headTemplate+
' '+
DPGlobal.footTemplate+
'
'+
'
'+
'
'+
'
'+
DPGlobal.headTemplate+
DPGlobal.contTemplate+
DPGlobal.footTemplate+
'
'+
'
'+
'
'+
'
'+
DPGlobal.headTemplate+
DPGlobal.contTemplate+
DPGlobal.footTemplate+
'
'+
'
'+
'
'+
'
'+
DPGlobal.headTemplate+
DPGlobal.contTemplate+
DPGlobal.footTemplate+
'
'+
'
'+
'
'+
'
'+
DPGlobal.headTemplate+
DPGlobal.contTemplate+
DPGlobal.footTemplate+
'
'+
'
'+
'
';
$.fn.datepicker.DPGlobal = DPGlobal;
/* DATEPICKER NO CONFLICT
* =================== */
$.fn.datepicker.noConflict = function(){
$.fn.datepicker = old;
return this;
};
/* DATEPICKER VERSION
* =================== */
$.fn.datepicker.version = '1.9.0';
$.fn.datepicker.deprecated = function(msg){
var console = window.console;
if (console && console.warn) {
console.warn('DEPRECATED: ' + msg);
}
};
/* DATEPICKER DATA-API
* ================== */
$(document).on(
'focus.datepicker.data-api click.datepicker.data-api',
'[data-provide="datepicker"]',
function(e){
var $this = $(this);
if ($this.data('datepicker'))
return;
e.preventDefault();
// component click requires us to explicitly show it
datepickerPlugin.call($this, 'show');
}
);
$(function(){
datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
});
}));
/**
* Italian translation for bootstrap-datepicker
* Enrico Rubboli
*/
;(function($){
$.fn.datepicker.dates['it'] = {
days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"],
daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"],
daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa"],
months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"],
monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"],
today: "Oggi",
monthsTitle: "Mesi",
clear: "Cancella",
weekStart: 1,
format: "dd/mm/yyyy"
};
}(jQuery));
/**
* Turkish translation for bootstrap-datepicker
* Serkan Algur
*/
;(function($){
$.fn.datepicker.dates['tr'] = {
days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"],
daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts"],
daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct"],
months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"],
monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"],
today: "Bugün",
clear: "Temizle",
weekStart: 1,
format: "dd.mm.yyyy"
};
}(jQuery));
/*!
* Salvattore 1.0.9 by @rnmp and @ppold
* https://github.com/rnmp/salvattore
*/
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.salvattore = factory();
}
}(this, function() {
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
if (!window.matchMedia) {
window.matchMedia = function() {
"use strict";
// For browsers that support matchMedium api such as IE 9 and webkit
var styleMedia = (window.styleMedia || window.media);
// For those that don't support matchMedium
if (!styleMedia) {
var style = document.createElement('style'),
script = document.getElementsByTagName('script')[0],
info = null;
style.type = 'text/css';
style.id = 'matchmediajs-test';
script.parentNode.insertBefore(style, script);
// 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;
styleMedia = {
matchMedium: function(media) {
var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }';
// 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
if (style.styleSheet) {
style.styleSheet.cssText = text;
} else {
style.textContent = text;
}
// Test if media query is true or false
return info.width === '1px';
}
};
}
return function(media) {
return {
matches: styleMedia.matchMedium(media || 'all'),
media: media || 'all'
};
};
}();
}
/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */
(function(){
"use strict";
// Bail out for browsers that have addListener support
if (window.matchMedia && window.matchMedia('all').addListener) {
return false;
}
var localMatchMedia = window.matchMedia,
hasMediaQueries = localMatchMedia('only all').matches,
isListening = false,
timeoutID = 0, // setTimeout for debouncing 'handleChange'
queries = [], // Contains each 'mql' and associated 'listeners' if 'addListener' is used
handleChange = function(evt) {
// Debounce
clearTimeout(timeoutID);
timeoutID = setTimeout(function() {
for (var i = 0, il = queries.length; i < il; i++) {
var mql = queries[i].mql,
listeners = queries[i].listeners || [],
matches = localMatchMedia(mql.media).matches;
// Update mql.matches value and call listeners
// Fire listeners only if transitioning to or from matched state
if (matches !== mql.matches) {
mql.matches = matches;
for (var j = 0, jl = listeners.length; j < jl; j++) {
listeners[j].call(window, mql);
}
}
}
}, 30);
};
window.matchMedia = function(media) {
var mql = localMatchMedia(media),
listeners = [],
index = 0;
mql.addListener = function(listener) {
// Changes would not occur to css media type so return now (Affects IE <= 8)
if (!hasMediaQueries) {
return;
}
// Set up 'resize' listener for browsers that support CSS3 media queries (Not for IE <= 8)
// There should only ever be 1 resize listener running for performance
if (!isListening) {
isListening = true;
window.addEventListener('resize', handleChange, true);
}
// Push object only if it has not been pushed already
if (index === 0) {
index = queries.push({
mql : mql,
listeners : listeners
});
}
listeners.push(listener);
};
mql.removeListener = function(listener) {
for (var i = 0, il = listeners.length; i < il; i++){
if (listeners[i] === listener){
listeners.splice(i, 1);
}
}
};
return mql;
};
}());
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
"use strict";
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] ||
window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
if (typeof window.CustomEvent !== "function") {
(function() {
"use strict";
function CustomEvent(event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
})();
}
/* jshint laxcomma: true */
var salvattore = (function (global, document, undefined) {
"use strict";
var self = {},
grids = [],
mediaRules = [],
mediaQueries = [],
add_to_dataset = function(element, key, value) {
// uses dataset function or a fallback for = 0 && length <= MAX_ARRAY_INDEX;
};
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
// Handles raw objects in addition to array-likes. Treats all
// sparse array-likes as if they were dense.
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
// Return the results of applying the iteratee to each element.
_.map = _.collect = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
results = Array(length);
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
// Create a reducing function iterating left or right.
function createReduce(dir) {
// Optimized iterator function as using arguments.length
// in the main function will deoptimize the, see #1991.
function iterator(obj, iteratee, memo, keys, index, length) {
for (; index >= 0 && index < length; index += dir) {
var currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
}
return function(obj, iteratee, memo, context) {
iteratee = optimizeCb(iteratee, context, 4);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
index = dir > 0 ? 0 : length - 1;
// Determine the initial value if none is provided.
if (arguments.length < 3) {
memo = obj[keys ? keys[index] : index];
index += dir;
}
return iterator(obj, iteratee, memo, keys, index, length);
};
}
// **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`.
_.reduce = _.foldl = _.inject = createReduce(1);
// The right-associative version of reduce, also known as `foldr`.
_.reduceRight = _.foldr = createReduce(-1);
// Return the first value which passes a truth test. Aliased as `detect`.
_.find = _.detect = function(obj, predicate, context) {
var key;
if (isArrayLike(obj)) {
key = _.findIndex(obj, predicate, context);
} else {
key = _.findKey(obj, predicate, context);
}
if (key !== void 0 && key !== -1) return obj[key];
};
// Return all the elements that pass a truth test.
// Aliased as `select`.
_.filter = _.select = function(obj, predicate, context) {
var results = [];
predicate = cb(predicate, context);
_.each(obj, function(value, index, list) {
if (predicate(value, index, list)) results.push(value);
});
return results;
};
// Return all the elements for which a truth test fails.
_.reject = function(obj, predicate, context) {
return _.filter(obj, _.negate(cb(predicate)), context);
};
// Determine whether all of the elements match a truth test.
// Aliased as `all`.
_.every = _.all = function(obj, predicate, context) {
predicate = cb(predicate, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length;
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
if (!predicate(obj[currentKey], currentKey, obj)) return false;
}
return true;
};
// Determine if at least one element in the object matches a truth test.
// Aliased as `any`.
_.some = _.any = function(obj, predicate, context) {
predicate = cb(predicate, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length;
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
if (predicate(obj[currentKey], currentKey, obj)) return true;
}
return false;
};
// Determine if the array or object contains a given item (using `===`).
// Aliased as `includes` and `include`.
_.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
if (!isArrayLike(obj)) obj = _.values(obj);
if (typeof fromIndex != 'number' || guard) fromIndex = 0;
return _.indexOf(obj, item, fromIndex) >= 0;
};
// Invoke a method (with arguments) on every item in a collection.
_.invoke = function(obj, method) {
var args = slice.call(arguments, 2);
var isFunc = _.isFunction(method);
return _.map(obj, function(value) {
var func = isFunc ? method : value[method];
return func == null ? func : func.apply(value, args);
});
};
// Convenience version of a common use case of `map`: fetching a property.
_.pluck = function(obj, key) {
return _.map(obj, _.property(key));
};
// Convenience version of a common use case of `filter`: selecting only objects
// containing specific `key:value` pairs.
_.where = function(obj, attrs) {
return _.filter(obj, _.matcher(attrs));
};
// Convenience version of a common use case of `find`: getting the first object
// containing specific `key:value` pairs.
_.findWhere = function(obj, attrs) {
return _.find(obj, _.matcher(attrs));
};
// Return the maximum element (or element-based computation).
_.max = function(obj, iteratee, context) {
var result = -Infinity, lastComputed = -Infinity,
value, computed;
if (iteratee == null && obj != null) {
obj = isArrayLike(obj) ? obj : _.values(obj);
for (var i = 0, length = obj.length; i < length; i++) {
value = obj[i];
if (value > result) {
result = value;
}
}
} else {
iteratee = cb(iteratee, context);
_.each(obj, function(value, index, list) {
computed = iteratee(value, index, list);
if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
result = value;
lastComputed = computed;
}
});
}
return result;
};
// Return the minimum element (or element-based computation).
_.min = function(obj, iteratee, context) {
var result = Infinity, lastComputed = Infinity,
value, computed;
if (iteratee == null && obj != null) {
obj = isArrayLike(obj) ? obj : _.values(obj);
for (var i = 0, length = obj.length; i < length; i++) {
value = obj[i];
if (value < result) {
result = value;
}
}
} else {
iteratee = cb(iteratee, context);
_.each(obj, function(value, index, list) {
computed = iteratee(value, index, list);
if (computed < lastComputed || computed === Infinity && result === Infinity) {
result = value;
lastComputed = computed;
}
});
}
return result;
};
// Shuffle a collection, using the modern version of the
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
_.shuffle = function(obj) {
var set = isArrayLike(obj) ? obj : _.values(obj);
var length = set.length;
var shuffled = Array(length);
for (var index = 0, rand; index < length; index++) {
rand = _.random(0, index);
if (rand !== index) shuffled[index] = shuffled[rand];
shuffled[rand] = set[index];
}
return shuffled;
};
// Sample **n** random values from a collection.
// If **n** is not specified, returns a single random element.
// The internal `guard` argument allows it to work with `map`.
_.sample = function(obj, n, guard) {
if (n == null || guard) {
if (!isArrayLike(obj)) obj = _.values(obj);
return obj[_.random(obj.length - 1)];
}
return _.shuffle(obj).slice(0, Math.max(0, n));
};
// Sort the object's values by a criterion produced by an iteratee.
_.sortBy = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
return _.pluck(_.map(obj, function(value, index, list) {
return {
value: value,
index: index,
criteria: iteratee(value, index, list)
};
}).sort(function(left, right) {
var a = left.criteria;
var b = right.criteria;
if (a !== b) {
if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1;
}
return left.index - right.index;
}), 'value');
};
// An internal function used for aggregate "group by" operations.
var group = function(behavior) {
return function(obj, iteratee, context) {
var result = {};
iteratee = cb(iteratee, context);
_.each(obj, function(value, index) {
var key = iteratee(value, index, obj);
behavior(result, value, key);
});
return result;
};
};
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
_.groupBy = group(function(result, value, key) {
if (_.has(result, key)) result[key].push(value); else result[key] = [value];
});
// Indexes the object's values by a criterion, similar to `groupBy`, but for
// when you know that your index values will be unique.
_.indexBy = group(function(result, value, key) {
result[key] = value;
});
// Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the
// criterion.
_.countBy = group(function(result, value, key) {
if (_.has(result, key)) result[key]++; else result[key] = 1;
});
// Safely create a real, live array from anything iterable.
_.toArray = function(obj) {
if (!obj) return [];
if (_.isArray(obj)) return slice.call(obj);
if (isArrayLike(obj)) return _.map(obj, _.identity);
return _.values(obj);
};
// Return the number of elements in an object.
_.size = function(obj) {
if (obj == null) return 0;
return isArrayLike(obj) ? obj.length : _.keys(obj).length;
};
// Split a collection into two arrays: one whose elements all satisfy the given
// predicate, and one whose elements all do not satisfy the predicate.
_.partition = function(obj, predicate, context) {
predicate = cb(predicate, context);
var pass = [], fail = [];
_.each(obj, function(value, key, obj) {
(predicate(value, key, obj) ? pass : fail).push(value);
});
return [pass, fail];
};
// Array Functions
// ---------------
// Get the first element of an array. Passing **n** will return the first N
// values in the array. Aliased as `head` and `take`. The **guard** check
// allows it to work with `_.map`.
_.first = _.head = _.take = function(array, n, guard) {
if (array == null) return void 0;
if (n == null || guard) return array[0];
return _.initial(array, array.length - n);
};
// Returns everything but the last entry of the array. Especially useful on
// the arguments object. Passing **n** will return all the values in
// the array, excluding the last N.
_.initial = function(array, n, guard) {
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
};
// Get the last element of an array. Passing **n** will return the last N
// values in the array.
_.last = function(array, n, guard) {
if (array == null) return void 0;
if (n == null || guard) return array[array.length - 1];
return _.rest(array, Math.max(0, array.length - n));
};
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
// Especially useful on the arguments object. Passing an **n** will return
// the rest N values in the array.
_.rest = _.tail = _.drop = function(array, n, guard) {
return slice.call(array, n == null || guard ? 1 : n);
};
// Trim out all falsy values from an array.
_.compact = function(array) {
return _.filter(array, _.identity);
};
// Internal implementation of a recursive `flatten` function.
var flatten = function(input, shallow, strict, startIndex) {
var output = [], idx = 0;
for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
var value = input[i];
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
//flatten current level of array or arguments object
if (!shallow) value = flatten(value, shallow, strict);
var j = 0, len = value.length;
output.length += len;
while (j < len) {
output[idx++] = value[j++];
}
} else if (!strict) {
output[idx++] = value;
}
}
return output;
};
// Flatten out an array, either recursively (by default), or just one level.
_.flatten = function(array, shallow) {
return flatten(array, shallow, false);
};
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
return _.difference(array, slice.call(arguments, 1));
};
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
_.uniq = _.unique = function(array, isSorted, iteratee, context) {
if (!_.isBoolean(isSorted)) {
context = iteratee;
iteratee = isSorted;
isSorted = false;
}
if (iteratee != null) iteratee = cb(iteratee, context);
var result = [];
var seen = [];
for (var i = 0, length = getLength(array); i < length; i++) {
var value = array[i],
computed = iteratee ? iteratee(value, i, array) : value;
if (isSorted) {
if (!i || seen !== computed) result.push(value);
seen = computed;
} else if (iteratee) {
if (!_.contains(seen, computed)) {
seen.push(computed);
result.push(value);
}
} else if (!_.contains(result, value)) {
result.push(value);
}
}
return result;
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
return _.uniq(flatten(arguments, true, true));
};
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
var result = [];
var argsLength = arguments.length;
for (var i = 0, length = getLength(array); i < length; i++) {
var item = array[i];
if (_.contains(result, item)) continue;
for (var j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break;
}
if (j === argsLength) result.push(item);
}
return result;
};
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
var rest = flatten(arguments, true, true, 1);
return _.filter(array, function(value){
return !_.contains(rest, value);
});
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
_.zip = function() {
return _.unzip(arguments);
};
// Complement of _.zip. Unzip accepts an array of arrays and groups
// each array's elements on shared indices
_.unzip = function(array) {
var length = array && _.max(array, getLength).length || 0;
var result = Array(length);
for (var index = 0; index < length; index++) {
result[index] = _.pluck(array, index);
}
return result;
};
// Converts lists into objects. Pass either a single array of `[key, value]`
// pairs, or two parallel arrays of the same length -- one of keys, and one of
// the corresponding values.
_.object = function(list, values) {
var result = {};
for (var i = 0, length = getLength(list); i < length; i++) {
if (values) {
result[list[i]] = values[i];
} else {
result[list[i][0]] = list[i][1];
}
}
return result;
};
// Generator function to create the findIndex and findLastIndex functions
function createPredicateIndexFinder(dir) {
return function(array, predicate, context) {
predicate = cb(predicate, context);
var length = getLength(array);
var index = dir > 0 ? 0 : length - 1;
for (; index >= 0 && index < length; index += dir) {
if (predicate(array[index], index, array)) return index;
}
return -1;
};
}
// Returns the first index on an array-like that passes a predicate test
_.findIndex = createPredicateIndexFinder(1);
_.findLastIndex = createPredicateIndexFinder(-1);
// Use a comparator function to figure out the smallest index at which
// an object should be inserted so as to maintain order. Uses binary search.
_.sortedIndex = function(array, obj, iteratee, context) {
iteratee = cb(iteratee, context, 1);
var value = iteratee(obj);
var low = 0, high = getLength(array);
while (low < high) {
var mid = Math.floor((low + high) / 2);
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
};
// Generator function to create the indexOf and lastIndexOf functions
function createIndexFinder(dir, predicateFind, sortedIndex) {
return function(array, item, idx) {
var i = 0, length = getLength(array);
if (typeof idx == 'number') {
if (dir > 0) {
i = idx >= 0 ? idx : Math.max(idx + length, i);
} else {
length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
}
} else if (sortedIndex && idx && length) {
idx = sortedIndex(array, item);
return array[idx] === item ? idx : -1;
}
if (item !== item) {
idx = predicateFind(slice.call(array, i, length), _.isNaN);
return idx >= 0 ? idx + i : -1;
}
for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
if (array[idx] === item) return idx;
}
return -1;
};
}
// Return the position of the first occurrence of an item in an array,
// or -1 if the item is not included in the array.
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
_.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
// Generate an integer Array containing an arithmetic progression. A port of
// the native Python `range()` function. See
// [the Python documentation](http://docs.python.org/library/functions.html#range).
_.range = function(start, stop, step) {
if (stop == null) {
stop = start || 0;
start = 0;
}
step = step || 1;
var length = Math.max(Math.ceil((stop - start) / step), 0);
var range = Array(length);
for (var idx = 0; idx < length; idx++, start += step) {
range[idx] = start;
}
return range;
};
// Function (ahem) Functions
// ------------------
// Determines whether to execute a function as a constructor
// or a normal function with the provided arguments
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
var self = baseCreate(sourceFunc.prototype);
var result = sourceFunc.apply(self, args);
if (_.isObject(result)) return result;
return self;
};
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
// available.
_.bind = function(func, context) {
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
var args = slice.call(arguments, 2);
var bound = function() {
return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
};
return bound;
};
// Partially apply a function by creating a version that has had some of its
// arguments pre-filled, without changing its dynamic `this` context. _ acts
// as a placeholder, allowing any combination of arguments to be pre-filled.
_.partial = function(func) {
var boundArgs = slice.call(arguments, 1);
var bound = function() {
var position = 0, length = boundArgs.length;
var args = Array(length);
for (var i = 0; i < length; i++) {
args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
}
while (position < arguments.length) args.push(arguments[position++]);
return executeBound(func, bound, this, this, args);
};
return bound;
};
// Bind a number of an object's methods to that object. Remaining arguments
// are the method names to be bound. Useful for ensuring that all callbacks
// defined on an object belong to it.
_.bindAll = function(obj) {
var i, length = arguments.length, key;
if (length <= 1) throw new Error('bindAll must be passed function names');
for (i = 1; i < length; i++) {
key = arguments[i];
obj[key] = _.bind(obj[key], obj);
}
return obj;
};
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
var memoize = function(key) {
var cache = memoize.cache;
var address = '' + (hasher ? hasher.apply(this, arguments) : key);
if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
return cache[address];
};
memoize.cache = {};
return memoize;
};
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){
return func.apply(null, args);
}, wait);
};
// Defers a function, scheduling it to run after the current call stack has
// cleared.
_.defer = _.partial(_.delay, _, 1);
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.
_.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;
var later = function() {
var last = _.now() - timestamp;
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function() {
context = this;
args = arguments;
timestamp = _.now();
var callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
};
// Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
_.wrap = function(func, wrapper) {
return _.partial(wrapper, func);
};
// Returns a negated version of the passed-in predicate.
_.negate = function(predicate) {
return function() {
return !predicate.apply(this, arguments);
};
};
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
_.compose = function() {
var args = arguments;
var start = args.length - 1;
return function() {
var i = start;
var result = args[start].apply(this, arguments);
while (i--) result = args[i].call(this, result);
return result;
};
};
// Returns a function that will only be executed on and after the Nth call.
_.after = function(times, func) {
return function() {
if (--times < 1) {
return func.apply(this, arguments);
}
};
};
// Returns a function that will only be executed up to (but not including) the Nth call.
_.before = function(times, func) {
var memo;
return function() {
if (--times > 0) {
memo = func.apply(this, arguments);
}
if (times <= 1) func = null;
return memo;
};
};
// Returns a function that will be executed at most one time, no matter how
// often you call it. Useful for lazy initialization.
_.once = _.partial(_.before, 2);
// Object Functions
// ----------------
// Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
function collectNonEnumProps(obj, keys) {
var nonEnumIdx = nonEnumerableProps.length;
var constructor = obj.constructor;
var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
// Constructor is a special case.
var prop = 'constructor';
if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
while (nonEnumIdx--) {
prop = nonEnumerableProps[nonEnumIdx];
if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
keys.push(prop);
}
}
}
// Retrieve the names of an object's own properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = function(obj) {
if (!_.isObject(obj)) return [];
if (nativeKeys) return nativeKeys(obj);
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
// Ahem, IE < 9.
if (hasEnumBug) collectNonEnumProps(obj, keys);
return keys;
};
// Retrieve all the property names of an object.
_.allKeys = function(obj) {
if (!_.isObject(obj)) return [];
var keys = [];
for (var key in obj) keys.push(key);
// Ahem, IE < 9.
if (hasEnumBug) collectNonEnumProps(obj, keys);
return keys;
};
// Retrieve the values of an object's properties.
_.values = function(obj) {
var keys = _.keys(obj);
var length = keys.length;
var values = Array(length);
for (var i = 0; i < length; i++) {
values[i] = obj[keys[i]];
}
return values;
};
// Returns the results of applying the iteratee to each element of the object
// In contrast to _.map it returns an object
_.mapObject = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
var keys = _.keys(obj),
length = keys.length,
results = {},
currentKey;
for (var index = 0; index < length; index++) {
currentKey = keys[index];
results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
// Convert an object into a list of `[key, value]` pairs.
_.pairs = function(obj) {
var keys = _.keys(obj);
var length = keys.length;
var pairs = Array(length);
for (var i = 0; i < length; i++) {
pairs[i] = [keys[i], obj[keys[i]]];
}
return pairs;
};
// Invert the keys and values of an object. The values must be serializable.
_.invert = function(obj) {
var result = {};
var keys = _.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
result[obj[keys[i]]] = keys[i];
}
return result;
};
// Return a sorted list of the function names available on the object.
// Aliased as `methods`
_.functions = _.methods = function(obj) {
var names = [];
for (var key in obj) {
if (_.isFunction(obj[key])) names.push(key);
}
return names.sort();
};
// Extend a given object with all the properties in passed-in object(s).
_.extend = createAssigner(_.allKeys);
// Assigns a given object with all the own properties in the passed-in object(s)
// (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
_.extendOwn = _.assign = createAssigner(_.keys);
// Returns the first key on an object that passes a predicate test
_.findKey = function(obj, predicate, context) {
predicate = cb(predicate, context);
var keys = _.keys(obj), key;
for (var i = 0, length = keys.length; i < length; i++) {
key = keys[i];
if (predicate(obj[key], key, obj)) return key;
}
};
// Return a copy of the object only containing the whitelisted properties.
_.pick = function(object, oiteratee, context) {
var result = {}, obj = object, iteratee, keys;
if (obj == null) return result;
if (_.isFunction(oiteratee)) {
keys = _.allKeys(obj);
iteratee = optimizeCb(oiteratee, context);
} else {
keys = flatten(arguments, false, false, 1);
iteratee = function(value, key, obj) { return key in obj; };
obj = Object(obj);
}
for (var i = 0, length = keys.length; i < length; i++) {
var key = keys[i];
var value = obj[key];
if (iteratee(value, key, obj)) result[key] = value;
}
return result;
};
// Return a copy of the object without the blacklisted properties.
_.omit = function(obj, iteratee, context) {
if (_.isFunction(iteratee)) {
iteratee = _.negate(iteratee);
} else {
var keys = _.map(flatten(arguments, false, false, 1), String);
iteratee = function(value, key) {
return !_.contains(keys, key);
};
}
return _.pick(obj, iteratee, context);
};
// Fill in a given object with default properties.
_.defaults = createAssigner(_.allKeys, true);
// Creates an object that inherits from the given prototype object.
// If additional properties are provided then they will be added to the
// created object.
_.create = function(prototype, props) {
var result = baseCreate(prototype);
if (props) _.extendOwn(result, props);
return result;
};
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
// Invokes interceptor with the obj, and then returns obj.
// The primary purpose of this method is to "tap into" a method chain, in
// order to perform operations on intermediate results within the chain.
_.tap = function(obj, interceptor) {
interceptor(obj);
return obj;
};
// Returns whether an object has a given set of `key:value` pairs.
_.isMatch = function(object, attrs) {
var keys = _.keys(attrs), length = keys.length;
if (object == null) return !length;
var obj = Object(object);
for (var i = 0; i < length; i++) {
var key = keys[i];
if (attrs[key] !== obj[key] || !(key in obj)) return false;
}
return true;
};
// Internal recursive comparison function for `isEqual`.
var eq = function(a, b, aStack, bStack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
if (a === b) return a !== 0 || 1 / a === 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
if (a instanceof _) a = a._wrapped;
if (b instanceof _) b = b._wrapped;
// Compare `[[Class]]` names.
var className = toString.call(a);
if (className !== toString.call(b)) return false;
switch (className) {
// Strings, numbers, regular expressions, dates, and booleans are compared by value.
case '[object RegExp]':
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
case '[object String]':
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
return '' + a === '' + b;
case '[object Number]':
// `NaN`s are equivalent, but non-reflexive.
// Object(NaN) is equivalent to NaN
if (+a !== +a) return +b !== +b;
// An `egal` comparison is performed for other numeric values.
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
case '[object Date]':
case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
return +a === +b;
}
var areArrays = className === '[object Array]';
if (!areArrays) {
if (typeof a != 'object' || typeof b != 'object') return false;
// Objects with different constructors are not equivalent, but `Object`s or `Array`s
// from different frames are.
var aCtor = a.constructor, bCtor = b.constructor;
if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
_.isFunction(bCtor) && bCtor instanceof bCtor)
&& ('constructor' in a && 'constructor' in b)) {
return false;
}
}
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
// Initializing stack of traversed objects.
// It's done here since we only need them for objects and arrays comparison.
aStack = aStack || [];
bStack = bStack || [];
var length = aStack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (aStack[length] === a) return bStack[length] === b;
}
// Add the first object to the stack of traversed objects.
aStack.push(a);
bStack.push(b);
// Recursively compare objects and arrays.
if (areArrays) {
// Compare array lengths to determine if a deep comparison is necessary.
length = a.length;
if (length !== b.length) return false;
// Deep compare the contents, ignoring non-numeric properties.
while (length--) {
if (!eq(a[length], b[length], aStack, bStack)) return false;
}
} else {
// Deep compare objects.
var keys = _.keys(a), key;
length = keys.length;
// Ensure that both objects contain the same number of properties before comparing deep equality.
if (_.keys(b).length !== length) return false;
while (length--) {
// Deep compare each member
key = keys[length];
if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
}
}
// Remove the first object from the stack of traversed objects.
aStack.pop();
bStack.pop();
return true;
};
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
return eq(a, b);
};
// Is a given array, string, or object empty?
// An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) {
if (obj == null) return true;
if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
return _.keys(obj).length === 0;
};
// Is a given value a DOM element?
_.isElement = function(obj) {
return !!(obj && obj.nodeType === 1);
};
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
var type = typeof obj;
return type === 'function' || type === 'object' && !!obj;
};
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
_['is' + name] = function(obj) {
return toString.call(obj) === '[object ' + name + ']';
};
});
// Define a fallback version of the method in browsers (ahem, IE < 9), where
// there isn't any inspectable "Arguments" type.
if (!_.isArguments(arguments)) {
_.isArguments = function(obj) {
return _.has(obj, 'callee');
};
}
// Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
// IE 11 (#1621), and in Safari 8 (#1929).
if (typeof /./ != 'function' && typeof Int8Array != 'object') {
_.isFunction = function(obj) {
return typeof obj == 'function' || false;
};
}
// Is a given object a finite number?
_.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
_.isNaN = function(obj) {
return _.isNumber(obj) && obj !== +obj;
};
// Is a given value a boolean?
_.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
};
// Is a given value equal to null?
_.isNull = function(obj) {
return obj === null;
};
// Is a given variable undefined?
_.isUndefined = function(obj) {
return obj === void 0;
};
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
return obj != null && hasOwnProperty.call(obj, key);
};
// Utility Functions
// -----------------
// Run Underscore.js in *noConflict* mode, returning the `_` variable to its
// previous owner. Returns a reference to the Underscore object.
_.noConflict = function() {
root._ = previousUnderscore;
return this;
};
// Keep the identity function around for default iteratees.
_.identity = function(value) {
return value;
};
// Predicate-generating functions. Often useful outside of Underscore.
_.constant = function(value) {
return function() {
return value;
};
};
_.noop = function(){};
_.property = property;
// Generates a function for a given object that returns a given property.
_.propertyOf = function(obj) {
return obj == null ? function(){} : function(key) {
return obj[key];
};
};
// Returns a predicate for checking whether an object has a given set of
// `key:value` pairs.
_.matcher = _.matches = function(attrs) {
attrs = _.extendOwn({}, attrs);
return function(obj) {
return _.isMatch(obj, attrs);
};
};
// Run a function **n** times.
_.times = function(n, iteratee, context) {
var accum = Array(Math.max(0, n));
iteratee = optimizeCb(iteratee, context, 1);
for (var i = 0; i < n; i++) accum[i] = iteratee(i);
return accum;
};
// Return a random integer between min and max (inclusive).
_.random = function(min, max) {
if (max == null) {
max = min;
min = 0;
}
return min + Math.floor(Math.random() * (max - min + 1));
};
// A (possibly faster) way to get the current timestamp as an integer.
_.now = Date.now || function() {
return new Date().getTime();
};
// List of HTML entities for escaping.
var escapeMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'`': '`'
};
var unescapeMap = _.invert(escapeMap);
// Functions for escaping and unescaping strings to/from HTML interpolation.
var createEscaper = function(map) {
var escaper = function(match) {
return map[match];
};
// Regexes for identifying a key that needs to be escaped
var source = '(?:' + _.keys(map).join('|') + ')';
var testRegexp = RegExp(source);
var replaceRegexp = RegExp(source, 'g');
return function(string) {
string = string == null ? '' : '' + string;
return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
};
};
_.escape = createEscaper(escapeMap);
_.unescape = createEscaper(unescapeMap);
// If the value of the named `property` is a function then invoke it with the
// `object` as context; otherwise, return it.
_.result = function(object, property, fallback) {
var value = object == null ? void 0 : object[property];
if (value === void 0) {
value = fallback;
}
return _.isFunction(value) ? value.call(object) : value;
};
// Generate a unique integer id (unique within the entire client session).
// Useful for temporary DOM ids.
var idCounter = 0;
_.uniqueId = function(prefix) {
var id = ++idCounter + '';
return prefix ? prefix + id : id;
};
// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
// When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match.
var noMatch = /(.)^/;
// Certain characters need to be escaped so that they can be put into a
// string literal.
var escapes = {
"'": "'",
'\\': '\\',
'\r': 'r',
'\n': 'n',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
var escapeChar = function(match) {
return '\\' + escapes[match];
};
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
// NB: `oldSettings` only exists for backwards compatibility.
_.template = function(text, settings, oldSettings) {
if (!settings && oldSettings) settings = oldSettings;
settings = _.defaults({}, settings, _.templateSettings);
// Combine delimiters into one regular expression via alternation.
var matcher = RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
// Compile the template source, escaping string literals appropriately.
var index = 0;
var source = "__p+='";
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
source += text.slice(index, offset).replace(escaper, escapeChar);
index = offset + match.length;
if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
} else if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
} else if (evaluate) {
source += "';\n" + evaluate + "\n__p+='";
}
// Adobe VMs need the match returned to produce the correct offest.
return match;
});
source += "';\n";
// If a variable is not specified, place data values in local scope.
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
source + 'return __p;\n';
try {
var render = new Function(settings.variable || 'obj', '_', source);
} catch (e) {
e.source = source;
throw e;
}
var template = function(data) {
return render.call(this, data, _);
};
// Provide the compiled source as a convenience for precompilation.
var argument = settings.variable || 'obj';
template.source = 'function(' + argument + '){\n' + source + '}';
return template;
};
// Add a "chain" function. Start chaining a wrapped Underscore object.
_.chain = function(obj) {
var instance = _(obj);
instance._chain = true;
return instance;
};
// OOP
// ---------------
// If Underscore is called as a function, it returns a wrapped object that
// can be used OO-style. This wrapper holds altered versions of all the
// underscore functions. Wrapped objects may be chained.
// Helper function to continue chaining intermediate results.
var result = function(instance, obj) {
return instance._chain ? _(obj).chain() : obj;
};
// Add your own custom functions to the Underscore object.
_.mixin = function(obj) {
_.each(_.functions(obj), function(name) {
var func = _[name] = obj[name];
_.prototype[name] = function() {
var args = [this._wrapped];
push.apply(args, arguments);
return result(this, func.apply(_, args));
};
});
};
// Add all of the Underscore functions to the wrapper object.
_.mixin(_);
// Add all mutator Array functions to the wrapper.
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
var obj = this._wrapped;
method.apply(obj, arguments);
if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
return result(this, obj);
};
});
// Add all accessor Array functions to the wrapper.
_.each(['concat', 'join', 'slice'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
return result(this, method.apply(this._wrapped, arguments));
};
});
// Extracts the result from a wrapped and chained object.
_.prototype.value = function() {
return this._wrapped;
};
// Provide unwrapping proxy for some methods used in engine operations
// such as arithmetic and JSON stringification.
_.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
_.prototype.toString = function() {
return '' + this._wrapped;
};
// AMD registration happens at the end for compatibility with AMD loaders
// that may not enforce next-turn semantics on modules. Even though general
// practice for AMD registration is to be anonymous, underscore registers
// as a named module because, like jQuery, it is a base library that is
// popular enough to be bundled in a third party lib, but not be part of
// an AMD load request. Those cases could generate an error when an
// anonymous define() is called outside of a loader request.
if (typeof define === 'function' && define.amd) {
define('underscore', [], function() {
return _;
});
}
}.call(this));
/**
* Bootstrap based calendar full view.
*
* https://github.com/Serhioromano/bootstrap-calendar
*
* User: Sergey Romanov
*/
"use strict";
Date.prototype.getWeek = function (iso8601) {
if (iso8601) {
var target = new Date(this.valueOf());
var dayNr = (this.getDay() + 6) % 7;
target.setDate(target.getDate() - dayNr + 3);
var firstThursday = target.valueOf();
target.setMonth(0, 1);
if (target.getDay() != 4) {
target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
}
return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
} else {
var onejan = new Date(this.getFullYear(), 0, 1);
return Math.ceil((((this.getTime() - onejan.getTime()) / 86400000) + onejan.getDay() + 1) / 7);
}
};
Date.prototype.getMonthFormatted = function () {
var month = this.getMonth() + 1;
return month < 10 ? '0' + month : month;
};
Date.prototype.getDateFormatted = function () {
var date = this.getDate();
return date < 10 ? '0' + date : date;
};
if (!String.prototype.format) {
String.prototype.format = function () {
var args = arguments;
return this.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
};
}
if (!String.prototype.formatNum) {
String.prototype.formatNum = function (decimal) {
var r = "" + this;
while (r.length < decimal)
r = "0" + r;
return r;
};
}
(function ($) {
var defaults = {
// Container to append the tooltip
tooltip_container: 'body',
// Width of the calendar
width: '100%',
// Initial view (can be 'month', 'week', 'day')
view: 'month',
// Initial date. No matter month, week or day this will be a starting point. Can be 'now' or a date in format 'yyyy-mm-dd'
day: 'now',
// Day Start time and end time with time intervals. Time split 10, 15 or 30.
time_start: '06:00',
time_end: '22:00',
time_split: '30',
// Source of events data. It can be one of the following:
// - URL to return JSON list of events in special format.
// {success:1, result: [....]} or for error {success:0, error:'Something terrible happened'}
// events: [...] as described in events property description
// The start and end variables will be sent to this url
// - A function that received the start and end date, and that
// returns an array of events (as described in events property description)
// - An array containing the events
events_source: '',
// Static cache of events. If set to true, events will only be loaded once.
// Useful if response is not constrained by date.
events_cache: false,
// Set format12 to true if you want to use 12 Hour format instead of 24 Hour
format12: false,
am_suffix: "AM",
pm_suffix: "PM",
// Path to templates should end with slash /. It can be as relative
// /component/bootstrap-calendar/tmpls/
// or absolute
// http://localhost/component/bootstrap-calendar/tmpls/
tmpl_path: 'tmpls/',
tmpl_cache: true,
tmpl_inline: false,
classes: {
months: {
inmonth: 'cal-day-inmonth',
outmonth: 'cal-day-outmonth',
saturday: 'cal-day-weekend',
sunday: 'cal-day-weekend',
holidays: 'cal-day-holiday',
today: 'cal-day-today'
},
week: {
workday: 'cal-day-workday',
saturday: 'cal-day-weekend',
sunday: 'cal-day-weekend',
holidays: 'cal-day-holiday',
today: 'cal-day-today'
}
},
// ID of the element of modal window. If set, events URLs will be opened in modal windows.
modal: null,
// modal handling setting, one of "iframe", "ajax" or "template"
modal_type: "iframe",
// function to set modal title, will be passed the event as a parameter
modal_title: null,
views: {
year: {
slide_events: 1,
enable: 1
},
month: {
slide_events: 1,
enable: 1
},
week: {
enable: 1
},
day: {
enable: 1
}
},
merge_holidays: false,
display_week_numbers: true,
weekbox: true,
start_from_first: false,
// ------------------------------------------------------------
// CALLBACKS. Events triggered by calendar class. You can use
// those to affect you UI
// ------------------------------------------------------------
onAfterEventsLoad: function (events) {
// Inside this function 'this' is the calendar instance
},
onBeforeEventsLoad: function (next) {
// Inside this function 'this' is the calendar instance
next();
},
onAfterViewLoad: function (view) {
// Inside this function 'this' is the calendar instance
},
onAfterModalShown: function (events) {
// Inside this function 'this' is the calendar instance
},
onAfterModalHidden: function (events) {
// Inside this function 'this' is the calendar instance
},
onAfterSliderOpening: function (events) {
},
// -------------------------------------------------------------
// INTERNAL USE ONLY. DO NOT ASSIGN IT WILL BE OVERRIDDEN ANYWAY
// -------------------------------------------------------------
events: [],
templates: {
year: '',
month: '',
week: '',
day: ''
},
stop_cycling: false
};
var defaults_extended = {
first_day: 2,
week_numbers_iso_8601: false,
holidays: {
// January 1
'01-01': "New Year's Day",
// Third (+3*) Monday (1) in January (01)
'01+3*1': "Birthday of Dr. Martin Luther King, Jr.",
// Third (+3*) Monday (1) in February (02)
'02+3*1': "Washington's Birthday",
// Last (-1*) Monday (1) in May (05)
'05-1*1': "Memorial Day",
// July 4
'04-07': "Independence Day",
// First (+1*) Monday (1) in September (09)
'09+1*1': "Labor Day",
// Second (+2*) Monday (1) in October (10)
'10+2*1': "Columbus Day",
// November 11
'11-11': "Veterans Day",
// Fourth (+4*) Thursday (4) in November (11)
'11+4*4': "Thanksgiving Day",
// December 25
'25-12': "Christmas"
}
};
var strings = {
error_noview: 'Calendar: View {0} not found',
error_dateformat: 'Calendar: Wrong date format {0}. Should be either "now" or "yyyy-mm-dd"',
error_loadurl: 'Calendar: Event URL is not set',
error_where: 'Calendar: Wrong navigation direction {0}. Can be only "next" or "prev" or "today"',
error_timedevide: 'Calendar: Time split parameter should divide 60 without decimals. Something like 10, 15, 30',
no_events_in_day: 'No events in this day.',
title_year: '{0}',
title_month: '{0} {1}',
title_week: 'week {0} of {1}',
title_day: '{0} {1} {2}, {3}',
week: 'Week {0}',
all_day: 'All day',
time: 'Time',
events: 'Events',
before_time: 'Ends before timeline',
after_time: 'Starts after timeline',
m0: 'January',
m1: 'February',
m2: 'March',
m3: 'April',
m4: 'May',
m5: 'June',
m6: 'July',
m7: 'August',
m8: 'September',
m9: 'October',
m10: 'November',
m11: 'December',
ms0: 'Jan',
ms1: 'Feb',
ms2: 'Mar',
ms3: 'Apr',
ms4: 'May',
ms5: 'Jun',
ms6: 'Jul',
ms7: 'Aug',
ms8: 'Sep',
ms9: 'Oct',
ms10: 'Nov',
ms11: 'Dec',
d0: 'Sunday',
d1: 'Monday',
d2: 'Tuesday',
d3: 'Wednesday',
d4: 'Thursday',
d5: 'Friday',
d6: 'Saturday'
};
var browser_timezone = '';
try {
if ($.type(window.jstz) == 'object' && $.type(jstz.determine) == 'function') {
browser_timezone = jstz.determine().name();
if ($.type(browser_timezone) !== 'string') {
browser_timezone = '';
}
}
}
catch (e) {
}
function buildEventsUrl(events_url, data) {
var separator, key, url;
url = events_url;
separator = (events_url.indexOf('?') < 0) ? '?' : '&';
for (key in data) {
url += separator + key + '=' + encodeURIComponent(data[key]);
separator = '&';
}
return url;
}
function getExtentedOption(cal, option_name) {
var fromOptions = (cal.options[option_name] != null) ? cal.options[option_name] : null;
var fromLanguage = (cal.locale[option_name] != null) ? cal.locale[option_name] : null;
if ((option_name == 'holidays') && cal.options.merge_holidays) {
var holidays = {};
$.extend(true, holidays, fromLanguage ? fromLanguage : defaults_extended.holidays);
if (fromOptions) {
$.extend(true, holidays, fromOptions);
}
return holidays;
}
else {
if (fromOptions != null) {
return fromOptions;
}
if (fromLanguage != null) {
return fromLanguage;
}
return defaults_extended[option_name];
}
}
function getHolidays(cal, year) {
var hash = [];
var holidays_def = getExtentedOption(cal, 'holidays');
for (var k in holidays_def) {
hash.push(k + ':' + holidays_def[k]);
}
hash.push(year);
hash = hash.join('|');
if (hash in getHolidays.cache) {
return getHolidays.cache[hash];
}
var holidays = [];
$.each(holidays_def, function (key, name) {
var firstDay = null, lastDay = null, failed = false;
$.each(key.split('>'), function (i, chunk) {
var m, date = null;
if (m = /^(\d\d)-(\d\d)$/.exec(chunk)) {
date = new Date(year, parseInt(m[2], 10) - 1, parseInt(m[1], 10));
}
else if (m = /^(\d\d)-(\d\d)-(\d\d\d\d)$/.exec(chunk)) {
if (parseInt(m[3], 10) == year) {
date = new Date(year, parseInt(m[2], 10) - 1, parseInt(m[1], 10));
}
}
else if (m = /^easter(([+\-])(\d+))?$/.exec(chunk)) {
date = getEasterDate(year, m[1] ? parseInt(m[1], 10) : 0);
}
else if (m = /^(\d\d)([+\-])([1-5])\*([0-6])$/.exec(chunk)) {
var month = parseInt(m[1], 10) - 1;
var direction = m[2];
var offset = parseInt(m[3]);
var weekday = parseInt(m[4]);
switch (direction) {
case '+':
var d = new Date(year, month, 1 - 7);
while (d.getDay() != weekday) {
d = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1);
}
date = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 7 * offset);
break;
case '-':
var d = new Date(year, month + 1, 0 + 7);
while (d.getDay() != weekday) {
d = new Date(d.getFullYear(), d.getMonth(), d.getDate() - 1);
}
date = new Date(d.getFullYear(), d.getMonth(), d.getDate() - 7 * offset);
break;
}
}
if (!date) {
warn('Unknown holiday: ' + key);
failed = true;
return false;
}
switch (i) {
case 0:
firstDay = date;
break;
case 1:
if (date.getTime() <= firstDay.getTime()) {
warn('Unknown holiday: ' + key);
failed = true;
return false;
}
lastDay = date;
break;
default:
warn('Unknown holiday: ' + key);
failed = true;
return false;
}
});
if (!failed) {
var days = [];
if (lastDay) {
for (var date = new Date(firstDay.getTime()); date.getTime() <= lastDay.getTime(); date.setDate(date.getDate() + 1)) {
days.push(new Date(date.getTime()));
}
}
else {
days.push(firstDay);
}
holidays.push({name: name, days: days});
}
});
getHolidays.cache[hash] = holidays;
return getHolidays.cache[hash];
}
getHolidays.cache = {};
function warn(message) {
if ($.type(window.console) == 'object' && $.type(window.console.warn) == 'function') {
window.console.warn('[Bootstrap-Calendar] ' + message);
}
}
function Calendar(params, context) {
this.options = $.extend(true, {position: {start: new Date(), end: new Date()}}, defaults, params);
this.setLanguage(this.options.language);
this.context = context;
context.css('width', this.options.width).addClass('cal-context');
this.view();
return this;
}
Calendar.prototype.setOptions = function (object) {
$.extend(this.options, object);
if ('language' in object) {
this.setLanguage(object.language);
}
if ('modal' in object) {
this._update_modal();
}
}
Calendar.prototype.setLanguage = function (lang) {
if (window.calendar_languages && (lang in window.calendar_languages)) {
this.locale = $.extend(true, {}, strings, calendar_languages[lang]);
this.options.language = lang;
} else {
this.locale = strings;
delete this.options.language;
}
}
Calendar.prototype._getDayNames = function () {
if (getExtentedOption(this, 'first_day') == 1) {
return [this.locale.d1, this.locale.d2, this.locale.d3, this.locale.d4, this.locale.d5, this.locale.d6, this.locale.d0];
} else {
return [this.locale.d0, this.locale.d1, this.locale.d2, this.locale.d3, this.locale.d4, this.locale.d5, this.locale.d6];
}
}
Calendar.prototype._getMonths = function () {
var months = [];
for (var i = 0; i < 12; i++) {
months.push({
"name": this.locale['m' + i],
"number": ("00" + (i + 1)).slice(-2),
});
}
return months;
}
Calendar.prototype._render = function () {
this.context.html('');
this._loadTemplate(this.options.view);
this.stop_cycling = false;
var data = {};
data.cal = this;
data.day = 1;
// Getting list of days in a week in correct order. Works for month and week views
data.days_name = this._getDayNames();
// Get all events between start and end
var start = parseInt(this.options.position.start.getTime());
var end = parseInt(this.options.position.end.getTime());
data.events = this.getEventsBetween(start, end);
data.months = this._getMonths();
data.month = '' + this.options.position.start.getMonthFormatted();
//console.log(data.months, data.month);
switch (this.options.view) {
case 'month':
break;
case 'week':
this._calculate_hour_minutes(data);
break;
case 'day':
this._calculate_hour_minutes(data);
break;
}
data.start = new Date(this.options.position.start.getTime());
data.lang = this.locale;
this.context.append(this.options.templates[this.options.view](data));
this._update();
};
Calendar.prototype._format_hour = function (str_hour) {
var hour_split = str_hour.split(":");
var hour = parseInt(hour_split[0]);
var minutes = parseInt(hour_split[1]);
var suffix = '';
if (this.options.format12) {
if (hour < 12) {
suffix = this.options.am_suffix;
}
else {
suffix = this.options.pm_suffix;
}
hour = hour % 12;
if (hour == 0) {
hour = 12;
}
}
return hour.toString().formatNum(2) + ':' + minutes.toString().formatNum(2) + suffix;
};
Calendar.prototype._format_time = function (datetime) {
return this._format_hour(datetime.getHours() + ':' + datetime.getMinutes());
};
Calendar.prototype._calculate_hour_minutes = function (data) {
var $self = this;
var time_split = parseInt(this.options.time_split);
var time_split_count = 60 / time_split;
var time_split_hour = Math.min(time_split_count, 1);
if (((time_split_count >= 1) && (time_split_count % 1 != 0)) || ((time_split_count < 1) && (1440 / time_split % 1 != 0))) {
$.error(this.locale.error_timedevide);
}
var time_start = this.options.time_start.split(":");
var time_end = this.options.time_end.split(":");
data.hours = (parseInt(time_end[0]) - parseInt(time_start[0])) * time_split_hour;
var lines = data.hours * time_split_count - parseInt(time_start[1]) / time_split;
var ms_per_line = (60000 * time_split);
var start = new Date(this.options.position.start.getTime());
start.setHours(time_start[0]);
start.setMinutes(time_start[1]);
var end = new Date(this.options.position.end.getTime());
end.setHours(time_end[0]);
end.setMinutes(time_end[1]);
data.all_day = [];
data.by_hour = [];
data.after_time = [];
data.before_time = [];
$.each(data.events, function (k, e) {
var s = new Date(parseInt(e.start));
var f = new Date(parseInt(e.end));
e.start_hour = $self._format_time(s);
e.end_hour = $self._format_time(f);
if (e.start < start.getTime()) {
warn(1);
e.start_hour = s.getDate() + ' ' + $self.locale['ms' + s.getMonth()] + ' ' + e.start_hour;
}
if (e.end > end.getTime()) {
warn(1);
e.end_hour = f.getDate() + ' ' + $self.locale['ms' + f.getMonth()] + ' ' + e.end_hour;
}
if (e.start < start.getTime() && e.end > end.getTime()) {
data.all_day.push(e);
return;
}
if (e.end < start.getTime()) {
data.before_time.push(e);
return;
}
if (e.start > end.getTime()) {
data.after_time.push(e);
return;
}
var event_start = start.getTime() - e.start;
if (event_start >= 0) {
e.top = 0;
} else {
e.top = Math.abs(event_start) / ms_per_line;
}
var lines_left = Math.abs(lines - e.top);
var lines_in_event = (e.end - e.start) / ms_per_line;
if (event_start >= 0) {
lines_in_event = (e.end - start.getTime()) / ms_per_line;
}
e.lines = lines_in_event;
if (lines_in_event > lines_left) {
e.lines = lines_left;
}
data.by_hour.push(e);
});
//var d = new Date('2013-03-14 13:20:00');
//warn(d.getTime());
};
Calendar.prototype._hour_min = function (hour) {
var time_start = this.options.time_start.split(":");
var time_split = parseInt(this.options.time_split);
var in_hour = 60 / time_split;
return (hour == 0) ? (in_hour - (parseInt(time_start[1]) / time_split)) : in_hour;
};
Calendar.prototype._hour = function (hour, part) {
var time_start = this.options.time_start.split(":");
var time_split = parseInt(this.options.time_split);
var h = "" + (parseInt(time_start[0]) + hour * Math.max(time_split / 60, 1));
var m = "" + time_split * part;
return this._format_hour(h.formatNum(2) + ":" + m.formatNum(2));
};
Calendar.prototype._week = function (event) {
this._loadTemplate('week-days');
var t = {};
var start = parseInt(this.options.position.start.getTime());
var end = parseInt(this.options.position.end.getTime());
var events = [];
var self = this;
var first_day = getExtentedOption(this, 'first_day');
$.each(this.getEventsBetween(start, end), function (k, event) {
event.start_day = new Date(parseInt(event.start)).getDay();
if (first_day == 1) {
event.start_day = (event.start_day + 6) % 7;
}
if ((event.end - event.start) <= 86400000) {
event.days = 1;
} else {
event.days = ((event.end - event.start) / 86400000);
}
if (event.start < start) {
event.days = event.days - ((start - event.start) / 86400000);
event.start_day = 0;
}
event.days = Math.ceil(event.days);
if (event.start_day + event.days > 7) {
event.days = 7 - (event.start_day);
}
events.push(event);
});
t.events = events;
t.cal = this;
return self.options.templates['week-days'](t);
}
Calendar.prototype._month = function (month) {
this._loadTemplate('year-month');
var t = {cal: this};
var newmonth = month + 1;
t.data_day = this.options.position.start.getFullYear() + '-' + (newmonth < 10 ? '0' + newmonth : newmonth) + '-' + '01';
t.month_name = this.locale['m' + month];
var curdate = new Date(this.options.position.start.getFullYear(), month, 1, 0, 0, 0);
t.start = parseInt(curdate.getTime());
t.end = parseInt(new Date(this.options.position.start.getFullYear(), month + 1, 1, 0, 0, 0).getTime());
t.events = this.getEventsBetween(t.start, t.end);
return this.options.templates['year-month'](t);
}
Calendar.prototype._day = function (week, day) {
this._loadTemplate('month-day');
var t = {tooltip: '', cal: this};
var cls = this.options.classes.months.outmonth;
var firstday = this.options.position.start.getDay();
if (getExtentedOption(this, 'first_day') == 2) {
firstday++;
} else {
firstday = (firstday == 0 ? 7 : firstday);
}
day = this.options.start_from_first ? day : (day - firstday) + 1;
var curdate = new Date(this.options.position.start.getFullYear(), this.options.position.start.getMonth(), day, 0, 0, 0);
t.data_dayname = this._getDayNames()[(firstday + day - 2) % 7];
// if day of the current month
if (day > 0) {
cls = this.options.classes.months.inmonth;
}
// stop cycling table rows;
var daysinmonth = (new Date(this.options.position.end.getTime() - 1)).getDate();
if ((day + 1) > daysinmonth) {
this.stop_cycling = true;
}
// if day of the next month
if (day > daysinmonth) {
day = day - daysinmonth;
cls = this.options.classes.months.outmonth;
}
cls = $.trim(cls + " " + this._getDayClass("months", curdate));
if (day <= 0) {
var daysinprevmonth = (new Date(this.options.position.start.getFullYear(), this.options.position.start.getMonth(), 0)).getDate();
day = daysinprevmonth - Math.abs(day);
cls += ' cal-month-first-row';
}
var holiday = this._getHoliday(curdate);
if (holiday !== false) {
t.tooltip = holiday;
}
t.data_day = curdate.getFullYear() + '-' + curdate.getMonthFormatted() + '-' + (day < 10 ? '0' + day : day);
t.day = day;
t.start = parseInt(curdate.getTime());
t.end = parseInt(t.start + 86400000);
t.events = this.getEventsBetween(t.start, t.end);
if (t.events.length) {
cls += ' cal-day-withevents';
}
t.cls = cls;
return this.options.templates['month-day'](t);
}
Calendar.prototype._getHoliday = function (date) {
var result = false;
$.each(getHolidays(this, date.getFullYear()), function () {
var found = false;
$.each(this.days, function () {
if (this.toDateString() == date.toDateString()) {
found = true;
return false;
}
});
if (found) {
result = this.name;
return false;
}
});
return result;
};
Calendar.prototype._getHolidayName = function (date) {
var holiday = this._getHoliday(date);
return (holiday === false) ? "" : holiday;
};
Calendar.prototype._getDayClass = function (class_group, date) {
var self = this;
var addClass = function (which, to) {
var cls;
cls = (self.options.classes && (class_group in self.options.classes) && (which in self.options.classes[class_group])) ? self.options.classes[class_group][which] : "";
if ((typeof(cls) == "string") && cls.length) {
to.push(cls);
}
};
var classes = [];
if (date.toDateString() == (new Date()).toDateString()) {
addClass("today", classes);
}
var holiday = this._getHoliday(date);
if (holiday !== false) {
addClass("holidays", classes);
}
switch (date.getDay()) {
case 0:
addClass("sunday", classes);
break;
case 6:
addClass("saturday", classes);
break;
}
addClass(date.toDateString(), classes);
return classes.join(" ");
};
Calendar.prototype.view = function (view) {
if (view) {
if (!this.options.views[view].enable) {
return;
}
this.options.view = view;
}
this._init_position();
this._loadEvents();
this._render();
this.options.onAfterViewLoad.call(this, this.options.view);
};
Calendar.prototype.navigate = function (where, next, custom) {
var to = $.extend({}, this.options.position);
if (where == 'next') {
switch (this.options.view) {
case 'year':
to.start.setFullYear(this.options.position.start.getFullYear() + 1);
break;
case 'month':
to.start.setMonth(this.options.position.start.getMonth() + 1);
break;
case 'week':
to.start.setDate(this.options.position.start.getDate() + 7);
break;
case 'day':
to.start.setDate(this.options.position.start.getDate() + 1);
break;
}
} else if (where == 'prev') {
switch (this.options.view) {
case 'year':
to.start.setFullYear(this.options.position.start.getFullYear() - 1);
break;
case 'month':
to.start.setMonth(this.options.position.start.getMonth() - 1);
break;
case 'week':
to.start.setDate(this.options.position.start.getDate() - 7);
break;
case 'day':
to.start.setDate(this.options.position.start.getDate() - 1);
break;
}
} else if (where == 'today') {
to.start.setTime(new Date().getTime());
}
else if (where == 'custom') {
var customDate = new Date(custom);
switch (this.options.view) {
case 'year':
to.start.setFullYear(customDate.getFullYear());
break;
case 'month':
to.start.setMonth(customDate.getMonth());
break;
case 'week':
to.start.setDate(customDate.getDate());
break;
case 'day':
to.start.setDate(customDate.getDate());
break;
}
}
else {
$.error(this.locale.error_where.format(where))
}
this.options.day = to.start.getFullYear() + '-' + to.start.getMonthFormatted() + '-' + to.start.getDateFormatted();
this.view();
if (_.isFunction(next)) {
next();
}
};
Calendar.prototype._init_position = function () {
var year, month, day;
if (this.options.day == 'now') {
var date = new Date();
year = date.getFullYear();
month = date.getMonth();
day = date.getDate();
} else if (this.options.day.match(/^\d{4}-\d{2}-\d{2}$/g)) {
var list = this.options.day.split('-');
year = parseInt(list[0], 10);
month = parseInt(list[1], 10) - 1;
day = parseInt(list[2], 10);
}
else {
$.error(this.locale.error_dateformat.format(this.options.day));
}
switch (this.options.view) {
case 'year':
this.options.position.start.setTime(new Date(year, 0, 1).getTime());
this.options.position.end.setTime(new Date(year + 1, 0, 1).getTime());
break;
case 'month':
this.options.position.start.setTime(new Date(year, month, 1).getTime());
this.options.position.end.setTime(new Date(year, month + 1, 1).getTime());
break;
case 'day':
this.options.position.start.setTime(new Date(year, month, day).getTime());
this.options.position.end.setTime(new Date(year, month, day + 1).getTime());
break;
case 'week':
var curr = new Date(year, month, day);
var first;
if (getExtentedOption(this, 'first_day') == 1) {
first = curr.getDate() - ((curr.getDay() + 6) % 7);
}
else {
first = curr.getDate() - curr.getDay();
}
this.options.position.start.setTime(new Date(year, month, first).getTime());
this.options.position.end.setTime(new Date(year, month, first + 7).getTime());
break;
default:
$.error(this.locale.error_noview.format(this.options.view))
}
return this;
};
Calendar.prototype.getTitle = function () {
var p = this.options.position.start;
switch (this.options.view) {
case 'year':
return this.locale.title_year.format(p.getFullYear());
break;
case 'month':
return this.locale.title_month.format(this.locale['m' + p.getMonth()], p.getFullYear());
break;
case 'week':
return this.locale.title_week.format(p.getWeek(getExtentedOption(this, 'week_numbers_iso_8601')), p.getFullYear());
break;
case 'day':
return this.locale.title_day.format(this.locale['d' + p.getDay()], p.getDate(), this.locale['m' + p.getMonth()], p.getFullYear());
break;
}
return;
};
Calendar.prototype.getYear = function () {
var p = this.options.position.start;
return p.getFullYear();
};
Calendar.prototype.getMonth = function () {
var p = this.options.position.start;
return this.locale['m' + p.getMonth()];
};
Calendar.prototype.getDay = function () {
var p = this.options.position.start;
return this.locale['d' + p.getDay()];
};
Calendar.prototype.isToday = function () {
var now = new Date().getTime();
return ((now > this.options.position.start) && (now < this.options.position.end));
}
Calendar.prototype.getStartDate = function () {
return this.options.position.start;
}
Calendar.prototype.getEndDate = function () {
return this.options.position.end;
}
Calendar.prototype._loadEvents = function () {
var self = this;
var source = null;
if ('events_source' in this.options && this.options.events_source !== '') {
source = this.options.events_source;
}
else if ('events_url' in this.options) {
source = this.options.events_url;
warn('The events_url option is DEPRECATED and it will be REMOVED in near future. Please use events_source instead.');
}
var loader;
switch ($.type(source)) {
case 'function':
loader = function () {
return source(self.options.position.start, self.options.position.end, browser_timezone);
};
break;
case 'array':
loader = function () {
return [].concat(source);
};
break;
case 'string':
if (source.length) {
loader = function () {
var events = [];
var d_from = self.options.position.start;
var d_to = self.options.position.end;
var params = {
from: d_from.getTime(),
to: d_to.getTime(),
utc_offset_from: d_from.getTimezoneOffset(),
utc_offset_to: d_to.getTimezoneOffset()
};
if (browser_timezone.length) {
params.browser_timezone = browser_timezone;
}
$.ajax({
url: buildEventsUrl(source, params),
dataType: 'json',
type: 'GET',
async: false
}).done(function (json) {
if (!json.success) {
$.error(json.error);
}
if (json.result) {
events = json.result;
}
});
return events;
};
}
break;
}
if (!loader) {
$.error(this.locale.error_loadurl);
}
this.options.onBeforeEventsLoad.call(this, function () {
if (!self.options.events.length || !self.options.events_cache) {
self.options.events = loader();
self.options.events.sort(function (a, b) {
var delta;
delta = a.start - b.start;
if (delta == 0) {
delta = a.end - b.end;
}
return delta;
});
}
self.options.onAfterEventsLoad.call(self, self.options.events);
});
};
Calendar.prototype._templatePath = function (name) {
if (typeof this.options.tmpl_path == 'function') {
return this.options.tmpl_path(name)
}
else {
return this.options.tmpl_path + name + '.html';
}
};
Calendar.prototype._loadTemplate = function (name) {
if (this.options.templates[name]) {
return;
}
var self = this;
if (this.options.tmpl_inline) {
var tmpl = $('#bctmpl_' + name);
if (tmpl.length == 0) {
console.log('No ' + name + 'template.');
return;
}
self.options.templates[name] = _.template(tmpl.html());
}
else {
$.ajax({
url: self._templatePath(name),
dataType: 'html',
type: 'GET',
async: false,
cache: this.options.tmpl_cache
}).done(function (html) {
self.options.templates[name] = _.template(html);
});
}
};
Calendar.prototype._update = function () {
var self = this;
/*$('*[data-toggle="tooltip"]').tooltip({container: this.options.tooltip_container});
$('*[data-cal-date]').click(function () {
var view = $(this).data('cal-view');
self.options.day = $(this).data('cal-date');
self.view(view);
});
$('.cal-cell').dblclick(function () {
var view = $('[data-cal-date]', this).data('cal-view');
self.options.day = $('[data-cal-date]', this).data('cal-date');
self.view(view);
});*/
this['_update_' + this.options.view]();
this._update_modal();
};
Calendar.prototype._update_modal = function () {
var self = this;
$('a[data-event-id]', this.context).unbind('click');
if (!self.options.modal) {
return;
}
var modal = $(self.options.modal);
if (!modal.length) {
return;
}
var ifrm = null;
if (self.options.modal_type == "iframe") {
ifrm = $(document.createElement("iframe"))
.attr({
width: "100%",
frameborder: "0"
});
}
$('a[data-event-id]', this.context).on('click', function (event) {
event.preventDefault();
event.stopPropagation();
var url = $(this).attr('href');
var id = $(this).data("event-id");
var event = _.find(self.options.events, function (event) {
return event.id == id
});
if (self.options.modal_type == "iframe") {
ifrm.attr('src', url);
$('.modal-body', modal).html(ifrm);
}
if (!modal.data('handled.bootstrap-calendar') || (modal.data('handled.bootstrap-calendar') && modal.data('handled.event-id') != event.id)) {
modal.off('show.bs.modal')
.off('shown.bs.modal')
.off('hidden.bs.modal')
.on('show.bs.modal', function () {
var modal_body = $(this).find('.modal-body');
switch (self.options.modal_type) {
case "iframe" :
var height = modal_body.height() - parseInt(modal_body.css('padding-top'), 10) - parseInt(modal_body.css('padding-bottom'), 10);
$(this).find('iframe').height(Math.max(height, 50));
break;
case "ajax":
$.ajax({
url: url, dataType: "html", async: false, success: function (data) {
modal_body.html(data);
}
});
break;
case "template":
self._loadTemplate("modal");
// also serve calendar instance to underscore template to be able to access current language strings
modal_body.html(self.options.templates["modal"]({"event": event, "calendar": self}))
break;
}
// set the title of the bootstrap modal
if (_.isFunction(self.options.modal_title)) {
modal.find(".modal-title").html(self.options.modal_title(event));
}
})
.on('shown.bs.modal', function () {
self.options.onAfterModalShown.call(self, self.options.events);
})
.on('hidden.bs.modal', function () {
self.options.onAfterModalHidden.call(self, self.options.events);
})
.data('handled.bootstrap-calendar', true).data('handled.event-id', event.id);
}
modal.modal('show');
});
};
Calendar.prototype._update_day = function () {
$('#cal-day-panel').height($('#cal-day-panel-hour').height());
};
Calendar.prototype._update_week = function () {
};
Calendar.prototype._update_year = function () {
this._update_month_year();
};
Calendar.prototype._update_month = function () {
this._update_month_year();
var self = this;
if (this.options.weekbox == true) {
var week = $(document.createElement('div')).attr('id', 'cal-week-box');
var start = this.options.position.start.getFullYear() + '-' + this.options.position.start.getMonthFormatted() + '-';
self.context.find('.cal-month-box .cal-row-fluid')
.on('mouseenter', function () {
var p = new Date(self.options.position.start);
var child = $('.cal-cell1:first-child .cal-month-day', this);
var day = (child.hasClass('cal-month-first-row') ? 1 : $('[data-cal-date]', child).text());
p.setDate(parseInt(day));
day = (day < 10 ? '0' + day : day);
week.html(self.locale.week.format(self.options.display_week_numbers == true ? p.getWeek(getExtentedOption(self, 'week_numbers_iso_8601')) : ''));
week.attr('data-cal-week', start + day).show().appendTo(child);
})
.on('mouseleave', function () {
week.hide();
});
week.click(function () {
self.options.day = $(this).data('cal-week');
self.view('week');
});
}
self.context.find('a.event').mouseenter(function () {
$('a[data-event-id="' + $(this).data('event-id') + '"]').closest('.cal-cell1').addClass('day-highlight dh-' + $(this).data('event-class'));
});
self.context.find('a.event').mouseleave(function () {
$('div.cal-cell1').removeClass('day-highlight dh-' + $(this).data('event-class'));
});
};
Calendar.prototype._update_month_year = function () {
if (!this.options.views[this.options.view].slide_events) {
return;
}
var self = this;
self.context.find('.cal-month-day, .cal-year-box .span3')
.on('click', function (event) {
if ($('.events-list', this).length == 0) {
return;
}
showEventsList(event, this, slider, self);
})
;
var slider = $(document.createElement('div')).attr('id', 'cal-slide-box');
slider.hide().click(function (event) {
event.stopPropagation();
});
this._loadTemplate('events-list');
};
Calendar.prototype.getEventsBetween = function (start, end) {
var events = [];
$.each(this.options.events, function () {
if (this.start == null) {
return true;
}
var event_end = this.end || this.start;
if ((parseInt(this.start) < end) && (parseInt(event_end) >= start)) {
events.push(this);
}
});
return events;
};
function showEventsList(event, that, slider, self) {
event.stopPropagation();
var that = $(that);
var cell = that.closest('.cal-cell');
var row = cell.closest('.cal-before-eventlist');
var tick_position = cell.data('cal-row');
var baseCls = 'open-on';
var cls = baseCls + tick_position;
cell.toggleClass('open').closest('.cal-month-box').find('.cal-cell').not(cell).removeClass('open');
if (slider.hasClass(cls)) {
slider.slideUp('fast').removeClass(cls);
}
else {
var slideDown = function () {
var event_list = $('.events-list', cell);
slider.html(self.options.templates['events-list']({
cal: self,
events: self.getEventsBetween(parseInt(event_list.data('cal-start')), parseInt(event_list.data('cal-end')))
}));
row.after(slider);
$('#cal-slide-tick').addClass('tick' + tick_position).show();
slider.slideDown('fast', function () {
slider.addClass(cls);
self.options.onAfterSliderOpening.call(self, self.options.events);
});
};
var sliderClasses = slider.attr('class') || '';
if (sliderClasses.indexOf(baseCls) > -1) {
slider.slideUp('fast', slideDown);
slider.attr('class', '');
}
else {
slideDown();
}
}
}
function getEasterDate(year, offsetDays) {
var a = year % 19;
var b = Math.floor(year / 100);
var c = year % 100;
var d = Math.floor(b / 4);
var e = b % 4;
var f = Math.floor((b + 8) / 25);
var g = Math.floor((b - f + 1) / 3);
var h = (19 * a + b - d - g + 15) % 30;
var i = Math.floor(c / 4);
var k = c % 4;
var l = (32 + 2 * e + 2 * i - h - k) % 7;
var m = Math.floor((a + 11 * h + 22 * l) / 451);
var n0 = (h + l + 7 * m + 114)
var n = Math.floor(n0 / 31) - 1;
var p = n0 % 31 + 1;
return new Date(year, n, p + (offsetDays ? offsetDays : 0), 0, 0, 0);
}
$.fn.calendar = function (params) {
return new Calendar(params, this);
}
}(jQuery));
if(!window.calendar_languages) {
window.calendar_languages = {};
}
window.calendar_languages['it-IT'] = {
error_noview: 'Calendario: vista {0} non trovata',
error_dateformat: 'Calendario: formato data {0} non valido. Dovrebbe essere "now" o "yyyy-mm-dd"',
error_loadurl: 'Calendario: URL di caricamento degli eventi non impostato',
error_where: 'Calendario: direzione di spostamento {0} non valida. I valori validi sono "next" o "prev" o "today"',
error_timedevide: 'Calendario: Il divisore del tempo deve poter dividere 60 in un numero intero. Per esempio 10, 15, 30',
no_events_in_day: 'Nessun evento in questo giorno.',
title_year: 'Anno {0}',
title_month: '{0} {1}',
title_week: 'Settimana {0} del {1}',
title_day: '{0} {1} {2} {3}',
week: 'Settimana {0}',
all_day: 'Tutto il giorno',
time: 'Ora',
events: 'Eventi',
before_time: 'Evento antecedente',
after_time: 'Evento che prosegue',
m0: 'Gennaio',
m1: 'Febbraio',
m2: 'Marzo',
m3: 'Aprile',
m4: 'Maggio',
m5: 'Giugno',
m6: 'Luglio',
m7: 'Agosto',
m8: 'Settembre',
m9: 'Ottobre',
m10: 'Novembre',
m11: 'Dicembre',
ms0: 'Gen',
ms1: 'Feb',
ms2: 'Mar',
ms3: 'Apr',
ms4: 'Mag',
ms5: 'Giu',
ms6: 'Lug',
ms7: 'Ago',
ms8: 'Set',
ms9: 'Ott',
ms10: 'Nov',
ms11: 'Dic',
d0: 'Domenica',
d1: 'Lunedì',
d2: 'Martedì',
d3: 'Mercoledì',
d4: 'Giovedì',
d5: 'Venerdì',
d6: 'Sabato',
first_day: 1,
week_numbers_iso_8601: true,
holidays: {
'01-01': 'Capodanno',
'06-01': 'Epifania',
'easter': 'Pasqua',
'easter+1': 'Lunedì dell’Angelo',
'25-04': 'Festa della Liberazione',
'01-05': 'Festa del Lavoro',
'02-06': 'Festa della Repubblica',
'15-08': 'Ferragosto',
'01-11': 'Ognissanti',
'08-12': 'Immacolata Concezione',
'25-12': 'Natale',
'26-12': 'Santo Stefano'
}
};
if(!window.calendar_languages) {
window.calendar_languages = {};
}
window.calendar_languages['de-DE'] = {
error_noview: 'Kalender: Ansicht {0} nicht gefunden',
error_dateformat: 'Kalender: Falsches Datumsformat {0}. Sollte entweder "now" oder "yyyy-mm-dd" sein',
error_loadurl: 'Kalender: Event-URL nicht gesetzt.',
error_where: 'Kalender: Falsche Navigationsrichtung {0}. Nur "next", "prev" oder "today" sind erlaubt',
error_timedevide: 'Kalender: Parameter für die Zeiteinteilung muss ein Teiler von 60 sein. Beispielsweise 10, 15, 30',
no_events_in_day: 'Keine Ereignisse an diesem Tag.',
title_year: '{0}',
title_month: '{0} {1}',
title_week: '{0}. Kalenderwoche {1}',
title_day: '{0}, der {1}. {2} {3}',
week: 'KW {0}',
all_day: 'Ganztägig',
time: 'Zeit',
events: 'Ereignisse',
before_time: 'Endet vor Zeitspanne',
after_time: 'Beginnt nach Zeitspanne',
m0: 'Januar',
m1: 'Februar',
m2: 'März',
m3: 'April',
m4: 'Mai',
m5: 'Juni',
m6: 'Juli',
m7: 'August',
m8: 'September',
m9: 'Oktober',
m10: 'November',
m11: 'Dezember',
ms0: 'Jan',
ms1: 'Feb',
ms2: 'Mär',
ms3: 'Apr',
ms4: 'Mai',
ms5: 'Jun',
ms6: 'Jul',
ms7: 'Aug',
ms8: 'Sep',
ms9: 'Okt',
ms10: 'Nov',
ms11: 'Dez',
d0: 'Sonntag',
d1: 'Montag',
d2: 'Dienstag',
d3: 'Mittwoch',
d4: 'Donnerstag',
d5: 'Freitag',
d6: 'Samstag',
first_day: 1,
week_numbers_iso_8601: true,
holidays: {
'01-01': 'Neujahr',
'06-01': 'Heilige Drei Könige',
'easter-3': 'Gründonnerstag',
'easter-2': 'Karfreitag',
'easter': 'Ostersonntag',
'easter+1': 'Ostermontag',
'01-05': 'Tag der Arbeit',
'easter+39': 'Himmelfahrt',
'easter+49': 'Pfingstsonntag',
'easter+50': 'Pfingstmontag',
'15-08': 'Mariä Himmelfahrt',
'03-10': 'Tag der Deutschen Einheit',
'01-11': 'Allerheiligen',
'25-12': 'Erster Weihnachtsfeiertag',
'26-12': 'Zweiter Weihnachtsfeiertag'
}
};
if(!window.calendar_languages) {
window.calendar_languages = {};
}
window.calendar_languages['de-AT'] = {
error_noview: 'Kalender: Ansicht {0} nicht gefunden',
error_dateformat: 'Kalender: Falsches Datumsformat {0}. Sollte entweder "now" oder "yyyy-mm-dd" sein',
error_loadurl: 'Kalender: Event-URL nicht gesetzt.',
error_where: 'Kalender: Falsche Navigationsrichtung {0}. Nur "next", "prev" oder "today" sind erlaubt',
error_timedevide: 'Kalender: Parameter für die Zeiteinteilung muss ein Teiler von 60 sein. Beispielsweise 10, 15, 30',
no_events_in_day: 'Keine Ereignisse an diesem Tag.',
title_year: '{0}',
title_month: '{0} {1}',
title_week: '{0}. Kalenderwoche {1}',
title_day: '{0}, der {1}. {2} {3}',
week: 'KW {0}',
all_day: 'Ganztägig',
time: 'Zeit',
events: 'Ereignisse',
before_time: 'Endet vor Zeitspanne',
after_time: 'Beginnt nach Zeitspanne',
m0: 'Jänner',
m1: 'Februar',
m2: 'März',
m3: 'April',
m4: 'Mai',
m5: 'Juni',
m6: 'Juli',
m7: 'August',
m8: 'September',
m9: 'Oktober',
m10: 'November',
m11: 'Dezember',
ms0: 'Jan',
ms1: 'Feb',
ms2: 'Mär',
ms3: 'Apr',
ms4: 'Mai',
ms5: 'Jun',
ms6: 'Jul',
ms7: 'Aug',
ms8: 'Sep',
ms9: 'Okt',
ms10: 'Nov',
ms11: 'Dez',
d0: 'Sonntag',
d1: 'Montag',
d2: 'Dienstag',
d3: 'Mittwoch',
d4: 'Donnerstag',
d5: 'Freitag',
d6: 'Samstag',
first_day: 1,
week_numbers_iso_8601: true,
holidays: {
'01-01': 'Neujahr',
'06-01': 'Heilige Drei Könige',
'easter-2': 'Karfreitag',
'easter+1': 'Ostermontag',
'01-05': 'Staatsfeiertag',
'easter+39': 'Christi Himmelfahrt',
'easter+49': 'Pfingstsonntag',
'easter+50': 'Pfingstmontag',
'15-08': 'Mariä Himmelfahrt',
'26-10': 'Nationalfeiertag',
'01-11': 'Allerheiligen',
'08-12': 'Mariä Empfängnis',
'24-12': 'Heiliger Abend',
'25-12': 'Weihnachten',
'26-12': 'Stefanitag',
'31-12': 'Silvester'
}
};
if(!window.calendar_languages) {
window.calendar_languages = {};
}
window.calendar_languages['es-ES'] = {
error_noview: 'Calendario: Vista {0} no encontrada',
error_dateformat: 'Calendario: Formato de fecha inválido {0}. Debe ser "now" o "yyyy-mm-dd"',
error_loadurl: 'Calendario: URL de carga de eventos no configurada',
error_where: 'Calendario: Dirección de navegación incorrecta {0}. Los valores correctos son "next" o "prev" o "today"',
error_timedevide: 'Calendario: parámetro para el separador de hora debe dividir 60 por un entero. Por ejemplo 10, 15, 30',
no_events_in_day: 'No hay eventos hoy',
title_year: 'Año {0}',
title_month: '{0} {1}',
title_week: 'Semana {0} del {1}',
title_day: '{0} {1} {2} {3}',
week: 'Semana {0}',
all_day: 'Todo el día',
time: 'Tiempo',
events: 'Eventos',
before_time: 'Horas previas',
after_time: 'Horas posteriores',
m0: 'Enero',
m1: 'Febrero',
m2: 'Marzo',
m3: 'Abril',
m4: 'Mayo',
m5: 'Junio',
m6: 'Julio',
m7: 'Agosto',
m8: 'Septiembre',
m9: 'Octubre',
m10: 'Noviembre',
m11: 'Diciembre',
ms0: 'Ene',
ms1: 'Feb',
ms2: 'Mar',
ms3: 'Abr',
ms4: 'May',
ms5: 'Jun',
ms6: 'Jul',
ms7: 'Ago',
ms8: 'Sep',
ms9: 'Oct',
ms10: 'Nov',
ms11: 'Dic',
d0: 'Domingo',
d1: 'Lunes',
d2: 'Martes',
d3: 'Miércoles',
d4: 'Jueves',
d5: 'Viernes',
d6: 'Sábado',
easter: 'Pascua',
easterMonday: 'Lunes de Pascua',
first_day: 1,
week_numbers_iso_8601: true,
holidays: {
'01-01': "Año Nuevo",
'06-01': "Día de Reyes",
'19-03': "San José",
'easter-3': "Jueves Santo",
'easter-2': "Viernes Santo",
'easter': "Pascua",
'easter+1': "Lunes de Pascua",
'01-05': "Día del Trabajador",
'15-08': "Asunción",
'12-10': "Fiesta Nacional de España",
'01-11': "Día de todos los Santos",
'06-12': "Día de la Constitución",
'08-12': "Inmaculada Concepción",
'25-12': "Navidad"
}
};
if(!window.calendar_languages) {
window.calendar_languages = {};
}
window.calendar_languages['fr-FR'] = {
error_noview: 'Calendrier: Vue {0} introuvable',
error_dateformat: 'Calendrier: Format de date incorrect {0}. Formats acceptés : "now" ou "yyyy-mm-dd"',
error_loadurl: 'Calendrier: L\'adresse de chargement des évènements n\'est pas définie',
error_where: 'Calendrier: Mauvaise commande de navigation {0}. Commandes acceptées : "suivant", "précédent" or "aujourd\'hui"',
error_timedevide: 'Calendrier: La valeur des espaces-temps doit diviser 60 avec une valeur exacte. Par exemple 10, 15, 30',
title_year: 'Année {0}',
title_month: '{0} {1}',
title_week: 'Semaine {0}',
title_day: '{0} {1} {2} {3}',
week: 'Semaine {0}',
all_day: 'Toute la journée',
time: 'Heure',
events: 'Evènements',
before_time: 'Se terminant avant le début de plage horaire',
after_time: 'Se terminant après la fin de la plage horaire',
m0: 'Janvier',
m1: 'Février',
m2: 'Mars',
m3: 'Avril',
m4: 'Mai',
m5: 'Juin',
m6: 'Juillet',
m7: 'Août',
m8: 'Septembre',
m9: 'Octobre',
m10: 'Novembre',
m11: 'Décembre',
ms0: 'Jan',
ms1: 'Fév',
ms2: 'Mar',
ms3: 'Avr',
ms4: 'Mai',
ms5: 'Jun',
ms6: 'Jul',
ms7: 'Aoû',
ms8: 'Sep',
ms9: 'Oct',
ms10: 'Nov',
ms11: 'Déc',
d0: 'Dimanche',
d1: 'Lundi',
d2: 'Mardi',
d3: 'Mercredi',
d4: 'Jeudi',
d5: 'Vendredi',
d6: 'Samedi',
first_day: 1,
week_numbers_iso_8601: true,
holidays: {
'01-01': "Premier de l'an",
'easter': "Pâques",
'easter+1': "Lundi de Pâques",
'01-05': "Fête du Travail",
'08-05': "Fête de la Victoire 1945",
'easter+39': "Ascension",
'easter+49': "Pentecôte",
'easter+50': "Lundi de Pentecôte",
'14-07': "Fête Nationale",
'15-08': "Assomption",
'01-11': "Toussaint",
'11-11': "Armistice 1918",
'25-12': "Noël"
}
};
if(!window.calendar_languages) {
window.calendar_languages = {};
}
window.calendar_languages['el-GR'] = {
error_noview: 'Ημερολόγιο: Η προβολή {0} δεν βρέθηκε',
error_dateformat: 'Ημερολόγιο: Η μορφή της ημερομηνίας {0} δεν είναι έγκυρη. Παρακαλώ χρησιμοποιήστε "now" ή "yyyy-mm-dd"',
error_loadurl: 'Ημερολόγιο: Η διεύθυνση λήψης των event δεν έχει καθοριστεί',
error_where: 'Ημερολόγιο: Η μορφή κατεύθυνσης {0} δεν είναι έγκυρη. Παρακαλώ χρησιμοποιήστε μία εκ των "next", "prev" και "today"',
error_timedevide: 'Ημερολόγιο: παράμετρος στο διαχωριστή χρόνου πρέπει να διαιρέσει το 60 με έναν ακέραιο αριθμό. Για παράδειγμα 10, 15, 30',
no_events_in_day: 'Δεν υπάρχουν καταχωρήσεις σε αυτήν την ημέρα.',
title_year: 'Έτος {0}',
title_month: '{0} {1}',
title_week: 'Εβδομάδα {0} του έτους {1}',
title_day: '{0} {1} {2} {3}',
week: 'Εβδομάδα {0}',
all_day: 'Όλη την ημέρα',
time: 'χρόνος',
events: 'εξελίξεις',
before_time: 'Ώρα πριν από το τέλος της ταινίας',
after_time: 'Τερματισμός μετά από μια προσωρινή ταινία',
m0: 'Ιανουάριος',
m1: 'Φεβρουάριος',
m2: 'Μάρτιος',
m3: 'Απρίλιος',
m4: 'Μάϊος',
m5: 'Ιούνιος',
m6: 'Ιούλιος',
m7: 'Αύγουστος',
m8: 'Σεπτέμβριος',
m9: 'Οκτώβριος',
m10: 'Νοέμβριος',
m11: 'Δεκέμβριος',
ms0: 'Ιαν',
ms1: 'Φεβ',
ms2: 'Μαρ',
ms3: 'Απρ',
ms4: 'Μαϊ',
ms5: 'Ιουν',
ms6: 'Ιουλ',
ms7: 'Αυγ',
ms8: 'Σεπ',
ms9: 'Οκτ',
ms10: 'Νοε',
ms11: 'Δεκ',
d0: 'Κυριακή',
d1: 'Δευτέρα',
d2: 'Τρίτη',
d3: 'Τετάρτη',
d4: 'Πέμπτη',
d5: 'Παρασκευή',
d6: 'Σάββατο',
easter: 'Πάσχα',
easterMonday: 'Δευτέρα του Πάσχα',
first_day: 1,
week_numbers_iso_8601: true,
holidays: {
'01-01': "Πρωτοχρονιά",
'06-01': "Θεοφάνεια",
'easter-41': "Καθαρά Δευτέρα",
'23-03': "Εικοστή Πέμπτη Μαρτιου",
'easter-2': "Μεγάλη Παρασκευή",
'easter': "Κυριακή του Πάσχα",
'easter+1': "Δευτέρα του Πάσχα",
'01-05': "Εργατική Πρωτομαγιά",
'easter+49': "Πεντηκοστή",
'easter+50': "Αγίου Πνεύματος",
'15-08': "Η Κοίμηση της Θεοτόκου",
'28-10': "Ημέρα του Όχι",
'25-12': "Χριστούγεννα",
'26-12': "Σύναξις Ὑπεραγίας Θεοτόκου Μαρίας"
}
};
if(!window.calendar_languages) {
window.calendar_languages = {};
}
window.calendar_languages['tr-TR'] = {
error_noview: 'Takvim: Görünüm {0} bulunamadı',
error_dateformat: 'Takvim: Yanlış tarih formatı {0}. Şunlardan biri olmalı "now" veya "yyyy-mm-dd"',
error_loadurl: 'Takvim: Etkinlik bağlantısı belirtilmemiş',
error_where: 'Takvim: Yanlış gezinme yönü {0}. Sadece bunlardan biri olabilir "next" veya "prev" veya "today"',
error_timedevide: 'Takvim: Zaman bölme parametresi 60\'ı kalansız bölmelidir. 10, 15, 30 gibi',
no_events_in_day: 'Bugün etkinlik yok',
title_year: '{0}',
title_month: '{0} {1}',
title_week: '{1} {0}. Hafta',
title_day: '{0} {1} {2}, {3}',
week: '{0}. Hafta',
all_day: 'Tüm gün',
time: 'Zaman',
events: 'Etkinlikler',
before_time: 'Zamanından önce biter',
after_time: 'Zamanından sonra başlar',
m0: 'Ocak',
m1: 'Şubat',
m2: 'Mart',
m3: 'Nisan',
m4: 'Mayıs',
m5: 'Haziran',
m6: 'Temmuz',
m7: 'Ağustos',
m8: 'Eylül',
m9: 'Ekim',
m10: 'Kasım',
m11: 'Aralık',
ms0: 'Oca',
ms1: 'Şub',
ms2: 'Mar',
ms3: 'Nis',
ms4: 'May',
ms5: 'Haz',
ms6: 'Tem',
ms7: 'Ağu',
ms8: 'Eyl',
ms9: 'Eki',
ms10: 'Kas',
ms11: 'Ara',
d0: 'Pazar',
d1: 'Pazartesi',
d2: 'Salı',
d3: 'Çarşamba',
d4: 'Perşembe',
d5: 'Cuma',
d6: 'Cumartesi',
first_day: 1,
week_numbers_iso_8601: true,
holidays: {
'01-01' : 'Yılbaşı',
'23-04' : 'Ulusal Egemenlik ve Çocuk Bayramı',
'01-05' : 'İşçi Bayramı',
'19-05' : 'Atatürk\'ü Anma, Gençlik ve Spor Bayramı',
'30-08' : 'Zafer Bayramı',
'29-10' : 'Cumhuriyet Bayramı'
}
};
/*! nouislider - 11.1.0 - 2018-04-02 11:18:13 */
(function (factory) {
if ( typeof define === 'function' && define.amd ) {
// AMD. Register as an anonymous module.
define([], factory);
} else if ( typeof exports === 'object' ) {
// Node/CommonJS
module.exports = factory();
} else {
// Browser globals
window.noUiSlider = factory();
}
}(function( ){
'use strict';
var VERSION = '11.1.0';
function isValidFormatter ( entry ) {
return typeof entry === 'object' && typeof entry.to === 'function' && typeof entry.from === 'function';
}
function removeElement ( el ) {
el.parentElement.removeChild(el);
}
function isSet ( value ) {
return value !== null && value !== undefined;
}
// Bindable version
function preventDefault ( e ) {
e.preventDefault();
}
// Removes duplicates from an array.
function unique ( array ) {
return array.filter(function(a){
return !this[a] ? this[a] = true : false;
}, {});
}
// Round a value to the closest 'to'.
function closest ( value, to ) {
return Math.round(value / to) * to;
}
// Current position of an element relative to the document.
function offset ( elem, orientation ) {
var rect = elem.getBoundingClientRect();
var doc = elem.ownerDocument;
var docElem = doc.documentElement;
var pageOffset = getPageOffset(doc);
// getBoundingClientRect contains left scroll in Chrome on Android.
// I haven't found a feature detection that proves this. Worst case
// scenario on mis-match: the 'tap' feature on horizontal sliders breaks.
if ( /webkit.*Chrome.*Mobile/i.test(navigator.userAgent) ) {
pageOffset.x = 0;
}
return orientation ? (rect.top + pageOffset.y - docElem.clientTop) : (rect.left + pageOffset.x - docElem.clientLeft);
}
// Checks whether a value is numerical.
function isNumeric ( a ) {
return typeof a === 'number' && !isNaN( a ) && isFinite( a );
}
// Sets a class and removes it after [duration] ms.
function addClassFor ( element, className, duration ) {
if (duration > 0) {
addClass(element, className);
setTimeout(function(){
removeClass(element, className);
}, duration);
}
}
// Limits a value to 0 - 100
function limit ( a ) {
return Math.max(Math.min(a, 100), 0);
}
// Wraps a variable as an array, if it isn't one yet.
// Note that an input array is returned by reference!
function asArray ( a ) {
return Array.isArray(a) ? a : [a];
}
// Counts decimals
function countDecimals ( numStr ) {
numStr = String(numStr);
var pieces = numStr.split(".");
return pieces.length > 1 ? pieces[1].length : 0;
}
// http://youmightnotneedjquery.com/#add_class
function addClass ( el, className ) {
if ( el.classList ) {
el.classList.add(className);
} else {
el.className += ' ' + className;
}
}
// http://youmightnotneedjquery.com/#remove_class
function removeClass ( el, className ) {
if ( el.classList ) {
el.classList.remove(className);
} else {
el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
}
// https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/
function hasClass ( el, className ) {
return el.classList ? el.classList.contains(className) : new RegExp('\\b' + className + '\\b').test(el.className);
}
// https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes
function getPageOffset ( doc ) {
var supportPageOffset = window.pageXOffset !== undefined;
var isCSS1Compat = ((doc.compatMode || "") === "CSS1Compat");
var x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? doc.documentElement.scrollLeft : doc.body.scrollLeft;
var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? doc.documentElement.scrollTop : doc.body.scrollTop;
return {
x: x,
y: y
};
}
// we provide a function to compute constants instead
// of accessing window.* as soon as the module needs it
// so that we do not compute anything if not needed
function getActions ( ) {
// Determine the events to bind. IE11 implements pointerEvents without
// a prefix, which breaks compatibility with the IE10 implementation.
return window.navigator.pointerEnabled ? {
start: 'pointerdown',
move: 'pointermove',
end: 'pointerup'
} : window.navigator.msPointerEnabled ? {
start: 'MSPointerDown',
move: 'MSPointerMove',
end: 'MSPointerUp'
} : {
start: 'mousedown touchstart',
move: 'mousemove touchmove',
end: 'mouseup touchend'
};
}
// https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
// Issue #785
function getSupportsPassive ( ) {
var supportsPassive = false;
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supportsPassive = true;
}
});
window.addEventListener('test', null, opts);
} catch (e) {}
return supportsPassive;
}
function getSupportsTouchActionNone ( ) {
return window.CSS && CSS.supports && CSS.supports('touch-action', 'none');
}
// Value calculation
// Determine the size of a sub-range in relation to a full range.
function subRangeRatio ( pa, pb ) {
return (100 / (pb - pa));
}
// (percentage) How many percent is this value of this range?
function fromPercentage ( range, value ) {
return (value * 100) / ( range[1] - range[0] );
}
// (percentage) Where is this value on this range?
function toPercentage ( range, value ) {
return fromPercentage( range, range[0] < 0 ?
value + Math.abs(range[0]) :
value - range[0] );
}
// (value) How much is this percentage on this range?
function isPercentage ( range, value ) {
return ((value * ( range[1] - range[0] )) / 100) + range[0];
}
// Range conversion
function getJ ( value, arr ) {
var j = 1;
while ( value >= arr[j] ){
j += 1;
}
return j;
}
// (percentage) Input a value, find where, on a scale of 0-100, it applies.
function toStepping ( xVal, xPct, value ) {
if ( value >= xVal.slice(-1)[0] ){
return 100;
}
var j = getJ( value, xVal );
var va = xVal[j-1];
var vb = xVal[j];
var pa = xPct[j-1];
var pb = xPct[j];
return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb));
}
// (value) Input a percentage, find where it is on the specified range.
function fromStepping ( xVal, xPct, value ) {
// There is no range group that fits 100
if ( value >= 100 ){
return xVal.slice(-1)[0];
}
var j = getJ( value, xPct );
var va = xVal[j-1];
var vb = xVal[j];
var pa = xPct[j-1];
var pb = xPct[j];
return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb));
}
// (percentage) Get the step that applies at a certain value.
function getStep ( xPct, xSteps, snap, value ) {
if ( value === 100 ) {
return value;
}
var j = getJ( value, xPct );
var a = xPct[j-1];
var b = xPct[j];
// If 'snap' is set, steps are used as fixed points on the slider.
if ( snap ) {
// Find the closest position, a or b.
if ((value - a) > ((b-a)/2)){
return b;
}
return a;
}
if ( !xSteps[j-1] ){
return value;
}
return xPct[j-1] + closest(
value - xPct[j-1],
xSteps[j-1]
);
}
// Entry parsing
function handleEntryPoint ( index, value, that ) {
var percentage;
// Wrap numerical input in an array.
if ( typeof value === "number" ) {
value = [value];
}
// Reject any invalid input, by testing whether value is an array.
if ( !Array.isArray(value) ){
throw new Error("noUiSlider (" + VERSION + "): 'range' contains invalid value.");
}
// Covert min/max syntax to 0 and 100.
if ( index === 'min' ) {
percentage = 0;
} else if ( index === 'max' ) {
percentage = 100;
} else {
percentage = parseFloat( index );
}
// Check for correct input.
if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) {
throw new Error("noUiSlider (" + VERSION + "): 'range' value isn't numeric.");
}
// Store values.
that.xPct.push( percentage );
that.xVal.push( value[0] );
// NaN will evaluate to false too, but to keep
// logging clear, set step explicitly. Make sure
// not to override the 'step' setting with false.
if ( !percentage ) {
if ( !isNaN( value[1] ) ) {
that.xSteps[0] = value[1];
}
} else {
that.xSteps.push( isNaN(value[1]) ? false : value[1] );
}
that.xHighestCompleteStep.push(0);
}
function handleStepPoint ( i, n, that ) {
// Ignore 'false' stepping.
if ( !n ) {
return true;
}
// Factor to range ratio
that.xSteps[i] = fromPercentage([that.xVal[i], that.xVal[i+1]], n) / subRangeRatio(that.xPct[i], that.xPct[i+1]);
var totalSteps = (that.xVal[i+1] - that.xVal[i]) / that.xNumSteps[i];
var highestStep = Math.ceil(Number(totalSteps.toFixed(3)) - 1);
var step = that.xVal[i] + (that.xNumSteps[i] * highestStep);
that.xHighestCompleteStep[i] = step;
}
// Interface
function Spectrum ( entry, snap, singleStep ) {
this.xPct = [];
this.xVal = [];
this.xSteps = [ singleStep || false ];
this.xNumSteps = [ false ];
this.xHighestCompleteStep = [];
this.snap = snap;
var index;
var ordered = []; // [0, 'min'], [1, '50%'], [2, 'max']
// Map the object keys to an array.
for ( index in entry ) {
if ( entry.hasOwnProperty(index) ) {
ordered.push([entry[index], index]);
}
}
// Sort all entries by value (numeric sort).
if ( ordered.length && typeof ordered[0][0] === "object" ) {
ordered.sort(function(a, b) { return a[0][0] - b[0][0]; });
} else {
ordered.sort(function(a, b) { return a[0] - b[0]; });
}
// Convert all entries to subranges.
for ( index = 0; index < ordered.length; index++ ) {
handleEntryPoint(ordered[index][1], ordered[index][0], this);
}
// Store the actual step values.
// xSteps is sorted in the same order as xPct and xVal.
this.xNumSteps = this.xSteps.slice(0);
// Convert all numeric steps to the percentage of the subrange they represent.
for ( index = 0; index < this.xNumSteps.length; index++ ) {
handleStepPoint(index, this.xNumSteps[index], this);
}
}
Spectrum.prototype.getMargin = function ( value ) {
var step = this.xNumSteps[0];
if ( step && ((value / step) % 1) !== 0 ) {
throw new Error("noUiSlider (" + VERSION + "): 'limit', 'margin' and 'padding' must be divisible by step.");
}
return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false;
};
Spectrum.prototype.toStepping = function ( value ) {
value = toStepping( this.xVal, this.xPct, value );
return value;
};
Spectrum.prototype.fromStepping = function ( value ) {
return fromStepping( this.xVal, this.xPct, value );
};
Spectrum.prototype.getStep = function ( value ) {
value = getStep(this.xPct, this.xSteps, this.snap, value );
return value;
};
Spectrum.prototype.getNearbySteps = function ( value ) {
var j = getJ(value, this.xPct);
return {
stepBefore: { startValue: this.xVal[j-2], step: this.xNumSteps[j-2], highestStep: this.xHighestCompleteStep[j-2] },
thisStep: { startValue: this.xVal[j-1], step: this.xNumSteps[j-1], highestStep: this.xHighestCompleteStep[j-1] },
stepAfter: { startValue: this.xVal[j-0], step: this.xNumSteps[j-0], highestStep: this.xHighestCompleteStep[j-0] }
};
};
Spectrum.prototype.countStepDecimals = function () {
var stepDecimals = this.xNumSteps.map(countDecimals);
return Math.max.apply(null, stepDecimals);
};
// Outside testing
Spectrum.prototype.convert = function ( value ) {
return this.getStep(this.toStepping(value));
};
/* Every input option is tested and parsed. This'll prevent
endless validation in internal methods. These tests are
structured with an item for every option available. An
option can be marked as required by setting the 'r' flag.
The testing function is provided with three arguments:
- The provided value for the option;
- A reference to the options object;
- The name for the option;
The testing function returns false when an error is detected,
or true when everything is OK. It can also modify the option
object, to make sure all values can be correctly looped elsewhere. */
var defaultFormatter = { 'to': function( value ){
return value !== undefined && value.toFixed(2);
}, 'from': Number };
function validateFormat ( entry ) {
// Any object with a to and from method is supported.
if ( isValidFormatter(entry) ) {
return true;
}
throw new Error("noUiSlider (" + VERSION + "): 'format' requires 'to' and 'from' methods.");
}
function testStep ( parsed, entry ) {
if ( !isNumeric( entry ) ) {
throw new Error("noUiSlider (" + VERSION + "): 'step' is not numeric.");
}
// The step option can still be used to set stepping
// for linear sliders. Overwritten if set in 'range'.
parsed.singleStep = entry;
}
function testRange ( parsed, entry ) {
// Filter incorrect input.
if ( typeof entry !== 'object' || Array.isArray(entry) ) {
throw new Error("noUiSlider (" + VERSION + "): 'range' is not an object.");
}
// Catch missing start or end.
if ( entry.min === undefined || entry.max === undefined ) {
throw new Error("noUiSlider (" + VERSION + "): Missing 'min' or 'max' in 'range'.");
}
// Catch equal start or end.
if ( entry.min === entry.max ) {
throw new Error("noUiSlider (" + VERSION + "): 'range' 'min' and 'max' cannot be equal.");
}
parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.singleStep);
}
function testStart ( parsed, entry ) {
entry = asArray(entry);
// Validate input. Values aren't tested, as the public .val method
// will always provide a valid location.
if ( !Array.isArray( entry ) || !entry.length ) {
throw new Error("noUiSlider (" + VERSION + "): 'start' option is incorrect.");
}
// Store the number of handles.
parsed.handles = entry.length;
// When the slider is initialized, the .val method will
// be called with the start options.
parsed.start = entry;
}
function testSnap ( parsed, entry ) {
// Enforce 100% stepping within subranges.
parsed.snap = entry;
if ( typeof entry !== 'boolean' ){
throw new Error("noUiSlider (" + VERSION + "): 'snap' option must be a boolean.");
}
}
function testAnimate ( parsed, entry ) {
// Enforce 100% stepping within subranges.
parsed.animate = entry;
if ( typeof entry !== 'boolean' ){
throw new Error("noUiSlider (" + VERSION + "): 'animate' option must be a boolean.");
}
}
function testAnimationDuration ( parsed, entry ) {
parsed.animationDuration = entry;
if ( typeof entry !== 'number' ){
throw new Error("noUiSlider (" + VERSION + "): 'animationDuration' option must be a number.");
}
}
function testConnect ( parsed, entry ) {
var connect = [false];
var i;
// Map legacy options
if ( entry === 'lower' ) {
entry = [true, false];
}
else if ( entry === 'upper' ) {
entry = [false, true];
}
// Handle boolean options
if ( entry === true || entry === false ) {
for ( i = 1; i < parsed.handles; i++ ) {
connect.push(entry);
}
connect.push(false);
}
// Reject invalid input
else if ( !Array.isArray( entry ) || !entry.length || entry.length !== parsed.handles + 1 ) {
throw new Error("noUiSlider (" + VERSION + "): 'connect' option doesn't match handle count.");
}
else {
connect = entry;
}
parsed.connect = connect;
}
function testOrientation ( parsed, entry ) {
// Set orientation to an a numerical value for easy
// array selection.
switch ( entry ){
case 'horizontal':
parsed.ort = 0;
break;
case 'vertical':
parsed.ort = 1;
break;
default:
throw new Error("noUiSlider (" + VERSION + "): 'orientation' option is invalid.");
}
}
function testMargin ( parsed, entry ) {
if ( !isNumeric(entry) ){
throw new Error("noUiSlider (" + VERSION + "): 'margin' option must be numeric.");
}
// Issue #582
if ( entry === 0 ) {
return;
}
parsed.margin = parsed.spectrum.getMargin(entry);
if ( !parsed.margin ) {
throw new Error("noUiSlider (" + VERSION + "): 'margin' option is only supported on linear sliders.");
}
}
function testLimit ( parsed, entry ) {
if ( !isNumeric(entry) ){
throw new Error("noUiSlider (" + VERSION + "): 'limit' option must be numeric.");
}
parsed.limit = parsed.spectrum.getMargin(entry);
if ( !parsed.limit || parsed.handles < 2 ) {
throw new Error("noUiSlider (" + VERSION + "): 'limit' option is only supported on linear sliders with 2 or more handles.");
}
}
function testPadding ( parsed, entry ) {
if ( !isNumeric(entry) && !Array.isArray(entry) ){
throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be numeric or array of exactly 2 numbers.");
}
if ( Array.isArray(entry) && !(entry.length === 2 || isNumeric(entry[0]) || isNumeric(entry[1])) ) {
throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be numeric or array of exactly 2 numbers.");
}
if ( entry === 0 ) {
return;
}
if ( !Array.isArray(entry) ) {
entry = [entry, entry];
}
// 'getMargin' returns false for invalid values.
parsed.padding = [parsed.spectrum.getMargin(entry[0]), parsed.spectrum.getMargin(entry[1])];
if ( parsed.padding[0] === false || parsed.padding[1] === false ) {
throw new Error("noUiSlider (" + VERSION + "): 'padding' option is only supported on linear sliders.");
}
if ( parsed.padding[0] < 0 || parsed.padding[1] < 0 ) {
throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be a positive number(s).");
}
if ( parsed.padding[0] + parsed.padding[1] >= 100 ) {
throw new Error("noUiSlider (" + VERSION + "): 'padding' option must not exceed 100% of the range.");
}
}
function testDirection ( parsed, entry ) {
// Set direction as a numerical value for easy parsing.
// Invert connection for RTL sliders, so that the proper
// handles get the connect/background classes.
switch ( entry ) {
case 'ltr':
parsed.dir = 0;
break;
case 'rtl':
parsed.dir = 1;
break;
default:
throw new Error("noUiSlider (" + VERSION + "): 'direction' option was not recognized.");
}
}
function testBehaviour ( parsed, entry ) {
// Make sure the input is a string.
if ( typeof entry !== 'string' ) {
throw new Error("noUiSlider (" + VERSION + "): 'behaviour' must be a string containing options.");
}
// Check if the string contains any keywords.
// None are required.
var tap = entry.indexOf('tap') >= 0;
var drag = entry.indexOf('drag') >= 0;
var fixed = entry.indexOf('fixed') >= 0;
var snap = entry.indexOf('snap') >= 0;
var hover = entry.indexOf('hover') >= 0;
if ( fixed ) {
if ( parsed.handles !== 2 ) {
throw new Error("noUiSlider (" + VERSION + "): 'fixed' behaviour must be used with 2 handles");
}
// Use margin to enforce fixed state
testMargin(parsed, parsed.start[1] - parsed.start[0]);
}
parsed.events = {
tap: tap || snap,
drag: drag,
fixed: fixed,
snap: snap,
hover: hover
};
}
function testTooltips ( parsed, entry ) {
if ( entry === false ) {
return;
}
else if ( entry === true ) {
parsed.tooltips = [];
for ( var i = 0; i < parsed.handles; i++ ) {
parsed.tooltips.push(true);
}
}
else {
parsed.tooltips = asArray(entry);
if ( parsed.tooltips.length !== parsed.handles ) {
throw new Error("noUiSlider (" + VERSION + "): must pass a formatter for all handles.");
}
parsed.tooltips.forEach(function(formatter){
if ( typeof formatter !== 'boolean' && (typeof formatter !== 'object' || typeof formatter.to !== 'function') ) {
throw new Error("noUiSlider (" + VERSION + "): 'tooltips' must be passed a formatter or 'false'.");
}
});
}
}
function testAriaFormat ( parsed, entry ) {
parsed.ariaFormat = entry;
validateFormat(entry);
}
function testFormat ( parsed, entry ) {
parsed.format = entry;
validateFormat(entry);
}
function testCssPrefix ( parsed, entry ) {
if ( typeof entry !== 'string' && entry !== false ) {
throw new Error("noUiSlider (" + VERSION + "): 'cssPrefix' must be a string or `false`.");
}
parsed.cssPrefix = entry;
}
function testCssClasses ( parsed, entry ) {
if ( typeof entry !== 'object' ) {
throw new Error("noUiSlider (" + VERSION + "): 'cssClasses' must be an object.");
}
if ( typeof parsed.cssPrefix === 'string' ) {
parsed.cssClasses = {};
for ( var key in entry ) {
if ( !entry.hasOwnProperty(key) ) { continue; }
parsed.cssClasses[key] = parsed.cssPrefix + entry[key];
}
} else {
parsed.cssClasses = entry;
}
}
// Test all developer settings and parse to assumption-safe values.
function testOptions ( options ) {
// To prove a fix for #537, freeze options here.
// If the object is modified, an error will be thrown.
// Object.freeze(options);
var parsed = {
margin: 0,
limit: 0,
padding: 0,
animate: true,
animationDuration: 300,
ariaFormat: defaultFormatter,
format: defaultFormatter
};
// Tests are executed in the order they are presented here.
var tests = {
'step': { r: false, t: testStep },
'start': { r: true, t: testStart },
'connect': { r: true, t: testConnect },
'direction': { r: true, t: testDirection },
'snap': { r: false, t: testSnap },
'animate': { r: false, t: testAnimate },
'animationDuration': { r: false, t: testAnimationDuration },
'range': { r: true, t: testRange },
'orientation': { r: false, t: testOrientation },
'margin': { r: false, t: testMargin },
'limit': { r: false, t: testLimit },
'padding': { r: false, t: testPadding },
'behaviour': { r: true, t: testBehaviour },
'ariaFormat': { r: false, t: testAriaFormat },
'format': { r: false, t: testFormat },
'tooltips': { r: false, t: testTooltips },
'cssPrefix': { r: true, t: testCssPrefix },
'cssClasses': { r: true, t: testCssClasses }
};
var defaults = {
'connect': false,
'direction': 'ltr',
'behaviour': 'tap',
'orientation': 'horizontal',
'cssPrefix' : 'noUi-',
'cssClasses': {
target: 'target',
base: 'base',
origin: 'origin',
handle: 'handle',
handleLower: 'handle-lower',
handleUpper: 'handle-upper',
horizontal: 'horizontal',
vertical: 'vertical',
background: 'background',
connect: 'connect',
connects: 'connects',
ltr: 'ltr',
rtl: 'rtl',
draggable: 'draggable',
drag: 'state-drag',
tap: 'state-tap',
active: 'active',
tooltip: 'tooltip',
pips: 'pips',
pipsHorizontal: 'pips-horizontal',
pipsVertical: 'pips-vertical',
marker: 'marker',
markerHorizontal: 'marker-horizontal',
markerVertical: 'marker-vertical',
markerNormal: 'marker-normal',
markerLarge: 'marker-large',
markerSub: 'marker-sub',
value: 'value',
valueHorizontal: 'value-horizontal',
valueVertical: 'value-vertical',
valueNormal: 'value-normal',
valueLarge: 'value-large',
valueSub: 'value-sub'
}
};
// AriaFormat defaults to regular format, if any.
if ( options.format && !options.ariaFormat ) {
options.ariaFormat = options.format;
}
// Run all options through a testing mechanism to ensure correct
// input. It should be noted that options might get modified to
// be handled properly. E.g. wrapping integers in arrays.
Object.keys(tests).forEach(function( name ){
// If the option isn't set, but it is required, throw an error.
if ( !isSet(options[name]) && defaults[name] === undefined ) {
if ( tests[name].r ) {
throw new Error("noUiSlider (" + VERSION + "): '" + name + "' is required.");
}
return true;
}
tests[name].t( parsed, !isSet(options[name]) ? defaults[name] : options[name] );
});
// Forward pips options
parsed.pips = options.pips;
// All recent browsers accept unprefixed transform.
// We need -ms- for IE9 and -webkit- for older Android;
// Assume use of -webkit- if unprefixed and -ms- are not supported.
// https://caniuse.com/#feat=transforms2d
var d = document.createElement("div");
var msPrefix = d.style.msTransform !== undefined;
var noPrefix = d.style.transform !== undefined;
parsed.transformRule = noPrefix ? 'transform' : (msPrefix ? 'msTransform' : 'webkitTransform');
// Pips don't move, so we can place them using left/top.
var styles = [['left', 'top'], ['right', 'bottom']];
parsed.style = styles[parsed.dir][parsed.ort];
return parsed;
}
function scope ( target, options, originalOptions ){
var actions = getActions();
var supportsTouchActionNone = getSupportsTouchActionNone();
var supportsPassive = supportsTouchActionNone && getSupportsPassive();
// All variables local to 'scope' are prefixed with 'scope_'
var scope_Target = target;
var scope_Locations = [];
var scope_Base;
var scope_Handles;
var scope_HandleNumbers = [];
var scope_ActiveHandlesCount = 0;
var scope_Connects;
var scope_Spectrum = options.spectrum;
var scope_Values = [];
var scope_Events = {};
var scope_Self;
var scope_Pips;
var scope_Document = target.ownerDocument;
var scope_DocumentElement = scope_Document.documentElement;
var scope_Body = scope_Document.body;
// For horizontal sliders in standard ltr documents,
// make .noUi-origin overflow to the left so the document doesn't scroll.
var scope_DirOffset = (scope_Document.dir === 'rtl') || (options.ort === 1) ? 0 : 100;
/*! In this file: Construction of DOM elements; */
// Creates a node, adds it to target, returns the new node.
function addNodeTo ( addTarget, className ) {
var div = scope_Document.createElement('div');
if ( className ) {
addClass(div, className);
}
addTarget.appendChild(div);
return div;
}
// Append a origin to the base
function addOrigin ( base, handleNumber ) {
var origin = addNodeTo(base, options.cssClasses.origin);
var handle = addNodeTo(origin, options.cssClasses.handle);
handle.setAttribute('data-handle', handleNumber);
// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
// 0 = focusable and reachable
handle.setAttribute('tabindex', '0');
handle.setAttribute('role', 'slider');
handle.setAttribute('aria-orientation', options.ort ? 'vertical' : 'horizontal');
if ( handleNumber === 0 ) {
addClass(handle, options.cssClasses.handleLower);
}
else if ( handleNumber === options.handles - 1 ) {
addClass(handle, options.cssClasses.handleUpper);
}
return origin;
}
// Insert nodes for connect elements
function addConnect ( base, add ) {
if ( !add ) {
return false;
}
return addNodeTo(base, options.cssClasses.connect);
}
// Add handles to the slider base.
function addElements ( connectOptions, base ) {
var connectBase = addNodeTo(base, options.cssClasses.connects);
scope_Handles = [];
scope_Connects = [];
scope_Connects.push(addConnect(connectBase, connectOptions[0]));
// [::::O====O====O====]
// connectOptions = [0, 1, 1, 1]
for ( var i = 0; i < options.handles; i++ ) {
// Keep a list of all added handles.
scope_Handles.push(addOrigin(base, i));
scope_HandleNumbers[i] = i;
scope_Connects.push(addConnect(connectBase, connectOptions[i + 1]));
}
}
// Initialize a single slider.
function addSlider ( addTarget ) {
// Apply classes and data to the target.
addClass(addTarget, options.cssClasses.target);
if ( options.dir === 0 ) {
addClass(addTarget, options.cssClasses.ltr);
} else {
addClass(addTarget, options.cssClasses.rtl);
}
if ( options.ort === 0 ) {
addClass(addTarget, options.cssClasses.horizontal);
} else {
addClass(addTarget, options.cssClasses.vertical);
}
scope_Base = addNodeTo(addTarget, options.cssClasses.base);
}
function addTooltip ( handle, handleNumber ) {
if ( !options.tooltips[handleNumber] ) {
return false;
}
return addNodeTo(handle.firstChild, options.cssClasses.tooltip);
}
// The tooltips option is a shorthand for using the 'update' event.
function tooltips ( ) {
// Tooltips are added with options.tooltips in original order.
var tips = scope_Handles.map(addTooltip);
bindEvent('update', function(values, handleNumber, unencoded) {
if ( !tips[handleNumber] ) {
return;
}
var formattedValue = values[handleNumber];
if ( options.tooltips[handleNumber] !== true ) {
formattedValue = options.tooltips[handleNumber].to(unencoded[handleNumber]);
}
tips[handleNumber].innerHTML = formattedValue;
});
}
function aria ( ) {
bindEvent('update', function ( values, handleNumber, unencoded, tap, positions ) {
// Update Aria Values for all handles, as a change in one changes min and max values for the next.
scope_HandleNumbers.forEach(function( index ){
var handle = scope_Handles[index];
var min = checkHandlePosition(scope_Locations, index, 0, true, true, true);
var max = checkHandlePosition(scope_Locations, index, 100, true, true, true);
var now = positions[index];
var text = options.ariaFormat.to(unencoded[index]);
handle.children[0].setAttribute('aria-valuemin', min.toFixed(1));
handle.children[0].setAttribute('aria-valuemax', max.toFixed(1));
handle.children[0].setAttribute('aria-valuenow', now.toFixed(1));
handle.children[0].setAttribute('aria-valuetext', text);
});
});
}
function getGroup ( mode, values, stepped ) {
// Use the range.
if ( mode === 'range' || mode === 'steps' ) {
return scope_Spectrum.xVal;
}
if ( mode === 'count' ) {
if ( values < 2 ) {
throw new Error("noUiSlider (" + VERSION + "): 'values' (>= 2) required for mode 'count'.");
}
// Divide 0 - 100 in 'count' parts.
var interval = values - 1;
var spread = ( 100 / interval );
values = [];
// List these parts and have them handled as 'positions'.
while ( interval-- ) {
values[ interval ] = ( interval * spread );
}
values.push(100);
mode = 'positions';
}
if ( mode === 'positions' ) {
// Map all percentages to on-range values.
return values.map(function( value ){
return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value );
});
}
if ( mode === 'values' ) {
// If the value must be stepped, it needs to be converted to a percentage first.
if ( stepped ) {
return values.map(function( value ){
// Convert to percentage, apply step, return to value.
return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) );
});
}
// Otherwise, we can simply use the values.
return values;
}
}
function generateSpread ( density, mode, group ) {
function safeIncrement(value, increment) {
// Avoid floating point variance by dropping the smallest decimal places.
return (value + increment).toFixed(7) / 1;
}
var indexes = {};
var firstInRange = scope_Spectrum.xVal[0];
var lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length-1];
var ignoreFirst = false;
var ignoreLast = false;
var prevPct = 0;
// Create a copy of the group, sort it and filter away all duplicates.
group = unique(group.slice().sort(function(a, b){ return a - b; }));
// Make sure the range starts with the first element.
if ( group[0] !== firstInRange ) {
group.unshift(firstInRange);
ignoreFirst = true;
}
// Likewise for the last one.
if ( group[group.length - 1] !== lastInRange ) {
group.push(lastInRange);
ignoreLast = true;
}
group.forEach(function ( current, index ) {
// Get the current step and the lower + upper positions.
var step;
var i;
var q;
var low = current;
var high = group[index+1];
var newPct;
var pctDifference;
var pctPos;
var type;
var steps;
var realSteps;
var stepsize;
// When using 'steps' mode, use the provided steps.
// Otherwise, we'll step on to the next subrange.
if ( mode === 'steps' ) {
step = scope_Spectrum.xNumSteps[ index ];
}
// Default to a 'full' step.
if ( !step ) {
step = high-low;
}
// Low can be 0, so test for false. If high is undefined,
// we are at the last subrange. Index 0 is already handled.
if ( low === false || high === undefined ) {
return;
}
// Make sure step isn't 0, which would cause an infinite loop (#654)
step = Math.max(step, 0.0000001);
// Find all steps in the subrange.
for ( i = low; i <= high; i = safeIncrement(i, step) ) {
// Get the percentage value for the current step,
// calculate the size for the subrange.
newPct = scope_Spectrum.toStepping( i );
pctDifference = newPct - prevPct;
steps = pctDifference / density;
realSteps = Math.round(steps);
// This ratio represents the amount of percentage-space a point indicates.
// For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided.
// Round the percentage offset to an even number, then divide by two
// to spread the offset on both sides of the range.
stepsize = pctDifference/realSteps;
// Divide all points evenly, adding the correct number to this subrange.
// Run up to <= so that 100% gets a point, event if ignoreLast is set.
for ( q = 1; q <= realSteps; q += 1 ) {
// The ratio between the rounded value and the actual size might be ~1% off.
// Correct the percentage offset by the number of points
// per subrange. density = 1 will result in 100 points on the
// full range, 2 for 50, 4 for 25, etc.
pctPos = prevPct + ( q * stepsize );
indexes[pctPos.toFixed(5)] = ['x', 0];
}
// Determine the point type.
type = (group.indexOf(i) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 );
// Enforce the 'ignoreFirst' option by overwriting the type for 0.
if ( !index && ignoreFirst ) {
type = 0;
}
if ( !(i === high && ignoreLast)) {
// Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value.
indexes[newPct.toFixed(5)] = [i, type];
}
// Update the percentage count.
prevPct = newPct;
}
});
return indexes;
}
function addMarking ( spread, filterFunc, formatter ) {
var element = scope_Document.createElement('div');
var valueSizeClasses = [
options.cssClasses.valueNormal,
options.cssClasses.valueLarge,
options.cssClasses.valueSub
];
var markerSizeClasses = [
options.cssClasses.markerNormal,
options.cssClasses.markerLarge,
options.cssClasses.markerSub
];
var valueOrientationClasses = [
options.cssClasses.valueHorizontal,
options.cssClasses.valueVertical
];
var markerOrientationClasses = [
options.cssClasses.markerHorizontal,
options.cssClasses.markerVertical
];
addClass(element, options.cssClasses.pips);
addClass(element, options.ort === 0 ? options.cssClasses.pipsHorizontal : options.cssClasses.pipsVertical);
function getClasses( type, source ){
var a = source === options.cssClasses.value;
var orientationClasses = a ? valueOrientationClasses : markerOrientationClasses;
var sizeClasses = a ? valueSizeClasses : markerSizeClasses;
return source + ' ' + orientationClasses[options.ort] + ' ' + sizeClasses[type];
}
function addSpread ( offset, values ){
// Apply the filter function, if it is set.
values[1] = (values[1] && filterFunc) ? filterFunc(values[0], values[1]) : values[1];
// Add a marker for every point
var node = addNodeTo(element, false);
node.className = getClasses(values[1], options.cssClasses.marker);
node.style[options.style] = offset + '%';
// Values are only appended for points marked '1' or '2'.
if ( values[1] ) {
node = addNodeTo(element, false);
node.className = getClasses(values[1], options.cssClasses.value);
node.setAttribute('data-value', values[0]);
node.style[options.style] = offset + '%';
node.innerText = formatter.to(values[0]);
}
}
// Append all points.
Object.keys(spread).forEach(function(a){
addSpread(a, spread[a]);
});
return element;
}
function removePips ( ) {
if ( scope_Pips ) {
removeElement(scope_Pips);
scope_Pips = null;
}
}
function pips ( grid ) {
// Fix #669
removePips();
var mode = grid.mode;
var density = grid.density || 1;
var filter = grid.filter || false;
var values = grid.values || false;
var stepped = grid.stepped || false;
var group = getGroup( mode, values, stepped );
var spread = generateSpread( density, mode, group );
var format = grid.format || {
to: Math.round
};
scope_Pips = scope_Target.appendChild(addMarking(
spread,
filter,
format
));
return scope_Pips;
}
/*! In this file: Browser events (not slider events like slide, change); */
// Shorthand for base dimensions.
function baseSize ( ) {
var rect = scope_Base.getBoundingClientRect();
var alt = 'offset' + ['Width', 'Height'][options.ort];
return options.ort === 0 ? (rect.width||scope_Base[alt]) : (rect.height||scope_Base[alt]);
}
// Handler for attaching events trough a proxy.
function attachEvent ( events, element, callback, data ) {
// This function can be used to 'filter' events to the slider.
// element is a node, not a nodeList
var method = function ( e ){
e = fixEvent(e, data.pageOffset, data.target || element);
// fixEvent returns false if this event has a different target
// when handling (multi-) touch events;
if ( !e ) {
return false;
}
// doNotReject is passed by all end events to make sure released touches
// are not rejected, leaving the slider "stuck" to the cursor;
if ( scope_Target.hasAttribute('disabled') && !data.doNotReject ) {
return false;
}
// Stop if an active 'tap' transition is taking place.
if ( hasClass(scope_Target, options.cssClasses.tap) && !data.doNotReject ) {
return false;
}
// Ignore right or middle clicks on start #454
if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) {
return false;
}
// Ignore right or middle clicks on start #454
if ( data.hover && e.buttons ) {
return false;
}
// 'supportsPassive' is only true if a browser also supports touch-action: none in CSS.
// iOS safari does not, so it doesn't get to benefit from passive scrolling. iOS does support
// touch-action: manipulation, but that allows panning, which breaks
// sliders after zooming/on non-responsive pages.
// See: https://bugs.webkit.org/show_bug.cgi?id=133112
if ( !supportsPassive ) {
e.preventDefault();
}
e.calcPoint = e.points[ options.ort ];
// Call the event handler with the event [ and additional data ].
callback ( e, data );
};
var methods = [];
// Bind a closure on the target for every event type.
events.split(' ').forEach(function( eventName ){
element.addEventListener(eventName, method, supportsPassive ? { passive: true } : false);
methods.push([eventName, method]);
});
return methods;
}
// Provide a clean event with standardized offset values.
function fixEvent ( e, pageOffset, eventTarget ) {
// Filter the event to register the type, which can be
// touch, mouse or pointer. Offset changes need to be
// made on an event specific basis.
var touch = e.type.indexOf('touch') === 0;
var mouse = e.type.indexOf('mouse') === 0;
var pointer = e.type.indexOf('pointer') === 0;
var x;
var y;
// IE10 implemented pointer events with a prefix;
if ( e.type.indexOf('MSPointer') === 0 ) {
pointer = true;
}
// In the event that multitouch is activated, the only thing one handle should be concerned
// about is the touches that originated on top of it.
if ( touch ) {
// Returns true if a touch originated on the target.
var isTouchOnTarget = function (checkTouch) {
return checkTouch.target === eventTarget || eventTarget.contains(checkTouch.target);
};
// In the case of touchstart events, we need to make sure there is still no more than one
// touch on the target so we look amongst all touches.
if (e.type === 'touchstart') {
var targetTouches = Array.prototype.filter.call(e.touches, isTouchOnTarget);
// Do not support more than one touch per handle.
if ( targetTouches.length > 1 ) {
return false;
}
x = targetTouches[0].pageX;
y = targetTouches[0].pageY;
} else {
// In the other cases, find on changedTouches is enough.
var targetTouch = Array.prototype.find.call(e.changedTouches, isTouchOnTarget);
// Cancel if the target touch has not moved.
if ( !targetTouch ) {
return false;
}
x = targetTouch.pageX;
y = targetTouch.pageY;
}
}
pageOffset = pageOffset || getPageOffset(scope_Document);
if ( mouse || pointer ) {
x = e.clientX + pageOffset.x;
y = e.clientY + pageOffset.y;
}
e.pageOffset = pageOffset;
e.points = [x, y];
e.cursor = mouse || pointer; // Fix #435
return e;
}
// Translate a coordinate in the document to a percentage on the slider
function calcPointToPercentage ( calcPoint ) {
var location = calcPoint - offset(scope_Base, options.ort);
var proposal = ( location * 100 ) / baseSize();
// Clamp proposal between 0% and 100%
// Out-of-bound coordinates may occur when .noUi-base pseudo-elements
// are used (e.g. contained handles feature)
proposal = limit(proposal);
return options.dir ? 100 - proposal : proposal;
}
// Find handle closest to a certain percentage on the slider
function getClosestHandle ( proposal ) {
var closest = 100;
var handleNumber = false;
scope_Handles.forEach(function(handle, index){
// Disabled handles are ignored
if ( handle.hasAttribute('disabled') ) {
return;
}
var pos = Math.abs(scope_Locations[index] - proposal);
if ( pos < closest || (pos === 100 && closest === 100) ) {
handleNumber = index;
closest = pos;
}
});
return handleNumber;
}
// Fire 'end' when a mouse or pen leaves the document.
function documentLeave ( event, data ) {
if ( event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null ){
eventEnd (event, data);
}
}
// Handle movement on document for handle and range drag.
function eventMove ( event, data ) {
// Fix #498
// Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty).
// https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero
// IE9 has .buttons and .which zero on mousemove.
// Firefox breaks the spec MDN defines.
if ( navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0 ) {
return eventEnd(event, data);
}
// Check if we are moving up or down
var movement = (options.dir ? -1 : 1) * (event.calcPoint - data.startCalcPoint);
// Convert the movement into a percentage of the slider width/height
var proposal = (movement * 100) / data.baseSize;
moveHandles(movement > 0, proposal, data.locations, data.handleNumbers);
}
// Unbind move events on document, call callbacks.
function eventEnd ( event, data ) {
// The handle is no longer active, so remove the class.
if ( data.handle ) {
removeClass(data.handle, options.cssClasses.active);
scope_ActiveHandlesCount -= 1;
}
// Unbind the move and end events, which are added on 'start'.
data.listeners.forEach(function( c ) {
scope_DocumentElement.removeEventListener(c[0], c[1]);
});
if ( scope_ActiveHandlesCount === 0 ) {
// Remove dragging class.
removeClass(scope_Target, options.cssClasses.drag);
setZindex();
// Remove cursor styles and text-selection events bound to the body.
if ( event.cursor ) {
scope_Body.style.cursor = '';
scope_Body.removeEventListener('selectstart', preventDefault);
}
}
data.handleNumbers.forEach(function(handleNumber){
fireEvent('change', handleNumber);
fireEvent('set', handleNumber);
fireEvent('end', handleNumber);
});
}
// Bind move events on document.
function eventStart ( event, data ) {
var handle;
if ( data.handleNumbers.length === 1 ) {
var handleOrigin = scope_Handles[data.handleNumbers[0]];
// Ignore 'disabled' handles
if ( handleOrigin.hasAttribute('disabled') ) {
return false;
}
handle = handleOrigin.children[0];
scope_ActiveHandlesCount += 1;
// Mark the handle as 'active' so it can be styled.
addClass(handle, options.cssClasses.active);
}
// A drag should never propagate up to the 'tap' event.
event.stopPropagation();
// Record the event listeners.
var listeners = [];
// Attach the move and end events.
var moveEvent = attachEvent(actions.move, scope_DocumentElement, eventMove, {
// The event target has changed so we need to propagate the original one so that we keep
// relying on it to extract target touches.
target: event.target,
handle: handle,
listeners: listeners,
startCalcPoint: event.calcPoint,
baseSize: baseSize(),
pageOffset: event.pageOffset,
handleNumbers: data.handleNumbers,
buttonsProperty: event.buttons,
locations: scope_Locations.slice()
});
var endEvent = attachEvent(actions.end, scope_DocumentElement, eventEnd, {
target: event.target,
handle: handle,
listeners: listeners,
doNotReject: true,
handleNumbers: data.handleNumbers
});
var outEvent = attachEvent("mouseout", scope_DocumentElement, documentLeave, {
target: event.target,
handle: handle,
listeners: listeners,
doNotReject: true,
handleNumbers: data.handleNumbers
});
// We want to make sure we pushed the listeners in the listener list rather than creating
// a new one as it has already been passed to the event handlers.
listeners.push.apply(listeners, moveEvent.concat(endEvent, outEvent));
// Text selection isn't an issue on touch devices,
// so adding cursor styles can be skipped.
if ( event.cursor ) {
// Prevent the 'I' cursor and extend the range-drag cursor.
scope_Body.style.cursor = getComputedStyle(event.target).cursor;
// Mark the target with a dragging state.
if ( scope_Handles.length > 1 ) {
addClass(scope_Target, options.cssClasses.drag);
}
// Prevent text selection when dragging the handles.
// In noUiSlider <= 9.2.0, this was handled by calling preventDefault on mouse/touch start/move,
// which is scroll blocking. The selectstart event is supported by FireFox starting from version 52,
// meaning the only holdout is iOS Safari. This doesn't matter: text selection isn't triggered there.
// The 'cursor' flag is false.
// See: http://caniuse.com/#search=selectstart
scope_Body.addEventListener('selectstart', preventDefault, false);
}
data.handleNumbers.forEach(function(handleNumber){
fireEvent('start', handleNumber);
});
}
// Move closest handle to tapped location.
function eventTap ( event ) {
// The tap event shouldn't propagate up
event.stopPropagation();
var proposal = calcPointToPercentage(event.calcPoint);
var handleNumber = getClosestHandle(proposal);
// Tackle the case that all handles are 'disabled'.
if ( handleNumber === false ) {
return false;
}
// Flag the slider as it is now in a transitional state.
// Transition takes a configurable amount of ms (default 300). Re-enable the slider after that.
if ( !options.events.snap ) {
addClassFor(scope_Target, options.cssClasses.tap, options.animationDuration);
}
setHandle(handleNumber, proposal, true, true);
setZindex();
fireEvent('slide', handleNumber, true);
fireEvent('update', handleNumber, true);
fireEvent('change', handleNumber, true);
fireEvent('set', handleNumber, true);
if ( options.events.snap ) {
eventStart(event, { handleNumbers: [handleNumber] });
}
}
// Fires a 'hover' event for a hovered mouse/pen position.
function eventHover ( event ) {
var proposal = calcPointToPercentage(event.calcPoint);
var to = scope_Spectrum.getStep(proposal);
var value = scope_Spectrum.fromStepping(to);
Object.keys(scope_Events).forEach(function( targetEvent ) {
if ( 'hover' === targetEvent.split('.')[0] ) {
scope_Events[targetEvent].forEach(function( callback ) {
callback.call( scope_Self, value );
});
}
});
}
// Attach events to several slider parts.
function bindSliderEvents ( behaviour ) {
// Attach the standard drag event to the handles.
if ( !behaviour.fixed ) {
scope_Handles.forEach(function( handle, index ){
// These events are only bound to the visual handle
// element, not the 'real' origin element.
attachEvent ( actions.start, handle.children[0], eventStart, {
handleNumbers: [index]
});
});
}
// Attach the tap event to the slider base.
if ( behaviour.tap ) {
attachEvent (actions.start, scope_Base, eventTap, {});
}
// Fire hover events
if ( behaviour.hover ) {
attachEvent (actions.move, scope_Base, eventHover, { hover: true });
}
// Make the range draggable.
if ( behaviour.drag ){
scope_Connects.forEach(function( connect, index ){
if ( connect === false || index === 0 || index === scope_Connects.length - 1 ) {
return;
}
var handleBefore = scope_Handles[index - 1];
var handleAfter = scope_Handles[index];
var eventHolders = [connect];
addClass(connect, options.cssClasses.draggable);
// When the range is fixed, the entire range can
// be dragged by the handles. The handle in the first
// origin will propagate the start event upward,
// but it needs to be bound manually on the other.
if ( behaviour.fixed ) {
eventHolders.push(handleBefore.children[0]);
eventHolders.push(handleAfter.children[0]);
}
eventHolders.forEach(function( eventHolder ) {
attachEvent ( actions.start, eventHolder, eventStart, {
handles: [handleBefore, handleAfter],
handleNumbers: [index - 1, index]
});
});
});
}
}
/*! In this file: Slider events (not browser events); */
// Attach an event to this slider, possibly including a namespace
function bindEvent ( namespacedEvent, callback ) {
scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || [];
scope_Events[namespacedEvent].push(callback);
// If the event bound is 'update,' fire it immediately for all handles.
if ( namespacedEvent.split('.')[0] === 'update' ) {
scope_Handles.forEach(function(a, index){
fireEvent('update', index);
});
}
}
// Undo attachment of event
function removeEvent ( namespacedEvent ) {
var event = namespacedEvent && namespacedEvent.split('.')[0];
var namespace = event && namespacedEvent.substring(event.length);
Object.keys(scope_Events).forEach(function( bind ){
var tEvent = bind.split('.')[0];
var tNamespace = bind.substring(tEvent.length);
if ( (!event || event === tEvent) && (!namespace || namespace === tNamespace) ) {
delete scope_Events[bind];
}
});
}
// External event handling
function fireEvent ( eventName, handleNumber, tap ) {
Object.keys(scope_Events).forEach(function( targetEvent ) {
var eventType = targetEvent.split('.')[0];
if ( eventName === eventType ) {
scope_Events[targetEvent].forEach(function( callback ) {
callback.call(
// Use the slider public API as the scope ('this')
scope_Self,
// Return values as array, so arg_1[arg_2] is always valid.
scope_Values.map(options.format.to),
// Handle index, 0 or 1
handleNumber,
// Unformatted slider values
scope_Values.slice(),
// Event is fired by tap, true or false
tap || false,
// Left offset of the handle, in relation to the slider
scope_Locations.slice()
);
});
}
});
}
/*! In this file: Mechanics for slider operation */
function toPct ( pct ) {
return pct + '%';
}
// Split out the handle positioning logic so the Move event can use it, too
function checkHandlePosition ( reference, handleNumber, to, lookBackward, lookForward, getValue ) {
// For sliders with multiple handles, limit movement to the other handle.
// Apply the margin option by adding it to the handle positions.
if ( scope_Handles.length > 1 ) {
if ( lookBackward && handleNumber > 0 ) {
to = Math.max(to, reference[handleNumber - 1] + options.margin);
}
if ( lookForward && handleNumber < scope_Handles.length - 1 ) {
to = Math.min(to, reference[handleNumber + 1] - options.margin);
}
}
// The limit option has the opposite effect, limiting handles to a
// maximum distance from another. Limit must be > 0, as otherwise
// handles would be unmoveable.
if ( scope_Handles.length > 1 && options.limit ) {
if ( lookBackward && handleNumber > 0 ) {
to = Math.min(to, reference[handleNumber - 1] + options.limit);
}
if ( lookForward && handleNumber < scope_Handles.length - 1 ) {
to = Math.max(to, reference[handleNumber + 1] - options.limit);
}
}
// The padding option keeps the handles a certain distance from the
// edges of the slider. Padding must be > 0.
if ( options.padding ) {
if ( handleNumber === 0 ) {
to = Math.max(to, options.padding[0]);
}
if ( handleNumber === scope_Handles.length - 1 ) {
to = Math.min(to, 100 - options.padding[1]);
}
}
to = scope_Spectrum.getStep(to);
// Limit percentage to the 0 - 100 range
to = limit(to);
// Return false if handle can't move
if ( to === reference[handleNumber] && !getValue ) {
return false;
}
return to;
}
// Uses slider orientation to create CSS rules. a = base value;
function inRuleOrder ( v, a ) {
var o = options.ort;
return (o?a:v) + ', ' + (o?v:a);
}
// Moves handle(s) by a percentage
// (bool, % to move, [% where handle started, ...], [index in scope_Handles, ...])
function moveHandles ( upward, proposal, locations, handleNumbers ) {
var proposals = locations.slice();
var b = [!upward, upward];
var f = [upward, !upward];
// Copy handleNumbers so we don't change the dataset
handleNumbers = handleNumbers.slice();
// Check to see which handle is 'leading'.
// If that one can't move the second can't either.
if ( upward ) {
handleNumbers.reverse();
}
// Step 1: get the maximum percentage that any of the handles can move
if ( handleNumbers.length > 1 ) {
handleNumbers.forEach(function(handleNumber, o) {
var to = checkHandlePosition(proposals, handleNumber, proposals[handleNumber] + proposal, b[o], f[o], false);
// Stop if one of the handles can't move.
if ( to === false ) {
proposal = 0;
} else {
proposal = to - proposals[handleNumber];
proposals[handleNumber] = to;
}
});
}
// If using one handle, check backward AND forward
else {
b = f = [true];
}
var state = false;
// Step 2: Try to set the handles with the found percentage
handleNumbers.forEach(function(handleNumber, o) {
state = setHandle(handleNumber, locations[handleNumber] + proposal, b[o], f[o]) || state;
});
// Step 3: If a handle moved, fire events
if ( state ) {
handleNumbers.forEach(function(handleNumber){
fireEvent('update', handleNumber);
fireEvent('slide', handleNumber);
});
}
}
// Takes a base value and an offset. This offset is used for the connect bar size.
// In the initial design for this feature, the origin element was 1% wide.
// Unfortunately, a rounding bug in Chrome makes it impossible to implement this feature
// in this manner: https://bugs.chromium.org/p/chromium/issues/detail?id=798223
function transformDirection ( a, b ) {
return options.dir ? 100 - a - b : a;
}
// Updates scope_Locations and scope_Values, updates visual state
function updateHandlePosition ( handleNumber, to ) {
// Update locations.
scope_Locations[handleNumber] = to;
// Convert the value to the slider stepping/range.
scope_Values[handleNumber] = scope_Spectrum.fromStepping(to);
var rule = 'translate(' + inRuleOrder(toPct(transformDirection(to, 0) - scope_DirOffset), '0') + ')';
scope_Handles[handleNumber].style[options.transformRule] = rule;
updateConnect(handleNumber);
updateConnect(handleNumber + 1);
}
// Handles before the slider middle are stacked later = higher,
// Handles after the middle later is lower
// [[7] [8] .......... | .......... [5] [4]
function setZindex ( ) {
scope_HandleNumbers.forEach(function(handleNumber){
var dir = (scope_Locations[handleNumber] > 50 ? -1 : 1);
var zIndex = 3 + (scope_Handles.length + (dir * handleNumber));
scope_Handles[handleNumber].style.zIndex = zIndex;
});
}
// Test suggested values and apply margin, step.
function setHandle ( handleNumber, to, lookBackward, lookForward ) {
to = checkHandlePosition(scope_Locations, handleNumber, to, lookBackward, lookForward, false);
if ( to === false ) {
return false;
}
updateHandlePosition(handleNumber, to);
return true;
}
// Updates style attribute for connect nodes
function updateConnect ( index ) {
// Skip connects set to false
if ( !scope_Connects[index] ) {
return;
}
var l = 0;
var h = 100;
if ( index !== 0 ) {
l = scope_Locations[index - 1];
}
if ( index !== scope_Connects.length - 1 ) {
h = scope_Locations[index];
}
// We use two rules:
// 'translate' to change the left/top offset;
// 'scale' to change the width of the element;
// As the element has a width of 100%, a translation of 100% is equal to 100% of the parent (.noUi-base)
var connectWidth = h - l;
var translateRule = 'translate(' + inRuleOrder(toPct(transformDirection(l, connectWidth)), '0') + ')';
var scaleRule = 'scale(' + inRuleOrder(connectWidth / 100, '1') + ')';
scope_Connects[index].style[options.transformRule] = translateRule + ' ' + scaleRule;
}
/*! In this file: All methods eventually exposed in slider.noUiSlider... */
// Parses value passed to .set method. Returns current value if not parse-able.
function resolveToValue ( to, handleNumber ) {
// Setting with null indicates an 'ignore'.
// Inputting 'false' is invalid.
if ( to === null || to === false || to === undefined ) {
return scope_Locations[handleNumber];
}
// If a formatted number was passed, attempt to decode it.
if ( typeof to === 'number' ) {
to = String(to);
}
to = options.format.from(to);
to = scope_Spectrum.toStepping(to);
// If parsing the number failed, use the current value.
if ( to === false || isNaN(to) ) {
return scope_Locations[handleNumber];
}
return to;
}
// Set the slider value.
function valueSet ( input, fireSetEvent ) {
var values = asArray(input);
var isInit = scope_Locations[0] === undefined;
// Event fires by default
fireSetEvent = (fireSetEvent === undefined ? true : !!fireSetEvent);
// Animation is optional.
// Make sure the initial values were set before using animated placement.
if ( options.animate && !isInit ) {
addClassFor(scope_Target, options.cssClasses.tap, options.animationDuration);
}
// First pass, without lookAhead but with lookBackward. Values are set from left to right.
scope_HandleNumbers.forEach(function(handleNumber){
setHandle(handleNumber, resolveToValue(values[handleNumber], handleNumber), true, false);
});
// Second pass. Now that all base values are set, apply constraints
scope_HandleNumbers.forEach(function(handleNumber){
setHandle(handleNumber, scope_Locations[handleNumber], true, true);
});
setZindex();
scope_HandleNumbers.forEach(function(handleNumber){
fireEvent('update', handleNumber);
// Fire the event only for handles that received a new value, as per #579
if ( values[handleNumber] !== null && fireSetEvent ) {
fireEvent('set', handleNumber);
}
});
}
// Reset slider to initial values
function valueReset ( fireSetEvent ) {
valueSet(options.start, fireSetEvent);
}
// Get the slider value.
function valueGet ( ) {
var values = scope_Values.map(options.format.to);
// If only one handle is used, return a single value.
if ( values.length === 1 ){
return values[0];
}
return values;
}
// Removes classes from the root and empties it.
function destroy ( ) {
for ( var key in options.cssClasses ) {
if ( !options.cssClasses.hasOwnProperty(key) ) { continue; }
removeClass(scope_Target, options.cssClasses[key]);
}
while (scope_Target.firstChild) {
scope_Target.removeChild(scope_Target.firstChild);
}
delete scope_Target.noUiSlider;
}
// Get the current step size for the slider.
function getCurrentStep ( ) {
// Check all locations, map them to their stepping point.
// Get the step point, then find it in the input list.
return scope_Locations.map(function( location, index ){
var nearbySteps = scope_Spectrum.getNearbySteps( location );
var value = scope_Values[index];
var increment = nearbySteps.thisStep.step;
var decrement = null;
// If the next value in this step moves into the next step,
// the increment is the start of the next step - the current value
if ( increment !== false ) {
if ( value + increment > nearbySteps.stepAfter.startValue ) {
increment = nearbySteps.stepAfter.startValue - value;
}
}
// If the value is beyond the starting point
if ( value > nearbySteps.thisStep.startValue ) {
decrement = nearbySteps.thisStep.step;
}
else if ( nearbySteps.stepBefore.step === false ) {
decrement = false;
}
// If a handle is at the start of a step, it always steps back into the previous step first
else {
decrement = value - nearbySteps.stepBefore.highestStep;
}
// Now, if at the slider edges, there is not in/decrement
if ( location === 100 ) {
increment = null;
}
else if ( location === 0 ) {
decrement = null;
}
// As per #391, the comparison for the decrement step can have some rounding issues.
var stepDecimals = scope_Spectrum.countStepDecimals();
// Round per #391
if ( increment !== null && increment !== false ) {
increment = Number(increment.toFixed(stepDecimals));
}
if ( decrement !== null && decrement !== false ) {
decrement = Number(decrement.toFixed(stepDecimals));
}
return [decrement, increment];
});
}
// Updateable: margin, limit, padding, step, range, animate, snap
function updateOptions ( optionsToUpdate, fireSetEvent ) {
// Spectrum is created using the range, snap, direction and step options.
// 'snap' and 'step' can be updated.
// If 'snap' and 'step' are not passed, they should remain unchanged.
var v = valueGet();
var updateAble = ['margin', 'limit', 'padding', 'range', 'animate', 'snap', 'step', 'format'];
// Only change options that we're actually passed to update.
updateAble.forEach(function(name){
if ( optionsToUpdate[name] !== undefined ) {
originalOptions[name] = optionsToUpdate[name];
}
});
var newOptions = testOptions(originalOptions);
// Load new options into the slider state
updateAble.forEach(function(name){
if ( optionsToUpdate[name] !== undefined ) {
options[name] = newOptions[name];
}
});
scope_Spectrum = newOptions.spectrum;
// Limit, margin and padding depend on the spectrum but are stored outside of it. (#677)
options.margin = newOptions.margin;
options.limit = newOptions.limit;
options.padding = newOptions.padding;
// Update pips, removes existing.
if ( options.pips ) {
pips(options.pips);
}
// Invalidate the current positioning so valueSet forces an update.
scope_Locations = [];
valueSet(optionsToUpdate.start || v, fireSetEvent);
}
/*! In this file: Calls to functions. All other scope_ files define functions only; */
// Create the base element, initialize HTML and set classes.
// Add handles and connect elements.
addSlider(scope_Target);
addElements(options.connect, scope_Base);
// Attach user events.
bindSliderEvents(options.events);
// Use the public value method to set the start values.
valueSet(options.start);
scope_Self = {
destroy: destroy,
steps: getCurrentStep,
on: bindEvent,
off: removeEvent,
get: valueGet,
set: valueSet,
reset: valueReset,
// Exposed for unit testing, don't use this in your application.
__moveHandles: function(a, b, c) { moveHandles(a, b, scope_Locations, c); },
options: originalOptions, // Issue #600, #678
updateOptions: updateOptions,
target: scope_Target, // Issue #597
removePips: removePips,
pips: pips // Issue #594
};
if ( options.pips ) {
pips(options.pips);
}
if ( options.tooltips ) {
tooltips();
}
aria();
return scope_Self;
}
// Run the standard initializer
function initialize ( target, originalOptions ) {
if ( !target || !target.nodeName ) {
throw new Error("noUiSlider (" + VERSION + "): create requires a single element, got: " + target);
}
// Throw an error if the slider was already initialized.
if ( target.noUiSlider ) {
throw new Error("noUiSlider (" + VERSION + "): Slider was already initialized.");
}
// Test the options and create the slider environment;
var options = testOptions( originalOptions, target );
var api = scope( target, options, originalOptions );
target.noUiSlider = api;
return api;
}
// Use an object instead of a function for future expandability;
return {
version: VERSION,
create: initialize
};
}));
/*!
* @fileOverview TouchSwipe - jQuery Plugin
* @version 1.6.18
*
* @author Matt Bryson http://www.github.com/mattbryson
* @see https://github.com/mattbryson/TouchSwipe-Jquery-Plugin
* @see http://labs.rampinteractive.co.uk/touchSwipe/
* @see http://plugins.jquery.com/project/touchSwipe
* @license
* Copyright (c) 2010-2015 Matt Bryson
* Dual licensed under the MIT or GPL Version 2 licenses.
*
*/
/*
*
* Changelog
* $Date: 2010-12-12 (Wed, 12 Dec 2010) $
* $version: 1.0.0
* $version: 1.0.1 - removed multibyte comments
*
* $Date: 2011-21-02 (Mon, 21 Feb 2011) $
* $version: 1.1.0 - added allowPageScroll property to allow swiping and scrolling of page
* - changed handler signatures so one handler can be used for multiple events
* $Date: 2011-23-02 (Wed, 23 Feb 2011) $
* $version: 1.2.0 - added click handler. This is fired if the user simply clicks and does not swipe. The event object and click target are passed to handler.
* - If you use the http://code.google.com/p/jquery-ui-for-ipad-and-iphone/ plugin, you can also assign jQuery mouse events to children of a touchSwipe object.
* $version: 1.2.1 - removed console log!
*
* $version: 1.2.2 - Fixed bug where scope was not preserved in callback methods.
*
* $Date: 2011-28-04 (Thurs, 28 April 2011) $
* $version: 1.2.4 - Changed licence terms to be MIT or GPL inline with jQuery. Added check for support of touch events to stop non compatible browsers erroring.
*
* $Date: 2011-27-09 (Tues, 27 September 2011) $
* $version: 1.2.5 - Added support for testing swipes with mouse on desktop browser (thanks to https://github.com/joelhy)
*
* $Date: 2012-14-05 (Mon, 14 May 2012) $
* $version: 1.2.6 - Added timeThreshold between start and end touch, so user can ignore slow swipes (thanks to Mark Chase). Default is null, all swipes are detected
*
* $Date: 2012-05-06 (Tues, 05 June 2012) $
* $version: 1.2.7 - Changed time threshold to have null default for backwards compatibility. Added duration param passed back in events, and refactored how time is handled.
*
* $Date: 2012-05-06 (Tues, 05 June 2012) $
* $version: 1.2.8 - Added the possibility to return a value like null or false in the trigger callback. In that way we can control when the touch start/move should take effect or not (simply by returning in some cases return null; or return false;) This effects the ontouchstart/ontouchmove event.
*
* $Date: 2012-06-06 (Wed, 06 June 2012) $
* $version: 1.3.0 - Refactored whole plugin to allow for methods to be executed, as well as exposed defaults for user override. Added 'enable', 'disable', and 'destroy' methods
*
* $Date: 2012-05-06 (Fri, 05 June 2012) $
* $version: 1.3.1 - Bug fixes - bind() with false as last argument is no longer supported in jQuery 1.6, also, if you just click, the duration is now returned correctly.
*
* $Date: 2012-29-07 (Sun, 29 July 2012) $
* $version: 1.3.2 - Added fallbackToMouseEvents option to NOT capture mouse events on non touch devices.
* - Added "all" fingers value to the fingers property, so any combination of fingers triggers the swipe, allowing event handlers to check the finger count
*
* $Date: 2012-09-08 (Thurs, 9 Aug 2012) $
* $version: 1.3.3 - Code tidy prep for min version
*
* $Date: 2012-04-10 (wed, 4 Oct 2012) $
* $version: 1.4.0 - Added pinch support, pinchIn and pinchOut
*
* $Date: 2012-11-10 (Thurs, 11 Oct 2012) $
* $version: 1.5.0 - Added excludedElements, a jquery selector that specifies child elements that do NOT trigger swipes. By default, this is .noSwipe
*
* $Date: 2012-22-10 (Mon, 22 Oct 2012) $
* $version: 1.5.1 - Fixed bug with jQuery 1.8 and trailing comma in excludedElements
* - Fixed bug with IE and eventPreventDefault()
* $Date: 2013-01-12 (Fri, 12 Jan 2013) $
* $version: 1.6.0 - Fixed bugs with pinching, mainly when both pinch and swipe enabled, as well as adding time threshold for multifinger gestures, so releasing one finger beofre the other doesnt trigger as single finger gesture.
* - made the demo site all static local HTML pages so they can be run locally by a developer
* - added jsDoc comments and added documentation for the plugin
* - code tidy
* - added triggerOnTouchLeave property that will end the event when the user swipes off the element.
* $Date: 2013-03-23 (Sat, 23 Mar 2013) $
* $version: 1.6.1 - Added support for ie8 touch events
* $version: 1.6.2 - Added support for events binding with on / off / bind in jQ for all callback names.
* - Deprecated the 'click' handler in favour of tap.
* - added cancelThreshold property
* - added option method to update init options at runtime
* $version 1.6.3 - added doubletap, longtap events and longTapThreshold, doubleTapThreshold property
*
* $Date: 2013-04-04 (Thurs, 04 April 2013) $
* $version 1.6.4 - Fixed bug with cancelThreshold introduced in 1.6.3, where swipe status no longer fired start event, and stopped once swiping back.
*
* $Date: 2013-08-24 (Sat, 24 Aug 2013) $
* $version 1.6.5 - Merged a few pull requests fixing various bugs, added AMD support.
*
* $Date: 2014-06-04 (Wed, 04 June 2014) $
* $version 1.6.6 - Merge of pull requests.
* - IE10 touch support
* - Only prevent default event handling on valid swipe
* - Separate license/changelog comment
* - Detect if the swipe is valid at the end of the touch event.
* - Pass fingerdata to event handlers.
* - Add 'hold' gesture
* - Be more tolerant about the tap distance
* - Typos and minor fixes
*
* $Date: 2015-22-01 (Thurs, 22 Jan 2015) $
* $version 1.6.7 - Added patch from https://github.com/mattbryson/TouchSwipe-Jquery-Plugin/issues/206 to fix memory leak
*
* $Date: 2015-2-2 (Mon, 2 Feb 2015) $
* $version 1.6.8 - Added preventDefaultEvents option to proxy events regardless.
* - Fixed issue with swipe and pinch not triggering at the same time
*
* $Date: 2015-9-6 (Tues, 9 June 2015) $
* $version 1.6.9 - Added PR from jdalton/hybrid to fix pointer events
* - Added scrolling demo
* - Added version property to plugin
*
* $Date: 2015-1-10 (Wed, 1 October 2015) $
* $version 1.6.10 - Added PR from beatspace to fix tap events
* $version 1.6.11 - Added PRs from indri-indri ( Doc tidyup), kkirsche ( Bower tidy up ), UziTech (preventDefaultEvents fixes )
* - Allowed setting multiple options via .swipe("options", options_hash) and more simply .swipe(options_hash) or exisitng instances
* $version 1.6.12 - Fixed bug with multi finger releases above 2 not triggering events
*
* $Date: 2015-12-18 (Fri, 18 December 2015) $
* $version 1.6.13 - Added PRs
* - Fixed #267 allowPageScroll not working correctly
* $version 1.6.14 - Fixed #220 / #248 doubletap not firing with swipes, #223 commonJS compatible
* $version 1.6.15 - More bug fixes
*
* $Date: 2016-04-29 (Fri, 29 April 2016) $
* $version 1.6.16 - Swipes with 0 distance now allow default events to trigger. So tapping any form elements or A tags will allow default interaction, but swiping will trigger a swipe.
* Removed the a, input, select etc from the excluded Children list as the 0 distance tap solves that issue.
* $Date: 2016-05-19 (Fri, 29 April 2016) $
* $version 1.6.17 - Fixed context issue when calling instance methods via $("selector").swipe("method");
* $version 1.6.18 - now honors fallbackToMouseEvents=false for MS Pointer events when a Mouse is used.
*
* $Date: 2018-09-17 (Mon, 17 September 2018) $
* $version 1.6.19 - replaced jQuery bind with on, replaced deprecated `navigator.pointerEvents` with `window.PointerEvents`
*/
/**
* See (http://jquery.com/).
* @name $
* @class
* See the jQuery Library (http://jquery.com/) for full details. This just
* documents the function and classes that are added to jQuery by this plug-in.
*/
/**
* See (http://jquery.com/)
* @name fn
* @class
* See the jQuery Library (http://jquery.com/) for full details. This just
* documents the function and classes that are added to jQuery by this plug-in.
* @memberOf $
*/
(function(factory) {
if (typeof define === 'function' && define.amd && define.amd.jQuery) {
// AMD. Register as anonymous module.
define(['jquery'], factory);
} else if (typeof module !== 'undefined' && module.exports) {
// CommonJS Module
factory(require("jquery"));
} else {
// Browser globals.
factory(jQuery);
}
}(function($) {
"use strict";
//Constants
var VERSION = "1.6.18",
LEFT = "left",
RIGHT = "right",
UP = "up",
DOWN = "down",
IN = "in",
OUT = "out",
NONE = "none",
AUTO = "auto",
SWIPE = "swipe",
PINCH = "pinch",
TAP = "tap",
DOUBLE_TAP = "doubletap",
LONG_TAP = "longtap",
HOLD = "hold",
HORIZONTAL = "horizontal",
VERTICAL = "vertical",
ALL_FINGERS = "all",
DOUBLE_TAP_THRESHOLD = 10,
PHASE_START = "start",
PHASE_MOVE = "move",
PHASE_END = "end",
PHASE_CANCEL = "cancel",
SUPPORTS_TOUCH = 'ontouchstart' in window,
SUPPORTS_POINTER_IE10 = window.navigator.msPointerEnabled && !window.PointerEvent && !SUPPORTS_TOUCH,
SUPPORTS_POINTER = (window.PointerEvent || window.navigator.msPointerEnabled) && !SUPPORTS_TOUCH,
PLUGIN_NS = 'TouchSwipe';
/**
* The default configuration, and available options to configure touch swipe with.
* You can set the default values by updating any of the properties prior to instantiation.
* @name $.fn.swipe.defaults
* @namespace
* @property {int} [fingers=1] The number of fingers to detect in a swipe. Any swipes that do not meet this requirement will NOT trigger swipe handlers.
* @property {int} [threshold=75] The number of pixels that the user must move their finger by before it is considered a swipe.
* @property {int} [cancelThreshold=null] The number of pixels that the user must move their finger back from the original swipe direction to cancel the gesture.
* @property {int} [pinchThreshold=20] The number of pixels that the user must pinch their finger by before it is considered a pinch.
* @property {int} [maxTimeThreshold=null] Time, in milliseconds, between touchStart and touchEnd must NOT exceed in order to be considered a swipe.
* @property {int} [fingerReleaseThreshold=250] Time in milliseconds between releasing multiple fingers. If 2 fingers are down, and are released one after the other, if they are within this threshold, it counts as a simultaneous release.
* @property {int} [longTapThreshold=500] Time in milliseconds between tap and release for a long tap
* @property {int} [doubleTapThreshold=200] Time in milliseconds between 2 taps to count as a double tap
* @property {function} [swipe=null] A handler to catch all swipes. See {@link $.fn.swipe#event:swipe}
* @property {function} [swipeLeft=null] A handler that is triggered for "left" swipes. See {@link $.fn.swipe#event:swipeLeft}
* @property {function} [swipeRight=null] A handler that is triggered for "right" swipes. See {@link $.fn.swipe#event:swipeRight}
* @property {function} [swipeUp=null] A handler that is triggered for "up" swipes. See {@link $.fn.swipe#event:swipeUp}
* @property {function} [swipeDown=null] A handler that is triggered for "down" swipes. See {@link $.fn.swipe#event:swipeDown}
* @property {function} [swipeStatus=null] A handler triggered for every phase of the swipe. See {@link $.fn.swipe#event:swipeStatus}
* @property {function} [pinchIn=null] A handler triggered for pinch in events. See {@link $.fn.swipe#event:pinchIn}
* @property {function} [pinchOut=null] A handler triggered for pinch out events. See {@link $.fn.swipe#event:pinchOut}
* @property {function} [pinchStatus=null] A handler triggered for every phase of a pinch. See {@link $.fn.swipe#event:pinchStatus}
* @property {function} [tap=null] A handler triggered when a user just taps on the item, rather than swipes it. If they do not move, tap is triggered, if they do move, it is not.
* @property {function} [doubleTap=null] A handler triggered when a user double taps on the item. The delay between taps can be set with the doubleTapThreshold property. See {@link $.fn.swipe.defaults#doubleTapThreshold}
* @property {function} [longTap=null] A handler triggered when a user long taps on the item. The delay between start and end can be set with the longTapThreshold property. See {@link $.fn.swipe.defaults#longTapThreshold}
* @property (function) [hold=null] A handler triggered when a user reaches longTapThreshold on the item. See {@link $.fn.swipe.defaults#longTapThreshold}
* @property {boolean} [triggerOnTouchEnd=true] If true, the swipe events are triggered when the touch end event is received (user releases finger). If false, it will be triggered on reaching the threshold, and then cancel the touch event automatically.
* @property {boolean} [triggerOnTouchLeave=false] If true, then when the user leaves the swipe object, the swipe will end and trigger appropriate handlers.
* @property {string|undefined} [allowPageScroll='auto'] How the browser handles page scrolls when the user is swiping on a touchSwipe object. See {@link $.fn.swipe.pageScroll}.
"auto"
: all undefined swipes will cause the page to scroll in that direction.
"none"
: the page will not scroll when user swipes.
"horizontal"
: will force page to scroll on horizontal swipes.
"vertical"
: will force page to scroll on vertical swipes.
* @property {boolean} [fallbackToMouseEvents=true] If true mouse events are used when run on a non touch device, false will stop swipes being triggered by mouse events on non touch devices.
* @property {string} [excludedElements=".noSwipe"] A jquery selector that specifies child elements that do NOT trigger swipes. By default this excludes elements with the class .noSwipe .
* @property {boolean} [preventDefaultEvents=true] by default default events are cancelled, so the page doesn't move. You can disable this so both native events fire as well as your handlers.
*/
var defaults = {
fingers: 1,
threshold: 75,
cancelThreshold: null,
pinchThreshold: 20,
maxTimeThreshold: null,
fingerReleaseThreshold: 250,
longTapThreshold: 500,
doubleTapThreshold: 200,
swipe: null,
swipeLeft: null,
swipeRight: null,
swipeUp: null,
swipeDown: null,
swipeStatus: null,
pinchIn: null,
pinchOut: null,
pinchStatus: null,
click: null, //Deprecated since 1.6.2
tap: null,
doubleTap: null,
longTap: null,
hold: null,
triggerOnTouchEnd: true,
triggerOnTouchLeave: false,
allowPageScroll: "auto",
fallbackToMouseEvents: true,
excludedElements: ".noSwipe",
preventDefaultEvents: true
};
/**
* Applies TouchSwipe behaviour to one or more jQuery objects.
* The TouchSwipe plugin can be instantiated via this method, or methods within
* TouchSwipe can be executed via this method as per jQuery plugin architecture.
* An existing plugin can have its options changed simply by re calling .swipe(options)
* @see TouchSwipe
* @class
* @param {Mixed} method If the current DOMNode is a TouchSwipe object, and method
is a TouchSwipe method, then
* the method
is executed, and any following arguments are passed to the TouchSwipe method.
* If method
is an object, then the TouchSwipe class is instantiated on the current DOMNode, passing the
* configuration properties defined in the object. See TouchSwipe
*
*/
$.fn.swipe = function(method) {
var $this = $(this),
plugin = $this.data(PLUGIN_NS);
//Check if we are already instantiated and trying to execute a method
if (plugin && typeof method === 'string') {
if (plugin[method]) {
return plugin[method].apply(plugin, Array.prototype.slice.call(arguments, 1));
} else {
$.error('Method ' + method + ' does not exist on jQuery.swipe');
}
}
//Else update existing plugin with new options hash
else if (plugin && typeof method === 'object') {
plugin['option'].apply(plugin, arguments);
}
//Else not instantiated and trying to pass init object (or nothing)
else if (!plugin && (typeof method === 'object' || !method)) {
return init.apply(this, arguments);
}
return $this;
};
/**
* The version of the plugin
* @readonly
*/
$.fn.swipe.version = VERSION;
//Expose our defaults so a user could override the plugin defaults
$.fn.swipe.defaults = defaults;
/**
* The phases that a touch event goes through. The phase
is passed to the event handlers.
* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
* @namespace
* @readonly
* @property {string} PHASE_START Constant indicating the start phase of the touch event. Value is "start"
.
* @property {string} PHASE_MOVE Constant indicating the move phase of the touch event. Value is "move"
.
* @property {string} PHASE_END Constant indicating the end phase of the touch event. Value is "end"
.
* @property {string} PHASE_CANCEL Constant indicating the cancel phase of the touch event. Value is "cancel"
.
*/
$.fn.swipe.phases = {
PHASE_START: PHASE_START,
PHASE_MOVE: PHASE_MOVE,
PHASE_END: PHASE_END,
PHASE_CANCEL: PHASE_CANCEL
};
/**
* The direction constants that are passed to the event handlers.
* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
* @namespace
* @readonly
* @property {string} LEFT Constant indicating the left direction. Value is "left"
.
* @property {string} RIGHT Constant indicating the right direction. Value is "right"
.
* @property {string} UP Constant indicating the up direction. Value is "up"
.
* @property {string} DOWN Constant indicating the down direction. Value is "cancel"
.
* @property {string} IN Constant indicating the in direction. Value is "in"
.
* @property {string} OUT Constant indicating the out direction. Value is "out"
.
*/
$.fn.swipe.directions = {
LEFT: LEFT,
RIGHT: RIGHT,
UP: UP,
DOWN: DOWN,
IN: IN,
OUT: OUT
};
/**
* The page scroll constants that can be used to set the value of allowPageScroll
option
* These properties are read only
* @namespace
* @readonly
* @see $.fn.swipe.defaults#allowPageScroll
* @property {string} NONE Constant indicating no page scrolling is allowed. Value is "none"
.
* @property {string} HORIZONTAL Constant indicating horizontal page scrolling is allowed. Value is "horizontal"
.
* @property {string} VERTICAL Constant indicating vertical page scrolling is allowed. Value is "vertical"
.
* @property {string} AUTO Constant indicating either horizontal or vertical will be allowed, depending on the swipe handlers registered. Value is "auto"
.
*/
$.fn.swipe.pageScroll = {
NONE: NONE,
HORIZONTAL: HORIZONTAL,
VERTICAL: VERTICAL,
AUTO: AUTO
};
/**
* Constants representing the number of fingers used in a swipe. These are used to set both the value of fingers
in the
* options object, as well as the value of the fingers
event property.
* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
* @namespace
* @readonly
* @see $.fn.swipe.defaults#fingers
* @property {string} ONE Constant indicating 1 finger is to be detected / was detected. Value is 1
.
* @property {string} TWO Constant indicating 2 fingers are to be detected / were detected. Value is 2
.
* @property {string} THREE Constant indicating 3 finger are to be detected / were detected. Value is 3
.
* @property {string} FOUR Constant indicating 4 finger are to be detected / were detected. Not all devices support this. Value is 4
.
* @property {string} FIVE Constant indicating 5 finger are to be detected / were detected. Not all devices support this. Value is 5
.
* @property {string} ALL Constant indicating any combination of finger are to be detected. Value is "all"
.
*/
$.fn.swipe.fingers = {
ONE: 1,
TWO: 2,
THREE: 3,
FOUR: 4,
FIVE: 5,
ALL: ALL_FINGERS
};
/**
* Initialise the plugin for each DOM element matched
* This creates a new instance of the main TouchSwipe class for each DOM element, and then
* saves a reference to that instance in the elements data property.
* @internal
*/
function init(options) {
//Prep and extend the options
if (options && (options.allowPageScroll === undefined && (options.swipe !== undefined || options.swipeStatus !== undefined))) {
options.allowPageScroll = NONE;
}
//Check for deprecated options
//Ensure that any old click handlers are assigned to the new tap, unless we have a tap
if (options.click !== undefined && options.tap === undefined) {
options.tap = options.click;
}
if (!options) {
options = {};
}
//pass empty object so we dont modify the defaults
options = $.extend({}, $.fn.swipe.defaults, options);
//For each element instantiate the plugin
return this.each(function() {
var $this = $(this);
//Check we havent already initialised the plugin
var plugin = $this.data(PLUGIN_NS);
if (!plugin) {
plugin = new TouchSwipe(this, options);
$this.data(PLUGIN_NS, plugin);
}
});
}
/**
* Main TouchSwipe Plugin Class.
* Do not use this to construct your TouchSwipe object, use the jQuery plugin method $.fn.swipe(); {@link $.fn.swipe}
* @private
* @name TouchSwipe
* @param {DOMNode} element The HTML DOM object to apply to plugin to
* @param {Object} options The options to configure the plugin with. @link {$.fn.swipe.defaults}
* @see $.fh.swipe.defaults
* @see $.fh.swipe
* @class
*/
function TouchSwipe(element, options) {
//take a local/instacne level copy of the options - should make it this.options really...
var options = $.extend({}, options);
var useTouchEvents = (SUPPORTS_TOUCH || SUPPORTS_POINTER || !options.fallbackToMouseEvents),
START_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerDown' : 'pointerdown') : 'touchstart') : 'mousedown',
MOVE_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerMove' : 'pointermove') : 'touchmove') : 'mousemove',
END_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerUp' : 'pointerup') : 'touchend') : 'mouseup',
LEAVE_EV = useTouchEvents ? (SUPPORTS_POINTER ? 'mouseleave' : null) : 'mouseleave', //we manually detect leave on touch devices, so null event here
CANCEL_EV = (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerCancel' : 'pointercancel') : 'touchcancel');
//touch properties
var distance = 0,
direction = null,
currentDirection = null,
duration = 0,
startTouchesDistance = 0,
endTouchesDistance = 0,
pinchZoom = 1,
pinchDistance = 0,
pinchDirection = 0,
maximumsMap = null;
//jQuery wrapped element for this instance
var $element = $(element);
//Current phase of th touch cycle
var phase = "start";
// the current number of fingers being used.
var fingerCount = 0;
//track mouse points / delta
var fingerData = {};
//track times
var startTime = 0,
endTime = 0,
previousTouchEndTime = 0,
fingerCountAtRelease = 0,
doubleTapStartTime = 0;
//Timeouts
var singleTapTimeout = null,
holdTimeout = null;
// Add gestures to all swipable areas if supported
try {
$element.on(START_EV, touchStart);
$element.on(CANCEL_EV, touchCancel);
} catch (e) {
$.error('events not supported ' + START_EV + ',' + CANCEL_EV + ' on jQuery.swipe');
}
//
//Public methods
//
/**
* re-enables the swipe plugin with the previous configuration
* @function
* @name $.fn.swipe#enable
* @return {DOMNode} The Dom element that was registered with TouchSwipe
* @example $("#element").swipe("enable");
*/
this.enable = function() {
//Incase we are already enabled, clean up...
this.disable();
$element.on(START_EV, touchStart);
$element.on(CANCEL_EV, touchCancel);
return $element;
};
/**
* disables the swipe plugin
* @function
* @name $.fn.swipe#disable
* @return {DOMNode} The Dom element that is now registered with TouchSwipe
* @example $("#element").swipe("disable");
*/
this.disable = function() {
removeListeners();
return $element;
};
/**
* Destroy the swipe plugin completely. To use any swipe methods, you must re initialise the plugin.
* @function
* @name $.fn.swipe#destroy
* @example $("#element").swipe("destroy");
*/
this.destroy = function() {
removeListeners();
$element.data(PLUGIN_NS, null);
$element = null;
};
/**
* Allows run time updating of the swipe configuration options.
* @function
* @name $.fn.swipe#option
* @param {String} property The option property to get or set, or a has of multiple options to set
* @param {Object} [value] The value to set the property to
* @return {Object} If only a property name is passed, then that property value is returned. If nothing is passed the current options hash is returned.
* @example $("#element").swipe("option", "threshold"); // return the threshold
* @example $("#element").swipe("option", "threshold", 100); // set the threshold after init
* @example $("#element").swipe("option", {threshold:100, fingers:3} ); // set multiple properties after init
* @example $("#element").swipe({threshold:100, fingers:3} ); // set multiple properties after init - the "option" method is optional!
* @example $("#element").swipe("option"); // Return the current options hash
* @see $.fn.swipe.defaults
*
*/
this.option = function(property, value) {
if (typeof property === 'object') {
options = $.extend(options, property);
} else if (options[property] !== undefined) {
if (value === undefined) {
return options[property];
} else {
options[property] = value;
}
} else if (!property) {
return options;
} else {
$.error('Option ' + property + ' does not exist on jQuery.swipe.options');
}
return null;
}
//
// Private methods
//
//
// EVENTS
//
/**
* Event handler for a touch start event.
* Stops the default click event from triggering and stores where we touched
* @inner
* @param {object} jqEvent The normalised jQuery event object.
*/
function touchStart(jqEvent) {
//If we already in a touch event (a finger already in use) then ignore subsequent ones..
if (getTouchInProgress()) {
return;
}
//Check if this element matches any in the excluded elements selectors, or its parent is excluded, if so, DON'T swipe
if ($(jqEvent.target).closest(options.excludedElements, $element).length > 0) {
return;
}
//As we use Jquery bind for events, we need to target the original event object
//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
//If we have a pointer event, whoes type is 'mouse' and we have said NO mouse events, then dont do anything.
if(event.pointerType && event.pointerType=="mouse" && options.fallbackToMouseEvents==false) {
return;
};
var ret,
touches = event.touches,
evt = touches ? touches[0] : event;
phase = PHASE_START;
//If we support touches, get the finger count
if (touches) {
// get the total number of fingers touching the screen
fingerCount = touches.length;
}
//Else this is the desktop, so stop the browser from dragging content
else if (options.preventDefaultEvents !== false) {
jqEvent.preventDefault(); //call this on jq event so we are cross browser
}
//clear vars..
distance = 0;
direction = null;
currentDirection=null;
pinchDirection = null;
duration = 0;
startTouchesDistance = 0;
endTouchesDistance = 0;
pinchZoom = 1;
pinchDistance = 0;
maximumsMap = createMaximumsData();
cancelMultiFingerRelease();
//Create the default finger data
createFingerData(0, evt);
// check the number of fingers is what we are looking for, or we are capturing pinches
if (!touches || (fingerCount === options.fingers || options.fingers === ALL_FINGERS) || hasPinches()) {
// get the coordinates of the touch
startTime = getTimeStamp();
if (fingerCount == 2) {
//Keep track of the initial pinch distance, so we can calculate the diff later
//Store second finger data as start
createFingerData(1, touches[1]);
startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
}
if (options.swipeStatus || options.pinchStatus) {
ret = triggerHandler(event, phase);
}
} else {
//A touch with more or less than the fingers we are looking for, so cancel
ret = false;
}
//If we have a return value from the users handler, then return and cancel
if (ret === false) {
phase = PHASE_CANCEL;
triggerHandler(event, phase);
return ret;
} else {
if (options.hold) {
holdTimeout = setTimeout($.proxy(function() {
//Trigger the event
$element.trigger('hold', [event.target]);
//Fire the callback
if (options.hold) {
ret = options.hold.call($element, event, event.target);
}
}, this), options.longTapThreshold);
}
setTouchInProgress(true);
}
return null;
};
/**
* Event handler for a touch move event.
* If we change fingers during move, then cancel the event
* @inner
* @param {object} jqEvent The normalised jQuery event object.
*/
function touchMove(jqEvent) {
//As we use Jquery bind for events, we need to target the original event object
//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
//If we are ending, cancelling, or within the threshold of 2 fingers being released, don't track anything..
if (phase === PHASE_END || phase === PHASE_CANCEL || inMultiFingerRelease())
return;
var ret,
touches = event.touches,
evt = touches ? touches[0] : event;
//Update the finger data
var currentFinger = updateFingerData(evt);
endTime = getTimeStamp();
if (touches) {
fingerCount = touches.length;
}
if (options.hold) {
clearTimeout(holdTimeout);
}
phase = PHASE_MOVE;
//If we have 2 fingers get Touches distance as well
if (fingerCount == 2) {
//Keep track of the initial pinch distance, so we can calculate the diff later
//We do this here as well as the start event, in case they start with 1 finger, and the press 2 fingers
if (startTouchesDistance == 0) {
//Create second finger if this is the first time...
createFingerData(1, touches[1]);
startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
} else {
//Else just update the second finger
updateFingerData(touches[1]);
endTouchesDistance = calculateTouchesDistance(fingerData[0].end, fingerData[1].end);
pinchDirection = calculatePinchDirection(fingerData[0].end, fingerData[1].end);
}
pinchZoom = calculatePinchZoom(startTouchesDistance, endTouchesDistance);
pinchDistance = Math.abs(startTouchesDistance - endTouchesDistance);
}
if ((fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !touches || hasPinches()) {
//The overall direction of the swipe. From start to now.
direction = calculateDirection(currentFinger.start, currentFinger.end);
//The immediate direction of the swipe, direction between the last movement and this one.
currentDirection = calculateDirection(currentFinger.last, currentFinger.end);
//Check if we need to prevent default event (page scroll / pinch zoom) or not
validateDefaultEvent(jqEvent, currentDirection);
//Distance and duration are all off the main finger
distance = calculateDistance(currentFinger.start, currentFinger.end);
duration = calculateDuration();
//Cache the maximum distance we made in this direction
setMaxDistance(direction, distance);
//Trigger status handler
ret = triggerHandler(event, phase);
//If we trigger end events when threshold are met, or trigger events when touch leaves element
if (!options.triggerOnTouchEnd || options.triggerOnTouchLeave) {
var inBounds = true;
//If checking if we leave the element, run the bounds check (we can use touchleave as its not supported on webkit)
if (options.triggerOnTouchLeave) {
var bounds = getbounds(this);
inBounds = isInBounds(currentFinger.end, bounds);
}
//Trigger end handles as we swipe if thresholds met or if we have left the element if the user has asked to check these..
if (!options.triggerOnTouchEnd && inBounds) {
phase = getNextPhase(PHASE_MOVE);
}
//We end if out of bounds here, so set current phase to END, and check if its modified
else if (options.triggerOnTouchLeave && !inBounds) {
phase = getNextPhase(PHASE_END);
}
if (phase == PHASE_CANCEL || phase == PHASE_END) {
triggerHandler(event, phase);
}
}
} else {
phase = PHASE_CANCEL;
triggerHandler(event, phase);
}
if (ret === false) {
phase = PHASE_CANCEL;
triggerHandler(event, phase);
}
}
/**
* Event handler for a touch end event.
* Calculate the direction and trigger events
* @inner
* @param {object} jqEvent The normalised jQuery event object.
*/
function touchEnd(jqEvent) {
//As we use Jquery bind for events, we need to target the original event object
//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent,
touches = event.touches;
//If we are still in a touch with the device wait a fraction and see if the other finger comes up
//if it does within the threshold, then we treat it as a multi release, not a single release and end the touch / swipe
if (touches) {
if (touches.length && !inMultiFingerRelease()) {
startMultiFingerRelease(event);
return true;
} else if (touches.length && inMultiFingerRelease()) {
return true;
}
}
//If a previous finger has been released, check how long ago, if within the threshold, then assume it was a multifinger release.
//This is used to allow 2 fingers to release fractionally after each other, whilst maintaining the event as containing 2 fingers, not 1
if (inMultiFingerRelease()) {
fingerCount = fingerCountAtRelease;
}
//Set end of swipe
endTime = getTimeStamp();
//Get duration incase move was never fired
duration = calculateDuration();
//If we trigger handlers at end of swipe OR, we trigger during, but they didnt trigger and we are still in the move phase
if (didSwipeBackToCancel() || !validateSwipeDistance()) {
phase = PHASE_CANCEL;
triggerHandler(event, phase);
} else if (options.triggerOnTouchEnd || (options.triggerOnTouchEnd === false && phase === PHASE_MOVE)) {
//call this on jq event so we are cross browser
if (options.preventDefaultEvents !== false && jqEvent.cancelable !== false) {
jqEvent.preventDefault();
}
phase = PHASE_END;
triggerHandler(event, phase);
}
//Special cases - A tap should always fire on touch end regardless,
//So here we manually trigger the tap end handler by itself
//We dont run trigger handler as it will re-trigger events that may have fired already
else if (!options.triggerOnTouchEnd && hasTap()) {
//Trigger the pinch events...
phase = PHASE_END;
triggerHandlerForGesture(event, phase, TAP);
} else if (phase === PHASE_MOVE) {
phase = PHASE_CANCEL;
triggerHandler(event, phase);
}
setTouchInProgress(false);
return null;
}
/**
* Event handler for a touch cancel event.
* Clears current vars
* @inner
*/
function touchCancel() {
// reset the variables back to default values
fingerCount = 0;
endTime = 0;
startTime = 0;
startTouchesDistance = 0;
endTouchesDistance = 0;
pinchZoom = 1;
//If we were in progress of tracking a possible multi touch end, then re set it.
cancelMultiFingerRelease();
setTouchInProgress(false);
}
/**
* Event handler for a touch leave event.
* This is only triggered on desktops, in touch we work this out manually
* as the touchleave event is not supported in webkit
* @inner
*/
function touchLeave(jqEvent) {
//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
//If we have the trigger on leave property set....
if (options.triggerOnTouchLeave) {
phase = getNextPhase(PHASE_END);
triggerHandler(event, phase);
}
}
/**
* Removes all listeners that were associated with the plugin
* @inner
*/
function removeListeners() {
$element.off(START_EV, touchStart);
$element.off(CANCEL_EV, touchCancel);
$element.off(MOVE_EV, touchMove);
$element.off(END_EV, touchEnd);
//we only have leave events on desktop, we manually calculate leave on touch as its not supported in webkit
if (LEAVE_EV) {
$element.off(LEAVE_EV, touchLeave);
}
setTouchInProgress(false);
}
/**
* Checks if the time and distance thresholds have been met, and if so then the appropriate handlers are fired.
*/
function getNextPhase(currentPhase) {
var nextPhase = currentPhase;
// Ensure we have valid swipe (under time and over distance and check if we are out of bound...)
var validTime = validateSwipeTime();
var validDistance = validateSwipeDistance();
var didCancel = didSwipeBackToCancel();
//If we have exceeded our time, then cancel
if (!validTime || didCancel) {
nextPhase = PHASE_CANCEL;
}
//Else if we are moving, and have reached distance then end
else if (validDistance && currentPhase == PHASE_MOVE && (!options.triggerOnTouchEnd || options.triggerOnTouchLeave)) {
nextPhase = PHASE_END;
}
//Else if we have ended by leaving and didn't reach distance, then cancel
else if (!validDistance && currentPhase == PHASE_END && options.triggerOnTouchLeave) {
nextPhase = PHASE_CANCEL;
}
return nextPhase;
}
/**
* Trigger the relevant event handler
* The handlers are passed the original event, the element that was swiped, and in the case of the catch all handler, the direction that was swiped, "left", "right", "up", or "down"
* @param {object} event the original event object
* @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
* @inner
*/
function triggerHandler(event, phase) {
var ret,
touches = event.touches;
// SWIPE GESTURES
if (didSwipe() || hasSwipes()) {
ret = triggerHandlerForGesture(event, phase, SWIPE);
}
// PINCH GESTURES (if the above didn't cancel)
if ((didPinch() || hasPinches()) && ret !== false) {
ret = triggerHandlerForGesture(event, phase, PINCH);
}
// CLICK / TAP (if the above didn't cancel)
if (didDoubleTap() && ret !== false) {
//Trigger the tap events...
ret = triggerHandlerForGesture(event, phase, DOUBLE_TAP);
}
// CLICK / TAP (if the above didn't cancel)
else if (didLongTap() && ret !== false) {
//Trigger the tap events...
ret = triggerHandlerForGesture(event, phase, LONG_TAP);
}
// CLICK / TAP (if the above didn't cancel)
else if (didTap() && ret !== false) {
//Trigger the tap event..
ret = triggerHandlerForGesture(event, phase, TAP);
}
// If we are cancelling the gesture, then manually trigger the reset handler
if (phase === PHASE_CANCEL) {
touchCancel(event);
}
// If we are ending the gesture, then manually trigger the reset handler IF all fingers are off
if (phase === PHASE_END) {
//If we support touch, then check that all fingers are off before we cancel
if (touches) {
if (!touches.length) {
touchCancel(event);
}
} else {
touchCancel(event);
}
}
return ret;
}
/**
* Trigger the relevant event handler
* The handlers are passed the original event, the element that was swiped, and in the case of the catch all handler, the direction that was swiped, "left", "right", "up", or "down"
* @param {object} event the original event object
* @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
* @param {string} gesture the gesture to trigger a handler for : PINCH or SWIPE {@link $.fn.swipe.gestures}
* @return Boolean False, to indicate that the event should stop propagation, or void.
* @inner
*/
function triggerHandlerForGesture(event, phase, gesture) {
var ret;
//SWIPES....
if (gesture == SWIPE) {
//Trigger status every time..
$element.trigger('swipeStatus', [phase, direction || null, distance || 0, duration || 0, fingerCount, fingerData, currentDirection]);
if (options.swipeStatus) {
ret = options.swipeStatus.call($element, event, phase, direction || null, distance || 0, duration || 0, fingerCount, fingerData, currentDirection);
//If the status cancels, then dont run the subsequent event handlers..
if (ret === false) return false;
}
if (phase == PHASE_END && validateSwipe()) {
//Cancel any taps that were in progress...
clearTimeout(singleTapTimeout);
clearTimeout(holdTimeout);
$element.trigger('swipe', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
if (options.swipe) {
ret = options.swipe.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
//If the status cancels, then dont run the subsequent event handlers..
if (ret === false) return false;
}
//trigger direction specific event handlers
switch (direction) {
case LEFT:
$element.trigger('swipeLeft', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
if (options.swipeLeft) {
ret = options.swipeLeft.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
}
break;
case RIGHT:
$element.trigger('swipeRight', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
if (options.swipeRight) {
ret = options.swipeRight.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
}
break;
case UP:
$element.trigger('swipeUp', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
if (options.swipeUp) {
ret = options.swipeUp.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
}
break;
case DOWN:
$element.trigger('swipeDown', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
if (options.swipeDown) {
ret = options.swipeDown.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
}
break;
}
}
}
//PINCHES....
if (gesture == PINCH) {
$element.trigger('pinchStatus', [phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
if (options.pinchStatus) {
ret = options.pinchStatus.call($element, event, phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
//If the status cancels, then dont run the subsequent event handlers..
if (ret === false) return false;
}
if (phase == PHASE_END && validatePinch()) {
switch (pinchDirection) {
case IN:
$element.trigger('pinchIn', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
if (options.pinchIn) {
ret = options.pinchIn.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
}
break;
case OUT:
$element.trigger('pinchOut', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
if (options.pinchOut) {
ret = options.pinchOut.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
}
break;
}
}
}
if (gesture == TAP) {
if (phase === PHASE_CANCEL || phase === PHASE_END) {
clearTimeout(singleTapTimeout);
clearTimeout(holdTimeout);
//If we are also looking for doubelTaps, wait incase this is one...
if (hasDoubleTap() && !inDoubleTap()) {
doubleTapStartTime = getTimeStamp();
//Now wait for the double tap timeout, and trigger this single tap
//if its not cancelled by a double tap
singleTapTimeout = setTimeout($.proxy(function() {
doubleTapStartTime = null;
$element.trigger('tap', [event.target]);
if (options.tap) {
ret = options.tap.call($element, event, event.target);
}
}, this), options.doubleTapThreshold);
} else {
doubleTapStartTime = null;
$element.trigger('tap', [event.target]);
if (options.tap) {
ret = options.tap.call($element, event, event.target);
}
}
}
} else if (gesture == DOUBLE_TAP) {
if (phase === PHASE_CANCEL || phase === PHASE_END) {
clearTimeout(singleTapTimeout);
clearTimeout(holdTimeout);
doubleTapStartTime = null;
$element.trigger('doubletap', [event.target]);
if (options.doubleTap) {
ret = options.doubleTap.call($element, event, event.target);
}
}
} else if (gesture == LONG_TAP) {
if (phase === PHASE_CANCEL || phase === PHASE_END) {
clearTimeout(singleTapTimeout);
doubleTapStartTime = null;
$element.trigger('longtap', [event.target]);
if (options.longTap) {
ret = options.longTap.call($element, event, event.target);
}
}
}
return ret;
}
//
// GESTURE VALIDATION
//
/**
* Checks the user has swipe far enough
* @return Boolean if threshold
has been set, return true if the threshold was met, else false.
* If no threshold was set, then we return true.
* @inner
*/
function validateSwipeDistance() {
var valid = true;
//If we made it past the min swipe distance..
if (options.threshold !== null) {
valid = distance >= options.threshold;
}
return valid;
}
/**
* Checks the user has swiped back to cancel.
* @return Boolean if cancelThreshold
has been set, return true if the cancelThreshold was met, else false.
* If no cancelThreshold was set, then we return true.
* @inner
*/
function didSwipeBackToCancel() {
var cancelled = false;
if (options.cancelThreshold !== null && direction !== null) {
cancelled = (getMaxDistance(direction) - distance) >= options.cancelThreshold;
}
return cancelled;
}
/**
* Checks the user has pinched far enough
* @return Boolean if pinchThreshold
has been set, return true if the threshold was met, else false.
* If no threshold was set, then we return true.
* @inner
*/
function validatePinchDistance() {
if (options.pinchThreshold !== null) {
return pinchDistance >= options.pinchThreshold;
}
return true;
}
/**
* Checks that the time taken to swipe meets the minimum / maximum requirements
* @return Boolean
* @inner
*/
function validateSwipeTime() {
var result;
//If no time set, then return true
if (options.maxTimeThreshold) {
if (duration >= options.maxTimeThreshold) {
result = false;
} else {
result = true;
}
} else {
result = true;
}
return result;
}
/**
* Checks direction of the swipe and the value allowPageScroll to see if we should allow or prevent the default behaviour from occurring.
* This will essentially allow page scrolling or not when the user is swiping on a touchSwipe object.
* @param {object} jqEvent The normalised jQuery representation of the event object.
* @param {string} direction The direction of the event. See {@link $.fn.swipe.directions}
* @see $.fn.swipe.directions
* @inner
*/
function validateDefaultEvent(jqEvent, direction) {
//If the option is set, allways allow the event to bubble up (let user handle weirdness)
if (options.preventDefaultEvents === false) {
return;
}
if (options.allowPageScroll === NONE) {
jqEvent.preventDefault();
} else {
var auto = options.allowPageScroll === AUTO;
switch (direction) {
case LEFT:
if ((options.swipeLeft && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
jqEvent.preventDefault();
}
break;
case RIGHT:
if ((options.swipeRight && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
jqEvent.preventDefault();
}
break;
case UP:
if ((options.swipeUp && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
jqEvent.preventDefault();
}
break;
case DOWN:
if ((options.swipeDown && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
jqEvent.preventDefault();
}
break;
case NONE:
break;
}
}
}
// PINCHES
/**
* Returns true of the current pinch meets the thresholds
* @return Boolean
* @inner
*/
function validatePinch() {
var hasCorrectFingerCount = validateFingers();
var hasEndPoint = validateEndPoint();
var hasCorrectDistance = validatePinchDistance();
return hasCorrectFingerCount && hasEndPoint && hasCorrectDistance;
}
/**
* Returns true if any Pinch events have been registered
* @return Boolean
* @inner
*/
function hasPinches() {
//Enure we dont return 0 or null for false values
return !!(options.pinchStatus || options.pinchIn || options.pinchOut);
}
/**
* Returns true if we are detecting pinches, and have one
* @return Boolean
* @inner
*/
function didPinch() {
//Enure we dont return 0 or null for false values
return !!(validatePinch() && hasPinches());
}
// SWIPES
/**
* Returns true if the current swipe meets the thresholds
* @return Boolean
* @inner
*/
function validateSwipe() {
//Check validity of swipe
var hasValidTime = validateSwipeTime();
var hasValidDistance = validateSwipeDistance();
var hasCorrectFingerCount = validateFingers();
var hasEndPoint = validateEndPoint();
var didCancel = didSwipeBackToCancel();
// if the user swiped more than the minimum length, perform the appropriate action
// hasValidDistance is null when no distance is set
var valid = !didCancel && hasEndPoint && hasCorrectFingerCount && hasValidDistance && hasValidTime;
return valid;
}
/**
* Returns true if any Swipe events have been registered
* @return Boolean
* @inner
*/
function hasSwipes() {
//Enure we dont return 0 or null for false values
return !!(options.swipe || options.swipeStatus || options.swipeLeft || options.swipeRight || options.swipeUp || options.swipeDown);
}
/**
* Returns true if we are detecting swipes and have one
* @return Boolean
* @inner
*/
function didSwipe() {
//Enure we dont return 0 or null for false values
return !!(validateSwipe() && hasSwipes());
}
/**
* Returns true if we have matched the number of fingers we are looking for
* @return Boolean
* @inner
*/
function validateFingers() {
//The number of fingers we want were matched, or on desktop we ignore
return ((fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !SUPPORTS_TOUCH);
}
/**
* Returns true if we have an end point for the swipe
* @return Boolean
* @inner
*/
function validateEndPoint() {
//We have an end value for the finger
return fingerData[0].end.x !== 0;
}
// TAP / CLICK
/**
* Returns true if a click / tap events have been registered
* @return Boolean
* @inner
*/
function hasTap() {
//Enure we dont return 0 or null for false values
return !!(options.tap);
}
/**
* Returns true if a double tap events have been registered
* @return Boolean
* @inner
*/
function hasDoubleTap() {
//Enure we dont return 0 or null for false values
return !!(options.doubleTap);
}
/**
* Returns true if any long tap events have been registered
* @return Boolean
* @inner
*/
function hasLongTap() {
//Enure we dont return 0 or null for false values
return !!(options.longTap);
}
/**
* Returns true if we could be in the process of a double tap (one tap has occurred, we are listening for double taps, and the threshold hasn't past.
* @return Boolean
* @inner
*/
function validateDoubleTap() {
if (doubleTapStartTime == null) {
return false;
}
var now = getTimeStamp();
return (hasDoubleTap() && ((now - doubleTapStartTime) <= options.doubleTapThreshold));
}
/**
* Returns true if we could be in the process of a double tap (one tap has occurred, we are listening for double taps, and the threshold hasn't past.
* @return Boolean
* @inner
*/
function inDoubleTap() {
return validateDoubleTap();
}
/**
* Returns true if we have a valid tap
* @return Boolean
* @inner
*/
function validateTap() {
return ((fingerCount === 1 || !SUPPORTS_TOUCH) && (isNaN(distance) || distance < options.threshold));
}
/**
* Returns true if we have a valid long tap
* @return Boolean
* @inner
*/
function validateLongTap() {
//slight threshold on moving finger
return ((duration > options.longTapThreshold) && (distance < DOUBLE_TAP_THRESHOLD));
}
/**
* Returns true if we are detecting taps and have one
* @return Boolean
* @inner
*/
function didTap() {
//Enure we dont return 0 or null for false values
return !!(validateTap() && hasTap());
}
/**
* Returns true if we are detecting double taps and have one
* @return Boolean
* @inner
*/
function didDoubleTap() {
//Enure we dont return 0 or null for false values
return !!(validateDoubleTap() && hasDoubleTap());
}
/**
* Returns true if we are detecting long taps and have one
* @return Boolean
* @inner
*/
function didLongTap() {
//Enure we dont return 0 or null for false values
return !!(validateLongTap() && hasLongTap());
}
// MULTI FINGER TOUCH
/**
* Starts tracking the time between 2 finger releases, and keeps track of how many fingers we initially had up
* @inner
*/
function startMultiFingerRelease(event) {
previousTouchEndTime = getTimeStamp();
fingerCountAtRelease = event.touches.length + 1;
}
/**
* Cancels the tracking of time between 2 finger releases, and resets counters
* @inner
*/
function cancelMultiFingerRelease() {
previousTouchEndTime = 0;
fingerCountAtRelease = 0;
}
/**
* Checks if we are in the threshold between 2 fingers being released
* @return Boolean
* @inner
*/
function inMultiFingerRelease() {
var withinThreshold = false;
if (previousTouchEndTime) {
var diff = getTimeStamp() - previousTouchEndTime
if (diff <= options.fingerReleaseThreshold) {
withinThreshold = true;
}
}
return withinThreshold;
}
/**
* gets a data flag to indicate that a touch is in progress
* @return Boolean
* @inner
*/
function getTouchInProgress() {
//strict equality to ensure only true and false are returned
return !!($element.data(PLUGIN_NS + '_intouch') === true);
}
/**
* Sets a data flag to indicate that a touch is in progress
* @param {boolean} val The value to set the property to
* @inner
*/
function setTouchInProgress(val) {
//If destroy is called in an event handler, we have no el, and we have already cleaned up, so return.
if(!$element) { return; }
//Add or remove event listeners depending on touch status
if (val === true) {
$element.on(MOVE_EV, touchMove);
$element.on(END_EV, touchEnd);
//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
if (LEAVE_EV) {
$element.on(LEAVE_EV, touchLeave);
}
} else {
$element.off(MOVE_EV, touchMove, false);
$element.off(END_EV, touchEnd, false);
//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
if (LEAVE_EV) {
$element.off(LEAVE_EV, touchLeave, false);
}
}
//strict equality to ensure only true and false can update the value
$element.data(PLUGIN_NS + '_intouch', val === true);
}
/**
* Creates the finger data for the touch/finger in the event object.
* @param {int} id The id to store the finger data under (usually the order the fingers were pressed)
* @param {object} evt The event object containing finger data
* @return finger data object
* @inner
*/
function createFingerData(id, evt) {
var f = {
start: {
x: 0,
y: 0
},
last: {
x: 0,
y: 0
},
end: {
x: 0,
y: 0
}
};
f.start.x = f.last.x = f.end.x = evt.pageX || evt.clientX;
f.start.y = f.last.y = f.end.y = evt.pageY || evt.clientY;
fingerData[id] = f;
return f;
}
/**
* Updates the finger data for a particular event object
* @param {object} evt The event object containing the touch/finger data to upadte
* @return a finger data object.
* @inner
*/
function updateFingerData(evt) {
var id = evt.identifier !== undefined ? evt.identifier : 0;
var f = getFingerData(id);
if (f === null) {
f = createFingerData(id, evt);
}
f.last.x = f.end.x;
f.last.y = f.end.y;
f.end.x = evt.pageX || evt.clientX;
f.end.y = evt.pageY || evt.clientY;
return f;
}
/**
* Returns a finger data object by its event ID.
* Each touch event has an identifier property, which is used
* to track repeat touches
* @param {int} id The unique id of the finger in the sequence of touch events.
* @return a finger data object.
* @inner
*/
function getFingerData(id) {
return fingerData[id] || null;
}
/**
* Sets the maximum distance swiped in the given direction.
* If the new value is lower than the current value, the max value is not changed.
* @param {string} direction The direction of the swipe
* @param {int} distance The distance of the swipe
* @inner
*/
function setMaxDistance(direction, distance) {
if(direction==NONE) return;
distance = Math.max(distance, getMaxDistance(direction));
maximumsMap[direction].distance = distance;
}
/**
* gets the maximum distance swiped in the given direction.
* @param {string} direction The direction of the swipe
* @return int The distance of the swipe
* @inner
*/
function getMaxDistance(direction) {
if (maximumsMap[direction]) return maximumsMap[direction].distance;
return undefined;
}
/**
* Creats a map of directions to maximum swiped values.
* @return Object A dictionary of maximum values, indexed by direction.
* @inner
*/
function createMaximumsData() {
var maxData = {};
maxData[LEFT] = createMaximumVO(LEFT);
maxData[RIGHT] = createMaximumVO(RIGHT);
maxData[UP] = createMaximumVO(UP);
maxData[DOWN] = createMaximumVO(DOWN);
return maxData;
}
/**
* Creates a map maximum swiped values for a given swipe direction
* @param {string} The direction that these values will be associated with
* @return Object Maximum values
* @inner
*/
function createMaximumVO(dir) {
return {
direction: dir,
distance: 0
}
}
//
// MATHS / UTILS
//
/**
* Calculate the duration of the swipe
* @return int
* @inner
*/
function calculateDuration() {
return endTime - startTime;
}
/**
* Calculate the distance between 2 touches (pinch)
* @param {point} startPoint A point object containing x and y co-ordinates
* @param {point} endPoint A point object containing x and y co-ordinates
* @return int;
* @inner
*/
function calculateTouchesDistance(startPoint, endPoint) {
var diffX = Math.abs(startPoint.x - endPoint.x);
var diffY = Math.abs(startPoint.y - endPoint.y);
return Math.round(Math.sqrt(diffX * diffX + diffY * diffY));
}
/**
* Calculate the zoom factor between the start and end distances
* @param {int} startDistance Distance (between 2 fingers) the user started pinching at
* @param {int} endDistance Distance (between 2 fingers) the user ended pinching at
* @return float The zoom value from 0 to 1.
* @inner
*/
function calculatePinchZoom(startDistance, endDistance) {
var percent = (endDistance / startDistance) * 1;
return percent.toFixed(2);
}
/**
* Returns the pinch direction, either IN or OUT for the given points
* @return string Either {@link $.fn.swipe.directions.IN} or {@link $.fn.swipe.directions.OUT}
* @see $.fn.swipe.directions
* @inner
*/
function calculatePinchDirection() {
if (pinchZoom < 1) {
return OUT;
} else {
return IN;
}
}
/**
* Calculate the length / distance of the swipe
* @param {point} startPoint A point object containing x and y co-ordinates
* @param {point} endPoint A point object containing x and y co-ordinates
* @return int
* @inner
*/
function calculateDistance(startPoint, endPoint) {
return Math.round(Math.sqrt(Math.pow(endPoint.x - startPoint.x, 2) + Math.pow(endPoint.y - startPoint.y, 2)));
}
/**
* Calculate the angle of the swipe
* @param {point} startPoint A point object containing x and y co-ordinates
* @param {point} endPoint A point object containing x and y co-ordinates
* @return int
* @inner
*/
function calculateAngle(startPoint, endPoint) {
var x = startPoint.x - endPoint.x;
var y = endPoint.y - startPoint.y;
var r = Math.atan2(y, x); //radians
var angle = Math.round(r * 180 / Math.PI); //degrees
//ensure value is positive
if (angle < 0) {
angle = 360 - Math.abs(angle);
}
return angle;
}
/**
* Calculate the direction of the swipe
* This will also call calculateAngle to get the latest angle of swipe
* @param {point} startPoint A point object containing x and y co-ordinates
* @param {point} endPoint A point object containing x and y co-ordinates
* @return string Either {@link $.fn.swipe.directions.LEFT} / {@link $.fn.swipe.directions.RIGHT} / {@link $.fn.swipe.directions.DOWN} / {@link $.fn.swipe.directions.UP}
* @see $.fn.swipe.directions
* @inner
*/
function calculateDirection(startPoint, endPoint) {
if( comparePoints(startPoint, endPoint) ) {
return NONE;
}
var angle = calculateAngle(startPoint, endPoint);
if ((angle <= 45) && (angle >= 0)) {
return LEFT;
} else if ((angle <= 360) && (angle >= 315)) {
return LEFT;
} else if ((angle >= 135) && (angle <= 225)) {
return RIGHT;
} else if ((angle > 45) && (angle < 135)) {
return DOWN;
} else {
return UP;
}
}
/**
* Returns a MS time stamp of the current time
* @return int
* @inner
*/
function getTimeStamp() {
var now = new Date();
return now.getTime();
}
/**
* Returns a bounds object with left, right, top and bottom properties for the element specified.
* @param {DomNode} The DOM node to get the bounds for.
*/
function getbounds(el) {
el = $(el);
var offset = el.offset();
var bounds = {
left: offset.left,
right: offset.left + el.outerWidth(),
top: offset.top,
bottom: offset.top + el.outerHeight()
}
return bounds;
}
/**
* Checks if the point object is in the bounds object.
* @param {object} point A point object.
* @param {int} point.x The x value of the point.
* @param {int} point.y The x value of the point.
* @param {object} bounds The bounds object to test
* @param {int} bounds.left The leftmost value
* @param {int} bounds.right The righttmost value
* @param {int} bounds.top The topmost value
* @param {int} bounds.bottom The bottommost value
*/
function isInBounds(point, bounds) {
return (point.x > bounds.left && point.x < bounds.right && point.y > bounds.top && point.y < bounds.bottom);
};
/**
* Checks if the two points are equal
* @param {object} point A point object.
* @param {object} point B point object.
* @return true of the points match
*/
function comparePoints(pointA, pointB) {
return (pointA.x == pointB.x && pointA.y == pointB.y);
}
}
/**
* A catch all handler that is triggered for all swipe directions.
* @name $.fn.swipe#swipe
* @event
* @default null
* @param {EventObject} event The original event object
* @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user swiped
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {object} fingerData The coordinates of fingers in event
* @param {string} currentDirection The current direction the user is swiping.
*/
/**
* A handler that is triggered for "left" swipes.
* @name $.fn.swipe#swipeLeft
* @event
* @default null
* @param {EventObject} event The original event object
* @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user swiped
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {object} fingerData The coordinates of fingers in event
* @param {string} currentDirection The current direction the user is swiping.
*/
/**
* A handler that is triggered for "right" swipes.
* @name $.fn.swipe#swipeRight
* @event
* @default null
* @param {EventObject} event The original event object
* @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user swiped
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {object} fingerData The coordinates of fingers in event
* @param {string} currentDirection The current direction the user is swiping.
*/
/**
* A handler that is triggered for "up" swipes.
* @name $.fn.swipe#swipeUp
* @event
* @default null
* @param {EventObject} event The original event object
* @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user swiped
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {object} fingerData The coordinates of fingers in event
* @param {string} currentDirection The current direction the user is swiping.
*/
/**
* A handler that is triggered for "down" swipes.
* @name $.fn.swipe#swipeDown
* @event
* @default null
* @param {EventObject} event The original event object
* @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user swiped
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {object} fingerData The coordinates of fingers in event
* @param {string} currentDirection The current direction the user is swiping.
*/
/**
* A handler triggered for every phase of the swipe. This handler is constantly fired for the duration of the pinch.
* This is triggered regardless of swipe thresholds.
* @name $.fn.swipe#swipeStatus
* @event
* @default null
* @param {EventObject} event The original event object
* @param {string} phase The phase of the swipe event. See {@link $.fn.swipe.phases}
* @param {string} direction The direction the user swiped in. This is null if the user has yet to move. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user swiped. This is 0 if the user has yet to move.
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {object} fingerData The coordinates of fingers in event
* @param {string} currentDirection The current direction the user is swiping.
*/
/**
* A handler triggered for pinch in events.
* @name $.fn.swipe#pinchIn
* @event
* @default null
* @param {EventObject} event The original event object
* @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user pinched
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {int} zoom The zoom/scale level the user pinched too, 0-1.
* @param {object} fingerData The coordinates of fingers in event
*/
/**
* A handler triggered for pinch out events.
* @name $.fn.swipe#pinchOut
* @event
* @default null
* @param {EventObject} event The original event object
* @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user pinched
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {int} zoom The zoom/scale level the user pinched too, 0-1.
* @param {object} fingerData The coordinates of fingers in event
*/
/**
* A handler triggered for all pinch events. This handler is constantly fired for the duration of the pinch. This is triggered regardless of thresholds.
* @name $.fn.swipe#pinchStatus
* @event
* @default null
* @param {EventObject} event The original event object
* @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
* @param {int} distance The distance the user pinched
* @param {int} duration The duration of the swipe in milliseconds
* @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
* @param {int} zoom The zoom/scale level the user pinched too, 0-1.
* @param {object} fingerData The coordinates of fingers in event
*/
/**
* A click handler triggered when a user simply clicks, rather than swipes on an element.
* This is deprecated since version 1.6.2, any assignment to click will be assigned to the tap handler.
* You cannot use on
to bind to this event as the default jQ click
event will be triggered.
* Use the tap
event instead.
* @name $.fn.swipe#click
* @event
* @deprecated since version 1.6.2, please use {@link $.fn.swipe#tap} instead
* @default null
* @param {EventObject} event The original event object
* @param {DomObject} target The element clicked on.
*/
/**
* A click / tap handler triggered when a user simply clicks or taps, rather than swipes on an element.
* @name $.fn.swipe#tap
* @event
* @default null
* @param {EventObject} event The original event object
* @param {DomObject} target The element clicked on.
*/
/**
* A double tap handler triggered when a user double clicks or taps on an element.
* You can set the time delay for a double tap with the {@link $.fn.swipe.defaults#doubleTapThreshold} property.
* Note: If you set both doubleTap
and tap
handlers, the tap
event will be delayed by the doubleTapThreshold
* as the script needs to check if its a double tap.
* @name $.fn.swipe#doubleTap
* @see $.fn.swipe.defaults#doubleTapThreshold
* @event
* @default null
* @param {EventObject} event The original event object
* @param {DomObject} target The element clicked on.
*/
/**
* A long tap handler triggered once a tap has been release if the tap was longer than the longTapThreshold.
* You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property.
* @name $.fn.swipe#longTap
* @see $.fn.swipe.defaults#longTapThreshold
* @event
* @default null
* @param {EventObject} event The original event object
* @param {DomObject} target The element clicked on.
*/
/**
* A hold tap handler triggered as soon as the longTapThreshold is reached
* You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property.
* @name $.fn.swipe#hold
* @see $.fn.swipe.defaults#longTapThreshold
* @event
* @default null
* @param {EventObject} event The original event object
* @param {DomObject} target The element clicked on.
*/
}));
(function(w){"object"===typeof exports&&"undefined"!==typeof module?module.exports=w():"function"===typeof define&&define.amd?define([],w):("undefined"!==typeof window?window:"undefined"!==typeof global?global:"undefined"!==typeof self?self:this).SmartBanner=w()})(function(){return function e(b,g,f){function c(d,m){if(!g[d]){if(!b[d]){var t="function"==typeof require&&require;if(!m&&t)return t(d,!0);if(a)return a(d,!0);m=Error("Cannot find module '"+d+"'");throw m.code="MODULE_NOT_FOUND",m;}m=g[d]=
{exports:{}};b[d][0].call(m.exports,function(a){var e=b[d][1][a];return c(e?e:a)},m,m.exports,e,b,g,f)}return g[d].exports}for(var a="function"==typeof require&&require,d=0;d× '+
this.options.title+"
"+this.options.author+"
"+e+' '+this.options.button+" ";a.body?a.body.appendChild(p):a&&a.addEventListener("DOMContentLoaded",function(){a.body.appendChild(p)});c(".smartbanner-button",p).addEventListener("click",this.install.bind(this),!1);c(".smartbanner-close",p).addEventListener("click",this.close.bind(this),!1)},hide:function(){q.classList.remove("smartbanner-show");
if("function"===typeof this.options.close)return this.options.close()},show:function(){q.classList.add("smartbanner-show");if("function"===typeof this.options.show)return this.options.show()},close:function(){this.hide();d.set("smartbanner-closed","true",{path:"/",expires:new Date(Number(new Date)+864E5*this.options.daysHidden)});if("function"===typeof this.options.close)return this.options.close()},install:function(){this.hide();d.set("smartbanner-installed","true",{path:"/",expires:new Date(Number(new Date)+
864E5*this.options.daysReminder)});if("function"===typeof this.options.close)return this.options.close()},parseAppId:function(){var a=c('meta[name="'+this.appMeta+'"]');if(a)return this.appId="windows"===this.type?a.getAttribute("content"):/app-id=([^\s,]+)/.exec(a.getAttribute("content"))[1]}};g.exports=b},{"component-query":2,"cookie-cutter":3,"get-doc":4,"ua-parser-js":6,"xtend/mutable":7}],2:[function(b,g,f){function e(c,a){return a.querySelector(c)}f=g.exports=function(c,a){a=a||document;return e(c,
a)};f.all=function(c,a){a=a||document;return a.querySelectorAll(c)};f.engine=function(c){if(!c.one)throw Error(".one callback required");if(!c.all)throw Error(".all callback required");e=c.one;f.all=c.all;return f}},{}],3:[function(b,g,f){f=g.exports=function(e){e||(e={});"string"===typeof e&&(e={cookie:e});void 0===e.cookie&&(e.cookie="");return{get:function(c){for(var a=e.cookie.split(/;\s*/),d=0;d