2017-10-25 16:05:39 -07:00
! function ( t ) { function e ( i ) { if ( n [ i ] ) return n [ i ] . exports ; var r = n [ i ] = { i : i , l : ! 1 , exports : { } } ; return t [ i ] . call ( r . exports , r , r . exports , e ) , r . l = ! 0 , r . exports } var n = { } ; e . m = t , e . c = n , e . d = function ( t , n , i ) { e . o ( t , n ) || Object . defineProperty ( t , n , { configurable : ! 1 , enumerable : ! 0 , get : i } ) } , e . n = function ( t ) { var n = t && t . _ _esModule ? function ( ) { return t . default } : function ( ) { return t } ; return e . d ( n , "a" , n ) , n } , e . o = function ( t , e ) { return Object . prototype . hasOwnProperty . call ( t , e ) } , e . p = "" , e ( e . s = 0 ) } ( { "+B67" : function ( t , e , n ) { var i = n ( "/Psq" ) ; "string" == typeof i && ( i = [ [ t . i , i , "" ] ] ) , i . locals && ( t . exports = i . locals ) ; n ( "rjj0" ) ( "6e100439" , i , ! 0 ) } , "/Psq" : function ( t , e , n ) { e = t . exports = n ( "FZ+f" ) ( void 0 ) , e . push ( [ t . i , "" , "" ] ) } , 0 : function ( t , e , n ) { n ( "GDnL" ) , n ( "Bqz+" ) , n ( "1CH1" ) , t . exports = n ( "f5J3" ) } , 1 : function ( t , e ) { } , "1CH1" : function ( t , e ) { } , "3IRH" : function ( t , e ) { t . exports = function ( t ) { return t . webpackPolyfill || ( t . deprecate = function ( ) { } , t . paths = [ ] , t . children || ( t . children = [ ] ) , Object . defineProperty ( t , "loaded" , { enumerable : ! 0 , get : function ( ) { return t . l } } ) , Object . defineProperty ( t , "id" , { enumerable : ! 0 , get : function ( ) { return t . i } } ) , t . webpackPolyfill = 1 ) , t } } , "4dDV" : function ( t , e , n ) { var i = n ( "aLss" ) ; "string" == typeof i && ( i = [ [ t . i , i , "" ] ] ) , i . locals && ( t . exports = i . locals ) ; n ( "rjj0" ) ( "aa37c4a4" , i , ! 0 ) } , "6dED" : function ( t , e ) { t . exports = { render : function ( ) { var t = this , e = t . $createElement , n = t . _self . _c || e ; return n ( "div" , [ n ( "div" , [ n ( "div" , { staticClass : "panel panel-default" } , [ n ( "div" , { staticClass : "panel-heading" } , [ n ( "div" , { staticStyle : { display : "flex" , "justify-content" : "space-between" , "align-items" : "center" } } , [ n ( "span" , [ t . _v ( "\n Personal Access Tokens\n " ) ] ) , t . _v ( " " ) , n ( "a" , { staticClass : "action-link" , on : { click : t . showCreateTokenForm } } , [ t . _v ( "\n Create New Token\n " ) ] ) ] ) ] ) , t . _v ( " " ) , n ( "div" , { staticClass : "panel-body" } , [ 0 === t . tokens . length ? n ( "p" , { staticClass : "m-b-none" } , [ t . _v ( "\n You have not created any personal access tokens.\n " ) ] ) : t . _e ( ) , t . _v ( " " ) , t . tokens . length > 0 ? n ( "table" , { staticClass : "table table-borderless m-b-none" } , [ t . _m ( 0 ) , t . _v ( " " ) , n ( "tbody" , t . _l ( t . tokens , function ( e ) { return n ( "tr" , [ n ( "td" , { staticStyle : { "vertical-align" : "middle" } } , [ t . _v ( "\n " + t . _s ( e . name ) + "\n " ) ] ) , t . _v ( " " ) , n ( "td" , { staticStyle : { "vertical-align" : "middle" } } , [ n ( "a" , { staticClass : "action-link text-danger" , on : { click : function ( n ) { t . revoke ( e ) } } } , [ t . _v ( "\n Delete\n " ) ] ) ] ) ] ) } ) ) ] ) : t . _e ( ) ] ) ] ) ] ) , t . _v ( " " ) , n ( "div" , { staticClass : "modal fade" , attrs : { id : "modal-create-token" , tabindex : "-1" , role : "dialog" } } , [ n ( "div" , { staticClass : "modal-dialog" } , [ n ( "div" , { staticClass : "modal-content" } , [ t . _m ( 1 ) , t . _v ( " " ) , n ( "div" , { staticClass : "modal-body" } , [ t . form . errors . length > 0 ? n ( "div" , { staticClass : "alert alert-danger" } , [ t . _m ( 2 ) , t . _v ( " " ) , n ( "br" ) , t . _v ( " " ) , n ( "ul" , t . _l ( t . form . errors , function ( e ) { return n ( "li" , [ t . _v ( "\n " + t . _s ( e ) + "\n " ) ] ) } ) ) ] ) : t . _e ( ) , t . _v ( " " ) , n ( "form" , { staticClass : "form-horizontal" , attrs : { role : "form" } , on : { submit : function ( e ) { e . preventDefault ( ) , t . store ( e ) } } } , [ n ( "div" , { staticClass : "form-group" } , [ n ( "label" , { staticClass : "col-md-4 control-label" } , [ t . _v ( "Name" ) ] ) , t . _v ( " " ) , n ( "div" , { staticClass : "col-md-6" } , [ n ( "input" , { directives : [ { name : "model" , rawName : "v-model" , value : t . form . name , expression : "form.name" } ] , staticClass : "form-control" , attrs : { id : "create-token-name" , type : "text" , name : "name" } , domProps : { value : t . form . name } , on : { input : function ( e ) { e . target . composing || ( t . form . name = e . target . value ) } } } ) ] ) ] ) , t . _v ( " " ) , t . scopes . length > 0 ? n ( "div" , { staticClass : "form-group" } , [ n ( "label" , { staticClass : "col-md-4 control-label" } , [ t . _v ( "Scopes" ) ] ) , t . _v ( " " ) , n ( "div" , { staticClass : "col-md-6" } , t . _l ( t . scopes , function ( e ) { return n ( "div" , [ n ( "div" , { staticClass : "checkbox" } , [ n ( "label" , [ n ( "input" , { attrs : { type : "checkbox" } , domProps : { checked : t . scopeIsAssigned ( e . id ) } , on : { click : function ( n ) { t . toggleScope ( e . id ) } } } ) , t . _v ( "\n\n " + t . _s ( e . id ) + "\n " ) ] ) ] ) ] ) } ) ) ] ) : t .
2017-10-25 18:13:03 -07:00
//# sourceMappingURL=vue.js.map
! function ( t , e ) { "function" == typeof define && define . amd ? define ( e ) : "object" == typeof exports ? module . exports = e ( require , exports , module ) : t . Tether = e ( ) } ( this , function ( t , e , o ) { "use strict" ; function i ( t , e ) { if ( ! ( t instanceof e ) ) throw new TypeError ( "Cannot call a class as a function" ) } function n ( t ) { var e = t . getBoundingClientRect ( ) , o = { } ; for ( var i in e ) o [ i ] = e [ i ] ; if ( t . ownerDocument !== document ) { var r = t . ownerDocument . defaultView . frameElement ; if ( r ) { var s = n ( r ) ; o . top += s . top , o . bottom += s . top , o . left += s . left , o . right += s . left } } return o } function r ( t ) { var e = getComputedStyle ( t ) || { } , o = e . position , i = [ ] ; if ( "fixed" === o ) return [ t ] ; for ( var n = t ; ( n = n . parentNode ) && n && 1 === n . nodeType ; ) { var r = void 0 ; try { r = getComputedStyle ( n ) } catch ( s ) { } if ( "undefined" == typeof r || null === r ) return i . push ( n ) , i ; var a = r , f = a . overflow , l = a . overflowX , h = a . overflowY ; /(auto|scroll)/ . test ( f + h + l ) && ( "absolute" !== o || [ "relative" , "absolute" , "fixed" ] . indexOf ( r . position ) >= 0 ) && i . push ( n ) } return i . push ( t . ownerDocument . body ) , t . ownerDocument !== document && i . push ( t . ownerDocument . defaultView ) , i } function s ( ) { A && document . body . removeChild ( A ) , A = null } function a ( t ) { var e = void 0 ; t === document ? ( e = document , t = document . documentElement ) : e = t . ownerDocument ; var o = e . documentElement , i = n ( t ) , r = P ( ) ; return i . top -= r . top , i . left -= r . left , "undefined" == typeof i . width && ( i . width = document . body . scrollWidth - i . left - i . right ) , "undefined" == typeof i . height && ( i . height = document . body . scrollHeight - i . top - i . bottom ) , i . top = i . top - o . clientTop , i . left = i . left - o . clientLeft , i . right = e . body . clientWidth - i . width - i . left , i . bottom = e . body . clientHeight - i . height - i . top , i } function f ( t ) { return t . offsetParent || document . documentElement } function l ( ) { if ( M ) return M ; var t = document . createElement ( "div" ) ; t . style . width = "100%" , t . style . height = "200px" ; var e = document . createElement ( "div" ) ; h ( e . style , { position : "absolute" , top : 0 , left : 0 , pointerEvents : "none" , visibility : "hidden" , width : "200px" , height : "150px" , overflow : "hidden" } ) , e . appendChild ( t ) , document . body . appendChild ( e ) ; var o = t . offsetWidth ; e . style . overflow = "scroll" ; var i = t . offsetWidth ; o === i && ( i = e . clientWidth ) , document . body . removeChild ( e ) ; var n = o - i ; return M = { width : n , height : n } } function h ( ) { var t = arguments . length <= 0 || void 0 === arguments [ 0 ] ? { } : arguments [ 0 ] , e = [ ] ; return Array . prototype . push . apply ( e , arguments ) , e . slice ( 1 ) . forEach ( function ( e ) { if ( e ) for ( var o in e ) ( { } ) . hasOwnProperty . call ( e , o ) && ( t [ o ] = e [ o ] ) } ) , t } function d ( t , e ) { if ( "undefined" != typeof t . classList ) e . split ( " " ) . forEach ( function ( e ) { e . trim ( ) && t . classList . remove ( e ) } ) ; else { var o = new RegExp ( "(^| )" + e . split ( " " ) . join ( "|" ) + "( |$)" , "gi" ) , i = c ( t ) . replace ( o , " " ) ; g ( t , i ) } } function p ( t , e ) { if ( "undefined" != typeof t . classList ) e . split ( " " ) . forEach ( function ( e ) { e . trim ( ) && t . classList . add ( e ) } ) ; else { d ( t , e ) ; var o = c ( t ) + ( " " + e ) ; g ( t , o ) } } function u ( t , e ) { if ( "undefined" != typeof t . classList ) return t . classList . contains ( e ) ; var o = c ( t ) ; return new RegExp ( "(^| )" + e + "( |$)" , "gi" ) . test ( o ) } function c ( t ) { return t . className instanceof t . ownerDocument . defaultView . SVGAnimatedString ? t . className . baseVal : t . className } function g ( t , e ) { t . setAttribute ( "class" , e ) } function m ( t , e , o ) { o . forEach ( function ( o ) { e . indexOf ( o ) === - 1 && u ( t , o ) && d ( t , o ) } ) , e . forEach ( function ( e ) { u ( t , e ) || p ( t , e ) } ) } function i ( t , e ) { if ( ! ( t instanceof e ) ) throw new TypeError ( "Cannot call a class as a function" ) } function v ( t , e ) { if ( "function" != typeof e && null !== e ) throw new TypeError ( "Super expression must either be null or a function, not " + typeof e ) ; t . prototype = Object . create ( e && e . prototype , { constructor : { value : t , enumerable : ! 1 , writable : ! 0 , configurable : ! 0 } } ) , e && ( Object . setPrototypeOf ? Object . setPrototypeOf ( t , e ) : t . _ _proto _ _ = e ) } function y ( t , e ) { var o = arguments . length <= 2 || void 0 === arguments [ 2 ] ? 1 : arguments [ 2 ] ; return t + o >= e && e >= t - o } function b ( ) { return "undefined" != typeof performance && "undefined" != typeof performance . now ? performance . now ( ) : + new Date } function w ( ) { for ( var t = { top : 0 , left : 0 } , e = arguments . length , o = Array ( e ) , i = 0 ; i < e ; i ++ ) o [ i ] = arguments [ i ] ; return o . forEach ( function ( e ) { var o = e . top , i = e . left ; "string" == typeof o && ( o = parseFloat ( o , 10 ) ) , "string" == typeof i && ( i = parseFloat ( i , 10 ) ) , t . top += o , t . left += i } ) , t } function C ( t , e ) { return "string" == typeof t . left && t . left . indexOf ( "%" ) !== - 1 && ( t . left = parseFloat ( t . left , 10 ) / 100 * e . widt
/*! Copyright (c) 2011 Piotr Rochala (http:/ / rocha . la )
* Dual licensed under the MIT ( http : //www.opensource.org/licenses/mit-license.php)
* and GPL ( http : //www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version : 1.3 . 8
*
* /
( function ( $ ) {
$ . fn . extend ( {
slimScroll : function ( options ) {
var defaults = {
// width in pixels of the visible scroll area
width : 'auto' ,
// height in pixels of the visible scroll area
height : '250px' ,
// width in pixels of the scrollbar and rail
size : '7px' ,
// scrollbar color, accepts any hex/color value
color : '#000' ,
// scrollbar position - left/right
position : 'right' ,
// distance in pixels between the side edge and the scrollbar
distance : '1px' ,
// default scroll position on load - top / bottom / $('selector')
start : 'top' ,
// sets scrollbar opacity
opacity : . 4 ,
// enables always-on mode for the scrollbar
alwaysVisible : false ,
// check if we should hide the scrollbar when user is hovering over
disableFadeOut : false ,
// sets visibility of the rail
railVisible : false ,
// sets rail color
railColor : '#333' ,
// sets rail opacity
railOpacity : . 2 ,
// whether we should use jQuery UI Draggable to enable bar dragging
railDraggable : true ,
// defautlt CSS class of the slimscroll rail
railClass : 'slimScrollRail' ,
// defautlt CSS class of the slimscroll bar
barClass : 'slimScrollBar' ,
// defautlt CSS class of the slimscroll wrapper
wrapperClass : 'slimScrollDiv' ,
// check if mousewheel should scroll the window if we reach top/bottom
allowPageScroll : false ,
// scroll amount applied to each mouse wheel step
wheelStep : 20 ,
// scroll amount applied when user is using gestures
touchScrollStep : 200 ,
// sets border radius
borderRadius : '7px' ,
// sets border radius of the rail
railBorderRadius : '7px'
} ;
var o = $ . extend ( defaults , options ) ;
// do it for every element that matches selector
this . each ( function ( ) {
var isOverPanel , isOverBar , isDragg , queueHide , touchDif ,
barHeight , percentScroll , lastScroll ,
divS = '<div></div>' ,
minBarHeight = 30 ,
releaseScroll = false ;
// used in event handlers and for better minification
var me = $ ( this ) ;
// ensure we are not binding it again
if ( me . parent ( ) . hasClass ( o . wrapperClass ) )
{
// start from last bar position
var offset = me . scrollTop ( ) ;
// find bar and rail
bar = me . siblings ( '.' + o . barClass ) ;
rail = me . siblings ( '.' + o . railClass ) ;
getBarHeight ( ) ;
// check if we should scroll existing instance
if ( $ . isPlainObject ( options ) )
{
// Pass height: auto to an existing slimscroll object to force a resize after contents have changed
if ( 'height' in options && options . height == 'auto' ) {
me . parent ( ) . css ( 'height' , 'auto' ) ;
me . css ( 'height' , 'auto' ) ;
var height = me . parent ( ) . parent ( ) . height ( ) ;
me . parent ( ) . css ( 'height' , height ) ;
me . css ( 'height' , height ) ;
} else if ( 'height' in options ) {
var h = options . height ;
me . parent ( ) . css ( 'height' , h ) ;
me . css ( 'height' , h ) ;
}
if ( 'scrollTo' in options )
{
// jump to a static point
offset = parseInt ( o . scrollTo ) ;
}
else if ( 'scrollBy' in options )
{
// jump by value pixels
offset += parseInt ( o . scrollBy ) ;
}
else if ( 'destroy' in options )
{
// remove slimscroll elements
bar . remove ( ) ;
rail . remove ( ) ;
me . unwrap ( ) ;
return ;
}
// scroll content by the given offset
scrollContent ( offset , false , true ) ;
}
return ;
}
else if ( $ . isPlainObject ( options ) )
{
if ( 'destroy' in options )
{
return ;
}
}
// optionally set height to the parent's height
o . height = ( o . height == 'auto' ) ? me . parent ( ) . height ( ) : o . height ;
// wrap content
var wrapper = $ ( divS )
. addClass ( o . wrapperClass )
. css ( {
position : 'relative' ,
overflow : 'hidden' ,
width : o . width ,
height : o . height
} ) ;
// update style for the div
me . css ( {
overflow : 'hidden' ,
width : o . width ,
height : o . height
} ) ;
// create scrollbar rail
var rail = $ ( divS )
. addClass ( o . railClass )
. css ( {
width : o . size ,
height : '100%' ,
position : 'absolute' ,
top : 0 ,
display : ( o . alwaysVisible && o . railVisible ) ? 'block' : 'none' ,
'border-radius' : o . railBorderRadius ,
background : o . railColor ,
opacity : o . railOpacity ,
zIndex : 90
} ) ;
// create scrollbar
var bar = $ ( divS )
. addClass ( o . barClass )
. css ( {
background : o . color ,
width : o . size ,
position : 'absolute' ,
top : 0 ,
opacity : o . opacity ,
display : o . alwaysVisible ? 'block' : 'none' ,
'border-radius' : o . borderRadius ,
BorderRadius : o . borderRadius ,
MozBorderRadius : o . borderRadius ,
WebkitBorderRadius : o . borderRadius ,
zIndex : 99
} ) ;
// set position
var posCss = ( o . position == 'right' ) ? { right : o . distance } : { left : o . distance } ;
rail . css ( posCss ) ;
bar . css ( posCss ) ;
// wrap it
me . wrap ( wrapper ) ;
// append to parent div
me . parent ( ) . append ( bar ) ;
me . parent ( ) . append ( rail ) ;
// make it draggable and no longer dependent on the jqueryUI
if ( o . railDraggable ) {
bar . bind ( "mousedown" , function ( e ) {
var $doc = $ ( document ) ;
isDragg = true ;
t = parseFloat ( bar . css ( 'top' ) ) ;
pageY = e . pageY ;
$doc . bind ( "mousemove.slimscroll" , function ( e ) {
currTop = t + e . pageY - pageY ;
bar . css ( 'top' , currTop ) ;
scrollContent ( 0 , bar . position ( ) . top , false ) ; // scroll content
} ) ;
$doc . bind ( "mouseup.slimscroll" , function ( e ) {
isDragg = false ; hideBar ( ) ;
$doc . unbind ( '.slimscroll' ) ;
} ) ;
return false ;
} ) . bind ( "selectstart.slimscroll" , function ( e ) {
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
return false ;
} ) ;
}
// on rail over
rail . hover ( function ( ) {
showBar ( ) ;
} , function ( ) {
hideBar ( ) ;
} ) ;
// on bar over
bar . hover ( function ( ) {
isOverBar = true ;
} , function ( ) {
isOverBar = false ;
} ) ;
// show on parent mouseover
me . hover ( function ( ) {
isOverPanel = true ;
showBar ( ) ;
hideBar ( ) ;
} , function ( ) {
isOverPanel = false ;
hideBar ( ) ;
} ) ;
// support for mobile
me . bind ( 'touchstart' , function ( e , b ) {
if ( e . originalEvent . touches . length )
{
// record where touch started
touchDif = e . originalEvent . touches [ 0 ] . pageY ;
}
} ) ;
me . bind ( 'touchmove' , function ( e ) {
// prevent scrolling the page if necessary
if ( ! releaseScroll )
{
e . originalEvent . preventDefault ( ) ;
}
if ( e . originalEvent . touches . length )
{
// see how far user swiped
var diff = ( touchDif - e . originalEvent . touches [ 0 ] . pageY ) / o . touchScrollStep ;
// scroll content
scrollContent ( diff , true ) ;
touchDif = e . originalEvent . touches [ 0 ] . pageY ;
}
} ) ;
// set up initial height
getBarHeight ( ) ;
// check start position
if ( o . start === 'bottom' )
{
// scroll content to bottom
bar . css ( { top : me . outerHeight ( ) - bar . outerHeight ( ) } ) ;
scrollContent ( 0 , true ) ;
}
else if ( o . start !== 'top' )
{
// assume jQuery selector
scrollContent ( $ ( o . start ) . position ( ) . top , null , true ) ;
// make sure bar stays hidden
if ( ! o . alwaysVisible ) { bar . hide ( ) ; }
}
// attach scroll events
attachWheel ( this ) ;
function _onWheel ( e )
{
// use mouse wheel only when mouse is over
if ( ! isOverPanel ) { return ; }
var e = e || window . event ;
var delta = 0 ;
if ( e . wheelDelta ) { delta = - e . wheelDelta / 120 ; }
if ( e . detail ) { delta = e . detail / 3 ; }
var target = e . target || e . srcTarget || e . srcElement ;
if ( $ ( target ) . closest ( '.' + o . wrapperClass ) . is ( me . parent ( ) ) ) {
// scroll content
scrollContent ( delta , true ) ;
}
// stop window scroll
if ( e . preventDefault && ! releaseScroll ) { e . preventDefault ( ) ; }
if ( ! releaseScroll ) { e . returnValue = false ; }
}
function scrollContent ( y , isWheel , isJump )
{
releaseScroll = false ;
var delta = y ;
var maxTop = me . outerHeight ( ) - bar . outerHeight ( ) ;
if ( isWheel )
{
// move bar with mouse wheel
delta = parseInt ( bar . css ( 'top' ) ) + y * parseInt ( o . wheelStep ) / 100 * bar . outerHeight ( ) ;
// move bar, make sure it doesn't go out
delta = Math . min ( Math . max ( delta , 0 ) , maxTop ) ;
// if scrolling down, make sure a fractional change to the
// scroll position isn't rounded away when the scrollbar's CSS is set
// this flooring of delta would happened automatically when
// bar.css is set below, but we floor here for clarity
delta = ( y > 0 ) ? Math . ceil ( delta ) : Math . floor ( delta ) ;
// scroll the scrollbar
bar . css ( { top : delta + 'px' } ) ;
}
// calculate actual scroll amount
percentScroll = parseInt ( bar . css ( 'top' ) ) / ( me . outerHeight ( ) - bar . outerHeight ( ) ) ;
delta = percentScroll * ( me [ 0 ] . scrollHeight - me . outerHeight ( ) ) ;
if ( isJump )
{
delta = y ;
var offsetTop = delta / me [ 0 ] . scrollHeight * me . outerHeight ( ) ;
offsetTop = Math . min ( Math . max ( offsetTop , 0 ) , maxTop ) ;
bar . css ( { top : offsetTop + 'px' } ) ;
}
// scroll content
me . scrollTop ( delta ) ;
// fire scrolling event
me . trigger ( 'slimscrolling' , ~ ~ delta ) ;
// ensure bar is visible
showBar ( ) ;
// trigger hide when scroll is stopped
hideBar ( ) ;
}
function attachWheel ( target )
{
if ( window . addEventListener )
{
target . addEventListener ( 'DOMMouseScroll' , _onWheel , false ) ;
target . addEventListener ( 'mousewheel' , _onWheel , false ) ;
}
else
{
document . attachEvent ( "onmousewheel" , _onWheel )
}
}
function getBarHeight ( )
{
// calculate scrollbar height and make sure it is not too small
barHeight = Math . max ( ( me . outerHeight ( ) / me [ 0 ] . scrollHeight ) * me . outerHeight ( ) , minBarHeight ) ;
bar . css ( { height : barHeight + 'px' } ) ;
// hide scrollbar if content is not long enough
var display = barHeight == me . outerHeight ( ) ? 'none' : 'block' ;
bar . css ( { display : display } ) ;
}
function showBar ( )
{
// recalculate bar height
getBarHeight ( ) ;
clearTimeout ( queueHide ) ;
// when bar reached top or bottom
if ( percentScroll == ~ ~ percentScroll )
{
//release wheel
releaseScroll = o . allowPageScroll ;
// publish approporiate event
if ( lastScroll != percentScroll )
{
var msg = ( ~ ~ percentScroll == 0 ) ? 'top' : 'bottom' ;
me . trigger ( 'slimscroll' , msg ) ;
}
}
else
{
releaseScroll = false ;
}
lastScroll = percentScroll ;
// show only when required
if ( barHeight >= me . outerHeight ( ) ) {
//allow window scroll
releaseScroll = true ;
return ;
}
bar . stop ( true , true ) . fadeIn ( 'fast' ) ;
if ( o . railVisible ) { rail . stop ( true , true ) . fadeIn ( 'fast' ) ; }
}
function hideBar ( )
{
// only hide when options allow it
if ( ! o . alwaysVisible )
{
queueHide = setTimeout ( function ( ) {
if ( ! ( o . disableFadeOut && isOverPanel ) && ! isOverBar && ! isDragg )
{
bar . fadeOut ( 'slow' ) ;
rail . fadeOut ( 'slow' ) ;
}
} , 1000 ) ;
}
}
} ) ;
// maintain chainability
return this ;
}
} ) ;
$ . fn . extend ( {
slimscroll : $ . fn . slimScroll
} ) ;
} ) ( jQuery ) ;
// This [jQuery](https://jquery.com/) plugin implements an `<iframe>`
// [transport](https://api.jquery.com/jQuery.ajax/#extending-ajax) so that
// `$.ajax()` calls support the uploading of files using standard HTML file
// input fields. This is done by switching the exchange from `XMLHttpRequest`
// to a hidden `iframe` element containing a form that is submitted.
// The [source for the plugin](https://github.com/cmlenz/jquery-iframe-transport)
// is available on [Github](https://github.com/) and licensed under the [MIT
// license](https://github.com/cmlenz/jquery-iframe-transport/blob/master/LICENSE).
// ## Usage
// To use this plugin, you simply add an `iframe` option with the value `true`
// to the Ajax settings an `$.ajax()` call, and specify the file fields to
// include in the submssion using the `files` option, which can be a selector,
// jQuery object, or a list of DOM elements containing one or more
// `<input type="file">` elements:
// $("#myform").submit(function() {
// $.ajax(this.action, {
// files: $(":file", this),
// iframe: true
// }).complete(function(data) {
// console.log(data);
// });
// });
// The plugin will construct hidden `<iframe>` and `<form>` elements, add the
// file field(s) to that form, submit the form, and process the response.
// If you want to include other form fields in the form submission, include
// them in the `data` option, and set the `processData` option to `false`:
// $("#myform").submit(function() {
// $.ajax(this.action, {
// data: $(":text", this).serializeArray(),
// files: $(":file", this),
// iframe: true,
// processData: false
// }).complete(function(data) {
// console.log(data);
// });
// });
// ### Response Data Types
// As the transport does not have access to the HTTP headers of the server
// response, it is not as simple to make use of the automatic content type
// detection provided by jQuery as with regular XHR. If you can't set the
// expected response data type (for example because it may vary depending on
// the outcome of processing by the server), you will need to employ a
// workaround on the server side: Send back an HTML document containing just a
// `<textarea>` element with a `data-type` attribute that specifies the MIME
// type, and put the actual payload in the textarea:
// <textarea data-type="application/json">
// {"ok": true, "message": "Thanks so much"}
// </textarea>
// The iframe transport plugin will detect this and pass the value of the
// `data-type` attribute on to jQuery as if it was the "Content-Type" response
// header, thereby enabling the same kind of conversions that jQuery applies
// to regular responses. For the example above you should get a Javascript
// object as the `data` parameter of the `complete` callback, with the
// properties `ok: true` and `message: "Thanks so much"`.
// ### Handling Server Errors
// Another problem with using an `iframe` for file uploads is that it is
// impossible for the javascript code to determine the HTTP status code of the
// servers response. Effectively, all of the calls you make will look like they
// are getting successful responses, and thus invoke the `done()` or
// `complete()` callbacks. You can only communicate problems using the content
// of the response payload. For example, consider using a JSON response such as
// the following to indicate a problem with an uploaded file:
// <textarea data-type="application/json">
// {"ok": false, "message": "Please only upload reasonably sized files."}
// </textarea>
// ### Compatibility
// This plugin has primarily been tested on Safari 5 (or later), Firefox 4 (or
// later), and Internet Explorer (all the way back to version 6). While I
// haven't found any issues with it so far, I'm fairly sure it still doesn't
// work around all the quirks in all different browsers. But the code is still
// pretty simple overall, so you should be able to fix it and contribute a
// patch :)
// ## Annotated Source
( function ( $ , undefined ) {
"use strict" ;
// Register a prefilter that checks whether the `iframe` option is set, and
// switches to the "iframe" data type if it is `true`.
$ . ajaxPrefilter ( function ( options , origOptions , jqXHR ) {
if ( options . iframe ) {
options . originalURL = options . url ;
return "iframe" ;
}
} ) ;
// Register a transport for the "iframe" data type. It will only activate
// when the "files" option has been set to a non-empty list of enabled file
// inputs.
$ . ajaxTransport ( "iframe" , function ( options , origOptions , jqXHR ) {
var form = null ,
iframe = null ,
name = "iframe-" + $ . now ( ) ,
files = $ ( options . files ) . filter ( ":file:enabled" ) ,
markers = null ,
accepts = null ;
// This function gets called after a successful submission or an abortion
// and should revert all changes made to the page to enable the
// submission via this transport.
function cleanUp ( ) {
files . each ( function ( i , file ) {
var $file = $ ( file ) ;
$file . data ( "clone" ) . replaceWith ( $file ) ;
} ) ;
form . remove ( ) ;
iframe . one ( "load" , function ( ) { iframe . remove ( ) ; } ) ;
iframe . attr ( "src" , "javascript:false;" ) ;
}
// Remove "iframe" from the data types list so that further processing is
// based on the content type returned by the server, without attempting an
// (unsupported) conversion from "iframe" to the actual type.
options . dataTypes . shift ( ) ;
// Use the data from the original AJAX options, as it doesn't seem to be
// copied over since jQuery 1.7.
// See https://github.com/cmlenz/jquery-iframe-transport/issues/6
options . data = origOptions . data ;
if ( files . length ) {
form = $ ( "<form enctype='multipart/form-data' method='post'></form>" ) .
hide ( ) . attr ( { action : options . originalURL , target : name } ) ;
// If there is any additional data specified via the `data` option,
// we add it as hidden fields to the form. This (currently) requires
// the `processData` option to be set to false so that the data doesn't
// get serialized to a string.
if ( typeof ( options . data ) === "string" && options . data . length > 0 ) {
$ . error ( "data must not be serialized" ) ;
}
$ . each ( options . data || { } , function ( name , value ) {
if ( $ . isPlainObject ( value ) ) {
name = value . name ;
value = value . value ;
}
$ ( "<input type='hidden' />" ) . attr ( { name : name , value : value } ) .
appendTo ( form ) ;
} ) ;
// Add a hidden `X-Requested-With` field with the value `IFrame` to the
// field, to help server-side code to determine that the upload happened
// through this transport.
$ ( "<input type='hidden' value='IFrame' name='X-Requested-With' />" ) .
appendTo ( form ) ;
// Borrowed straight from the JQuery source.
// Provides a way of specifying the accepted data type similar to the
// HTTP "Accept" header
if ( options . dataTypes [ 0 ] && options . accepts [ options . dataTypes [ 0 ] ] ) {
accepts = options . accepts [ options . dataTypes [ 0 ] ] +
( options . dataTypes [ 0 ] !== "*" ? ", */*; q=0.01" : "" ) ;
} else {
accepts = options . accepts [ "*" ] ;
}
$ ( "<input type='hidden' name='X-HTTP-Accept'>" ) .
attr ( "value" , accepts ) . appendTo ( form ) ;
// Move the file fields into the hidden form, but first remember their
// original locations in the document by replacing them with disabled
// clones. This should also avoid introducing unwanted changes to the
// page layout during submission.
markers = files . after ( function ( idx ) {
var $this = $ ( this ) ,
$clone = $this . clone ( ) . prop ( "disabled" , true ) ;
$this . data ( "clone" , $clone ) ;
return $clone ;
} ) . next ( ) ;
files . appendTo ( form ) ;
return {
// The `send` function is called by jQuery when the request should be
// sent.
send : function ( headers , completeCallback ) {
iframe = $ ( "<iframe src='javascript:false;' name='" + name +
"' id='" + name + "' style='display:none'></iframe>" ) ;
// The first load event gets fired after the iframe has been injected
// into the DOM, and is used to prepare the actual submission.
iframe . one ( "load" , function ( ) {
// The second load event gets fired when the response to the form
// submission is received. The implementation detects whether the
// actual payload is embedded in a `<textarea>` element, and
// prepares the required conversions to be made in that case.
iframe . one ( "load" , function ( ) {
var doc = this . contentWindow ? this . contentWindow . document :
( this . contentDocument ? this . contentDocument : this . document ) ,
root = doc . documentElement ? doc . documentElement : doc . body ,
textarea = root . getElementsByTagName ( "textarea" ) [ 0 ] ,
type = textarea && textarea . getAttribute ( "data-type" ) || null ,
status = textarea && textarea . getAttribute ( "data-status" ) || 200 ,
statusText = textarea && textarea . getAttribute ( "data-statusText" ) || "OK" ,
content = {
html : root . innerHTML ,
text : type ?
textarea . value :
root ? ( root . textContent || root . innerText ) : null
} ;
cleanUp ( ) ;
completeCallback ( status , statusText , content , type ?
( "Content-Type: " + type ) :
null ) ;
} ) ;
// Now that the load handler has been set up, submit the form.
form [ 0 ] . submit ( ) ;
} ) ;
// After everything has been set up correctly, the form and iframe
// get injected into the DOM so that the submission can be
// initiated.
$ ( "body" ) . append ( form , iframe ) ;
} ,
// The `abort` function is called by jQuery when the request should be
// aborted.
abort : function ( ) {
if ( iframe !== null ) {
iframe . unbind ( "load" ) . attr ( "src" , "javascript:false;" ) ;
cleanUp ( ) ;
}
}
} ;
}
} ) ;
} ) ( jQuery ) ;
/ *
* jQuery File Upload Plugin
* https : //github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010 , Sebastian Tschan
* https : //blueimp.net
*
* Licensed under the MIT license :
* https : //opensource.org/licenses/MIT
* /
/* jshint nomen:false */
/* global define, require, window, document, location, Blob, FormData */
; ( function ( factory ) {
'use strict' ;
if ( typeof define === 'function' && define . amd ) {
// Register as an anonymous AMD module:
define ( [
'jquery' ,
'jquery-ui/ui/widget'
] , factory ) ;
} else if ( typeof exports === 'object' ) {
// Node/CommonJS:
factory (
require ( 'jquery' ) ,
require ( './vendor/jquery.ui.widget' )
) ;
} else {
// Browser globals:
factory ( window . jQuery ) ;
}
} ( function ( $ ) {
'use strict' ;
// Detect file input support, based on
// http://viljamis.com/blog/2012/file-upload-support-on-mobile/
$ . support . fileInput = ! ( new RegExp (
// Handle devices which give false positives for the feature detection:
'(Android (1\\.[0156]|2\\.[01]))' +
'|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
'|(w(eb)?OSBrowser)|(webOS)' +
'|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
) . test ( window . navigator . userAgent ) ||
// Feature detection for all other devices:
$ ( '<input type="file">' ) . prop ( 'disabled' ) ) ;
// The FileReader API is not actually used, but works as feature detection,
// as some Safari versions (5?) support XHR file uploads via the FormData API,
// but not non-multipart XHR file uploads.
// window.XMLHttpRequestUpload is not available on IE10, so we check for
// window.ProgressEvent instead to detect XHR2 file upload capability:
$ . support . xhrFileUpload = ! ! ( window . ProgressEvent && window . FileReader ) ;
$ . support . xhrFormDataFileUpload = ! ! window . FormData ;
// Detect support for Blob slicing (required for chunked uploads):
$ . support . blobSlice = window . Blob && ( Blob . prototype . slice ||
Blob . prototype . webkitSlice || Blob . prototype . mozSlice ) ;
// Helper function to create drag handlers for dragover/dragenter/dragleave:
function getDragHandler ( type ) {
var isDragOver = type === 'dragover' ;
return function ( e ) {
e . dataTransfer = e . originalEvent && e . originalEvent . dataTransfer ;
var dataTransfer = e . dataTransfer ;
if ( dataTransfer && $ . inArray ( 'Files' , dataTransfer . types ) !== - 1 &&
this . _trigger (
type ,
$ . Event ( type , { delegatedEvent : e } )
) !== false ) {
e . preventDefault ( ) ;
if ( isDragOver ) {
dataTransfer . dropEffect = 'copy' ;
}
}
} ;
}
// The fileupload widget listens for change events on file input fields defined
// via fileInput setting and paste or drop events of the given dropZone.
// In addition to the default jQuery Widget methods, the fileupload widget
// exposes the "add" and "send" methods, to add or directly send files using
// the fileupload API.
// By default, files added via file input selection, paste, drag & drop or
// "add" method are uploaded immediately, but it is possible to override
// the "add" callback option to queue file uploads.
$ . widget ( 'blueimp.fileupload' , {
options : {
// The drop target element(s), by the default the complete document.
// Set to null to disable drag & drop support:
dropZone : $ ( document ) ,
// The paste target element(s), by the default undefined.
// Set to a DOM node or jQuery object to enable file pasting:
pasteZone : undefined ,
// The file input field(s), that are listened to for change events.
// If undefined, it is set to the file input fields inside
// of the widget element on plugin initialization.
// Set to null to disable the change listener.
fileInput : undefined ,
// By default, the file input field is replaced with a clone after
// each input field change event. This is required for iframe transport
// queues and allows change events to be fired for the same file
// selection, but can be disabled by setting the following option to false:
replaceFileInput : true ,
// The parameter name for the file form data (the request argument name).
// If undefined or empty, the name property of the file input field is
// used, or "files[]" if the file input name property is also empty,
// can be a string or an array of strings:
paramName : undefined ,
// By default, each file of a selection is uploaded using an individual
// request for XHR type uploads. Set to false to upload file
// selections in one request each:
singleFileUploads : true ,
// To limit the number of files uploaded with one XHR request,
// set the following option to an integer greater than 0:
limitMultiFileUploads : undefined ,
// The following option limits the number of files uploaded with one
// XHR request to keep the request size under or equal to the defined
// limit in bytes:
limitMultiFileUploadSize : undefined ,
// Multipart file uploads add a number of bytes to each uploaded file,
// therefore the following option adds an overhead for each file used
// in the limitMultiFileUploadSize configuration:
limitMultiFileUploadSizeOverhead : 512 ,
// Set the following option to true to issue all file upload requests
// in a sequential order:
sequentialUploads : false ,
// To limit the number of concurrent uploads,
// set the following option to an integer greater than 0:
limitConcurrentUploads : undefined ,
// Set the following option to true to force iframe transport uploads:
forceIframeTransport : false ,
// Set the following option to the location of a redirect url on the
// origin server, for cross-domain iframe transport uploads:
redirect : undefined ,
// The parameter name for the redirect url, sent as part of the form
// data and set to 'redirect' if this option is empty:
redirectParamName : undefined ,
// Set the following option to the location of a postMessage window,
// to enable postMessage transport uploads:
postMessage : undefined ,
// By default, XHR file uploads are sent as multipart/form-data.
// The iframe transport is always using multipart/form-data.
// Set to false to enable non-multipart XHR uploads:
multipart : true ,
// To upload large files in smaller chunks, set the following option
// to a preferred maximum chunk size. If set to 0, null or undefined,
// or the browser does not support the required Blob API, files will
// be uploaded as a whole.
maxChunkSize : undefined ,
// When a non-multipart upload or a chunked multipart upload has been
// aborted, this option can be used to resume the upload by setting
// it to the size of the already uploaded bytes. This option is most
// useful when modifying the options object inside of the "add" or
// "send" callbacks, as the options are cloned for each file upload.
uploadedBytes : undefined ,
// By default, failed (abort or error) file uploads are removed from the
// global progress calculation. Set the following option to false to
// prevent recalculating the global progress data:
recalculateProgress : true ,
// Interval in milliseconds to calculate and trigger progress events:
progressInterval : 100 ,
// Interval in milliseconds to calculate progress bitrate:
bitrateInterval : 500 ,
// By default, uploads are started automatically when adding files:
autoUpload : true ,
// Error and info messages:
messages : {
uploadedBytes : 'Uploaded bytes exceed file size'
} ,
// Translation function, gets the message key to be translated
// and an object with context specific data as arguments:
i18n : function ( message , context ) {
message = this . messages [ message ] || message . toString ( ) ;
if ( context ) {
$ . each ( context , function ( key , value ) {
message = message . replace ( '{' + key + '}' , value ) ;
} ) ;
}
return message ;
} ,
// Additional form data to be sent along with the file uploads can be set
// using this option, which accepts an array of objects with name and
// value properties, a function returning such an array, a FormData
// object (for XHR file uploads), or a simple object.
// The form of the first fileInput is given as parameter to the function:
formData : function ( form ) {
return form . serializeArray ( ) ;
} ,
// The add callback is invoked as soon as files are added to the fileupload
// widget (via file input selection, drag & drop, paste or add API call).
// If the singleFileUploads option is enabled, this callback will be
// called once for each file in the selection for XHR file uploads, else
// once for each file selection.
//
// The upload starts when the submit method is invoked on the data parameter.
// The data object contains a files property holding the added files
// and allows you to override plugin options as well as define ajax settings.
//
// Listeners for this callback can also be bound the following way:
// .bind('fileuploadadd', func);
//
// data.submit() returns a Promise object and allows to attach additional
// handlers using jQuery's Deferred callbacks:
// data.submit().done(func).fail(func).always(func);
add : function ( e , data ) {
if ( e . isDefaultPrevented ( ) ) {
return false ;
}
if ( data . autoUpload || ( data . autoUpload !== false &&
$ ( this ) . fileupload ( 'option' , 'autoUpload' ) ) ) {
data . process ( ) . done ( function ( ) {
data . submit ( ) ;
} ) ;
}
} ,
// Other callbacks:
// Callback for the submit event of each file upload:
// submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
// Callback for the start of each file upload request:
// send: function (e, data) {}, // .bind('fileuploadsend', func);
// Callback for successful uploads:
// done: function (e, data) {}, // .bind('fileuploaddone', func);
// Callback for failed (abort or error) uploads:
// fail: function (e, data) {}, // .bind('fileuploadfail', func);
// Callback for completed (success, abort or error) requests:
// always: function (e, data) {}, // .bind('fileuploadalways', func);
// Callback for upload progress events:
// progress: function (e, data) {}, // .bind('fileuploadprogress', func);
// Callback for global upload progress events:
// progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
// Callback for uploads start, equivalent to the global ajaxStart event:
// start: function (e) {}, // .bind('fileuploadstart', func);
// Callback for uploads stop, equivalent to the global ajaxStop event:
// stop: function (e) {}, // .bind('fileuploadstop', func);
// Callback for change events of the fileInput(s):
// change: function (e, data) {}, // .bind('fileuploadchange', func);
// Callback for paste events to the pasteZone(s):
// paste: function (e, data) {}, // .bind('fileuploadpaste', func);
// Callback for drop events of the dropZone(s):
// drop: function (e, data) {}, // .bind('fileuploaddrop', func);
// Callback for dragover events of the dropZone(s):
// dragover: function (e) {}, // .bind('fileuploaddragover', func);
// Callback for the start of each chunk upload request:
// chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
// Callback for successful chunk uploads:
// chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);
// Callback for failed (abort or error) chunk uploads:
// chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);
// Callback for completed (success, abort or error) chunk upload requests:
// chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);
// The plugin options are used as settings object for the ajax calls.
// The following are jQuery ajax settings required for the file uploads:
processData : false ,
contentType : false ,
cache : false ,
timeout : 0
} ,
// A list of options that require reinitializing event listeners and/or
// special initialization code:
_specialOptions : [
'fileInput' ,
'dropZone' ,
'pasteZone' ,
'multipart' ,
'forceIframeTransport'
] ,
_blobSlice : $ . support . blobSlice && function ( ) {
var slice = this . slice || this . webkitSlice || this . mozSlice ;
return slice . apply ( this , arguments ) ;
} ,
_BitrateTimer : function ( ) {
this . timestamp = ( ( Date . now ) ? Date . now ( ) : ( new Date ( ) ) . getTime ( ) ) ;
this . loaded = 0 ;
this . bitrate = 0 ;
this . getBitrate = function ( now , loaded , interval ) {
var timeDiff = now - this . timestamp ;
if ( ! this . bitrate || ! interval || timeDiff > interval ) {
this . bitrate = ( loaded - this . loaded ) * ( 1000 / timeDiff ) * 8 ;
this . loaded = loaded ;
this . timestamp = now ;
}
return this . bitrate ;
} ;
} ,
_isXHRUpload : function ( options ) {
return ! options . forceIframeTransport &&
( ( ! options . multipart && $ . support . xhrFileUpload ) ||
$ . support . xhrFormDataFileUpload ) ;
} ,
_getFormData : function ( options ) {
var formData ;
if ( $ . type ( options . formData ) === 'function' ) {
return options . formData ( options . form ) ;
}
if ( $ . isArray ( options . formData ) ) {
return options . formData ;
}
if ( $ . type ( options . formData ) === 'object' ) {
formData = [ ] ;
$ . each ( options . formData , function ( name , value ) {
formData . push ( { name : name , value : value } ) ;
} ) ;
return formData ;
}
return [ ] ;
} ,
_getTotal : function ( files ) {
var total = 0 ;
$ . each ( files , function ( index , file ) {
total += file . size || 1 ;
} ) ;
return total ;
} ,
_initProgressObject : function ( obj ) {
var progress = {
loaded : 0 ,
total : 0 ,
bitrate : 0
} ;
if ( obj . _progress ) {
$ . extend ( obj . _progress , progress ) ;
} else {
obj . _progress = progress ;
}
} ,
_initResponseObject : function ( obj ) {
var prop ;
if ( obj . _response ) {
for ( prop in obj . _response ) {
if ( obj . _response . hasOwnProperty ( prop ) ) {
delete obj . _response [ prop ] ;
}
}
} else {
obj . _response = { } ;
}
} ,
_onProgress : function ( e , data ) {
if ( e . lengthComputable ) {
var now = ( ( Date . now ) ? Date . now ( ) : ( new Date ( ) ) . getTime ( ) ) ,
loaded ;
if ( data . _time && data . progressInterval &&
( now - data . _time < data . progressInterval ) &&
e . loaded !== e . total ) {
return ;
}
data . _time = now ;
loaded = Math . floor (
e . loaded / e . total * ( data . chunkSize || data . _progress . total )
) + ( data . uploadedBytes || 0 ) ;
// Add the difference from the previously loaded state
// to the global loaded counter:
this . _progress . loaded += ( loaded - data . _progress . loaded ) ;
this . _progress . bitrate = this . _bitrateTimer . getBitrate (
now ,
this . _progress . loaded ,
data . bitrateInterval
) ;
data . _progress . loaded = data . loaded = loaded ;
data . _progress . bitrate = data . bitrate = data . _bitrateTimer . getBitrate (
now ,
loaded ,
data . bitrateInterval
) ;
// Trigger a custom progress event with a total data property set
// to the file size(s) of the current upload and a loaded data
// property calculated accordingly:
this . _trigger (
'progress' ,
$ . Event ( 'progress' , { delegatedEvent : e } ) ,
data
) ;
// Trigger a global progress event for all current file uploads,
// including ajax calls queued for sequential file uploads:
this . _trigger (
'progressall' ,
$ . Event ( 'progressall' , { delegatedEvent : e } ) ,
this . _progress
) ;
}
} ,
_initProgressListener : function ( options ) {
var that = this ,
xhr = options . xhr ? options . xhr ( ) : $ . ajaxSettings . xhr ( ) ;
// Accesss to the native XHR object is required to add event listeners
// for the upload progress event:
if ( xhr . upload ) {
$ ( xhr . upload ) . bind ( 'progress' , function ( e ) {
var oe = e . originalEvent ;
// Make sure the progress event properties get copied over:
e . lengthComputable = oe . lengthComputable ;
e . loaded = oe . loaded ;
e . total = oe . total ;
that . _onProgress ( e , options ) ;
} ) ;
options . xhr = function ( ) {
return xhr ;
} ;
}
} ,
_isInstanceOf : function ( type , obj ) {
// Cross-frame instanceof check
return Object . prototype . toString . call ( obj ) === '[object ' + type + ']' ;
} ,
_initXHRData : function ( options ) {
var that = this ,
formData ,
file = options . files [ 0 ] ,
// Ignore non-multipart setting if not supported:
multipart = options . multipart || ! $ . support . xhrFileUpload ,
paramName = $ . type ( options . paramName ) === 'array' ?
options . paramName [ 0 ] : options . paramName ;
options . headers = $ . extend ( { } , options . headers ) ;
if ( options . contentRange ) {
options . headers [ 'Content-Range' ] = options . contentRange ;
}
if ( ! multipart || options . blob || ! this . _isInstanceOf ( 'File' , file ) ) {
options . headers [ 'Content-Disposition' ] = 'attachment; filename="' +
encodeURI ( file . name ) + '"' ;
}
if ( ! multipart ) {
options . contentType = file . type || 'application/octet-stream' ;
options . data = options . blob || file ;
} else if ( $ . support . xhrFormDataFileUpload ) {
if ( options . postMessage ) {
// window.postMessage does not allow sending FormData
// objects, so we just add the File/Blob objects to
// the formData array and let the postMessage window
// create the FormData object out of this array:
formData = this . _getFormData ( options ) ;
if ( options . blob ) {
formData . push ( {
name : paramName ,
value : options . blob
} ) ;
} else {
$ . each ( options . files , function ( index , file ) {
formData . push ( {
name : ( $ . type ( options . paramName ) === 'array' &&
options . paramName [ index ] ) || paramName ,
value : file
} ) ;
} ) ;
}
} else {
if ( that . _isInstanceOf ( 'FormData' , options . formData ) ) {
formData = options . formData ;
} else {
formData = new FormData ( ) ;
$ . each ( this . _getFormData ( options ) , function ( index , field ) {
formData . append ( field . name , field . value ) ;
} ) ;
}
if ( options . blob ) {
formData . append ( paramName , options . blob , file . name ) ;
} else {
$ . each ( options . files , function ( index , file ) {
// This check allows the tests to run with
// dummy objects:
if ( that . _isInstanceOf ( 'File' , file ) ||
that . _isInstanceOf ( 'Blob' , file ) ) {
formData . append (
( $ . type ( options . paramName ) === 'array' &&
options . paramName [ index ] ) || paramName ,
file ,
file . uploadName || file . name
) ;
}
} ) ;
}
}
options . data = formData ;
}
// Blob reference is not needed anymore, free memory:
options . blob = null ;
} ,
_initIframeSettings : function ( options ) {
var targetHost = $ ( '<a></a>' ) . prop ( 'href' , options . url ) . prop ( 'host' ) ;
// Setting the dataType to iframe enables the iframe transport:
options . dataType = 'iframe ' + ( options . dataType || '' ) ;
// The iframe transport accepts a serialized array as form data:
options . formData = this . _getFormData ( options ) ;
// Add redirect url to form data on cross-domain uploads:
if ( options . redirect && targetHost && targetHost !== location . host ) {
options . formData . push ( {
name : options . redirectParamName || 'redirect' ,
value : options . redirect
} ) ;
}
} ,
_initDataSettings : function ( options ) {
if ( this . _isXHRUpload ( options ) ) {
if ( ! this . _chunkedUpload ( options , true ) ) {
if ( ! options . data ) {
this . _initXHRData ( options ) ;
}
this . _initProgressListener ( options ) ;
}
if ( options . postMessage ) {
// Setting the dataType to postmessage enables the
// postMessage transport:
options . dataType = 'postmessage ' + ( options . dataType || '' ) ;
}
} else {
this . _initIframeSettings ( options ) ;
}
} ,
_getParamName : function ( options ) {
var fileInput = $ ( options . fileInput ) ,
paramName = options . paramName ;
if ( ! paramName ) {
paramName = [ ] ;
fileInput . each ( function ( ) {
var input = $ ( this ) ,
name = input . prop ( 'name' ) || 'files[]' ,
i = ( input . prop ( 'files' ) || [ 1 ] ) . length ;
while ( i ) {
paramName . push ( name ) ;
i -= 1 ;
}
} ) ;
if ( ! paramName . length ) {
paramName = [ fileInput . prop ( 'name' ) || 'files[]' ] ;
}
} else if ( ! $ . isArray ( paramName ) ) {
paramName = [ paramName ] ;
}
return paramName ;
} ,
_initFormSettings : function ( options ) {
// Retrieve missing options from the input field and the
// associated form, if available:
if ( ! options . form || ! options . form . length ) {
options . form = $ ( options . fileInput . prop ( 'form' ) ) ;
// If the given file input doesn't have an associated form,
// use the default widget file input's form:
if ( ! options . form . length ) {
options . form = $ ( this . options . fileInput . prop ( 'form' ) ) ;
}
}
options . paramName = this . _getParamName ( options ) ;
if ( ! options . url ) {
options . url = options . form . prop ( 'action' ) || location . href ;
}
// The HTTP request method must be "POST" or "PUT":
options . type = ( options . type ||
( $ . type ( options . form . prop ( 'method' ) ) === 'string' &&
options . form . prop ( 'method' ) ) || ''
) . toUpperCase ( ) ;
if ( options . type !== 'POST' && options . type !== 'PUT' &&
options . type !== 'PATCH' ) {
options . type = 'POST' ;
}
if ( ! options . formAcceptCharset ) {
options . formAcceptCharset = options . form . attr ( 'accept-charset' ) ;
}
} ,
_getAJAXSettings : function ( data ) {
var options = $ . extend ( { } , this . options , data ) ;
this . _initFormSettings ( options ) ;
this . _initDataSettings ( options ) ;
return options ;
} ,
// jQuery 1.6 doesn't provide .state(),
// while jQuery 1.8+ removed .isRejected() and .isResolved():
_getDeferredState : function ( deferred ) {
if ( deferred . state ) {
return deferred . state ( ) ;
}
if ( deferred . isResolved ( ) ) {
return 'resolved' ;
}
if ( deferred . isRejected ( ) ) {
return 'rejected' ;
}
return 'pending' ;
} ,
// Maps jqXHR callbacks to the equivalent
// methods of the given Promise object:
_enhancePromise : function ( promise ) {
promise . success = promise . done ;
promise . error = promise . fail ;
promise . complete = promise . always ;
return promise ;
} ,
// Creates and returns a Promise object enhanced with
// the jqXHR methods abort, success, error and complete:
_getXHRPromise : function ( resolveOrReject , context , args ) {
var dfd = $ . Deferred ( ) ,
promise = dfd . promise ( ) ;
context = context || this . options . context || promise ;
if ( resolveOrReject === true ) {
dfd . resolveWith ( context , args ) ;
} else if ( resolveOrReject === false ) {
dfd . rejectWith ( context , args ) ;
}
promise . abort = dfd . promise ;
return this . _enhancePromise ( promise ) ;
} ,
// Adds convenience methods to the data callback argument:
_addConvenienceMethods : function ( e , data ) {
var that = this ,
getPromise = function ( args ) {
return $ . Deferred ( ) . resolveWith ( that , args ) . promise ( ) ;
} ;
data . process = function ( resolveFunc , rejectFunc ) {
if ( resolveFunc || rejectFunc ) {
data . _processQueue = this . _processQueue =
( this . _processQueue || getPromise ( [ this ] ) ) . then (
function ( ) {
if ( data . errorThrown ) {
return $ . Deferred ( )
. rejectWith ( that , [ data ] ) . promise ( ) ;
}
return getPromise ( arguments ) ;
}
) . then ( resolveFunc , rejectFunc ) ;
}
return this . _processQueue || getPromise ( [ this ] ) ;
} ;
data . submit = function ( ) {
if ( this . state ( ) !== 'pending' ) {
data . jqXHR = this . jqXHR =
( that . _trigger (
'submit' ,
$ . Event ( 'submit' , { delegatedEvent : e } ) ,
this
) !== false ) && that . _onSend ( e , this ) ;
}
return this . jqXHR || that . _getXHRPromise ( ) ;
} ;
data . abort = function ( ) {
if ( this . jqXHR ) {
return this . jqXHR . abort ( ) ;
}
this . errorThrown = 'abort' ;
that . _trigger ( 'fail' , null , this ) ;
return that . _getXHRPromise ( false ) ;
} ;
data . state = function ( ) {
if ( this . jqXHR ) {
return that . _getDeferredState ( this . jqXHR ) ;
}
if ( this . _processQueue ) {
return that . _getDeferredState ( this . _processQueue ) ;
}
} ;
data . processing = function ( ) {
return ! this . jqXHR && this . _processQueue && that
. _getDeferredState ( this . _processQueue ) === 'pending' ;
} ;
data . progress = function ( ) {
return this . _progress ;
} ;
data . response = function ( ) {
return this . _response ;
} ;
} ,
// Parses the Range header from the server response
// and returns the uploaded bytes:
_getUploadedBytes : function ( jqXHR ) {
var range = jqXHR . getResponseHeader ( 'Range' ) ,
parts = range && range . split ( '-' ) ,
upperBytesPos = parts && parts . length > 1 &&
parseInt ( parts [ 1 ] , 10 ) ;
return upperBytesPos && upperBytesPos + 1 ;
} ,
// Uploads a file in multiple, sequential requests
// by splitting the file up in multiple blob chunks.
// If the second parameter is true, only tests if the file
// should be uploaded in chunks, but does not invoke any
// upload requests:
_chunkedUpload : function ( options , testOnly ) {
options . uploadedBytes = options . uploadedBytes || 0 ;
var that = this ,
file = options . files [ 0 ] ,
fs = file . size ,
ub = options . uploadedBytes ,
mcs = options . maxChunkSize || fs ,
slice = this . _blobSlice ,
dfd = $ . Deferred ( ) ,
promise = dfd . promise ( ) ,
jqXHR ,
upload ;
if ( ! ( this . _isXHRUpload ( options ) && slice && ( ub || ( $ . type ( mcs ) === 'function' ? mcs ( options ) : mcs ) < fs ) ) ||
options . data ) {
return false ;
}
if ( testOnly ) {
return true ;
}
if ( ub >= fs ) {
file . error = options . i18n ( 'uploadedBytes' ) ;
return this . _getXHRPromise (
false ,
options . context ,
[ null , 'error' , file . error ]
) ;
}
// The chunk upload method:
upload = function ( ) {
// Clone the options object for each chunk upload:
var o = $ . extend ( { } , options ) ,
currentLoaded = o . _progress . loaded ;
o . blob = slice . call (
file ,
ub ,
ub + ( $ . type ( mcs ) === 'function' ? mcs ( o ) : mcs ) ,
file . type
) ;
// Store the current chunk size, as the blob itself
// will be dereferenced after data processing:
o . chunkSize = o . blob . size ;
// Expose the chunk bytes position range:
o . contentRange = 'bytes ' + ub + '-' +
( ub + o . chunkSize - 1 ) + '/' + fs ;
// Process the upload data (the blob and potential form data):
that . _initXHRData ( o ) ;
// Add progress listeners for this chunk upload:
that . _initProgressListener ( o ) ;
jqXHR = ( ( that . _trigger ( 'chunksend' , null , o ) !== false && $ . ajax ( o ) ) ||
that . _getXHRPromise ( false , o . context ) )
. done ( function ( result , textStatus , jqXHR ) {
ub = that . _getUploadedBytes ( jqXHR ) ||
( ub + o . chunkSize ) ;
// Create a progress event if no final progress event
// with loaded equaling total has been triggered
// for this chunk:
if ( currentLoaded + o . chunkSize - o . _progress . loaded ) {
that . _onProgress ( $ . Event ( 'progress' , {
lengthComputable : true ,
loaded : ub - o . uploadedBytes ,
total : ub - o . uploadedBytes
} ) , o ) ;
}
options . uploadedBytes = o . uploadedBytes = ub ;
o . result = result ;
o . textStatus = textStatus ;
o . jqXHR = jqXHR ;
that . _trigger ( 'chunkdone' , null , o ) ;
that . _trigger ( 'chunkalways' , null , o ) ;
if ( ub < fs ) {
// File upload not yet complete,
// continue with the next chunk:
upload ( ) ;
} else {
dfd . resolveWith (
o . context ,
[ result , textStatus , jqXHR ]
) ;
}
} )
. fail ( function ( jqXHR , textStatus , errorThrown ) {
o . jqXHR = jqXHR ;
o . textStatus = textStatus ;
o . errorThrown = errorThrown ;
that . _trigger ( 'chunkfail' , null , o ) ;
that . _trigger ( 'chunkalways' , null , o ) ;
dfd . rejectWith (
o . context ,
[ jqXHR , textStatus , errorThrown ]
) ;
} ) ;
} ;
this . _enhancePromise ( promise ) ;
promise . abort = function ( ) {
return jqXHR . abort ( ) ;
} ;
upload ( ) ;
return promise ;
} ,
_beforeSend : function ( e , data ) {
if ( this . _active === 0 ) {
// the start callback is triggered when an upload starts
// and no other uploads are currently running,
// equivalent to the global ajaxStart event:
this . _trigger ( 'start' ) ;
// Set timer for global bitrate progress calculation:
this . _bitrateTimer = new this . _BitrateTimer ( ) ;
// Reset the global progress values:
this . _progress . loaded = this . _progress . total = 0 ;
this . _progress . bitrate = 0 ;
}
// Make sure the container objects for the .response() and
// .progress() methods on the data object are available
// and reset to their initial state:
this . _initResponseObject ( data ) ;
this . _initProgressObject ( data ) ;
data . _progress . loaded = data . loaded = data . uploadedBytes || 0 ;
data . _progress . total = data . total = this . _getTotal ( data . files ) || 1 ;
data . _progress . bitrate = data . bitrate = 0 ;
this . _active += 1 ;
// Initialize the global progress values:
this . _progress . loaded += data . loaded ;
this . _progress . total += data . total ;
} ,
_onDone : function ( result , textStatus , jqXHR , options ) {
var total = options . _progress . total ,
response = options . _response ;
if ( options . _progress . loaded < total ) {
// Create a progress event if no final progress event
// with loaded equaling total has been triggered:
this . _onProgress ( $ . Event ( 'progress' , {
lengthComputable : true ,
loaded : total ,
total : total
} ) , options ) ;
}
response . result = options . result = result ;
response . textStatus = options . textStatus = textStatus ;
response . jqXHR = options . jqXHR = jqXHR ;
this . _trigger ( 'done' , null , options ) ;
} ,
_onFail : function ( jqXHR , textStatus , errorThrown , options ) {
var response = options . _response ;
if ( options . recalculateProgress ) {
// Remove the failed (error or abort) file upload from
// the global progress calculation:
this . _progress . loaded -= options . _progress . loaded ;
this . _progress . total -= options . _progress . total ;
}
response . jqXHR = options . jqXHR = jqXHR ;
response . textStatus = options . textStatus = textStatus ;
response . errorThrown = options . errorThrown = errorThrown ;
this . _trigger ( 'fail' , null , options ) ;
} ,
_onAlways : function ( jqXHRorResult , textStatus , jqXHRorError , options ) {
// jqXHRorResult, textStatus and jqXHRorError are added to the
// options object via done and fail callbacks
this . _trigger ( 'always' , null , options ) ;
} ,
_onSend : function ( e , data ) {
if ( ! data . submit ) {
this . _addConvenienceMethods ( e , data ) ;
}
var that = this ,
jqXHR ,
aborted ,
slot ,
pipe ,
options = that . _getAJAXSettings ( data ) ,
send = function ( ) {
that . _sending += 1 ;
// Set timer for bitrate progress calculation:
options . _bitrateTimer = new that . _BitrateTimer ( ) ;
jqXHR = jqXHR || (
( ( aborted || that . _trigger (
'send' ,
$ . Event ( 'send' , { delegatedEvent : e } ) ,
options
) === false ) &&
that . _getXHRPromise ( false , options . context , aborted ) ) ||
that . _chunkedUpload ( options ) || $ . ajax ( options )
) . done ( function ( result , textStatus , jqXHR ) {
that . _onDone ( result , textStatus , jqXHR , options ) ;
} ) . fail ( function ( jqXHR , textStatus , errorThrown ) {
that . _onFail ( jqXHR , textStatus , errorThrown , options ) ;
} ) . always ( function ( jqXHRorResult , textStatus , jqXHRorError ) {
that . _onAlways (
jqXHRorResult ,
textStatus ,
jqXHRorError ,
options
) ;
that . _sending -= 1 ;
that . _active -= 1 ;
if ( options . limitConcurrentUploads &&
options . limitConcurrentUploads > that . _sending ) {
// Start the next queued upload,
// that has not been aborted:
var nextSlot = that . _slots . shift ( ) ;
while ( nextSlot ) {
if ( that . _getDeferredState ( nextSlot ) === 'pending' ) {
nextSlot . resolve ( ) ;
break ;
}
nextSlot = that . _slots . shift ( ) ;
}
}
if ( that . _active === 0 ) {
// The stop callback is triggered when all uploads have
// been completed, equivalent to the global ajaxStop event:
that . _trigger ( 'stop' ) ;
}
} ) ;
return jqXHR ;
} ;
this . _beforeSend ( e , options ) ;
if ( this . options . sequentialUploads ||
( this . options . limitConcurrentUploads &&
this . options . limitConcurrentUploads <= this . _sending ) ) {
if ( this . options . limitConcurrentUploads > 1 ) {
slot = $ . Deferred ( ) ;
this . _slots . push ( slot ) ;
pipe = slot . then ( send ) ;
} else {
this . _sequence = this . _sequence . then ( send , send ) ;
pipe = this . _sequence ;
}
// Return the piped Promise object, enhanced with an abort method,
// which is delegated to the jqXHR object of the current upload,
// and jqXHR callbacks mapped to the equivalent Promise methods:
pipe . abort = function ( ) {
aborted = [ undefined , 'abort' , 'abort' ] ;
if ( ! jqXHR ) {
if ( slot ) {
slot . rejectWith ( options . context , aborted ) ;
}
return send ( ) ;
}
return jqXHR . abort ( ) ;
} ;
return this . _enhancePromise ( pipe ) ;
}
return send ( ) ;
} ,
_onAdd : function ( e , data ) {
var that = this ,
result = true ,
options = $ . extend ( { } , this . options , data ) ,
files = data . files ,
filesLength = files . length ,
limit = options . limitMultiFileUploads ,
limitSize = options . limitMultiFileUploadSize ,
overhead = options . limitMultiFileUploadSizeOverhead ,
batchSize = 0 ,
paramName = this . _getParamName ( options ) ,
paramNameSet ,
paramNameSlice ,
fileSet ,
i ,
j = 0 ;
if ( ! filesLength ) {
return false ;
}
if ( limitSize && files [ 0 ] . size === undefined ) {
limitSize = undefined ;
}
if ( ! ( options . singleFileUploads || limit || limitSize ) ||
! this . _isXHRUpload ( options ) ) {
fileSet = [ files ] ;
paramNameSet = [ paramName ] ;
} else if ( ! ( options . singleFileUploads || limitSize ) && limit ) {
fileSet = [ ] ;
paramNameSet = [ ] ;
for ( i = 0 ; i < filesLength ; i += limit ) {
fileSet . push ( files . slice ( i , i + limit ) ) ;
paramNameSlice = paramName . slice ( i , i + limit ) ;
if ( ! paramNameSlice . length ) {
paramNameSlice = paramName ;
}
paramNameSet . push ( paramNameSlice ) ;
}
} else if ( ! options . singleFileUploads && limitSize ) {
fileSet = [ ] ;
paramNameSet = [ ] ;
for ( i = 0 ; i < filesLength ; i = i + 1 ) {
batchSize += files [ i ] . size + overhead ;
if ( i + 1 === filesLength ||
( ( batchSize + files [ i + 1 ] . size + overhead ) > limitSize ) ||
( limit && i + 1 - j >= limit ) ) {
fileSet . push ( files . slice ( j , i + 1 ) ) ;
paramNameSlice = paramName . slice ( j , i + 1 ) ;
if ( ! paramNameSlice . length ) {
paramNameSlice = paramName ;
}
paramNameSet . push ( paramNameSlice ) ;
j = i + 1 ;
batchSize = 0 ;
}
}
} else {
paramNameSet = paramName ;
}
data . originalFiles = files ;
$ . each ( fileSet || files , function ( index , element ) {
var newData = $ . extend ( { } , data ) ;
newData . files = fileSet ? element : [ element ] ;
newData . paramName = paramNameSet [ index ] ;
that . _initResponseObject ( newData ) ;
that . _initProgressObject ( newData ) ;
that . _addConvenienceMethods ( e , newData ) ;
result = that . _trigger (
'add' ,
$ . Event ( 'add' , { delegatedEvent : e } ) ,
newData
) ;
return result ;
} ) ;
return result ;
} ,
_replaceFileInput : function ( data ) {
var input = data . fileInput ,
inputClone = input . clone ( true ) ,
restoreFocus = input . is ( document . activeElement ) ;
// Add a reference for the new cloned file input to the data argument:
data . fileInputClone = inputClone ;
$ ( '<form></form>' ) . append ( inputClone ) [ 0 ] . reset ( ) ;
// Detaching allows to insert the fileInput on another form
// without loosing the file input value:
input . after ( inputClone ) . detach ( ) ;
// If the fileInput had focus before it was detached,
// restore focus to the inputClone.
if ( restoreFocus ) {
inputClone . focus ( ) ;
}
// Avoid memory leaks with the detached file input:
$ . cleanData ( input . unbind ( 'remove' ) ) ;
// Replace the original file input element in the fileInput
// elements set with the clone, which has been copied including
// event handlers:
this . options . fileInput = this . options . fileInput . map ( function ( i , el ) {
if ( el === input [ 0 ] ) {
return inputClone [ 0 ] ;
}
return el ;
} ) ;
// If the widget has been initialized on the file input itself,
// override this.element with the file input clone:
if ( input [ 0 ] === this . element [ 0 ] ) {
this . element = inputClone ;
}
} ,
_handleFileTreeEntry : function ( entry , path ) {
var that = this ,
dfd = $ . Deferred ( ) ,
entries = [ ] ,
dirReader ,
errorHandler = function ( e ) {
if ( e && ! e . entry ) {
e . entry = entry ;
}
// Since $.when returns immediately if one
// Deferred is rejected, we use resolve instead.
// This allows valid files and invalid items
// to be returned together in one set:
dfd . resolve ( [ e ] ) ;
} ,
successHandler = function ( entries ) {
that . _handleFileTreeEntries (
entries ,
path + entry . name + '/'
) . done ( function ( files ) {
dfd . resolve ( files ) ;
} ) . fail ( errorHandler ) ;
} ,
readEntries = function ( ) {
dirReader . readEntries ( function ( results ) {
if ( ! results . length ) {
successHandler ( entries ) ;
} else {
entries = entries . concat ( results ) ;
readEntries ( ) ;
}
} , errorHandler ) ;
} ;
path = path || '' ;
if ( entry . isFile ) {
if ( entry . _file ) {
// Workaround for Chrome bug #149735
entry . _file . relativePath = path ;
dfd . resolve ( entry . _file ) ;
} else {
entry . file ( function ( file ) {
file . relativePath = path ;
dfd . resolve ( file ) ;
} , errorHandler ) ;
}
} else if ( entry . isDirectory ) {
dirReader = entry . createReader ( ) ;
readEntries ( ) ;
} else {
// Return an empy list for file system items
// other than files or directories:
dfd . resolve ( [ ] ) ;
}
return dfd . promise ( ) ;
} ,
_handleFileTreeEntries : function ( entries , path ) {
var that = this ;
return $ . when . apply (
$ ,
$ . map ( entries , function ( entry ) {
return that . _handleFileTreeEntry ( entry , path ) ;
} )
) . then ( function ( ) {
return Array . prototype . concat . apply (
[ ] ,
arguments
) ;
} ) ;
} ,
_getDroppedFiles : function ( dataTransfer ) {
dataTransfer = dataTransfer || { } ;
var items = dataTransfer . items ;
if ( items && items . length && ( items [ 0 ] . webkitGetAsEntry ||
items [ 0 ] . getAsEntry ) ) {
return this . _handleFileTreeEntries (
$ . map ( items , function ( item ) {
var entry ;
if ( item . webkitGetAsEntry ) {
entry = item . webkitGetAsEntry ( ) ;
if ( entry ) {
// Workaround for Chrome bug #149735:
entry . _file = item . getAsFile ( ) ;
}
return entry ;
}
return item . getAsEntry ( ) ;
} )
) ;
}
return $ . Deferred ( ) . resolve (
$ . makeArray ( dataTransfer . files )
) . promise ( ) ;
} ,
_getSingleFileInputFiles : function ( fileInput ) {
fileInput = $ ( fileInput ) ;
var entries = fileInput . prop ( 'webkitEntries' ) ||
fileInput . prop ( 'entries' ) ,
files ,
value ;
if ( entries && entries . length ) {
return this . _handleFileTreeEntries ( entries ) ;
}
files = $ . makeArray ( fileInput . prop ( 'files' ) ) ;
if ( ! files . length ) {
value = fileInput . prop ( 'value' ) ;
if ( ! value ) {
return $ . Deferred ( ) . resolve ( [ ] ) . promise ( ) ;
}
// If the files property is not available, the browser does not
// support the File API and we add a pseudo File object with
// the input value as name with path information removed:
files = [ { name : value . replace ( /^.*\\/ , '' ) } ] ;
} else if ( files [ 0 ] . name === undefined && files [ 0 ] . fileName ) {
// File normalization for Safari 4 and Firefox 3:
$ . each ( files , function ( index , file ) {
file . name = file . fileName ;
file . size = file . fileSize ;
} ) ;
}
return $ . Deferred ( ) . resolve ( files ) . promise ( ) ;
} ,
_getFileInputFiles : function ( fileInput ) {
if ( ! ( fileInput instanceof $ ) || fileInput . length === 1 ) {
return this . _getSingleFileInputFiles ( fileInput ) ;
}
return $ . when . apply (
$ ,
$ . map ( fileInput , this . _getSingleFileInputFiles )
) . then ( function ( ) {
return Array . prototype . concat . apply (
[ ] ,
arguments
) ;
} ) ;
} ,
_onChange : function ( e ) {
var that = this ,
data = {
fileInput : $ ( e . target ) ,
form : $ ( e . target . form )
} ;
this . _getFileInputFiles ( data . fileInput ) . always ( function ( files ) {
data . files = files ;
if ( that . options . replaceFileInput ) {
that . _replaceFileInput ( data ) ;
}
if ( that . _trigger (
'change' ,
$ . Event ( 'change' , { delegatedEvent : e } ) ,
data
) !== false ) {
that . _onAdd ( e , data ) ;
}
} ) ;
} ,
_onPaste : function ( e ) {
var items = e . originalEvent && e . originalEvent . clipboardData &&
e . originalEvent . clipboardData . items ,
data = { files : [ ] } ;
if ( items && items . length ) {
$ . each ( items , function ( index , item ) {
var file = item . getAsFile && item . getAsFile ( ) ;
if ( file ) {
data . files . push ( file ) ;
}
} ) ;
if ( this . _trigger (
'paste' ,
$ . Event ( 'paste' , { delegatedEvent : e } ) ,
data
) !== false ) {
this . _onAdd ( e , data ) ;
}
}
} ,
_onDrop : function ( e ) {
e . dataTransfer = e . originalEvent && e . originalEvent . dataTransfer ;
var that = this ,
dataTransfer = e . dataTransfer ,
data = { } ;
if ( dataTransfer && dataTransfer . files && dataTransfer . files . length ) {
e . preventDefault ( ) ;
this . _getDroppedFiles ( dataTransfer ) . always ( function ( files ) {
data . files = files ;
if ( that . _trigger (
'drop' ,
$ . Event ( 'drop' , { delegatedEvent : e } ) ,
data
) !== false ) {
that . _onAdd ( e , data ) ;
}
} ) ;
}
} ,
_onDragOver : getDragHandler ( 'dragover' ) ,
_onDragEnter : getDragHandler ( 'dragenter' ) ,
_onDragLeave : getDragHandler ( 'dragleave' ) ,
_initEventHandlers : function ( ) {
if ( this . _isXHRUpload ( this . options ) ) {
this . _on ( this . options . dropZone , {
dragover : this . _onDragOver ,
drop : this . _onDrop ,
// event.preventDefault() on dragenter is required for IE10+:
dragenter : this . _onDragEnter ,
// dragleave is not required, but added for completeness:
dragleave : this . _onDragLeave
} ) ;
this . _on ( this . options . pasteZone , {
paste : this . _onPaste
} ) ;
}
if ( $ . support . fileInput ) {
this . _on ( this . options . fileInput , {
change : this . _onChange
} ) ;
}
} ,
_destroyEventHandlers : function ( ) {
this . _off ( this . options . dropZone , 'dragenter dragleave dragover drop' ) ;
this . _off ( this . options . pasteZone , 'paste' ) ;
this . _off ( this . options . fileInput , 'change' ) ;
} ,
_destroy : function ( ) {
this . _destroyEventHandlers ( ) ;
} ,
_setOption : function ( key , value ) {
var reinit = $ . inArray ( key , this . _specialOptions ) !== - 1 ;
if ( reinit ) {
this . _destroyEventHandlers ( ) ;
}
this . _super ( key , value ) ;
if ( reinit ) {
this . _initSpecialOptions ( ) ;
this . _initEventHandlers ( ) ;
}
} ,
_initSpecialOptions : function ( ) {
var options = this . options ;
if ( options . fileInput === undefined ) {
options . fileInput = this . element . is ( 'input[type="file"]' ) ?
this . element : this . element . find ( 'input[type="file"]' ) ;
} else if ( ! ( options . fileInput instanceof $ ) ) {
options . fileInput = $ ( options . fileInput ) ;
}
if ( ! ( options . dropZone instanceof $ ) ) {
options . dropZone = $ ( options . dropZone ) ;
}
if ( ! ( options . pasteZone instanceof $ ) ) {
options . pasteZone = $ ( options . pasteZone ) ;
}
} ,
_getRegExp : function ( str ) {
var parts = str . split ( '/' ) ,
modifiers = parts . pop ( ) ;
parts . shift ( ) ;
return new RegExp ( parts . join ( '/' ) , modifiers ) ;
} ,
_isRegExpOption : function ( key , value ) {
return key !== 'url' && $ . type ( value ) === 'string' &&
/^\/.*\/[igm]{0,3}$/ . test ( value ) ;
} ,
_initDataAttributes : function ( ) {
var that = this ,
options = this . options ,
data = this . element . data ( ) ;
// Initialize options set via HTML5 data-attributes:
$ . each (
this . element [ 0 ] . attributes ,
function ( index , attr ) {
var key = attr . name . toLowerCase ( ) ,
value ;
if ( /^data-/ . test ( key ) ) {
// Convert hyphen-ated key to camelCase:
key = key . slice ( 5 ) . replace ( /-[a-z]/g , function ( str ) {
return str . charAt ( 1 ) . toUpperCase ( ) ;
} ) ;
value = data [ key ] ;
if ( that . _isRegExpOption ( key , value ) ) {
value = that . _getRegExp ( value ) ;
}
options [ key ] = value ;
}
}
) ;
} ,
_create : function ( ) {
this . _initDataAttributes ( ) ;
this . _initSpecialOptions ( ) ;
this . _slots = [ ] ;
this . _sequence = this . _getXHRPromise ( true ) ;
this . _sending = this . _active = 0 ;
this . _initProgressObject ( this ) ;
this . _initEventHandlers ( ) ;
} ,
// This method is exposed to the widget API and allows to query
// the number of active uploads:
active : function ( ) {
return this . _active ;
} ,
// This method is exposed to the widget API and allows to query
// the widget upload progress.
// It returns an object with loaded, total and bitrate properties
// for the running uploads:
progress : function ( ) {
return this . _progress ;
} ,
// This method is exposed to the widget API and allows adding files
// using the fileupload API. The data parameter accepts an object which
// must have a files property and can contain additional options:
// .fileupload('add', {files: filesList});
add : function ( data ) {
var that = this ;
if ( ! data || this . options . disabled ) {
return ;
}
if ( data . fileInput && ! data . files ) {
this . _getFileInputFiles ( data . fileInput ) . always ( function ( files ) {
data . files = files ;
that . _onAdd ( null , data ) ;
} ) ;
} else {
data . files = $ . makeArray ( data . files ) ;
this . _onAdd ( null , data ) ;
}
} ,
// This method is exposed to the widget API and allows sending files
// using the fileupload API. The data parameter accepts an object which
// must have a files or fileInput property and can contain additional options:
// .fileupload('send', {files: filesList});
// The method returns a Promise object for the file upload call.
send : function ( data ) {
if ( data && ! this . options . disabled ) {
if ( data . fileInput && ! data . files ) {
var that = this ,
dfd = $ . Deferred ( ) ,
promise = dfd . promise ( ) ,
jqXHR ,
aborted ;
promise . abort = function ( ) {
aborted = true ;
if ( jqXHR ) {
return jqXHR . abort ( ) ;
}
dfd . reject ( null , 'abort' , 'abort' ) ;
return promise ;
} ;
this . _getFileInputFiles ( data . fileInput ) . always (
function ( files ) {
if ( aborted ) {
return ;
}
if ( ! files . length ) {
dfd . reject ( ) ;
return ;
}
data . files = files ;
jqXHR = that . _onSend ( null , data ) ;
jqXHR . then (
function ( result , textStatus , jqXHR ) {
dfd . resolve ( result , textStatus , jqXHR ) ;
} ,
function ( jqXHR , textStatus , errorThrown ) {
dfd . reject ( jqXHR , textStatus , errorThrown ) ;
}
) ;
}
) ;
return this . _enhancePromise ( promise ) ;
}
data . files = $ . makeArray ( data . files ) ;
if ( data . files . length ) {
return this . _onSend ( null , data ) ;
}
}
return this . _getXHRPromise ( false , data && data . context ) ;
}
} ) ;
} ) ) ;
; ( function ( ) {
'use strict' ;
/ * *
* @ preserve FastClick : polyfill to remove click delays on browsers with touch UIs .
*
* @ codingstandard ftlabs - jsv2
* @ copyright The Financial Times Limited [ All Rights Reserved ]
* @ license MIT License ( see LICENSE . txt )
* /
/*jslint browser:true, node:true*/
/*global define, Event, Node*/
/ * *
* Instantiate fast - clicking listeners on the specified layer .
*
* @ constructor
* @ param { Element } layer The layer to listen on
* @ param { Object } [ options = { } ] The options to override the defaults
* /
function FastClick ( layer , options ) {
var oldOnClick ;
options = options || { } ;
/ * *
* Whether a click is currently being tracked .
*
* @ type boolean
* /
this . trackingClick = false ;
/ * *
* Timestamp for when click tracking started .
*
* @ type number
* /
this . trackingClickStart = 0 ;
/ * *
* The element being tracked for a click .
*
* @ type EventTarget
* /
this . targetElement = null ;
/ * *
* X - coordinate of touch start event .
*
* @ type number
* /
this . touchStartX = 0 ;
/ * *
* Y - coordinate of touch start event .
*
* @ type number
* /
this . touchStartY = 0 ;
/ * *
* ID of the last touch , retrieved from Touch . identifier .
*
* @ type number
* /
this . lastTouchIdentifier = 0 ;
/ * *
* Touchmove boundary , beyond which a click will be cancelled .
*
* @ type number
* /
this . touchBoundary = options . touchBoundary || 10 ;
/ * *
* The FastClick layer .
*
* @ type Element
* /
this . layer = layer ;
/ * *
* The minimum time between tap ( touchstart and touchend ) events
*
* @ type number
* /
this . tapDelay = options . tapDelay || 200 ;
/ * *
* The maximum time for a tap
*
* @ type number
* /
this . tapTimeout = options . tapTimeout || 700 ;
if ( FastClick . notNeeded ( layer ) ) {
return ;
}
// Some old versions of Android don't have Function.prototype.bind
function bind ( method , context ) {
return function ( ) { return method . apply ( context , arguments ) ; } ;
}
var methods = [ 'onMouse' , 'onClick' , 'onTouchStart' , 'onTouchMove' , 'onTouchEnd' , 'onTouchCancel' ] ;
var context = this ;
for ( var i = 0 , l = methods . length ; i < l ; i ++ ) {
context [ methods [ i ] ] = bind ( context [ methods [ i ] ] , context ) ;
}
// Set up event handlers as required
if ( deviceIsAndroid ) {
layer . addEventListener ( 'mouseover' , this . onMouse , true ) ;
layer . addEventListener ( 'mousedown' , this . onMouse , true ) ;
layer . addEventListener ( 'mouseup' , this . onMouse , true ) ;
}
layer . addEventListener ( 'click' , this . onClick , true ) ;
layer . addEventListener ( 'touchstart' , this . onTouchStart , false ) ;
layer . addEventListener ( 'touchmove' , this . onTouchMove , false ) ;
layer . addEventListener ( 'touchend' , this . onTouchEnd , false ) ;
layer . addEventListener ( 'touchcancel' , this . onTouchCancel , false ) ;
// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
// layer when they are cancelled.
if ( ! Event . prototype . stopImmediatePropagation ) {
layer . removeEventListener = function ( type , callback , capture ) {
var rmv = Node . prototype . removeEventListener ;
if ( type === 'click' ) {
rmv . call ( layer , type , callback . hijacked || callback , capture ) ;
} else {
rmv . call ( layer , type , callback , capture ) ;
}
} ;
layer . addEventListener = function ( type , callback , capture ) {
var adv = Node . prototype . addEventListener ;
if ( type === 'click' ) {
adv . call ( layer , type , callback . hijacked || ( callback . hijacked = function ( event ) {
if ( ! event . propagationStopped ) {
callback ( event ) ;
}
} ) , capture ) ;
} else {
adv . call ( layer , type , callback , capture ) ;
}
} ;
}
// If a handler is already declared in the element's onclick attribute, it will be fired before
// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
// adding it as listener.
if ( typeof layer . onclick === 'function' ) {
// Android browser on at least 3.2 requires a new reference to the function in layer.onclick
// - the old one won't work if passed to addEventListener directly.
oldOnClick = layer . onclick ;
layer . addEventListener ( 'click' , function ( event ) {
oldOnClick ( event ) ;
} , false ) ;
layer . onclick = null ;
}
}
/ * *
* Windows Phone 8.1 fakes user agent string to look like Android and iPhone .
*
* @ type boolean
* /
var deviceIsWindowsPhone = navigator . userAgent . indexOf ( "Windows Phone" ) >= 0 ;
/ * *
* Android requires exceptions .
*
* @ type boolean
* /
var deviceIsAndroid = navigator . userAgent . indexOf ( 'Android' ) > 0 && ! deviceIsWindowsPhone ;
/ * *
* iOS requires exceptions .
*
* @ type boolean
* /
var deviceIsIOS = /iP(ad|hone|od)/ . test ( navigator . userAgent ) && ! deviceIsWindowsPhone ;
/ * *
* iOS 4 requires an exception for select elements .
*
* @ type boolean
* /
var deviceIsIOS4 = deviceIsIOS && ( /OS 4_\d(_\d)?/ ) . test ( navigator . userAgent ) ;
/ * *
* iOS 6.0 - 7. * requires the target element to be manually derived
*
* @ type boolean
* /
var deviceIsIOSWithBadTarget = deviceIsIOS && ( /OS [6-7]_\d/ ) . test ( navigator . userAgent ) ;
/ * *
* BlackBerry requires exceptions .
*
* @ type boolean
* /
var deviceIsBlackBerry10 = navigator . userAgent . indexOf ( 'BB10' ) > 0 ;
/ * *
* Determine whether a given element requires a native click .
*
* @ param { EventTarget | Element } target Target DOM element
* @ returns { boolean } Returns true if the element needs a native click
* /
FastClick . prototype . needsClick = function ( target ) {
switch ( target . nodeName . toLowerCase ( ) ) {
// Don't send a synthetic click to disabled inputs (issue #62)
case 'button' :
case 'select' :
case 'textarea' :
if ( target . disabled ) {
return true ;
}
break ;
case 'input' :
// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
if ( ( deviceIsIOS && target . type === 'file' ) || target . disabled ) {
return true ;
}
break ;
case 'label' :
case 'iframe' : // iOS8 homescreen apps can prevent events bubbling into frames
case 'video' :
return true ;
}
return ( /\bneedsclick\b/ ) . test ( target . className ) ;
} ;
/ * *
* Determine whether a given element requires a call to focus to simulate click into element .
*
* @ param { EventTarget | Element } target Target DOM element
* @ returns { boolean } Returns true if the element requires a call to focus to simulate native click .
* /
FastClick . prototype . needsFocus = function ( target ) {
switch ( target . nodeName . toLowerCase ( ) ) {
case 'textarea' :
return true ;
case 'select' :
return ! deviceIsAndroid ;
case 'input' :
switch ( target . type ) {
case 'button' :
case 'checkbox' :
case 'file' :
case 'image' :
case 'radio' :
case 'submit' :
return false ;
}
// No point in attempting to focus disabled inputs
return ! target . disabled && ! target . readOnly ;
default :
return ( /\bneedsfocus\b/ ) . test ( target . className ) ;
}
} ;
/ * *
* Send a click event to the specified element .
*
* @ param { EventTarget | Element } targetElement
* @ param { Event } event
* /
FastClick . prototype . sendClick = function ( targetElement , event ) {
var clickEvent , touch ;
// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
if ( document . activeElement && document . activeElement !== targetElement ) {
document . activeElement . blur ( ) ;
}
touch = event . changedTouches [ 0 ] ;
// Synthesise a click event, with an extra attribute so it can be tracked
clickEvent = document . createEvent ( 'MouseEvents' ) ;
clickEvent . initMouseEvent ( this . determineEventType ( targetElement ) , true , true , window , 1 , touch . screenX , touch . screenY , touch . clientX , touch . clientY , false , false , false , false , 0 , null ) ;
clickEvent . forwardedTouchEvent = true ;
targetElement . dispatchEvent ( clickEvent ) ;
} ;
FastClick . prototype . determineEventType = function ( targetElement ) {
//Issue #159: Android Chrome Select Box does not open with a synthetic click event
if ( deviceIsAndroid && targetElement . tagName . toLowerCase ( ) === 'select' ) {
return 'mousedown' ;
}
return 'click' ;
} ;
/ * *
* @ param { EventTarget | Element } targetElement
* /
FastClick . prototype . focus = function ( targetElement ) {
var length ;
// Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
if ( deviceIsIOS && targetElement . setSelectionRange && targetElement . type . indexOf ( 'date' ) !== 0 && targetElement . type !== 'time' && targetElement . type !== 'month' ) {
length = targetElement . value . length ;
targetElement . setSelectionRange ( length , length ) ;
} else {
targetElement . focus ( ) ;
}
} ;
/ * *
* Check whether the given target element is a child of a scrollable layer and if so , set a flag on it .
*
* @ param { EventTarget | Element } targetElement
* /
FastClick . prototype . updateScrollParent = function ( targetElement ) {
var scrollParent , parentElement ;
scrollParent = targetElement . fastClickScrollParent ;
// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
// target element was moved to another parent.
if ( ! scrollParent || ! scrollParent . contains ( targetElement ) ) {
parentElement = targetElement ;
do {
if ( parentElement . scrollHeight > parentElement . offsetHeight ) {
scrollParent = parentElement ;
targetElement . fastClickScrollParent = parentElement ;
break ;
}
parentElement = parentElement . parentElement ;
} while ( parentElement ) ;
}
// Always update the scroll top tracker if possible.
if ( scrollParent ) {
scrollParent . fastClickLastScrollTop = scrollParent . scrollTop ;
}
} ;
/ * *
* @ param { EventTarget } targetElement
* @ returns { Element | EventTarget }
* /
FastClick . prototype . getTargetElementFromEventTarget = function ( eventTarget ) {
// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
if ( eventTarget . nodeType === Node . TEXT _NODE ) {
return eventTarget . parentNode ;
}
return eventTarget ;
} ;
/ * *
* On touch start , record the position and scroll offset .
*
* @ param { Event } event
* @ returns { boolean }
* /
FastClick . prototype . onTouchStart = function ( event ) {
var targetElement , touch , selection ;
// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
if ( event . targetTouches . length > 1 ) {
return true ;
}
targetElement = this . getTargetElementFromEventTarget ( event . target ) ;
touch = event . targetTouches [ 0 ] ;
if ( deviceIsIOS ) {
// Only trusted events will deselect text on iOS (issue #49)
selection = window . getSelection ( ) ;
if ( selection . rangeCount && ! selection . isCollapsed ) {
return true ;
}
if ( ! deviceIsIOS4 ) {
// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
// with the same identifier as the touch event that previously triggered the click that triggered the alert.
// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
// Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string,
// which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long,
// random integers, it's safe to to continue if the identifier is 0 here.
if ( touch . identifier && touch . identifier === this . lastTouchIdentifier ) {
event . preventDefault ( ) ;
return false ;
}
this . lastTouchIdentifier = touch . identifier ;
// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
// 1) the user does a fling scroll on the scrollable layer
// 2) the user stops the fling scroll with another tap
// then the event.target of the last 'touchend' event will be the element that was under the user's finger
// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
this . updateScrollParent ( targetElement ) ;
}
}
this . trackingClick = true ;
this . trackingClickStart = event . timeStamp ;
this . targetElement = targetElement ;
this . touchStartX = touch . pageX ;
this . touchStartY = touch . pageY ;
// Prevent phantom clicks on fast double-tap (issue #36)
if ( ( event . timeStamp - this . lastClickTime ) < this . tapDelay ) {
event . preventDefault ( ) ;
}
return true ;
} ;
/ * *
* Based on a touchmove event object , check whether the touch has moved past a boundary since it started .
*
* @ param { Event } event
* @ returns { boolean }
* /
FastClick . prototype . touchHasMoved = function ( event ) {
var touch = event . changedTouches [ 0 ] , boundary = this . touchBoundary ;
if ( Math . abs ( touch . pageX - this . touchStartX ) > boundary || Math . abs ( touch . pageY - this . touchStartY ) > boundary ) {
return true ;
}
return false ;
} ;
/ * *
* Update the last position .
*
* @ param { Event } event
* @ returns { boolean }
* /
FastClick . prototype . onTouchMove = function ( event ) {
if ( ! this . trackingClick ) {
return true ;
}
// If the touch has moved, cancel the click tracking
if ( this . targetElement !== this . getTargetElementFromEventTarget ( event . target ) || this . touchHasMoved ( event ) ) {
this . trackingClick = false ;
this . targetElement = null ;
}
return true ;
} ;
/ * *
* Attempt to find the labelled control for the given label element .
*
* @ param { EventTarget | HTMLLabelElement } labelElement
* @ returns { Element | null }
* /
FastClick . prototype . findControl = function ( labelElement ) {
// Fast path for newer browsers supporting the HTML5 control attribute
if ( labelElement . control !== undefined ) {
return labelElement . control ;
}
// All browsers under test that support touch events also support the HTML5 htmlFor attribute
if ( labelElement . htmlFor ) {
return document . getElementById ( labelElement . htmlFor ) ;
}
// If no for attribute exists, attempt to retrieve the first labellable descendant element
// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
return labelElement . querySelector ( 'button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea' ) ;
} ;
/ * *
* On touch end , determine whether to send a click event at once .
*
* @ param { Event } event
* @ returns { boolean }
* /
FastClick . prototype . onTouchEnd = function ( event ) {
var forElement , trackingClickStart , targetTagName , scrollParent , touch , targetElement = this . targetElement ;
if ( ! this . trackingClick ) {
return true ;
}
// Prevent phantom clicks on fast double-tap (issue #36)
if ( ( event . timeStamp - this . lastClickTime ) < this . tapDelay ) {
this . cancelNextClick = true ;
return true ;
}
if ( ( event . timeStamp - this . trackingClickStart ) > this . tapTimeout ) {
return true ;
}
// Reset to prevent wrong click cancel on input (issue #156).
this . cancelNextClick = false ;
this . lastClickTime = event . timeStamp ;
trackingClickStart = this . trackingClickStart ;
this . trackingClick = false ;
this . trackingClickStart = 0 ;
// On some iOS devices, the targetElement supplied with the event is invalid if the layer
// is performing a transition or scroll, and has to be re-detected manually. Note that
// for this to function correctly, it must be called *after* the event target is checked!
// See issue #57; also filed as rdar://13048589 .
if ( deviceIsIOSWithBadTarget ) {
touch = event . changedTouches [ 0 ] ;
// In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
targetElement = document . elementFromPoint ( touch . pageX - window . pageXOffset , touch . pageY - window . pageYOffset ) || targetElement ;
targetElement . fastClickScrollParent = this . targetElement . fastClickScrollParent ;
}
targetTagName = targetElement . tagName . toLowerCase ( ) ;
if ( targetTagName === 'label' ) {
forElement = this . findControl ( targetElement ) ;
if ( forElement ) {
this . focus ( targetElement ) ;
if ( deviceIsAndroid ) {
return false ;
}
targetElement = forElement ;
}
} else if ( this . needsFocus ( targetElement ) ) {
// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
if ( ( event . timeStamp - trackingClickStart ) > 100 || ( deviceIsIOS && window . top !== window && targetTagName === 'input' ) ) {
this . targetElement = null ;
return false ;
}
this . focus ( targetElement ) ;
this . sendClick ( targetElement , event ) ;
// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
// Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others)
if ( ! deviceIsIOS || targetTagName !== 'select' ) {
this . targetElement = null ;
event . preventDefault ( ) ;
}
return false ;
}
if ( deviceIsIOS && ! deviceIsIOS4 ) {
// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
scrollParent = targetElement . fastClickScrollParent ;
if ( scrollParent && scrollParent . fastClickLastScrollTop !== scrollParent . scrollTop ) {
return true ;
}
}
// Prevent the actual click from going though - unless the target node is marked as requiring
// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
if ( ! this . needsClick ( targetElement ) ) {
event . preventDefault ( ) ;
this . sendClick ( targetElement , event ) ;
}
return false ;
} ;
/ * *
* On touch cancel , stop tracking the click .
*
* @ returns { void }
* /
FastClick . prototype . onTouchCancel = function ( ) {
this . trackingClick = false ;
this . targetElement = null ;
} ;
/ * *
* Determine mouse events which should be permitted .
*
* @ param { Event } event
* @ returns { boolean }
* /
FastClick . prototype . onMouse = function ( event ) {
// If a target element was never set (because a touch event was never fired) allow the event
if ( ! this . targetElement ) {
return true ;
}
if ( event . forwardedTouchEvent ) {
return true ;
}
// Programmatically generated events targeting a specific element should be permitted
if ( ! event . cancelable ) {
return true ;
}
// Derive and check the target element to see whether the mouse event needs to be permitted;
// unless explicitly enabled, prevent non-touch click events from triggering actions,
// to prevent ghost/doubleclicks.
if ( ! this . needsClick ( this . targetElement ) || this . cancelNextClick ) {
// Prevent any user-added listeners declared on FastClick element from being fired.
if ( event . stopImmediatePropagation ) {
event . stopImmediatePropagation ( ) ;
} else {
// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
event . propagationStopped = true ;
}
// Cancel the event
event . stopPropagation ( ) ;
event . preventDefault ( ) ;
return false ;
}
// If the mouse event is permitted, return true for the action to go through.
return true ;
} ;
/ * *
* On actual clicks , determine whether this is a touch - generated click , a click action occurring
* naturally after a delay after a touch ( which needs to be cancelled to avoid duplication ) , or
* an actual click which should be permitted .
*
* @ param { Event } event
* @ returns { boolean }
* /
FastClick . prototype . onClick = function ( event ) {
var permitted ;
// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
if ( this . trackingClick ) {
this . targetElement = null ;
this . trackingClick = false ;
return true ;
}
// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
if ( event . target . type === 'submit' && event . detail === 0 ) {
return true ;
}
permitted = this . onMouse ( event ) ;
// Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
if ( ! permitted ) {
this . targetElement = null ;
}
// If clicks are permitted, return true for the action to go through.
return permitted ;
} ;
/ * *
* Remove all FastClick ' s event listeners .
*
* @ returns { void }
* /
FastClick . prototype . destroy = function ( ) {
var layer = this . layer ;
if ( deviceIsAndroid ) {
layer . removeEventListener ( 'mouseover' , this . onMouse , true ) ;
layer . removeEventListener ( 'mousedown' , this . onMouse , true ) ;
layer . removeEventListener ( 'mouseup' , this . onMouse , true ) ;
}
layer . removeEventListener ( 'click' , this . onClick , true ) ;
layer . removeEventListener ( 'touchstart' , this . onTouchStart , false ) ;
layer . removeEventListener ( 'touchmove' , this . onTouchMove , false ) ;
layer . removeEventListener ( 'touchend' , this . onTouchEnd , false ) ;
layer . removeEventListener ( 'touchcancel' , this . onTouchCancel , false ) ;
} ;
/ * *
* Check whether FastClick is needed .
*
* @ param { Element } layer The layer to listen on
* /
FastClick . notNeeded = function ( layer ) {
var metaViewport ;
var chromeVersion ;
var blackberryVersion ;
var firefoxVersion ;
// Devices that don't support touch don't need FastClick
if ( typeof window . ontouchstart === 'undefined' ) {
return true ;
}
// Chrome version - zero for other browsers
chromeVersion = + ( /Chrome\/([0-9]+)/ . exec ( navigator . userAgent ) || [ , 0 ] ) [ 1 ] ;
if ( chromeVersion ) {
if ( deviceIsAndroid ) {
metaViewport = document . querySelector ( 'meta[name=viewport]' ) ;
if ( metaViewport ) {
// Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
if ( metaViewport . content . indexOf ( 'user-scalable=no' ) !== - 1 ) {
return true ;
}
// Chrome 32 and above with width=device-width or less don't need FastClick
if ( chromeVersion > 31 && document . documentElement . scrollWidth <= window . outerWidth ) {
return true ;
}
}
// Chrome desktop doesn't need FastClick (issue #15)
} else {
return true ;
}
}
if ( deviceIsBlackBerry10 ) {
blackberryVersion = navigator . userAgent . match ( /Version\/([0-9]*)\.([0-9]*)/ ) ;
// BlackBerry 10.3+ does not require Fastclick library.
// https://github.com/ftlabs/fastclick/issues/251
if ( blackberryVersion [ 1 ] >= 10 && blackberryVersion [ 2 ] >= 3 ) {
metaViewport = document . querySelector ( 'meta[name=viewport]' ) ;
if ( metaViewport ) {
// user-scalable=no eliminates click delay.
if ( metaViewport . content . indexOf ( 'user-scalable=no' ) !== - 1 ) {
return true ;
}
// width=device-width (or less than device-width) eliminates click delay.
if ( document . documentElement . scrollWidth <= window . outerWidth ) {
return true ;
}
}
}
}
// IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97)
if ( layer . style . msTouchAction === 'none' || layer . style . touchAction === 'manipulation' ) {
return true ;
}
// Firefox version - zero for other browsers
firefoxVersion = + ( /Firefox\/([0-9]+)/ . exec ( navigator . userAgent ) || [ , 0 ] ) [ 1 ] ;
if ( firefoxVersion >= 27 ) {
// Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896
metaViewport = document . querySelector ( 'meta[name=viewport]' ) ;
if ( metaViewport && ( metaViewport . content . indexOf ( 'user-scalable=no' ) !== - 1 || document . documentElement . scrollWidth <= window . outerWidth ) ) {
return true ;
}
}
// IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version
// http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx
if ( layer . style . touchAction === 'none' || layer . style . touchAction === 'manipulation' ) {
return true ;
}
return false ;
} ;
/ * *
* Factory method for creating a FastClick object
*
* @ param { Element } layer The layer to listen on
* @ param { Object } [ options = { } ] The options to override the defaults
* /
FastClick . attach = function ( layer , options ) {
return new FastClick ( layer , options ) ;
} ;
if ( typeof define === 'function' && typeof define . amd === 'object' && define . amd ) {
// AMD. Register as an anonymous module.
define ( function ( ) {
return FastClick ;
} ) ;
} else if ( typeof module !== 'undefined' && module . exports ) {
module . exports = FastClick . attach ;
module . exports . FastClick = FastClick ;
} else {
window . FastClick = FastClick ;
}
} ( ) ) ;
/ * !
* Bootstrap Colorpicker v2 . 5.2
* https : //itsjavi.com/bootstrap-colorpicker/
*
* Originally written by ( c ) 2012 Stefan Petre
* Licensed under the Apache License v2 . 0
* http : //www.apache.org/licenses/LICENSE-2.0.txt
*
* /
( function ( root , factory ) {
if ( typeof define === 'function' && define . amd ) {
// AMD. Register as an anonymous module unless amdModuleId is set
define ( [ "jquery" ] , function ( jq ) {
return ( factory ( jq ) ) ;
} ) ;
} else if ( typeof exports === 'object' ) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module . exports = factory ( require ( "jquery" ) ) ;
} else if ( jQuery && ! jQuery . fn . colorpicker ) {
factory ( jQuery ) ;
}
} ( this , function ( $ ) {
'use strict' ;
/ * *
* Color manipulation helper class
*
* @ param { Object | String } [ val ]
* @ param { Object } [ predefinedColors ]
* @ param { String | null } [ fallbackColor ]
* @ param { String | null } [ fallbackFormat ]
* @ param { Boolean } [ hexNumberSignPrefix ]
* @ constructor
* /
var Color = function (
val , predefinedColors , fallbackColor , fallbackFormat , hexNumberSignPrefix ) {
this . fallbackValue = fallbackColor ?
(
fallbackColor && ( typeof fallbackColor . h !== 'undefined' ) ?
fallbackColor :
this . value = {
h : 0 ,
s : 0 ,
b : 0 ,
a : 1
}
) :
null ;
this . fallbackFormat = fallbackFormat ? fallbackFormat : 'rgba' ;
this . hexNumberSignPrefix = hexNumberSignPrefix === true ;
this . value = this . fallbackValue ;
this . origFormat = null ; // original string format
this . predefinedColors = predefinedColors ? predefinedColors : { } ;
// We don't want to share aliases across instances so we extend new object
this . colors = $ . extend ( { } , Color . webColors , this . predefinedColors ) ;
if ( val ) {
if ( typeof val . h !== 'undefined' ) {
this . value = val ;
} else {
this . setColor ( String ( val ) ) ;
}
}
if ( ! this . value ) {
// Initial value is always black if no arguments are passed or val is empty
this . value = {
h : 0 ,
s : 0 ,
b : 0 ,
a : 1
} ;
}
} ;
Color . webColors = { // 140 predefined colors from the HTML Colors spec
"aliceblue" : "f0f8ff" ,
"antiquewhite" : "faebd7" ,
"aqua" : "00ffff" ,
"aquamarine" : "7fffd4" ,
"azure" : "f0ffff" ,
"beige" : "f5f5dc" ,
"bisque" : "ffe4c4" ,
"black" : "000000" ,
"blanchedalmond" : "ffebcd" ,
"blue" : "0000ff" ,
"blueviolet" : "8a2be2" ,
"brown" : "a52a2a" ,
"burlywood" : "deb887" ,
"cadetblue" : "5f9ea0" ,
"chartreuse" : "7fff00" ,
"chocolate" : "d2691e" ,
"coral" : "ff7f50" ,
"cornflowerblue" : "6495ed" ,
"cornsilk" : "fff8dc" ,
"crimson" : "dc143c" ,
"cyan" : "00ffff" ,
"darkblue" : "00008b" ,
"darkcyan" : "008b8b" ,
"darkgoldenrod" : "b8860b" ,
"darkgray" : "a9a9a9" ,
"darkgreen" : "006400" ,
"darkkhaki" : "bdb76b" ,
"darkmagenta" : "8b008b" ,
"darkolivegreen" : "556b2f" ,
"darkorange" : "ff8c00" ,
"darkorchid" : "9932cc" ,
"darkred" : "8b0000" ,
"darksalmon" : "e9967a" ,
"darkseagreen" : "8fbc8f" ,
"darkslateblue" : "483d8b" ,
"darkslategray" : "2f4f4f" ,
"darkturquoise" : "00ced1" ,
"darkviolet" : "9400d3" ,
"deeppink" : "ff1493" ,
"deepskyblue" : "00bfff" ,
"dimgray" : "696969" ,
"dodgerblue" : "1e90ff" ,
"firebrick" : "b22222" ,
"floralwhite" : "fffaf0" ,
"forestgreen" : "228b22" ,
"fuchsia" : "ff00ff" ,
"gainsboro" : "dcdcdc" ,
"ghostwhite" : "f8f8ff" ,
"gold" : "ffd700" ,
"goldenrod" : "daa520" ,
"gray" : "808080" ,
"green" : "008000" ,
"greenyellow" : "adff2f" ,
"honeydew" : "f0fff0" ,
"hotpink" : "ff69b4" ,
"indianred" : "cd5c5c" ,
"indigo" : "4b0082" ,
"ivory" : "fffff0" ,
"khaki" : "f0e68c" ,
"lavender" : "e6e6fa" ,
"lavenderblush" : "fff0f5" ,
"lawngreen" : "7cfc00" ,
"lemonchiffon" : "fffacd" ,
"lightblue" : "add8e6" ,
"lightcoral" : "f08080" ,
"lightcyan" : "e0ffff" ,
"lightgoldenrodyellow" : "fafad2" ,
"lightgrey" : "d3d3d3" ,
"lightgreen" : "90ee90" ,
"lightpink" : "ffb6c1" ,
"lightsalmon" : "ffa07a" ,
"lightseagreen" : "20b2aa" ,
"lightskyblue" : "87cefa" ,
"lightslategray" : "778899" ,
"lightsteelblue" : "b0c4de" ,
"lightyellow" : "ffffe0" ,
"lime" : "00ff00" ,
"limegreen" : "32cd32" ,
"linen" : "faf0e6" ,
"magenta" : "ff00ff" ,
"maroon" : "800000" ,
"mediumaquamarine" : "66cdaa" ,
"mediumblue" : "0000cd" ,
"mediumorchid" : "ba55d3" ,
"mediumpurple" : "9370d8" ,
"mediumseagreen" : "3cb371" ,
"mediumslateblue" : "7b68ee" ,
"mediumspringgreen" : "00fa9a" ,
"mediumturquoise" : "48d1cc" ,
"mediumvioletred" : "c71585" ,
"midnightblue" : "191970" ,
"mintcream" : "f5fffa" ,
"mistyrose" : "ffe4e1" ,
"moccasin" : "ffe4b5" ,
"navajowhite" : "ffdead" ,
"navy" : "000080" ,
"oldlace" : "fdf5e6" ,
"olive" : "808000" ,
"olivedrab" : "6b8e23" ,
"orange" : "ffa500" ,
"orangered" : "ff4500" ,
"orchid" : "da70d6" ,
"palegoldenrod" : "eee8aa" ,
"palegreen" : "98fb98" ,
"paleturquoise" : "afeeee" ,
"palevioletred" : "d87093" ,
"papayawhip" : "ffefd5" ,
"peachpuff" : "ffdab9" ,
"peru" : "cd853f" ,
"pink" : "ffc0cb" ,
"plum" : "dda0dd" ,
"powderblue" : "b0e0e6" ,
"purple" : "800080" ,
"red" : "ff0000" ,
"rosybrown" : "bc8f8f" ,
"royalblue" : "4169e1" ,
"saddlebrown" : "8b4513" ,
"salmon" : "fa8072" ,
"sandybrown" : "f4a460" ,
"seagreen" : "2e8b57" ,
"seashell" : "fff5ee" ,
"sienna" : "a0522d" ,
"silver" : "c0c0c0" ,
"skyblue" : "87ceeb" ,
"slateblue" : "6a5acd" ,
"slategray" : "708090" ,
"snow" : "fffafa" ,
"springgreen" : "00ff7f" ,
"steelblue" : "4682b4" ,
"tan" : "d2b48c" ,
"teal" : "008080" ,
"thistle" : "d8bfd8" ,
"tomato" : "ff6347" ,
"turquoise" : "40e0d0" ,
"violet" : "ee82ee" ,
"wheat" : "f5deb3" ,
"white" : "ffffff" ,
"whitesmoke" : "f5f5f5" ,
"yellow" : "ffff00" ,
"yellowgreen" : "9acd32" ,
"transparent" : "transparent"
} ;
Color . prototype = {
constructor : Color ,
colors : { } , // merged web and predefined colors
predefinedColors : { } ,
/ * *
* @ return { Object }
* /
getValue : function ( ) {
return this . value ;
} ,
/ * *
* @ param { Object } val
* /
setValue : function ( val ) {
this . value = val ;
} ,
_sanitizeNumber : function ( val ) {
if ( typeof val === 'number' ) {
return val ;
}
if ( isNaN ( val ) || ( val === null ) || ( val === '' ) || ( val === undefined ) ) {
return 1 ;
}
if ( val === '' ) {
return 0 ;
}
if ( typeof val . toLowerCase !== 'undefined' ) {
if ( val . match ( /^\./ ) ) {
val = "0" + val ;
}
return Math . ceil ( parseFloat ( val ) * 100 ) / 100 ;
}
return 1 ;
} ,
isTransparent : function ( strVal ) {
if ( ! strVal || ! ( typeof strVal === 'string' || strVal instanceof String ) ) {
return false ;
}
strVal = strVal . toLowerCase ( ) . trim ( ) ;
return ( strVal === 'transparent' ) || ( strVal . match ( /#?00000000/ ) ) || ( strVal . match ( /(rgba|hsla)\(0,0,0,0?\.?0\)/ ) ) ;
} ,
rgbaIsTransparent : function ( rgba ) {
return ( ( rgba . r === 0 ) && ( rgba . g === 0 ) && ( rgba . b === 0 ) && ( rgba . a === 0 ) ) ;
} ,
// parse a string to HSB
/ * *
* @ protected
* @ param { String } strVal
* @ returns { boolean } Returns true if it could be parsed , false otherwise
* /
setColor : function ( strVal ) {
strVal = strVal . toLowerCase ( ) . trim ( ) ;
if ( strVal ) {
if ( this . isTransparent ( strVal ) ) {
this . value = {
h : 0 ,
s : 0 ,
b : 0 ,
a : 0
} ;
return true ;
} else {
var parsedColor = this . parse ( strVal ) ;
if ( parsedColor ) {
this . value = this . value = {
h : parsedColor . h ,
s : parsedColor . s ,
b : parsedColor . b ,
a : parsedColor . a
} ;
if ( ! this . origFormat ) {
this . origFormat = parsedColor . format ;
}
} else if ( this . fallbackValue ) {
// if parser fails, defaults to fallbackValue if defined, otherwise the value won't be changed
this . value = this . fallbackValue ;
}
}
}
return false ;
} ,
setHue : function ( h ) {
this . value . h = 1 - h ;
} ,
setSaturation : function ( s ) {
this . value . s = s ;
} ,
setBrightness : function ( b ) {
this . value . b = 1 - b ;
} ,
setAlpha : function ( a ) {
this . value . a = Math . round ( ( parseInt ( ( 1 - a ) * 100 , 10 ) / 100 ) * 100 ) / 100 ;
} ,
toRGB : function ( h , s , b , a ) {
if ( arguments . length === 0 ) {
h = this . value . h ;
s = this . value . s ;
b = this . value . b ;
a = this . value . a ;
}
h *= 360 ;
var R , G , B , X , C ;
h = ( h % 360 ) / 60 ;
C = b * s ;
X = C * ( 1 - Math . abs ( h % 2 - 1 ) ) ;
R = G = B = b - C ;
h = ~ ~ h ;
R += [ C , X , 0 , 0 , X , C ] [ h ] ;
G += [ X , C , C , X , 0 , 0 ] [ h ] ;
B += [ 0 , 0 , X , C , C , X ] [ h ] ;
return {
r : Math . round ( R * 255 ) ,
g : Math . round ( G * 255 ) ,
b : Math . round ( B * 255 ) ,
a : a
} ;
} ,
toHex : function ( ignoreFormat , h , s , b , a ) {
if ( arguments . length <= 1 ) {
h = this . value . h ;
s = this . value . s ;
b = this . value . b ;
a = this . value . a ;
}
var prefix = '#' ;
var rgb = this . toRGB ( h , s , b , a ) ;
if ( this . rgbaIsTransparent ( rgb ) ) {
return 'transparent' ;
}
if ( ! ignoreFormat ) {
prefix = ( this . hexNumberSignPrefix ? '#' : '' ) ;
}
var hexStr = prefix + (
( 1 << 24 ) +
( parseInt ( rgb . r ) << 16 ) +
( parseInt ( rgb . g ) << 8 ) +
parseInt ( rgb . b ) )
. toString ( 16 )
. slice ( 1 ) ;
return hexStr ;
} ,
toHSL : function ( h , s , b , a ) {
if ( arguments . length === 0 ) {
h = this . value . h ;
s = this . value . s ;
b = this . value . b ;
a = this . value . a ;
}
var H = h ,
L = ( 2 - s ) * b ,
S = s * b ;
if ( L > 0 && L <= 1 ) {
S /= L ;
} else {
S /= 2 - L ;
}
L /= 2 ;
if ( S > 1 ) {
S = 1 ;
}
return {
h : isNaN ( H ) ? 0 : H ,
s : isNaN ( S ) ? 0 : S ,
l : isNaN ( L ) ? 0 : L ,
a : isNaN ( a ) ? 0 : a
} ;
} ,
toAlias : function ( r , g , b , a ) {
var c , rgb = ( arguments . length === 0 ) ? this . toHex ( true ) : this . toHex ( true , r , g , b , a ) ;
// support predef. colors in non-hex format too, as defined in the alias itself
var original = this . origFormat === 'alias' ? rgb : this . toString ( false , this . origFormat ) ;
for ( var alias in this . colors ) {
c = this . colors [ alias ] . toLowerCase ( ) . trim ( ) ;
if ( ( c === rgb ) || ( c === original ) ) {
return alias ;
}
}
return false ;
} ,
RGBtoHSB : function ( r , g , b , a ) {
r /= 255 ;
g /= 255 ;
b /= 255 ;
var H , S , V , C ;
V = Math . max ( r , g , b ) ;
C = V - Math . min ( r , g , b ) ;
H = ( C === 0 ? null :
V === r ? ( g - b ) / C :
V === g ? ( b - r ) / C + 2 :
( r - g ) / C + 4
) ;
H = ( ( H + 360 ) % 6 ) * 60 / 360 ;
S = C === 0 ? 0 : C / V ;
return {
h : this . _sanitizeNumber ( H ) ,
s : S ,
b : V ,
a : this . _sanitizeNumber ( a )
} ;
} ,
HueToRGB : function ( p , q , h ) {
if ( h < 0 ) {
h += 1 ;
} else if ( h > 1 ) {
h -= 1 ;
}
if ( ( h * 6 ) < 1 ) {
return p + ( q - p ) * h * 6 ;
} else if ( ( h * 2 ) < 1 ) {
return q ;
} else if ( ( h * 3 ) < 2 ) {
return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6 ;
} else {
return p ;
}
} ,
HSLtoRGB : function ( h , s , l , a ) {
if ( s < 0 ) {
s = 0 ;
}
var q ;
if ( l <= 0.5 ) {
q = l * ( 1 + s ) ;
} else {
q = l + s - ( l * s ) ;
}
var p = 2 * l - q ;
var tr = h + ( 1 / 3 ) ;
var tg = h ;
var tb = h - ( 1 / 3 ) ;
var r = Math . round ( this . HueToRGB ( p , q , tr ) * 255 ) ;
var g = Math . round ( this . HueToRGB ( p , q , tg ) * 255 ) ;
var b = Math . round ( this . HueToRGB ( p , q , tb ) * 255 ) ;
return [ r , g , b , this . _sanitizeNumber ( a ) ] ;
} ,
/ * *
* @ param { String } strVal
* @ returns { Object } Object containing h , s , b , a , format properties or FALSE if failed to parse
* /
parse : function ( strVal ) {
if ( arguments . length === 0 ) {
return false ;
}
var that = this ,
result = false ,
isAlias = ( typeof this . colors [ strVal ] !== 'undefined' ) ,
values , format ;
if ( isAlias ) {
strVal = this . colors [ strVal ] . toLowerCase ( ) . trim ( ) ;
}
$ . each ( this . stringParsers , function ( i , parser ) {
var match = parser . re . exec ( strVal ) ;
values = match && parser . parse . apply ( that , [ match ] ) ;
if ( values ) {
result = { } ;
format = ( isAlias ? 'alias' : ( parser . format ? parser . format : that . getValidFallbackFormat ( ) ) ) ;
if ( format . match ( /hsla?/ ) ) {
result = that . RGBtoHSB . apply ( that , that . HSLtoRGB . apply ( that , values ) ) ;
} else {
result = that . RGBtoHSB . apply ( that , values ) ;
}
if ( result instanceof Object ) {
result . format = format ;
}
return false ; // stop iterating
}
return true ;
} ) ;
return result ;
} ,
getValidFallbackFormat : function ( ) {
var formats = [
'rgba' , 'rgb' , 'hex' , 'hsla' , 'hsl'
] ;
if ( this . origFormat && ( formats . indexOf ( this . origFormat ) !== - 1 ) ) {
return this . origFormat ;
}
if ( this . fallbackFormat && ( formats . indexOf ( this . fallbackFormat ) !== - 1 ) ) {
return this . fallbackFormat ;
}
return 'rgba' ; // By default, return a format that will not lose the alpha info
} ,
/ * *
*
* @ param { string } [ format ] ( default : rgba )
* @ param { boolean } [ translateAlias ] Return real color for pre - defined ( non - standard ) aliases ( default : false )
* @ param { boolean } [ forceRawValue ] Forces hashtag prefix when getting hex color ( default : false )
* @ returns { String }
* /
toString : function ( forceRawValue , format , translateAlias ) {
format = format || this . origFormat || this . fallbackFormat ;
translateAlias = translateAlias || false ;
var c = false ;
switch ( format ) {
case 'rgb' :
{
c = this . toRGB ( ) ;
if ( this . rgbaIsTransparent ( c ) ) {
return 'transparent' ;
}
return 'rgb(' + c . r + ',' + c . g + ',' + c . b + ')' ;
}
break ;
case 'rgba' :
{
c = this . toRGB ( ) ;
return 'rgba(' + c . r + ',' + c . g + ',' + c . b + ',' + c . a + ')' ;
}
break ;
case 'hsl' :
{
c = this . toHSL ( ) ;
return 'hsl(' + Math . round ( c . h * 360 ) + ',' + Math . round ( c . s * 100 ) + '%,' + Math . round ( c . l * 100 ) + '%)' ;
}
break ;
case 'hsla' :
{
c = this . toHSL ( ) ;
return 'hsla(' + Math . round ( c . h * 360 ) + ',' + Math . round ( c . s * 100 ) + '%,' + Math . round ( c . l * 100 ) + '%,' + c . a + ')' ;
}
break ;
case 'hex' :
{
return this . toHex ( forceRawValue ) ;
}
break ;
case 'alias' :
{
c = this . toAlias ( ) ;
if ( c === false ) {
return this . toString ( forceRawValue , this . getValidFallbackFormat ( ) ) ;
}
if ( translateAlias && ! ( c in Color . webColors ) && ( c in this . predefinedColors ) ) {
return this . predefinedColors [ c ] ;
}
return c ;
}
default :
{
return c ;
}
break ;
}
} ,
// a set of RE's that can match strings and generate color tuples.
// from John Resig color plugin
// https://github.com/jquery/jquery-color/
stringParsers : [ {
re : /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*?\)/ ,
format : 'rgb' ,
parse : function ( execResult ) {
return [
execResult [ 1 ] ,
execResult [ 2 ] ,
execResult [ 3 ] ,
1
] ;
}
} , {
re : /rgb\(\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*?\)/ ,
format : 'rgb' ,
parse : function ( execResult ) {
return [
2.55 * execResult [ 1 ] ,
2.55 * execResult [ 2 ] ,
2.55 * execResult [ 3 ] ,
1
] ;
}
} , {
re : /rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/ ,
format : 'rgba' ,
parse : function ( execResult ) {
return [
execResult [ 1 ] ,
execResult [ 2 ] ,
execResult [ 3 ] ,
execResult [ 4 ]
] ;
}
} , {
re : /rgba\(\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/ ,
format : 'rgba' ,
parse : function ( execResult ) {
return [
2.55 * execResult [ 1 ] ,
2.55 * execResult [ 2 ] ,
2.55 * execResult [ 3 ] ,
execResult [ 4 ]
] ;
}
} , {
re : /hsl\(\s*(\d*(?:\.\d+)?)\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*?\)/ ,
format : 'hsl' ,
parse : function ( execResult ) {
return [
execResult [ 1 ] / 360 ,
execResult [ 2 ] / 100 ,
execResult [ 3 ] / 100 ,
execResult [ 4 ]
] ;
}
} , {
re : /hsla\(\s*(\d*(?:\.\d+)?)\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/ ,
format : 'hsla' ,
parse : function ( execResult ) {
return [
execResult [ 1 ] / 360 ,
execResult [ 2 ] / 100 ,
execResult [ 3 ] / 100 ,
execResult [ 4 ]
] ;
}
} , {
re : /#?([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/ ,
format : 'hex' ,
parse : function ( execResult ) {
return [
parseInt ( execResult [ 1 ] , 16 ) ,
parseInt ( execResult [ 2 ] , 16 ) ,
parseInt ( execResult [ 3 ] , 16 ) ,
1
] ;
}
} , {
re : /#?([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/ ,
format : 'hex' ,
parse : function ( execResult ) {
return [
parseInt ( execResult [ 1 ] + execResult [ 1 ] , 16 ) ,
parseInt ( execResult [ 2 ] + execResult [ 2 ] , 16 ) ,
parseInt ( execResult [ 3 ] + execResult [ 3 ] , 16 ) ,
1
] ;
}
} ] ,
colorNameToHex : function ( name ) {
if ( typeof this . colors [ name . toLowerCase ( ) ] !== 'undefined' ) {
return this . colors [ name . toLowerCase ( ) ] ;
}
return false ;
}
} ;
/ *
* Default plugin options
* /
var defaults = {
horizontal : false , // horizontal mode layout ?
inline : false , //forces to show the colorpicker as an inline element
color : false , //forces a color
format : false , //forces a format
input : 'input' , // children input selector
container : false , // container selector
component : '.add-on, .input-group-addon' , // children component selector
fallbackColor : false , // fallback color value. null = keeps current color.
fallbackFormat : 'hex' , // fallback color format
hexNumberSignPrefix : true , // put a '#' (number sign) before hex strings
sliders : {
saturation : {
maxLeft : 100 ,
maxTop : 100 ,
callLeft : 'setSaturation' ,
callTop : 'setBrightness'
} ,
hue : {
maxLeft : 0 ,
maxTop : 100 ,
callLeft : false ,
callTop : 'setHue'
} ,
alpha : {
maxLeft : 0 ,
maxTop : 100 ,
callLeft : false ,
callTop : 'setAlpha'
}
} ,
slidersHorz : {
saturation : {
maxLeft : 100 ,
maxTop : 100 ,
callLeft : 'setSaturation' ,
callTop : 'setBrightness'
} ,
hue : {
maxLeft : 100 ,
maxTop : 0 ,
callLeft : 'setHue' ,
callTop : false
} ,
alpha : {
maxLeft : 100 ,
maxTop : 0 ,
callLeft : 'setAlpha' ,
callTop : false
}
} ,
template : '<div class="colorpicker dropdown-menu">' +
'<div class="colorpicker-saturation"><i><b></b></i></div>' +
'<div class="colorpicker-hue"><i></i></div>' +
'<div class="colorpicker-alpha"><i></i></div>' +
'<div class="colorpicker-color"><div /></div>' +
'<div class="colorpicker-selectors"></div>' +
'</div>' ,
align : 'right' ,
customClass : null , // custom class added to the colorpicker element
colorSelectors : null // custom color aliases
} ;
/ * *
* Colorpicker component class
*
* @ param { Object | String } element
* @ param { Object } options
* @ constructor
* /
var Colorpicker = function ( element , options ) {
this . element = $ ( element ) . addClass ( 'colorpicker-element' ) ;
this . options = $ . extend ( true , { } , defaults , this . element . data ( ) , options ) ;
this . component = this . options . component ;
this . component = ( this . component !== false ) ? this . element . find ( this . component ) : false ;
if ( this . component && ( this . component . length === 0 ) ) {
this . component = false ;
}
this . container = ( this . options . container === true ) ? this . element : this . options . container ;
this . container = ( this . container !== false ) ? $ ( this . container ) : false ;
// Is the element an input? Should we search inside for any input?
this . input = this . element . is ( 'input' ) ? this . element : ( this . options . input ?
this . element . find ( this . options . input ) : false ) ;
if ( this . input && ( this . input . length === 0 ) ) {
this . input = false ;
}
// Set HSB color
this . color = this . createColor ( this . options . color !== false ? this . options . color : this . getValue ( ) ) ;
this . format = this . options . format !== false ? this . options . format : this . color . origFormat ;
if ( this . options . color !== false ) {
this . updateInput ( this . color ) ;
this . updateData ( this . color ) ;
}
this . disabled = false ;
// Setup picker
var $picker = this . picker = $ ( this . options . template ) ;
if ( this . options . customClass ) {
$picker . addClass ( this . options . customClass ) ;
}
if ( this . options . inline ) {
$picker . addClass ( 'colorpicker-inline colorpicker-visible' ) ;
} else {
$picker . addClass ( 'colorpicker-hidden' ) ;
}
if ( this . options . horizontal ) {
$picker . addClass ( 'colorpicker-horizontal' ) ;
}
if (
( [ 'rgba' , 'hsla' , 'alias' ] . indexOf ( this . format ) !== - 1 ) ||
this . options . format === false ||
this . getValue ( ) === 'transparent'
) {
$picker . addClass ( 'colorpicker-with-alpha' ) ;
}
if ( this . options . align === 'right' ) {
$picker . addClass ( 'colorpicker-right' ) ;
}
if ( this . options . inline === true ) {
$picker . addClass ( 'colorpicker-no-arrow' ) ;
}
if ( this . options . colorSelectors ) {
var colorpicker = this ,
selectorsContainer = colorpicker . picker . find ( '.colorpicker-selectors' ) ;
if ( selectorsContainer . length > 0 ) {
$ . each ( this . options . colorSelectors , function ( name , color ) {
var $btn = $ ( '<i />' )
. addClass ( 'colorpicker-selectors-color' )
. css ( 'background-color' , color )
. data ( 'class' , name ) . data ( 'alias' , name ) ;
$btn . on ( 'mousedown.colorpicker touchstart.colorpicker' , function ( event ) {
event . preventDefault ( ) ;
colorpicker . setValue (
colorpicker . format === 'alias' ? $ ( this ) . data ( 'alias' ) : $ ( this ) . css ( 'background-color' )
) ;
} ) ;
selectorsContainer . append ( $btn ) ;
} ) ;
selectorsContainer . show ( ) . addClass ( 'colorpicker-visible' ) ;
}
}
// Prevent closing the colorpicker when clicking on itself
$picker . on ( 'mousedown.colorpicker touchstart.colorpicker' , $ . proxy ( function ( e ) {
if ( e . target === e . currentTarget ) {
e . preventDefault ( ) ;
}
} , this ) ) ;
// Bind click/tap events on the sliders
$picker . find ( '.colorpicker-saturation, .colorpicker-hue, .colorpicker-alpha' )
. on ( 'mousedown.colorpicker touchstart.colorpicker' , $ . proxy ( this . mousedown , this ) ) ;
$picker . appendTo ( this . container ? this . container : $ ( 'body' ) ) ;
// Bind other events
if ( this . input !== false ) {
this . input . on ( {
'keyup.colorpicker' : $ . proxy ( this . keyup , this )
} ) ;
this . input . on ( {
'change.colorpicker' : $ . proxy ( this . change , this )
} ) ;
if ( this . component === false ) {
this . element . on ( {
'focus.colorpicker' : $ . proxy ( this . show , this )
} ) ;
}
if ( this . options . inline === false ) {
this . element . on ( {
'focusout.colorpicker' : $ . proxy ( this . hide , this )
} ) ;
}
}
if ( this . component !== false ) {
this . component . on ( {
'click.colorpicker' : $ . proxy ( this . show , this )
} ) ;
}
if ( ( this . input === false ) && ( this . component === false ) ) {
this . element . on ( {
'click.colorpicker' : $ . proxy ( this . show , this )
} ) ;
}
// for HTML5 input[type='color']
if ( ( this . input !== false ) && ( this . component !== false ) && ( this . input . attr ( 'type' ) === 'color' ) ) {
this . input . on ( {
'click.colorpicker' : $ . proxy ( this . show , this ) ,
'focus.colorpicker' : $ . proxy ( this . show , this )
} ) ;
}
this . update ( ) ;
$ ( $ . proxy ( function ( ) {
this . element . trigger ( 'create' ) ;
} , this ) ) ;
} ;
Colorpicker . Color = Color ;
Colorpicker . prototype = {
constructor : Colorpicker ,
destroy : function ( ) {
this . picker . remove ( ) ;
this . element . removeData ( 'colorpicker' , 'color' ) . off ( '.colorpicker' ) ;
if ( this . input !== false ) {
this . input . off ( '.colorpicker' ) ;
}
if ( this . component !== false ) {
this . component . off ( '.colorpicker' ) ;
}
this . element . removeClass ( 'colorpicker-element' ) ;
this . element . trigger ( {
type : 'destroy'
} ) ;
} ,
reposition : function ( ) {
if ( this . options . inline !== false || this . options . container ) {
return false ;
}
var type = this . container && this . container [ 0 ] !== window . document . body ? 'position' : 'offset' ;
var element = this . component || this . element ;
var offset = element [ type ] ( ) ;
if ( this . options . align === 'right' ) {
offset . left -= this . picker . outerWidth ( ) - element . outerWidth ( ) ;
}
this . picker . css ( {
top : offset . top + element . outerHeight ( ) ,
left : offset . left
} ) ;
} ,
show : function ( e ) {
if ( this . isDisabled ( ) ) {
// Don't show the widget if it's disabled (the input)
return ;
}
this . picker . addClass ( 'colorpicker-visible' ) . removeClass ( 'colorpicker-hidden' ) ;
this . reposition ( ) ;
$ ( window ) . on ( 'resize.colorpicker' , $ . proxy ( this . reposition , this ) ) ;
if ( e && ( ! this . hasInput ( ) || this . input . attr ( 'type' ) === 'color' ) ) {
if ( e . stopPropagation && e . preventDefault ) {
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
}
}
if ( ( this . component || ! this . input ) && ( this . options . inline === false ) ) {
$ ( window . document ) . on ( {
'mousedown.colorpicker' : $ . proxy ( this . hide , this )
} ) ;
}
this . element . trigger ( {
type : 'showPicker' ,
color : this . color
} ) ;
} ,
hide : function ( e ) {
if ( ( typeof e !== 'undefined' ) && e . target ) {
// Prevent hide if triggered by an event and an element inside the colorpicker has been clicked/touched
if (
$ ( e . currentTarget ) . parents ( '.colorpicker' ) . length > 0 ||
$ ( e . target ) . parents ( '.colorpicker' ) . length > 0
) {
return false ;
}
}
this . picker . addClass ( 'colorpicker-hidden' ) . removeClass ( 'colorpicker-visible' ) ;
$ ( window ) . off ( 'resize.colorpicker' , this . reposition ) ;
$ ( window . document ) . off ( {
'mousedown.colorpicker' : this . hide
} ) ;
this . update ( ) ;
this . element . trigger ( {
type : 'hidePicker' ,
color : this . color
} ) ;
} ,
updateData : function ( val ) {
val = val || this . color . toString ( false , this . format ) ;
this . element . data ( 'color' , val ) ;
return val ;
} ,
updateInput : function ( val ) {
val = val || this . color . toString ( false , this . format ) ;
if ( this . input !== false ) {
this . input . prop ( 'value' , val ) ;
this . input . trigger ( 'change' ) ;
}
return val ;
} ,
updatePicker : function ( val ) {
if ( typeof val !== 'undefined' ) {
this . color = this . createColor ( val ) ;
}
var sl = ( this . options . horizontal === false ) ? this . options . sliders : this . options . slidersHorz ;
var icns = this . picker . find ( 'i' ) ;
if ( icns . length === 0 ) {
return ;
}
if ( this . options . horizontal === false ) {
sl = this . options . sliders ;
icns . eq ( 1 ) . css ( 'top' , sl . hue . maxTop * ( 1 - this . color . value . h ) ) . end ( )
. eq ( 2 ) . css ( 'top' , sl . alpha . maxTop * ( 1 - this . color . value . a ) ) ;
} else {
sl = this . options . slidersHorz ;
icns . eq ( 1 ) . css ( 'left' , sl . hue . maxLeft * ( 1 - this . color . value . h ) ) . end ( )
. eq ( 2 ) . css ( 'left' , sl . alpha . maxLeft * ( 1 - this . color . value . a ) ) ;
}
icns . eq ( 0 ) . css ( {
'top' : sl . saturation . maxTop - this . color . value . b * sl . saturation . maxTop ,
'left' : this . color . value . s * sl . saturation . maxLeft
} ) ;
this . picker . find ( '.colorpicker-saturation' )
. css ( 'backgroundColor' , this . color . toHex ( true , this . color . value . h , 1 , 1 , 1 ) ) ;
this . picker . find ( '.colorpicker-alpha' )
. css ( 'backgroundColor' , this . color . toHex ( true ) ) ;
this . picker . find ( '.colorpicker-color, .colorpicker-color div' )
. css ( 'backgroundColor' , this . color . toString ( true , this . format ) ) ;
return val ;
} ,
updateComponent : function ( val ) {
var color ;
if ( typeof val !== 'undefined' ) {
color = this . createColor ( val ) ;
} else {
color = this . color ;
}
if ( this . component !== false ) {
var icn = this . component . find ( 'i' ) . eq ( 0 ) ;
if ( icn . length > 0 ) {
icn . css ( {
'backgroundColor' : color . toString ( true , this . format )
} ) ;
} else {
this . component . css ( {
'backgroundColor' : color . toString ( true , this . format )
} ) ;
}
}
return color . toString ( false , this . format ) ;
} ,
update : function ( force ) {
var val ;
if ( ( this . getValue ( false ) !== false ) || ( force === true ) ) {
// Update input/data only if the current value is not empty
val = this . updateComponent ( ) ;
this . updateInput ( val ) ;
this . updateData ( val ) ;
this . updatePicker ( ) ; // only update picker if value is not empty
}
return val ;
} ,
setValue : function ( val ) { // set color manually
this . color = this . createColor ( val ) ;
this . update ( true ) ;
this . element . trigger ( {
type : 'changeColor' ,
color : this . color ,
value : val
} ) ;
} ,
/ * *
* Creates a new color using the instance options
* @ protected
* @ param { String } val
* @ returns { Color }
* /
createColor : function ( val ) {
return new Color (
val ? val : null ,
this . options . colorSelectors ,
this . options . fallbackColor ? this . options . fallbackColor : this . color ,
this . options . fallbackFormat ,
this . options . hexNumberSignPrefix
) ;
} ,
getValue : function ( defaultValue ) {
defaultValue = ( typeof defaultValue === 'undefined' ) ? this . options . fallbackColor : defaultValue ;
var val ;
if ( this . hasInput ( ) ) {
val = this . input . val ( ) ;
} else {
val = this . element . data ( 'color' ) ;
}
if ( ( val === undefined ) || ( val === '' ) || ( val === null ) ) {
// if not defined or empty, return default
val = defaultValue ;
}
return val ;
} ,
hasInput : function ( ) {
return ( this . input !== false ) ;
} ,
isDisabled : function ( ) {
return this . disabled ;
} ,
disable : function ( ) {
if ( this . hasInput ( ) ) {
this . input . prop ( 'disabled' , true ) ;
}
this . disabled = true ;
this . element . trigger ( {
type : 'disable' ,
color : this . color ,
value : this . getValue ( )
} ) ;
return true ;
} ,
enable : function ( ) {
if ( this . hasInput ( ) ) {
this . input . prop ( 'disabled' , false ) ;
}
this . disabled = false ;
this . element . trigger ( {
type : 'enable' ,
color : this . color ,
value : this . getValue ( )
} ) ;
return true ;
} ,
currentSlider : null ,
mousePointer : {
left : 0 ,
top : 0
} ,
mousedown : function ( e ) {
if ( ! e . pageX && ! e . pageY && e . originalEvent && e . originalEvent . touches ) {
e . pageX = e . originalEvent . touches [ 0 ] . pageX ;
e . pageY = e . originalEvent . touches [ 0 ] . pageY ;
}
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
var target = $ ( e . target ) ;
//detect the slider and set the limits and callbacks
var zone = target . closest ( 'div' ) ;
var sl = this . options . horizontal ? this . options . slidersHorz : this . options . sliders ;
if ( ! zone . is ( '.colorpicker' ) ) {
if ( zone . is ( '.colorpicker-saturation' ) ) {
this . currentSlider = $ . extend ( { } , sl . saturation ) ;
} else if ( zone . is ( '.colorpicker-hue' ) ) {
this . currentSlider = $ . extend ( { } , sl . hue ) ;
} else if ( zone . is ( '.colorpicker-alpha' ) ) {
this . currentSlider = $ . extend ( { } , sl . alpha ) ;
} else {
return false ;
}
var offset = zone . offset ( ) ;
//reference to guide's style
this . currentSlider . guide = zone . find ( 'i' ) [ 0 ] . style ;
this . currentSlider . left = e . pageX - offset . left ;
this . currentSlider . top = e . pageY - offset . top ;
this . mousePointer = {
left : e . pageX ,
top : e . pageY
} ;
//trigger mousemove to move the guide to the current position
$ ( window . document ) . on ( {
'mousemove.colorpicker' : $ . proxy ( this . mousemove , this ) ,
'touchmove.colorpicker' : $ . proxy ( this . mousemove , this ) ,
'mouseup.colorpicker' : $ . proxy ( this . mouseup , this ) ,
'touchend.colorpicker' : $ . proxy ( this . mouseup , this )
} ) . trigger ( 'mousemove' ) ;
}
return false ;
} ,
mousemove : function ( e ) {
if ( ! e . pageX && ! e . pageY && e . originalEvent && e . originalEvent . touches ) {
e . pageX = e . originalEvent . touches [ 0 ] . pageX ;
e . pageY = e . originalEvent . touches [ 0 ] . pageY ;
}
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
var left = Math . max (
0 ,
Math . min (
this . currentSlider . maxLeft ,
this . currentSlider . left + ( ( e . pageX || this . mousePointer . left ) - this . mousePointer . left )
)
) ;
var top = Math . max (
0 ,
Math . min (
this . currentSlider . maxTop ,
this . currentSlider . top + ( ( e . pageY || this . mousePointer . top ) - this . mousePointer . top )
)
) ;
this . currentSlider . guide . left = left + 'px' ;
this . currentSlider . guide . top = top + 'px' ;
if ( this . currentSlider . callLeft ) {
this . color [ this . currentSlider . callLeft ] . call ( this . color , left / this . currentSlider . maxLeft ) ;
}
if ( this . currentSlider . callTop ) {
this . color [ this . currentSlider . callTop ] . call ( this . color , top / this . currentSlider . maxTop ) ;
}
// Change format dynamically
// Only occurs if user choose the dynamic format by
// setting option format to false
if (
this . options . format === false &&
( this . currentSlider . callTop === 'setAlpha' ||
this . currentSlider . callLeft === 'setAlpha' )
) {
// Converting from hex / rgb to rgba
if ( this . color . value . a !== 1 ) {
this . format = 'rgba' ;
this . color . origFormat = 'rgba' ;
}
// Converting from rgba to hex
else {
this . format = 'hex' ;
this . color . origFormat = 'hex' ;
}
}
this . update ( true ) ;
this . element . trigger ( {
type : 'changeColor' ,
color : this . color
} ) ;
return false ;
} ,
mouseup : function ( e ) {
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
$ ( window . document ) . off ( {
'mousemove.colorpicker' : this . mousemove ,
'touchmove.colorpicker' : this . mousemove ,
'mouseup.colorpicker' : this . mouseup ,
'touchend.colorpicker' : this . mouseup
} ) ;
return false ;
} ,
change : function ( e ) {
this . keyup ( e ) ;
} ,
keyup : function ( e ) {
if ( ( e . keyCode === 38 ) ) {
if ( this . color . value . a < 1 ) {
this . color . value . a = Math . round ( ( this . color . value . a + 0.01 ) * 100 ) / 100 ;
}
this . update ( true ) ;
} else if ( ( e . keyCode === 40 ) ) {
if ( this . color . value . a > 0 ) {
this . color . value . a = Math . round ( ( this . color . value . a - 0.01 ) * 100 ) / 100 ;
}
this . update ( true ) ;
} else {
this . color = this . createColor ( this . input . val ( ) ) ;
// Change format dynamically
// Only occurs if user choose the dynamic format by
// setting option format to false
if ( this . color . origFormat && this . options . format === false ) {
this . format = this . color . origFormat ;
}
if ( this . getValue ( false ) !== false ) {
this . updateData ( ) ;
this . updateComponent ( ) ;
this . updatePicker ( ) ;
}
}
this . element . trigger ( {
type : 'changeColor' ,
color : this . color ,
value : this . input . val ( )
} ) ;
}
} ;
$ . colorpicker = Colorpicker ;
$ . fn . colorpicker = function ( option ) {
var apiArgs = Array . prototype . slice . call ( arguments , 1 ) ,
isSingleElement = ( this . length === 1 ) ,
returnValue = null ;
var $jq = this . each ( function ( ) {
var $this = $ ( this ) ,
inst = $this . data ( 'colorpicker' ) ,
options = ( ( typeof option === 'object' ) ? option : { } ) ;
if ( ! inst ) {
inst = new Colorpicker ( this , options ) ;
$this . data ( 'colorpicker' , inst ) ;
}
if ( typeof option === 'string' ) {
if ( $ . isFunction ( inst [ option ] ) ) {
returnValue = inst [ option ] . apply ( inst , apiArgs ) ;
} else { // its a property ?
if ( apiArgs . length ) {
// set property
inst [ option ] = apiArgs [ 0 ] ;
}
returnValue = inst [ option ] ;
}
} else {
returnValue = $this ;
}
} ) ;
return isSingleElement ? returnValue : $jq ;
} ;
$ . fn . colorpicker . constructor = Colorpicker ;
} ) ) ;
/ * !
* Datepicker for Bootstrap v1 . 7.1 ( https : //github.com/uxsolutions/bootstrap-datepicker)
*
* Licensed under the Apache License v2 . 0 ( http : //www.apache.org/licenses/LICENSE-2.0)
* /
( 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 . _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, .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 ( ) ;
}
} ,
_events : [ ] ,
_secondaryEvents : [ ] ,
_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 . prop ( '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 = '<tr>' ;
if ( this . o . calendarWeeks ) {
html += '<th class="cw"> </th>' ;
}
while ( dowCnt < this . o . weekStart + 7 ) {
html += '<th class="dow' ;
if ( $ . inArray ( dowCnt , this . o . daysOfWeekDisabled ) !== - 1 )
html += ' disabled' ;
html += '">' + dates [ this . o . language ] . daysMin [ ( dowCnt ++ ) % 7 ] + '</th>' ;
}
html += '</tr>' ;
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 += '<span class="month' + focused + '">' + dates [ this . o . language ] . monthsShort [ i ] + '</span>' ;
}
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 += '<span class="' + classes . join ( ' ' ) + '"' + ( tooltip ? ' title="' + tooltip + '"' : '' ) + '>' + currVal + '</span>' ;
}
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 ,
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' , this . o . todayBtn === true || this . o . todayBtn === 'linked' ? '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 ( '<tr>' ) ;
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 ( '<td class="cw">' + calWeek + '</td>' ) ;
}
}
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 ( '<td class="' + clsName . join ( ' ' ) + '"' + ( tooltip ? ' title="' + tooltip + '"' : '' ) + ' data-date="' + prevMonth . getTime ( ) . toString ( ) + '">' + content + '</td>' ) ;
tooltip = null ;
if ( weekDay === this . o . weekEnd ) {
html . push ( '</tr>' ) ;
}
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 0 :
prevIsDisabled = year <= startYear && month <= startMonth ;
nextIsDisabled = year >= endYear && month >= endMonth ;
break ;
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 ;
}
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 ) ;
} ) ;
} ,
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 : '<thead>' +
'<tr>' +
'<th colspan="7" class="datepicker-title"></th>' +
'</tr>' +
'<tr>' +
'<th class="prev">' + defaults . templates . leftArrow + '</th>' +
'<th colspan="5" class="datepicker-switch"></th>' +
'<th class="next">' + defaults . templates . rightArrow + '</th>' +
'</tr>' +
'</thead>' ,
contTemplate : '<tbody><tr><td colspan="7"></td></tr></tbody>' ,
footTemplate : '<tfoot>' +
'<tr>' +
'<th colspan="7" class="today"></th>' +
'</tr>' +
'<tr>' +
'<th colspan="7" class="clear"></th>' +
'</tr>' +
'</tfoot>'
} ;
DPGlobal . template = '<div class="datepicker">' +
'<div class="datepicker-days">' +
'<table class="table-condensed">' +
DPGlobal . headTemplate +
'<tbody></tbody>' +
DPGlobal . footTemplate +
'</table>' +
'</div>' +
'<div class="datepicker-months">' +
'<table class="table-condensed">' +
DPGlobal . headTemplate +
DPGlobal . contTemplate +
DPGlobal . footTemplate +
'</table>' +
'</div>' +
'<div class="datepicker-years">' +
'<table class="table-condensed">' +
DPGlobal . headTemplate +
DPGlobal . contTemplate +
DPGlobal . footTemplate +
'</table>' +
'</div>' +
'<div class="datepicker-decades">' +
'<table class="table-condensed">' +
DPGlobal . headTemplate +
DPGlobal . contTemplate +
DPGlobal . footTemplate +
'</table>' +
'</div>' +
'<div class="datepicker-centuries">' +
'<table class="table-condensed">' +
DPGlobal . headTemplate +
DPGlobal . contTemplate +
DPGlobal . footTemplate +
'</table>' +
'</div>' +
'</div>' ;
$ . fn . datepicker . DPGlobal = DPGlobal ;
/ * D A T E P I C K E R N O C O N F L I C T
* === === === === === === = * /
$ . fn . datepicker . noConflict = function ( ) {
$ . fn . datepicker = old ;
return this ;
} ;
/ * D A T E P I C K E R V E R S I O N
* === === === === === === = * /
$ . fn . datepicker . version = '1.7.1' ;
$ . fn . datepicker . deprecated = function ( msg ) {
var console = window . console ;
if ( console && console . warn ) {
console . warn ( 'DEPRECATED: ' + msg ) ;
}
} ;
/ * D A T E P I C K E R D A T A - A P I
* === === === === === === * /
$ ( 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"]' ) ) ;
} ) ;
} ) ) ;
/ * !
* iCheck v1 . 0.2 , http : //git.io/arlzeA
* === === === === === === === === === === === ==
* Powerful jQuery and Zepto plugin for checkboxes and radio buttons customization
*
* ( c ) 2013 Damir Sultanov , http : //fronteed.com
* MIT Licensed
* /
( function ( $ ) {
// Cached vars
var _iCheck = 'iCheck' ,
_iCheckHelper = _iCheck + '-helper' ,
_checkbox = 'checkbox' ,
_radio = 'radio' ,
_checked = 'checked' ,
_unchecked = 'un' + _checked ,
_disabled = 'disabled' , a
_determinate = 'determinate' ,
_indeterminate = 'in' + _determinate ,
_update = 'update' ,
_type = 'type' ,
_click = 'click' ,
_touch = 'touchbegin.i touchend.i' ,
_add = 'addClass' ,
_remove = 'removeClass' ,
_callback = 'trigger' ,
_label = 'label' ,
_cursor = 'cursor' ,
_mobile = /ipad|iphone|ipod|android|blackberry|windows phone|opera mini|silk/i . test ( navigator . userAgent ) ;
// Plugin init
$ . fn [ _iCheck ] = function ( options , fire ) {
// Walker
var handle = 'input[type="' + _checkbox + '"], input[type="' + _radio + '"]' ,
stack = $ ( ) ,
walker = function ( object ) {
object . each ( function ( ) {
var self = $ ( this ) ;
if ( self . is ( handle ) ) {
stack = stack . add ( self ) ;
} else {
stack = stack . add ( self . find ( handle ) ) ;
}
} ) ;
} ;
// Check if we should operate with some method
if ( /^(check|uncheck|toggle|indeterminate|determinate|disable|enable|update|destroy)$/i . test ( options ) ) {
// Normalize method's name
options = options . toLowerCase ( ) ;
// Find checkboxes and radio buttons
walker ( this ) ;
return stack . each ( function ( ) {
var self = $ ( this ) ;
if ( options == 'destroy' ) {
tidy ( self , 'ifDestroyed' ) ;
} else {
operate ( self , true , options ) ;
}
// Fire method's callback
if ( $ . isFunction ( fire ) ) {
fire ( ) ;
}
} ) ;
// Customization
} else if ( typeof options == 'object' || ! options ) {
// Check if any options were passed
var settings = $ . extend ( {
checkedClass : _checked ,
disabledClass : _disabled ,
indeterminateClass : _indeterminate ,
labelHover : true
} , options ) ,
selector = settings . handle ,
hoverClass = settings . hoverClass || 'hover' ,
focusClass = settings . focusClass || 'focus' ,
activeClass = settings . activeClass || 'active' ,
labelHover = ! ! settings . labelHover ,
labelHoverClass = settings . labelHoverClass || 'hover' ,
// Setup clickable area
area = ( '' + settings . increaseArea ) . replace ( '%' , '' ) | 0 ;
// Selector limit
if ( selector == _checkbox || selector == _radio ) {
handle = 'input[type="' + selector + '"]' ;
}
// Clickable area limit
if ( area < - 50 ) {
area = - 50 ;
}
// Walk around the selector
walker ( this ) ;
return stack . each ( function ( ) {
var self = $ ( this ) ;
// If already customized
tidy ( self ) ;
var node = this ,
id = node . id ,
// Layer styles
offset = - area + '%' ,
size = 100 + ( area * 2 ) + '%' ,
layer = {
position : 'absolute' ,
top : offset ,
left : offset ,
display : 'block' ,
width : size ,
height : size ,
margin : 0 ,
padding : 0 ,
background : '#fff' ,
border : 0 ,
opacity : 0
} ,
// Choose how to hide input
hide = _mobile ? {
position : 'absolute' ,
visibility : 'hidden'
} : area ? layer : {
position : 'absolute' ,
opacity : 0
} ,
// Get proper class
className = node [ _type ] == _checkbox ? settings . checkboxClass || 'i' + _checkbox : settings . radioClass || 'i' + _radio ,
// Find assigned labels
label = $ ( _label + '[for="' + id + '"]' ) . add ( self . closest ( _label ) ) ,
// Check ARIA option
aria = ! ! settings . aria ,
// Set ARIA placeholder
ariaID = _iCheck + '-' + Math . random ( ) . toString ( 36 ) . substr ( 2 , 6 ) ,
// Parent & helper
parent = '<div class="' + className + '" ' + ( aria ? 'role="' + node [ _type ] + '" ' : '' ) ,
helper ;
// Set ARIA "labelledby"
if ( aria ) {
label . each ( function ( ) {
parent += 'aria-labelledby="' ;
if ( this . id ) {
parent += this . id ;
} else {
this . id = ariaID ;
parent += ariaID ;
}
parent += '"' ;
} ) ;
}
// Wrap input
parent = self . wrap ( parent + '/>' ) [ _callback ] ( 'ifCreated' ) . parent ( ) . append ( settings . insert ) ;
// Layer addition
helper = $ ( '<ins class="' + _iCheckHelper + '"/>' ) . css ( layer ) . appendTo ( parent ) ;
// Finalize customization
self . data ( _iCheck , { o : settings , s : self . attr ( 'style' ) } ) . css ( hide ) ;
! ! settings . inheritClass && parent [ _add ] ( node . className || '' ) ;
! ! settings . inheritID && id && parent . attr ( 'id' , _iCheck + '-' + id ) ;
parent . css ( 'position' ) == 'static' && parent . css ( 'position' , 'relative' ) ;
operate ( self , true , _update ) ;
// Label events
if ( label . length ) {
label . on ( _click + '.i mouseover.i mouseout.i ' + _touch , function ( event ) {
var type = event [ _type ] ,
item = $ ( this ) ;
// Do nothing if input is disabled
if ( ! node [ _disabled ] ) {
// Click
if ( type == _click ) {
if ( $ ( event . target ) . is ( 'a' ) ) {
return ;
}
operate ( self , false , true ) ;
// Hover state
} else if ( labelHover ) {
// mouseout|touchend
if ( /ut|nd/ . test ( type ) ) {
parent [ _remove ] ( hoverClass ) ;
item [ _remove ] ( labelHoverClass ) ;
} else {
parent [ _add ] ( hoverClass ) ;
item [ _add ] ( labelHoverClass ) ;
}
}
if ( _mobile ) {
event . stopPropagation ( ) ;
} else {
return false ;
}
}
} ) ;
}
// Input events
self . on ( _click + '.i focus.i blur.i keyup.i keydown.i keypress.i' , function ( event ) {
var type = event [ _type ] ,
key = event . keyCode ;
// Click
if ( type == _click ) {
return false ;
// Keydown
} else if ( type == 'keydown' && key == 32 ) {
if ( ! ( node [ _type ] == _radio && node [ _checked ] ) ) {
if ( node [ _checked ] ) {
off ( self , _checked ) ;
} else {
on ( self , _checked ) ;
}
}
return false ;
// Keyup
} else if ( type == 'keyup' && node [ _type ] == _radio ) {
! node [ _checked ] && on ( self , _checked ) ;
// Focus/blur
} else if ( /us|ur/ . test ( type ) ) {
parent [ type == 'blur' ? _remove : _add ] ( focusClass ) ;
}
} ) ;
// Helper events
helper . on ( _click + ' mousedown mouseup mouseover mouseout ' + _touch , function ( event ) {
var type = event [ _type ] ,
// mousedown|mouseup
toggle = /wn|up/ . test ( type ) ? activeClass : hoverClass ;
// Do nothing if input is disabled
if ( ! node [ _disabled ] ) {
// Click
if ( type == _click ) {
operate ( self , false , true ) ;
// Active and hover states
} else {
// State is on
if ( /wn|er|in/ . test ( type ) ) {
// mousedown|mouseover|touchbegin
parent [ _add ] ( toggle ) ;
// State is off
} else {
parent [ _remove ] ( toggle + ' ' + activeClass ) ;
}
// Label hover
if ( label . length && labelHover && toggle == hoverClass ) {
// mouseout|touchend
label [ /ut|nd/ . test ( type ) ? _remove : _add ] ( labelHoverClass ) ;
}
}
if ( _mobile ) {
event . stopPropagation ( ) ;
} else {
return false ;
}
}
} ) ;
} ) ;
} else {
return this ;
}
} ;
// Do something with inputs
function operate ( input , direct , method ) {
var node = input [ 0 ] ,
state = /er/ . test ( method ) ? _indeterminate : /bl/ . test ( method ) ? _disabled : _checked ,
active = method == _update ? {
checked : node [ _checked ] ,
disabled : node [ _disabled ] ,
indeterminate : input . attr ( _indeterminate ) == 'true' || input . attr ( _determinate ) == 'false'
} : node [ state ] ;
// Check, disable or indeterminate
if ( /^(ch|di|in)/ . test ( method ) && ! active ) {
on ( input , state ) ;
// Uncheck, enable or determinate
} else if ( /^(un|en|de)/ . test ( method ) && active ) {
off ( input , state ) ;
// Update
} else if ( method == _update ) {
// Handle states
for ( var each in active ) {
if ( active [ each ] ) {
on ( input , each , true ) ;
} else {
off ( input , each , true ) ;
}
}
} else if ( ! direct || method == 'toggle' ) {
// Helper or label was clicked
if ( ! direct ) {
input [ _callback ] ( 'ifClicked' ) ;
}
// Toggle checked state
if ( active ) {
if ( node [ _type ] !== _radio ) {
off ( input , state ) ;
}
} else {
on ( input , state ) ;
}
}
}
// Add checked, disabled or indeterminate state
function on ( input , state , keep ) {
var node = input [ 0 ] ,
parent = input . parent ( ) ,
checked = state == _checked ,
indeterminate = state == _indeterminate ,
disabled = state == _disabled ,
callback = indeterminate ? _determinate : checked ? _unchecked : 'enabled' ,
regular = option ( input , callback + capitalize ( node [ _type ] ) ) ,
specific = option ( input , state + capitalize ( node [ _type ] ) ) ;
// Prevent unnecessary actions
if ( node [ state ] !== true ) {
// Toggle assigned radio buttons
if ( ! keep && state == _checked && node [ _type ] == _radio && node . name ) {
var form = input . closest ( 'form' ) ,
inputs = 'input[name="' + node . name + '"]' ;
inputs = form . length ? form . find ( inputs ) : $ ( inputs ) ;
inputs . each ( function ( ) {
if ( this !== node && $ ( this ) . data ( _iCheck ) ) {
off ( $ ( this ) , state ) ;
}
} ) ;
}
// Indeterminate state
if ( indeterminate ) {
// Add indeterminate state
node [ state ] = true ;
// Remove checked state
if ( node [ _checked ] ) {
off ( input , _checked , 'force' ) ;
}
// Checked or disabled state
} else {
// Add checked or disabled state
if ( ! keep ) {
node [ state ] = true ;
}
// Remove indeterminate state
if ( checked && node [ _indeterminate ] ) {
off ( input , _indeterminate , false ) ;
}
}
// Trigger callbacks
callbacks ( input , checked , state , keep ) ;
}
// Add proper cursor
if ( node [ _disabled ] && ! ! option ( input , _cursor , true ) ) {
parent . find ( '.' + _iCheckHelper ) . css ( _cursor , 'default' ) ;
}
// Add state class
parent [ _add ] ( specific || option ( input , state ) || '' ) ;
// Set ARIA attribute
if ( ! ! parent . attr ( 'role' ) && ! indeterminate ) {
parent . attr ( 'aria-' + ( disabled ? _disabled : _checked ) , 'true' ) ;
}
// Remove regular state class
parent [ _remove ] ( regular || option ( input , callback ) || '' ) ;
}
// Remove checked, disabled or indeterminate state
function off ( input , state , keep ) {
var node = input [ 0 ] ,
parent = input . parent ( ) ,
checked = state == _checked ,
indeterminate = state == _indeterminate ,
disabled = state == _disabled ,
callback = indeterminate ? _determinate : checked ? _unchecked : 'enabled' ,
regular = option ( input , callback + capitalize ( node [ _type ] ) ) ,
specific = option ( input , state + capitalize ( node [ _type ] ) ) ;
// Prevent unnecessary actions
if ( node [ state ] !== false ) {
// Toggle state
if ( indeterminate || ! keep || keep == 'force' ) {
node [ state ] = false ;
}
// Trigger callbacks
callbacks ( input , checked , callback , keep ) ;
}
// Add proper cursor
if ( ! node [ _disabled ] && ! ! option ( input , _cursor , true ) ) {
parent . find ( '.' + _iCheckHelper ) . css ( _cursor , 'pointer' ) ;
}
// Remove state class
parent [ _remove ] ( specific || option ( input , state ) || '' ) ;
// Set ARIA attribute
if ( ! ! parent . attr ( 'role' ) && ! indeterminate ) {
parent . attr ( 'aria-' + ( disabled ? _disabled : _checked ) , 'false' ) ;
}
// Add regular state class
parent [ _add ] ( regular || option ( input , callback ) || '' ) ;
}
// Remove all traces
function tidy ( input , callback ) {
if ( input . data ( _iCheck ) ) {
// Remove everything except input
input . parent ( ) . html ( input . attr ( 'style' , input . data ( _iCheck ) . s || '' ) ) ;
// Callback
if ( callback ) {
input [ _callback ] ( callback ) ;
}
// Unbind events
input . off ( '.i' ) . unwrap ( ) ;
$ ( _label + '[for="' + input [ 0 ] . id + '"]' ) . add ( input . closest ( _label ) ) . off ( '.i' ) ;
}
}
// Get some option
function option ( input , state , regular ) {
if ( input . data ( _iCheck ) ) {
return input . data ( _iCheck ) . o [ state + ( regular ? '' : 'Class' ) ] ;
}
}
// Capitalize some string
function capitalize ( string ) {
return string . charAt ( 0 ) . toUpperCase ( ) + string . slice ( 1 ) ;
}
// Executable handlers
function callbacks ( input , checked , callback , keep ) {
if ( ! keep ) {
if ( checked ) {
input [ _callback ] ( 'ifToggled' ) ;
}
input [ _callback ] ( 'ifChanged' ) [ _callback ] ( 'if' + capitalize ( callback ) ) ;
}
}
} ) ( window . jQuery || window . Zepto ) ;
/ * !
* Lightbox for Bootstrap by @ ashleydw
* https : //github.com/ashleydw/lightbox
*
* License : https : //github.com/ashleydw/lightbox/blob/master/LICENSE
* /
+ function ( $ ) {
'use strict' ;
var _createClass = ( function ( ) { function defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( 'value' in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } } return function ( Constructor , protoProps , staticProps ) { if ( protoProps ) defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) defineProperties ( Constructor , staticProps ) ; return Constructor ; } ; } ) ( ) ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( 'Cannot call a class as a function' ) ; } }
var Lightbox = ( function ( $ ) {
var NAME = 'ekkoLightbox' ;
var JQUERY _NO _CONFLICT = $ . fn [ NAME ] ;
var Default = {
title : '' ,
footer : '' ,
maxWidth : 9999 ,
maxHeight : 9999 ,
showArrows : true , //display the left / right arrows or not
wrapping : true , //if true, gallery loops infinitely
type : null , //force the lightbox into image / youtube mode. if null, or not image|youtube|vimeo; detect it
alwaysShowClose : false , //always show the close button, even if there is no title
loadingMessage : '<div class="ekko-lightbox-loader"><div><div></div><div></div></div></div>' , // http://tobiasahlin.com/spinkit/
leftArrow : '<span>❮</span>' ,
rightArrow : '<span>❯</span>' ,
strings : {
close : 'Close' ,
fail : 'Failed to load image:' ,
type : 'Could not detect remote target type. Force the type using data-type'
} ,
doc : document , // if in an iframe can specify top.document
onShow : function onShow ( ) { } ,
onShown : function onShown ( ) { } ,
onHide : function onHide ( ) { } ,
onHidden : function onHidden ( ) { } ,
onNavigate : function onNavigate ( ) { } ,
onContentLoaded : function onContentLoaded ( ) { }
} ;
var Lightbox = ( function ( ) {
_createClass ( Lightbox , null , [ {
key : 'Default' ,
/ * *
Class properties :
_$element : null - > the < a > element currently being displayed
_$modal : The bootstrap modal generated
_$modalDialog : The . modal - dialog
_$modalContent : The . modal - content
_$modalBody : The . modal - body
_$modalHeader : The . modal - header
_$modalFooter : The . modal - footer
_$lightboxContainerOne : Container of the first lightbox element
_$lightboxContainerTwo : Container of the second lightbox element
_$lightboxBody : First element in the container
_$modalArrows : The overlayed arrows container
_$galleryItems : Other < a > ' s available for this gallery
_galleryName : Name of the current data ( 'gallery' ) showing
_galleryIndex : The current index of the _$galleryItems being shown
_config : { } the options for the modal
_modalId : unique id for the current lightbox
_padding / _border : CSS properties for the modal container ; these are used to calculate the available space for the content
* /
get : function get ( ) {
return Default ;
}
} ] ) ;
function Lightbox ( $element , config ) {
var _this = this ;
_classCallCheck ( this , Lightbox ) ;
this . _config = $ . extend ( { } , Default , config ) ;
this . _$modalArrows = null ;
this . _galleryIndex = 0 ;
this . _galleryName = null ;
this . _padding = null ;
this . _border = null ;
this . _titleIsShown = false ;
this . _footerIsShown = false ;
this . _wantedWidth = 0 ;
this . _wantedHeight = 0 ;
this . _touchstartX = 0 ;
this . _touchendX = 0 ;
this . _modalId = 'ekkoLightbox-' + Math . floor ( Math . random ( ) * 1000 + 1 ) ;
this . _$element = $element instanceof jQuery ? $element : $ ( $element ) ;
this . _isBootstrap3 = $ . fn . modal . Constructor . VERSION [ 0 ] == 3 ;
var h4 = '<h4 class="modal-title">' + ( this . _config . title || " " ) + '</h4>' ;
var btn = '<button type="button" class="close" data-dismiss="modal" aria-label="' + this . _config . strings . close + '"><span aria-hidden="true">×</span></button>' ;
var header = '<div class="modal-header' + ( this . _config . title || this . _config . alwaysShowClose ? '' : ' hide' ) + '">' + ( this . _isBootstrap3 ? btn + h4 : h4 + btn ) + '</div>' ;
var footer = '<div class="modal-footer' + ( this . _config . footer ? '' : ' hide' ) + '">' + ( this . _config . footer || " " ) + '</div>' ;
var body = '<div class="modal-body"><div class="ekko-lightbox-container"><div class="ekko-lightbox-item fade in show"></div><div class="ekko-lightbox-item fade"></div></div></div>' ;
var dialog = '<div class="modal-dialog" role="document"><div class="modal-content">' + header + body + footer + '</div></div>' ;
$ ( this . _config . doc . body ) . append ( '<div id="' + this . _modalId + '" class="ekko-lightbox modal fade" tabindex="-1" tabindex="-1" role="dialog" aria-hidden="true">' + dialog + '</div>' ) ;
this . _$modal = $ ( '#' + this . _modalId , this . _config . doc ) ;
this . _$modalDialog = this . _$modal . find ( '.modal-dialog' ) . first ( ) ;
this . _$modalContent = this . _$modal . find ( '.modal-content' ) . first ( ) ;
this . _$modalBody = this . _$modal . find ( '.modal-body' ) . first ( ) ;
this . _$modalHeader = this . _$modal . find ( '.modal-header' ) . first ( ) ;
this . _$modalFooter = this . _$modal . find ( '.modal-footer' ) . first ( ) ;
this . _$lightboxContainer = this . _$modalBody . find ( '.ekko-lightbox-container' ) . first ( ) ;
this . _$lightboxBodyOne = this . _$lightboxContainer . find ( '> div:first-child' ) . first ( ) ;
this . _$lightboxBodyTwo = this . _$lightboxContainer . find ( '> div:last-child' ) . first ( ) ;
this . _border = this . _calculateBorders ( ) ;
this . _padding = this . _calculatePadding ( ) ;
this . _galleryName = this . _$element . data ( 'gallery' ) ;
if ( this . _galleryName ) {
this . _$galleryItems = $ ( document . body ) . find ( '*[data-gallery="' + this . _galleryName + '"]' ) ;
this . _galleryIndex = this . _$galleryItems . index ( this . _$element ) ;
$ ( document ) . on ( 'keydown.ekkoLightbox' , this . _navigationalBinder . bind ( this ) ) ;
// add the directional arrows to the modal
if ( this . _config . showArrows && this . _$galleryItems . length > 1 ) {
this . _$lightboxContainer . append ( '<div class="ekko-lightbox-nav-overlay"><a href="#">' + this . _config . leftArrow + '</a><a href="#">' + this . _config . rightArrow + '</a></div>' ) ;
this . _$modalArrows = this . _$lightboxContainer . find ( 'div.ekko-lightbox-nav-overlay' ) . first ( ) ;
this . _$lightboxContainer . on ( 'click' , 'a:first-child' , function ( event ) {
event . preventDefault ( ) ;
return _this . navigateLeft ( ) ;
} ) ;
this . _$lightboxContainer . on ( 'click' , 'a:last-child' , function ( event ) {
event . preventDefault ( ) ;
return _this . navigateRight ( ) ;
} ) ;
this . updateNavigation ( ) ;
}
}
this . _$modal . on ( 'show.bs.modal' , this . _config . onShow . bind ( this ) ) . on ( 'shown.bs.modal' , function ( ) {
_this . _toggleLoading ( true ) ;
_this . _handle ( ) ;
return _this . _config . onShown . call ( _this ) ;
} ) . on ( 'hide.bs.modal' , this . _config . onHide . bind ( this ) ) . on ( 'hidden.bs.modal' , function ( ) {
if ( _this . _galleryName ) {
$ ( document ) . off ( 'keydown.ekkoLightbox' ) ;
$ ( window ) . off ( 'resize.ekkoLightbox' ) ;
}
_this . _$modal . remove ( ) ;
return _this . _config . onHidden . call ( _this ) ;
} ) . modal ( this . _config ) ;
$ ( window ) . on ( 'resize.ekkoLightbox' , function ( ) {
_this . _resize ( _this . _wantedWidth , _this . _wantedHeight ) ;
} ) ;
this . _$lightboxContainer . on ( 'touchstart' , function ( ) {
_this . _touchstartX = event . changedTouches [ 0 ] . screenX ;
} ) . on ( 'touchend' , function ( ) {
_this . _touchendX = event . changedTouches [ 0 ] . screenX ;
_this . _swipeGesure ( ) ;
} ) ;
}
_createClass ( Lightbox , [ {
key : 'element' ,
value : function element ( ) {
return this . _$element ;
}
} , {
key : 'modal' ,
value : function modal ( ) {
return this . _$modal ;
}
} , {
key : 'navigateTo' ,
value : function navigateTo ( index ) {
if ( index < 0 || index > this . _$galleryItems . length - 1 ) return this ;
this . _galleryIndex = index ;
this . updateNavigation ( ) ;
this . _$element = $ ( this . _$galleryItems . get ( this . _galleryIndex ) ) ;
this . _handle ( ) ;
}
} , {
key : 'navigateLeft' ,
value : function navigateLeft ( ) {
if ( ! this . _$galleryItems ) return ;
if ( this . _$galleryItems . length === 1 ) return ;
if ( this . _galleryIndex === 0 ) {
if ( this . _config . wrapping ) this . _galleryIndex = this . _$galleryItems . length - 1 ; else return ;
} else //circular
this . _galleryIndex -- ;
this . _config . onNavigate . call ( this , 'left' , this . _galleryIndex ) ;
return this . navigateTo ( this . _galleryIndex ) ;
}
} , {
key : 'navigateRight' ,
value : function navigateRight ( ) {
if ( ! this . _$galleryItems ) return ;
if ( this . _$galleryItems . length === 1 ) return ;
if ( this . _galleryIndex === this . _$galleryItems . length - 1 ) {
if ( this . _config . wrapping ) this . _galleryIndex = 0 ; else return ;
} else //circular
this . _galleryIndex ++ ;
this . _config . onNavigate . call ( this , 'right' , this . _galleryIndex ) ;
return this . navigateTo ( this . _galleryIndex ) ;
}
} , {
key : 'updateNavigation' ,
value : function updateNavigation ( ) {
if ( ! this . _config . wrapping ) {
var $nav = this . _$lightboxContainer . find ( 'div.ekko-lightbox-nav-overlay' ) ;
if ( this . _galleryIndex === 0 ) $nav . find ( 'a:first-child' ) . addClass ( 'disabled' ) ; else $nav . find ( 'a:first-child' ) . removeClass ( 'disabled' ) ;
if ( this . _galleryIndex === this . _$galleryItems . length - 1 ) $nav . find ( 'a:last-child' ) . addClass ( 'disabled' ) ; else $nav . find ( 'a:last-child' ) . removeClass ( 'disabled' ) ;
}
}
} , {
key : 'close' ,
value : function close ( ) {
return this . _$modal . modal ( 'hide' ) ;
}
// helper private methods
} , {
key : '_navigationalBinder' ,
value : function _navigationalBinder ( event ) {
event = event || window . event ;
if ( event . keyCode === 39 ) return this . navigateRight ( ) ;
if ( event . keyCode === 37 ) return this . navigateLeft ( ) ;
}
// type detection private methods
} , {
key : '_detectRemoteType' ,
value : function _detectRemoteType ( src , type ) {
type = type || false ;
if ( ! type && this . _isImage ( src ) ) type = 'image' ;
if ( ! type && this . _getYoutubeId ( src ) ) type = 'youtube' ;
if ( ! type && this . _getVimeoId ( src ) ) type = 'vimeo' ;
if ( ! type && this . _getInstagramId ( src ) ) type = 'instagram' ;
if ( ! type || [ 'image' , 'youtube' , 'vimeo' , 'instagram' , 'video' , 'url' ] . indexOf ( type ) < 0 ) type = 'url' ;
return type ;
}
} , {
key : '_isImage' ,
value : function _isImage ( string ) {
return string && string . match ( /(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i ) ;
}
} , {
key : '_containerToUse' ,
value : function _containerToUse ( ) {
var _this2 = this ;
// if currently showing an image, fade it out and remove
var $toUse = this . _$lightboxBodyTwo ;
var $current = this . _$lightboxBodyOne ;
if ( this . _$lightboxBodyTwo . hasClass ( 'in' ) ) {
$toUse = this . _$lightboxBodyOne ;
$current = this . _$lightboxBodyTwo ;
}
$current . removeClass ( 'in show' ) ;
setTimeout ( function ( ) {
if ( ! _this2 . _$lightboxBodyTwo . hasClass ( 'in' ) ) _this2 . _$lightboxBodyTwo . empty ( ) ;
if ( ! _this2 . _$lightboxBodyOne . hasClass ( 'in' ) ) _this2 . _$lightboxBodyOne . empty ( ) ;
} , 500 ) ;
$toUse . addClass ( 'in show' ) ;
return $toUse ;
}
} , {
key : '_handle' ,
value : function _handle ( ) {
var $toUse = this . _containerToUse ( ) ;
this . _updateTitleAndFooter ( ) ;
var currentRemote = this . _$element . attr ( 'data-remote' ) || this . _$element . attr ( 'href' ) ;
var currentType = this . _detectRemoteType ( currentRemote , this . _$element . attr ( 'data-type' ) || false ) ;
if ( [ 'image' , 'youtube' , 'vimeo' , 'instagram' , 'video' , 'url' ] . indexOf ( currentType ) < 0 ) return this . _error ( this . _config . strings . type ) ;
switch ( currentType ) {
case 'image' :
this . _preloadImage ( currentRemote , $toUse ) ;
this . _preloadImageByIndex ( this . _galleryIndex , 3 ) ;
break ;
case 'youtube' :
this . _showYoutubeVideo ( currentRemote , $toUse ) ;
break ;
case 'vimeo' :
this . _showVimeoVideo ( this . _getVimeoId ( currentRemote ) , $toUse ) ;
break ;
case 'instagram' :
this . _showInstagramVideo ( this . _getInstagramId ( currentRemote ) , $toUse ) ;
break ;
case 'video' :
this . _showHtml5Video ( currentRemote , $toUse ) ;
break ;
default :
// url
this . _loadRemoteContent ( currentRemote , $toUse ) ;
break ;
}
return this ;
}
} , {
key : '_getYoutubeId' ,
value : function _getYoutubeId ( string ) {
if ( ! string ) return false ;
var matches = string . match ( /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/ ) ;
return matches && matches [ 2 ] . length === 11 ? matches [ 2 ] : false ;
}
} , {
key : '_getVimeoId' ,
value : function _getVimeoId ( string ) {
return string && string . indexOf ( 'vimeo' ) > 0 ? string : false ;
}
} , {
key : '_getInstagramId' ,
value : function _getInstagramId ( string ) {
return string && string . indexOf ( 'instagram' ) > 0 ? string : false ;
}
// layout private methods
} , {
key : '_toggleLoading' ,
value : function _toggleLoading ( show ) {
show = show || false ;
if ( show ) {
this . _$modalDialog . css ( 'display' , 'none' ) ;
this . _$modal . removeClass ( 'in show' ) ;
$ ( '.modal-backdrop' ) . append ( this . _config . loadingMessage ) ;
} else {
this . _$modalDialog . css ( 'display' , 'block' ) ;
this . _$modal . addClass ( 'in show' ) ;
$ ( '.modal-backdrop' ) . find ( '.ekko-lightbox-loader' ) . remove ( ) ;
}
return this ;
}
} , {
key : '_calculateBorders' ,
value : function _calculateBorders ( ) {
return {
top : this . _totalCssByAttribute ( 'border-top-width' ) ,
right : this . _totalCssByAttribute ( 'border-right-width' ) ,
bottom : this . _totalCssByAttribute ( 'border-bottom-width' ) ,
left : this . _totalCssByAttribute ( 'border-left-width' )
} ;
}
} , {
key : '_calculatePadding' ,
value : function _calculatePadding ( ) {
return {
top : this . _totalCssByAttribute ( 'padding-top' ) ,
right : this . _totalCssByAttribute ( 'padding-right' ) ,
bottom : this . _totalCssByAttribute ( 'padding-bottom' ) ,
left : this . _totalCssByAttribute ( 'padding-left' )
} ;
}
} , {
key : '_totalCssByAttribute' ,
value : function _totalCssByAttribute ( attribute ) {
return parseInt ( this . _$modalDialog . css ( attribute ) , 10 ) + parseInt ( this . _$modalContent . css ( attribute ) , 10 ) + parseInt ( this . _$modalBody . css ( attribute ) , 10 ) ;
}
} , {
key : '_updateTitleAndFooter' ,
value : function _updateTitleAndFooter ( ) {
var title = this . _$element . data ( 'title' ) || "" ;
var caption = this . _$element . data ( 'footer' ) || "" ;
this . _titleIsShown = false ;
if ( title || this . _config . alwaysShowClose ) {
this . _titleIsShown = true ;
this . _$modalHeader . css ( 'display' , '' ) . find ( '.modal-title' ) . html ( title || " " ) ;
} else this . _$modalHeader . css ( 'display' , 'none' ) ;
this . _footerIsShown = false ;
if ( caption ) {
this . _footerIsShown = true ;
this . _$modalFooter . css ( 'display' , '' ) . html ( caption ) ;
} else this . _$modalFooter . css ( 'display' , 'none' ) ;
return this ;
}
} , {
key : '_showYoutubeVideo' ,
value : function _showYoutubeVideo ( remote , $containerForElement ) {
var id = this . _getYoutubeId ( remote ) ;
var query = remote . indexOf ( '&' ) > 0 ? remote . substr ( remote . indexOf ( '&' ) ) : '' ;
var width = this . _$element . data ( 'width' ) || 560 ;
var height = this . _$element . data ( 'height' ) || width / ( 560 / 315 ) ;
return this . _showVideoIframe ( '//www.youtube.com/embed/' + id + '?badge=0&autoplay=1&html5=1' + query , width , height , $containerForElement ) ;
}
} , {
key : '_showVimeoVideo' ,
value : function _showVimeoVideo ( id , $containerForElement ) {
var width = this . _$element . data ( 'width' ) || 500 ;
var height = this . _$element . data ( 'height' ) || width / ( 560 / 315 ) ;
return this . _showVideoIframe ( id + '?autoplay=1' , width , height , $containerForElement ) ;
}
} , {
key : '_showInstagramVideo' ,
value : function _showInstagramVideo ( id , $containerForElement ) {
// instagram load their content into iframe's so this can be put straight into the element
var width = this . _$element . data ( 'width' ) || 612 ;
var height = width + 80 ;
id = id . substr ( - 1 ) !== '/' ? id + '/' : id ; // ensure id has trailing slash
$containerForElement . html ( '<iframe width="' + width + '" height="' + height + '" src="' + id + 'embed/" frameborder="0" allowfullscreen></iframe>' ) ;
this . _resize ( width , height ) ;
this . _config . onContentLoaded . call ( this ) ;
if ( this . _$modalArrows ) //hide the arrows when showing video
this . _$modalArrows . css ( 'display' , 'none' ) ;
this . _toggleLoading ( false ) ;
return this ;
}
} , {
key : '_showVideoIframe' ,
value : function _showVideoIframe ( url , width , height , $containerForElement ) {
// should be used for videos only. for remote content use loadRemoteContent (data-type=url)
height = height || width ; // default to square
$containerForElement . html ( '<div class="embed-responsive embed-responsive-16by9"><iframe width="' + width + '" height="' + height + '" src="' + url + '" frameborder="0" allowfullscreen class="embed-responsive-item"></iframe></div>' ) ;
this . _resize ( width , height ) ;
this . _config . onContentLoaded . call ( this ) ;
if ( this . _$modalArrows ) this . _$modalArrows . css ( 'display' , 'none' ) ; //hide the arrows when showing video
this . _toggleLoading ( false ) ;
return this ;
}
} , {
key : '_showHtml5Video' ,
value : function _showHtml5Video ( url , $containerForElement ) {
// should be used for videos only. for remote content use loadRemoteContent (data-type=url)
var width = this . _$element . data ( 'width' ) || 560 ;
var height = this . _$element . data ( 'height' ) || width / ( 560 / 315 ) ;
$containerForElement . html ( '<div class="embed-responsive embed-responsive-16by9"><video width="' + width + '" height="' + height + '" src="' + url + '" preload="auto" autoplay controls class="embed-responsive-item"></video></div>' ) ;
this . _resize ( width , height ) ;
this . _config . onContentLoaded . call ( this ) ;
if ( this . _$modalArrows ) this . _$modalArrows . css ( 'display' , 'none' ) ; //hide the arrows when showing video
this . _toggleLoading ( false ) ;
return this ;
}
} , {
key : '_loadRemoteContent' ,
value : function _loadRemoteContent ( url , $containerForElement ) {
var _this3 = this ;
var width = this . _$element . data ( 'width' ) || 560 ;
var height = this . _$element . data ( 'height' ) || 560 ;
var disableExternalCheck = this . _$element . data ( 'disableExternalCheck' ) || false ;
this . _toggleLoading ( false ) ;
// external urls are loading into an iframe
// local ajax can be loaded into the container itself
if ( ! disableExternalCheck && ! this . _isExternal ( url ) ) {
$containerForElement . load ( url , $ . proxy ( function ( ) {
return _this3 . _$element . trigger ( 'loaded.bs.modal' ) ; l ;
} ) ) ;
} else {
$containerForElement . html ( '<iframe src="' + url + '" frameborder="0" allowfullscreen></iframe>' ) ;
this . _config . onContentLoaded . call ( this ) ;
}
if ( this . _$modalArrows ) //hide the arrows when remote content
this . _$modalArrows . css ( 'display' , 'none' ) ;
this . _resize ( width , height ) ;
return this ;
}
} , {
key : '_isExternal' ,
value : function _isExternal ( url ) {
var match = url . match ( /^([^:\/?#]+:)?(?:\/\/([^\/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/ ) ;
if ( typeof match [ 1 ] === "string" && match [ 1 ] . length > 0 && match [ 1 ] . toLowerCase ( ) !== location . protocol ) return true ;
if ( typeof match [ 2 ] === "string" && match [ 2 ] . length > 0 && match [ 2 ] . replace ( new RegExp ( ':(' + ( {
"http:" : 80 ,
"https:" : 443
} ) [ location . protocol ] + ')?$' ) , "" ) !== location . host ) return true ;
return false ;
}
} , {
key : '_error' ,
value : function _error ( message ) {
console . error ( message ) ;
this . _containerToUse ( ) . html ( message ) ;
this . _resize ( 300 , 300 ) ;
return this ;
}
} , {
key : '_preloadImageByIndex' ,
value : function _preloadImageByIndex ( startIndex , numberOfTimes ) {
if ( ! this . _$galleryItems ) return ;
var next = $ ( this . _$galleryItems . get ( startIndex ) , false ) ;
if ( typeof next == 'undefined' ) return ;
var src = next . attr ( 'data-remote' ) || next . attr ( 'href' ) ;
if ( next . attr ( 'data-type' ) === 'image' || this . _isImage ( src ) ) this . _preloadImage ( src , false ) ;
if ( numberOfTimes > 0 ) return this . _preloadImageByIndex ( startIndex + 1 , numberOfTimes - 1 ) ;
}
} , {
key : '_preloadImage' ,
value : function _preloadImage ( src , $containerForImage ) {
var _this4 = this ;
$containerForImage = $containerForImage || false ;
var img = new Image ( ) ;
if ( $containerForImage ) {
( function ( ) {
// if loading takes > 200ms show a loader
var loadingTimeout = setTimeout ( function ( ) {
$containerForImage . append ( _this4 . _config . loadingMessage ) ;
} , 200 ) ;
img . onload = function ( ) {
if ( loadingTimeout ) clearTimeout ( loadingTimeout ) ;
loadingTimeout = null ;
var image = $ ( '<img />' ) ;
image . attr ( 'src' , img . src ) ;
image . addClass ( 'img-fluid' ) ;
// backward compatibility for bootstrap v3
image . css ( 'width' , '100%' ) ;
$containerForImage . html ( image ) ;
if ( _this4 . _$modalArrows ) _this4 . _$modalArrows . css ( 'display' , '' ) ; // remove display to default to css property
_this4 . _resize ( img . width , img . height ) ;
_this4 . _toggleLoading ( false ) ;
return _this4 . _config . onContentLoaded . call ( _this4 ) ;
} ;
img . onerror = function ( ) {
_this4 . _toggleLoading ( false ) ;
return _this4 . _error ( _this4 . _config . strings . fail + ( ' ' + src ) ) ;
} ;
} ) ( ) ;
}
img . src = src ;
return img ;
}
} , {
key : '_swipeGesure' ,
value : function _swipeGesure ( ) {
if ( this . _touchendX < this . _touchstartX ) {
return this . navigateRight ( ) ;
}
if ( this . _touchendX > this . _touchstartX ) {
return this . navigateLeft ( ) ;
}
}
} , {
key : '_resize' ,
value : function _resize ( width , height ) {
height = height || width ;
this . _wantedWidth = width ;
this . _wantedHeight = height ;
var imageAspecRatio = width / height ;
// if width > the available space, scale down the expected width and height
var widthBorderAndPadding = this . _padding . left + this . _padding . right + this . _border . left + this . _border . right ;
// force 10px margin if window size > 575px
var addMargin = this . _config . doc . body . clientWidth > 575 ? 20 : 0 ;
var discountMargin = this . _config . doc . body . clientWidth > 575 ? 0 : 20 ;
var maxWidth = Math . min ( width + widthBorderAndPadding , this . _config . doc . body . clientWidth - addMargin , this . _config . maxWidth ) ;
if ( width + widthBorderAndPadding > maxWidth ) {
height = ( maxWidth - widthBorderAndPadding - discountMargin ) / imageAspecRatio ;
width = maxWidth ;
} else width = width + widthBorderAndPadding ;
var headerHeight = 0 ,
footerHeight = 0 ;
// as the resize is performed the modal is show, the calculate might fail
// if so, default to the default sizes
if ( this . _footerIsShown ) footerHeight = this . _$modalFooter . outerHeight ( true ) || 55 ;
if ( this . _titleIsShown ) headerHeight = this . _$modalHeader . outerHeight ( true ) || 67 ;
var borderPadding = this . _padding . top + this . _padding . bottom + this . _border . bottom + this . _border . top ;
//calculated each time as resizing the window can cause them to change due to Bootstraps fluid margins
var margins = parseFloat ( this . _$modalDialog . css ( 'margin-top' ) ) + parseFloat ( this . _$modalDialog . css ( 'margin-bottom' ) ) ;
var maxHeight = Math . min ( height , $ ( window ) . height ( ) - borderPadding - margins - headerHeight - footerHeight , this . _config . maxHeight - borderPadding - headerHeight - footerHeight ) ;
if ( height > maxHeight ) {
// if height > the available height, scale down the width
width = Math . ceil ( maxHeight * imageAspecRatio ) + widthBorderAndPadding ;
}
this . _$lightboxContainer . css ( 'height' , maxHeight ) ;
this . _$modalDialog . css ( 'flex' , 1 ) . css ( 'maxWidth' , width ) ;
var modal = this . _$modal . data ( 'bs.modal' ) ;
if ( modal ) {
// v4 method is mistakenly protected
try {
modal . _handleUpdate ( ) ;
} catch ( Exception ) {
modal . handleUpdate ( ) ;
}
}
return this ;
}
} ] , [ {
key : '_jQueryInterface' ,
value : function _jQueryInterface ( config ) {
var _this5 = this ;
config = config || { } ;
return this . each ( function ( ) {
var $this = $ ( _this5 ) ;
var _config = $ . extend ( { } , Lightbox . Default , $this . data ( ) , typeof config === 'object' && config ) ;
new Lightbox ( _this5 , _config ) ;
} ) ;
}
} ] ) ;
return Lightbox ;
} ) ( ) ;
$ . fn [ NAME ] = Lightbox . _jQueryInterface ;
$ . fn [ NAME ] . Constructor = Lightbox ;
$ . fn [ NAME ] . noConflict = function ( ) {
$ . fn [ NAME ] = JQUERY _NO _CONFLICT ;
return Lightbox . _jQueryInterface ;
} ;
return Lightbox ;
} ) ( jQuery ) ;
//# sourceMappingURL=ekko-lightbox.js.map
} ( jQuery ) ;
/ * ! A d m i n L T E a p p . j s
* === === === === === =
* Main JS application file for AdminLTE v2 . This file
* should be included in all pages . It controls some layout
* options and implements exclusive AdminLTE plugins .
*
* @ Author Almsaeed Studio
* @ Support < http : //www.almsaeedstudio.com>
* @ Email < support @ almsaeedstudio . com >
* @ version 2.3 . 0
* @ license MIT < http : //opensource.org/licenses/MIT>
* /
//Make sure jQuery has been loaded before app.js
if ( typeof jQuery === "undefined" ) {
throw new Error ( "AdminLTE requires jQuery" ) ;
}
/ * A d m i n L T E
*
* @ type Object
* @ description $ . AdminLTE is the main object for the template ' s app .
* It ' s used for implementing functions and options related
* to the template . Keeping everything wrapped in an object
* prevents conflict with other plugins and is a better
* way to organize our code .
* /
$ . AdminLTE = { } ;
/ * - - - - - - - - - - - - - - - - - - - -
* - AdminLTE Options -
* -- -- -- -- -- -- -- -- -- --
* Modify these options to suit your implementation
* /
$ . AdminLTE . options = {
//Add slimscroll to navbar menus
//This requires you to load the slimscroll plugin
//in every page before app.js
navbarMenuSlimscroll : true ,
navbarMenuSlimscrollWidth : "3px" , //The width of the scroll bar
navbarMenuHeight : "200px" , //The height of the inner menu
//General animation speed for JS animated elements such as box collapse/expand and
//sidebar treeview slide up/down. This options accepts an integer as milliseconds,
//'fast', 'normal', or 'slow'
animationSpeed : 500 ,
//Sidebar push menu toggle button selector
sidebarToggleSelector : "[data-toggle='offcanvas']" ,
//Activate sidebar push menu
sidebarPushMenu : true ,
//Activate sidebar slimscroll if the fixed layout is set (requires SlimScroll Plugin)
sidebarSlimScroll : true ,
//Enable sidebar expand on hover effect for sidebar mini
//This option is forced to true if both the fixed layout and sidebar mini
//are used together
sidebarExpandOnHover : false ,
//BoxRefresh Plugin
enableBoxRefresh : true ,
//Bootstrap.js tooltip
enableBSToppltip : true ,
BSTooltipSelector : "[data-toggle='tooltip']" ,
//Enable Fast Click. Fastclick.js creates a more
//native touch experience with touch devices. If you
//choose to enable the plugin, make sure you load the script
//before AdminLTE's app.js
enableFastclick : true ,
//Control Sidebar Options
enableControlSidebar : true ,
controlSidebarOptions : {
//Which button should trigger the open/close event
toggleBtnSelector : "[data-toggle='control-sidebar']" ,
//The sidebar selector
selector : ".control-sidebar" ,
//Enable slide over content
slide : true
} ,
//Box Widget Plugin. Enable this plugin
//to allow boxes to be collapsed and/or removed
enableBoxWidget : true ,
//Box Widget plugin options
boxWidgetOptions : {
boxWidgetIcons : {
//Collapse icon
collapse : 'fa-minus' ,
//Open icon
open : 'fa-plus' ,
//Remove icon
remove : 'fa-times'
} ,
boxWidgetSelectors : {
//Remove button selector
remove : '[data-widget="remove"]' ,
//Collapse button selector
collapse : '[data-widget="collapse"]'
}
} ,
//Direct Chat plugin options
directChat : {
//Enable direct chat by default
enable : true ,
//The button to open and close the chat contacts pane
contactToggleSelector : '[data-widget="chat-pane-toggle"]'
} ,
//Define the set of colors to use globally around the website
colors : {
lightBlue : "#3c8dbc" ,
red : "#f56954" ,
green : "#00a65a" ,
aqua : "#00c0ef" ,
yellow : "#f39c12" ,
blue : "#0073b7" ,
navy : "#001F3F" ,
teal : "#39CCCC" ,
olive : "#3D9970" ,
lime : "#01FF70" ,
orange : "#FF851B" ,
fuchsia : "#F012BE" ,
purple : "#8E24AA" ,
maroon : "#D81B60" ,
black : "#222222" ,
gray : "#d2d6de"
} ,
//The standard screen sizes that bootstrap uses.
//If you change these in the variables.less file, change
//them here too.
screenSizes : {
xs : 480 ,
sm : 768 ,
md : 992 ,
lg : 1200
}
} ;
/ * - - - - - - - - - - - - - - - - - -
* - Implementation -
* -- -- -- -- -- -- -- -- --
* The next block of code implements AdminLTE ' s
* functions and plugins as specified by the
* options above .
* /
$ ( function ( ) {
"use strict" ;
//Fix for IE page transitions
$ ( "body" ) . removeClass ( "hold-transition" ) ;
//Extend options if external options exist
if ( typeof AdminLTEOptions !== "undefined" ) {
$ . extend ( true ,
$ . AdminLTE . options ,
AdminLTEOptions ) ;
}
//Easy access to options
var o = $ . AdminLTE . options ;
//Set up the object
_init ( ) ;
//Activate the layout maker
$ . AdminLTE . layout . activate ( ) ;
//Enable sidebar tree view controls
$ . AdminLTE . tree ( '.sidebar' ) ;
//Enable control sidebar
if ( o . enableControlSidebar ) {
$ . AdminLTE . controlSidebar . activate ( ) ;
}
//Add slimscroll to navbar dropdown
if ( o . navbarMenuSlimscroll && typeof $ . fn . slimscroll != 'undefined' ) {
$ ( ".navbar .menu" ) . slimscroll ( {
height : o . navbarMenuHeight ,
alwaysVisible : false ,
size : o . navbarMenuSlimscrollWidth
} ) . css ( "width" , "100%" ) ;
}
//Activate sidebar push menu
if ( o . sidebarPushMenu ) {
$ . AdminLTE . pushMenu . activate ( o . sidebarToggleSelector ) ;
}
//Activate Bootstrap tooltip
if ( o . enableBSToppltip ) {
$ . widget . bridge ( 'uitooltip' , $ . ui . tooltip ) ;
$ ( 'body' ) . tooltip ( {
selector : o . BSTooltipSelector
} ) ;
}
//Activate box widget
if ( o . enableBoxWidget ) {
$ . AdminLTE . boxWidget . activate ( ) ;
}
//Activate fast click
if ( o . enableFastclick && typeof FastClick != 'undefined' ) {
FastClick . attach ( document . body ) ;
}
//Activate direct chat widget
if ( o . directChat . enable ) {
$ ( document ) . on ( 'click' , o . directChat . contactToggleSelector , function ( ) {
var box = $ ( this ) . parents ( '.direct-chat' ) . first ( ) ;
box . toggleClass ( 'direct-chat-contacts-open' ) ;
} ) ;
}
/ *
* INITIALIZE BUTTON TOGGLE
* -- -- -- -- -- -- -- -- -- -- -- --
* /
$ ( '.btn-group[data-toggle="btn-toggle"]' ) . each ( function ( ) {
var group = $ ( this ) ;
$ ( this ) . find ( ".btn" ) . on ( 'click' , function ( e ) {
group . find ( ".btn.active" ) . removeClass ( "active" ) ;
$ ( this ) . addClass ( "active" ) ;
e . preventDefault ( ) ;
} ) ;
} ) ;
} ) ;
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - Initialize the AdminLTE Object -
* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* All AdminLTE functions are implemented below .
* /
function _init ( ) {
'use strict' ;
/ * L a y o u t
* === ===
* Fixes the layout height in case min - height fails .
*
* @ type Object
* @ usage $ . AdminLTE . layout . activate ( )
* $ . AdminLTE . layout . fix ( )
* $ . AdminLTE . layout . fixSidebar ( )
* /
$ . AdminLTE . layout = {
activate : function ( ) {
var _this = this ;
_this . fix ( ) ;
_this . fixSidebar ( ) ;
$ ( window , ".wrapper" ) . resize ( function ( ) {
_this . fix ( ) ;
_this . fixSidebar ( ) ;
} ) ;
} ,
fix : function ( ) {
//Get window height and the wrapper height
var neg = $ ( '.main-header' ) . outerHeight ( ) + $ ( '.main-footer' ) . outerHeight ( ) ;
var window _height = $ ( window ) . height ( ) ;
var sidebar _height = $ ( ".sidebar" ) . height ( ) ;
//Set the min-height of the content and sidebar based on the
//the height of the document.
if ( $ ( "body" ) . hasClass ( "fixed" ) ) {
$ ( ".content-wrapper, .right-side" ) . css ( 'min-height' , window _height - $ ( '.main-footer' ) . outerHeight ( ) ) ;
} else {
var postSetWidth ;
if ( window _height >= sidebar _height ) {
$ ( ".content-wrapper, .right-side" ) . css ( 'min-height' , window _height - neg ) ;
postSetWidth = window _height - neg ;
} else {
$ ( ".content-wrapper, .right-side" ) . css ( 'min-height' , sidebar _height ) ;
postSetWidth = sidebar _height ;
}
//Fix for the control sidebar height
var controlSidebar = $ ( $ . AdminLTE . options . controlSidebarOptions . selector ) ;
if ( typeof controlSidebar !== "undefined" ) {
if ( controlSidebar . height ( ) > postSetWidth )
$ ( ".content-wrapper, .right-side" ) . css ( 'min-height' , controlSidebar . height ( ) ) ;
}
}
} ,
fixSidebar : function ( ) {
//Make sure the body tag has the .fixed class
if ( ! $ ( "body" ) . hasClass ( "fixed" ) ) {
if ( typeof $ . fn . slimScroll != 'undefined' ) {
$ ( ".sidebar" ) . slimScroll ( { destroy : true } ) . height ( "auto" ) ;
}
return ;
} else if ( typeof $ . fn . slimScroll == 'undefined' && window . console ) {
window . console . error ( "Error: the fixed layout requires the slimscroll plugin!" ) ;
}
//Enable slimscroll for fixed layout
if ( $ . AdminLTE . options . sidebarSlimScroll ) {
if ( typeof $ . fn . slimScroll != 'undefined' ) {
//Destroy if it exists
$ ( ".sidebar" ) . slimScroll ( { destroy : true } ) . height ( "auto" ) ;
//Add slimscroll
$ ( ".sidebar" ) . slimscroll ( {
height : ( $ ( window ) . height ( ) - $ ( ".main-header" ) . height ( ) ) + "px" ,
color : "rgba(0,0,0,0.2)" ,
size : "3px"
} ) ;
}
}
}
} ;
/ * P u s h M e n u ( )
* === === === =
* Adds the push menu functionality to the sidebar .
*
* @ type Function
* @ usage : $ . AdminLTE . pushMenu ( "[data-toggle='offcanvas']" )
* /
$ . AdminLTE . pushMenu = {
activate : function ( toggleBtn ) {
//Get the screen sizes
var screenSizes = $ . AdminLTE . options . screenSizes ;
//Enable sidebar toggle
$ ( toggleBtn ) . on ( 'click' , function ( e ) {
e . preventDefault ( ) ;
//Enable sidebar push menu
if ( $ ( window ) . width ( ) > ( screenSizes . sm - 1 ) ) {
if ( $ ( "body" ) . hasClass ( 'sidebar-collapse' ) ) {
$ ( "body" ) . removeClass ( 'sidebar-collapse' ) . trigger ( 'expanded.pushMenu' ) ;
} else {
$ ( "body" ) . addClass ( 'sidebar-collapse' ) . trigger ( 'collapsed.pushMenu' ) ;
}
}
//Handle sidebar push menu for small screens
else {
if ( $ ( "body" ) . hasClass ( 'sidebar-open' ) ) {
$ ( "body" ) . removeClass ( 'sidebar-open' ) . removeClass ( 'sidebar-collapse' ) . trigger ( 'collapsed.pushMenu' ) ;
} else {
$ ( "body" ) . addClass ( 'sidebar-open' ) . trigger ( 'expanded.pushMenu' ) ;
}
}
} ) ;
$ ( ".content-wrapper" ) . click ( function ( ) {
//Enable hide menu when clicking on the content-wrapper on small screens
if ( $ ( window ) . width ( ) <= ( screenSizes . sm - 1 ) && $ ( "body" ) . hasClass ( "sidebar-open" ) ) {
$ ( "body" ) . removeClass ( 'sidebar-open' ) ;
}
} ) ;
//Enable expand on hover for sidebar mini
if ( $ . AdminLTE . options . sidebarExpandOnHover
|| ( $ ( 'body' ) . hasClass ( 'fixed' )
&& $ ( 'body' ) . hasClass ( 'sidebar-mini' ) ) ) {
this . expandOnHover ( ) ;
}
} ,
expandOnHover : function ( ) {
var _this = this ;
var screenWidth = $ . AdminLTE . options . screenSizes . sm - 1 ;
//Expand sidebar on hover
$ ( '.main-sidebar' ) . hover ( function ( ) {
if ( $ ( 'body' ) . hasClass ( 'sidebar-mini' )
&& $ ( "body" ) . hasClass ( 'sidebar-collapse' )
&& $ ( window ) . width ( ) > screenWidth ) {
_this . expand ( ) ;
}
} , function ( ) {
if ( $ ( 'body' ) . hasClass ( 'sidebar-mini' )
&& $ ( 'body' ) . hasClass ( 'sidebar-expanded-on-hover' )
&& $ ( window ) . width ( ) > screenWidth ) {
_this . collapse ( ) ;
}
} ) ;
} ,
expand : function ( ) {
$ ( "body" ) . removeClass ( 'sidebar-collapse' ) . addClass ( 'sidebar-expanded-on-hover' ) ;
} ,
collapse : function ( ) {
if ( $ ( 'body' ) . hasClass ( 'sidebar-expanded-on-hover' ) ) {
$ ( 'body' ) . removeClass ( 'sidebar-expanded-on-hover' ) . addClass ( 'sidebar-collapse' ) ;
}
}
} ;
/ * T r e e ( )
* === ===
* Converts the sidebar into a multilevel
* tree view menu .
*
* @ type Function
* @ Usage : $ . AdminLTE . tree ( '.sidebar' )
* /
$ . AdminLTE . tree = function ( menu ) {
var _this = this ;
var animationSpeed = $ . AdminLTE . options . animationSpeed ;
$ ( document ) . on ( 'click' , menu + ' li a' , function ( e ) {
//Get the clicked link and the next element
var $this = $ ( this ) ;
var checkElement = $this . next ( ) ;
//Check if the next element is a menu and is visible
if ( ( checkElement . is ( '.treeview-menu' ) ) && ( checkElement . is ( ':visible' ) ) ) {
//Close the menu
checkElement . slideUp ( animationSpeed , function ( ) {
checkElement . removeClass ( 'menu-open' ) ;
//Fix the layout in case the sidebar stretches over the height of the window
//_this.layout.fix();
} ) ;
checkElement . parent ( "li" ) . removeClass ( "active" ) ;
}
//If the menu is not visible
else if ( ( checkElement . is ( '.treeview-menu' ) ) && ( ! checkElement . is ( ':visible' ) ) ) {
//Get the parent menu
var parent = $this . parents ( 'ul' ) . first ( ) ;
//Close all open menus within the parent
var ul = parent . find ( 'ul:visible' ) . slideUp ( animationSpeed ) ;
//Remove the menu-open class from the parent
ul . removeClass ( 'menu-open' ) ;
//Get the parent li
var parent _li = $this . parent ( "li" ) ;
//Open the target menu and add the menu-open class
checkElement . slideDown ( animationSpeed , function ( ) {
//Add the class active to the parent li
checkElement . addClass ( 'menu-open' ) ;
parent . find ( 'li.active' ) . removeClass ( 'active' ) ;
parent _li . addClass ( 'active' ) ;
//Fix the layout in case the sidebar stretches over the height of the window
_this . layout . fix ( ) ;
} ) ;
}
//if this isn't a link, prevent the page from being redirected
if ( checkElement . is ( '.treeview-menu' ) ) {
e . preventDefault ( ) ;
}
} ) ;
} ;
/ * C o n t r o l S i d e b a r
* === === === === ==
* Adds functionality to the right sidebar
*
* @ type Object
* @ usage $ . AdminLTE . controlSidebar . activate ( options )
* /
$ . AdminLTE . controlSidebar = {
//instantiate the object
activate : function ( ) {
//Get the object
var _this = this ;
//Update options
var o = $ . AdminLTE . options . controlSidebarOptions ;
//Get the sidebar
var sidebar = $ ( o . selector ) ;
//The toggle button
var btn = $ ( o . toggleBtnSelector ) ;
//Listen to the click event
btn . on ( 'click' , function ( e ) {
e . preventDefault ( ) ;
//If the sidebar is not open
if ( ! sidebar . hasClass ( 'control-sidebar-open' )
&& ! $ ( 'body' ) . hasClass ( 'control-sidebar-open' ) ) {
//Open the sidebar
_this . open ( sidebar , o . slide ) ;
} else {
_this . close ( sidebar , o . slide ) ;
}
} ) ;
//If the body has a boxed layout, fix the sidebar bg position
var bg = $ ( ".control-sidebar-bg" ) ;
_this . _fix ( bg ) ;
//If the body has a fixed layout, make the control sidebar fixed
if ( $ ( 'body' ) . hasClass ( 'fixed' ) ) {
_this . _fixForFixed ( sidebar ) ;
} else {
//If the content height is less than the sidebar's height, force max height
if ( $ ( '.content-wrapper, .right-side' ) . height ( ) < sidebar . height ( ) ) {
_this . _fixForContent ( sidebar ) ;
}
}
} ,
//Open the control sidebar
open : function ( sidebar , slide ) {
//Slide over content
if ( slide ) {
sidebar . addClass ( 'control-sidebar-open' ) ;
} else {
//Push the content by adding the open class to the body instead
//of the sidebar itself
$ ( 'body' ) . addClass ( 'control-sidebar-open' ) ;
}
} ,
//Close the control sidebar
close : function ( sidebar , slide ) {
if ( slide ) {
sidebar . removeClass ( 'control-sidebar-open' ) ;
} else {
$ ( 'body' ) . removeClass ( 'control-sidebar-open' ) ;
}
} ,
_fix : function ( sidebar ) {
var _this = this ;
if ( $ ( "body" ) . hasClass ( 'layout-boxed' ) ) {
sidebar . css ( 'position' , 'absolute' ) ;
sidebar . height ( $ ( ".wrapper" ) . height ( ) ) ;
$ ( window ) . resize ( function ( ) {
_this . _fix ( sidebar ) ;
} ) ;
} else {
sidebar . css ( {
'position' : 'fixed' ,
'height' : 'auto'
} ) ;
}
} ,
_fixForFixed : function ( sidebar ) {
sidebar . css ( {
'position' : 'fixed' ,
'max-height' : '100%' ,
'overflow' : 'auto' ,
'padding-bottom' : '50px'
} ) ;
} ,
_fixForContent : function ( sidebar ) {
$ ( ".content-wrapper, .right-side" ) . css ( 'min-height' , sidebar . height ( ) ) ;
}
} ;
/ * B o x W i d g e t
* === === ===
* BoxWidget is a plugin to handle collapsing and
* removing boxes from the screen .
*
* @ type Object
* @ usage $ . AdminLTE . boxWidget . activate ( )
* Set all your options in the main $ . AdminLTE . options object
* /
$ . AdminLTE . boxWidget = {
selectors : $ . AdminLTE . options . boxWidgetOptions . boxWidgetSelectors ,
icons : $ . AdminLTE . options . boxWidgetOptions . boxWidgetIcons ,
animationSpeed : $ . AdminLTE . options . animationSpeed ,
activate : function ( _box ) {
var _this = this ;
if ( ! _box ) {
_box = document ; // activate all boxes per default
}
//Listen for collapse event triggers
$ ( _box ) . on ( 'click' , _this . selectors . collapse , function ( e ) {
e . preventDefault ( ) ;
_this . collapse ( $ ( this ) ) ;
} ) ;
//Listen for remove event triggers
$ ( _box ) . on ( 'click' , _this . selectors . remove , function ( e ) {
e . preventDefault ( ) ;
_this . remove ( $ ( this ) ) ;
} ) ;
} ,
collapse : function ( element ) {
var _this = this ;
//Find the box parent
var box = element . parents ( ".box" ) . first ( ) ;
//Find the body and the footer
var box _content = box . find ( "> .box-body, > .box-footer, > form >.box-body, > form > .box-footer" ) ;
if ( ! box . hasClass ( "collapsed-box" ) ) {
//Convert minus into plus
element . children ( ":first" )
. removeClass ( _this . icons . collapse )
. addClass ( _this . icons . open ) ;
//Hide the content
box _content . slideUp ( _this . animationSpeed , function ( ) {
box . addClass ( "collapsed-box" ) ;
} ) ;
} else {
//Convert plus into minus
element . children ( ":first" )
. removeClass ( _this . icons . open )
. addClass ( _this . icons . collapse ) ;
//Show the content
box _content . slideDown ( _this . animationSpeed , function ( ) {
box . removeClass ( "collapsed-box" ) ;
} ) ;
}
} ,
remove : function ( element ) {
//Find the box parent
var box = element . parents ( ".box" ) . first ( ) ;
box . slideUp ( this . animationSpeed ) ;
}
} ;
}
/ * - - - - - - - - - - - - - - - - - -
* - Custom Plugins -
* -- -- -- -- -- -- -- -- --
* All custom plugins are defined below .
* /
/ *
* BOX REFRESH BUTTON
* -- -- -- -- -- -- -- -- --
* This is a custom plugin to use with the component BOX . It allows you to add
* a refresh button to the box . It converts the box ' s state to a loading state .
*
* @ type plugin
* @ usage $ ( "#box-widget" ) . boxRefresh ( options ) ;
* /
( function ( $ ) {
"use strict" ;
$ . fn . boxRefresh = function ( options ) {
// Render options
var settings = $ . extend ( {
//Refresh button selector
trigger : ".refresh-btn" ,
//File source to be loaded (e.g: ajax/src.php)
source : "" ,
//Callbacks
onLoadStart : function ( box ) {
return box ;
} , //Right after the button has been clicked
onLoadDone : function ( box ) {
return box ;
} //When the source has been loaded
} , options ) ;
//The overlay
var overlay = $ ( '<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>' ) ;
return this . each ( function ( ) {
//if a source is specified
if ( settings . source === "" ) {
if ( window . console ) {
window . console . log ( "Please specify a source first - boxRefresh()" ) ;
}
return ;
}
//the box
var box = $ ( this ) ;
//the button
var rBtn = box . find ( settings . trigger ) . first ( ) ;
//On trigger click
rBtn . on ( 'click' , function ( e ) {
e . preventDefault ( ) ;
//Add loading overlay
start ( box ) ;
//Perform ajax call
box . find ( ".box-body" ) . load ( settings . source , function ( ) {
done ( box ) ;
} ) ;
} ) ;
} ) ;
function start ( box ) {
//Add overlay and loading img
box . append ( overlay ) ;
settings . onLoadStart . call ( box ) ;
}
function done ( box ) {
//Remove overlay and loading img
box . find ( overlay ) . remove ( ) ;
settings . onLoadDone . call ( box ) ;
}
} ;
} ) ( jQuery ) ;
/ *
* EXPLICIT BOX ACTIVATION
* -- -- -- -- -- -- -- -- -- -- -- -
* This is a custom plugin to use with the component BOX . It allows you to activate
* a box inserted in the DOM after the app . js was loaded .
*
* @ type plugin
* @ usage $ ( "#box-widget" ) . activateBox ( ) ;
* /
( function ( $ ) {
'use strict' ;
$ . fn . activateBox = function ( ) {
$ . AdminLTE . boxWidget . activate ( this ) ;
} ;
} ) ( jQuery ) ;
/ * *
* Module containing core application logic .
* @ param { jQuery } $ Insulated jQuery object
* @ param { JSON } settings Insulated ` window.snipeit.settings ` object .
* @ return { IIFE } Immediately invoked . Returns self .
* /
var lineOptions = {
legend : {
position : "bottom"
} ,
scales : {
yAxes : [ {
ticks : {
fontColor : "rgba(0,0,0,0.5)" ,
fontStyle : "bold" ,
beginAtZero : true ,
maxTicksLimit : 5 ,
padding : 20
} ,
gridLines : {
drawTicks : false ,
display : false
}
} ] ,
xAxes : [ {
gridLines : {
zeroLineColor : "transparent"
} ,
ticks : {
padding : 20 ,
fontColor : "rgba(0,0,0,0.5)" ,
fontStyle : "bold"
}
} ]
}
} ;
var pieOptions = {
//Boolean - Whether we should show a stroke on each segment
segmentShowStroke : true ,
//String - The colour of each segment stroke
segmentStrokeColor : "#fff" ,
//Number - The width of each segment stroke
segmentStrokeWidth : 1 ,
//Number - The percentage of the chart that we cut out of the middle
percentageInnerCutout : 50 , // This is 0 for Pie charts
//Number - Amount of animation steps
animationSteps : 100 ,
//String - Animation easing effect
animationEasing : "easeOutBounce" ,
//Boolean - Whether we animate the rotation of the Doughnut
animateRotate : true ,
//Boolean - Whether we animate scaling the Doughnut from the centre
animateScale : false ,
//Boolean - whether to make the chart responsive to window resizing
responsive : true ,
// Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
maintainAspectRatio : false ,
//String - A legend template
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li>" +
"<i class='fa fa-circle-o' style='color: <%=segments[i].fillColor%>'></i>" +
"<%if(segments[i].label){%><%=segments[i].label%><%}%> foo</li><%}%></ul>" ,
//String - A tooltip template
tooltipTemplate : "<%=value %> <%=label%> "
} ;
//-----------------
//- END PIE CHART -
//-----------------
( function ( $ , settings ) {
var Components = { } ;
Components . modals = { } ;
// confirm delete modal
Components . modals . confirmDelete = function ( ) {
var $el = $ ( 'table' ) ;
var events = {
'click' : function ( evnt ) {
var $context = $ ( this ) ;
var $dataConfirmModal = $ ( '#dataConfirmModal' ) ;
var href = $context . attr ( 'href' ) ;
var message = $context . attr ( 'data-content' ) ;
var title = $context . attr ( 'data-title' ) ;
$ ( '#myModalLabel' ) . text ( title ) ;
$dataConfirmModal . find ( '.modal-body' ) . text ( message ) ;
$ ( '#deleteForm' ) . attr ( 'action' , href ) ;
$dataConfirmModal . modal ( {
show : true
} ) ;
return false ;
}
} ;
var render = function ( ) {
$el . on ( 'click' , '.delete-asset' , events [ 'click' ] ) ;
} ;
return {
render : render
} ;
} ;
/ * *
* Application start point
* Component definition stays out of load event , execution only happens .
* /
$ ( function ( ) {
new Components . modals . confirmDelete ( ) . render ( ) ;
} ) ;
} ( jQuery , window . snipeit . settings ) ) ;
$ ( document ) . ready ( function ( ) {
/ *
* Slideout help menu
* /
$ ( '.slideout-menu-toggle' ) . on ( 'click' , function ( event ) {
console . log ( 'clicked' ) ;
event . preventDefault ( ) ;
// create menu variables
var slideoutMenu = $ ( '.slideout-menu' ) ;
var slideoutMenuWidth = $ ( '.slideout-menu' ) . width ( ) ;
// toggle open class
slideoutMenu . toggleClass ( "open" ) ;
// slide menu
if ( slideoutMenu . hasClass ( "open" ) ) {
slideoutMenu . show ( ) ;
slideoutMenu . animate ( {
right : "0px"
} ) ;
} else {
slideoutMenu . animate ( {
right : - slideoutMenuWidth
} , "-350px" ) ;
slideoutMenu . fadeOut ( ) ;
}
} ) ;
/ *
* iCheck checkbox plugin
* /
$ ( 'input[type="checkbox"].minimal, input[type="radio"].minimal' ) . iCheck ( {
checkboxClass : 'icheckbox_minimal-blue' ,
radioClass : 'iradio_minimal-blue'
} ) ;
/ *
* Select2
* /
var iOS = /iPhone|iPad|iPod/ . test ( navigator . userAgent ) && ! window . MSStream ;
if ( ! iOS )
{
// Vue collision: Avoid overriding a vue select2 instance
// by checking to see if the item has already been select2'd.
$ ( 'select.select2:not(".select2-hidden-accessible")' ) . each ( function ( i , obj ) {
{
$ ( obj ) . select2 ( ) ;
}
} ) ;
}
$ ( '.datepicker' ) . datepicker ( ) ;
} ) ;
/ *
*
* Snipe - IT Universal Modal support
*
* Enables modal dialogs to create sub - resources throughout Snipe - IT
*
* /
/ *
HOW TO USE
Create a Button looking like this :
< a href = '{{ route(' modal . user ') }}' data - toggle = "modal" data - target = "#createModal" data - dependency = "user" data - select = 'assigned_to' class = "btn btn-sm btn-default" > New < / a >
If you don 't have access to Blade commands (like {{ and }}, etc), you can hard-code a URL as the ' href '
data - toggle = "modal" - required for Bootstrap Modals
data - target = "#createModal" - fixed ID for the modal , do not change
data - dependency = "user" - which Snipe - IT model you ' re going to be creating .
data - select = "assigned_to" - What is the * ID * of the select - dropdown that you 're going to be adding to, if the modal-create was a success? Be on the lookout for duplicate ID' s , it will confuse this library !
class = "btn btn-sm btn-default" - makes it look button - ey , feel free to change : )
* /
$ ( function ( ) {
//handle modal-add-interstitial calls
var model , select ;
if ( $ ( '#createModal' ) . length == 0 ) {
$ ( 'body' ) . append ( '<div class="modal fade" id="createModal"></div><!-- /.modal -->' ) ;
}
$ ( '#createModal' ) . on ( "show.bs.modal" , function ( event ) {
var link = $ ( event . relatedTarget ) ;
model = link . data ( "dependency" ) ;
select = link . data ( "select" ) ;
$ ( '#createModal' ) . load ( link . attr ( 'href' ) , function ( ) {
//do we need to re-select2 this, after load? Probably.
$ ( '#createModal' ) . find ( 'select.select2' ) . select2 ( ) ;
} ) ;
} ) ;
$ ( '#createModal' ) . on ( 'click' , '#modal-save' , function ( ) {
var data = { } ;
//console.warn("We are about to SAVE!!! for model: "+model+" and select ID: "+select);
$ ( '.modal-body input:visible' ) . each ( function ( index , elem ) {
var bits = elem . id . split ( "-" ) ;
if ( bits [ 0 ] === "modal" ) {
data [ bits [ 1 ] ] = $ ( elem ) . val ( ) ;
}
} ) ;
//this can probably get replaced with a normal 'serialize' instead
$ ( '.modal-body select:visible' ) . each ( function ( index , elem ) {
var bits = elem . id . split ( "-" ) ;
data [ bits [ 1 ] ] = $ ( elem ) . val ( ) ;
} ) ;
data . _token = Laravel . csrfToken ;
$ . ajax ( {
type : 'POST' ,
url : baseUrl + "/api/v1/" + model + "s" ,
headers : {
"X-Requested-With" : 'XMLHttpRequest' ,
"X-CSRF-TOKEN" : $ ( 'meta[name="csrf-token"]' ) . attr ( 'content' )
} ,
data : data ,
success : function ( result ) {
console . dir ( result ) ;
if ( result . status == "error" ) {
var error _message = "" ;
for ( var field in result . messages ) {
error _message += "<li>Problem(s) with field <i><strong>" + field + "</strong></i>: " + result . messages [ field ] ;
console . dir ( result . messages ) ;
console . log ( 'error_messages are: ' + error _message ) ;
}
$ ( '#modal_error_msg' ) . html ( error _message ) . show ( ) ;
return false ;
}
var id = result . payload . id ;
var name = result . payload . name || ( result . payload . first _name + " " + result . payload . last _name ) ;
if ( ! id || ! name ) {
console . error ( "Could not find resulting name or ID from modal-create. Name: " + name + ", id: " + id ) ;
return false ;
}
$ ( '#createModal' ) . modal ( 'hide' ) ;
$ ( '#createModal' ) . html ( "" ) ;
// "select" is the original drop-down menu that someone
// clicked 'add' on to add a new 'thing'
// this code adds the newly created object to that select
var selector = document . getElementById ( select ) ;
if ( ! selector ) {
return false ;
}
selector . options [ selector . length ] = new Option ( name , id ) ;
selector . selectedIndex = selector . length - 1 ;
$ ( selector ) . trigger ( "change" ) ;
if ( window . fetchCustomFields ) {
fetchCustomFields ( ) ;
}
} ,
error : function ( result ) {
msg = result . responseJSON . messages || result . responseJSON . error ;
$ ( '#modal_error_msg' ) . html ( "Server Error: " + msg ) . show ( ) ;
}
} ) ;
} ) ;
} ) ;