",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ // 1.9 BC for #7810
+ // TODO remove dual storage
+ $.data( element, this.widgetName, this );
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ // 1.9 BC for #7810
+ // TODO remove dual storage
+ .removeData( this.widgetName )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( value === undefined ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( value === undefined ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
+ .attr( "aria-disabled", value );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement,
+ instance = this;
+
+ // no suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ // accept selectors, DOM elements
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^(\w+)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+});
+
+// DEPRECATED
+if ( $.uiBackCompat !== false ) {
+ $.Widget.prototype._getCreateOptions = function() {
+ return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
+ };
+}
+
+})( jQuery );
diff --git a/alarm-analysis/src/main/webapp/public/common/js/jQuery-File-Upload/js/vendor/jquery.ui.widget.js b/alarm-analysis/src/main/webapp/public/common/js/jQuery-File-Upload/js/vendor/jquery.ui.widget.js
new file mode 100644
index 00000000..072269b0
--- /dev/null
+++ b/alarm-analysis/src/main/webapp/public/common/js/jQuery-File-Upload/js/vendor/jquery.ui.widget.js
@@ -0,0 +1,572 @@
+/*! jQuery UI - v1.11.4+CommonJS - 2015-08-28
+ * http://jqueryui.com
+ * Includes: widget.js
+ * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
+
+(function( factory ) {
+ if ( typeof define === "function" && define.amd ) {
+
+ // AMD. Register as an anonymous module.
+ define([ "jquery" ], factory );
+
+ } else if ( typeof exports === "object" ) {
+
+ // Node/CommonJS
+ factory( require( "jquery" ) );
+
+ } else {
+
+ // Browser globals
+ factory( jQuery );
+ }
+}(function( $ ) {
+ /*!
+ * jQuery UI Widget 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/jQuery.widget/
+ */
+
+
+ var widget_uuid = 0,
+ widget_slice = Array.prototype.slice;
+
+ $.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 );
+
+ $.widget = function( name, base, prototype ) {
+ var fullName, existingConstructor, constructor, basePrototype,
+ // proxiedPrototype allows the provided prototype to remain unmodified
+ // so that it can be used as a mixin for multiple widgets (#8876)
+ proxiedPrototype = {},
+ namespace = name.split( "." )[ 0 ];
+
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+ // extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+ // copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+ // track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ });
+
+ basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( !$.isFunction( value ) ) {
+ proxiedPrototype[ prop ] = value;
+ return;
+ }
+ proxiedPrototype[ prop ] = (function() {
+ var _super = function() {
+ return base.prototype[ prop ].apply( this, arguments );
+ },
+ _superApply = function( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ };
+ return function() {
+ var __super = this._super,
+ __superApply = this._superApply,
+ returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ })();
+ });
+ constructor.prototype = $.widget.extend( basePrototype, {
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
+ }, proxiedPrototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ widgetFullName: fullName
+ });
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+ });
+ // remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+
+ return constructor;
+ };
+
+ $.widget.extend = function( target ) {
+ var input = widget_slice.call( arguments, 1 ),
+ inputIndex = 0,
+ inputLength = input.length,
+ key,
+ value;
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+ };
+
+ $.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName || name;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = widget_slice.call( arguments, 1 ),
+ returnValue = this;
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var methodValue,
+ instance = $.data( this, fullName );
+ if ( options === "instance" ) {
+ returnValue = instance;
+ return false;
+ }
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name + " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+ if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+ }
+ methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ });
+ } else {
+
+ // Allow multiple hashes to be passed on init
+ if ( args.length ) {
+ options = $.widget.extend.apply( null, [ options ].concat(args) );
+ }
+
+ this.each(function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} );
+ if ( instance._init ) {
+ instance._init();
+ }
+ } else {
+ $.data( this, fullName, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+ };
+
+ $.Widget = function( /* options, element */ ) {};
+ $.Widget._childConstructors = [];
+
+ $.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "
",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = widget_uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( arguments.length === 1 ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( arguments.length === 1 ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled", !!value );
+
+ // If the widget is becoming disabled, then nothing is interactive
+ if ( value ) {
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOptions({ disabled: false });
+ },
+ disable: function() {
+ return this._setOptions({ disabled: true });
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement,
+ instance = this;
+
+ // no suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
+ this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+
+ // Clear the stack to avoid memory leaks (#10056)
+ this.bindings = $( this.bindings.not( element ).get() );
+ this.focusable = $( this.focusable.not( element ).get() );
+ this.hoverable = $( this.hoverable.not( element ).get() );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+ };
+
+ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+ });
+
+ var widget = $.widget;
+
+
+
+}));
diff --git a/alarm-analysis/src/main/webapp/public/common/js/jquery.sly.js b/alarm-analysis/src/main/webapp/public/common/js/jquery.sly.js
new file mode 100644
index 00000000..ce3390ff
--- /dev/null
+++ b/alarm-analysis/src/main/webapp/public/common/js/jquery.sly.js
@@ -0,0 +1,1446 @@
+/*!
+ * jQuery Sly v0.9.6
+ * https://github.com/Darsain/sly
+ *
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/MIT
+ */
+
+/*jshint eqeqeq: true, noempty: true, strict: true, undef: true, expr: true, smarttabs: true, browser: true */
+/*global jQuery:false */
+
+;(function($, undefined){
+'use strict';
+
+// Plugin names
+var pluginName = 'sly',
+ namespace = 'plugin_' + pluginName;
+
+/**
+ * Plugin class
+ *
+ * @class
+ * @param {Element} frame DOM element of sly container
+ * @param {Object} o Object with plugin options
+ */
+function Plugin( frame, o ){
+
+ // Alias for this
+ var self = this,
+
+ // Frame variables
+ $frame = $(frame),
+ $slidee = $frame.children().eq(0),
+ frameSize = 0,
+ slideeSize = 0,
+ pos = {
+ cur: 0,
+ max: 0,
+ min: 0
+ },
+
+ // Scrollbar variables
+ $sb = $(o.scrollBar).eq(0),
+ $handle = $sb.length ? $sb.children().eq(0) : 0,
+ sbSize = 0,
+ handleSize = 0,
+ hPos = {
+ cur: 0,
+ max: 0,
+ min: 0
+ },
+
+ // Pagesbar variables
+ $pb = $(o.pagesBar),
+ $pages = 0,
+ pages = [],
+
+ // Navigation type booleans
+ basicNav = o.itemNav === 'basic',
+ smartNav = o.itemNav === 'smart',
+ forceCenteredNav = o.itemNav === 'forceCentered',
+ centeredNav = o.itemNav === 'centered' || forceCenteredNav,
+ itemNav = basicNav || smartNav || centeredNav || forceCenteredNav,
+
+ // Other variables
+ $items = 0,
+ items = [],
+ rel = {
+ firstItem: 0,
+ lastItem: 1,
+ centerItem: 1,
+ activeItem: -1,
+ activePage: 0,
+ items: 0,
+ pages: 0
+ },
+ $scrollSource = o.scrollSource ? $( o.scrollSource ) : $frame,
+ $dragSource = o.dragSource ? $( o.dragSource ) : $frame,
+ $prevButton = $(o.prev),
+ $nextButton = $(o.next),
+ $prevPageButton = $(o.prevPage),
+ $nextPageButton = $(o.nextPage),
+ cycleIndex = 0,
+ cycleIsPaused = 0,
+ isDragging = 0,
+ callbacks = {};
+
+
+ /**
+ * (Re)Loading function
+ *
+ * Populates arrays, sets sizes, binds events, ...
+ *
+ * @public
+ */
+ var load = this.reload = function(){
+
+ // Local variables
+ var ignoredMargin = 0,
+ oldPos = $.extend({}, pos);
+
+ // Clear cycling timeout
+ clearTimeout( cycleIndex );
+
+ // Reset global variables
+ frameSize = o.horizontal ? $frame.width() : $frame.height();
+ sbSize = o.horizontal ? $sb.width() : $sb.height();
+ slideeSize = o.horizontal ? $slidee.outerWidth() : $slidee.outerHeight();
+ $items = $slidee.children();
+ items = [];
+ pages = [];
+
+ // Set position limits & relatives
+ pos.min = 0;
+ pos.max = slideeSize > frameSize ? slideeSize - frameSize : 0;
+ rel.items = $items.length;
+
+ // Sizes & offsets logic, but only when needed
+ if( itemNav ){
+
+ var marginStart = getPx( $items, o.horizontal ? 'marginLeft' : 'marginTop' ),
+ marginEnd = getPx( $items.slice(-1), o.horizontal ? 'marginRight' : 'marginBottom' ),
+ centerOffset = 0,
+ paddingStart = getPx( $slidee, o.horizontal ? 'paddingLeft' : 'paddingTop' ),
+ paddingEnd = getPx( $slidee, o.horizontal ? 'paddingRight' : 'paddingBottom' ),
+ areFloated = $items.css('float') !== 'none';
+
+ // Update ignored margin
+ ignoredMargin = marginStart ? 0 : marginEnd;
+
+ // Reset slideeSize
+ slideeSize = 0;
+
+ // Iterate through items
+ $items.each(function(i,e){
+
+ // Item
+ var item = $(e),
+ itemSize = o.horizontal ? item.outerWidth(true) : item.outerHeight(true),
+ marginTop = getPx( item, 'marginTop' ),
+ marginBottom = getPx( item, 'marginBottom'),
+ marginLeft = getPx( item, 'marginLeft'),
+ marginRight = getPx( item, 'marginRight'),
+ itemObj = {
+ size: itemSize,
+ offStart: slideeSize - ( !i || o.horizontal ? 0 : marginTop ),
+ offCenter: slideeSize - Math.round( frameSize / 2 - itemSize / 2 ),
+ offEnd: slideeSize - frameSize + itemSize - ( marginStart ? 0 : marginRight ),
+ margins: {
+ top: marginTop,
+ bottom: marginBottom,
+ left: marginLeft,
+ right: marginRight
+ }
+ };
+
+ // Account for centerOffset & slidee padding
+ if( !i ){
+ centerOffset = -( forceCenteredNav ? Math.round( frameSize / 2 - itemSize / 2 ) : 0 ) + paddingStart;
+ slideeSize += paddingStart;
+ }
+
+ // Increment slidee size for size of the active element
+ slideeSize += itemSize;
+
+ // Try to account for vertical margin collapsing in vertical mode
+ // It's not bulletproof, but should work in 99% of cases
+ if( !o.horizontal && !areFloated ){
+
+ // Subtract smaller margin, but only when top margin is not 0, and this is not the first element
+ if( marginBottom && marginTop && i > 0 ){
+ slideeSize -= marginTop < marginBottom ? marginTop : marginBottom;
+ }
+
+ }
+
+ // Things to be done at last item
+ if( i === $items.length - 1 ){
+ slideeSize += paddingEnd;
+ }
+
+ // Add item object to items array
+ items.push(itemObj);
+
+ });
+
+ // Resize slidee
+ $slidee.css( o.horizontal ? { width: slideeSize+'px' } : { height: slideeSize+'px' } );
+
+ // Adjust slidee size for last margin
+ slideeSize -= ignoredMargin;
+
+ // Set limits
+ pos.min = centerOffset;
+ pos.max = forceCenteredNav ? items[items.length-1].offCenter : slideeSize > frameSize ? slideeSize - frameSize : 0;
+
+ // Fix overflowing activeItem
+ rel.activeItem >= items.length && self.activate( items.length-1 );
+
+ }
+
+ // Assign relative position indexes
+ assignRelatives();
+
+ // Scrollbar
+ if( $handle ){
+
+ // Stretch scrollbar handle to represent the visible area
+ handleSize = o.dynamicHandle ? Math.round( sbSize * frameSize / slideeSize ) : o.horizontal ? $handle.width() : $handle.height();
+ handleSize = handleSize > sbSize ? sbSize : handleSize;
+ handleSize = handleSize < o.minHandleSize ? o.minHandleSize : handleSize;
+ hPos.max = sbSize - handleSize;
+
+ // Resize handle
+ $handle.css( o.horizontal ? { width: handleSize+'px' } : { height: handleSize+'px' } );
+
+ }
+
+ // Pages
+ var tempPagePos = 0,
+ pagesHtml = '',
+ pageIndex = 0;
+
+ // Populate pages array
+ if( forceCenteredNav ){
+ pages = $.map( items, function( o ){ return o.offCenter; } );
+ } else {
+ while( tempPagePos - frameSize < pos.max ){
+
+ var pagePos = tempPagePos > pos.max ? pos.max : tempPagePos;
+
+ pages.push( pagePos );
+ tempPagePos += frameSize;
+
+ // When item navigation, and last page is smaller than half of the last item size,
+ // adjust the last page position to pos.max and break the loop
+ if( tempPagePos > pos.max && itemNav && pos.max - pagePos < ( items[items.length-1].size - ignoredMargin ) / 2 ){
+
+ pages[pages.length-1] = pos.max;
+ break;
+
+ }
+
+ }
+ }
+
+ // Pages bar
+ if( $pb.length ){
+
+ for( var i = 0; i < pages.length; i++ ){
+ pagesHtml += o.pageBuilder( pageIndex++ );
+ }
+
+ // Bind page navigation, append to pagesbar, and save to $pages variable
+ $pages = $(pagesHtml).bind('click.' + namespace, function(){
+
+ self.activatePage( $pages.index(this) );
+
+ }).appendTo( $pb.empty() );
+
+ }
+
+ // Bind activating to items
+ $items.unbind('.' + namespace).bind('mouseup.' + namespace, function(e){
+
+ e.which === 1 && !isDragging && self.activate( this );
+
+ });
+
+ // Fix overflowing
+ pos.cur < pos.min && slide( pos.min );
+ pos.cur > pos.max && slide( pos.max );
+
+ // Extend relative variables object with some useful info
+ rel.pages = pages.length;
+ rel.slideeSize = slideeSize;
+ rel.frameSize = frameSize;
+ rel.sbSize = sbSize;
+ rel.handleSize = handleSize;
+
+ // Synchronize scrollbar
+ syncBars(0);
+
+ // Disable buttons
+ disableButtons();
+
+ // Automatic cycling
+ if( itemNav && o.cycleBy ){
+
+ var pauseEvents = 'mouseenter.' + namespace + ' mouseleave.' + namespace;
+
+ // Pause on hover
+ o.pauseOnHover && $frame.unbind(pauseEvents).bind(pauseEvents, function(e){
+
+ !cycleIsPaused && self.cycle( e.type === 'mouseenter', 1 );
+
+ });
+
+ // Initiate cycling
+ self.cycle( o.startPaused );
+
+ }
+
+ // Trigger :load event
+ $frame.trigger( pluginName + ':load', [ $.extend({}, pos, { old: oldPos }), $items, rel ] );
+
+ };
+
+
+ /**
+ * Slide the slidee
+ *
+ * @private
+ *
+ * @param {Int} newPos New slidee position in relation to frame
+ * @param {Bool} align Whetner to Align elements to the frame border
+ * @param {Int} speed Animation speed in milliseconds
+ */
+ function slide( newPos, align, speed ){
+
+ speed = isNumber( speed ) ? speed : o.speed;
+
+ // Align items
+ if( align && itemNav ){
+
+ var tempRel = getRelatives( newPos );
+
+ if( centeredNav ){
+
+ newPos = items[tempRel.centerItem].offCenter;
+ self[ forceCenteredNav ? 'activate' : 'toCenter']( tempRel.centerItem, 1 );
+
+ } else if( newPos > pos.min && newPos < pos.max ){
+
+ newPos = items[tempRel.firstItem].offStart;
+
+ }
+
+ }
+
+ // Fix overflowing position
+ if( !isDragging || !o.elasticBounds ){
+ newPos = newPos < pos.min ? pos.min : newPos;
+ newPos = newPos > pos.max ? pos.max : newPos;
+ }
+
+ // Stop if position has not changed
+ if( newPos === pos.cur ) {
+ return;
+ } else {
+ pos.cur = newPos;
+ }
+
+ // Reassign relative indexes
+ assignRelatives();
+
+ // Add disabled classes
+ disableButtons();
+
+ // halt ongoing animations
+ stop();
+
+ // Trigger :move event
+ !isDragging && $frame.trigger( pluginName + ':move', [ pos, $items, rel ] );
+
+ var newProp = o.horizontal ? { left: -pos.cur+'px' } : { top: -pos.cur+'px' };
+
+ // Slidee move
+ if( speed > 16 ){
+
+ $slidee.animate( newProp, speed, isDragging ? 'swing' : o.easing, function(e){
+
+ // Trigger :moveEnd event
+ !isDragging && $frame.trigger( pluginName + ':moveEnd', [ pos, $items, rel ] );
+
+ });
+
+ } else {
+
+ $slidee.css( newProp );
+
+ // Trigger :moveEnd event
+ !isDragging && $frame.trigger( pluginName + ':moveEnd', [ pos, $items, rel ] );
+
+ }
+
+ }
+
+
+ /**
+ * Synchronizes scrollbar & pagesbar positions with the slidee
+ *
+ * @private
+ *
+ * @param {Int} speed Animation speed for scrollbar synchronization
+ */
+ function syncBars( speed ){
+
+ // Scrollbar synchronization
+ if ($handle) {
+
+ hPos.cur = Math.round( ( pos.cur - pos.min ) / ( pos.max - pos.min ) * hPos.max );
+ hPos.cur = hPos.cur < hPos.min ? hPos.min : hPos.cur > hPos.max ? hPos.max : hPos.cur;
+ $handle.stop().animate( o.horizontal ? { left: hPos.cur+'px' } : { top: hPos.cur+'px' }, isNumber(speed) ? speed : o.speed, o.easing );
+
+ }
+
+ // Pagesbar synchronization
+ syncPages();
+
+ }
+
+
+ /**
+ * Synchronizes pagesbar
+ *
+ * @private
+ */
+ function syncPages(){
+
+ if (!$pages.length) {
+ return;
+ }
+
+ // Classes
+ $pages.removeClass(o.activeClass).eq(rel.activePage).addClass(o.activeClass);
+
+ }
+
+
+ /**
+ * Activate previous item
+ *
+ * @public
+ */
+ this.prev = function(){
+
+ self.activate( rel.activeItem - 1 );
+
+ };
+
+
+ /**
+ * Activate next item
+ *
+ * @public
+ */
+ this.next = function(){
+
+ self.activate( rel.activeItem + 1 );
+
+ };
+
+
+ /**
+ * Activate previous page
+ *
+ * @public
+ */
+ this.prevPage = function(){
+
+ self.activatePage( rel.activePage - 1 );
+
+ };
+
+
+ /**
+ * Activate next page
+ *
+ * @public
+ */
+ this.nextPage = function(){
+
+ self.activatePage( rel.activePage + 1 );
+
+ };
+
+
+ /**
+ * Stop ongoing animations
+ *
+ * @private
+ */
+ function stop(){
+
+ $slidee.add($handle).stop();
+
+ }
+
+
+ /**
+ * Animate element or the whole slidee to the start of the frame
+ *
+ * @public
+ *
+ * @param {Element|Int} el DOM element, or index of element in items array
+ */
+ this.toStart = function( el ){
+
+ if( itemNav ){
+
+ var index = getIndex( el );
+
+ if( el === undefined ){
+
+ slide( pos.min, 1 );
+
+ } else if( index !== -1 ){
+
+ // You can't align items to the start of the frame when centeredNav is enabled
+ if (centeredNav) {
+ return;
+ }
+
+ index !== -1 && slide( items[index].offStart );
+
+ }
+
+ } else {
+
+ if( el === undefined ){
+
+ slide( pos.min );
+
+ } else {
+
+ var $el = $slidee.find(el).eq(0);
+
+ if( $el.length ){
+
+ var offset = o.horizontal ? $el.offset().left - $slidee.offset().left : $el.offset().top - $slidee.offset().top;
+
+ slide( offset );
+
+ }
+
+ }
+
+ }
+
+ syncBars();
+
+ };
+
+
+ /**
+ * Animate element or the whole slidee to the end of the frame
+ *
+ * @public
+ *
+ * @param {Element|Int} el DOM element, or index of element in items array
+ */
+ this.toEnd = function( el ){
+
+ if( itemNav ){
+
+ var index = getIndex( el );
+
+ if( el === undefined ){
+
+ slide( pos.max, 1 );
+
+ } else if( index !== -1 ){
+
+ // You can't align items to the end of the frame when centeredNav is enabled
+ if (centeredNav) {
+ return;
+ }
+
+ slide( items[index].offEnd );
+
+ }
+
+ } else {
+
+ if( el === undefined ){
+
+ slide( pos.max );
+
+ } else {
+
+ var $el = $slidee.find(el).eq(0);
+
+ if( $el.length ){
+
+ var offset = o.horizontal ? $el.offset().left - $slidee.offset().left : $el.offset().top - $slidee.offset().top;
+
+ slide( offset - frameSize + $el[o.horizontal ? 'outerWidth' : 'outerHeight']() );
+
+ }
+
+ }
+
+ }
+
+ syncBars();
+
+ };
+
+
+ /**
+ * Animate element or the whole slidee to the center of the frame
+ *
+ * @public
+ *
+ * @param {Element|Int} el DOM element, or index of element in items array
+ */
+ this.toCenter = function( el ){
+
+ if( itemNav ){
+
+ var index = getIndex( el );
+
+ if( el === undefined ){
+
+ slide( Math.round( pos.max / 2 + pos.min / 2 ), 1 );
+
+ } else if( index !== -1 ){
+
+ slide( items[index].offCenter );
+ forceCenteredNav && self.activate( index, 1 );
+
+ }
+
+ } else {
+
+ if( el === undefined ){
+
+ slide( Math.round( pos.max / 2 ) );
+
+ } else {
+
+ var $el = $slidee.find(el).eq(0);
+
+ if( $el.length ){
+
+ var offset = o.horizontal ? $el.offset().left - $slidee.offset().left : $el.offset().top - $slidee.offset().top;
+
+ slide( offset - frameSize / 2 + $el[o.horizontal ? 'outerWidth' : 'outerHeight']() / 2 );
+
+ }
+
+ }
+
+
+ }
+
+ syncBars();
+
+ };
+
+
+ /**
+ * Get an index of the element
+ *
+ * @private
+ *
+ * @param {Element|Int} el DOM element, or index of element in items array
+ */
+ function getIndex( el ){
+
+ return isNumber(el) ? el < 0 ? 0 : el > items.length-1 ? items.length-1 : el : el === undefined ? -1 : $items.index( el );
+
+ }
+
+
+ /**
+ * Parse style to pixels
+ *
+ * @private
+ *
+ * @param {Object} $item jQuery object with element
+ * @param {Property} property Property to get the pixels from
+ */
+ function getPx( $item, property ){
+
+ return parseInt( $item.css( property ), 10 );
+
+ }
+
+
+ /**
+ * Activates an element
+ *
+ * Element is positioned to one of the sides of the frame, based on it's current position.
+ * If the element is close to the right frame border, it will be animated to the start of the left border,
+ * and vice versa. This helps user to navigate through the elements only by clicking on them, without
+ * the need for navigation buttons, scrolling, or keyboard arrows.
+ *
+ * @public
+ *
+ * @param {Element|Int} el DOM element, or index of element in items array
+ * @param {Bool} noReposition Activate item without repositioning it
+ */
+ this.activate = function( el, noReposition ){
+
+ if (!itemNav || el === undefined) {
+ return;
+ }
+
+ var index = getIndex( el ),
+ oldActive = rel.activeItem;
+
+ // Update activeItem index
+ rel.activeItem = index;
+
+ // Add active class to the active element
+ $items.removeClass(o.activeClass).eq(index).addClass(o.activeClass);
+
+ // Trigget :active event if a new element is being activated
+ index !== oldActive && $items.eq( index ).trigger( pluginName + ':active', [ $items, rel ] );
+
+ if( !noReposition ){
+
+ // When centeredNav is enabled, center the element
+ if( centeredNav ){
+
+ self.toCenter( index );
+
+ // Otherwise determine where to position the element
+ } else if( smartNav ) {
+
+ // If activated element is currently on the far right side of the frame, assume that
+ // user is moving forward and animate it to the start of the visible frame, and vice versa
+ if (index >= rel.lastItem) {
+ self.toStart(index);
+ } else if (index <= rel.firstItem) {
+ self.toEnd(index);
+ }
+
+ }
+
+ }
+
+ // Add disabled classes
+ disableButtons();
+
+ };
+
+
+ /**
+ * Activates a page
+ *
+ * @public
+ *
+ * @param {Int} index Page index, starting from 0
+ */
+ this.activatePage = function( index ){
+
+ // Fix overflowing
+ index = index < 0 ? 0 : index >= pages.length ? pages.length-1 : index;
+ slide( pages[index], itemNav );
+
+ syncBars();
+
+ };
+
+
+ /**
+ * Return relative positions of items based on their location within visible frame
+ *
+ * @private
+ *
+ * @param {Int} sPos Position of slidee
+ */
+ function getRelatives( sPos ){
+
+ var newRel = {},
+ centerOffset = forceCenteredNav ? 0 : frameSize / 2;
+
+ // Determine active page
+ for( var p = 0; p < pages.length; p++ ){
+
+ if( sPos >= pos.max || p === pages.length - 1 ){
+ newRel.activePage = pages.length - 1;
+ break;
+ }
+
+ if( sPos <= pages[p] + centerOffset ){
+ newRel.activePage = p;
+ break;
+ }
+
+ }
+
+ // Relative item indexes
+ if( itemNav ){
+
+ var first = false,
+ last = false,
+ center = false;
+
+ /* From start */
+ for( var i=0; i < items.length; i++ ){
+
+ // First item
+ if (first === false && sPos <= items[i].offStart) {
+ first = i;
+ }
+
+ // Centered item
+ if (center === false && sPos - items[i].size / 2 <= items[i].offCenter) {
+ center = i;
+ }
+
+ // Last item
+ if (i === items.length - 1 || (last === false && sPos < items[i + 1].offEnd)) {
+ last = i;
+ }
+
+ // Terminate if all are assigned
+ if (last !== false) {
+ break;
+ }
+
+ }
+
+ // Safe assignment, just to be sure the false won't be returned
+ newRel.firstItem = isNumber( first ) ? first : 0;
+ newRel.centerItem = isNumber( center ) ? center : newRel.firstItem;
+ newRel.lastItem = isNumber( last ) ? last : newRel.centerItem;
+
+ }
+
+ return newRel;
+
+ }
+
+
+ /**
+ * Assign element indexes to the relative positions
+ *
+ * @private
+ */
+ function assignRelatives(){
+
+ $.extend( rel, getRelatives( pos.cur ) );
+
+ }
+
+
+ /**
+ * Disable buttons when needed
+ *
+ * Adds disabledClass, and when the button is