2019-01-11 09:59:01 +01:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - transition . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#transitions
* === === === === === === === === === === === === === === === === ===
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === = * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/* CSS TRANSITION SUPPORT (http:/ / www . modernizr . com / )
* === === === === === === === === === === === === === === === === === === = * /
$ ( function ( ) {
$ . support . transition = ( function ( ) {
var transitionEnd = ( function ( ) {
var el = document . createElement ( 'bootstrap' )
, transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd'
, 'MozTransition' : 'transitionend'
, 'OTransition' : 'oTransitionEnd otransitionend'
, 'transition' : 'transitionend'
}
, name
for ( name in transEndEventNames ) {
if ( el . style [ name ] !== undefined ) {
return transEndEventNames [ name ]
}
}
} ( ) )
return transitionEnd && {
end : transitionEnd
}
} ) ( )
} )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - affix . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#affix
* === === === === === === === === === === === === === === === === === === === =
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === = * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * A F F I X C L A S S D E F I N I T I O N
* === === === === === === === = * /
var Affix = function ( element , options ) {
this . options = $ . extend ( { } , $ . fn . affix . defaults , options )
this . $window = $ ( window )
. on ( 'scroll.affix.data-api' , $ . proxy ( this . checkPosition , this ) )
. on ( 'click.affix.data-api' , $ . proxy ( function ( ) { setTimeout ( $ . proxy ( this . checkPosition , this ) , 1 ) } , this ) )
this . $element = $ ( element )
this . checkPosition ( )
}
Affix . prototype . checkPosition = function ( ) {
if ( ! this . $element . is ( ':visible' ) ) return
var scrollHeight = $ ( document ) . height ( )
, scrollTop = this . $window . scrollTop ( )
, position = this . $element . offset ( )
, offset = this . options . offset
, offsetBottom = offset . bottom
, offsetTop = offset . top
, reset = 'affix affix-top affix-bottom'
, affix
if ( typeof offset != 'object' ) offsetBottom = offsetTop = offset
if ( typeof offsetTop == 'function' ) offsetTop = offset . top ( )
if ( typeof offsetBottom == 'function' ) offsetBottom = offset . bottom ( )
affix = this . unpin != null && ( scrollTop + this . unpin <= position . top ) ?
false : offsetBottom != null && ( position . top + this . $element . height ( ) >= scrollHeight - offsetBottom ) ?
'bottom' : offsetTop != null && scrollTop <= offsetTop ?
'top' : false
if ( this . affixed === affix ) return
this . affixed = affix
this . unpin = affix == 'bottom' ? position . top - scrollTop : null
this . $element . removeClass ( reset ) . addClass ( 'affix' + ( affix ? '-' + affix : '' ) )
}
/ * A F F I X P L U G I N D E F I N I T I O N
* === === === === === === === == * /
var old = $ . fn . affix
$ . fn . affix = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'affix' )
, options = typeof option == 'object' && option
if ( ! data ) $this . data ( 'affix' , ( data = new Affix ( this , options ) ) )
if ( typeof option == 'string' ) data [ option ] ( )
} )
}
$ . fn . affix . Constructor = Affix
$ . fn . affix . defaults = {
offset : 0
}
/ * A F F I X N O C O N F L I C T
* === === === === === == * /
$ . fn . affix . noConflict = function ( ) {
$ . fn . affix = old
return this
}
/ * A F F I X D A T A - A P I
* === === === === == * /
$ ( window ) . on ( 'load' , function ( ) {
$ ( '[data-spy="affix"]' ) . each ( function ( ) {
var $spy = $ ( this )
, data = $spy . data ( )
data . offset = data . offset || { }
data . offsetBottom && ( data . offset . bottom = data . offsetBottom )
data . offsetTop && ( data . offset . top = data . offsetTop )
$spy . affix ( data )
} )
} )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - dropdown . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#dropdowns
* === === === === === === === === === === === === === === === === === === === ===
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === === * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * D R O P D O W N C L A S S D E F I N I T I O N
* === === === === === === === === = * /
var toggle = '[data-toggle=dropdown]'
, Dropdown = function ( element ) {
var $el = $ ( element ) . on ( 'click.dropdown.data-api' , this . toggle )
$ ( 'html' ) . on ( 'click.dropdown.data-api' , function ( ) {
$el . parent ( ) . removeClass ( 'open' )
} )
}
Dropdown . prototype = {
constructor : Dropdown
, toggle : function ( e ) {
var $this = $ ( this )
, $parent
, isActive
if ( $this . is ( '.disabled, :disabled' ) ) return
$parent = getParent ( $this )
isActive = $parent . hasClass ( 'open' )
clearMenus ( )
if ( ! isActive ) {
if ( 'ontouchstart' in document . documentElement ) {
// if mobile we we use a backdrop because click events don't delegate
$ ( '<div class="dropdown-backdrop"/>' ) . insertBefore ( $ ( this ) ) . on ( 'click' , clearMenus )
}
$parent . toggleClass ( 'open' )
}
$this . focus ( )
return false
}
, keydown : function ( e ) {
var $this
, $items
, $active
, $parent
, isActive
, index
if ( ! /(38|40|27)/ . test ( e . keyCode ) ) return
$this = $ ( this )
e . preventDefault ( )
e . stopPropagation ( )
if ( $this . is ( '.disabled, :disabled' ) ) return
$parent = getParent ( $this )
isActive = $parent . hasClass ( 'open' )
if ( ! isActive || ( isActive && e . keyCode == 27 ) ) {
if ( e . which == 27 ) $parent . find ( toggle ) . focus ( )
return $this . click ( )
}
$items = $ ( '[role=menu] li:not(.divider):visible a' , $parent )
if ( ! $items . length ) return
index = $items . index ( $items . filter ( ':focus' ) )
if ( e . keyCode == 38 && index > 0 ) index -- // up
if ( e . keyCode == 40 && index < $items . length - 1 ) index ++ // down
if ( ! ~ index ) index = 0
$items
. eq ( index )
. focus ( )
}
}
function clearMenus ( ) {
$ ( '.dropdown-backdrop' ) . remove ( )
$ ( toggle ) . each ( function ( ) {
getParent ( $ ( this ) ) . removeClass ( 'open' )
} )
}
function getParent ( $this ) {
var selector = $this . attr ( 'data-target' )
, $parent
if ( ! selector ) {
selector = $this . attr ( 'href' )
selector = selector && /#/ . test ( selector ) && selector . replace ( /.*(?=#[^\s]*$)/ , '' ) //strip for ie7
}
$parent = selector && $ ( selector )
if ( ! $parent || ! $parent . length ) $parent = $this . parent ( )
return $parent
}
/ * D R O P D O W N P L U G I N D E F I N I T I O N
* === === === === === === === === == * /
var old = $ . fn . dropdown
$ . fn . dropdown = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'dropdown' )
if ( ! data ) $this . data ( 'dropdown' , ( data = new Dropdown ( this ) ) )
if ( typeof option == 'string' ) data [ option ] . call ( $this )
} )
}
$ . fn . dropdown . Constructor = Dropdown
/ * D R O P D O W N N O C O N F L I C T
* === === === === === === == * /
$ . fn . dropdown . noConflict = function ( ) {
$ . fn . dropdown = old
return this
}
/ * A P P L Y T O S T A N D A R D D R O P D O W N E L E M E N T S
* === === === === === === === === === === === == * /
$ ( document )
. on ( 'click.dropdown.data-api' , clearMenus )
. on ( 'click.dropdown.data-api' , '.dropdown form' , function ( e ) { e . stopPropagation ( ) } )
. on ( 'click.dropdown.data-api' , toggle , Dropdown . prototype . toggle )
. on ( 'keydown.dropdown.data-api' , toggle + ', [role=menu]' , Dropdown . prototype . keydown )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - alert . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#alerts
* === === === === === === === === === === === === === === === === === === === =
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === = * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * A L E R T C L A S S D E F I N I T I O N
* === === === === === === === = * /
var dismiss = '[data-dismiss="alert"]'
, Alert = function ( el ) {
$ ( el ) . on ( 'click' , dismiss , this . close )
}
Alert . prototype . close = function ( e ) {
var $this = $ ( this )
, selector = $this . attr ( 'data-target' )
, $parent
if ( ! selector ) {
selector = $this . attr ( 'href' )
selector = selector && selector . replace ( /.*(?=#[^\s]*$)/ , '' ) //strip for ie7
}
$parent = $ ( selector )
e && e . preventDefault ( )
$parent . length || ( $parent = $this . hasClass ( 'alert' ) ? $this : $this . parent ( ) )
$parent . trigger ( e = $ . Event ( 'close' ) )
if ( e . isDefaultPrevented ( ) ) return
$parent . removeClass ( 'in' )
function removeElement ( ) {
$parent
. trigger ( 'closed' )
. remove ( )
}
$ . support . transition && $parent . hasClass ( 'fade' ) ?
$parent . on ( $ . support . transition . end , removeElement ) :
removeElement ( )
}
/ * A L E R T P L U G I N D E F I N I T I O N
* === === === === === === === == * /
var old = $ . fn . alert
$ . fn . alert = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'alert' )
if ( ! data ) $this . data ( 'alert' , ( data = new Alert ( this ) ) )
if ( typeof option == 'string' ) data [ option ] . call ( $this )
} )
}
$ . fn . alert . Constructor = Alert
/ * A L E R T N O C O N F L I C T
* === === === === === == * /
$ . fn . alert . noConflict = function ( ) {
$ . fn . alert = old
return this
}
/ * A L E R T D A T A - A P I
* === === === === == * /
$ ( document ) . on ( 'click.alert.data-api' , dismiss , Alert . prototype . close )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - button . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#buttons
* === === === === === === === === === === === === === === === === === === === ===
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === === * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * B U T T O N P U B L I C C L A S S D E F I N I T I O N
* === === === === === === === === === === * /
var Button = function ( element , options ) {
this . $element = $ ( element )
this . options = $ . extend ( { } , $ . fn . button . defaults , options )
}
Button . prototype . setState = function ( state ) {
var d = 'disabled'
, $el = this . $element
, data = $el . data ( )
, val = $el . is ( 'input' ) ? 'val' : 'html'
state = state + 'Text'
data . resetText || $el . data ( 'resetText' , $el [ val ] ( ) )
$el [ val ] ( data [ state ] || this . options [ state ] )
// push to event loop to allow forms to submit
setTimeout ( function ( ) {
state == 'loadingText' ?
$el . addClass ( d ) . attr ( d , d ) :
$el . removeClass ( d ) . removeAttr ( d )
} , 0 )
}
Button . prototype . toggle = function ( ) {
var $parent = this . $element . closest ( '[data-toggle="buttons-radio"]' )
$parent && $parent
. find ( '.active' )
. removeClass ( 'active' )
this . $element . toggleClass ( 'active' )
}
/ * B U T T O N P L U G I N D E F I N I T I O N
* === === === === === === === === * /
var old = $ . fn . button
$ . fn . button = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'button' )
, options = typeof option == 'object' && option
if ( ! data ) $this . data ( 'button' , ( data = new Button ( this , options ) ) )
if ( option == 'toggle' ) data . toggle ( )
else if ( option ) data . setState ( option )
} )
}
$ . fn . button . defaults = {
loadingText : 'loading...'
}
$ . fn . button . Constructor = Button
/ * B U T T O N N O C O N F L I C T
* === === === === === === * /
$ . fn . button . noConflict = function ( ) {
$ . fn . button = old
return this
}
/ * B U T T O N D A T A - A P I
* === === === === === * /
$ ( document ) . on ( 'click.button.data-api' , '[data-toggle^=button]' , function ( e ) {
var $btn = $ ( e . target )
if ( ! $btn . hasClass ( 'btn' ) ) $btn = $btn . closest ( '.btn' )
$btn . button ( 'toggle' )
} )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - collapse . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#collapse
* === === === === === === === === === === === === === === === === === === === === =
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === === * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * C O L L A P S E P U B L I C C L A S S D E F I N I T I O N
* === === === === === === === === === === == * /
var Collapse = function ( element , options ) {
this . $element = $ ( element )
this . options = $ . extend ( { } , $ . fn . collapse . defaults , options )
if ( this . options . parent ) {
this . $parent = $ ( this . options . parent )
}
this . options . toggle && this . toggle ( )
}
Collapse . prototype = {
constructor : Collapse
, dimension : function ( ) {
var hasWidth = this . $element . hasClass ( 'width' )
return hasWidth ? 'width' : 'height'
}
, show : function ( ) {
var dimension
, scroll
, actives
, hasData
if ( this . transitioning || this . $element . hasClass ( 'in' ) ) return
dimension = this . dimension ( )
scroll = $ . camelCase ( [ 'scroll' , dimension ] . join ( '-' ) )
actives = this . $parent && this . $parent . find ( '> .accordion-group > .in' )
if ( actives && actives . length ) {
hasData = actives . data ( 'collapse' )
if ( hasData && hasData . transitioning ) return
actives . collapse ( 'hide' )
hasData || actives . data ( 'collapse' , null )
}
this . $element [ dimension ] ( 0 )
this . transition ( 'addClass' , $ . Event ( 'show' ) , 'shown' )
$ . support . transition && this . $element [ dimension ] ( this . $element [ 0 ] [ scroll ] )
}
, hide : function ( ) {
var dimension
if ( this . transitioning || ! this . $element . hasClass ( 'in' ) ) return
dimension = this . dimension ( )
this . reset ( this . $element [ dimension ] ( ) )
this . transition ( 'removeClass' , $ . Event ( 'hide' ) , 'hidden' )
this . $element [ dimension ] ( 0 )
}
, reset : function ( size ) {
var dimension = this . dimension ( )
this . $element
. removeClass ( 'collapse' )
[ dimension ] ( size || 'auto' )
[ 0 ] . offsetWidth
this . $element [ size !== null ? 'addClass' : 'removeClass' ] ( 'collapse' )
return this
}
, transition : function ( method , startEvent , completeEvent ) {
var that = this
, complete = function ( ) {
if ( startEvent . type == 'show' ) that . reset ( )
that . transitioning = 0
that . $element . trigger ( completeEvent )
}
this . $element . trigger ( startEvent )
if ( startEvent . isDefaultPrevented ( ) ) return
this . transitioning = 1
this . $element [ method ] ( 'in' )
$ . support . transition && this . $element . hasClass ( 'collapse' ) ?
this . $element . one ( $ . support . transition . end , complete ) :
complete ( )
}
, toggle : function ( ) {
this [ this . $element . hasClass ( 'in' ) ? 'hide' : 'show' ] ( )
}
}
/ * C O L L A P S E P L U G I N D E F I N I T I O N
* === === === === === === === === == * /
var old = $ . fn . collapse
$ . fn . collapse = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'collapse' )
, options = $ . extend ( { } , $ . fn . collapse . defaults , $this . data ( ) , typeof option == 'object' && option )
if ( ! data ) $this . data ( 'collapse' , ( data = new Collapse ( this , options ) ) )
if ( typeof option == 'string' ) data [ option ] ( )
} )
}
$ . fn . collapse . defaults = {
toggle : true
}
$ . fn . collapse . Constructor = Collapse
/ * C O L L A P S E N O C O N F L I C T
* === === === === === === == * /
$ . fn . collapse . noConflict = function ( ) {
$ . fn . collapse = old
return this
}
/ * C O L L A P S E D A T A - A P I
* === === === === === == * /
$ ( document ) . on ( 'click.collapse.data-api' , '[data-toggle=collapse]' , function ( e ) {
var $this = $ ( this ) , href
, target = $this . attr ( 'data-target' )
|| e . preventDefault ( )
|| ( href = $this . attr ( 'href' ) ) && href . replace ( /.*(?=#[^\s]+$)/ , '' ) //strip for ie7
, option = $ ( target ) . data ( 'collapse' ) ? 'toggle' : $this . data ( )
$this [ $ ( target ) . hasClass ( 'in' ) ? 'addClass' : 'removeClass' ] ( 'collapsed' )
$ ( target ) . collapse ( option )
} )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - modal . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#modals
* === === === === === === === === === === === === === === === === === === ===
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * M O D A L C L A S S D E F I N I T I O N
* === === === === === === === = * /
var Modal = function ( element , options ) {
this . options = options
this . $element = $ ( element )
. delegate ( '[data-dismiss="modal"]' , 'click.dismiss.modal' , $ . proxy ( this . hide , this ) )
this . options . remote && this . $element . find ( '.modal-body' ) . load ( this . options . remote )
}
Modal . prototype = {
constructor : Modal
, toggle : function ( ) {
return this [ ! this . isShown ? 'show' : 'hide' ] ( )
}
, show : function ( ) {
var that = this
, e = $ . Event ( 'show' )
this . $element . trigger ( e )
if ( this . isShown || e . isDefaultPrevented ( ) ) return
this . isShown = true
this . escape ( )
this . backdrop ( function ( ) {
var transition = $ . support . transition && that . $element . hasClass ( 'fade' )
if ( ! that . $element . parent ( ) . length ) {
that . $element . appendTo ( document . body ) //don't move modals dom position
}
that . $element . show ( )
if ( transition ) {
that . $element [ 0 ] . offsetWidth // force reflow
}
that . $element
. addClass ( 'in' )
. attr ( 'aria-hidden' , false )
that . enforceFocus ( )
transition ?
that . $element . one ( $ . support . transition . end , function ( ) { that . $element . focus ( ) . trigger ( 'shown' ) } ) :
that . $element . focus ( ) . trigger ( 'shown' )
} )
}
, hide : function ( e ) {
e && e . preventDefault ( )
var that = this
e = $ . Event ( 'hide' )
this . $element . trigger ( e )
if ( ! this . isShown || e . isDefaultPrevented ( ) ) return
this . isShown = false
this . escape ( )
$ ( document ) . off ( 'focusin.modal' )
this . $element
. removeClass ( 'in' )
. attr ( 'aria-hidden' , true )
$ . support . transition && this . $element . hasClass ( 'fade' ) ?
this . hideWithTransition ( ) :
this . hideModal ( )
}
, enforceFocus : function ( ) {
var that = this
$ ( document ) . on ( 'focusin.modal' , function ( e ) {
if ( that . $element [ 0 ] !== e . target && ! that . $element . has ( e . target ) . length ) {
that . $element . focus ( )
}
} )
}
, escape : function ( ) {
var that = this
if ( this . isShown && this . options . keyboard ) {
this . $element . on ( 'keyup.dismiss.modal' , function ( e ) {
e . which == 27 && that . hide ( )
} )
} else if ( ! this . isShown ) {
this . $element . off ( 'keyup.dismiss.modal' )
}
}
, hideWithTransition : function ( ) {
var that = this
, timeout = setTimeout ( function ( ) {
that . $element . off ( $ . support . transition . end )
that . hideModal ( )
} , 500 )
this . $element . one ( $ . support . transition . end , function ( ) {
clearTimeout ( timeout )
that . hideModal ( )
} )
}
, hideModal : function ( ) {
var that = this
this . $element . hide ( )
this . backdrop ( function ( ) {
that . removeBackdrop ( )
that . $element . trigger ( 'hidden' )
} )
}
, removeBackdrop : function ( ) {
this . $backdrop && this . $backdrop . remove ( )
this . $backdrop = null
}
, backdrop : function ( callback ) {
var that = this
, animate = this . $element . hasClass ( 'fade' ) ? 'fade' : ''
if ( this . isShown && this . options . backdrop ) {
var doAnimate = $ . support . transition && animate
this . $backdrop = $ ( '<div class="modal-backdrop ' + animate + '" />' )
. appendTo ( document . body )
this . $backdrop . click (
this . options . backdrop == 'static' ?
$ . proxy ( this . $element [ 0 ] . focus , this . $element [ 0 ] )
: $ . proxy ( this . hide , this )
)
if ( doAnimate ) this . $backdrop [ 0 ] . offsetWidth // force reflow
this . $backdrop . addClass ( 'in' )
if ( ! callback ) return
doAnimate ?
this . $backdrop . one ( $ . support . transition . end , callback ) :
callback ( )
} else if ( ! this . isShown && this . $backdrop ) {
this . $backdrop . removeClass ( 'in' )
$ . support . transition && this . $element . hasClass ( 'fade' ) ?
this . $backdrop . one ( $ . support . transition . end , callback ) :
callback ( )
} else if ( callback ) {
callback ( )
}
}
}
/ * M O D A L P L U G I N D E F I N I T I O N
* === === === === === === === == * /
var old = $ . fn . modal
$ . fn . modal = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'modal' )
, options = $ . extend ( { } , $ . fn . modal . defaults , $this . data ( ) , typeof option == 'object' && option )
if ( ! data ) $this . data ( 'modal' , ( data = new Modal ( this , options ) ) )
if ( typeof option == 'string' ) data [ option ] ( )
else if ( options . show ) data . show ( )
} )
}
$ . fn . modal . defaults = {
backdrop : true
, keyboard : true
, show : true
}
$ . fn . modal . Constructor = Modal
/ * M O D A L N O C O N F L I C T
* === === === === === == * /
$ . fn . modal . noConflict = function ( ) {
$ . fn . modal = old
return this
}
/ * M O D A L D A T A - A P I
* === === === === == * /
$ ( document ) . on ( 'click.modal.data-api' , '[data-toggle="modal"]' , function ( e ) {
var $this = $ ( this )
, href = $this . attr ( 'href' )
, $target = $ ( $this . attr ( 'data-target' ) || ( href && href . replace ( /.*(?=#[^\s]+$)/ , '' ) ) ) //strip for ie7
, option = $target . data ( 'modal' ) ? 'toggle' : $ . extend ( { remote : ! /#/ . test ( href ) && href } , $target . data ( ) , $this . data ( ) )
e . preventDefault ( )
$target
. modal ( option )
. one ( 'hide' , function ( ) {
$this . focus ( )
} )
} )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - tooltip . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#tooltips
* Inspired by the original jQuery . tipsy by Jason Frame
* === === === === === === === === === === === === === === === === === === === ==
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === = * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * T O O L T I P P U B L I C C L A S S D E F I N I T I O N
* === === === === === === === === === === = * /
var Tooltip = function ( element , options ) {
this . init ( 'tooltip' , element , options )
}
Tooltip . prototype = {
constructor : Tooltip
, init : function ( type , element , options ) {
var eventIn
, eventOut
, triggers
, trigger
, i
this . type = type
this . $element = $ ( element )
this . options = this . getOptions ( options )
this . enabled = true
triggers = this . options . trigger . split ( ' ' )
for ( i = triggers . length ; i -- ; ) {
trigger = triggers [ i ]
if ( trigger == 'click' ) {
this . $element . on ( 'click.' + this . type , this . options . selector , $ . proxy ( this . toggle , this ) )
} else if ( trigger != 'manual' ) {
eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
this . $element . on ( eventIn + '.' + this . type , this . options . selector , $ . proxy ( this . enter , this ) )
this . $element . on ( eventOut + '.' + this . type , this . options . selector , $ . proxy ( this . leave , this ) )
}
}
this . options . selector ?
( this . _options = $ . extend ( { } , this . options , { trigger : 'manual' , selector : '' } ) ) :
this . fixTitle ( )
}
, getOptions : function ( options ) {
options = $ . extend ( { } , $ . fn [ this . type ] . defaults , this . $element . data ( ) , options )
if ( options . delay && typeof options . delay == 'number' ) {
options . delay = {
show : options . delay
, hide : options . delay
}
}
return options
}
, enter : function ( e ) {
var defaults = $ . fn [ this . type ] . defaults
, options = { }
, self
this . _options && $ . each ( this . _options , function ( key , value ) {
if ( defaults [ key ] != value ) options [ key ] = value
} , this )
self = $ ( e . currentTarget ) [ this . type ] ( options ) . data ( this . type )
if ( ! self . options . delay || ! self . options . delay . show ) return self . show ( )
clearTimeout ( this . timeout )
self . hoverState = 'in'
this . timeout = setTimeout ( function ( ) {
if ( self . hoverState == 'in' ) self . show ( )
} , self . options . delay . show )
}
, leave : function ( e ) {
var self = $ ( e . currentTarget ) [ this . type ] ( this . _options ) . data ( this . type )
if ( this . timeout ) clearTimeout ( this . timeout )
if ( ! self . options . delay || ! self . options . delay . hide ) return self . hide ( )
self . hoverState = 'out'
this . timeout = setTimeout ( function ( ) {
if ( self . hoverState == 'out' ) self . hide ( )
} , self . options . delay . hide )
}
, show : function ( ) {
var $tip
, pos
, actualWidth
, actualHeight
, placement
, tp
, e = $ . Event ( 'show' )
if ( this . hasContent ( ) && this . enabled ) {
this . $element . trigger ( e )
if ( e . isDefaultPrevented ( ) ) return
$tip = this . tip ( )
this . setContent ( )
if ( this . options . animation ) {
$tip . addClass ( 'fade' )
}
placement = typeof this . options . placement == 'function' ?
this . options . placement . call ( this , $tip [ 0 ] , this . $element [ 0 ] ) :
this . options . placement
$tip
. detach ( )
. css ( { top : 0 , left : 0 , display : 'block' } )
this . options . container ? $tip . appendTo ( this . options . container ) : $tip . insertAfter ( this . $element )
pos = this . getPosition ( )
actualWidth = $tip [ 0 ] . offsetWidth
actualHeight = $tip [ 0 ] . offsetHeight
switch ( placement ) {
case 'bottom' :
tp = { top : pos . top + pos . height , left : pos . left + pos . width / 2 - actualWidth / 2 }
break
case 'top' :
tp = { top : pos . top - actualHeight , left : pos . left + pos . width / 2 - actualWidth / 2 }
break
case 'left' :
tp = { top : pos . top + pos . height / 2 - actualHeight / 2 , left : pos . left - actualWidth }
break
case 'right' :
tp = { top : pos . top + pos . height / 2 - actualHeight / 2 , left : pos . left + pos . width }
break
}
this . applyPlacement ( tp , placement )
this . $element . trigger ( 'shown' )
}
}
, applyPlacement : function ( offset , placement ) {
var $tip = this . tip ( )
, width = $tip [ 0 ] . offsetWidth
, height = $tip [ 0 ] . offsetHeight
, actualWidth
, actualHeight
, delta
, replace
$tip
. offset ( offset )
. addClass ( placement )
. addClass ( 'in' )
actualWidth = $tip [ 0 ] . offsetWidth
actualHeight = $tip [ 0 ] . offsetHeight
if ( placement == 'top' && actualHeight != height ) {
offset . top = offset . top + height - actualHeight
replace = true
}
if ( placement == 'bottom' || placement == 'top' ) {
delta = 0
if ( offset . left < 0 ) {
delta = offset . left * - 2
offset . left = 0
$tip . offset ( offset )
actualWidth = $tip [ 0 ] . offsetWidth
actualHeight = $tip [ 0 ] . offsetHeight
}
this . replaceArrow ( delta - width + actualWidth , actualWidth , 'left' )
} else {
this . replaceArrow ( actualHeight - height , actualHeight , 'top' )
}
if ( replace ) $tip . offset ( offset )
}
, replaceArrow : function ( delta , dimension , position ) {
this
. arrow ( )
. css ( position , delta ? ( 50 * ( 1 - delta / dimension ) + "%" ) : '' )
}
, setContent : function ( ) {
var $tip = this . tip ( )
, title = this . getTitle ( )
$tip . find ( '.tooltip-inner' ) [ this . options . html ? 'html' : 'text' ] ( title )
$tip . removeClass ( 'fade in top bottom left right' )
}
, hide : function ( ) {
var that = this
, $tip = this . tip ( )
, e = $ . Event ( 'hide' )
this . $element . trigger ( e )
if ( e . isDefaultPrevented ( ) ) return
$tip . removeClass ( 'in' )
function removeWithAnimation ( ) {
var timeout = setTimeout ( function ( ) {
$tip . off ( $ . support . transition . end ) . detach ( )
} , 500 )
$tip . one ( $ . support . transition . end , function ( ) {
clearTimeout ( timeout )
$tip . detach ( )
} )
}
$ . support . transition && this . $tip . hasClass ( 'fade' ) ?
removeWithAnimation ( ) :
$tip . detach ( )
this . $element . trigger ( 'hidden' )
return this
}
, fixTitle : function ( ) {
var $e = this . $element
if ( $e . attr ( 'title' ) || typeof ( $e . attr ( 'data-original-title' ) ) != 'string' ) {
$e . attr ( 'data-original-title' , $e . attr ( 'title' ) || '' ) . attr ( 'title' , '' )
}
}
, hasContent : function ( ) {
return this . getTitle ( )
}
, getPosition : function ( ) {
var el = this . $element [ 0 ]
return $ . extend ( { } , ( typeof el . getBoundingClientRect == 'function' ) ? el . getBoundingClientRect ( ) : {
width : el . offsetWidth
, height : el . offsetHeight
} , this . $element . offset ( ) )
}
, getTitle : function ( ) {
var title
, $e = this . $element
, o = this . options
title = $e . attr ( 'data-original-title' )
|| ( typeof o . title == 'function' ? o . title . call ( $e [ 0 ] ) : o . title )
return title
}
, tip : function ( ) {
return this . $tip = this . $tip || $ ( this . options . template )
}
, arrow : function ( ) {
return this . $arrow = this . $arrow || this . tip ( ) . find ( ".tooltip-arrow" )
}
, validate : function ( ) {
if ( ! this . $element [ 0 ] . parentNode ) {
this . hide ( )
this . $element = null
this . options = null
}
}
, enable : function ( ) {
this . enabled = true
}
, disable : function ( ) {
this . enabled = false
}
, toggleEnabled : function ( ) {
this . enabled = ! this . enabled
}
, toggle : function ( e ) {
var self = e ? $ ( e . currentTarget ) [ this . type ] ( this . _options ) . data ( this . type ) : this
self . tip ( ) . hasClass ( 'in' ) ? self . hide ( ) : self . show ( )
}
, destroy : function ( ) {
this . hide ( ) . $element . off ( '.' + this . type ) . removeData ( this . type )
}
}
/ * T O O L T I P P L U G I N D E F I N I T I O N
* === === === === === === === === = * /
var old = $ . fn . tooltip
$ . fn . tooltip = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'tooltip' )
, options = typeof option == 'object' && option
if ( ! data ) $this . data ( 'tooltip' , ( data = new Tooltip ( this , options ) ) )
if ( typeof option == 'string' ) data [ option ] ( )
} )
}
$ . fn . tooltip . Constructor = Tooltip
$ . fn . tooltip . defaults = {
animation : true
, placement : 'top'
, selector : false
, template : '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
, trigger : 'hover focus'
, title : ''
, delay : 0
, html : false
, container : false
}
/ * T O O L T I P N O C O N F L I C T
* === === === === === === = * /
$ . fn . tooltip . noConflict = function ( ) {
$ . fn . tooltip = old
return this
}
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - popover . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#popovers
* === === === === === === === === === === === === === === === === === === === ==
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === == * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * P O P O V E R P U B L I C C L A S S D E F I N I T I O N
* === === === === === === === === === === = * /
var Popover = function ( element , options ) {
this . init ( 'popover' , element , options )
}
/ * N O T E : P O P O V E R E X T E N D S B O O T S T R A P - T O O L T I P . j s
=== === === === === === === === === === === === === === * /
Popover . prototype = $ . extend ( { } , $ . fn . tooltip . Constructor . prototype , {
constructor : Popover
, setContent : function ( ) {
var $tip = this . tip ( )
, title = this . getTitle ( )
, content = this . getContent ( )
$tip . find ( '.popover-title' ) [ this . options . html ? 'html' : 'text' ] ( title )
$tip . find ( '.popover-content' ) [ this . options . html ? 'html' : 'text' ] ( content )
$tip . removeClass ( 'fade top bottom left right in' )
}
, hasContent : function ( ) {
return this . getTitle ( ) || this . getContent ( )
}
, getContent : function ( ) {
var content
, $e = this . $element
, o = this . options
content = ( typeof o . content == 'function' ? o . content . call ( $e [ 0 ] ) : o . content )
|| $e . attr ( 'data-content' )
return content
}
, tip : function ( ) {
if ( ! this . $tip ) {
this . $tip = $ ( this . options . template )
}
return this . $tip
}
, destroy : function ( ) {
this . hide ( ) . $element . off ( '.' + this . type ) . removeData ( this . type )
}
} )
/ * P O P O V E R P L U G I N D E F I N I T I O N
* === === === === === === === == * /
var old = $ . fn . popover
$ . fn . popover = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'popover' )
, options = typeof option == 'object' && option
if ( ! data ) $this . data ( 'popover' , ( data = new Popover ( this , options ) ) )
if ( typeof option == 'string' ) data [ option ] ( )
} )
}
$ . fn . popover . Constructor = Popover
$ . fn . popover . defaults = $ . extend ( { } , $ . fn . tooltip . defaults , {
placement : 'right'
, trigger : 'click'
, content : ''
, template : '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
} )
/ * P O P O V E R N O C O N F L I C T
* === === === === === === = * /
$ . fn . popover . noConflict = function ( ) {
$ . fn . popover = old
return this
}
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - scrollspy . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#scrollspy
* === === === === === === === === === === === === === === === === === === === === =
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === === == * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * S C R O L L S P Y C L A S S D E F I N I T I O N
* === === === === === === === === == * /
function ScrollSpy ( element , options ) {
var process = $ . proxy ( this . process , this )
, $element = $ ( element ) . is ( 'body' ) ? $ ( window ) : $ ( element )
, href
this . options = $ . extend ( { } , $ . fn . scrollspy . defaults , options )
this . $scrollElement = $element . on ( 'scroll.scroll-spy.data-api' , process )
this . selector = ( this . options . target
|| ( ( href = $ ( element ) . attr ( 'href' ) ) && href . replace ( /.*(?=#[^\s]+$)/ , '' ) ) //strip for ie7
|| '' ) + ' .nav li > a'
this . $body = $ ( 'body' )
this . refresh ( )
this . process ( )
}
ScrollSpy . prototype = {
constructor : ScrollSpy
, refresh : function ( ) {
var self = this
, $targets
this . offsets = $ ( [ ] )
this . targets = $ ( [ ] )
$targets = this . $body
. find ( this . selector )
. map ( function ( ) {
var $el = $ ( this )
, href = $el . data ( 'target' ) || $el . attr ( 'href' )
, $href = /^#\w/ . test ( href ) && $ ( href )
return ( $href
&& $href . length
&& [ [ $href . position ( ) . top + ( ! $ . isWindow ( self . $scrollElement . get ( 0 ) ) && self . $scrollElement . scrollTop ( ) ) , href ] ] ) || null
} )
. sort ( function ( a , b ) { return a [ 0 ] - b [ 0 ] } )
. each ( function ( ) {
self . offsets . push ( this [ 0 ] )
self . targets . push ( this [ 1 ] )
} )
}
, process : function ( ) {
var scrollTop = this . $scrollElement . scrollTop ( ) + this . options . offset
, scrollHeight = this . $scrollElement [ 0 ] . scrollHeight || this . $body [ 0 ] . scrollHeight
, maxScroll = scrollHeight - this . $scrollElement . height ( )
, offsets = this . offsets
, targets = this . targets
, activeTarget = this . activeTarget
, i
if ( scrollTop >= maxScroll ) {
return activeTarget != ( i = targets . last ( ) [ 0 ] )
&& this . activate ( i )
}
for ( i = offsets . length ; i -- ; ) {
activeTarget != targets [ i ]
&& scrollTop >= offsets [ i ]
&& ( ! offsets [ i + 1 ] || scrollTop <= offsets [ i + 1 ] )
&& this . activate ( targets [ i ] )
}
}
, activate : function ( target ) {
var active
, selector
this . activeTarget = target
$ ( this . selector )
. parent ( '.active' )
. removeClass ( 'active' )
selector = this . selector
+ '[data-target="' + target + '"],'
+ this . selector + '[href="' + target + '"]'
active = $ ( selector )
. parent ( 'li' )
. addClass ( 'active' )
if ( active . parent ( '.dropdown-menu' ) . length ) {
active = active . closest ( 'li.dropdown' ) . addClass ( 'active' )
}
active . trigger ( 'activate' )
}
}
/ * S C R O L L S P Y P L U G I N D E F I N I T I O N
* === === === === === === === === === * /
var old = $ . fn . scrollspy
$ . fn . scrollspy = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'scrollspy' )
, options = typeof option == 'object' && option
if ( ! data ) $this . data ( 'scrollspy' , ( data = new ScrollSpy ( this , options ) ) )
if ( typeof option == 'string' ) data [ option ] ( )
} )
}
$ . fn . scrollspy . Constructor = ScrollSpy
$ . fn . scrollspy . defaults = {
offset : 10
}
/ * S C R O L L S P Y N O C O N F L I C T
* === === === === === === === * /
$ . fn . scrollspy . noConflict = function ( ) {
$ . fn . scrollspy = old
return this
}
/ * S C R O L L S P Y D A T A - A P I
* === === === === === === * /
$ ( window ) . on ( 'load' , function ( ) {
$ ( '[data-spy="scroll"]' ) . each ( function ( ) {
var $spy = $ ( this )
$spy . scrollspy ( $spy . data ( ) )
} )
} )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - tab . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#tabs
* === === === === === === === === === === === === === === === === === === ==
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === == * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * T A B C L A S S D E F I N I T I O N
* === === === === === === == * /
var Tab = function ( element ) {
this . element = $ ( element )
}
Tab . prototype = {
constructor : Tab
, show : function ( ) {
var $this = this . element
, $ul = $this . closest ( 'ul:not(.dropdown-menu)' )
, selector = $this . attr ( 'data-target' )
, previous
, $target
, e
if ( ! selector ) {
selector = $this . attr ( 'href' )
selector = selector && selector . replace ( /.*(?=#[^\s]*$)/ , '' ) //strip for ie7
}
if ( $this . parent ( 'li' ) . hasClass ( 'active' ) ) return
previous = $ul . find ( '.active:last a' ) [ 0 ]
e = $ . Event ( 'show' , {
relatedTarget : previous
} )
$this . trigger ( e )
if ( e . isDefaultPrevented ( ) ) return
$target = $ ( selector )
this . activate ( $this . parent ( 'li' ) , $ul )
this . activate ( $target , $target . parent ( ) , function ( ) {
$this . trigger ( {
type : 'shown'
, relatedTarget : previous
} )
} )
}
, activate : function ( element , container , callback ) {
var $active = container . find ( '> .active' )
, transition = callback
&& $ . support . transition
&& $active . hasClass ( 'fade' )
function next ( ) {
$active
. removeClass ( 'active' )
. find ( '> .dropdown-menu > .active' )
. removeClass ( 'active' )
element . addClass ( 'active' )
if ( transition ) {
element [ 0 ] . offsetWidth // reflow for transition
element . addClass ( 'in' )
} else {
element . removeClass ( 'fade' )
}
if ( element . parent ( '.dropdown-menu' ) ) {
element . closest ( 'li.dropdown' ) . addClass ( 'active' )
}
callback && callback ( )
}
transition ?
$active . one ( $ . support . transition . end , next ) :
next ( )
$active . removeClass ( 'in' )
}
}
/ * T A B P L U G I N D E F I N I T I O N
* === === === === === === === * /
var old = $ . fn . tab
$ . fn . tab = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'tab' )
if ( ! data ) $this . data ( 'tab' , ( data = new Tab ( this ) ) )
if ( typeof option == 'string' ) data [ option ] ( )
} )
}
$ . fn . tab . Constructor = Tab
/ * T A B N O C O N F L I C T
* === === === === === * /
$ . fn . tab . noConflict = function ( ) {
$ . fn . tab = old
return this
}
/ * T A B D A T A - A P I
* === === === === * /
$ ( document ) . on ( 'click.tab.data-api' , '[data-toggle="tab"], [data-toggle="pill"]' , function ( e ) {
e . preventDefault ( )
$ ( this ) . tab ( 'show' )
} )
} ( window . jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - typeahead . js v2 . 3.2
* http : //getbootstrap.com/2.3.2/javascript.html#typeahead
* === === === === === === === === === === === === === === === === === === === === =
* Copyright 2013 Twitter , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === === * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * T Y P E A H E A D P U B L I C C L A S S D E F I N I T I O N
* === === === === === === === === === === === * /
var Typeahead = function ( element , options ) {
this . $element = $ ( element )
this . options = $ . extend ( { } , $ . fn . typeahead . defaults , options )
this . matcher = this . options . matcher || this . matcher
this . sorter = this . options . sorter || this . sorter
this . highlighter = this . options . highlighter || this . highlighter
this . updater = this . options . updater || this . updater
this . source = this . options . source
this . $menu = $ ( this . options . menu )
this . shown = false
this . listen ( )
}
Typeahead . prototype = {
constructor : Typeahead
, select : function ( ) {
var val = this . $menu . find ( '.active' ) . attr ( 'data-value' )
this . $element
. val ( this . updater ( val ) )
. change ( )
return this . hide ( )
}
, updater : function ( item ) {
return item
}
, show : function ( ) {
var pos = $ . extend ( { } , this . $element . position ( ) , {
height : this . $element [ 0 ] . offsetHeight
} )
this . $menu
. insertAfter ( this . $element )
. css ( {
top : pos . top + pos . height
, left : pos . left
} )
. show ( )
this . shown = true
return this
}
, hide : function ( ) {
this . $menu . hide ( )
this . shown = false
return this
}
, lookup : function ( event ) {
var items
this . query = this . $element . val ( )
if ( ! this . query || this . query . length < this . options . minLength ) {
return this . shown ? this . hide ( ) : this
}
items = $ . isFunction ( this . source ) ? this . source ( this . query , $ . proxy ( this . process , this ) ) : this . source
return items ? this . process ( items ) : this
}
, process : function ( items ) {
var that = this
items = $ . grep ( items , function ( item ) {
return that . matcher ( item )
} )
items = this . sorter ( items )
if ( ! items . length ) {
return this . shown ? this . hide ( ) : this
}
return this . render ( items . slice ( 0 , this . options . items ) ) . show ( )
}
, matcher : function ( item ) {
return ~ item . toLowerCase ( ) . indexOf ( this . query . toLowerCase ( ) )
}
, sorter : function ( items ) {
var beginswith = [ ]
, caseSensitive = [ ]
, caseInsensitive = [ ]
, item
while ( item = items . shift ( ) ) {
if ( ! item . toLowerCase ( ) . indexOf ( this . query . toLowerCase ( ) ) ) beginswith . push ( item )
else if ( ~ item . indexOf ( this . query ) ) caseSensitive . push ( item )
else caseInsensitive . push ( item )
}
return beginswith . concat ( caseSensitive , caseInsensitive )
}
, highlighter : function ( item ) {
var query = this . query . replace ( /[\-\[\]{}()*+?.,\\\^$|#\s]/g , '\\$&' )
return item . replace ( new RegExp ( '(' + query + ')' , 'ig' ) , function ( $1 , match ) {
return '<strong>' + match + '</strong>'
} )
}
, render : function ( items ) {
var that = this
items = $ ( items ) . map ( function ( i , item ) {
i = $ ( that . options . item ) . attr ( 'data-value' , item )
i . find ( 'a' ) . html ( that . highlighter ( item ) )
return i [ 0 ]
} )
items . first ( ) . addClass ( 'active' )
this . $menu . html ( items )
return this
}
, next : function ( event ) {
var active = this . $menu . find ( '.active' ) . removeClass ( 'active' )
, next = active . next ( )
if ( ! next . length ) {
next = $ ( this . $menu . find ( 'li' ) [ 0 ] )
}
next . addClass ( 'active' )
}
, prev : function ( event ) {
var active = this . $menu . find ( '.active' ) . removeClass ( 'active' )
, prev = active . prev ( )
if ( ! prev . length ) {
prev = this . $menu . find ( 'li' ) . last ( )
}
prev . addClass ( 'active' )
}
, listen : function ( ) {
this . $element
. on ( 'focus' , $ . proxy ( this . focus , this ) )
. on ( 'blur' , $ . proxy ( this . blur , this ) )
. on ( 'keypress' , $ . proxy ( this . keypress , this ) )
. on ( 'keyup' , $ . proxy ( this . keyup , this ) )
if ( this . eventSupported ( 'keydown' ) ) {
this . $element . on ( 'keydown' , $ . proxy ( this . keydown , this ) )
}
this . $menu
. on ( 'click' , $ . proxy ( this . click , this ) )
. on ( 'mouseenter' , 'li' , $ . proxy ( this . mouseenter , this ) )
. on ( 'mouseleave' , 'li' , $ . proxy ( this . mouseleave , this ) )
}
, eventSupported : function ( eventName ) {
var isSupported = eventName in this . $element
if ( ! isSupported ) {
this . $element . setAttribute ( eventName , 'return;' )
isSupported = typeof this . $element [ eventName ] === 'function'
}
return isSupported
}
, move : function ( e ) {
if ( ! this . shown ) return
switch ( e . keyCode ) {
case 9 : // tab
case 13 : // enter
case 27 : // escape
e . preventDefault ( )
break
case 38 : // up arrow
e . preventDefault ( )
this . prev ( )
break
case 40 : // down arrow
e . preventDefault ( )
this . next ( )
break
}
e . stopPropagation ( )
}
, keydown : function ( e ) {
this . suppressKeyPressRepeat = ~ $ . inArray ( e . keyCode , [ 40 , 38 , 9 , 13 , 27 ] )
this . move ( e )
}
, keypress : function ( e ) {
if ( this . suppressKeyPressRepeat ) return
this . move ( e )
}
, keyup : function ( e ) {
switch ( e . keyCode ) {
case 40 : // down arrow
case 38 : // up arrow
case 16 : // shift
case 17 : // ctrl
case 18 : // alt
break
case 9 : // tab
case 13 : // enter
if ( ! this . shown ) return
this . select ( )
break
case 27 : // escape
if ( ! this . shown ) return
this . hide ( )
break
default :
this . lookup ( )
}
e . stopPropagation ( )
e . preventDefault ( )
}
, focus : function ( e ) {
this . focused = true
}
, blur : function ( e ) {
this . focused = false
if ( ! this . mousedover && this . shown ) this . hide ( )
}
, click : function ( e ) {
e . stopPropagation ( )
e . preventDefault ( )
this . select ( )
this . $element . focus ( )
}
, mouseenter : function ( e ) {
this . mousedover = true
this . $menu . find ( '.active' ) . removeClass ( 'active' )
$ ( e . currentTarget ) . addClass ( 'active' )
}
, mouseleave : function ( e ) {
this . mousedover = false
if ( ! this . focused && this . shown ) this . hide ( )
}
}
/ * T Y P E A H E A D P L U G I N D E F I N I T I O N
* === === === === === === === === === * /
var old = $ . fn . typeahead
$ . fn . typeahead = function ( option ) {
return this . each ( function ( ) {
var $this = $ ( this )
, data = $this . data ( 'typeahead' )
, options = typeof option == 'object' && option
if ( ! data ) $this . data ( 'typeahead' , ( data = new Typeahead ( this , options ) ) )
if ( typeof option == 'string' ) data [ option ] ( )
} )
}
$ . fn . typeahead . defaults = {
source : [ ]
, items : 8
, menu : '<ul class="typeahead dropdown-menu"></ul>'
, item : '<li><a href="#"></a></li>'
, minLength : 1
}
$ . fn . typeahead . Constructor = Typeahead
/ * T Y P E A H E A D N O C O N F L I C T
* === === === === === === = * /
$ . fn . typeahead . noConflict = function ( ) {
$ . fn . typeahead = old
return this
}
/ * T Y P E A H E A D D A T A - A P I
* === === === === === === * /
$ ( document ) . on ( 'focus.typeahead.data-api' , '[data-provide="typeahead"]' , function ( e ) {
var $this = $ ( this )
if ( $this . data ( 'typeahead' ) ) return
$this . typeahead ( $this . data ( ) )
} )
} ( window . jQuery ) ;
! function ( $ ) {
"use strict" ;
/ * L I G H T B O X C L A S S D E F I N I T I O N
* === === === === === === === === = * /
var Lightbox = function ( element , options )
{
this . options = options ;
this . $element = $ ( element )
. delegate ( '[data-dismiss="lightbox"]' , 'click.dismiss.lightbox' , $ . proxy ( this . hide , this ) ) ;
this . options . remote && this . $element . find ( '.lightbox-body' ) . load ( this . options . remote ) ;
}
// We depend upon Twitter Bootstrap's Modal library to simplify things here
Lightbox . prototype = $ . extend ( { } , $ . fn . modal . Constructor . prototype ) ;
Lightbox . prototype . constructor = Lightbox ;
// We can't use Modal for this, it depends upon a class
Lightbox . prototype . enforceFocus = function ( )
{
var that = this ;
$ ( document ) . on ( 'focusin.lightbox' , function ( e )
{
if ( that . $element [ 0 ] !== e . target && ! that . $element . has ( e . target ) . length )
{
that . $element . focus ( ) ;
}
} ) ;
} ;
// We have to have a copy of this since we are tweaking it a bit
Lightbox . prototype . show = function ( )
{
var that = this ,
e = $ . Event ( 'show' ) ;
this . $element . trigger ( e ) ;
if ( this . isShown || e . isDefaultPrevented ( ) ) return ;
this . isShown = true ;
this . escape ( ) ;
// This bit is added since we don't display until we have the size
// which prevents image jumping
this . preloadSize ( function ( )
{
that . backdrop ( function ( )
{
var transition = $ . support . transition && that . $element . hasClass ( 'fade' ) ;
if ( ! that . $element . parent ( ) . length )
{
that . $element . appendTo ( document . body ) ; //don't move modals dom position
}
that . $element . show ( ) ;
if ( transition )
{
that . $element [ 0 ] . offsetWidth ; // force reflow
}
that . $element
. addClass ( 'in' )
. attr ( 'aria-hidden' , false ) ;
that . enforceFocus ( ) ;
transition ?
that . $element . one ( $ . support . transition . end , function ( ) { that . $element . focus ( ) . trigger ( 'shown' ) } ) :
that . $element . focus ( ) . trigger ( 'shown' ) ;
} ) ;
} ) ;
} ;
// We have to have this because of a class in it
Lightbox . prototype . hide = function ( e )
{
e && e . preventDefault ( ) ;
var that = this ;
e = $ . Event ( 'hide' ) ;
this . $element . trigger ( e ) ;
if ( ! this . isShown || e . isDefaultPrevented ( ) ) return ;
this . isShown = false ;
this . escape ( ) ;
$ ( document ) . off ( 'focusin.lightbox' ) ;
this . $element
. removeClass ( 'in' )
. attr ( 'aria-hidden' , true ) ;
$ . support . transition && this . $element . hasClass ( 'fade' ) ?
this . hideWithTransition ( ) :
this . hideModal ( ) ;
} ;
// This references a class as well
Lightbox . prototype . escape = function ( )
{
var that = this ;
if ( this . isShown && this . options . keyboard )
{
this . $element . on ( 'keyup.dismiss.lightbox' , function ( e )
{
e . which == 27 && that . hide ( ) ;
} ) ;
}
else if ( ! this . isShown )
{
this . $element . off ( 'keyup.dismiss.lightbox' ) ;
}
}
Lightbox . prototype . preloadSize = function ( callback )
{
var callbacks = $ . Callbacks ( ) ;
if ( callback ) callbacks . add ( callback ) ;
var that = this ;
var windowHeight ,
windowWidth ,
padTop ,
padBottom ,
padLeft ,
padRight ,
$image ,
preloader ,
originalWidth ,
originalHeight ;
// Get the window width and height.
windowHeight = $ ( window ) . height ( ) ;
windowWidth = $ ( window ) . width ( ) ;
// Get the top, bottom, right, and left padding
padTop = parseInt ( that . $element . find ( '.lightbox-content' ) . css ( 'padding-top' ) , 10 ) ;
padBottom = parseInt ( that . $element . find ( '.lightbox-content' ) . css ( 'padding-bottom' ) , 10 ) ;
padLeft = parseInt ( that . $element . find ( '.lightbox-content' ) . css ( 'padding-left' ) , 10 ) ;
padRight = parseInt ( that . $element . find ( '.lightbox-content' ) . css ( 'padding-right' ) , 10 ) ;
// Load the image, we have to do this because if the image isn't already loaded we get a bad size
$image = that . $element . find ( '.lightbox-content' ) . find ( 'img:first' ) ;
preloader = new Image ( ) ;
preloader . onload = function ( )
{
//$image.width = preloader.width;
//$image.height = preloader.height;
//return _this.sizeContainer(preloader.width, preloader.height);
// The image could be bigger than the window, that is an issue.
if ( ( preloader . width + padLeft + padRight ) >= windowWidth )
{
originalWidth = preloader . width ;
originalHeight = preloader . height ;
preloader . width = windowWidth - padLeft - padRight ;
preloader . height = originalHeight / originalWidth * preloader . width ;
}
if ( ( preloader . height + padTop + padBottom ) >= windowHeight )
{
originalWidth = preloader . width ;
originalHeight = preloader . height ;
preloader . height = windowHeight - padTop - padBottom ;
preloader . width = originalWidth / originalHeight * preloader . height ;
}
that . $element . css ( {
'position' : 'fixed' ,
'width' : preloader . width + padLeft + padRight ,
'height' : preloader . height + padTop + padBottom ,
'top' : ( windowHeight / 2 ) - ( ( preloader . height + padTop + padBottom ) / 2 ) ,
'left' : '50%' ,
'margin-left' : - 1 * ( preloader . width + padLeft + padRight ) / 2
} ) ;
that . $element . find ( '.lightbox-content' ) . css ( {
'width' : preloader . width ,
'height' : preloader . height
} ) ;
// We have everything sized!
callbacks . fire ( ) ;
} ;
preloader . src = $image . attr ( 'src' ) ;
} ;
/ * L I G H T B O X P L U G I N D E F I N I T I O N
* === === === === === === === == * /
var old = $ . fn . lightbox ;
$ . fn . lightbox = function ( option )
{
return this . each ( function ( )
{
var $this = $ ( this ) ;
var data = $this . data ( 'lightbox' ) ;
var options = $ . extend ( { } , $ . fn . lightbox . defaults , $this . data ( ) , typeof option == 'object' && option ) ;
if ( ! data ) $this . data ( 'lightbox' , ( data = new Lightbox ( this , options ) ) ) ;
if ( typeof option == 'string' )
data [ option ] ( ) ;
else if ( options . show )
data . show ( ) ;
} ) ;
} ;
$ . fn . lightbox . defaults = {
backdrop : true ,
keyboard : true ,
show : true
} ;
$ . fn . lightbox . Constructor = Lightbox ;
/ * L I G H T B O X N O C O N F L I C T
* === === === === === == * /
$ . fn . lightbox . noConflict = function ( ) {
$ . fn . lightbox = old ;
return this ;
}
/ * L I G H T B O X D A T A - A P I
* === === === === === === * /
$ ( document ) . on ( 'click.lightbox.data-api' , '[data-toggle*="lightbox"]' , function ( e )
{
var $this = $ ( this ) ;
var href = $this . attr ( 'href' ) ;
var $target = $ ( $this . attr ( 'data-target' ) || ( href && href . replace ( /.*(?=#[^\s]+$)/ , '' ) ) ) ; //strip for ie7
var option = $target . data ( 'lightbox' ) ? 'toggle' : $ . extend ( { remote : ! /#/ . test ( href ) && href } , $target . data ( ) , $this . data ( ) ) ;
e . preventDefault ( ) ;
$target
. lightbox ( option )
. one ( 'hide' , function ( )
{
$this . focus ( ) ;
} ) ;
} )
} ( window . jQuery ) ;
/ * !
* jQuery contextMenu v1 . 10.3 - Plugin for simple contextMenu handling
*
* Version : v1 . 10.3
*
* Authors : Björn Brala ( SWIS . nl ) , Rodney Rehm , Addy Osmani ( patches for FF )
* Web : http : //swisnl.github.io/jQuery-contextMenu/
*
* Copyright ( c ) 2011 - 2015 SWIS BV and contributors
*
* Licensed under
* MIT License http : //www.opensource.org/licenses/mit-license
* GPL v3 http : //opensource.org/licenses/GPL-3.0
*
* Date : 2015 - 12 - 03 T20 : 12 : 18.918 Z
* /
( function ( factory ) {
if ( typeof define === 'function' && define . amd ) {
// AMD. Register as anonymous module.
define ( [ 'jquery' ] , factory ) ;
} else if ( typeof exports === 'object' ) {
// Node / CommonJS
factory ( require ( 'jquery' ) ) ;
} else {
// Browser globals.
factory ( jQuery ) ;
}
} ) ( function ( $ ) {
'use strict' ;
// TODO: -
// ARIA stuff: menuitem, menuitemcheckbox und menuitemradio
// create <menu> structure if $.support[htmlCommand || htmlMenuitem] and !opt.disableNative
// determine html5 compatibility
$ . support . htmlMenuitem = ( 'HTMLMenuItemElement' in window ) ;
$ . support . htmlCommand = ( 'HTMLCommandElement' in window ) ;
$ . support . eventSelectstart = ( 'onselectstart' in document . documentElement ) ;
/* / / should the need arise , test for css user - select
$ . support . cssUserSelect = ( function ( ) {
var t = false ,
e = document . createElement ( 'div' ) ;
$ . each ( 'Moz|Webkit|Khtml|O|ms|Icab|' . split ( '|' ) , function ( i , prefix ) {
var propCC = prefix + ( prefix ? 'U' : 'u' ) + 'serSelect' ,
prop = ( prefix ? ( '-' + prefix . toLowerCase ( ) + '-' ) : '' ) + 'user-select' ;
e . style . cssText = prop + ': text;' ;
if ( e . style [ propCC ] == 'text' ) {
t = true ;
return false ;
}
return true ;
} ) ;
return t ;
} ) ( ) ;
* /
if ( ! $ . ui || ! $ . widget ) {
// duck punch $.cleanData like jQueryUI does to get that remove event
$ . cleanData = ( function ( orig ) {
return function ( elems ) {
var events , elem , i ;
for ( i = 0 ; ( elem = elems [ i ] ) != null ; i ++ ) {
try {
// Only trigger remove when necessary to save time
events = $ . _data ( elem , 'events' ) ;
if ( events && events . remove ) {
$ ( elem ) . triggerHandler ( 'remove' ) ;
}
// Http://bugs.jquery.com/ticket/8235
} catch ( e ) { }
}
orig ( elems ) ;
} ;
} ) ( $ . cleanData ) ;
}
var // currently active contextMenu trigger
$currentTrigger = null ,
// is contextMenu initialized with at least one menu?
initialized = false ,
// window handle
$win = $ ( window ) ,
// number of registered menus
counter = 0 ,
// mapping selector to namespace
namespaces = { } ,
// mapping namespace to options
menus = { } ,
// custom command type handlers
types = { } ,
// default values
defaults = {
// selector of contextMenu trigger
selector : null ,
// where to append the menu to
appendTo : null ,
// method to trigger context menu ["right", "left", "hover"]
trigger : 'right' ,
// hide menu when mouse leaves trigger / menu elements
autoHide : false ,
// ms to wait before showing a hover-triggered context menu
delay : 200 ,
// flag denoting if a second trigger should simply move (true) or rebuild (false) an open menu
// as long as the trigger happened on one of the trigger-element's child nodes
reposition : true ,
// Default classname configuration to be able avoid conflicts in frameworks
classNames : {
hover : 'hover' , // Item hover
disabled : 'disabled' , // Item disabled
visible : 'visible' , // Item visible
notSelectable : 'not-selectable' , // Item not selectable
icon : 'icon' ,
iconEdit : 'icon-edit' ,
iconCut : 'icon-cut' ,
iconCopy : 'icon-copy' ,
iconPaste : 'icon-paste' ,
iconDelete : 'icon-delete' ,
iconAdd : 'icon-add' ,
iconQuit : 'icon-quit'
} ,
// determine position to show menu at
determinePosition : function ( $menu ) {
// position to the lower middle of the trigger element
if ( $ . ui && $ . ui . position ) {
// .position() is provided as a jQuery UI utility
// (...and it won't work on hidden elements)
$menu . css ( 'display' , 'block' ) . position ( {
my : 'center top' ,
at : 'center bottom' ,
of : this ,
offset : '0 5' ,
collision : 'fit'
} ) . css ( 'display' , 'none' ) ;
} else {
// determine contextMenu position
var offset = this . offset ( ) ;
offset . top += this . outerHeight ( ) ;
offset . left += this . outerWidth ( ) / 2 - $menu . outerWidth ( ) / 2 ;
$menu . css ( offset ) ;
}
} ,
// position menu
position : function ( opt , x , y ) {
var offset ;
// determine contextMenu position
if ( ! x && ! y ) {
opt . determinePosition . call ( this , opt . $menu ) ;
return ;
} else if ( x === 'maintain' && y === 'maintain' ) {
// x and y must not be changed (after re-show on command click)
offset = opt . $menu . position ( ) ;
} else {
// x and y are given (by mouse event)
offset = { top : y , left : x } ;
}
// correct offset if viewport demands it
var bottom = $win . scrollTop ( ) + $win . height ( ) ,
right = $win . scrollLeft ( ) + $win . width ( ) ,
height = opt . $menu . outerHeight ( ) ,
width = opt . $menu . outerWidth ( ) ;
if ( offset . top + height > bottom ) {
offset . top -= height ;
}
if ( offset . top < 0 ) {
offset . top = 0 ;
}
if ( offset . left + width > right ) {
offset . left -= width ;
}
if ( offset . left < 0 ) {
offset . left = 0 ;
}
opt . $menu . css ( offset ) ;
} ,
// position the sub-menu
positionSubmenu : function ( $menu ) {
if ( $ . ui && $ . ui . position ) {
// .position() is provided as a jQuery UI utility
// (...and it won't work on hidden elements)
$menu . css ( 'display' , 'block' ) . position ( {
my : 'left top' ,
at : 'right top' ,
of : this ,
collision : 'flipfit fit'
} ) . css ( 'display' , '' ) ;
} else {
// determine contextMenu position
var offset = {
top : 0 ,
left : this . outerWidth ( )
} ;
$menu . css ( offset ) ;
}
} ,
// offset to add to zIndex
zIndex : 1 ,
// show hide animation settings
animation : {
duration : 50 ,
show : 'slideDown' ,
hide : 'slideUp'
} ,
// events
events : {
show : $ . noop ,
hide : $ . noop
} ,
// default callback
callback : null ,
// list of contextMenu items
items : { }
} ,
// mouse position for hover activation
hoveract = {
timer : null ,
pageX : null ,
pageY : null
} ,
// determine zIndex
zindex = function ( $t ) {
var zin = 0 ,
$tt = $t ;
while ( true ) {
zin = Math . max ( zin , parseInt ( $tt . css ( 'z-index' ) , 10 ) || 0 ) ;
$tt = $tt . parent ( ) ;
if ( ! $tt || ! $tt . length || 'html body' . indexOf ( $tt . prop ( 'nodeName' ) . toLowerCase ( ) ) > - 1 ) {
break ;
}
}
return zin ;
} ,
// event handlers
handle = {
// abort anything
abortevent : function ( e ) {
e . preventDefault ( ) ;
e . stopImmediatePropagation ( ) ;
} ,
// contextmenu show dispatcher
contextmenu : function ( e ) {
var $this = $ ( this ) ;
// disable actual context-menu if we are using the right mouse button as the trigger
if ( e . data . trigger === 'right' ) {
e . preventDefault ( ) ;
e . stopImmediatePropagation ( ) ;
}
// abort native-triggered events unless we're triggering on right click
if ( ( e . data . trigger !== 'right' && e . data . trigger !== 'demand' ) && e . originalEvent ) {
return ;
}
// Let the current contextmenu decide if it should show or not based on its own trigger settings
if ( e . mouseButton !== undefined && e . data ) {
if ( ! ( e . data . trigger == 'left' && e . mouseButton === 0 ) && ! ( e . data . trigger == 'right' && e . mouseButton === 2 ) ) {
// Mouse click is not valid.
return ;
}
}
// abort event if menu is visible for this trigger
if ( $this . hasClass ( 'context-menu-active' ) ) {
return ;
}
if ( ! $this . hasClass ( 'context-menu-disabled' ) ) {
// theoretically need to fire a show event at <menu>
// http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus
// var evt = jQuery.Event("show", { data: data, pageX: e.pageX, pageY: e.pageY, relatedTarget: this });
// e.data.$menu.trigger(evt);
$currentTrigger = $this ;
if ( e . data . build ) {
var built = e . data . build ( $currentTrigger , e ) ;
// abort if build() returned false
if ( built === false ) {
return ;
}
// dynamically build menu on invocation
e . data = $ . extend ( true , { } , defaults , e . data , built || { } ) ;
// abort if there are no items to display
if ( ! e . data . items || $ . isEmptyObject ( e . data . items ) ) {
// Note: jQuery captures and ignores errors from event handlers
if ( window . console ) {
( console . error || console . log ) . call ( console , 'No items specified to show in contextMenu' ) ;
}
throw new Error ( 'No Items specified' ) ;
}
// backreference for custom command type creation
e . data . $trigger = $currentTrigger ;
op . create ( e . data ) ;
}
var showMenu = false ;
for ( var item in e . data . items ) {
if ( e . data . items . hasOwnProperty ( item ) ) {
var visible ;
if ( $ . isFunction ( e . data . items [ item ] . visible ) ) {
visible = e . data . items [ item ] . visible . call ( $ ( e . currentTarget ) , item , e . data ) ;
} else if ( typeof item . visible !== 'undefined' ) {
visible = e . data . items [ item ] . visible === true ;
} else {
visible = true ;
}
if ( visible ) {
showMenu = true ;
}
}
}
if ( showMenu ) {
// show menu
op . show . call ( $this , e . data , e . pageX , e . pageY ) ;
}
}
} ,
// contextMenu left-click trigger
click : function ( e ) {
e . preventDefault ( ) ;
e . stopImmediatePropagation ( ) ;
$ ( this ) . trigger ( $ . Event ( 'contextmenu' , { data : e . data , pageX : e . pageX , pageY : e . pageY } ) ) ;
} ,
// contextMenu right-click trigger
mousedown : function ( e ) {
// register mouse down
var $this = $ ( this ) ;
// hide any previous menus
if ( $currentTrigger && $currentTrigger . length && ! $currentTrigger . is ( $this ) ) {
$currentTrigger . data ( 'contextMenu' ) . $menu . trigger ( 'contextmenu:hide' ) ;
}
// activate on right click
if ( e . button === 2 ) {
$currentTrigger = $this . data ( 'contextMenuActive' , true ) ;
}
} ,
// contextMenu right-click trigger
mouseup : function ( e ) {
// show menu
var $this = $ ( this ) ;
if ( $this . data ( 'contextMenuActive' ) && $currentTrigger && $currentTrigger . length && $currentTrigger . is ( $this ) && ! $this . hasClass ( 'context-menu-disabled' ) ) {
e . preventDefault ( ) ;
e . stopImmediatePropagation ( ) ;
$currentTrigger = $this ;
$this . trigger ( $ . Event ( 'contextmenu' , { data : e . data , pageX : e . pageX , pageY : e . pageY } ) ) ;
}
$this . removeData ( 'contextMenuActive' ) ;
} ,
// contextMenu hover trigger
mouseenter : function ( e ) {
var $this = $ ( this ) ,
$related = $ ( e . relatedTarget ) ,
$document = $ ( document ) ;
// abort if we're coming from a menu
if ( $related . is ( '.context-menu-list' ) || $related . closest ( '.context-menu-list' ) . length ) {
return ;
}
// abort if a menu is shown
if ( $currentTrigger && $currentTrigger . length ) {
return ;
}
hoveract . pageX = e . pageX ;
hoveract . pageY = e . pageY ;
hoveract . data = e . data ;
$document . on ( 'mousemove.contextMenuShow' , handle . mousemove ) ;
hoveract . timer = setTimeout ( function ( ) {
hoveract . timer = null ;
$document . off ( 'mousemove.contextMenuShow' ) ;
$currentTrigger = $this ;
$this . trigger ( $ . Event ( 'contextmenu' , {
data : hoveract . data ,
pageX : hoveract . pageX ,
pageY : hoveract . pageY
} ) ) ;
} , e . data . delay ) ;
} ,
// contextMenu hover trigger
mousemove : function ( e ) {
hoveract . pageX = e . pageX ;
hoveract . pageY = e . pageY ;
} ,
// contextMenu hover trigger
mouseleave : function ( e ) {
// abort if we're leaving for a menu
var $related = $ ( e . relatedTarget ) ;
if ( $related . is ( '.context-menu-list' ) || $related . closest ( '.context-menu-list' ) . length ) {
return ;
}
try {
clearTimeout ( hoveract . timer ) ;
} catch ( e ) {
}
hoveract . timer = null ;
} ,
// click on layer to hide contextMenu
layerClick : function ( e ) {
var $this = $ ( this ) ,
root = $this . data ( 'contextMenuRoot' ) ,
button = e . button ,
x = e . pageX ,
y = e . pageY ,
target ,
offset ;
e . preventDefault ( ) ;
e . stopImmediatePropagation ( ) ;
setTimeout ( function ( ) {
var $window ;
var triggerAction = ( ( root . trigger === 'left' && button === 0 ) || ( root . trigger === 'right' && button === 2 ) ) ;
// find the element that would've been clicked, wasn't the layer in the way
if ( document . elementFromPoint && root . $layer ) {
root . $layer . hide ( ) ;
target = document . elementFromPoint ( x - $win . scrollLeft ( ) , y - $win . scrollTop ( ) ) ;
root . $layer . show ( ) ;
}
if ( root . reposition && triggerAction ) {
if ( document . elementFromPoint ) {
if ( root . $trigger . is ( target ) || root . $trigger . has ( target ) . length ) {
root . position . call ( root . $trigger , root , x , y ) ;
return ;
}
} else {
offset = root . $trigger . offset ( ) ;
$window = $ ( window ) ;
// while this looks kinda awful, it's the best way to avoid
// unnecessarily calculating any positions
offset . top += $window . scrollTop ( ) ;
if ( offset . top <= e . pageY ) {
offset . left += $window . scrollLeft ( ) ;
if ( offset . left <= e . pageX ) {
offset . bottom = offset . top + root . $trigger . outerHeight ( ) ;
if ( offset . bottom >= e . pageY ) {
offset . right = offset . left + root . $trigger . outerWidth ( ) ;
if ( offset . right >= e . pageX ) {
// reposition
root . position . call ( root . $trigger , root , x , y ) ;
return ;
}
}
}
}
}
}
if ( target && triggerAction ) {
root . $trigger . one ( 'contextmenu:hidden' , function ( ) {
$ ( target ) . contextMenu ( { x : x , y : y , button : button } ) ;
} ) ;
}
root . $menu . trigger ( 'contextmenu:hide' ) ;
} , 50 ) ;
} ,
// key handled :hover
keyStop : function ( e , opt ) {
if ( ! opt . isInput ) {
e . preventDefault ( ) ;
}
e . stopPropagation ( ) ;
} ,
key : function ( e ) {
var opt = { } ;
// Only get the data from $currentTrigger if it exists
if ( $currentTrigger ) {
opt = $currentTrigger . data ( 'contextMenu' ) || { } ;
}
switch ( e . keyCode ) {
case 9 :
case 38 : // up
handle . keyStop ( e , opt ) ;
// if keyCode is [38 (up)] or [9 (tab) with shift]
if ( opt . isInput ) {
if ( e . keyCode === 9 && e . shiftKey ) {
e . preventDefault ( ) ;
opt . $selected && opt . $selected . find ( 'input, textarea, select' ) . blur ( ) ;
opt . $menu . trigger ( 'prevcommand' ) ;
return ;
} else if ( e . keyCode === 38 && opt . $selected . find ( 'input, textarea, select' ) . prop ( 'type' ) === 'checkbox' ) {
// checkboxes don't capture this key
e . preventDefault ( ) ;
return ;
}
} else if ( e . keyCode !== 9 || e . shiftKey ) {
opt . $menu . trigger ( 'prevcommand' ) ;
return ;
}
// omitting break;
// case 9: // tab - reached through omitted break;
case 40 : // down
handle . keyStop ( e , opt ) ;
if ( opt . isInput ) {
if ( e . keyCode === 9 ) {
e . preventDefault ( ) ;
opt . $selected && opt . $selected . find ( 'input, textarea, select' ) . blur ( ) ;
opt . $menu . trigger ( 'nextcommand' ) ;
return ;
} else if ( e . keyCode === 40 && opt . $selected . find ( 'input, textarea, select' ) . prop ( 'type' ) === 'checkbox' ) {
// checkboxes don't capture this key
e . preventDefault ( ) ;
return ;
}
} else {
opt . $menu . trigger ( 'nextcommand' ) ;
return ;
}
break ;
case 37 : // left
handle . keyStop ( e , opt ) ;
if ( opt . isInput || ! opt . $selected || ! opt . $selected . length ) {
break ;
}
if ( ! opt . $selected . parent ( ) . hasClass ( 'context-menu-root' ) ) {
var $parent = opt . $selected . parent ( ) . parent ( ) ;
opt . $selected . trigger ( 'contextmenu:blur' ) ;
opt . $selected = $parent ;
return ;
}
break ;
case 39 : // right
handle . keyStop ( e , opt ) ;
if ( opt . isInput || ! opt . $selected || ! opt . $selected . length ) {
break ;
}
var itemdata = opt . $selected . data ( 'contextMenu' ) || { } ;
if ( itemdata . $menu && opt . $selected . hasClass ( 'context-menu-submenu' ) ) {
opt . $selected = null ;
itemdata . $selected = null ;
itemdata . $menu . trigger ( 'nextcommand' ) ;
return ;
}
break ;
case 35 : // end
case 36 : // home
if ( opt . $selected && opt . $selected . find ( 'input, textarea, select' ) . length ) {
return ;
} else {
( opt . $selected && opt . $selected . parent ( ) || opt . $menu )
. children ( ':not(.' + opt . classNames . disabled + ', .' + opt . classNames . notSelectable + ')' ) [ e . keyCode === 36 ? 'first' : 'last' ] ( )
. trigger ( 'contextmenu:focus' ) ;
e . preventDefault ( ) ;
return ;
}
break ;
case 13 : // enter
handle . keyStop ( e , opt ) ;
if ( opt . isInput ) {
if ( opt . $selected && ! opt . $selected . is ( 'textarea, select' ) ) {
e . preventDefault ( ) ;
return ;
}
break ;
}
if ( typeof opt . $selected !== 'undefined' && opt . $selected !== null ) {
opt . $selected . trigger ( 'mouseup' ) ;
}
return ;
case 32 : // space
case 33 : // page up
case 34 : // page down
// prevent browser from scrolling down while menu is visible
handle . keyStop ( e , opt ) ;
return ;
case 27 : // esc
handle . keyStop ( e , opt ) ;
opt . $menu . trigger ( 'contextmenu:hide' ) ;
return ;
default : // 0-9, a-z
var k = ( String . fromCharCode ( e . keyCode ) ) . toUpperCase ( ) ;
if ( opt . accesskeys && opt . accesskeys [ k ] ) {
// according to the specs accesskeys must be invoked immediately
opt . accesskeys [ k ] . $node . trigger ( opt . accesskeys [ k ] . $menu ? 'contextmenu:focus' : 'mouseup' ) ;
return ;
}
break ;
}
// pass event to selected item,
// stop propagation to avoid endless recursion
e . stopPropagation ( ) ;
if ( typeof opt . $selected !== 'undefined' && opt . $selected !== null ) {
opt . $selected . trigger ( e ) ;
}
} ,
// select previous possible command in menu
prevItem : function ( e ) {
e . stopPropagation ( ) ;
var opt = $ ( this ) . data ( 'contextMenu' ) || { } ;
var root = $ ( this ) . data ( 'contextMenuRoot' ) || { } ;
// obtain currently selected menu
if ( opt . $selected ) {
var $s = opt . $selected ;
opt = opt . $selected . parent ( ) . data ( 'contextMenu' ) || { } ;
opt . $selected = $s ;
}
var $children = opt . $menu . children ( ) ,
$prev = ! opt . $selected || ! opt . $selected . prev ( ) . length ? $children . last ( ) : opt . $selected . prev ( ) ,
$round = $prev ;
// skip disabled
while ( $prev . hasClass ( root . classNames . disabled ) || $prev . hasClass ( root . classNames . notSelectable ) ) {
if ( $prev . prev ( ) . length ) {
$prev = $prev . prev ( ) ;
} else {
$prev = $children . last ( ) ;
}
if ( $prev . is ( $round ) ) {
// break endless loop
return ;
}
}
// leave current
if ( opt . $selected ) {
handle . itemMouseleave . call ( opt . $selected . get ( 0 ) , e ) ;
}
// activate next
handle . itemMouseenter . call ( $prev . get ( 0 ) , e ) ;
// focus input
var $input = $prev . find ( 'input, textarea, select' ) ;
if ( $input . length ) {
$input . focus ( ) ;
}
} ,
// select next possible command in menu
nextItem : function ( e ) {
e . stopPropagation ( ) ;
var opt = $ ( this ) . data ( 'contextMenu' ) || { } ;
var root = $ ( this ) . data ( 'contextMenuRoot' ) || { } ;
// obtain currently selected menu
if ( opt . $selected ) {
var $s = opt . $selected ;
opt = opt . $selected . parent ( ) . data ( 'contextMenu' ) || { } ;
opt . $selected = $s ;
}
var $children = opt . $menu . children ( ) ,
$next = ! opt . $selected || ! opt . $selected . next ( ) . length ? $children . first ( ) : opt . $selected . next ( ) ,
$round = $next ;
// skip disabled
while ( $next . hasClass ( root . classNames . disabled ) || $next . hasClass ( root . classNames . notSelectable ) ) {
if ( $next . next ( ) . length ) {
$next = $next . next ( ) ;
} else {
$next = $children . first ( ) ;
}
if ( $next . is ( $round ) ) {
// break endless loop
return ;
}
}
// leave current
if ( opt . $selected ) {
handle . itemMouseleave . call ( opt . $selected . get ( 0 ) , e ) ;
}
// activate next
handle . itemMouseenter . call ( $next . get ( 0 ) , e ) ;
// focus input
var $input = $next . find ( 'input, textarea, select' ) ;
if ( $input . length ) {
$input . focus ( ) ;
}
} ,
// flag that we're inside an input so the key handler can act accordingly
focusInput : function ( ) {
var $this = $ ( this ) . closest ( '.context-menu-item' ) ,
data = $this . data ( ) ,
opt = data . contextMenu ,
root = data . contextMenuRoot ;
root . $selected = opt . $selected = $this ;
root . isInput = opt . isInput = true ;
} ,
// flag that we're inside an input so the key handler can act accordingly
blurInput : function ( ) {
var $this = $ ( this ) . closest ( '.context-menu-item' ) ,
data = $this . data ( ) ,
opt = data . contextMenu ,
root = data . contextMenuRoot ;
root . isInput = opt . isInput = false ;
} ,
// :hover on menu
menuMouseenter : function ( ) {
var root = $ ( this ) . data ( ) . contextMenuRoot ;
root . hovering = true ;
} ,
// :hover on menu
menuMouseleave : function ( e ) {
var root = $ ( this ) . data ( ) . contextMenuRoot ;
if ( root . $layer && root . $layer . is ( e . relatedTarget ) ) {
root . hovering = false ;
}
} ,
// :hover done manually so key handling is possible
itemMouseenter : function ( e ) {
var $this = $ ( this ) ,
data = $this . data ( ) ,
opt = data . contextMenu ,
root = data . contextMenuRoot ;
root . hovering = true ;
// abort if we're re-entering
if ( e && root . $layer && root . $layer . is ( e . relatedTarget ) ) {
e . preventDefault ( ) ;
e . stopImmediatePropagation ( ) ;
}
// make sure only one item is selected
( opt . $menu ? opt : root ) . $menu
. children ( '.hover' ) . trigger ( 'contextmenu:blur' ) ;
if ( $this . hasClass ( root . classNames . disabled ) || $this . hasClass ( root . classNames . notSelectable ) ) {
opt . $selected = null ;
return ;
}
$this . trigger ( 'contextmenu:focus' ) ;
} ,
// :hover done manually so key handling is possible
itemMouseleave : function ( e ) {
var $this = $ ( this ) ,
data = $this . data ( ) ,
opt = data . contextMenu ,
root = data . contextMenuRoot ;
if ( root !== opt && root . $layer && root . $layer . is ( e . relatedTarget ) ) {
if ( typeof root . $selected !== 'undefined' && root . $selected !== null ) {
root . $selected . trigger ( 'contextmenu:blur' ) ;
}
e . preventDefault ( ) ;
e . stopImmediatePropagation ( ) ;
root . $selected = opt . $selected = opt . $node ;
return ;
}
$this . trigger ( 'contextmenu:blur' ) ;
} ,
// contextMenu item click
itemClick : function ( e ) {
var $this = $ ( this ) ,
data = $this . data ( ) ,
opt = data . contextMenu ,
root = data . contextMenuRoot ,
key = data . contextMenuKey ,
callback ;
// abort if the key is unknown or disabled or is a menu
if ( ! opt . items [ key ] || $this . is ( '.' + root . classNames . disabled + ', .context-menu-submenu, .context-menu-separator, .' + root . classNames . notSelectable ) ) {
return ;
}
e . preventDefault ( ) ;
e . stopImmediatePropagation ( ) ;
if ( $ . isFunction ( root . callbacks [ key ] ) && Object . prototype . hasOwnProperty . call ( root . callbacks , key ) ) {
// item-specific callback
callback = root . callbacks [ key ] ;
} else if ( $ . isFunction ( root . callback ) ) {
// default callback
callback = root . callback ;
} else {
// no callback, no action
return ;
}
// hide menu if callback doesn't stop that
if ( callback . call ( root . $trigger , key , root ) !== false ) {
root . $menu . trigger ( 'contextmenu:hide' ) ;
} else if ( root . $menu . parent ( ) . length ) {
op . update . call ( root . $trigger , root ) ;
}
} ,
// ignore click events on input elements
inputClick : function ( e ) {
e . stopImmediatePropagation ( ) ;
} ,
// hide <menu>
hideMenu : function ( e , data ) {
var root = $ ( this ) . data ( 'contextMenuRoot' ) ;
op . hide . call ( root . $trigger , root , data && data . force ) ;
} ,
// focus <command>
focusItem : function ( e ) {
e . stopPropagation ( ) ;
var $this = $ ( this ) ,
data = $this . data ( ) ,
opt = data . contextMenu ,
root = data . contextMenuRoot ;
$this
. addClass ( [ root . classNames . hover , root . classNames . visible ] . join ( ' ' ) )
. siblings ( )
. removeClass ( root . classNames . visible )
. filter ( root . classNames . hover )
. trigger ( 'contextmenu:blur' ) ;
// remember selected
opt . $selected = root . $selected = $this ;
// position sub-menu - do after show so dumb $.ui.position can keep up
if ( opt . $node ) {
root . positionSubmenu . call ( opt . $node , opt . $menu ) ;
}
} ,
// blur <command>
blurItem : function ( e ) {
e . stopPropagation ( ) ;
var $this = $ ( this ) ,
data = $this . data ( ) ,
opt = data . contextMenu ,
root = data . contextMenuRoot ;
if ( opt . autoHide ) { // for tablets and touch screens this needs to remain
$this . removeClass ( root . classNames . visible ) ;
}
$this . removeClass ( root . classNames . hover ) ;
opt . $selected = null ;
}
} ,
// operations
op = {
show : function ( opt , x , y ) {
var $trigger = $ ( this ) ,
css = { } ;
// hide any open menus
$ ( '#context-menu-layer' ) . trigger ( 'mousedown' ) ;
// backreference for callbacks
opt . $trigger = $trigger ;
// show event
if ( opt . events . show . call ( $trigger , opt ) === false ) {
$currentTrigger = null ;
return ;
}
// create or update context menu
op . update . call ( $trigger , opt ) ;
// position menu
opt . position . call ( $trigger , opt , x , y ) ;
// make sure we're in front
if ( opt . zIndex ) {
css . zIndex = zindex ( $trigger ) + opt . zIndex ;
}
// add layer
op . layer . call ( opt . $menu , opt , css . zIndex ) ;
// adjust sub-menu zIndexes
opt . $menu . find ( 'ul' ) . css ( 'zIndex' , css . zIndex + 1 ) ;
// position and show context menu
opt . $menu . css ( css ) [ opt . animation . show ] ( opt . animation . duration , function ( ) {
$trigger . trigger ( 'contextmenu:visible' ) ;
} ) ;
// make options available and set state
$trigger
. data ( 'contextMenu' , opt )
. addClass ( 'context-menu-active' ) ;
// register key handler
$ ( document ) . off ( 'keydown.contextMenu' ) . on ( 'keydown.contextMenu' , handle . key ) ;
// register autoHide handler
if ( opt . autoHide ) {
// mouse position handler
$ ( document ) . on ( 'mousemove.contextMenuAutoHide' , function ( e ) {
// need to capture the offset on mousemove,
// since the page might've been scrolled since activation
var pos = $trigger . offset ( ) ;
pos . right = pos . left + $trigger . outerWidth ( ) ;
pos . bottom = pos . top + $trigger . outerHeight ( ) ;
if ( opt . $layer && ! opt . hovering && ( ! ( e . pageX >= pos . left && e . pageX <= pos . right ) || ! ( e . pageY >= pos . top && e . pageY <= pos . bottom ) ) ) {
// if mouse in menu...
opt . $menu . trigger ( 'contextmenu:hide' ) ;
}
} ) ;
}
} ,
hide : function ( opt , force ) {
var $trigger = $ ( this ) ;
if ( ! opt ) {
opt = $trigger . data ( 'contextMenu' ) || { } ;
}
// hide event
if ( ! force && opt . events && opt . events . hide . call ( $trigger , opt ) === false ) {
return ;
}
// remove options and revert state
$trigger
. removeData ( 'contextMenu' )
. removeClass ( 'context-menu-active' ) ;
if ( opt . $layer ) {
// keep layer for a bit so the contextmenu event can be aborted properly by opera
setTimeout ( ( function ( $layer ) {
return function ( ) {
$layer . remove ( ) ;
} ;
} ) ( opt . $layer ) , 10 ) ;
try {
delete opt . $layer ;
} catch ( e ) {
opt . $layer = null ;
}
}
// remove handle
$currentTrigger = null ;
// remove selected
opt . $menu . find ( '.' + opt . classNames . hover ) . trigger ( 'contextmenu:blur' ) ;
opt . $selected = null ;
// unregister key and mouse handlers
// $(document).off('.contextMenuAutoHide keydown.contextMenu'); // http://bugs.jquery.com/ticket/10705
$ ( document ) . off ( '.contextMenuAutoHide' ) . off ( 'keydown.contextMenu' ) ;
// hide menu
opt . $menu && opt . $menu [ opt . animation . hide ] ( opt . animation . duration , function ( ) {
// tear down dynamically built menu after animation is completed.
if ( opt . build ) {
opt . $menu . remove ( ) ;
$ . each ( opt , function ( key ) {
switch ( key ) {
case 'ns' :
case 'selector' :
case 'build' :
case 'trigger' :
return true ;
default :
opt [ key ] = undefined ;
try {
delete opt [ key ] ;
} catch ( e ) {
}
return true ;
}
} ) ;
}
setTimeout ( function ( ) {
$trigger . trigger ( 'contextmenu:hidden' ) ;
} , 10 ) ;
} ) ;
} ,
create : function ( opt , root ) {
if ( root === undefined ) {
root = opt ;
}
// create contextMenu
opt . $menu = $ ( '<ul class="context-menu-list"></ul>' ) . addClass ( opt . className || '' ) . data ( {
'contextMenu' : opt ,
'contextMenuRoot' : root
} ) ;
$ . each ( [ 'callbacks' , 'commands' , 'inputs' ] , function ( i , k ) {
opt [ k ] = { } ;
if ( ! root [ k ] ) {
root [ k ] = { } ;
}
} ) ;
root . accesskeys || ( root . accesskeys = { } ) ;
function createNameNode ( item ) {
var $name = $ ( '<span></span>' ) ;
if ( item . _accesskey ) {
if ( item . _beforeAccesskey ) {
$name . append ( document . createTextNode ( item . _beforeAccesskey ) ) ;
}
$ ( '<span></span>' )
. addClass ( 'context-menu-accesskey' )
. text ( item . _accesskey )
. appendTo ( $name ) ;
if ( item . _afterAccesskey ) {
$name . append ( document . createTextNode ( item . _afterAccesskey ) ) ;
}
} else {
$name . text ( item . name ) ;
}
return $name ;
}
// create contextMenu items
$ . each ( opt . items , function ( key , item ) {
var $t = $ ( '<li class="context-menu-item"></li>' ) . addClass ( item . className || '' ) ,
$label = null ,
$input = null ;
// iOS needs to see a click-event bound to an element to actually
// have the TouchEvents infrastructure trigger the click event
$t . on ( 'click' , $ . noop ) ;
// Make old school string seperator a real item so checks wont be
// akward later.
if ( typeof item === 'string' ) {
item = { type : 'cm_seperator' } ;
}
item . $node = $t . data ( {
'contextMenu' : opt ,
'contextMenuRoot' : root ,
'contextMenuKey' : key
} ) ;
// register accesskey
// NOTE: the accesskey attribute should be applicable to any element, but Safari5 and Chrome13 still can't do that
if ( typeof item . accesskey !== 'undefined' ) {
var aks = splitAccesskey ( item . accesskey ) ;
for ( var i = 0 , ak ; ak = aks [ i ] ; i ++ ) {
if ( ! root . accesskeys [ ak ] ) {
root . accesskeys [ ak ] = item ;
var matched = item . name . match ( new RegExp ( '^(.*?)(' + ak + ')(.*)$' , 'i' ) ) ;
if ( matched ) {
item . _beforeAccesskey = matched [ 1 ] ;
item . _accesskey = matched [ 2 ] ;
item . _afterAccesskey = matched [ 3 ] ;
}
break ;
}
}
}
if ( item . type && types [ item . type ] ) {
// run custom type handler
types [ item . type ] . call ( $t , item , opt , root ) ;
// register commands
$ . each ( [ opt , root ] , function ( i , k ) {
k . commands [ key ] = item ;
if ( $ . isFunction ( item . callback ) ) {
k . callbacks [ key ] = item . callback ;
}
} ) ;
} else {
// add label for input
if ( item . type === 'cm_seperator' ) {
$t . addClass ( 'context-menu-separator ' + root . classNames . notSelectable ) ;
} else if ( item . type === 'html' ) {
$t . addClass ( 'context-menu-html ' + root . classNames . notSelectable ) ;
} else if ( item . type ) {
$label = $ ( '<label></label>' ) . appendTo ( $t ) ;
createNameNode ( item ) . appendTo ( $label ) ;
$t . addClass ( 'context-menu-input' ) ;
opt . hasTypes = true ;
$ . each ( [ opt , root ] , function ( i , k ) {
k . commands [ key ] = item ;
k . inputs [ key ] = item ;
} ) ;
} else if ( item . items ) {
item . type = 'sub' ;
}
switch ( item . type ) {
case 'seperator' :
break ;
case 'text' :
$input = $ ( '<input type="text" value="1" name="" value="">' )
. attr ( 'name' , 'context-menu-input-' + key )
. val ( item . value || '' )
. appendTo ( $label ) ;
break ;
case 'textarea' :
$input = $ ( '<textarea name=""></textarea>' )
. attr ( 'name' , 'context-menu-input-' + key )
. val ( item . value || '' )
. appendTo ( $label ) ;
if ( item . height ) {
$input . height ( item . height ) ;
}
break ;
case 'checkbox' :
$input = $ ( '<input type="checkbox" value="1" name="" value="">' )
. attr ( 'name' , 'context-menu-input-' + key )
. val ( item . value || '' )
. prop ( 'checked' , ! ! item . selected )
. prependTo ( $label ) ;
break ;
case 'radio' :
$input = $ ( '<input type="radio" value="1" name="" value="">' )
. attr ( 'name' , 'context-menu-input-' + item . radio )
. val ( item . value || '' )
. prop ( 'checked' , ! ! item . selected )
. prependTo ( $label ) ;
break ;
case 'select' :
$input = $ ( '<select name="">' )
. attr ( 'name' , 'context-menu-input-' + key )
. appendTo ( $label ) ;
if ( item . options ) {
$ . each ( item . options , function ( value , text ) {
$ ( '<option></option>' ) . val ( value ) . text ( text ) . appendTo ( $input ) ;
} ) ;
$input . val ( item . selected ) ;
}
break ;
case 'sub' :
createNameNode ( item ) . appendTo ( $t ) ;
item . appendTo = item . $node ;
op . create ( item , root ) ;
$t . data ( 'contextMenu' , item ) . addClass ( 'context-menu-submenu' ) ;
item . callback = null ;
break ;
case 'html' :
$ ( item . html ) . appendTo ( $t ) ;
break ;
default :
$ . each ( [ opt , root ] , function ( i , k ) {
k . commands [ key ] = item ;
if ( $ . isFunction ( item . callback ) ) {
k . callbacks [ key ] = item . callback ;
}
} ) ;
createNameNode ( item ) . appendTo ( $t ) ;
break ;
}
// disable key listener in <input>
if ( item . type && item . type !== 'sub' && item . type !== 'html' && item . type !== 'cm_seperator' ) {
$input
. on ( 'focus' , handle . focusInput )
. on ( 'blur' , handle . blurInput ) ;
if ( item . events ) {
$input . on ( item . events , opt ) ;
}
}
// add icons
if ( item . icon ) {
if ( $ . isFunction ( item . icon ) ) {
item . _icon = item . icon . call ( this , this , $t , key , item ) ;
} else {
item . _icon = root . classNames . icon + ' ' + root . classNames . icon + '-' + item . icon ;
}
$t . addClass ( item . _icon ) ;
}
}
// cache contained elements
item . $input = $input ;
item . $label = $label ;
// attach item to menu
$t . appendTo ( opt . $menu ) ;
// Disable text selection
if ( ! opt . hasTypes && $ . support . eventSelectstart ) {
// browsers support user-select: none,
// IE has a special event for text-selection
// browsers supporting neither will not be preventing text-selection
$t . on ( 'selectstart.disableTextSelect' , handle . abortevent ) ;
}
} ) ;
// attach contextMenu to <body> (to bypass any possible overflow:hidden issues on parents of the trigger element)
if ( ! opt . $node ) {
opt . $menu . css ( 'display' , 'none' ) . addClass ( 'context-menu-root' ) ;
}
opt . $menu . appendTo ( opt . appendTo || document . body ) ;
} ,
resize : function ( $menu , nested ) {
// determine widths of submenus, as CSS won't grow them automatically
// position:absolute within position:absolute; min-width:100; max-width:200; results in width: 100;
// kinda sucks hard...
// determine width of absolutely positioned element
$menu . css ( { position : 'absolute' , display : 'block' } ) ;
// don't apply yet, because that would break nested elements' widths
$menu . data ( 'width' , Math . ceil ( $menu . width ( ) ) ) ;
// reset styles so they allow nested elements to grow/shrink naturally
$menu . css ( {
position : 'static' ,
minWidth : '0px' ,
maxWidth : '100000px'
} ) ;
// identify width of nested menus
$menu . find ( '> li > ul' ) . each ( function ( ) {
op . resize ( $ ( this ) , true ) ;
} ) ;
// reset and apply changes in the end because nested
// elements' widths wouldn't be calculatable otherwise
if ( ! nested ) {
$menu . find ( 'ul' ) . addBack ( ) . css ( {
position : '' ,
display : '' ,
minWidth : '' ,
maxWidth : ''
} ) . width ( function ( ) {
return $ ( this ) . data ( 'width' ) ;
} ) ;
}
} ,
update : function ( opt , root ) {
var $trigger = this ;
if ( root === undefined ) {
root = opt ;
op . resize ( opt . $menu ) ;
}
// re-check disabled for each item
opt . $menu . children ( ) . each ( function ( ) {
var $item = $ ( this ) ,
key = $item . data ( 'contextMenuKey' ) ,
item = opt . items [ key ] ,
disabled = ( $ . isFunction ( item . disabled ) && item . disabled . call ( $trigger , key , root ) ) || item . disabled === true ,
visible ;
if ( $ . isFunction ( item . visible ) ) {
visible = item . visible . call ( $trigger , key , root ) ;
} else if ( typeof item . visible !== 'undefined' ) {
visible = item . visible === true ;
} else {
visible = true ;
}
$item [ visible ? 'show' : 'hide' ] ( ) ;
// dis- / enable item
$item [ disabled ? 'addClass' : 'removeClass' ] ( root . classNames . disabled ) ;
if ( $ . isFunction ( item . icon ) ) {
$item . removeClass ( item . _icon ) ;
item . _icon = item . icon . call ( this , $trigger , $item , key , item ) ;
$item . addClass ( item . _icon ) ;
}
if ( item . type ) {
// dis- / enable input elements
$item . find ( 'input, select, textarea' ) . prop ( 'disabled' , disabled ) ;
// update input states
switch ( item . type ) {
case 'text' :
case 'textarea' :
item . $input . val ( item . value || '' ) ;
break ;
case 'checkbox' :
case 'radio' :
item . $input . val ( item . value || '' ) . prop ( 'checked' , ! ! item . selected ) ;
break ;
case 'select' :
item . $input . val ( item . selected || '' ) ;
break ;
}
}
if ( item . $menu ) {
// update sub-menu
op . update . call ( $trigger , item , root ) ;
}
} ) ;
} ,
layer : function ( opt , zIndex ) {
// add transparent layer for click area
// filter and background for Internet Explorer, Issue #23
var $layer = opt . $layer = $ ( '<div id="context-menu-layer" style="position:fixed; z-index:' + zIndex + '; top:0; left:0; opacity: 0; filter: alpha(opacity=0); background-color: #000;"></div>' )
. css ( { height : $win . height ( ) , width : $win . width ( ) , display : 'block' } )
. data ( 'contextMenuRoot' , opt )
. insertBefore ( this )
. on ( 'contextmenu' , handle . abortevent )
. on ( 'mousedown' , handle . layerClick ) ;
// IE6 doesn't know position:fixed;
if ( document . body . style . maxWidth === undefined ) { // IE6 doesn't support maxWidth
$layer . css ( {
'position' : 'absolute' ,
'height' : $ ( document ) . height ( )
} ) ;
}
return $layer ;
}
} ;
// split accesskey according to http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#assigned-access-key
function splitAccesskey ( val ) {
var t = val . split ( /\s+/ ) ,
keys = [ ] ;
for ( var i = 0 , k ; k = t [ i ] ; i ++ ) {
k = k . charAt ( 0 ) . toUpperCase ( ) ; // first character only
// theoretically non-accessible characters should be ignored, but different systems, different keyboard layouts, ... screw it.
// a map to look up already used access keys would be nice
keys . push ( k ) ;
}
return keys ;
}
// handle contextMenu triggers
$ . fn . contextMenu = function ( operation ) {
var $t = this , $o = operation ;
if ( this . length > 0 ) { // this is not a build on demand menu
if ( operation === undefined ) {
this . first ( ) . trigger ( 'contextmenu' ) ;
} else if ( operation . x !== undefined && operation . y !== undefined ) {
this . first ( ) . trigger ( $ . Event ( 'contextmenu' , { pageX : operation . x , pageY : operation . y , mouseButton : operation . button } ) ) ;
} else if ( operation === 'hide' ) {
var $menu = this . first ( ) . data ( 'contextMenu' ) ? this . first ( ) . data ( 'contextMenu' ) . $menu : null ;
$menu && $menu . trigger ( 'contextmenu:hide' ) ;
} else if ( operation === 'destroy' ) {
$ . contextMenu ( 'destroy' , { context : this } ) ;
} else if ( $ . isPlainObject ( operation ) ) {
operation . context = this ;
$ . contextMenu ( 'create' , operation ) ;
} else if ( operation ) {
this . removeClass ( 'context-menu-disabled' ) ;
} else if ( ! operation ) {
this . addClass ( 'context-menu-disabled' ) ;
}
} else {
$ . each ( menus , function ( ) {
if ( this . selector === $t . selector ) {
$o . data = this ;
$ . extend ( $o . data , { trigger : 'demand' } ) ;
}
} ) ;
handle . contextmenu . call ( $o . target , $o ) ;
}
return this ;
} ;
// manage contextMenu instances
$ . contextMenu = function ( operation , options ) {
if ( typeof operation !== 'string' ) {
options = operation ;
operation = 'create' ;
}
if ( typeof options === 'string' ) {
options = { selector : options } ;
} else if ( options === undefined ) {
options = { } ;
}
// merge with default options
var o = $ . extend ( true , { } , defaults , options || { } ) ;
var $document = $ ( document ) ;
var $context = $document ;
var _hasContext = false ;
if ( ! o . context || ! o . context . length ) {
o . context = document ;
} else {
// you never know what they throw at you...
$context = $ ( o . context ) . first ( ) ;
o . context = $context . get ( 0 ) ;
_hasContext = o . context !== document ;
}
switch ( operation ) {
case 'create' :
// no selector no joy
if ( ! o . selector ) {
throw new Error ( 'No selector specified' ) ;
}
// make sure internal classes are not bound to
if ( o . selector . match ( /.context-menu-(list|item|input)($|\s)/ ) ) {
throw new Error ( 'Cannot bind to selector "' + o . selector + '" as it contains a reserved className' ) ;
}
if ( ! o . build && ( ! o . items || $ . isEmptyObject ( o . items ) ) ) {
throw new Error ( 'No Items specified' ) ;
}
counter ++ ;
o . ns = '.contextMenu' + counter ;
if ( ! _hasContext ) {
namespaces [ o . selector ] = o . ns ;
}
menus [ o . ns ] = o ;
// default to right click
if ( ! o . trigger ) {
o . trigger = 'right' ;
}
if ( ! initialized ) {
// make sure item click is registered first
$document
. on ( {
'contextmenu:hide.contextMenu' : handle . hideMenu ,
'prevcommand.contextMenu' : handle . prevItem ,
'nextcommand.contextMenu' : handle . nextItem ,
'contextmenu.contextMenu' : handle . abortevent ,
'mouseenter.contextMenu' : handle . menuMouseenter ,
'mouseleave.contextMenu' : handle . menuMouseleave
} , '.context-menu-list' )
. on ( 'mouseup.contextMenu' , '.context-menu-input' , handle . inputClick )
. on ( {
'mouseup.contextMenu' : handle . itemClick ,
'contextmenu:focus.contextMenu' : handle . focusItem ,
'contextmenu:blur.contextMenu' : handle . blurItem ,
'contextmenu.contextMenu' : handle . abortevent ,
'mouseenter.contextMenu' : handle . itemMouseenter ,
'mouseleave.contextMenu' : handle . itemMouseleave
} , '.context-menu-item' ) ;
initialized = true ;
}
// engage native contextmenu event
$context
. on ( 'contextmenu' + o . ns , o . selector , o , handle . contextmenu ) ;
if ( _hasContext ) {
// add remove hook, just in case
$context . on ( 'remove' + o . ns , function ( ) {
$ ( this ) . contextMenu ( 'destroy' ) ;
} ) ;
}
switch ( o . trigger ) {
case 'hover' :
$context
. on ( 'mouseenter' + o . ns , o . selector , o , handle . mouseenter )
. on ( 'mouseleave' + o . ns , o . selector , o , handle . mouseleave ) ;
break ;
case 'left' :
$context . on ( 'click' + o . ns , o . selector , o , handle . click ) ;
break ;
/ *
default :
// http://www.quirksmode.org/dom/events/contextmenu.html
$document
. on ( 'mousedown' + o . ns , o . selector , o , handle . mousedown )
. on ( 'mouseup' + o . ns , o . selector , o , handle . mouseup ) ;
break ;
* /
}
// create menu
if ( ! o . build ) {
op . create ( o ) ;
}
break ;
case 'destroy' :
var $visibleMenu ;
if ( _hasContext ) {
// get proper options
var context = o . context ;
$ . each ( menus , function ( ns , o ) {
if ( o . context !== context ) {
return true ;
}
$visibleMenu = $ ( '.context-menu-list' ) . filter ( ':visible' ) ;
if ( $visibleMenu . length && $visibleMenu . data ( ) . contextMenuRoot . $trigger . is ( $ ( o . context ) . find ( o . selector ) ) ) {
$visibleMenu . trigger ( 'contextmenu:hide' , { force : true } ) ;
}
try {
if ( menus [ o . ns ] . $menu ) {
menus [ o . ns ] . $menu . remove ( ) ;
}
delete menus [ o . ns ] ;
} catch ( e ) {
menus [ o . ns ] = null ;
}
$ ( o . context ) . off ( o . ns ) ;
return true ;
} ) ;
} else if ( ! o . selector ) {
$document . off ( '.contextMenu .contextMenuAutoHide' ) ;
$ . each ( menus , function ( ns , o ) {
$ ( o . context ) . off ( o . ns ) ;
} ) ;
namespaces = { } ;
menus = { } ;
counter = 0 ;
initialized = false ;
$ ( '#context-menu-layer, .context-menu-list' ) . remove ( ) ;
} else if ( namespaces [ o . selector ] ) {
$visibleMenu = $ ( '.context-menu-list' ) . filter ( ':visible' ) ;
if ( $visibleMenu . length && $visibleMenu . data ( ) . contextMenuRoot . $trigger . is ( o . selector ) ) {
$visibleMenu . trigger ( 'contextmenu:hide' , { force : true } ) ;
}
try {
if ( menus [ namespaces [ o . selector ] ] . $menu ) {
menus [ namespaces [ o . selector ] ] . $menu . remove ( ) ;
}
delete menus [ namespaces [ o . selector ] ] ;
} catch ( e ) {
menus [ namespaces [ o . selector ] ] = null ;
}
$document . off ( namespaces [ o . selector ] ) ;
}
break ;
case 'html5' :
// if <command> or <menuitem> are not handled by the browser,
// or options was a bool true,
// initialize $.contextMenu for them
if ( ( ! $ . support . htmlCommand && ! $ . support . htmlMenuitem ) || ( typeof options === 'boolean' && options ) ) {
$ ( 'menu[type="context"]' ) . each ( function ( ) {
if ( this . id ) {
$ . contextMenu ( {
selector : '[contextmenu=' + this . id + ']' ,
items : $ . contextMenu . fromMenu ( this )
} ) ;
}
} ) . css ( 'display' , 'none' ) ;
}
break ;
default :
throw new Error ( 'Unknown operation "' + operation + '"' ) ;
}
return this ;
} ;
// import values into <input> commands
$ . contextMenu . setInputValues = function ( opt , data ) {
if ( data === undefined ) {
data = { } ;
}
$ . each ( opt . inputs , function ( key , item ) {
switch ( item . type ) {
case 'text' :
case 'textarea' :
item . value = data [ key ] || '' ;
break ;
case 'checkbox' :
item . selected = data [ key ] ? true : false ;
break ;
case 'radio' :
item . selected = ( data [ item . radio ] || '' ) === item . value ;
break ;
case 'select' :
item . selected = data [ key ] || '' ;
break ;
}
} ) ;
} ;
// export values from <input> commands
$ . contextMenu . getInputValues = function ( opt , data ) {
if ( data === undefined ) {
data = { } ;
}
$ . each ( opt . inputs , function ( key , item ) {
switch ( item . type ) {
case 'text' :
case 'textarea' :
case 'select' :
data [ key ] = item . $input . val ( ) ;
break ;
case 'checkbox' :
data [ key ] = item . $input . prop ( 'checked' ) ;
break ;
case 'radio' :
if ( item . $input . prop ( 'checked' ) ) {
data [ item . radio ] = item . value ;
}
break ;
}
} ) ;
return data ;
} ;
// find <label for="xyz">
function inputLabel ( node ) {
return ( node . id && $ ( 'label[for="' + node . id + '"]' ) . val ( ) ) || node . name ;
}
// convert <menu> to items object
function menuChildren ( items , $children , counter ) {
if ( ! counter ) {
counter = 0 ;
}
$children . each ( function ( ) {
var $node = $ ( this ) ,
node = this ,
nodeName = this . nodeName . toLowerCase ( ) ,
label ,
item ;
// extract <label><input>
if ( nodeName === 'label' && $node . find ( 'input, textarea, select' ) . length ) {
label = $node . text ( ) ;
$node = $node . children ( ) . first ( ) ;
node = $node . get ( 0 ) ;
nodeName = node . nodeName . toLowerCase ( ) ;
}
/ *
* < menu > accepts flow - content as children . that means < embed > , < canvas > and such are valid menu items .
* Not being the sadistic kind , $ . contextMenu only accepts :
* < command > , < menuitem > , < hr > , < span > , < p > < input [ text , radio , checkbox ] > , < textarea > , < select > and of course < menu > .
* Everything else will be imported as an html node , which is not interfaced with contextMenu .
* /
// http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#concept-command
switch ( nodeName ) {
// http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#the-menu-element
case 'menu' :
item = { name : $node . attr ( 'label' ) , items : { } } ;
counter = menuChildren ( item . items , $node . children ( ) , counter ) ;
break ;
// http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-a-element-to-define-a-command
case 'a' :
// http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-button-element-to-define-a-command
case 'button' :
item = {
name : $node . text ( ) ,
disabled : ! ! $node . attr ( 'disabled' ) ,
callback : ( function ( ) {
return function ( ) {
$node . click ( ) ;
} ;
} ) ( )
} ;
break ;
// http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-command-element-to-define-a-command
case 'menuitem' :
case 'command' :
switch ( $node . attr ( 'type' ) ) {
case undefined :
case 'command' :
case 'menuitem' :
item = {
name : $node . attr ( 'label' ) ,
disabled : ! ! $node . attr ( 'disabled' ) ,
icon : $node . attr ( 'icon' ) ,
callback : ( function ( ) {
return function ( ) {
$node . click ( ) ;
} ;
} ) ( )
} ;
break ;
case 'checkbox' :
item = {
type : 'checkbox' ,
disabled : ! ! $node . attr ( 'disabled' ) ,
name : $node . attr ( 'label' ) ,
selected : ! ! $node . attr ( 'checked' )
} ;
break ;
case 'radio' :
item = {
type : 'radio' ,
disabled : ! ! $node . attr ( 'disabled' ) ,
name : $node . attr ( 'label' ) ,
radio : $node . attr ( 'radiogroup' ) ,
value : $node . attr ( 'id' ) ,
selected : ! ! $node . attr ( 'checked' )
} ;
break ;
default :
item = undefined ;
}
break ;
case 'hr' :
item = '-------' ;
break ;
case 'input' :
switch ( $node . attr ( 'type' ) ) {
case 'text' :
item = {
type : 'text' ,
name : label || inputLabel ( node ) ,
disabled : ! ! $node . attr ( 'disabled' ) ,
value : $node . val ( )
} ;
break ;
case 'checkbox' :
item = {
type : 'checkbox' ,
name : label || inputLabel ( node ) ,
disabled : ! ! $node . attr ( 'disabled' ) ,
selected : ! ! $node . attr ( 'checked' )
} ;
break ;
case 'radio' :
item = {
type : 'radio' ,
name : label || inputLabel ( node ) ,
disabled : ! ! $node . attr ( 'disabled' ) ,
radio : ! ! $node . attr ( 'name' ) ,
value : $node . val ( ) ,
selected : ! ! $node . attr ( 'checked' )
} ;
break ;
default :
item = undefined ;
break ;
}
break ;
case 'select' :
item = {
type : 'select' ,
name : label || inputLabel ( node ) ,
disabled : ! ! $node . attr ( 'disabled' ) ,
selected : $node . val ( ) ,
options : { }
} ;
$node . children ( ) . each ( function ( ) {
item . options [ this . value ] = $ ( this ) . text ( ) ;
} ) ;
break ;
case 'textarea' :
item = {
type : 'textarea' ,
name : label || inputLabel ( node ) ,
disabled : ! ! $node . attr ( 'disabled' ) ,
value : $node . val ( )
} ;
break ;
case 'label' :
break ;
default :
item = { type : 'html' , html : $node . clone ( true ) } ;
break ;
}
if ( item ) {
counter ++ ;
items [ 'key' + counter ] = item ;
}
} ) ;
return counter ;
}
// convert html5 menu
$ . contextMenu . fromMenu = function ( element ) {
var $this = $ ( element ) ,
items = { } ;
menuChildren ( items , $this . children ( ) ) ;
return items ;
} ;
// make defaults accessible
$ . contextMenu . defaults = defaults ;
$ . contextMenu . types = types ;
// export internal functions - undocumented, for hacking only!
$ . contextMenu . handle = handle ;
$ . contextMenu . op = op ;
$ . contextMenu . menus = menus ;
} ) ;
var _extends = Object . assign || function ( target ) { for ( var i = 1 ; i < arguments . length ; i ++ ) { var source = arguments [ i ] ; for ( var key in source ) { if ( Object . prototype . hasOwnProperty . call ( source , key ) ) { target [ key ] = source [ key ] ; } } } return target ; } ;
var _typeof = typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ? function ( obj ) { return typeof obj ; } : function ( obj ) { return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ; } ;
( function ( global , factory ) {
( typeof exports === 'undefined' ? 'undefined' : _typeof ( exports ) ) === 'object' && typeof module !== 'undefined' ? module . exports = factory ( ) : typeof define === 'function' && define . amd ? define ( factory ) : global . LazyLoad = factory ( ) ;
} ) ( this , function ( ) {
'use strict' ;
var getInstanceSettings = function getInstanceSettings ( customSettings ) {
var defaultSettings = {
elements _selector : "img" ,
container : document ,
threshold : 300 ,
data _src : "src" ,
data _srcset : "srcset" ,
data _sizes : "sizes" ,
class _loading : "loading" ,
class _loaded : "loaded" ,
class _error : "error" ,
callback _load : null ,
callback _error : null ,
callback _set : null ,
callback _enter : null ,
to _webp : false
} ;
return _extends ( { } , defaultSettings , customSettings ) ;
} ;
var dataPrefix = "data-" ;
var processedDataName = "was-processed" ;
var processedDataValue = "true" ;
var getData = function getData ( element , attribute ) {
return element . getAttribute ( dataPrefix + attribute ) ;
} ;
var setData = function setData ( element , attribute , value ) {
return element . setAttribute ( dataPrefix + attribute , value ) ;
} ;
var setWasProcessed = function setWasProcessed ( element ) {
return setData ( element , processedDataName , processedDataValue ) ;
} ;
var getWasProcessed = function getWasProcessed ( element ) {
return getData ( element , processedDataName ) === processedDataValue ;
} ;
function purgeElements ( elements ) {
return elements . filter ( function ( element ) {
return ! getWasProcessed ( element ) ;
} ) ;
}
/* Creates instance and notifies it through the window element */
var createInstance = function createInstance ( classObj , options ) {
var event ;
var eventString = "LazyLoad::Initialized" ;
var instance = new classObj ( options ) ;
try {
// Works in modern browsers
event = new CustomEvent ( eventString , { detail : { instance : instance } } ) ;
} catch ( err ) {
// Works in Internet Explorer (all versions)
event = document . createEvent ( "CustomEvent" ) ;
event . initCustomEvent ( eventString , false , false , { instance : instance } ) ;
}
window . dispatchEvent ( event ) ;
} ;
/ * A u t o i n i t i a l i z a t i o n o f o n e o r m o r e i n s t a n c e s o f l a z y l o a d , d e p e n d i n g o n t h e
options passed in ( plain object or an array ) * /
function autoInitialize ( classObj , options ) {
if ( ! options ) {
return ;
}
if ( ! options . length ) {
// Plain object
createInstance ( classObj , options ) ;
} else {
// Array of objects
for ( var i = 0 , optionsItem ; optionsItem = options [ i ] ; i += 1 ) {
createInstance ( classObj , optionsItem ) ;
}
}
}
var runningOnBrowser = typeof window !== "undefined" ;
var isBot = runningOnBrowser && ! ( "onscroll" in window ) || /(gle|ing|ro)bot|crawl|spider/i . test ( navigator . userAgent ) ;
var supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window ;
var supportsClassList = runningOnBrowser && "classList" in document . createElement ( "p" ) ;
var detectWebP = function detectWebP ( ) {
if ( ! runningOnBrowser ) {
return false ;
}
var webPString = "image/webp" ;
var elem = document . createElement ( "canvas" ) ;
if ( elem . getContext && elem . getContext ( "2d" ) ) {
return elem . toDataURL ( webPString ) . indexOf ( "data:" + webPString ) === 0 ;
}
return false ;
} ;
var supportsWebP = detectWebP ( ) ;
var setSourcesInChildren = function setSourcesInChildren ( parentTag , attrName , dataAttrName , toWebP ) {
for ( var i = 0 , childTag ; childTag = parentTag . children [ i ] ; i += 1 ) {
if ( childTag . tagName === "SOURCE" ) {
var attrValue = getData ( childTag , dataAttrName ) ;
setAttributeIfNotNullOrEmpty ( childTag , attrName , attrValue , toWebP ) ;
}
}
} ;
var replaceExtToWebp = function replaceExtToWebp ( value , condition ) {
return condition ? value . replace ( /\.(jpe?g|png)/gi , ".webp" ) : value ;
} ;
var setAttributeIfNotNullOrEmpty = function setAttributeIfNotNullOrEmpty ( element , attrName , value , toWebP ) {
if ( ! value ) {
return ;
}
element . setAttribute ( attrName , replaceExtToWebp ( value , toWebP ) ) ;
} ;
var setSources = function setSources ( element , settings ) {
var sizesDataName = settings . data _sizes ,
srcsetDataName = settings . data _srcset ,
srcDataName = settings . data _src ;
var srcDataValue = getData ( element , srcDataName ) ;
var mustChangeToWebP = supportsWebP && settings . to _webp ;
switch ( element . tagName ) {
case "IMG" :
{
var parent = element . parentNode ;
if ( parent && parent . tagName === "PICTURE" ) {
setSourcesInChildren ( parent , "srcset" , srcsetDataName , mustChangeToWebP ) ;
}
var sizesDataValue = getData ( element , sizesDataName ) ;
setAttributeIfNotNullOrEmpty ( element , "sizes" , sizesDataValue ) ;
var srcsetDataValue = getData ( element , srcsetDataName ) ;
setAttributeIfNotNullOrEmpty ( element , "srcset" , srcsetDataValue , mustChangeToWebP ) ;
setAttributeIfNotNullOrEmpty ( element , "src" , srcDataValue , mustChangeToWebP ) ;
break ;
}
case "IFRAME" :
setAttributeIfNotNullOrEmpty ( element , "src" , srcDataValue ) ;
break ;
case "VIDEO" :
setSourcesInChildren ( element , "src" , srcDataName ) ;
setAttributeIfNotNullOrEmpty ( element , "src" , srcDataValue ) ;
break ;
default :
if ( srcDataValue ) {
var setValue = replaceExtToWebp ( srcDataValue , mustChangeToWebP ) ;
element . style . backgroundImage = 'url("' + setValue + '")' ;
}
}
} ;
var addClass = function addClass ( element , className ) {
if ( supportsClassList ) {
element . classList . add ( className ) ;
return ;
}
element . className += ( element . className ? " " : "" ) + className ;
} ;
var removeClass = function removeClass ( element , className ) {
if ( supportsClassList ) {
element . classList . remove ( className ) ;
return ;
}
element . className = element . className . replace ( new RegExp ( "(^|\\s+)" + className + "(\\s+|$)" ) , " " ) . replace ( /^\s+/ , "" ) . replace ( /\s+$/ , "" ) ;
} ;
var callCallback = function callCallback ( callback , argument ) {
if ( callback ) {
callback ( argument ) ;
}
} ;
var loadString = "load" ;
var errorString = "error" ;
var removeListeners = function removeListeners ( element , loadHandler , errorHandler ) {
element . removeEventListener ( loadString , loadHandler ) ;
element . removeEventListener ( errorString , errorHandler ) ;
} ;
var addOneShotListeners = function addOneShotListeners ( element , settings ) {
var onLoad = function onLoad ( event ) {
onEvent ( event , true , settings ) ;
removeListeners ( element , onLoad , onError ) ;
} ;
var onError = function onError ( event ) {
onEvent ( event , false , settings ) ;
removeListeners ( element , onLoad , onError ) ;
} ;
element . addEventListener ( loadString , onLoad ) ;
element . addEventListener ( errorString , onError ) ;
} ;
var onEvent = function onEvent ( event , success , settings ) {
var element = event . target ;
removeClass ( element , settings . class _loading ) ;
addClass ( element , success ? settings . class _loaded : settings . class _error ) ; // Setting loaded or error class
callCallback ( success ? settings . callback _load : settings . callback _error , element ) ;
} ;
function revealElement ( element , settings , force ) {
if ( ! force && getWasProcessed ( element ) ) {
return ; // element has already been processed and force wasn't true
}
callCallback ( settings . callback _enter , element ) ;
if ( [ "IMG" , "IFRAME" , "VIDEO" ] . indexOf ( element . tagName ) > - 1 ) {
addOneShotListeners ( element , settings ) ;
addClass ( element , settings . class _loading ) ;
}
setSources ( element , settings ) ;
setWasProcessed ( element ) ;
callCallback ( settings . callback _set , element ) ;
}
/ * e n t r y . i s I n t e r s e c t i n g n e e d s f a l l b a c k b e c a u s e i s n u l l o n s o m e v e r s i o n s o f M S E d g e , a n d
entry . intersectionRatio is not enough alone because it could be 0 on some intersecting elements * /
var isIntersecting = function isIntersecting ( element ) {
return element . isIntersecting || element . intersectionRatio > 0 ;
} ;
var getObserverSettings = function getObserverSettings ( settings ) {
return {
root : settings . container === document ? null : settings . container ,
rootMargin : settings . threshold + "px"
} ;
} ;
var LazyLoad = function LazyLoad ( customSettings , elements ) {
this . _settings = getInstanceSettings ( customSettings ) ;
this . _setObserver ( ) ;
this . update ( elements ) ;
} ;
LazyLoad . prototype = {
_setObserver : function _setObserver ( ) {
var _this = this ;
if ( ! supportsIntersectionObserver ) {
return ;
}
var revealIntersectingElements = function revealIntersectingElements ( entries ) {
entries . forEach ( function ( entry ) {
if ( isIntersecting ( entry ) ) {
var element = entry . target ;
_this . load ( element ) ;
_this . _observer . unobserve ( element ) ;
}
} ) ;
_this . _elements = purgeElements ( _this . _elements ) ;
} ;
this . _observer = new IntersectionObserver ( revealIntersectingElements , getObserverSettings ( this . _settings ) ) ;
} ,
loadAll : function loadAll ( ) {
var _this2 = this ;
this . _elements . forEach ( function ( element ) {
_this2 . load ( element ) ;
} ) ;
this . _elements = purgeElements ( this . _elements ) ;
} ,
update : function update ( elements ) {
var _this3 = this ;
var settings = this . _settings ;
var nodeSet = elements || settings . container . querySelectorAll ( settings . elements _selector ) ;
this . _elements = purgeElements ( Array . prototype . slice . call ( nodeSet ) ) ; // nodeset to array for IE compatibility
if ( isBot || ! this . _observer ) {
this . loadAll ( ) ;
return ;
}
this . _elements . forEach ( function ( element ) {
_this3 . _observer . observe ( element ) ;
} ) ;
} ,
destroy : function destroy ( ) {
var _this4 = this ;
if ( this . _observer ) {
purgeElements ( this . _elements ) . forEach ( function ( element ) {
_this4 . _observer . unobserve ( element ) ;
} ) ;
this . _observer = null ;
}
this . _elements = null ;
this . _settings = null ;
} ,
load : function load ( element , force ) {
revealElement ( element , this . _settings , force ) ;
}
} ;
/* Automatic instances creation if required (useful for async script loading) */
if ( runningOnBrowser ) {
autoInitialize ( LazyLoad , window . lazyLoadOptions ) ;
}
return LazyLoad ;
} ) ;
// jQuery Scrollstop Plugin v1.2.0
// https://github.com/ssorallen/jquery-scrollstop
( function ( factory ) {
// UMD[2] wrapper for jQuery plugins to work in AMD or in CommonJS.
//
// [2] https://github.com/umdjs/umd
if ( typeof define === 'function' && define . amd ) {
// AMD. Register as an anonymous module.
define ( [ 'jquery' ] , factory ) ;
} else if ( typeof exports === 'object' ) {
// Node/CommonJS
module . exports = factory ( require ( 'jquery' ) ) ;
} else {
// Browser globals
factory ( jQuery ) ;
}
} ( function ( $ ) {
// $.event.dispatch was undocumented and was deprecated in jQuery 1.7[1]. It
// was replaced by $.event.handle in jQuery 1.9.
//
// Use the first of the available functions to support jQuery <1.8.
//
// [1] https://github.com/jquery/jquery-migrate/blob/master/src/event.js#L25
var dispatch = $ . event . dispatch || $ . event . handle ;
var special = $ . event . special ,
uid1 = 'D' + ( + new Date ( ) ) ,
uid2 = 'D' + ( + new Date ( ) + 1 ) ;
special . scrollstart = {
setup : function ( data ) {
var _data = $ . extend ( {
latency : special . scrollstop . latency
} , data ) ;
var timer ,
handler = function ( evt ) {
var _self = this ,
_args = arguments ;
if ( timer ) {
clearTimeout ( timer ) ;
} else {
evt . type = 'scrollstart' ;
dispatch . apply ( _self , _args ) ;
}
timer = setTimeout ( function ( ) {
timer = null ;
} , _data . latency ) ;
} ;
$ ( this ) . bind ( 'scroll' , handler ) . data ( uid1 , handler ) ;
} ,
teardown : function ( ) {
$ ( this ) . unbind ( 'scroll' , $ ( this ) . data ( uid1 ) ) ;
}
} ;
special . scrollstop = {
latency : 250 ,
setup : function ( data ) {
var _data = $ . extend ( {
latency : special . scrollstop . latency
} , data ) ;
var timer ,
handler = function ( evt ) {
var _self = this ,
_args = arguments ;
if ( timer ) {
clearTimeout ( timer ) ;
}
timer = setTimeout ( function ( ) {
timer = null ;
evt . type = 'scrollstop' ;
dispatch . apply ( _self , _args ) ;
} , _data . latency ) ;
} ;
$ ( this ) . bind ( 'scroll' , handler ) . data ( uid2 , handler ) ;
} ,
teardown : function ( ) {
$ ( this ) . unbind ( 'scroll' , $ ( this ) . data ( uid2 ) ) ;
}
} ;
} ) ) ;
/ * *
* bootbox . js v3 . 3.0
*
* http : //bootboxjs.com/license.txt
* /
var bootbox = window . bootbox || ( function ( document , $ ) {
/*jshint scripturl:true sub:true */
var _locale = 'en' ,
_defaultLocale = 'en' ,
_animate = true ,
_backdrop = 'static' ,
_defaultHref = 'javascript:;' ,
_classes = '' ,
_btnClasses = { } ,
_icons = { } ,
/* last var should always be the public object we'll return */
that = { } ;
/ * *
* public API
* /
that . setLocale = function ( locale ) {
for ( var i in _locales ) {
if ( i == locale ) {
_locale = locale ;
return ;
}
}
throw new Error ( 'Invalid locale: ' + locale ) ;
} ;
that . addLocale = function ( locale , translations ) {
if ( typeof _locales [ locale ] === 'undefined' ) {
_locales [ locale ] = { } ;
}
for ( var str in translations ) {
_locales [ locale ] [ str ] = translations [ str ] ;
}
} ;
that . setIcons = function ( icons ) {
_icons = icons ;
if ( typeof _icons !== 'object' || _icons === null ) {
_icons = { } ;
}
} ;
that . setBtnClasses = function ( btnClasses ) {
_btnClasses = btnClasses ;
if ( typeof _btnClasses !== 'object' || _btnClasses === null ) {
_btnClasses = { } ;
}
} ;
that . alert = function ( /*str, label, cb*/ ) {
var str = "" ,
label = _translate ( 'OK' ) ,
cb = null ;
switch ( arguments . length ) {
case 1 :
// no callback, default button label
str = arguments [ 0 ] ;
break ;
case 2 :
// callback *or* custom button label dependent on type
str = arguments [ 0 ] ;
if ( typeof arguments [ 1 ] == 'function' ) {
cb = arguments [ 1 ] ;
} else {
label = arguments [ 1 ] ;
}
break ;
case 3 :
// callback and custom button label
str = arguments [ 0 ] ;
label = arguments [ 1 ] ;
cb = arguments [ 2 ] ;
break ;
default :
throw new Error ( "Incorrect number of arguments: expected 1-3" ) ;
}
return that . dialog ( str , {
// only button (ok)
"label" : label ,
"icon" : _icons . OK ,
"class" : _btnClasses . OK ,
"callback" : cb
} , {
// ensure that the escape key works; either invoking the user's
// callback or true to just close the dialog
"onEscape" : cb || true
} ) ;
} ;
that . confirm = function ( /*str, labelCancel, labelOk, cb*/ ) {
var str = "" ,
labelCancel = _translate ( 'CANCEL' ) ,
labelOk = _translate ( 'CONFIRM' ) ,
cb = null ;
switch ( arguments . length ) {
case 1 :
str = arguments [ 0 ] ;
break ;
case 2 :
str = arguments [ 0 ] ;
if ( typeof arguments [ 1 ] == 'function' ) {
cb = arguments [ 1 ] ;
} else {
labelCancel = arguments [ 1 ] ;
}
break ;
case 3 :
str = arguments [ 0 ] ;
labelCancel = arguments [ 1 ] ;
if ( typeof arguments [ 2 ] == 'function' ) {
cb = arguments [ 2 ] ;
} else {
labelOk = arguments [ 2 ] ;
}
break ;
case 4 :
str = arguments [ 0 ] ;
labelCancel = arguments [ 1 ] ;
labelOk = arguments [ 2 ] ;
cb = arguments [ 3 ] ;
break ;
default :
throw new Error ( "Incorrect number of arguments: expected 1-4" ) ;
}
var cancelCallback = function ( ) {
if ( typeof cb === 'function' ) {
return cb ( false ) ;
}
} ;
var confirmCallback = function ( ) {
if ( typeof cb === 'function' ) {
return cb ( true ) ;
}
} ;
return that . dialog ( str , [ {
// first button (cancel)
"label" : labelCancel ,
"icon" : _icons . CANCEL ,
"class" : _btnClasses . CANCEL ,
"callback" : cancelCallback
} , {
// second button (confirm)
"label" : labelOk ,
"icon" : _icons . CONFIRM ,
"class" : _btnClasses . CONFIRM ,
"callback" : confirmCallback
} ] , {
// escape key bindings
"onEscape" : cancelCallback
} ) ;
} ;
that . prompt = function ( /*str, labelCancel, labelOk, cb, defaultVal*/ ) {
var str = "" ,
labelCancel = _translate ( 'CANCEL' ) ,
labelOk = _translate ( 'CONFIRM' ) ,
cb = null ,
defaultVal = "" ;
switch ( arguments . length ) {
case 1 :
str = arguments [ 0 ] ;
break ;
case 2 :
str = arguments [ 0 ] ;
if ( typeof arguments [ 1 ] == 'function' ) {
cb = arguments [ 1 ] ;
} else {
labelCancel = arguments [ 1 ] ;
}
break ;
case 3 :
str = arguments [ 0 ] ;
labelCancel = arguments [ 1 ] ;
if ( typeof arguments [ 2 ] == 'function' ) {
cb = arguments [ 2 ] ;
} else {
labelOk = arguments [ 2 ] ;
}
break ;
case 4 :
str = arguments [ 0 ] ;
labelCancel = arguments [ 1 ] ;
labelOk = arguments [ 2 ] ;
cb = arguments [ 3 ] ;
break ;
case 5 :
str = arguments [ 0 ] ;
labelCancel = arguments [ 1 ] ;
labelOk = arguments [ 2 ] ;
cb = arguments [ 3 ] ;
defaultVal = arguments [ 4 ] ;
break ;
default :
throw new Error ( "Incorrect number of arguments: expected 1-5" ) ;
}
var header = str ;
// let's keep a reference to the form object for later
var form = $ ( "<form></form>" ) ;
form . append ( "<input class='input-block-level' autocomplete=off type=text value='" + defaultVal + "' />" ) ;
var cancelCallback = function ( ) {
if ( typeof cb === 'function' ) {
// yep, native prompts dismiss with null, whereas native
// confirms dismiss with false...
return cb ( null ) ;
}
} ;
var confirmCallback = function ( ) {
if ( typeof cb === 'function' ) {
return cb ( form . find ( "input[type=text]" ) . val ( ) ) ;
}
} ;
var div = that . dialog ( form , [ {
// first button (cancel)
"label" : labelCancel ,
"icon" : _icons . CANCEL ,
"class" : _btnClasses . CANCEL ,
"callback" : cancelCallback
} , {
// second button (confirm)
"label" : labelOk ,
"icon" : _icons . CONFIRM ,
"class" : _btnClasses . CONFIRM ,
"callback" : confirmCallback
} ] , {
// prompts need a few extra options
"header" : header ,
// explicitly tell dialog NOT to show the dialog...
"show" : false ,
"onEscape" : cancelCallback
} ) ;
// ... the reason the prompt needs to be hidden is because we need
// to bind our own "shown" handler, after creating the modal but
// before any show(n) events are triggered
// @see https://github.com/makeusabrew/bootbox/issues/69
div . on ( "shown" , function ( ) {
form . find ( "input[type=text]" ) . focus ( ) ;
// ensure that submitting the form (e.g. with the enter key)
// replicates the behaviour of a normal prompt()
form . on ( "submit" , function ( e ) {
e . preventDefault ( ) ;
div . find ( ".btn-primary" ) . click ( ) ;
} ) ;
} ) ;
div . modal ( "show" ) ;
return div ;
} ;
that . dialog = function ( str , handlers , options ) {
var buttons = "" ,
callbacks = [ ] ;
if ( ! options ) {
options = { } ;
}
// check for single object and convert to array if necessary
if ( typeof handlers === 'undefined' ) {
handlers = [ ] ;
} else if ( typeof handlers . length == 'undefined' ) {
handlers = [ handlers ] ;
}
var i = handlers . length ;
while ( i -- ) {
var label = null ,
href = null ,
_class = null ,
icon = '' ,
callback = null ;
if ( typeof handlers [ i ] [ 'label' ] == 'undefined' &&
typeof handlers [ i ] [ 'class' ] == 'undefined' &&
typeof handlers [ i ] [ 'callback' ] == 'undefined' ) {
// if we've got nothing we expect, check for condensed format
var propCount = 0 , // condensed will only match if this == 1
property = null ; // save the last property we found
// be nicer to count the properties without this, but don't think it's possible...
for ( var j in handlers [ i ] ) {
property = j ;
if ( ++ propCount > 1 ) {
// forget it, too many properties
break ;
}
}
if ( propCount == 1 && typeof handlers [ i ] [ j ] == 'function' ) {
// matches condensed format of label -> function
handlers [ i ] [ 'label' ] = property ;
handlers [ i ] [ 'callback' ] = handlers [ i ] [ j ] ;
}
}
if ( typeof handlers [ i ] [ 'callback' ] == 'function' ) {
callback = handlers [ i ] [ 'callback' ] ;
}
if ( handlers [ i ] [ 'class' ] ) {
_class = handlers [ i ] [ 'class' ] ;
} else if ( i == handlers . length - 1 && handlers . length <= 2 ) {
// always add a primary to the main option in a two-button dialog
_class = 'btn-primary' ;
}
if ( handlers [ i ] [ 'link' ] !== true ) {
_class = 'btn ' + _class ;
}
if ( handlers [ i ] [ 'label' ] ) {
label = handlers [ i ] [ 'label' ] ;
} else {
label = "Option " + ( i + 1 ) ;
}
if ( handlers [ i ] [ 'icon' ] ) {
icon = "<i class='" + handlers [ i ] [ 'icon' ] + "'></i> " ;
}
if ( handlers [ i ] [ 'href' ] ) {
href = handlers [ i ] [ 'href' ] ;
}
else {
href = _defaultHref ;
}
buttons = "<a data-handler='" + i + "' class='" + _class + "' href='" + href + "'>" + icon + "" + label + "</a>" + buttons ;
callbacks [ i ] = callback ;
}
// @see https://github.com/makeusabrew/bootbox/issues/46#issuecomment-8235302
// and https://github.com/twitter/bootstrap/issues/4474
// for an explanation of the inline overflow: hidden
// @see https://github.com/twitter/bootstrap/issues/4854
// for an explanation of tabIndex=-1
var parts = [ "<div class='bootbox modal' tabindex='-1' style='overflow:hidden;'>" ] ;
if ( options [ 'header' ] ) {
var closeButton = '' ;
if ( typeof options [ 'headerCloseButton' ] == 'undefined' || options [ 'headerCloseButton' ] ) {
closeButton = "<a href='" + _defaultHref + "' class='close'>×</a>" ;
}
parts . push ( "<div class='modal-header'>" + closeButton + "<h3>" + options [ 'header' ] + "</h3></div>" ) ;
}
// push an empty body into which we'll inject the proper content later
parts . push ( "<div class='modal-body'></div>" ) ;
if ( buttons ) {
parts . push ( "<div class='modal-footer'>" + buttons + "</div>" ) ;
}
parts . push ( "</div>" ) ;
var div = $ ( parts . join ( "\n" ) ) ;
// check whether we should fade in/out
var shouldFade = ( typeof options . animate === 'undefined' ) ? _animate : options . animate ;
if ( shouldFade ) {
div . addClass ( "fade" ) ;
}
var optionalClasses = ( typeof options . classes === 'undefined' ) ? _classes : options . classes ;
if ( optionalClasses ) {
div . addClass ( optionalClasses ) ;
}
// now we've built up the div properly we can inject the content whether it was a string or a jQuery object
div . find ( ".modal-body" ) . html ( str ) ;
function onCancel ( source ) {
// for now source is unused, but it will be in future
var hideModal = null ;
if ( typeof options . onEscape === 'function' ) {
// @see https://github.com/makeusabrew/bootbox/issues/91
hideModal = options . onEscape ( ) ;
}
if ( hideModal !== false ) {
div . modal ( 'hide' ) ;
}
}
// hook into the modal's keyup trigger to check for the escape key
div . on ( 'keyup.dismiss.modal' , function ( e ) {
// any truthy value passed to onEscape will dismiss the dialog
// as long as the onEscape function (if defined) doesn't prevent it
if ( e . which === 27 && options . onEscape ) {
onCancel ( 'escape' ) ;
}
} ) ;
// handle close buttons too
div . on ( 'click' , 'a.close' , function ( e ) {
e . preventDefault ( ) ;
onCancel ( 'close' ) ;
} ) ;
// well, *if* we have a primary - give the first dom element focus
div . on ( 'shown' , function ( ) {
div . find ( "a.btn-primary:first" ) . focus ( ) ;
} ) ;
div . on ( 'hidden' , function ( e ) {
// @see https://github.com/makeusabrew/bootbox/issues/115
// allow for the fact hidden events can propagate up from
// child elements like tooltips
if ( e . target === this ) {
div . remove ( ) ;
}
} ) ;
// wire up button handlers
div . on ( 'click' , '.modal-footer a' , function ( e ) {
var handler = $ ( this ) . data ( "handler" ) ,
cb = callbacks [ handler ] ,
hideModal = null ;
// sort of @see https://github.com/makeusabrew/bootbox/pull/68 - heavily adapted
// if we've got a custom href attribute, all bets are off
if ( typeof handler !== 'undefined' &&
typeof handlers [ handler ] [ 'href' ] !== 'undefined' ) {
return ;
}
e . preventDefault ( ) ;
if ( typeof cb === 'function' ) {
hideModal = cb ( e ) ;
}
// the only way hideModal *will* be false is if a callback exists and
// returns it as a value. in those situations, don't hide the dialog
// @see https://github.com/makeusabrew/bootbox/pull/25
if ( hideModal !== false ) {
div . modal ( "hide" ) ;
}
} ) ;
// stick the modal right at the bottom of the main body out of the way
$ ( "body" ) . append ( div ) ;
div . modal ( {
// unless explicitly overridden take whatever our default backdrop value is
backdrop : ( typeof options . backdrop === 'undefined' ) ? _backdrop : options . backdrop ,
// ignore bootstrap's keyboard options; we'll handle this ourselves (more fine-grained control)
keyboard : false ,
// @ see https://github.com/makeusabrew/bootbox/issues/69
// we *never* want the modal to be shown before we can bind stuff to it
// this method can also take a 'show' option, but we'll only use that
// later if we need to
show : false
} ) ;
// @see https://github.com/makeusabrew/bootbox/issues/64
// @see https://github.com/makeusabrew/bootbox/issues/60
// ...caused by...
// @see https://github.com/twitter/bootstrap/issues/4781
div . on ( "show" , function ( e ) {
$ ( document ) . off ( "focusin.modal" ) ;
} ) ;
if ( typeof options . show === 'undefined' || options . show === true ) {
div . modal ( "show" ) ;
}
return div ;
} ;
/ * *
* # modal is deprecated in v3 ; it can still be used but no guarantees are
* made - have never been truly convinced of its merit but perhaps just
* needs a tidyup and some TLC
* /
that . modal = function ( /*str, label, options*/ ) {
var str ;
var label ;
var options ;
var defaultOptions = {
"onEscape" : null ,
"keyboard" : true ,
"backdrop" : _backdrop
} ;
switch ( arguments . length ) {
case 1 :
str = arguments [ 0 ] ;
break ;
case 2 :
str = arguments [ 0 ] ;
if ( typeof arguments [ 1 ] == 'object' ) {
options = arguments [ 1 ] ;
} else {
label = arguments [ 1 ] ;
}
break ;
case 3 :
str = arguments [ 0 ] ;
label = arguments [ 1 ] ;
options = arguments [ 2 ] ;
break ;
default :
throw new Error ( "Incorrect number of arguments: expected 1-3" ) ;
}
defaultOptions [ 'header' ] = label ;
if ( typeof options == 'object' ) {
options = $ . extend ( defaultOptions , options ) ;
} else {
options = defaultOptions ;
}
return that . dialog ( str , [ ] , options ) ;
} ;
that . hideAll = function ( ) {
$ ( ".bootbox" ) . modal ( "hide" ) ;
} ;
that . animate = function ( animate ) {
_animate = animate ;
} ;
that . backdrop = function ( backdrop ) {
_backdrop = backdrop ;
} ;
that . classes = function ( classes ) {
_classes = classes ;
} ;
/ * *
* private API
* /
/ * *
* standard locales . Please add more according to ISO 639 - 1 standard . Multiple language variants are
* unlikely to be required . If this gets too large it can be split out into separate JS files .
* /
var _locales = {
'br' : {
OK : 'OK' ,
CANCEL : 'Cancelar' ,
CONFIRM : 'Sim'
} ,
'da' : {
OK : 'OK' ,
CANCEL : 'Annuller' ,
CONFIRM : 'Accepter'
} ,
'de' : {
OK : 'OK' ,
CANCEL : 'Abbrechen' ,
CONFIRM : 'Akzeptieren'
} ,
'en' : {
OK : 'OK' ,
CANCEL : 'Cancel' ,
CONFIRM : 'OK'
} ,
'es' : {
OK : 'OK' ,
CANCEL : 'Cancelar' ,
CONFIRM : 'Aceptar'
} ,
'fr' : {
OK : 'OK' ,
CANCEL : 'Annuler' ,
CONFIRM : 'D\'accord'
} ,
'it' : {
OK : 'OK' ,
CANCEL : 'Annulla' ,
CONFIRM : 'Conferma'
} ,
'nl' : {
OK : 'OK' ,
CANCEL : 'Annuleren' ,
CONFIRM : 'Accepteren'
} ,
'pl' : {
OK : 'OK' ,
CANCEL : 'Anuluj' ,
CONFIRM : 'Potwierdź'
} ,
'ru' : {
OK : 'OK' ,
CANCEL : 'Отмена' ,
CONFIRM : 'Применить'
} ,
'zh_CN' : {
OK : 'OK' ,
CANCEL : '取消' ,
CONFIRM : '确认'
} ,
'zh_TW' : {
OK : 'OK' ,
CANCEL : '取消' ,
CONFIRM : '確認'
}
} ;
function _translate ( str , locale ) {
// we assume if no target locale is probided then we should take it from current setting
if ( typeof locale === 'undefined' ) {
locale = _locale ;
}
if ( typeof _locales [ locale ] [ str ] === 'string' ) {
return _locales [ locale ] [ str ] ;
}
// if we couldn't find a lookup then try and fallback to a default translation
if ( locale != _defaultLocale ) {
return _translate ( str , _defaultLocale ) ;
}
// if we can't do anything then bail out with whatever string was passed in - last resort
return str ;
}
return that ;
} ( document , window . jQuery ) ) ;
// @see https://github.com/makeusabrew/bootbox/issues/71
window . bootbox = bootbox ;
/ * !
* @ fileOverview TouchSwipe - jQuery Plugin
* @ version 1.6 . 18
*
* @ author Matt Bryson http : //www.github.com/mattbryson
* @ see https : //github.com/mattbryson/TouchSwipe-Jquery-Plugin
* @ see http : //labs.rampinteractive.co.uk/touchSwipe/
* @ see http : //plugins.jquery.com/project/touchSwipe
* @ license
* Copyright ( c ) 2010 - 2015 Matt Bryson
* Dual licensed under the MIT or GPL Version 2 licenses .
*
* /
/ *
*
* Changelog
* $Date : 2010 - 12 - 12 ( Wed , 12 Dec 2010 ) $
* $version : 1.0 . 0
* $version : 1.0 . 1 - removed multibyte comments
*
* $Date : 2011 - 21 - 02 ( Mon , 21 Feb 2011 ) $
* $version : 1.1 . 0 - added allowPageScroll property to allow swiping and scrolling of page
* - changed handler signatures so one handler can be used for multiple events
* $Date : 2011 - 23 - 02 ( Wed , 23 Feb 2011 ) $
* $version : 1.2 . 0 - added click handler . This is fired if the user simply clicks and does not swipe . The event object and click target are passed to handler .
* - If you use the http : //code.google.com/p/jquery-ui-for-ipad-and-iphone/ plugin, you can also assign jQuery mouse events to children of a touchSwipe object.
* $version : 1.2 . 1 - removed console log !
*
* $version : 1.2 . 2 - Fixed bug where scope was not preserved in callback methods .
*
* $Date : 2011 - 28 - 04 ( Thurs , 28 April 2011 ) $
* $version : 1.2 . 4 - Changed licence terms to be MIT or GPL inline with jQuery . Added check for support of touch events to stop non compatible browsers erroring .
*
* $Date : 2011 - 27 - 09 ( Tues , 27 September 2011 ) $
* $version : 1.2 . 5 - Added support for testing swipes with mouse on desktop browser ( thanks to https : //github.com/joelhy)
*
* $Date : 2012 - 14 - 05 ( Mon , 14 May 2012 ) $
* $version : 1.2 . 6 - Added timeThreshold between start and end touch , so user can ignore slow swipes ( thanks to Mark Chase ) . Default is null , all swipes are detected
*
* $Date : 2012 - 05 - 06 ( Tues , 05 June 2012 ) $
* $version : 1.2 . 7 - Changed time threshold to have null default for backwards compatibility . Added duration param passed back in events , and refactored how time is handled .
*
* $Date : 2012 - 05 - 06 ( Tues , 05 June 2012 ) $
* $version : 1.2 . 8 - Added the possibility to return a value like null or false in the trigger callback . In that way we can control when the touch start / move should take effect or not ( simply by returning in some cases return null ; or return false ; ) This effects the ontouchstart / ontouchmove event .
*
* $Date : 2012 - 06 - 06 ( Wed , 06 June 2012 ) $
* $version : 1.3 . 0 - Refactored whole plugin to allow for methods to be executed , as well as exposed defaults for user override . Added 'enable' , 'disable' , and 'destroy' methods
*
* $Date : 2012 - 05 - 06 ( Fri , 05 June 2012 ) $
* $version : 1.3 . 1 - Bug fixes - bind ( ) with false as last argument is no longer supported in jQuery 1.6 , also , if you just click , the duration is now returned correctly .
*
* $Date : 2012 - 29 - 07 ( Sun , 29 July 2012 ) $
* $version : 1.3 . 2 - Added fallbackToMouseEvents option to NOT capture mouse events on non touch devices .
* - Added "all" fingers value to the fingers property , so any combination of fingers triggers the swipe , allowing event handlers to check the finger count
*
* $Date : 2012 - 09 - 08 ( Thurs , 9 Aug 2012 ) $
* $version : 1.3 . 3 - Code tidy prep for minefied version
*
* $Date : 2012 - 04 - 10 ( wed , 4 Oct 2012 ) $
* $version : 1.4 . 0 - Added pinch support , pinchIn and pinchOut
*
* $Date : 2012 - 11 - 10 ( Thurs , 11 Oct 2012 ) $
* $version : 1.5 . 0 - Added excludedElements , a jquery selector that specifies child elements that do NOT trigger swipes . By default , this is . noSwipe
*
* $Date : 2012 - 22 - 10 ( Mon , 22 Oct 2012 ) $
* $version : 1.5 . 1 - Fixed bug with jQuery 1.8 and trailing comma in excludedElements
* - Fixed bug with IE and eventPreventDefault ( )
* $Date : 2013 - 01 - 12 ( Fri , 12 Jan 2013 ) $
* $version : 1.6 . 0 - Fixed bugs with pinching , mainly when both pinch and swipe enabled , as well as adding time threshold for multifinger gestures , so releasing one finger beofre the other doesnt trigger as single finger gesture .
* - made the demo site all static local HTML pages so they can be run locally by a developer
* - added jsDoc comments and added documentation for the plugin
* - code tidy
* - added triggerOnTouchLeave property that will end the event when the user swipes off the element .
* $Date : 2013 - 03 - 23 ( Sat , 23 Mar 2013 ) $
* $version : 1.6 . 1 - Added support for ie8 touch events
* $version : 1.6 . 2 - Added support for events binding with on / off / bind in jQ for all callback names .
* - Deprecated the 'click' handler in favour of tap .
* - added cancelThreshold property
* - added option method to update init options at runtime
* $version 1.6 . 3 - added doubletap , longtap events and longTapThreshold , doubleTapThreshold property
*
* $Date : 2013 - 04 - 04 ( Thurs , 04 April 2013 ) $
* $version 1.6 . 4 - Fixed bug with cancelThreshold introduced in 1.6 . 3 , where swipe status no longer fired start event , and stopped once swiping back .
*
* $Date : 2013 - 08 - 24 ( Sat , 24 Aug 2013 ) $
* $version 1.6 . 5 - Merged a few pull requests fixing various bugs , added AMD support .
*
* $Date : 2014 - 06 - 04 ( Wed , 04 June 2014 ) $
* $version 1.6 . 6 - Merge of pull requests .
* - IE10 touch support
* - Only prevent default event handling on valid swipe
* - Separate license / changelog comment
* - Detect if the swipe is valid at the end of the touch event .
* - Pass fingerdata to event handlers .
* - Add 'hold' gesture
* - Be more tolerant about the tap distance
* - Typos and minor fixes
*
* $Date : 2015 - 22 - 01 ( Thurs , 22 Jan 2015 ) $
* $version 1.6 . 7 - Added patch from https : //github.com/mattbryson/TouchSwipe-Jquery-Plugin/issues/206 to fix memory leak
*
* $Date : 2015 - 2 - 2 ( Mon , 2 Feb 2015 ) $
* $version 1.6 . 8 - Added preventDefaultEvents option to proxy events regardless .
* - Fixed issue with swipe and pinch not triggering at the same time
*
* $Date : 2015 - 9 - 6 ( Tues , 9 June 2015 ) $
* $version 1.6 . 9 - Added PR from jdalton / hybrid to fix pointer events
* - Added scrolling demo
* - Added version property to plugin
*
* $Date : 2015 - 1 - 10 ( Wed , 1 October 2015 ) $
* $version 1.6 . 10 - Added PR from beatspace to fix tap events
* $version 1.6 . 11 - Added PRs from indri - indri ( Doc tidyup ) , kkirsche ( Bower tidy up ) , UziTech ( preventDefaultEvents fixes )
* - Allowed setting multiple options via . swipe ( "options" , options _hash ) and more simply . swipe ( options _hash ) or exisitng instances
* $version 1.6 . 12 - Fixed bug with multi finger releases above 2 not triggering events
*
* $Date : 2015 - 12 - 18 ( Fri , 18 December 2015 ) $
* $version 1.6 . 13 - Added PRs
* - Fixed # 267 allowPageScroll not working correctly
* $version 1.6 . 14 - Fixed # 220 / # 248 doubletap not firing with swipes , # 223 commonJS compatible
* $version 1.6 . 15 - More bug fixes
*
* $Date : 2016 - 04 - 29 ( Fri , 29 April 2016 ) $
* $version 1.6 . 16 - Swipes with 0 distance now allow default events to trigger . So tapping any form elements or A tags will allow default interaction , but swiping will trigger a swipe .
Removed the a , input , select etc from the excluded Children list as the 0 distance tap solves that issue .
* $Date : 2016 - 05 - 19 ( Fri , 29 April 2016 ) $
* $version 1.6 . 17 - Fixed context issue when calling instance methods via $ ( "selector" ) . swipe ( "method" ) ;
* $version 1.6 . 18 - now honors fallbackToMouseEvents = false for MS Pointer events when a Mouse is used .
* /
/ * *
* See ( http : //jquery.com/).
* @ name $
* @ class
* See the jQuery Library ( http : //jquery.com/) for full details. This just
* documents the function and classes that are added to jQuery by this plug - in .
* /
/ * *
* See ( http : //jquery.com/)
* @ name fn
* @ class
* See the jQuery Library ( http : //jquery.com/) for full details. This just
* documents the function and classes that are added to jQuery by this plug - in .
* @ memberOf $
* /
( function ( factory ) {
if ( typeof define === 'function' && define . amd && define . amd . jQuery ) {
// AMD. Register as anonymous module.
define ( [ 'jquery' ] , factory ) ;
} else if ( typeof module !== 'undefined' && module . exports ) {
// CommonJS Module
factory ( require ( "jquery" ) ) ;
} else {
// Browser globals.
factory ( jQuery ) ;
}
} ( function ( $ ) {
"use strict" ;
//Constants
var VERSION = "1.6.18" ,
LEFT = "left" ,
RIGHT = "right" ,
UP = "up" ,
DOWN = "down" ,
IN = "in" ,
OUT = "out" ,
NONE = "none" ,
AUTO = "auto" ,
SWIPE = "swipe" ,
PINCH = "pinch" ,
TAP = "tap" ,
DOUBLE _TAP = "doubletap" ,
LONG _TAP = "longtap" ,
HOLD = "hold" ,
HORIZONTAL = "horizontal" ,
VERTICAL = "vertical" ,
ALL _FINGERS = "all" ,
DOUBLE _TAP _THRESHOLD = 10 ,
PHASE _START = "start" ,
PHASE _MOVE = "move" ,
PHASE _END = "end" ,
PHASE _CANCEL = "cancel" ,
SUPPORTS _TOUCH = 'ontouchstart' in window ,
SUPPORTS _POINTER _IE10 = window . navigator . msPointerEnabled && ! window . navigator . pointerEnabled && ! SUPPORTS _TOUCH ,
SUPPORTS _POINTER = ( window . navigator . pointerEnabled || window . navigator . msPointerEnabled ) && ! SUPPORTS _TOUCH ,
PLUGIN _NS = 'TouchSwipe' ;
/ * *
* The default configuration , and available options to configure touch swipe with .
* You can set the default values by updating any of the properties prior to instantiation .
* @ name $ . fn . swipe . defaults
* @ namespace
* @ property { int } [ fingers = 1 ] The number of fingers to detect in a swipe . Any swipes that do not meet this requirement will NOT trigger swipe handlers .
* @ property { int } [ threshold = 75 ] The number of pixels that the user must move their finger by before it is considered a swipe .
* @ property { int } [ cancelThreshold = null ] The number of pixels that the user must move their finger back from the original swipe direction to cancel the gesture .
* @ property { int } [ pinchThreshold = 20 ] The number of pixels that the user must pinch their finger by before it is considered a pinch .
* @ property { int } [ maxTimeThreshold = null ] Time , in milliseconds , between touchStart and touchEnd must NOT exceed in order to be considered a swipe .
* @ property { int } [ fingerReleaseThreshold = 250 ] Time in milliseconds between releasing multiple fingers . If 2 fingers are down , and are released one after the other , if they are within this threshold , it counts as a simultaneous release .
* @ property { int } [ longTapThreshold = 500 ] Time in milliseconds between tap and release for a long tap
* @ property { int } [ doubleTapThreshold = 200 ] Time in milliseconds between 2 taps to count as a double tap
* @ property { function } [ swipe = null ] A handler to catch all swipes . See { @ link $ . fn . swipe # event : swipe }
* @ property { function } [ swipeLeft = null ] A handler that is triggered for "left" swipes . See { @ link $ . fn . swipe # event : swipeLeft }
* @ property { function } [ swipeRight = null ] A handler that is triggered for "right" swipes . See { @ link $ . fn . swipe # event : swipeRight }
* @ property { function } [ swipeUp = null ] A handler that is triggered for "up" swipes . See { @ link $ . fn . swipe # event : swipeUp }
* @ property { function } [ swipeDown = null ] A handler that is triggered for "down" swipes . See { @ link $ . fn . swipe # event : swipeDown }
* @ property { function } [ swipeStatus = null ] A handler triggered for every phase of the swipe . See { @ link $ . fn . swipe # event : swipeStatus }
* @ property { function } [ pinchIn = null ] A handler triggered for pinch in events . See { @ link $ . fn . swipe # event : pinchIn }
* @ property { function } [ pinchOut = null ] A handler triggered for pinch out events . See { @ link $ . fn . swipe # event : pinchOut }
* @ property { function } [ pinchStatus = null ] A handler triggered for every phase of a pinch . See { @ link $ . fn . swipe # event : pinchStatus }
* @ property { function } [ tap = null ] A handler triggered when a user just taps on the item , rather than swipes it . If they do not move , tap is triggered , if they do move , it is not .
* @ property { function } [ doubleTap = null ] A handler triggered when a user double taps on the item . The delay between taps can be set with the doubleTapThreshold property . See { @ link $ . fn . swipe . defaults # doubleTapThreshold }
* @ property { function } [ longTap = null ] A handler triggered when a user long taps on the item . The delay between start and end can be set with the longTapThreshold property . See { @ link $ . fn . swipe . defaults # longTapThreshold }
* @ property ( function ) [ hold = null ] A handler triggered when a user reaches longTapThreshold on the item . See { @ link $ . fn . swipe . defaults # longTapThreshold }
* @ property { boolean } [ triggerOnTouchEnd = true ] If true , the swipe events are triggered when the touch end event is received ( user releases finger ) . If false , it will be triggered on reaching the threshold , and then cancel the touch event automatically .
* @ property { boolean } [ triggerOnTouchLeave = false ] If true , then when the user leaves the swipe object , the swipe will end and trigger appropriate handlers .
* @ property { string | undefined } [ allowPageScroll = 'auto' ] How the browser handles page scrolls when the user is swiping on a touchSwipe object . See { @ link $ . fn . swipe . pageScroll } . < br / > < br / >
< code > "auto" < /code> : all undefined swipes will cause the page to scroll in that direction. <br/ >
< code > "none" < /code> : the page will not scroll when user swipes. <br/ >
< code > "horizontal" < /code> : will force page to scroll on horizontal swipes. <br/ >
< code > "vertical" < /code> : will force page to scroll on vertical swipes. <br/ >
* @ property { boolean } [ fallbackToMouseEvents = true ] If true mouse events are used when run on a non touch device , false will stop swipes being triggered by mouse events on non touch devices .
* @ property { string } [ excludedElements = ".noSwipe" ] A jquery selector that specifies child elements that do NOT trigger swipes . By default this excludes elements with the class . noSwipe .
* @ property { boolean } [ preventDefaultEvents = true ] by default default events are cancelled , so the page doesn ' t move . You can disable this so both native events fire as well as your handlers .
* /
var defaults = {
fingers : 1 ,
threshold : 75 ,
cancelThreshold : null ,
pinchThreshold : 20 ,
maxTimeThreshold : null ,
fingerReleaseThreshold : 250 ,
longTapThreshold : 500 ,
doubleTapThreshold : 200 ,
swipe : null ,
swipeLeft : null ,
swipeRight : null ,
swipeUp : null ,
swipeDown : null ,
swipeStatus : null ,
pinchIn : null ,
pinchOut : null ,
pinchStatus : null ,
click : null , //Deprecated since 1.6.2
tap : null ,
doubleTap : null ,
longTap : null ,
hold : null ,
triggerOnTouchEnd : true ,
triggerOnTouchLeave : false ,
allowPageScroll : "auto" ,
fallbackToMouseEvents : true ,
excludedElements : ".noSwipe" ,
preventDefaultEvents : true
} ;
/ * *
* Applies TouchSwipe behaviour to one or more jQuery objects .
* The TouchSwipe plugin can be instantiated via this method , or methods within
* TouchSwipe can be executed via this method as per jQuery plugin architecture .
* An existing plugin can have its options changed simply by re calling . swipe ( options )
* @ see TouchSwipe
* @ class
* @ param { Mixed } method If the current DOMNode is a TouchSwipe object , and < code > method < / c o d e > i s a T o u c h S w i p e m e t h o d , t h e n
* the < code > method < / c o d e > i s e x e c u t e d , a n d a n y f o l l o w i n g a r g u m e n t s a r e p a s s e d t o t h e T o u c h S w i p e m e t h o d .
* If < code > method < / c o d e > i s a n o b j e c t , t h e n t h e T o u c h S w i p e c l a s s i s i n s t a n t i a t e d o n t h e c u r r e n t D O M N o d e , p a s s i n g t h e
* configuration properties defined in the object . See TouchSwipe
*
* /
$ . fn . swipe = function ( method ) {
var $this = $ ( this ) ,
plugin = $this . data ( PLUGIN _NS ) ;
//Check if we are already instantiated and trying to execute a method
if ( plugin && typeof method === 'string' ) {
if ( plugin [ method ] ) {
return plugin [ method ] . apply ( plugin , Array . prototype . slice . call ( arguments , 1 ) ) ;
} else {
$ . error ( 'Method ' + method + ' does not exist on jQuery.swipe' ) ;
}
}
//Else update existing plugin with new options hash
else if ( plugin && typeof method === 'object' ) {
plugin [ 'option' ] . apply ( plugin , arguments ) ;
}
//Else not instantiated and trying to pass init object (or nothing)
else if ( ! plugin && ( typeof method === 'object' || ! method ) ) {
return init . apply ( this , arguments ) ;
}
return $this ;
} ;
/ * *
* The version of the plugin
* @ readonly
* /
$ . fn . swipe . version = VERSION ;
//Expose our defaults so a user could override the plugin defaults
$ . fn . swipe . defaults = defaults ;
/ * *
* The phases that a touch event goes through . The < code > phase < / c o d e > i s p a s s e d t o t h e e v e n t h a n d l e r s .
* These properties are read only , attempting to change them will not alter the values passed to the event handlers .
* @ namespace
* @ readonly
* @ property { string } PHASE _START Constant indicating the start phase of the touch event . Value is < code > "start" < / c o d e > .
* @ property { string } PHASE _MOVE Constant indicating the move phase of the touch event . Value is < code > "move" < / c o d e > .
* @ property { string } PHASE _END Constant indicating the end phase of the touch event . Value is < code > "end" < / c o d e > .
* @ property { string } PHASE _CANCEL Constant indicating the cancel phase of the touch event . Value is < code > "cancel" < / c o d e > .
* /
$ . fn . swipe . phases = {
PHASE _START : PHASE _START ,
PHASE _MOVE : PHASE _MOVE ,
PHASE _END : PHASE _END ,
PHASE _CANCEL : PHASE _CANCEL
} ;
/ * *
* The direction constants that are passed to the event handlers .
* These properties are read only , attempting to change them will not alter the values passed to the event handlers .
* @ namespace
* @ readonly
* @ property { string } LEFT Constant indicating the left direction . Value is < code > "left" < / c o d e > .
* @ property { string } RIGHT Constant indicating the right direction . Value is < code > "right" < / c o d e > .
* @ property { string } UP Constant indicating the up direction . Value is < code > "up" < / c o d e > .
* @ property { string } DOWN Constant indicating the down direction . Value is < code > "cancel" < / c o d e > .
* @ property { string } IN Constant indicating the in direction . Value is < code > "in" < / c o d e > .
* @ property { string } OUT Constant indicating the out direction . Value is < code > "out" < / c o d e > .
* /
$ . fn . swipe . directions = {
LEFT : LEFT ,
RIGHT : RIGHT ,
UP : UP ,
DOWN : DOWN ,
IN : IN ,
OUT : OUT
} ;
/ * *
* The page scroll constants that can be used to set the value of < code > allowPageScroll < / c o d e > o p t i o n
* These properties are read only
* @ namespace
* @ readonly
* @ see $ . fn . swipe . defaults # allowPageScroll
* @ property { string } NONE Constant indicating no page scrolling is allowed . Value is < code > "none" < / c o d e > .
* @ property { string } HORIZONTAL Constant indicating horizontal page scrolling is allowed . Value is < code > "horizontal" < / c o d e > .
* @ property { string } VERTICAL Constant indicating vertical page scrolling is allowed . Value is < code > "vertical" < / c o d e > .
* @ property { string } AUTO Constant indicating either horizontal or vertical will be allowed , depending on the swipe handlers registered . Value is < code > "auto" < / c o d e > .
* /
$ . fn . swipe . pageScroll = {
NONE : NONE ,
HORIZONTAL : HORIZONTAL ,
VERTICAL : VERTICAL ,
AUTO : AUTO
} ;
/ * *
* Constants representing the number of fingers used in a swipe . These are used to set both the value of < code > fingers < / c o d e > i n t h e
* options object , as well as the value of the < code > fingers < / c o d e > e v e n t p r o p e r t y .
* These properties are read only , attempting to change them will not alter the values passed to the event handlers .
* @ namespace
* @ readonly
* @ see $ . fn . swipe . defaults # fingers
* @ property { string } ONE Constant indicating 1 finger is to be detected / was detected . Value is < code > 1 < / c o d e > .
* @ property { string } TWO Constant indicating 2 fingers are to be detected / were detected . Value is < code > 2 < / c o d e > .
* @ property { string } THREE Constant indicating 3 finger are to be detected / were detected . Value is < code > 3 < / c o d e > .
* @ property { string } FOUR Constant indicating 4 finger are to be detected / were detected . Not all devices support this . Value is < code > 4 < / c o d e > .
* @ property { string } FIVE Constant indicating 5 finger are to be detected / were detected . Not all devices support this . Value is < code > 5 < / c o d e > .
* @ property { string } ALL Constant indicating any combination of finger are to be detected . Value is < code > "all" < / c o d e > .
* /
$ . fn . swipe . fingers = {
ONE : 1 ,
TWO : 2 ,
THREE : 3 ,
FOUR : 4 ,
FIVE : 5 ,
ALL : ALL _FINGERS
} ;
/ * *
* Initialise the plugin for each DOM element matched
* This creates a new instance of the main TouchSwipe class for each DOM element , and then
* saves a reference to that instance in the elements data property .
* @ internal
* /
function init ( options ) {
//Prep and extend the options
if ( options && ( options . allowPageScroll === undefined && ( options . swipe !== undefined || options . swipeStatus !== undefined ) ) ) {
options . allowPageScroll = NONE ;
}
//Check for deprecated options
//Ensure that any old click handlers are assigned to the new tap, unless we have a tap
if ( options . click !== undefined && options . tap === undefined ) {
options . tap = options . click ;
}
if ( ! options ) {
options = { } ;
}
//pass empty object so we dont modify the defaults
options = $ . extend ( { } , $ . fn . swipe . defaults , options ) ;
//For each element instantiate the plugin
return this . each ( function ( ) {
var $this = $ ( this ) ;
//Check we havent already initialised the plugin
var plugin = $this . data ( PLUGIN _NS ) ;
if ( ! plugin ) {
plugin = new TouchSwipe ( this , options ) ;
$this . data ( PLUGIN _NS , plugin ) ;
}
} ) ;
}
/ * *
* Main TouchSwipe Plugin Class .
* Do not use this to construct your TouchSwipe object , use the jQuery plugin method $ . fn . swipe ( ) ; { @ link $ . fn . swipe }
* @ private
* @ name TouchSwipe
* @ param { DOMNode } element The HTML DOM object to apply to plugin to
* @ param { Object } options The options to configure the plugin with . @ link { $ . fn . swipe . defaults }
* @ see $ . fh . swipe . defaults
* @ see $ . fh . swipe
* @ class
* /
function TouchSwipe ( element , options ) {
//take a local/instacne level copy of the options - should make it this.options really...
var options = $ . extend ( { } , options ) ;
var useTouchEvents = ( SUPPORTS _TOUCH || SUPPORTS _POINTER || ! options . fallbackToMouseEvents ) ,
START _EV = useTouchEvents ? ( SUPPORTS _POINTER ? ( SUPPORTS _POINTER _IE10 ? 'MSPointerDown' : 'pointerdown' ) : 'touchstart' ) : 'mousedown' ,
MOVE _EV = useTouchEvents ? ( SUPPORTS _POINTER ? ( SUPPORTS _POINTER _IE10 ? 'MSPointerMove' : 'pointermove' ) : 'touchmove' ) : 'mousemove' ,
END _EV = useTouchEvents ? ( SUPPORTS _POINTER ? ( SUPPORTS _POINTER _IE10 ? 'MSPointerUp' : 'pointerup' ) : 'touchend' ) : 'mouseup' ,
LEAVE _EV = useTouchEvents ? ( SUPPORTS _POINTER ? 'mouseleave' : null ) : 'mouseleave' , //we manually detect leave on touch devices, so null event here
CANCEL _EV = ( SUPPORTS _POINTER ? ( SUPPORTS _POINTER _IE10 ? 'MSPointerCancel' : 'pointercancel' ) : 'touchcancel' ) ;
//touch properties
var distance = 0 ,
direction = null ,
currentDirection = null ,
duration = 0 ,
startTouchesDistance = 0 ,
endTouchesDistance = 0 ,
pinchZoom = 1 ,
pinchDistance = 0 ,
pinchDirection = 0 ,
maximumsMap = null ;
//jQuery wrapped element for this instance
var $element = $ ( element ) ;
//Current phase of th touch cycle
var phase = "start" ;
// the current number of fingers being used.
var fingerCount = 0 ;
//track mouse points / delta
var fingerData = { } ;
//track times
var startTime = 0 ,
endTime = 0 ,
previousTouchEndTime = 0 ,
fingerCountAtRelease = 0 ,
doubleTapStartTime = 0 ;
//Timeouts
var singleTapTimeout = null ,
holdTimeout = null ;
// Add gestures to all swipable areas if supported
try {
$element . bind ( START _EV , touchStart ) ;
$element . bind ( CANCEL _EV , touchCancel ) ;
} catch ( e ) {
$ . error ( 'events not supported ' + START _EV + ',' + CANCEL _EV + ' on jQuery.swipe' ) ;
}
//
//Public methods
//
/ * *
* re - enables the swipe plugin with the previous configuration
* @ function
* @ name $ . fn . swipe # enable
* @ return { DOMNode } The Dom element that was registered with TouchSwipe
* @ example $ ( "#element" ) . swipe ( "enable" ) ;
* /
this . enable = function ( ) {
//Incase we are already enabled, clean up...
this . disable ( ) ;
$element . bind ( START _EV , touchStart ) ;
$element . bind ( CANCEL _EV , touchCancel ) ;
return $element ;
} ;
/ * *
* disables the swipe plugin
* @ function
* @ name $ . fn . swipe # disable
* @ return { DOMNode } The Dom element that is now registered with TouchSwipe
* @ example $ ( "#element" ) . swipe ( "disable" ) ;
* /
this . disable = function ( ) {
removeListeners ( ) ;
return $element ;
} ;
/ * *
* Destroy the swipe plugin completely . To use any swipe methods , you must re initialise the plugin .
* @ function
* @ name $ . fn . swipe # destroy
* @ example $ ( "#element" ) . swipe ( "destroy" ) ;
* /
this . destroy = function ( ) {
removeListeners ( ) ;
$element . data ( PLUGIN _NS , null ) ;
$element = null ;
} ;
/ * *
* Allows run time updating of the swipe configuration options .
* @ function
* @ name $ . fn . swipe # option
* @ param { String } property The option property to get or set , or a has of multiple options to set
* @ param { Object } [ value ] The value to set the property to
* @ return { Object } If only a property name is passed , then that property value is returned . If nothing is passed the current options hash is returned .
* @ example $ ( "#element" ) . swipe ( "option" , "threshold" ) ; // return the threshold
* @ example $ ( "#element" ) . swipe ( "option" , "threshold" , 100 ) ; // set the threshold after init
* @ example $ ( "#element" ) . swipe ( "option" , { threshold : 100 , fingers : 3 } ) ; // set multiple properties after init
* @ example $ ( "#element" ) . swipe ( { threshold : 100 , fingers : 3 } ) ; // set multiple properties after init - the "option" method is optional!
* @ example $ ( "#element" ) . swipe ( "option" ) ; // Return the current options hash
* @ see $ . fn . swipe . defaults
*
* /
this . option = function ( property , value ) {
if ( typeof property === 'object' ) {
options = $ . extend ( options , property ) ;
} else if ( options [ property ] !== undefined ) {
if ( value === undefined ) {
return options [ property ] ;
} else {
options [ property ] = value ;
}
} else if ( ! property ) {
return options ;
} else {
$ . error ( 'Option ' + property + ' does not exist on jQuery.swipe.options' ) ;
}
return null ;
}
//
// Private methods
//
//
// EVENTS
//
/ * *
* Event handler for a touch start event .
* Stops the default click event from triggering and stores where we touched
* @ inner
* @ param { object } jqEvent The normalised jQuery event object .
* /
function touchStart ( jqEvent ) {
//If we already in a touch event (a finger already in use) then ignore subsequent ones..
if ( getTouchInProgress ( ) ) {
return ;
}
//Check if this element matches any in the excluded elements selectors, or its parent is excluded, if so, DON'T swipe
if ( $ ( jqEvent . target ) . closest ( options . excludedElements , $element ) . length > 0 ) {
return ;
}
//As we use Jquery bind for events, we need to target the original event object
//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
var event = jqEvent . originalEvent ? jqEvent . originalEvent : jqEvent ;
//If we have a pointer event, whoes type is 'mouse' and we have said NO mouse events, then dont do anything.
if ( event . pointerType && event . pointerType == "mouse" && options . fallbackToMouseEvents == false ) {
return ;
} ;
var ret ,
touches = event . touches ,
evt = touches ? touches [ 0 ] : event ;
phase = PHASE _START ;
//If we support touches, get the finger count
if ( touches ) {
// get the total number of fingers touching the screen
fingerCount = touches . length ;
}
//Else this is the desktop, so stop the browser from dragging content
else if ( options . preventDefaultEvents !== false ) {
jqEvent . preventDefault ( ) ; //call this on jq event so we are cross browser
}
//clear vars..
distance = 0 ;
direction = null ;
currentDirection = null ;
pinchDirection = null ;
duration = 0 ;
startTouchesDistance = 0 ;
endTouchesDistance = 0 ;
pinchZoom = 1 ;
pinchDistance = 0 ;
maximumsMap = createMaximumsData ( ) ;
cancelMultiFingerRelease ( ) ;
//Create the default finger data
createFingerData ( 0 , evt ) ;
// check the number of fingers is what we are looking for, or we are capturing pinches
if ( ! touches || ( fingerCount === options . fingers || options . fingers === ALL _FINGERS ) || hasPinches ( ) ) {
// get the coordinates of the touch
startTime = getTimeStamp ( ) ;
if ( fingerCount == 2 ) {
//Keep track of the initial pinch distance, so we can calculate the diff later
//Store second finger data as start
createFingerData ( 1 , touches [ 1 ] ) ;
startTouchesDistance = endTouchesDistance = calculateTouchesDistance ( fingerData [ 0 ] . start , fingerData [ 1 ] . start ) ;
}
if ( options . swipeStatus || options . pinchStatus ) {
ret = triggerHandler ( event , phase ) ;
}
} else {
//A touch with more or less than the fingers we are looking for, so cancel
ret = false ;
}
//If we have a return value from the users handler, then return and cancel
if ( ret === false ) {
phase = PHASE _CANCEL ;
triggerHandler ( event , phase ) ;
return ret ;
} else {
if ( options . hold ) {
holdTimeout = setTimeout ( $ . proxy ( function ( ) {
//Trigger the event
$element . trigger ( 'hold' , [ event . target ] ) ;
//Fire the callback
if ( options . hold ) {
ret = options . hold . call ( $element , event , event . target ) ;
}
} , this ) , options . longTapThreshold ) ;
}
setTouchInProgress ( true ) ;
}
return null ;
} ;
/ * *
* Event handler for a touch move event .
* If we change fingers during move , then cancel the event
* @ inner
* @ param { object } jqEvent The normalised jQuery event object .
* /
function touchMove ( jqEvent ) {
//As we use Jquery bind for events, we need to target the original event object
//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
var event = jqEvent . originalEvent ? jqEvent . originalEvent : jqEvent ;
//If we are ending, cancelling, or within the threshold of 2 fingers being released, don't track anything..
if ( phase === PHASE _END || phase === PHASE _CANCEL || inMultiFingerRelease ( ) )
return ;
var ret ,
touches = event . touches ,
evt = touches ? touches [ 0 ] : event ;
//Update the finger data
var currentFinger = updateFingerData ( evt ) ;
endTime = getTimeStamp ( ) ;
if ( touches ) {
fingerCount = touches . length ;
}
if ( options . hold ) {
clearTimeout ( holdTimeout ) ;
}
phase = PHASE _MOVE ;
//If we have 2 fingers get Touches distance as well
if ( fingerCount == 2 ) {
//Keep track of the initial pinch distance, so we can calculate the diff later
//We do this here as well as the start event, in case they start with 1 finger, and the press 2 fingers
if ( startTouchesDistance == 0 ) {
//Create second finger if this is the first time...
createFingerData ( 1 , touches [ 1 ] ) ;
startTouchesDistance = endTouchesDistance = calculateTouchesDistance ( fingerData [ 0 ] . start , fingerData [ 1 ] . start ) ;
} else {
//Else just update the second finger
updateFingerData ( touches [ 1 ] ) ;
endTouchesDistance = calculateTouchesDistance ( fingerData [ 0 ] . end , fingerData [ 1 ] . end ) ;
pinchDirection = calculatePinchDirection ( fingerData [ 0 ] . end , fingerData [ 1 ] . end ) ;
}
pinchZoom = calculatePinchZoom ( startTouchesDistance , endTouchesDistance ) ;
pinchDistance = Math . abs ( startTouchesDistance - endTouchesDistance ) ;
}
if ( ( fingerCount === options . fingers || options . fingers === ALL _FINGERS ) || ! touches || hasPinches ( ) ) {
//The overall direction of the swipe. From start to now.
direction = calculateDirection ( currentFinger . start , currentFinger . end ) ;
//The immediate direction of the swipe, direction between the last movement and this one.
currentDirection = calculateDirection ( currentFinger . last , currentFinger . end ) ;
//Check if we need to prevent default event (page scroll / pinch zoom) or not
validateDefaultEvent ( jqEvent , currentDirection ) ;
//Distance and duration are all off the main finger
distance = calculateDistance ( currentFinger . start , currentFinger . end ) ;
duration = calculateDuration ( ) ;
//Cache the maximum distance we made in this direction
setMaxDistance ( direction , distance ) ;
//Trigger status handler
ret = triggerHandler ( event , phase ) ;
//If we trigger end events when threshold are met, or trigger events when touch leaves element
if ( ! options . triggerOnTouchEnd || options . triggerOnTouchLeave ) {
var inBounds = true ;
//If checking if we leave the element, run the bounds check (we can use touchleave as its not supported on webkit)
if ( options . triggerOnTouchLeave ) {
var bounds = getbounds ( this ) ;
inBounds = isInBounds ( currentFinger . end , bounds ) ;
}
//Trigger end handles as we swipe if thresholds met or if we have left the element if the user has asked to check these..
if ( ! options . triggerOnTouchEnd && inBounds ) {
phase = getNextPhase ( PHASE _MOVE ) ;
}
//We end if out of bounds here, so set current phase to END, and check if its modified
else if ( options . triggerOnTouchLeave && ! inBounds ) {
phase = getNextPhase ( PHASE _END ) ;
}
if ( phase == PHASE _CANCEL || phase == PHASE _END ) {
triggerHandler ( event , phase ) ;
}
}
} else {
phase = PHASE _CANCEL ;
triggerHandler ( event , phase ) ;
}
if ( ret === false ) {
phase = PHASE _CANCEL ;
triggerHandler ( event , phase ) ;
}
}
/ * *
* Event handler for a touch end event .
* Calculate the direction and trigger events
* @ inner
* @ param { object } jqEvent The normalised jQuery event object .
* /
function touchEnd ( jqEvent ) {
//As we use Jquery bind for events, we need to target the original event object
//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
var event = jqEvent . originalEvent ? jqEvent . originalEvent : jqEvent ,
touches = event . touches ;
//If we are still in a touch with the device wait a fraction and see if the other finger comes up
//if it does within the threshold, then we treat it as a multi release, not a single release and end the touch / swipe
if ( touches ) {
if ( touches . length && ! inMultiFingerRelease ( ) ) {
startMultiFingerRelease ( event ) ;
return true ;
} else if ( touches . length && inMultiFingerRelease ( ) ) {
return true ;
}
}
//If a previous finger has been released, check how long ago, if within the threshold, then assume it was a multifinger release.
//This is used to allow 2 fingers to release fractionally after each other, whilst maintaining the event as containing 2 fingers, not 1
if ( inMultiFingerRelease ( ) ) {
fingerCount = fingerCountAtRelease ;
}
//Set end of swipe
endTime = getTimeStamp ( ) ;
//Get duration incase move was never fired
duration = calculateDuration ( ) ;
//If we trigger handlers at end of swipe OR, we trigger during, but they didnt trigger and we are still in the move phase
if ( didSwipeBackToCancel ( ) || ! validateSwipeDistance ( ) ) {
phase = PHASE _CANCEL ;
triggerHandler ( event , phase ) ;
} else if ( options . triggerOnTouchEnd || ( options . triggerOnTouchEnd === false && phase === PHASE _MOVE ) ) {
//call this on jq event so we are cross browser
if ( options . preventDefaultEvents !== false && jqEvent . cancelable !== false ) {
jqEvent . preventDefault ( ) ;
}
phase = PHASE _END ;
triggerHandler ( event , phase ) ;
}
//Special cases - A tap should always fire on touch end regardless,
//So here we manually trigger the tap end handler by itself
//We dont run trigger handler as it will re-trigger events that may have fired already
else if ( ! options . triggerOnTouchEnd && hasTap ( ) ) {
//Trigger the pinch events...
phase = PHASE _END ;
triggerHandlerForGesture ( event , phase , TAP ) ;
} else if ( phase === PHASE _MOVE ) {
phase = PHASE _CANCEL ;
triggerHandler ( event , phase ) ;
}
setTouchInProgress ( false ) ;
return null ;
}
/ * *
* Event handler for a touch cancel event .
* Clears current vars
* @ inner
* /
function touchCancel ( ) {
// reset the variables back to default values
fingerCount = 0 ;
endTime = 0 ;
startTime = 0 ;
startTouchesDistance = 0 ;
endTouchesDistance = 0 ;
pinchZoom = 1 ;
//If we were in progress of tracking a possible multi touch end, then re set it.
cancelMultiFingerRelease ( ) ;
setTouchInProgress ( false ) ;
}
/ * *
* Event handler for a touch leave event .
* This is only triggered on desktops , in touch we work this out manually
* as the touchleave event is not supported in webkit
* @ inner
* /
function touchLeave ( jqEvent ) {
//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
var event = jqEvent . originalEvent ? jqEvent . originalEvent : jqEvent ;
//If we have the trigger on leave property set....
if ( options . triggerOnTouchLeave ) {
phase = getNextPhase ( PHASE _END ) ;
triggerHandler ( event , phase ) ;
}
}
/ * *
* Removes all listeners that were associated with the plugin
* @ inner
* /
function removeListeners ( ) {
$element . unbind ( START _EV , touchStart ) ;
$element . unbind ( CANCEL _EV , touchCancel ) ;
$element . unbind ( MOVE _EV , touchMove ) ;
$element . unbind ( END _EV , touchEnd ) ;
//we only have leave events on desktop, we manually calculate leave on touch as its not supported in webkit
if ( LEAVE _EV ) {
$element . unbind ( LEAVE _EV , touchLeave ) ;
}
setTouchInProgress ( false ) ;
}
/ * *
* Checks if the time and distance thresholds have been met , and if so then the appropriate handlers are fired .
* /
function getNextPhase ( currentPhase ) {
var nextPhase = currentPhase ;
// Ensure we have valid swipe (under time and over distance and check if we are out of bound...)
var validTime = validateSwipeTime ( ) ;
var validDistance = validateSwipeDistance ( ) ;
var didCancel = didSwipeBackToCancel ( ) ;
//If we have exceeded our time, then cancel
if ( ! validTime || didCancel ) {
nextPhase = PHASE _CANCEL ;
}
//Else if we are moving, and have reached distance then end
else if ( validDistance && currentPhase == PHASE _MOVE && ( ! options . triggerOnTouchEnd || options . triggerOnTouchLeave ) ) {
nextPhase = PHASE _END ;
}
//Else if we have ended by leaving and didn't reach distance, then cancel
else if ( ! validDistance && currentPhase == PHASE _END && options . triggerOnTouchLeave ) {
nextPhase = PHASE _CANCEL ;
}
return nextPhase ;
}
/ * *
* Trigger the relevant event handler
* The handlers are passed the original event , the element that was swiped , and in the case of the catch all handler , the direction that was swiped , "left" , "right" , "up" , or "down"
* @ param { object } event the original event object
* @ param { string } phase the phase of the swipe ( start , end cancel etc ) { @ link $ . fn . swipe . phases }
* @ inner
* /
function triggerHandler ( event , phase ) {
var ret ,
touches = event . touches ;
// SWIPE GESTURES
if ( didSwipe ( ) || hasSwipes ( ) ) {
ret = triggerHandlerForGesture ( event , phase , SWIPE ) ;
}
// PINCH GESTURES (if the above didn't cancel)
if ( ( didPinch ( ) || hasPinches ( ) ) && ret !== false ) {
ret = triggerHandlerForGesture ( event , phase , PINCH ) ;
}
// CLICK / TAP (if the above didn't cancel)
if ( didDoubleTap ( ) && ret !== false ) {
//Trigger the tap events...
ret = triggerHandlerForGesture ( event , phase , DOUBLE _TAP ) ;
}
// CLICK / TAP (if the above didn't cancel)
else if ( didLongTap ( ) && ret !== false ) {
//Trigger the tap events...
ret = triggerHandlerForGesture ( event , phase , LONG _TAP ) ;
}
// CLICK / TAP (if the above didn't cancel)
else if ( didTap ( ) && ret !== false ) {
//Trigger the tap event..
ret = triggerHandlerForGesture ( event , phase , TAP ) ;
}
// If we are cancelling the gesture, then manually trigger the reset handler
if ( phase === PHASE _CANCEL ) {
touchCancel ( event ) ;
}
// If we are ending the gesture, then manually trigger the reset handler IF all fingers are off
if ( phase === PHASE _END ) {
//If we support touch, then check that all fingers are off before we cancel
if ( touches ) {
if ( ! touches . length ) {
touchCancel ( event ) ;
}
} else {
touchCancel ( event ) ;
}
}
return ret ;
}
/ * *
* Trigger the relevant event handler
* The handlers are passed the original event , the element that was swiped , and in the case of the catch all handler , the direction that was swiped , "left" , "right" , "up" , or "down"
* @ param { object } event the original event object
* @ param { string } phase the phase of the swipe ( start , end cancel etc ) { @ link $ . fn . swipe . phases }
* @ param { string } gesture the gesture to trigger a handler for : PINCH or SWIPE { @ link $ . fn . swipe . gestures }
* @ return Boolean False , to indicate that the event should stop propagation , or void .
* @ inner
* /
function triggerHandlerForGesture ( event , phase , gesture ) {
var ret ;
//SWIPES....
if ( gesture == SWIPE ) {
//Trigger status every time..
$element . trigger ( 'swipeStatus' , [ phase , direction || null , distance || 0 , duration || 0 , fingerCount , fingerData , currentDirection ] ) ;
if ( options . swipeStatus ) {
ret = options . swipeStatus . call ( $element , event , phase , direction || null , distance || 0 , duration || 0 , fingerCount , fingerData , currentDirection ) ;
//If the status cancels, then dont run the subsequent event handlers..
if ( ret === false ) return false ;
}
if ( phase == PHASE _END && validateSwipe ( ) ) {
//Cancel any taps that were in progress...
clearTimeout ( singleTapTimeout ) ;
clearTimeout ( holdTimeout ) ;
$element . trigger ( 'swipe' , [ direction , distance , duration , fingerCount , fingerData , currentDirection ] ) ;
if ( options . swipe ) {
ret = options . swipe . call ( $element , event , direction , distance , duration , fingerCount , fingerData , currentDirection ) ;
//If the status cancels, then dont run the subsequent event handlers..
if ( ret === false ) return false ;
}
//trigger direction specific event handlers
switch ( direction ) {
case LEFT :
$element . trigger ( 'swipeLeft' , [ direction , distance , duration , fingerCount , fingerData , currentDirection ] ) ;
if ( options . swipeLeft ) {
ret = options . swipeLeft . call ( $element , event , direction , distance , duration , fingerCount , fingerData , currentDirection ) ;
}
break ;
case RIGHT :
$element . trigger ( 'swipeRight' , [ direction , distance , duration , fingerCount , fingerData , currentDirection ] ) ;
if ( options . swipeRight ) {
ret = options . swipeRight . call ( $element , event , direction , distance , duration , fingerCount , fingerData , currentDirection ) ;
}
break ;
case UP :
$element . trigger ( 'swipeUp' , [ direction , distance , duration , fingerCount , fingerData , currentDirection ] ) ;
if ( options . swipeUp ) {
ret = options . swipeUp . call ( $element , event , direction , distance , duration , fingerCount , fingerData , currentDirection ) ;
}
break ;
case DOWN :
$element . trigger ( 'swipeDown' , [ direction , distance , duration , fingerCount , fingerData , currentDirection ] ) ;
if ( options . swipeDown ) {
ret = options . swipeDown . call ( $element , event , direction , distance , duration , fingerCount , fingerData , currentDirection ) ;
}
break ;
}
}
}
//PINCHES....
if ( gesture == PINCH ) {
$element . trigger ( 'pinchStatus' , [ phase , pinchDirection || null , pinchDistance || 0 , duration || 0 , fingerCount , pinchZoom , fingerData ] ) ;
if ( options . pinchStatus ) {
ret = options . pinchStatus . call ( $element , event , phase , pinchDirection || null , pinchDistance || 0 , duration || 0 , fingerCount , pinchZoom , fingerData ) ;
//If the status cancels, then dont run the subsequent event handlers..
if ( ret === false ) return false ;
}
if ( phase == PHASE _END && validatePinch ( ) ) {
switch ( pinchDirection ) {
case IN :
$element . trigger ( 'pinchIn' , [ pinchDirection || null , pinchDistance || 0 , duration || 0 , fingerCount , pinchZoom , fingerData ] ) ;
if ( options . pinchIn ) {
ret = options . pinchIn . call ( $element , event , pinchDirection || null , pinchDistance || 0 , duration || 0 , fingerCount , pinchZoom , fingerData ) ;
}
break ;
case OUT :
$element . trigger ( 'pinchOut' , [ pinchDirection || null , pinchDistance || 0 , duration || 0 , fingerCount , pinchZoom , fingerData ] ) ;
if ( options . pinchOut ) {
ret = options . pinchOut . call ( $element , event , pinchDirection || null , pinchDistance || 0 , duration || 0 , fingerCount , pinchZoom , fingerData ) ;
}
break ;
}
}
}
if ( gesture == TAP ) {
if ( phase === PHASE _CANCEL || phase === PHASE _END ) {
clearTimeout ( singleTapTimeout ) ;
clearTimeout ( holdTimeout ) ;
//If we are also looking for doubelTaps, wait incase this is one...
if ( hasDoubleTap ( ) && ! inDoubleTap ( ) ) {
doubleTapStartTime = getTimeStamp ( ) ;
//Now wait for the double tap timeout, and trigger this single tap
//if its not cancelled by a double tap
singleTapTimeout = setTimeout ( $ . proxy ( function ( ) {
doubleTapStartTime = null ;
$element . trigger ( 'tap' , [ event . target ] ) ;
if ( options . tap ) {
ret = options . tap . call ( $element , event , event . target ) ;
}
} , this ) , options . doubleTapThreshold ) ;
} else {
doubleTapStartTime = null ;
$element . trigger ( 'tap' , [ event . target ] ) ;
if ( options . tap ) {
ret = options . tap . call ( $element , event , event . target ) ;
}
}
}
} else if ( gesture == DOUBLE _TAP ) {
if ( phase === PHASE _CANCEL || phase === PHASE _END ) {
clearTimeout ( singleTapTimeout ) ;
clearTimeout ( holdTimeout ) ;
doubleTapStartTime = null ;
$element . trigger ( 'doubletap' , [ event . target ] ) ;
if ( options . doubleTap ) {
ret = options . doubleTap . call ( $element , event , event . target ) ;
}
}
} else if ( gesture == LONG _TAP ) {
if ( phase === PHASE _CANCEL || phase === PHASE _END ) {
clearTimeout ( singleTapTimeout ) ;
doubleTapStartTime = null ;
$element . trigger ( 'longtap' , [ event . target ] ) ;
if ( options . longTap ) {
ret = options . longTap . call ( $element , event , event . target ) ;
}
}
}
return ret ;
}
//
// GESTURE VALIDATION
//
/ * *
* Checks the user has swipe far enough
* @ return Boolean if < code > threshold < / c o d e > h a s b e e n s e t , r e t u r n t r u e i f t h e t h r e s h o l d w a s m e t , e l s e f a l s e .
* If no threshold was set , then we return true .
* @ inner
* /
function validateSwipeDistance ( ) {
var valid = true ;
//If we made it past the min swipe distance..
if ( options . threshold !== null ) {
valid = distance >= options . threshold ;
}
return valid ;
}
/ * *
* Checks the user has swiped back to cancel .
* @ return Boolean if < code > cancelThreshold < / c o d e > h a s b e e n s e t , r e t u r n t r u e i f t h e c a n c e l T h r e s h o l d w a s m e t , e l s e f a l s e .
* If no cancelThreshold was set , then we return true .
* @ inner
* /
function didSwipeBackToCancel ( ) {
var cancelled = false ;
if ( options . cancelThreshold !== null && direction !== null ) {
cancelled = ( getMaxDistance ( direction ) - distance ) >= options . cancelThreshold ;
}
return cancelled ;
}
/ * *
* Checks the user has pinched far enough
* @ return Boolean if < code > pinchThreshold < / c o d e > h a s b e e n s e t , r e t u r n t r u e i f t h e t h r e s h o l d w a s m e t , e l s e f a l s e .
* If no threshold was set , then we return true .
* @ inner
* /
function validatePinchDistance ( ) {
if ( options . pinchThreshold !== null ) {
return pinchDistance >= options . pinchThreshold ;
}
return true ;
}
/ * *
* Checks that the time taken to swipe meets the minimum / maximum requirements
* @ return Boolean
* @ inner
* /
function validateSwipeTime ( ) {
var result ;
//If no time set, then return true
if ( options . maxTimeThreshold ) {
if ( duration >= options . maxTimeThreshold ) {
result = false ;
} else {
result = true ;
}
} else {
result = true ;
}
return result ;
}
/ * *
* Checks direction of the swipe and the value allowPageScroll to see if we should allow or prevent the default behaviour from occurring .
* This will essentially allow page scrolling or not when the user is swiping on a touchSwipe object .
* @ param { object } jqEvent The normalised jQuery representation of the event object .
* @ param { string } direction The direction of the event . See { @ link $ . fn . swipe . directions }
* @ see $ . fn . swipe . directions
* @ inner
* /
function validateDefaultEvent ( jqEvent , direction ) {
//If the option is set, allways allow the event to bubble up (let user handle weirdness)
if ( options . preventDefaultEvents === false ) {
return ;
}
if ( options . allowPageScroll === NONE ) {
jqEvent . preventDefault ( ) ;
} else {
var auto = options . allowPageScroll === AUTO ;
switch ( direction ) {
case LEFT :
if ( ( options . swipeLeft && auto ) || ( ! auto && options . allowPageScroll != HORIZONTAL ) ) {
jqEvent . preventDefault ( ) ;
}
break ;
case RIGHT :
if ( ( options . swipeRight && auto ) || ( ! auto && options . allowPageScroll != HORIZONTAL ) ) {
jqEvent . preventDefault ( ) ;
}
break ;
case UP :
if ( ( options . swipeUp && auto ) || ( ! auto && options . allowPageScroll != VERTICAL ) ) {
jqEvent . preventDefault ( ) ;
}
break ;
case DOWN :
if ( ( options . swipeDown && auto ) || ( ! auto && options . allowPageScroll != VERTICAL ) ) {
jqEvent . preventDefault ( ) ;
}
break ;
case NONE :
break ;
}
}
}
// PINCHES
/ * *
* Returns true of the current pinch meets the thresholds
* @ return Boolean
* @ inner
* /
function validatePinch ( ) {
var hasCorrectFingerCount = validateFingers ( ) ;
var hasEndPoint = validateEndPoint ( ) ;
var hasCorrectDistance = validatePinchDistance ( ) ;
return hasCorrectFingerCount && hasEndPoint && hasCorrectDistance ;
}
/ * *
* Returns true if any Pinch events have been registered
* @ return Boolean
* @ inner
* /
function hasPinches ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( options . pinchStatus || options . pinchIn || options . pinchOut ) ;
}
/ * *
* Returns true if we are detecting pinches , and have one
* @ return Boolean
* @ inner
* /
function didPinch ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( validatePinch ( ) && hasPinches ( ) ) ;
}
// SWIPES
/ * *
* Returns true if the current swipe meets the thresholds
* @ return Boolean
* @ inner
* /
function validateSwipe ( ) {
//Check validity of swipe
var hasValidTime = validateSwipeTime ( ) ;
var hasValidDistance = validateSwipeDistance ( ) ;
var hasCorrectFingerCount = validateFingers ( ) ;
var hasEndPoint = validateEndPoint ( ) ;
var didCancel = didSwipeBackToCancel ( ) ;
// if the user swiped more than the minimum length, perform the appropriate action
// hasValidDistance is null when no distance is set
var valid = ! didCancel && hasEndPoint && hasCorrectFingerCount && hasValidDistance && hasValidTime ;
return valid ;
}
/ * *
* Returns true if any Swipe events have been registered
* @ return Boolean
* @ inner
* /
function hasSwipes ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( options . swipe || options . swipeStatus || options . swipeLeft || options . swipeRight || options . swipeUp || options . swipeDown ) ;
}
/ * *
* Returns true if we are detecting swipes and have one
* @ return Boolean
* @ inner
* /
function didSwipe ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( validateSwipe ( ) && hasSwipes ( ) ) ;
}
/ * *
* Returns true if we have matched the number of fingers we are looking for
* @ return Boolean
* @ inner
* /
function validateFingers ( ) {
//The number of fingers we want were matched, or on desktop we ignore
return ( ( fingerCount === options . fingers || options . fingers === ALL _FINGERS ) || ! SUPPORTS _TOUCH ) ;
}
/ * *
* Returns true if we have an end point for the swipe
* @ return Boolean
* @ inner
* /
function validateEndPoint ( ) {
//We have an end value for the finger
return fingerData [ 0 ] . end . x !== 0 ;
}
// TAP / CLICK
/ * *
* Returns true if a click / tap events have been registered
* @ return Boolean
* @ inner
* /
function hasTap ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( options . tap ) ;
}
/ * *
* Returns true if a double tap events have been registered
* @ return Boolean
* @ inner
* /
function hasDoubleTap ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( options . doubleTap ) ;
}
/ * *
* Returns true if any long tap events have been registered
* @ return Boolean
* @ inner
* /
function hasLongTap ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( options . longTap ) ;
}
/ * *
* Returns true if we could be in the process of a double tap ( one tap has occurred , we are listening for double taps , and the threshold hasn ' t past .
* @ return Boolean
* @ inner
* /
function validateDoubleTap ( ) {
if ( doubleTapStartTime == null ) {
return false ;
}
var now = getTimeStamp ( ) ;
return ( hasDoubleTap ( ) && ( ( now - doubleTapStartTime ) <= options . doubleTapThreshold ) ) ;
}
/ * *
* Returns true if we could be in the process of a double tap ( one tap has occurred , we are listening for double taps , and the threshold hasn ' t past .
* @ return Boolean
* @ inner
* /
function inDoubleTap ( ) {
return validateDoubleTap ( ) ;
}
/ * *
* Returns true if we have a valid tap
* @ return Boolean
* @ inner
* /
function validateTap ( ) {
return ( ( fingerCount === 1 || ! SUPPORTS _TOUCH ) && ( isNaN ( distance ) || distance < options . threshold ) ) ;
}
/ * *
* Returns true if we have a valid long tap
* @ return Boolean
* @ inner
* /
function validateLongTap ( ) {
//slight threshold on moving finger
return ( ( duration > options . longTapThreshold ) && ( distance < DOUBLE _TAP _THRESHOLD ) ) ;
}
/ * *
* Returns true if we are detecting taps and have one
* @ return Boolean
* @ inner
* /
function didTap ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( validateTap ( ) && hasTap ( ) ) ;
}
/ * *
* Returns true if we are detecting double taps and have one
* @ return Boolean
* @ inner
* /
function didDoubleTap ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( validateDoubleTap ( ) && hasDoubleTap ( ) ) ;
}
/ * *
* Returns true if we are detecting long taps and have one
* @ return Boolean
* @ inner
* /
function didLongTap ( ) {
//Enure we dont return 0 or null for false values
return ! ! ( validateLongTap ( ) && hasLongTap ( ) ) ;
}
// MULTI FINGER TOUCH
/ * *
* Starts tracking the time between 2 finger releases , and keeps track of how many fingers we initially had up
* @ inner
* /
function startMultiFingerRelease ( event ) {
previousTouchEndTime = getTimeStamp ( ) ;
fingerCountAtRelease = event . touches . length + 1 ;
}
/ * *
* Cancels the tracking of time between 2 finger releases , and resets counters
* @ inner
* /
function cancelMultiFingerRelease ( ) {
previousTouchEndTime = 0 ;
fingerCountAtRelease = 0 ;
}
/ * *
* Checks if we are in the threshold between 2 fingers being released
* @ return Boolean
* @ inner
* /
function inMultiFingerRelease ( ) {
var withinThreshold = false ;
if ( previousTouchEndTime ) {
var diff = getTimeStamp ( ) - previousTouchEndTime
if ( diff <= options . fingerReleaseThreshold ) {
withinThreshold = true ;
}
}
return withinThreshold ;
}
/ * *
* gets a data flag to indicate that a touch is in progress
* @ return Boolean
* @ inner
* /
function getTouchInProgress ( ) {
//strict equality to ensure only true and false are returned
return ! ! ( $element . data ( PLUGIN _NS + '_intouch' ) === true ) ;
}
/ * *
* Sets a data flag to indicate that a touch is in progress
* @ param { boolean } val The value to set the property to
* @ inner
* /
function setTouchInProgress ( val ) {
//If destroy is called in an event handler, we have no el, and we have already cleaned up, so return.
if ( ! $element ) { return ; }
//Add or remove event listeners depending on touch status
if ( val === true ) {
$element . bind ( MOVE _EV , touchMove ) ;
$element . bind ( END _EV , touchEnd ) ;
//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
if ( LEAVE _EV ) {
$element . bind ( LEAVE _EV , touchLeave ) ;
}
} else {
$element . unbind ( MOVE _EV , touchMove , false ) ;
$element . unbind ( END _EV , touchEnd , false ) ;
//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
if ( LEAVE _EV ) {
$element . unbind ( LEAVE _EV , touchLeave , false ) ;
}
}
//strict equality to ensure only true and false can update the value
$element . data ( PLUGIN _NS + '_intouch' , val === true ) ;
}
/ * *
* Creates the finger data for the touch / finger in the event object .
* @ param { int } id The id to store the finger data under ( usually the order the fingers were pressed )
* @ param { object } evt The event object containing finger data
* @ return finger data object
* @ inner
* /
function createFingerData ( id , evt ) {
var f = {
start : {
x : 0 ,
y : 0
} ,
last : {
x : 0 ,
y : 0
} ,
end : {
x : 0 ,
y : 0
}
} ;
f . start . x = f . last . x = f . end . x = evt . pageX || evt . clientX ;
f . start . y = f . last . y = f . end . y = evt . pageY || evt . clientY ;
fingerData [ id ] = f ;
return f ;
}
/ * *
* Updates the finger data for a particular event object
* @ param { object } evt The event object containing the touch / finger data to upadte
* @ return a finger data object .
* @ inner
* /
function updateFingerData ( evt ) {
var id = evt . identifier !== undefined ? evt . identifier : 0 ;
var f = getFingerData ( id ) ;
if ( f === null ) {
f = createFingerData ( id , evt ) ;
}
f . last . x = f . end . x ;
f . last . y = f . end . y ;
f . end . x = evt . pageX || evt . clientX ;
f . end . y = evt . pageY || evt . clientY ;
return f ;
}
/ * *
* Returns a finger data object by its event ID .
* Each touch event has an identifier property , which is used
* to track repeat touches
* @ param { int } id The unique id of the finger in the sequence of touch events .
* @ return a finger data object .
* @ inner
* /
function getFingerData ( id ) {
return fingerData [ id ] || null ;
}
/ * *
* Sets the maximum distance swiped in the given direction .
* If the new value is lower than the current value , the max value is not changed .
* @ param { string } direction The direction of the swipe
* @ param { int } distance The distance of the swipe
* @ inner
* /
function setMaxDistance ( direction , distance ) {
if ( direction == NONE ) return ;
distance = Math . max ( distance , getMaxDistance ( direction ) ) ;
maximumsMap [ direction ] . distance = distance ;
}
/ * *
* gets the maximum distance swiped in the given direction .
* @ param { string } direction The direction of the swipe
* @ return int The distance of the swipe
* @ inner
* /
function getMaxDistance ( direction ) {
if ( maximumsMap [ direction ] ) return maximumsMap [ direction ] . distance ;
return undefined ;
}
/ * *
* Creats a map of directions to maximum swiped values .
* @ return Object A dictionary of maximum values , indexed by direction .
* @ inner
* /
function createMaximumsData ( ) {
var maxData = { } ;
maxData [ LEFT ] = createMaximumVO ( LEFT ) ;
maxData [ RIGHT ] = createMaximumVO ( RIGHT ) ;
maxData [ UP ] = createMaximumVO ( UP ) ;
maxData [ DOWN ] = createMaximumVO ( DOWN ) ;
return maxData ;
}
/ * *
* Creates a map maximum swiped values for a given swipe direction
* @ param { string } The direction that these values will be associated with
* @ return Object Maximum values
* @ inner
* /
function createMaximumVO ( dir ) {
return {
direction : dir ,
distance : 0
}
}
//
// MATHS / UTILS
//
/ * *
* Calculate the duration of the swipe
* @ return int
* @ inner
* /
function calculateDuration ( ) {
return endTime - startTime ;
}
/ * *
* Calculate the distance between 2 touches ( pinch )
* @ param { point } startPoint A point object containing x and y co - ordinates
* @ param { point } endPoint A point object containing x and y co - ordinates
* @ return int ;
* @ inner
* /
function calculateTouchesDistance ( startPoint , endPoint ) {
var diffX = Math . abs ( startPoint . x - endPoint . x ) ;
var diffY = Math . abs ( startPoint . y - endPoint . y ) ;
return Math . round ( Math . sqrt ( diffX * diffX + diffY * diffY ) ) ;
}
/ * *
* Calculate the zoom factor between the start and end distances
* @ param { int } startDistance Distance ( between 2 fingers ) the user started pinching at
* @ param { int } endDistance Distance ( between 2 fingers ) the user ended pinching at
* @ return float The zoom value from 0 to 1.
* @ inner
* /
function calculatePinchZoom ( startDistance , endDistance ) {
var percent = ( endDistance / startDistance ) * 1 ;
return percent . toFixed ( 2 ) ;
}
/ * *
* Returns the pinch direction , either IN or OUT for the given points
* @ return string Either { @ link $ . fn . swipe . directions . IN } or { @ link $ . fn . swipe . directions . OUT }
* @ see $ . fn . swipe . directions
* @ inner
* /
function calculatePinchDirection ( ) {
if ( pinchZoom < 1 ) {
return OUT ;
} else {
return IN ;
}
}
/ * *
* Calculate the length / distance of the swipe
* @ param { point } startPoint A point object containing x and y co - ordinates
* @ param { point } endPoint A point object containing x and y co - ordinates
* @ return int
* @ inner
* /
function calculateDistance ( startPoint , endPoint ) {
return Math . round ( Math . sqrt ( Math . pow ( endPoint . x - startPoint . x , 2 ) + Math . pow ( endPoint . y - startPoint . y , 2 ) ) ) ;
}
/ * *
* Calculate the angle of the swipe
* @ param { point } startPoint A point object containing x and y co - ordinates
* @ param { point } endPoint A point object containing x and y co - ordinates
* @ return int
* @ inner
* /
function calculateAngle ( startPoint , endPoint ) {
var x = startPoint . x - endPoint . x ;
var y = endPoint . y - startPoint . y ;
var r = Math . atan2 ( y , x ) ; //radians
var angle = Math . round ( r * 180 / Math . PI ) ; //degrees
//ensure value is positive
if ( angle < 0 ) {
angle = 360 - Math . abs ( angle ) ;
}
return angle ;
}
/ * *
* Calculate the direction of the swipe
* This will also call calculateAngle to get the latest angle of swipe
* @ param { point } startPoint A point object containing x and y co - ordinates
* @ param { point } endPoint A point object containing x and y co - ordinates
* @ return string Either { @ link $ . fn . swipe . directions . LEFT } / { @ link $ . fn . swipe . directions . RIGHT } / { @ link $ . fn . swipe . directions . DOWN } / { @ link $ . fn . swipe . directions . UP }
* @ see $ . fn . swipe . directions
* @ inner
* /
function calculateDirection ( startPoint , endPoint ) {
if ( comparePoints ( startPoint , endPoint ) ) {
return NONE ;
}
var angle = calculateAngle ( startPoint , endPoint ) ;
if ( ( angle <= 45 ) && ( angle >= 0 ) ) {
return LEFT ;
} else if ( ( angle <= 360 ) && ( angle >= 315 ) ) {
return LEFT ;
} else if ( ( angle >= 135 ) && ( angle <= 225 ) ) {
return RIGHT ;
} else if ( ( angle > 45 ) && ( angle < 135 ) ) {
return DOWN ;
} else {
return UP ;
}
}
/ * *
* Returns a MS time stamp of the current time
* @ return int
* @ inner
* /
function getTimeStamp ( ) {
var now = new Date ( ) ;
return now . getTime ( ) ;
}
/ * *
* Returns a bounds object with left , right , top and bottom properties for the element specified .
* @ param { DomNode } The DOM node to get the bounds for .
* /
function getbounds ( el ) {
el = $ ( el ) ;
var offset = el . offset ( ) ;
var bounds = {
left : offset . left ,
right : offset . left + el . outerWidth ( ) ,
top : offset . top ,
bottom : offset . top + el . outerHeight ( )
}
return bounds ;
}
/ * *
* Checks if the point object is in the bounds object .
* @ param { object } point A point object .
* @ param { int } point . x The x value of the point .
* @ param { int } point . y The x value of the point .
* @ param { object } bounds The bounds object to test
* @ param { int } bounds . left The leftmost value
* @ param { int } bounds . right The righttmost value
* @ param { int } bounds . top The topmost value
* @ param { int } bounds . bottom The bottommost value
* /
function isInBounds ( point , bounds ) {
return ( point . x > bounds . left && point . x < bounds . right && point . y > bounds . top && point . y < bounds . bottom ) ;
} ;
/ * *
* Checks if the two points are equal
* @ param { object } point A point object .
* @ param { object } point B point object .
* @ return true of the points match
* /
function comparePoints ( pointA , pointB ) {
return ( pointA . x == pointB . x && pointA . y == pointB . y ) ;
}
}
/ * *
* A catch all handler that is triggered for all swipe directions .
* @ name $ . fn . swipe # swipe
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { int } direction The direction the user swiped in . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user swiped
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { object } fingerData The coordinates of fingers in event
* @ param { string } currentDirection The current direction the user is swiping .
* /
/ * *
* A handler that is triggered for "left" swipes .
* @ name $ . fn . swipe # swipeLeft
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { int } direction The direction the user swiped in . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user swiped
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { object } fingerData The coordinates of fingers in event
* @ param { string } currentDirection The current direction the user is swiping .
* /
/ * *
* A handler that is triggered for "right" swipes .
* @ name $ . fn . swipe # swipeRight
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { int } direction The direction the user swiped in . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user swiped
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { object } fingerData The coordinates of fingers in event
* @ param { string } currentDirection The current direction the user is swiping .
* /
/ * *
* A handler that is triggered for "up" swipes .
* @ name $ . fn . swipe # swipeUp
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { int } direction The direction the user swiped in . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user swiped
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { object } fingerData The coordinates of fingers in event
* @ param { string } currentDirection The current direction the user is swiping .
* /
/ * *
* A handler that is triggered for "down" swipes .
* @ name $ . fn . swipe # swipeDown
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { int } direction The direction the user swiped in . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user swiped
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { object } fingerData The coordinates of fingers in event
* @ param { string } currentDirection The current direction the user is swiping .
* /
/ * *
* A handler triggered for every phase of the swipe . This handler is constantly fired for the duration of the pinch .
* This is triggered regardless of swipe thresholds .
* @ name $ . fn . swipe # swipeStatus
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { string } phase The phase of the swipe event . See { @ link $ . fn . swipe . phases }
* @ param { string } direction The direction the user swiped in . This is null if the user has yet to move . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user swiped . This is 0 if the user has yet to move .
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { object } fingerData The coordinates of fingers in event
* @ param { string } currentDirection The current direction the user is swiping .
* /
/ * *
* A handler triggered for pinch in events .
* @ name $ . fn . swipe # pinchIn
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { int } direction The direction the user pinched in . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user pinched
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { int } zoom The zoom / scale level the user pinched too , 0 - 1.
* @ param { object } fingerData The coordinates of fingers in event
* /
/ * *
* A handler triggered for pinch out events .
* @ name $ . fn . swipe # pinchOut
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { int } direction The direction the user pinched in . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user pinched
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { int } zoom The zoom / scale level the user pinched too , 0 - 1.
* @ param { object } fingerData The coordinates of fingers in event
* /
/ * *
* A handler triggered for all pinch events . This handler is constantly fired for the duration of the pinch . This is triggered regardless of thresholds .
* @ name $ . fn . swipe # pinchStatus
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { int } direction The direction the user pinched in . See { @ link $ . fn . swipe . directions }
* @ param { int } distance The distance the user pinched
* @ param { int } duration The duration of the swipe in milliseconds
* @ param { int } fingerCount The number of fingers used . See { @ link $ . fn . swipe . fingers }
* @ param { int } zoom The zoom / scale level the user pinched too , 0 - 1.
* @ param { object } fingerData The coordinates of fingers in event
* /
/ * *
* A click handler triggered when a user simply clicks , rather than swipes on an element .
* This is deprecated since version 1.6 . 2 , any assignment to click will be assigned to the tap handler .
* You cannot use < code > on < / c o d e > t o b i n d t o t h i s e v e n t a s t h e d e f a u l t j Q < c o d e > c l i c k < / c o d e > e v e n t w i l l b e t r i g g e r e d .
* Use the < code > tap < / c o d e > e v e n t i n s t e a d .
* @ name $ . fn . swipe # click
* @ event
* @ deprecated since version 1.6 . 2 , please use { @ link $ . fn . swipe # tap } instead
* @ default null
* @ param { EventObject } event The original event object
* @ param { DomObject } target The element clicked on .
* /
/ * *
* A click / tap handler triggered when a user simply clicks or taps , rather than swipes on an element .
* @ name $ . fn . swipe # tap
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { DomObject } target The element clicked on .
* /
/ * *
* A double tap handler triggered when a user double clicks or taps on an element .
* You can set the time delay for a double tap with the { @ link $ . fn . swipe . defaults # doubleTapThreshold } property .
* Note : If you set both < code > doubleTap < / c o d e > a n d < c o d e > t a p < / c o d e > h a n d l e r s , t h e < c o d e > t a p < / c o d e > e v e n t w i l l b e d e l a y e d b y t h e < c o d e > d o u b l e T a p T h r e s h o l d < / c o d e >
* as the script needs to check if its a double tap .
* @ name $ . fn . swipe # doubleTap
* @ see $ . fn . swipe . defaults # doubleTapThreshold
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { DomObject } target The element clicked on .
* /
/ * *
* A long tap handler triggered once a tap has been release if the tap was longer than the longTapThreshold .
* You can set the time delay for a long tap with the { @ link $ . fn . swipe . defaults # longTapThreshold } property .
* @ name $ . fn . swipe # longTap
* @ see $ . fn . swipe . defaults # longTapThreshold
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { DomObject } target The element clicked on .
* /
/ * *
* A hold tap handler triggered as soon as the longTapThreshold is reached
* You can set the time delay for a long tap with the { @ link $ . fn . swipe . defaults # longTapThreshold } property .
* @ name $ . fn . swipe # hold
* @ see $ . fn . swipe . defaults # longTapThreshold
* @ event
* @ default null
* @ param { EventObject } event The original event object
* @ param { DomObject } target The element clicked on .
* /
} ) ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - modalmanager . js v2 . 2.5
* === === === === === === === === === === === === === === === === === === === ==
* Copyright 2012 Jordan Schroter .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === = * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * M O D A L M A N A G E R C L A S S D E F I N I T I O N
* === === === === === === === = * /
var ModalManager = function ( element , options ) {
this . init ( element , options ) ;
} ;
ModalManager . prototype = {
constructor : ModalManager ,
init : function ( element , options ) {
this . $element = $ ( element ) ;
this . options = $ . extend ( { } , $ . fn . modalmanager . defaults , this . $element . data ( ) , typeof options == 'object' && options ) ;
this . stack = [ ] ;
this . backdropCount = 0 ;
if ( this . options . resize ) {
var resizeTimeout ,
that = this ;
$ ( window ) . on ( 'resize.modal' , function ( ) {
resizeTimeout && clearTimeout ( resizeTimeout ) ;
resizeTimeout = setTimeout ( function ( ) {
for ( var i = 0 ; i < that . stack . length ; i ++ ) {
that . stack [ i ] . isShown && that . stack [ i ] . layout ( ) ;
}
} , 10 ) ;
} ) ;
}
} ,
createModal : function ( element , options ) {
$ ( element ) . modal ( $ . extend ( { manager : this } , options ) ) ;
} ,
appendModal : function ( modal ) {
this . stack . push ( modal ) ;
var that = this ;
modal . $element . on ( 'show.modalmanager' , targetIsSelf ( function ( e ) {
var showModal = function ( ) {
modal . isShown = true ;
var transition = $ . support . transition && modal . $element . hasClass ( 'fade' ) ;
that . $element
. toggleClass ( 'modal-open' , that . hasOpenModal ( ) )
. toggleClass ( 'page-overflow' , $ ( window ) . height ( ) < that . $element . height ( ) ) ;
modal . $parent = modal . $element . parent ( ) ;
modal . $container = that . createContainer ( modal ) ;
modal . $element . appendTo ( modal . $container ) ;
that . backdrop ( modal , function ( ) {
modal . $element . show ( ) ;
if ( transition ) {
//modal.$element[0].style.display = 'run-in';
modal . $element [ 0 ] . offsetWidth ;
//modal.$element.one($.support.transition.end, function () { modal.$element[0].style.display = 'block' });
}
modal . layout ( ) ;
modal . $element
. addClass ( 'in' )
. attr ( 'aria-hidden' , false ) ;
var complete = function ( ) {
that . setFocus ( ) ;
modal . $element . trigger ( 'shown' ) ;
} ;
transition ?
modal . $element . one ( $ . support . transition . end , complete ) :
complete ( ) ;
} ) ;
} ;
modal . options . replace ?
that . replace ( showModal ) :
showModal ( ) ;
} ) ) ;
modal . $element . on ( 'hidden.modalmanager' , targetIsSelf ( function ( e ) {
that . backdrop ( modal ) ;
// handle the case when a modal may have been removed from the dom before this callback executes
if ( ! modal . $element . parent ( ) . length ) {
that . destroyModal ( modal ) ;
} else if ( modal . $backdrop ) {
var transition = $ . support . transition && modal . $element . hasClass ( 'fade' ) ;
// trigger a relayout due to firebox's buggy transition end event
if ( transition ) { modal . $element [ 0 ] . offsetWidth ; }
$ . support . transition && modal . $element . hasClass ( 'fade' ) ?
modal . $backdrop . one ( $ . support . transition . end , function ( ) { modal . destroy ( ) ; } ) :
modal . destroy ( ) ;
} else {
modal . destroy ( ) ;
}
} ) ) ;
modal . $element . on ( 'destroyed.modalmanager' , targetIsSelf ( function ( e ) {
that . destroyModal ( modal ) ;
} ) ) ;
} ,
getOpenModals : function ( ) {
var openModals = [ ] ;
for ( var i = 0 ; i < this . stack . length ; i ++ ) {
if ( this . stack [ i ] . isShown ) openModals . push ( this . stack [ i ] ) ;
}
return openModals ;
} ,
hasOpenModal : function ( ) {
return this . getOpenModals ( ) . length > 0 ;
} ,
setFocus : function ( ) {
var topModal ;
for ( var i = 0 ; i < this . stack . length ; i ++ ) {
if ( this . stack [ i ] . isShown ) topModal = this . stack [ i ] ;
}
if ( ! topModal ) return ;
topModal . focus ( ) ;
} ,
destroyModal : function ( modal ) {
modal . $element . off ( '.modalmanager' ) ;
if ( modal . $backdrop ) this . removeBackdrop ( modal ) ;
this . stack . splice ( this . getIndexOfModal ( modal ) , 1 ) ;
var hasOpenModal = this . hasOpenModal ( ) ;
this . $element . toggleClass ( 'modal-open' , hasOpenModal ) ;
if ( ! hasOpenModal ) {
this . $element . removeClass ( 'page-overflow' ) ;
}
this . removeContainer ( modal ) ;
this . setFocus ( ) ;
} ,
getModalAt : function ( index ) {
return this . stack [ index ] ;
} ,
getIndexOfModal : function ( modal ) {
for ( var i = 0 ; i < this . stack . length ; i ++ ) {
if ( modal === this . stack [ i ] ) return i ;
}
} ,
replace : function ( callback ) {
var topModal ;
for ( var i = 0 ; i < this . stack . length ; i ++ ) {
if ( this . stack [ i ] . isShown ) topModal = this . stack [ i ] ;
}
if ( topModal ) {
this . $backdropHandle = topModal . $backdrop ;
topModal . $backdrop = null ;
callback && topModal . $element . one ( 'hidden' ,
targetIsSelf ( $ . proxy ( callback , this ) ) ) ;
topModal . hide ( ) ;
} else if ( callback ) {
callback ( ) ;
}
} ,
removeBackdrop : function ( modal ) {
modal . $backdrop . remove ( ) ;
modal . $backdrop = null ;
} ,
createBackdrop : function ( animate , tmpl ) {
var $backdrop ;
if ( ! this . $backdropHandle ) {
$backdrop = $ ( tmpl )
. addClass ( animate )
. appendTo ( this . $element ) ;
} else {
$backdrop = this . $backdropHandle ;
$backdrop . off ( '.modalmanager' ) ;
this . $backdropHandle = null ;
this . isLoading && this . removeSpinner ( ) ;
}
return $backdrop ;
} ,
removeContainer : function ( modal ) {
modal . $container . remove ( ) ;
modal . $container = null ;
} ,
createContainer : function ( modal ) {
var $container ;
$container = $ ( '<div class="modal-scrollable">' )
. css ( 'z-index' , getzIndex ( 'modal' , this . getOpenModals ( ) . length ) )
. appendTo ( this . $element ) ;
if ( modal && modal . options . backdrop != 'static' ) {
$container . on ( 'click.modal' , targetIsSelf ( function ( e ) {
modal . hide ( ) ;
} ) ) ;
} else if ( modal ) {
$container . on ( 'click.modal' , targetIsSelf ( function ( e ) {
modal . attention ( ) ;
} ) ) ;
}
return $container ;
} ,
backdrop : function ( modal , callback ) {
var animate = modal . $element . hasClass ( 'fade' ) ? 'fade' : '' ,
showBackdrop = modal . options . backdrop &&
this . backdropCount < this . options . backdropLimit ;
if ( modal . isShown && showBackdrop ) {
var doAnimate = $ . support . transition && animate && ! this . $backdropHandle ;
modal . $backdrop = this . createBackdrop ( animate , modal . options . backdropTemplate ) ;
modal . $backdrop . css ( 'z-index' , getzIndex ( 'backdrop' , this . getOpenModals ( ) . length ) ) ;
if ( doAnimate ) modal . $backdrop [ 0 ] . offsetWidth ; // force reflow
modal . $backdrop . addClass ( 'in' ) ;
this . backdropCount += 1 ;
doAnimate ?
modal . $backdrop . one ( $ . support . transition . end , callback ) :
callback ( ) ;
} else if ( ! modal . isShown && modal . $backdrop ) {
modal . $backdrop . removeClass ( 'in' ) ;
this . backdropCount -= 1 ;
var that = this ;
$ . support . transition && modal . $element . hasClass ( 'fade' ) ?
modal . $backdrop . one ( $ . support . transition . end , function ( ) { that . removeBackdrop ( modal ) } ) :
that . removeBackdrop ( modal ) ;
} else if ( callback ) {
callback ( ) ;
}
} ,
removeSpinner : function ( ) {
this . $spinner && this . $spinner . remove ( ) ;
this . $spinner = null ;
this . isLoading = false ;
} ,
removeLoading : function ( ) {
this . $backdropHandle && this . $backdropHandle . remove ( ) ;
this . $backdropHandle = null ;
this . removeSpinner ( ) ;
} ,
loading : function ( callback ) {
callback = callback || function ( ) { } ;
this . $element
. toggleClass ( 'modal-open' , ! this . isLoading || this . hasOpenModal ( ) )
. toggleClass ( 'page-overflow' , $ ( window ) . height ( ) < this . $element . height ( ) ) ;
if ( ! this . isLoading ) {
this . $backdropHandle = this . createBackdrop ( 'fade' , this . options . backdropTemplate ) ;
this . $backdropHandle [ 0 ] . offsetWidth ; // force reflow
var openModals = this . getOpenModals ( ) ;
this . $backdropHandle
. css ( 'z-index' , getzIndex ( 'backdrop' , openModals . length + 1 ) )
. addClass ( 'in' ) ;
var $spinner = $ ( this . options . spinner )
. css ( 'z-index' , getzIndex ( 'modal' , openModals . length + 1 ) )
. appendTo ( this . $element )
. addClass ( 'in' ) ;
this . $spinner = $ ( this . createContainer ( ) )
. append ( $spinner )
. on ( 'click.modalmanager' , $ . proxy ( this . loading , this ) ) ;
this . isLoading = true ;
$ . support . transition ?
this . $backdropHandle . one ( $ . support . transition . end , callback ) :
callback ( ) ;
} else if ( this . isLoading && this . $backdropHandle ) {
this . $backdropHandle . removeClass ( 'in' ) ;
var that = this ;
$ . support . transition ?
this . $backdropHandle . one ( $ . support . transition . end , function ( ) { that . removeLoading ( ) } ) :
that . removeLoading ( ) ;
} else if ( callback ) {
callback ( this . isLoading ) ;
}
}
} ;
/ * P R I V A T E M E T H O D S
* === === === === === === === == * /
// computes and caches the zindexes
var getzIndex = ( function ( ) {
var zIndexFactor ,
baseIndex = { } ;
return function ( type , pos ) {
if ( typeof zIndexFactor === 'undefined' ) {
var $baseModal = $ ( '<div class="modal hide" />' ) . appendTo ( 'body' ) ,
$baseBackdrop = $ ( '<div class="modal-backdrop hide" />' ) . appendTo ( 'body' ) ;
baseIndex [ 'modal' ] = + $baseModal . css ( 'z-index' ) ;
baseIndex [ 'backdrop' ] = + $baseBackdrop . css ( 'z-index' ) ;
zIndexFactor = baseIndex [ 'modal' ] - baseIndex [ 'backdrop' ] ;
$baseModal . remove ( ) ;
$baseBackdrop . remove ( ) ;
$baseBackdrop = $baseModal = null ;
}
return baseIndex [ type ] + ( zIndexFactor * pos ) ;
}
} ( ) ) ;
// make sure the event target is the modal itself in order to prevent
// other components such as tabsfrom triggering the modal manager.
// if Boostsrap namespaced events, this would not be needed.
function targetIsSelf ( callback ) {
return function ( e ) {
if ( e && this === e . target ) {
return callback . apply ( this , arguments ) ;
}
}
}
/ * M O D A L M A N A G E R P L U G I N D E F I N I T I O N
* === === === === === === === == * /
$ . fn . modalmanager = function ( option , args ) {
return this . each ( function ( ) {
var $this = $ ( this ) ,
data = $this . data ( 'modalmanager' ) ;
if ( ! data ) $this . data ( 'modalmanager' , ( data = new ModalManager ( this , option ) ) ) ;
if ( typeof option === 'string' ) data [ option ] . apply ( data , [ ] . concat ( args ) )
} )
} ;
$ . fn . modalmanager . defaults = {
backdropLimit : 999 ,
resize : true ,
spinner : '<div class="loading-spinner fade" style="width: 200px; margin-left: -100px;"><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div></div>' ,
backdropTemplate : '<div class="modal-backdrop" />'
} ;
$ . fn . modalmanager . Constructor = ModalManager
// ModalManager handles the modal-open class so we need
// to remove conflicting bootstrap 3 event handlers
$ ( function ( ) {
$ ( document ) . off ( 'show.bs.modal' ) . off ( 'hidden.bs.modal' ) ;
} ) ;
} ( jQuery ) ;
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* bootstrap - modal . js v2 . 2.5
* === === === === === === === === === === === === === === === === === === === ==
* Copyright 2012 Jordan Schroter
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* === === === === === === === === === === === === === === === === === === === = * /
! function ( $ ) {
"use strict" ; // jshint ;_;
/ * M O D A L C L A S S D E F I N I T I O N
* === === === === === === === = * /
var Modal = function ( element , options ) {
this . init ( element , options ) ;
} ;
Modal . prototype = {
constructor : Modal ,
init : function ( element , options ) {
var that = this ;
this . options = options ;
this . $element = $ ( element )
. delegate ( '[data-dismiss="modal"]' , 'click.dismiss.modal' , $ . proxy ( this . hide , this ) ) ;
this . options . remote && this . $element . find ( '.modal-body' ) . load ( this . options . remote , function ( ) {
var e = $ . Event ( 'loaded' ) ;
that . $element . trigger ( e ) ;
} ) ;
var manager = typeof this . options . manager === 'function' ?
this . options . manager . call ( this ) : this . options . manager ;
manager = manager . appendModal ?
manager : $ ( manager ) . modalmanager ( ) . data ( 'modalmanager' ) ;
manager . appendModal ( this ) ;
} ,
toggle : function ( ) {
return this [ ! this . isShown ? 'show' : 'hide' ] ( ) ;
} ,
show : function ( ) {
var e = $ . Event ( 'show' ) ;
if ( this . isShown ) return ;
this . $element . trigger ( e ) ;
if ( e . isDefaultPrevented ( ) ) return ;
this . escape ( ) ;
this . tab ( ) ;
this . options . loading && this . loading ( ) ;
} ,
hide : function ( e ) {
e && e . preventDefault ( ) ;
e = $ . Event ( 'hide' ) ;
this . $element . trigger ( e ) ;
if ( ! this . isShown || e . isDefaultPrevented ( ) ) return ;
this . isShown = false ;
this . escape ( ) ;
this . tab ( ) ;
this . isLoading && this . loading ( ) ;
$ ( document ) . off ( 'focusin.modal' ) ;
this . $element
. removeClass ( 'in' )
. removeClass ( 'animated' )
. removeClass ( this . options . attentionAnimation )
. removeClass ( 'modal-overflow' )
. attr ( 'aria-hidden' , true ) ;
$ . support . transition && this . $element . hasClass ( 'fade' ) ?
this . hideWithTransition ( ) :
this . hideModal ( ) ;
} ,
layout : function ( ) {
var prop = this . options . height ? 'height' : 'max-height' ,
value = this . options . height || this . options . maxHeight ;
if ( this . options . width ) {
this . $element . css ( 'width' , this . options . width ) ;
var that = this ;
this . $element . css ( 'margin-left' , function ( ) {
if ( /%/ig . test ( that . options . width ) ) {
return - ( parseInt ( that . options . width ) / 2 ) + '%' ;
} else {
return - ( $ ( this ) . width ( ) / 2 ) + 'px' ;
}
} ) ;
} else {
this . $element . css ( 'width' , '' ) ;
this . $element . css ( 'margin-left' , '' ) ;
}
this . $element . find ( '.modal-body' )
. css ( 'overflow' , '' )
. css ( prop , '' ) ;
if ( value ) {
this . $element . find ( '.modal-body' )
. css ( 'overflow' , 'auto' )
. css ( prop , value ) ;
}
var modalOverflow = $ ( window ) . height ( ) - 10 < this . $element . height ( ) ;
if ( modalOverflow || this . options . modalOverflow ) {
this . $element
. css ( 'margin-top' , 0 )
. addClass ( 'modal-overflow' ) ;
} else {
this . $element
. css ( 'margin-top' , 0 - this . $element . height ( ) / 2 )
. removeClass ( 'modal-overflow' ) ;
}
} ,
tab : function ( ) {
var that = this ;
if ( this . isShown && this . options . consumeTab ) {
this . $element . on ( 'keydown.tabindex.modal' , '[data-tabindex]' , function ( e ) {
if ( e . keyCode && e . keyCode == 9 ) {
var elements = [ ] ,
tabindex = Number ( $ ( this ) . data ( 'tabindex' ) ) ;
that . $element . find ( '[data-tabindex]:enabled:visible:not([readonly])' ) . each ( function ( ev ) {
elements . push ( Number ( $ ( this ) . data ( 'tabindex' ) ) ) ;
} ) ;
elements . sort ( function ( a , b ) { return a - b } ) ;
var arrayPos = $ . inArray ( tabindex , elements ) ;
if ( ! e . shiftKey ) {
arrayPos < elements . length - 1 ?
that . $element . find ( '[data-tabindex=' + elements [ arrayPos + 1 ] + ']' ) . focus ( ) :
that . $element . find ( '[data-tabindex=' + elements [ 0 ] + ']' ) . focus ( ) ;
} else {
arrayPos == 0 ?
that . $element . find ( '[data-tabindex=' + elements [ elements . length - 1 ] + ']' ) . focus ( ) :
that . $element . find ( '[data-tabindex=' + elements [ arrayPos - 1 ] + ']' ) . focus ( ) ;
}
e . preventDefault ( ) ;
}
} ) ;
} else if ( ! this . isShown ) {
this . $element . off ( 'keydown.tabindex.modal' ) ;
}
} ,
escape : function ( ) {
var that = this ;
if ( this . isShown && this . options . keyboard ) {
if ( ! this . $element . attr ( 'tabindex' ) ) this . $element . attr ( 'tabindex' , - 1 ) ;
this . $element . on ( 'keyup.dismiss.modal' , function ( e ) {
e . which == 27 && that . hide ( ) ;
} ) ;
} else if ( ! this . isShown ) {
this . $element . off ( 'keyup.dismiss.modal' )
}
} ,
hideWithTransition : function ( ) {
var that = this
, timeout = setTimeout ( function ( ) {
that . $element . off ( $ . support . transition . end ) ;
that . hideModal ( ) ;
} , 500 ) ;
this . $element . one ( $ . support . transition . end , function ( ) {
clearTimeout ( timeout ) ;
that . hideModal ( ) ;
} ) ;
} ,
hideModal : function ( ) {
var prop = this . options . height ? 'height' : 'max-height' ;
var value = this . options . height || this . options . maxHeight ;
if ( value ) {
this . $element . find ( '.modal-body' )
. css ( 'overflow' , '' )
. css ( prop , '' ) ;
}
this . $element
. hide ( )
. trigger ( 'hidden' ) ;
} ,
removeLoading : function ( ) {
this . $loading . remove ( ) ;
this . $loading = null ;
this . isLoading = false ;
} ,
loading : function ( callback ) {
callback = callback || function ( ) { } ;
var animate = this . $element . hasClass ( 'fade' ) ? 'fade' : '' ;
if ( ! this . isLoading ) {
var doAnimate = $ . support . transition && animate ;
this . $loading = $ ( '<div class="loading-mask ' + animate + '">' )
. append ( this . options . spinner )
. appendTo ( this . $element ) ;
if ( doAnimate ) this . $loading [ 0 ] . offsetWidth ; // force reflow
this . $loading . addClass ( 'in' ) ;
this . isLoading = true ;
doAnimate ?
this . $loading . one ( $ . support . transition . end , callback ) :
callback ( ) ;
} else if ( this . isLoading && this . $loading ) {
this . $loading . removeClass ( 'in' ) ;
var that = this ;
$ . support . transition && this . $element . hasClass ( 'fade' ) ?
this . $loading . one ( $ . support . transition . end , function ( ) { that . removeLoading ( ) } ) :
that . removeLoading ( ) ;
} else if ( callback ) {
callback ( this . isLoading ) ;
}
} ,
focus : function ( ) {
var $focusElem = this . $element . find ( this . options . focusOn ) ;
$focusElem = $focusElem . length ? $focusElem : this . $element ;
$focusElem . focus ( ) ;
} ,
attention : function ( ) {
// NOTE: transitionEnd with keyframes causes odd behaviour
if ( this . options . attentionAnimation ) {
this . $element
. removeClass ( 'animated' )
. removeClass ( this . options . attentionAnimation ) ;
var that = this ;
setTimeout ( function ( ) {
that . $element
. addClass ( 'animated' )
. addClass ( that . options . attentionAnimation ) ;
} , 0 ) ;
}
this . focus ( ) ;
} ,
destroy : function ( ) {
var e = $ . Event ( 'destroy' ) ;
this . $element . trigger ( e ) ;
if ( e . isDefaultPrevented ( ) ) return ;
this . $element
. off ( '.modal' )
. removeData ( 'modal' )
. removeClass ( 'in' )
. attr ( 'aria-hidden' , true ) ;
if ( this . $parent !== this . $element . parent ( ) ) {
this . $element . appendTo ( this . $parent ) ;
} else if ( ! this . $parent . length ) {
// modal is not part of the DOM so remove it.
this . $element . remove ( ) ;
this . $element = null ;
}
this . $element . trigger ( 'destroyed' ) ;
}
} ;
/ * M O D A L P L U G I N D E F I N I T I O N
* === === === === === === === == * /
$ . fn . modal = function ( option , args ) {
return this . each ( function ( ) {
var $this = $ ( this ) ,
data = $this . data ( 'modal' ) ,
options = $ . extend ( { } , $ . fn . modal . defaults , $this . data ( ) , typeof option == 'object' && option ) ;
if ( ! data ) $this . data ( 'modal' , ( data = new Modal ( this , options ) ) ) ;
if ( typeof option == 'string' ) data [ option ] . apply ( data , [ ] . concat ( args ) ) ;
else if ( options . show ) data . show ( )
} )
} ;
$ . fn . modal . defaults = {
keyboard : true ,
backdrop : true ,
loading : false ,
show : true ,
width : null ,
height : null ,
maxHeight : null ,
modalOverflow : false ,
consumeTab : true ,
focusOn : null ,
replace : false ,
resize : false ,
attentionAnimation : 'shake' ,
manager : 'body' ,
spinner : '<div class="loading-spinner" style="width: 200px; margin-left: -100px;"><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div></div>' ,
backdropTemplate : '<div class="modal-backdrop" />'
} ;
$ . fn . modal . Constructor = Modal ;
/ * M O D A L D A T A - A P I
* === === === === == * /
$ ( function ( ) {
$ ( document ) . off ( 'click.modal' ) . on ( 'click.modal.data-api' , '[data-toggle="modal"]' , function ( e ) {
var $this = $ ( this ) ,
href = $this . attr ( 'href' ) ,
$target = $ ( $this . attr ( 'data-target' ) || ( href && href . replace ( /.*(?=#[^\s]+$)/ , '' ) ) ) , //strip for ie7
option = $target . data ( 'modal' ) ? 'toggle' : $ . extend ( { remote : ! /#/ . test ( href ) && href } , $target . data ( ) , $this . data ( ) ) ;
e . preventDefault ( ) ;
$target
. modal ( option )
. one ( 'hide' , function ( ) {
$this . focus ( ) ;
} )
} ) ;
} ) ;
} ( window . jQuery ) ;
/ * !
* clipboard . js v1 . 7.1
* https : //zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
* /
( function ( f ) { if ( typeof exports === "object" && typeof module !== "undefined" ) { module . exports = f ( ) } else if ( typeof define === "function" && define . amd ) { define ( [ ] , f ) } else { var g ; if ( typeof window !== "undefined" ) { g = window } else if ( typeof global !== "undefined" ) { g = global } else if ( typeof self !== "undefined" ) { g = self } else { g = this } g . Clipboard = f ( ) } } ) ( function ( ) { var define , module , exports ; return ( function e ( t , n , r ) { function s ( o , u ) { if ( ! n [ o ] ) { if ( ! t [ o ] ) { var a = typeof require == "function" && require ; if ( ! u && a ) return a ( o , ! 0 ) ; if ( i ) return i ( o , ! 0 ) ; var f = new Error ( "Cannot find module '" + o + "'" ) ; throw f . code = "MODULE_NOT_FOUND" , f } var l = n [ o ] = { exports : { } } ; t [ o ] [ 0 ] . call ( l . exports , function ( e ) { var n = t [ o ] [ 1 ] [ e ] ; return s ( n ? n : e ) } , l , l . exports , e , t , n , r ) } return n [ o ] . exports } var i = typeof require == "function" && require ; for ( var o = 0 ; o < r . length ; o ++ ) s ( r [ o ] ) ; return s } ) ( { 1 : [ function ( require , module , exports ) {
var DOCUMENT _NODE _TYPE = 9 ;
/ * *
* A polyfill for Element . matches ( )
* /
if ( typeof Element !== 'undefined' && ! Element . prototype . matches ) {
var proto = Element . prototype ;
proto . matches = proto . matchesSelector ||
proto . mozMatchesSelector ||
proto . msMatchesSelector ||
proto . oMatchesSelector ||
proto . webkitMatchesSelector ;
}
/ * *
* Finds the closest parent that matches a selector .
*
* @ param { Element } element
* @ param { String } selector
* @ return { Function }
* /
function closest ( element , selector ) {
while ( element && element . nodeType !== DOCUMENT _NODE _TYPE ) {
if ( typeof element . matches === 'function' &&
element . matches ( selector ) ) {
return element ;
}
element = element . parentNode ;
}
}
module . exports = closest ;
} , { } ] , 2 : [ function ( require , module , exports ) {
var closest = require ( './closest' ) ;
/ * *
* Delegates event to a selector .
*
* @ param { Element } element
* @ param { String } selector
* @ param { String } type
* @ param { Function } callback
* @ param { Boolean } useCapture
* @ return { Object }
* /
function delegate ( element , selector , type , callback , useCapture ) {
var listenerFn = listener . apply ( this , arguments ) ;
element . addEventListener ( type , listenerFn , useCapture ) ;
return {
destroy : function ( ) {
element . removeEventListener ( type , listenerFn , useCapture ) ;
}
}
}
/ * *
* Finds closest match and invokes callback .
*
* @ param { Element } element
* @ param { String } selector
* @ param { String } type
* @ param { Function } callback
* @ return { Function }
* /
function listener ( element , selector , type , callback ) {
return function ( e ) {
e . delegateTarget = closest ( e . target , selector ) ;
if ( e . delegateTarget ) {
callback . call ( element , e ) ;
}
}
}
module . exports = delegate ;
} , { "./closest" : 1 } ] , 3 : [ function ( require , module , exports ) {
/ * *
* Check if argument is a HTML element .
*
* @ param { Object } value
* @ return { Boolean }
* /
exports . node = function ( value ) {
return value !== undefined
&& value instanceof HTMLElement
&& value . nodeType === 1 ;
} ;
/ * *
* Check if argument is a list of HTML elements .
*
* @ param { Object } value
* @ return { Boolean }
* /
exports . nodeList = function ( value ) {
var type = Object . prototype . toString . call ( value ) ;
return value !== undefined
&& ( type === '[object NodeList]' || type === '[object HTMLCollection]' )
&& ( 'length' in value )
&& ( value . length === 0 || exports . node ( value [ 0 ] ) ) ;
} ;
/ * *
* Check if argument is a string .
*
* @ param { Object } value
* @ return { Boolean }
* /
exports . string = function ( value ) {
return typeof value === 'string'
|| value instanceof String ;
} ;
/ * *
* Check if argument is a function .
*
* @ param { Object } value
* @ return { Boolean }
* /
exports . fn = function ( value ) {
var type = Object . prototype . toString . call ( value ) ;
return type === '[object Function]' ;
} ;
} , { } ] , 4 : [ function ( require , module , exports ) {
var is = require ( './is' ) ;
var delegate = require ( 'delegate' ) ;
/ * *
* Validates all params and calls the right
* listener function based on its target type .
*
* @ param { String | HTMLElement | HTMLCollection | NodeList } target
* @ param { String } type
* @ param { Function } callback
* @ return { Object }
* /
function listen ( target , type , callback ) {
if ( ! target && ! type && ! callback ) {
throw new Error ( 'Missing required arguments' ) ;
}
if ( ! is . string ( type ) ) {
throw new TypeError ( 'Second argument must be a String' ) ;
}
if ( ! is . fn ( callback ) ) {
throw new TypeError ( 'Third argument must be a Function' ) ;
}
if ( is . node ( target ) ) {
return listenNode ( target , type , callback ) ;
}
else if ( is . nodeList ( target ) ) {
return listenNodeList ( target , type , callback ) ;
}
else if ( is . string ( target ) ) {
return listenSelector ( target , type , callback ) ;
}
else {
throw new TypeError ( 'First argument must be a String, HTMLElement, HTMLCollection, or NodeList' ) ;
}
}
/ * *
* Adds an event listener to a HTML element
* and returns a remove listener function .
*
* @ param { HTMLElement } node
* @ param { String } type
* @ param { Function } callback
* @ return { Object }
* /
function listenNode ( node , type , callback ) {
node . addEventListener ( type , callback ) ;
return {
destroy : function ( ) {
node . removeEventListener ( type , callback ) ;
}
}
}
/ * *
* Add an event listener to a list of HTML elements
* and returns a remove listener function .
*
* @ param { NodeList | HTMLCollection } nodeList
* @ param { String } type
* @ param { Function } callback
* @ return { Object }
* /
function listenNodeList ( nodeList , type , callback ) {
Array . prototype . forEach . call ( nodeList , function ( node ) {
node . addEventListener ( type , callback ) ;
} ) ;
return {
destroy : function ( ) {
Array . prototype . forEach . call ( nodeList , function ( node ) {
node . removeEventListener ( type , callback ) ;
} ) ;
}
}
}
/ * *
* Add an event listener to a selector
* and returns a remove listener function .
*
* @ param { String } selector
* @ param { String } type
* @ param { Function } callback
* @ return { Object }
* /
function listenSelector ( selector , type , callback ) {
return delegate ( document . body , selector , type , callback ) ;
}
module . exports = listen ;
} , { "./is" : 3 , "delegate" : 2 } ] , 5 : [ function ( require , module , exports ) {
function select ( element ) {
var selectedText ;
if ( element . nodeName === 'SELECT' ) {
element . focus ( ) ;
selectedText = element . value ;
}
else if ( element . nodeName === 'INPUT' || element . nodeName === 'TEXTAREA' ) {
var isReadOnly = element . hasAttribute ( 'readonly' ) ;
if ( ! isReadOnly ) {
element . setAttribute ( 'readonly' , '' ) ;
}
element . select ( ) ;
element . setSelectionRange ( 0 , element . value . length ) ;
if ( ! isReadOnly ) {
element . removeAttribute ( 'readonly' ) ;
}
selectedText = element . value ;
}
else {
if ( element . hasAttribute ( 'contenteditable' ) ) {
element . focus ( ) ;
}
var selection = window . getSelection ( ) ;
var range = document . createRange ( ) ;
range . selectNodeContents ( element ) ;
selection . removeAllRanges ( ) ;
selection . addRange ( range ) ;
selectedText = selection . toString ( ) ;
}
return selectedText ;
}
module . exports = select ;
} , { } ] , 6 : [ function ( require , module , exports ) {
function E ( ) {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}
E . prototype = {
on : function ( name , callback , ctx ) {
var e = this . e || ( this . e = { } ) ;
( e [ name ] || ( e [ name ] = [ ] ) ) . push ( {
fn : callback ,
ctx : ctx
} ) ;
return this ;
} ,
once : function ( name , callback , ctx ) {
var self = this ;
function listener ( ) {
self . off ( name , listener ) ;
callback . apply ( ctx , arguments ) ;
} ;
listener . _ = callback
return this . on ( name , listener , ctx ) ;
} ,
emit : function ( name ) {
var data = [ ] . slice . call ( arguments , 1 ) ;
var evtArr = ( ( this . e || ( this . e = { } ) ) [ name ] || [ ] ) . slice ( ) ;
var i = 0 ;
var len = evtArr . length ;
for ( i ; i < len ; i ++ ) {
evtArr [ i ] . fn . apply ( evtArr [ i ] . ctx , data ) ;
}
return this ;
} ,
off : function ( name , callback ) {
var e = this . e || ( this . e = { } ) ;
var evts = e [ name ] ;
var liveEvents = [ ] ;
if ( evts && callback ) {
for ( var i = 0 , len = evts . length ; i < len ; i ++ ) {
if ( evts [ i ] . fn !== callback && evts [ i ] . fn . _ !== callback )
liveEvents . push ( evts [ i ] ) ;
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
( liveEvents . length )
? e [ name ] = liveEvents
: delete e [ name ] ;
return this ;
}
} ;
module . exports = E ;
} , { } ] , 7 : [ function ( require , module , exports ) {
( function ( global , factory ) {
if ( typeof define === "function" && define . amd ) {
define ( [ 'module' , 'select' ] , factory ) ;
} else if ( typeof exports !== "undefined" ) {
factory ( module , require ( 'select' ) ) ;
} else {
var mod = {
exports : { }
} ;
factory ( mod , global . select ) ;
global . clipboardAction = mod . exports ;
}
} ) ( this , function ( module , _select ) {
'use strict' ;
var _select2 = _interopRequireDefault ( _select ) ;
function _interopRequireDefault ( obj ) {
return obj && obj . _ _esModule ? obj : {
default : obj
} ;
}
var _typeof = typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ? function ( obj ) {
return typeof obj ;
} : function ( obj ) {
return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ;
} ;
function _classCallCheck ( instance , Constructor ) {
if ( ! ( instance instanceof Constructor ) ) {
throw new TypeError ( "Cannot call a class as a function" ) ;
}
}
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 ;
} ;
} ( ) ;
var ClipboardAction = function ( ) {
/ * *
* @ param { Object } options
* /
function ClipboardAction ( options ) {
_classCallCheck ( this , ClipboardAction ) ;
this . resolveOptions ( options ) ;
this . initSelection ( ) ;
}
/ * *
* Defines base properties passed from constructor .
* @ param { Object } options
* /
_createClass ( ClipboardAction , [ {
key : 'resolveOptions' ,
value : function resolveOptions ( ) {
var options = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : { } ;
this . action = options . action ;
this . container = options . container ;
this . emitter = options . emitter ;
this . target = options . target ;
this . text = options . text ;
this . trigger = options . trigger ;
this . selectedText = '' ;
}
} , {
key : 'initSelection' ,
value : function initSelection ( ) {
if ( this . text ) {
this . selectFake ( ) ;
} else if ( this . target ) {
this . selectTarget ( ) ;
}
}
} , {
key : 'selectFake' ,
value : function selectFake ( ) {
var _this = this ;
var isRTL = document . documentElement . getAttribute ( 'dir' ) == 'rtl' ;
this . removeFake ( ) ;
this . fakeHandlerCallback = function ( ) {
return _this . removeFake ( ) ;
} ;
this . fakeHandler = this . container . addEventListener ( 'click' , this . fakeHandlerCallback ) || true ;
this . fakeElem = document . createElement ( 'textarea' ) ;
// Prevent zooming on iOS
this . fakeElem . style . fontSize = '12pt' ;
// Reset box model
this . fakeElem . style . border = '0' ;
this . fakeElem . style . padding = '0' ;
this . fakeElem . style . margin = '0' ;
// Move element out of screen horizontally
this . fakeElem . style . position = 'absolute' ;
this . fakeElem . style [ isRTL ? 'right' : 'left' ] = '-9999px' ;
// Move element to the same position vertically
var yPosition = window . pageYOffset || document . documentElement . scrollTop ;
this . fakeElem . style . top = yPosition + 'px' ;
this . fakeElem . setAttribute ( 'readonly' , '' ) ;
this . fakeElem . value = this . text ;
this . container . appendChild ( this . fakeElem ) ;
this . selectedText = ( 0 , _select2 . default ) ( this . fakeElem ) ;
this . copyText ( ) ;
}
} , {
key : 'removeFake' ,
value : function removeFake ( ) {
if ( this . fakeHandler ) {
this . container . removeEventListener ( 'click' , this . fakeHandlerCallback ) ;
this . fakeHandler = null ;
this . fakeHandlerCallback = null ;
}
if ( this . fakeElem ) {
this . container . removeChild ( this . fakeElem ) ;
this . fakeElem = null ;
}
}
} , {
key : 'selectTarget' ,
value : function selectTarget ( ) {
this . selectedText = ( 0 , _select2 . default ) ( this . target ) ;
this . copyText ( ) ;
}
} , {
key : 'copyText' ,
value : function copyText ( ) {
var succeeded = void 0 ;
try {
succeeded = document . execCommand ( this . action ) ;
} catch ( err ) {
succeeded = false ;
}
this . handleResult ( succeeded ) ;
}
} , {
key : 'handleResult' ,
value : function handleResult ( succeeded ) {
this . emitter . emit ( succeeded ? 'success' : 'error' , {
action : this . action ,
text : this . selectedText ,
trigger : this . trigger ,
clearSelection : this . clearSelection . bind ( this )
} ) ;
}
} , {
key : 'clearSelection' ,
value : function clearSelection ( ) {
if ( this . trigger ) {
this . trigger . focus ( ) ;
}
window . getSelection ( ) . removeAllRanges ( ) ;
}
} , {
key : 'destroy' ,
value : function destroy ( ) {
this . removeFake ( ) ;
}
} , {
key : 'action' ,
set : function set ( ) {
var action = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : 'copy' ;
this . _action = action ;
if ( this . _action !== 'copy' && this . _action !== 'cut' ) {
throw new Error ( 'Invalid "action" value, use either "copy" or "cut"' ) ;
}
} ,
get : function get ( ) {
return this . _action ;
}
} , {
key : 'target' ,
set : function set ( target ) {
if ( target !== undefined ) {
if ( target && ( typeof target === 'undefined' ? 'undefined' : _typeof ( target ) ) === 'object' && target . nodeType === 1 ) {
if ( this . action === 'copy' && target . hasAttribute ( 'disabled' ) ) {
throw new Error ( 'Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute' ) ;
}
if ( this . action === 'cut' && ( target . hasAttribute ( 'readonly' ) || target . hasAttribute ( 'disabled' ) ) ) {
throw new Error ( 'Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes' ) ;
}
this . _target = target ;
} else {
throw new Error ( 'Invalid "target" value, use a valid Element' ) ;
}
}
} ,
get : function get ( ) {
return this . _target ;
}
} ] ) ;
return ClipboardAction ;
} ( ) ;
module . exports = ClipboardAction ;
} ) ;
} , { "select" : 5 } ] , 8 : [ function ( require , module , exports ) {
( function ( global , factory ) {
if ( typeof define === "function" && define . amd ) {
define ( [ 'module' , './clipboard-action' , 'tiny-emitter' , 'good-listener' ] , factory ) ;
} else if ( typeof exports !== "undefined" ) {
factory ( module , require ( './clipboard-action' ) , require ( 'tiny-emitter' ) , require ( 'good-listener' ) ) ;
} else {
var mod = {
exports : { }
} ;
factory ( mod , global . clipboardAction , global . tinyEmitter , global . goodListener ) ;
global . clipboard = mod . exports ;
}
} ) ( this , function ( module , _clipboardAction , _tinyEmitter , _goodListener ) {
'use strict' ;
var _clipboardAction2 = _interopRequireDefault ( _clipboardAction ) ;
var _tinyEmitter2 = _interopRequireDefault ( _tinyEmitter ) ;
var _goodListener2 = _interopRequireDefault ( _goodListener ) ;
function _interopRequireDefault ( obj ) {
return obj && obj . _ _esModule ? obj : {
default : obj
} ;
}
var _typeof = typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ? function ( obj ) {
return typeof obj ;
} : function ( obj ) {
return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ;
} ;
function _classCallCheck ( instance , Constructor ) {
if ( ! ( instance instanceof Constructor ) ) {
throw new TypeError ( "Cannot call a class as a function" ) ;
}
}
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 _possibleConstructorReturn ( self , call ) {
if ( ! self ) {
throw new ReferenceError ( "this hasn't been initialised - super() hasn't been called" ) ;
}
return call && ( typeof call === "object" || typeof call === "function" ) ? call : self ;
}
function _inherits ( subClass , superClass ) {
if ( typeof superClass !== "function" && superClass !== null ) {
throw new TypeError ( "Super expression must either be null or a function, not " + typeof superClass ) ;
}
subClass . prototype = Object . create ( superClass && superClass . prototype , {
constructor : {
value : subClass ,
enumerable : false ,
writable : true ,
configurable : true
}
} ) ;
if ( superClass ) Object . setPrototypeOf ? Object . setPrototypeOf ( subClass , superClass ) : subClass . _ _proto _ _ = superClass ;
}
var Clipboard = function ( _Emitter ) {
_inherits ( Clipboard , _Emitter ) ;
/ * *
* @ param { String | HTMLElement | HTMLCollection | NodeList } trigger
* @ param { Object } options
* /
function Clipboard ( trigger , options ) {
_classCallCheck ( this , Clipboard ) ;
var _this = _possibleConstructorReturn ( this , ( Clipboard . _ _proto _ _ || Object . getPrototypeOf ( Clipboard ) ) . call ( this ) ) ;
_this . resolveOptions ( options ) ;
_this . listenClick ( trigger ) ;
return _this ;
}
/ * *
* Defines if attributes would be resolved using internal setter functions
* or custom functions that were passed in the constructor .
* @ param { Object } options
* /
_createClass ( Clipboard , [ {
key : 'resolveOptions' ,
value : function resolveOptions ( ) {
var options = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : { } ;
this . action = typeof options . action === 'function' ? options . action : this . defaultAction ;
this . target = typeof options . target === 'function' ? options . target : this . defaultTarget ;
this . text = typeof options . text === 'function' ? options . text : this . defaultText ;
this . container = _typeof ( options . container ) === 'object' ? options . container : document . body ;
}
} , {
key : 'listenClick' ,
value : function listenClick ( trigger ) {
var _this2 = this ;
this . listener = ( 0 , _goodListener2 . default ) ( trigger , 'click' , function ( e ) {
return _this2 . onClick ( e ) ;
} ) ;
}
} , {
key : 'onClick' ,
value : function onClick ( e ) {
var trigger = e . delegateTarget || e . currentTarget ;
if ( this . clipboardAction ) {
this . clipboardAction = null ;
}
this . clipboardAction = new _clipboardAction2 . default ( {
action : this . action ( trigger ) ,
target : this . target ( trigger ) ,
text : this . text ( trigger ) ,
container : this . container ,
trigger : trigger ,
emitter : this
} ) ;
}
} , {
key : 'defaultAction' ,
value : function defaultAction ( trigger ) {
return getAttributeValue ( 'action' , trigger ) ;
}
} , {
key : 'defaultTarget' ,
value : function defaultTarget ( trigger ) {
var selector = getAttributeValue ( 'target' , trigger ) ;
if ( selector ) {
return document . querySelector ( selector ) ;
}
}
} , {
key : 'defaultText' ,
value : function defaultText ( trigger ) {
return getAttributeValue ( 'text' , trigger ) ;
}
} , {
key : 'destroy' ,
value : function destroy ( ) {
this . listener . destroy ( ) ;
if ( this . clipboardAction ) {
this . clipboardAction . destroy ( ) ;
this . clipboardAction = null ;
}
}
} ] , [ {
key : 'isSupported' ,
value : function isSupported ( ) {
var action = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : [ 'copy' , 'cut' ] ;
var actions = typeof action === 'string' ? [ action ] : action ;
var support = ! ! document . queryCommandSupported ;
actions . forEach ( function ( action ) {
support = support && ! ! document . queryCommandSupported ( action ) ;
} ) ;
return support ;
}
} ] ) ;
return Clipboard ;
} ( _tinyEmitter2 . default ) ;
/ * *
* Helper function to retrieve attribute value .
* @ param { String } suffix
* @ param { Element } element
* /
function getAttributeValue ( suffix , element ) {
var attribute = 'data-clipboard-' + suffix ;
if ( ! element . hasAttribute ( attribute ) ) {
return ;
}
return element . getAttribute ( attribute ) ;
}
module . exports = Clipboard ;
} ) ;
} , { "./clipboard-action" : 7 , "good-listener" : 4 , "tiny-emitter" : 6 } ] } , { } , [ 8 ] ) ( 8 )
} ) ;
/ * !
* jQuery UI Touch Punch 0.2 . 3
*
* Copyright 2011 – 2014 , Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses .
*
* Depends :
* jquery . ui . widget . js
* jquery . ui . mouse . js
* /
( function ( $ ) {
// Detect touch support
$ . support . touch = 'ontouchend' in document ;
// Ignore browsers without touch support
if ( ! $ . support . touch ) {
return ;
}
var mouseProto = $ . ui . mouse . prototype ,
_mouseInit = mouseProto . _mouseInit ,
_mouseDestroy = mouseProto . _mouseDestroy ,
touchHandled ;
/ * *
* Simulate a mouse event based on a corresponding touch event
* @ param { Object } event A touch event
* @ param { String } simulatedType The corresponding mouse event
* /
function simulateMouseEvent ( event , simulatedType ) {
// Ignore multi-touch events
if ( event . originalEvent . touches . length > 1 ) {
return ;
}
event . preventDefault ( ) ;
var touch = event . originalEvent . changedTouches [ 0 ] ,
simulatedEvent = document . createEvent ( 'MouseEvents' ) ;
// Initialize the simulated mouse event using the touch event's coordinates
simulatedEvent . initMouseEvent (
simulatedType , // type
true , // bubbles
true , // cancelable
window , // view
1 , // detail
touch . screenX , // screenX
touch . screenY , // screenY
touch . clientX , // clientX
touch . clientY , // clientY
false , // ctrlKey
false , // altKey
false , // shiftKey
false , // metaKey
0 , // button
null // relatedTarget
) ;
// Dispatch the simulated event to the target element
event . target . dispatchEvent ( simulatedEvent ) ;
}
/ * *
* Handle the jQuery UI widget ' s touchstart events
* @ param { Object } event The widget element ' s touchstart event
* /
mouseProto . _touchStart = function ( event ) {
var self = this ;
// Ignore the event if another widget is already being handled
if ( touchHandled || ! self . _mouseCapture ( event . originalEvent . changedTouches [ 0 ] ) ) {
return ;
}
// Set the flag to prevent other widgets from inheriting the touch event
touchHandled = true ;
// Track movement to determine if interaction was a click
self . _touchMoved = false ;
// Simulate the mouseover event
simulateMouseEvent ( event , 'mouseover' ) ;
// Simulate the mousemove event
simulateMouseEvent ( event , 'mousemove' ) ;
// Simulate the mousedown event
simulateMouseEvent ( event , 'mousedown' ) ;
} ;
/ * *
* Handle the jQuery UI widget ' s touchmove events
* @ param { Object } event The document ' s touchmove event
* /
mouseProto . _touchMove = function ( event ) {
// Ignore event if not handled
if ( ! touchHandled ) {
return ;
}
// Interaction was not a click
this . _touchMoved = true ;
// Simulate the mousemove event
simulateMouseEvent ( event , 'mousemove' ) ;
} ;
/ * *
* Handle the jQuery UI widget ' s touchend events
* @ param { Object } event The document ' s touchend event
* /
mouseProto . _touchEnd = function ( event ) {
// Ignore event if not handled
if ( ! touchHandled ) {
return ;
}
// Simulate the mouseup event
simulateMouseEvent ( event , 'mouseup' ) ;
// Simulate the mouseout event
simulateMouseEvent ( event , 'mouseout' ) ;
// If the touch interaction did not move, it should trigger a click
if ( ! this . _touchMoved ) {
// Simulate the click event
simulateMouseEvent ( event , 'click' ) ;
}
// Unset the flag to allow other widgets to inherit the touch event
touchHandled = false ;
} ;
/ * *
* A duck punch of the $ . ui . mouse _mouseInit method to support touch events .
* This method extends the widget with bound touch event handlers that
* translate touch events to mouse events and pass them to the widget ' s
* original mouse event handling methods .
* /
mouseProto . _mouseInit = function ( ) {
var self = this ;
// Delegate the touch handlers to the widget's element
self . element . bind ( {
touchstart : $ . proxy ( self , '_touchStart' ) ,
touchmove : $ . proxy ( self , '_touchMove' ) ,
touchend : $ . proxy ( self , '_touchEnd' )
} ) ;
// Call the original $.ui.mouse init method
_mouseInit . call ( self ) ;
} ;
/ * *
* Remove the touch event handlers
* /
mouseProto . _mouseDestroy = function ( ) {
var self = this ;
// Delegate the touch handlers to the widget's element
self . element . unbind ( {
touchstart : $ . proxy ( self , '_touchStart' ) ,
touchmove : $ . proxy ( self , '_touchMove' ) ,
touchend : $ . proxy ( self , '_touchEnd' )
} ) ;
// Call the original $.ui.mouse destroy method
_mouseDestroy . call ( self ) ;
} ;
} ) ( jQuery ) ;