",
+ 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;
+
+
+/*!
+ * jQuery UI Mouse 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/mouse/
+ */
+
+
+var mouseHandled = false;
+$( document ).mouseup( function() {
+ mouseHandled = false;
+});
+
+var mouse = $.widget("ui.mouse", {
+ version: "1.11.4",
+ options: {
+ cancel: "input,textarea,button,select,option",
+ distance: 1,
+ delay: 0
+ },
+ _mouseInit: function() {
+ var that = this;
+
+ this.element
+ .bind("mousedown." + this.widgetName, function(event) {
+ return that._mouseDown(event);
+ })
+ .bind("click." + this.widgetName, function(event) {
+ if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, that.widgetName + ".preventClickEvent");
+ event.stopImmediatePropagation();
+ return false;
+ }
+ });
+
+ this.started = false;
+ },
+
+ // TODO: make sure destroying one instance of mouse doesn't mess with
+ // other instances of mouse
+ _mouseDestroy: function() {
+ this.element.unbind("." + this.widgetName);
+ if ( this._mouseMoveDelegate ) {
+ this.document
+ .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
+ }
+ },
+
+ _mouseDown: function(event) {
+ // don't let more than one widget handle mouseStart
+ if ( mouseHandled ) {
+ return;
+ }
+
+ this._mouseMoved = false;
+
+ // we may have missed mouseup (out of window)
+ (this._mouseStarted && this._mouseUp(event));
+
+ this._mouseDownEvent = event;
+
+ var that = this,
+ btnIsLeft = (event.which === 1),
+ // event.target.nodeName works around a bug in IE 8 with
+ // disabled inputs (#7620)
+ elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
+ if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+ return true;
+ }
+
+ this.mouseDelayMet = !this.options.delay;
+ if (!this.mouseDelayMet) {
+ this._mouseDelayTimer = setTimeout(function() {
+ that.mouseDelayMet = true;
+ }, this.options.delay);
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted = (this._mouseStart(event) !== false);
+ if (!this._mouseStarted) {
+ event.preventDefault();
+ return true;
+ }
+ }
+
+ // Click event may never have fired (Gecko & Opera)
+ if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, this.widgetName + ".preventClickEvent");
+ }
+
+ // these delegates are required to keep context
+ this._mouseMoveDelegate = function(event) {
+ return that._mouseMove(event);
+ };
+ this._mouseUpDelegate = function(event) {
+ return that._mouseUp(event);
+ };
+
+ this.document
+ .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
+ .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
+
+ event.preventDefault();
+
+ mouseHandled = true;
+ return true;
+ },
+
+ _mouseMove: function(event) {
+ // Only check for mouseups outside the document if you've moved inside the document
+ // at least once. This prevents the firing of mouseup in the case of IE<9, which will
+ // fire a mousemove event if content is placed under the cursor. See #7778
+ // Support: IE <9
+ if ( this._mouseMoved ) {
+ // IE mouseup check - mouseup happened when mouse was out of window
+ if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
+ return this._mouseUp(event);
+
+ // Iframe mouseup check - mouseup occurred in another document
+ } else if ( !event.which ) {
+ return this._mouseUp( event );
+ }
+ }
+
+ if ( event.which || event.button ) {
+ this._mouseMoved = true;
+ }
+
+ if (this._mouseStarted) {
+ this._mouseDrag(event);
+ return event.preventDefault();
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted =
+ (this._mouseStart(this._mouseDownEvent, event) !== false);
+ (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+ }
+
+ return !this._mouseStarted;
+ },
+
+ _mouseUp: function(event) {
+ this.document
+ .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
+ .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
+
+ if (this._mouseStarted) {
+ this._mouseStarted = false;
+
+ if (event.target === this._mouseDownEvent.target) {
+ $.data(event.target, this.widgetName + ".preventClickEvent", true);
+ }
+
+ this._mouseStop(event);
+ }
+
+ mouseHandled = false;
+ return false;
+ },
+
+ _mouseDistanceMet: function(event) {
+ return (Math.max(
+ Math.abs(this._mouseDownEvent.pageX - event.pageX),
+ Math.abs(this._mouseDownEvent.pageY - event.pageY)
+ ) >= this.options.distance
+ );
+ },
+
+ _mouseDelayMet: function(/* event */) {
+ return this.mouseDelayMet;
+ },
+
+ // These are placeholder methods, to be overriden by extending plugin
+ _mouseStart: function(/* event */) {},
+ _mouseDrag: function(/* event */) {},
+ _mouseStop: function(/* event */) {},
+ _mouseCapture: function(/* event */) { return true; }
+});
+
+
+/*!
+ * jQuery UI Sortable 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/sortable/
+ */
+
+
+var sortable = $.widget("ui.sortable", $.ui.mouse, {
+ version: "1.11.4",
+ widgetEventPrefix: "sort",
+ ready: false,
+ options: {
+ appendTo: "parent",
+ axis: false,
+ connectWith: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ dropOnEmpty: true,
+ forcePlaceholderSize: false,
+ forceHelperSize: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ items: "> *",
+ opacity: false,
+ placeholder: false,
+ revert: false,
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ scope: "default",
+ tolerance: "intersect",
+ zIndex: 1000,
+
+ // callbacks
+ activate: null,
+ beforeStop: null,
+ change: null,
+ deactivate: null,
+ out: null,
+ over: null,
+ receive: null,
+ remove: null,
+ sort: null,
+ start: null,
+ stop: null,
+ update: null
+ },
+
+ _isOverAxis: function( x, reference, size ) {
+ return ( x >= reference ) && ( x < ( reference + size ) );
+ },
+
+ _isFloating: function( item ) {
+ return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
+ },
+
+ _create: function() {
+ this.containerCache = {};
+ this.element.addClass("ui-sortable");
+
+ //Get the items
+ this.refresh();
+
+ //Let's determine the parent's offset
+ this.offset = this.element.offset();
+
+ //Initialize mouse events for interaction
+ this._mouseInit();
+
+ this._setHandleClassName();
+
+ //We're ready to go
+ this.ready = true;
+
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+
+ if ( key === "handle" ) {
+ this._setHandleClassName();
+ }
+ },
+
+ _setHandleClassName: function() {
+ this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
+ $.each( this.items, function() {
+ ( this.instance.options.handle ?
+ this.item.find( this.instance.options.handle ) : this.item )
+ .addClass( "ui-sortable-handle" );
+ });
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-sortable ui-sortable-disabled" )
+ .find( ".ui-sortable-handle" )
+ .removeClass( "ui-sortable-handle" );
+ this._mouseDestroy();
+
+ for ( var i = this.items.length - 1; i >= 0; i-- ) {
+ this.items[i].item.removeData(this.widgetName + "-item");
+ }
+
+ return this;
+ },
+
+ _mouseCapture: function(event, overrideHandle) {
+ var currentItem = null,
+ validHandle = false,
+ that = this;
+
+ if (this.reverting) {
+ return false;
+ }
+
+ if(this.options.disabled || this.options.type === "static") {
+ return false;
+ }
+
+ //We have to refresh the items data once first
+ this._refreshItems(event);
+
+ //Find out if the clicked node (or one of its parents) is a actual item in this.items
+ $(event.target).parents().each(function() {
+ if($.data(this, that.widgetName + "-item") === that) {
+ currentItem = $(this);
+ return false;
+ }
+ });
+ if($.data(event.target, that.widgetName + "-item") === that) {
+ currentItem = $(event.target);
+ }
+
+ if(!currentItem) {
+ return false;
+ }
+ if(this.options.handle && !overrideHandle) {
+ $(this.options.handle, currentItem).find("*").addBack().each(function() {
+ if(this === event.target) {
+ validHandle = true;
+ }
+ });
+ if(!validHandle) {
+ return false;
+ }
+ }
+
+ this.currentItem = currentItem;
+ this._removeCurrentsFromItems();
+ return true;
+
+ },
+
+ _mouseStart: function(event, overrideHandle, noActivation) {
+
+ var i, body,
+ o = this.options;
+
+ this.currentContainer = this;
+
+ //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+ this.refreshPositions();
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Get the next scrolling parent
+ this.scrollParent = this.helper.scrollParent();
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.currentItem.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ // Only after we got the offset, we can change the helper's position to absolute
+ // TODO: Still need to figure out a way to make relative sorting possible
+ this.helper.css("position", "absolute");
+ this.cssPosition = this.helper.css("position");
+
+ //Generate the original position
+ this.originalPosition = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Cache the former DOM position
+ this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+ //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.currentItem.hide();
+ }
+
+ //Create the placeholder
+ this._createPlaceholder();
+
+ //Set a containment if given in the options
+ if(o.containment) {
+ this._setContainment();
+ }
+
+ if( o.cursor && o.cursor !== "auto" ) { // cursor option
+ body = this.document.find( "body" );
+
+ // support: IE
+ this.storedCursor = body.css( "cursor" );
+ body.css( "cursor", o.cursor );
+
+ this.storedStylesheet = $( "" ).appendTo( body );
+ }
+
+ if(o.opacity) { // opacity option
+ if (this.helper.css("opacity")) {
+ this._storedOpacity = this.helper.css("opacity");
+ }
+ this.helper.css("opacity", o.opacity);
+ }
+
+ if(o.zIndex) { // zIndex option
+ if (this.helper.css("zIndex")) {
+ this._storedZIndex = this.helper.css("zIndex");
+ }
+ this.helper.css("zIndex", o.zIndex);
+ }
+
+ //Prepare scrolling
+ if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
+ this.overflowOffset = this.scrollParent.offset();
+ }
+
+ //Call callbacks
+ this._trigger("start", event, this._uiHash());
+
+ //Recache the helper size
+ if(!this._preserveHelperProportions) {
+ this._cacheHelperProportions();
+ }
+
+
+ //Post "activate" events to possible containers
+ if( !noActivation ) {
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
+ this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
+ }
+ }
+
+ //Prepare possible droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+ this.dragging = true;
+
+ this.helper.addClass("ui-sortable-helper");
+ this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+ return true;
+
+ },
+
+ _mouseDrag: function(event) {
+ var i, item, itemElement, intersection,
+ o = this.options,
+ scrolled = false;
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ if (!this.lastPositionAbs) {
+ this.lastPositionAbs = this.positionAbs;
+ }
+
+ //Do scrolling
+ if(this.options.scroll) {
+ if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
+
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+
+ } else {
+
+ if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
+ scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
+ } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
+ scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
+ }
+
+ if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
+ scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
+ } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
+ scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+ }
+
+ //Regenerate the absolute position used for position checks
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Set the helper position
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+
+ //Rearrange
+ for (i = this.items.length - 1; i >= 0; i--) {
+
+ //Cache variables and intersection, continue if no intersection
+ item = this.items[i];
+ itemElement = item.item[0];
+ intersection = this._intersectsWithPointer(item);
+ if (!intersection) {
+ continue;
+ }
+
+ // Only put the placeholder inside the current Container, skip all
+ // items from other containers. This works because when moving
+ // an item from one container to another the
+ // currentContainer is switched before the placeholder is moved.
+ //
+ // Without this, moving items in "sub-sortables" can cause
+ // the placeholder to jitter between the outer and inner container.
+ if (item.instance !== this.currentContainer) {
+ continue;
+ }
+
+ // cannot intersect with itself
+ // no useless actions that have been done before
+ // no action if the item moved is the parent of the item checked
+ if (itemElement !== this.currentItem[0] &&
+ this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
+ !$.contains(this.placeholder[0], itemElement) &&
+ (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
+ ) {
+
+ this.direction = intersection === 1 ? "down" : "up";
+
+ if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
+ this._rearrange(event, item);
+ } else {
+ break;
+ }
+
+ this._trigger("change", event, this._uiHash());
+ break;
+ }
+ }
+
+ //Post events to containers
+ this._contactContainers(event);
+
+ //Interconnect with droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ //Call callbacks
+ this._trigger("sort", event, this._uiHash());
+
+ this.lastPositionAbs = this.positionAbs;
+ return false;
+
+ },
+
+ _mouseStop: function(event, noPropagation) {
+
+ if(!event) {
+ return;
+ }
+
+ //If we are using droppables, inform the manager about the drop
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ $.ui.ddmanager.drop(this, event);
+ }
+
+ if(this.options.revert) {
+ var that = this,
+ cur = this.placeholder.offset(),
+ axis = this.options.axis,
+ animation = {};
+
+ if ( !axis || axis === "x" ) {
+ animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
+ }
+ if ( !axis || axis === "y" ) {
+ animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
+ }
+ this.reverting = true;
+ $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
+ that._clear(event);
+ });
+ } else {
+ this._clear(event, noPropagation);
+ }
+
+ return false;
+
+ },
+
+ cancel: function() {
+
+ if(this.dragging) {
+
+ this._mouseUp({ target: null });
+
+ if(this.options.helper === "original") {
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ //Post deactivating events to containers
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ this.containers[i]._trigger("deactivate", null, this._uiHash(this));
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", null, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ if (this.placeholder) {
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ if(this.placeholder[0].parentNode) {
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+ }
+ if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
+ this.helper.remove();
+ }
+
+ $.extend(this, {
+ helper: null,
+ dragging: false,
+ reverting: false,
+ _noFinalSort: null
+ });
+
+ if(this.domPosition.prev) {
+ $(this.domPosition.prev).after(this.currentItem);
+ } else {
+ $(this.domPosition.parent).prepend(this.currentItem);
+ }
+ }
+
+ return this;
+
+ },
+
+ serialize: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ str = [];
+ o = o || {};
+
+ $(items).each(function() {
+ var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
+ if (res) {
+ str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
+ }
+ });
+
+ if(!str.length && o.key) {
+ str.push(o.key + "=");
+ }
+
+ return str.join("&");
+
+ },
+
+ toArray: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ ret = [];
+
+ o = o || {};
+
+ items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
+ return ret;
+
+ },
+
+ /* Be careful with the following core functions */
+ _intersectsWith: function(item) {
+
+ var x1 = this.positionAbs.left,
+ x2 = x1 + this.helperProportions.width,
+ y1 = this.positionAbs.top,
+ y2 = y1 + this.helperProportions.height,
+ l = item.left,
+ r = l + item.width,
+ t = item.top,
+ b = t + item.height,
+ dyClick = this.offset.click.top,
+ dxClick = this.offset.click.left,
+ isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
+ isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
+ isOverElement = isOverElementHeight && isOverElementWidth;
+
+ if ( this.options.tolerance === "pointer" ||
+ this.options.forcePointerForContainers ||
+ (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
+ ) {
+ return isOverElement;
+ } else {
+
+ return (l < x1 + (this.helperProportions.width / 2) && // Right Half
+ x2 - (this.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (this.helperProportions.height / 2) && // Bottom Half
+ y2 - (this.helperProportions.height / 2) < b ); // Top Half
+
+ }
+ },
+
+ _intersectsWithPointer: function(item) {
+
+ var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+ isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+ isOverElement = isOverElementHeight && isOverElementWidth,
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (!isOverElement) {
+ return false;
+ }
+
+ return this.floating ?
+ ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
+ : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
+
+ },
+
+ _intersectsWithSides: function(item) {
+
+ var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+ isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (this.floating && horizontalDirection) {
+ return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
+ } else {
+ return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
+ }
+
+ },
+
+ _getDragVerticalDirection: function() {
+ var delta = this.positionAbs.top - this.lastPositionAbs.top;
+ return delta !== 0 && (delta > 0 ? "down" : "up");
+ },
+
+ _getDragHorizontalDirection: function() {
+ var delta = this.positionAbs.left - this.lastPositionAbs.left;
+ return delta !== 0 && (delta > 0 ? "right" : "left");
+ },
+
+ refresh: function(event) {
+ this._refreshItems(event);
+ this._setHandleClassName();
+ this.refreshPositions();
+ return this;
+ },
+
+ _connectWith: function() {
+ var options = this.options;
+ return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
+ },
+
+ _getItemsAsjQuery: function(connected) {
+
+ var i, j, cur, inst,
+ items = [],
+ queries = [],
+ connectWith = this._connectWith();
+
+ if(connectWith && connected) {
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i], this.document[0]);
+ for ( j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
+ }
+ }
+ }
+ }
+
+ queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
+
+ function addItems() {
+ items.push( this );
+ }
+ for (i = queries.length - 1; i >= 0; i--){
+ queries[i][0].each( addItems );
+ }
+
+ return $(items);
+
+ },
+
+ _removeCurrentsFromItems: function() {
+
+ var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
+
+ this.items = $.grep(this.items, function (item) {
+ for (var j=0; j < list.length; j++) {
+ if(list[j] === item.item[0]) {
+ return false;
+ }
+ }
+ return true;
+ });
+
+ },
+
+ _refreshItems: function(event) {
+
+ this.items = [];
+ this.containers = [this];
+
+ var i, j, cur, inst, targetData, _queries, item, queriesLength,
+ items = this.items,
+ queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
+ connectWith = this._connectWith();
+
+ if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i], this.document[0]);
+ for (j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+ this.containers.push(inst);
+ }
+ }
+ }
+ }
+
+ for (i = queries.length - 1; i >= 0; i--) {
+ targetData = queries[i][1];
+ _queries = queries[i][0];
+
+ for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+ item = $(_queries[j]);
+
+ item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
+
+ items.push({
+ item: item,
+ instance: targetData,
+ width: 0, height: 0,
+ left: 0, top: 0
+ });
+ }
+ }
+
+ },
+
+ refreshPositions: function(fast) {
+
+ // Determine whether items are being displayed horizontally
+ this.floating = this.items.length ?
+ this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
+ false;
+
+ //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+ if(this.offsetParent && this.helper) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ var i, item, t, p;
+
+ for (i = this.items.length - 1; i >= 0; i--){
+ item = this.items[i];
+
+ //We ignore calculating positions of all connected containers when we're not over them
+ if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
+ continue;
+ }
+
+ t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+ if (!fast) {
+ item.width = t.outerWidth();
+ item.height = t.outerHeight();
+ }
+
+ p = t.offset();
+ item.left = p.left;
+ item.top = p.top;
+ }
+
+ if(this.options.custom && this.options.custom.refreshContainers) {
+ this.options.custom.refreshContainers.call(this);
+ } else {
+ for (i = this.containers.length - 1; i >= 0; i--){
+ p = this.containers[i].element.offset();
+ this.containers[i].containerCache.left = p.left;
+ this.containers[i].containerCache.top = p.top;
+ this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
+ this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
+ }
+ }
+
+ return this;
+ },
+
+ _createPlaceholder: function(that) {
+ that = that || this;
+ var className,
+ o = that.options;
+
+ if(!o.placeholder || o.placeholder.constructor === String) {
+ className = o.placeholder;
+ o.placeholder = {
+ element: function() {
+
+ var nodeName = that.currentItem[0].nodeName.toLowerCase(),
+ element = $( "<" + nodeName + ">", that.document[0] )
+ .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
+ .removeClass("ui-sortable-helper");
+
+ if ( nodeName === "tbody" ) {
+ that._createTrPlaceholder(
+ that.currentItem.find( "tr" ).eq( 0 ),
+ $( "
", that.document[ 0 ] ).appendTo( element )
+ );
+ } else if ( nodeName === "tr" ) {
+ that._createTrPlaceholder( that.currentItem, element );
+ } else if ( nodeName === "img" ) {
+ element.attr( "src", that.currentItem.attr( "src" ) );
+ }
+
+ if ( !className ) {
+ element.css( "visibility", "hidden" );
+ }
+
+ return element;
+ },
+ update: function(container, p) {
+
+ // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
+ if(className && !o.forcePlaceholderSize) {
+ return;
+ }
+
+ //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
+ if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
+ if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
+ }
+ };
+ }
+
+ //Create the placeholder
+ that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
+
+ //Append it after the actual current item
+ that.currentItem.after(that.placeholder);
+
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+ o.placeholder.update(that, that.placeholder);
+
+ },
+
+ _createTrPlaceholder: function( sourceTr, targetTr ) {
+ var that = this;
+
+ sourceTr.children().each(function() {
+ $( " | ", that.document[ 0 ] )
+ .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
+ .appendTo( targetTr );
+ });
+ },
+
+ _contactContainers: function(event) {
+ var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
+ innermostContainer = null,
+ innermostIndex = null;
+
+ // get innermost container that intersects with item
+ for (i = this.containers.length - 1; i >= 0; i--) {
+
+ // never consider a container that's located within the item itself
+ if($.contains(this.currentItem[0], this.containers[i].element[0])) {
+ continue;
+ }
+
+ if(this._intersectsWith(this.containers[i].containerCache)) {
+
+ // if we've already found a container and it's more "inner" than this, then continue
+ if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
+ continue;
+ }
+
+ innermostContainer = this.containers[i];
+ innermostIndex = i;
+
+ } else {
+ // container doesn't intersect. trigger "out" event if necessary
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", event, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ // if no intersecting containers found, return
+ if(!innermostContainer) {
+ return;
+ }
+
+ // move the item into the container if it's not there already
+ if(this.containers.length === 1) {
+ if (!this.containers[innermostIndex].containerCache.over) {
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+ } else {
+
+ //When entering a new container, we will find the item with the least distance and append our item near it
+ dist = 10000;
+ itemWithLeastDistance = null;
+ floating = innermostContainer.floating || this._isFloating(this.currentItem);
+ posProperty = floating ? "left" : "top";
+ sizeProperty = floating ? "width" : "height";
+ axis = floating ? "clientX" : "clientY";
+
+ for (j = this.items.length - 1; j >= 0; j--) {
+ if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
+ continue;
+ }
+ if(this.items[j].item[0] === this.currentItem[0]) {
+ continue;
+ }
+
+ cur = this.items[j].item.offset()[posProperty];
+ nearBottom = false;
+ if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
+ nearBottom = true;
+ }
+
+ if ( Math.abs( event[ axis ] - cur ) < dist ) {
+ dist = Math.abs( event[ axis ] - cur );
+ itemWithLeastDistance = this.items[ j ];
+ this.direction = nearBottom ? "up": "down";
+ }
+ }
+
+ //Check if dropOnEmpty is enabled
+ if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
+ return;
+ }
+
+ if(this.currentContainer === this.containers[innermostIndex]) {
+ if ( !this.currentContainer.containerCache.over ) {
+ this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
+ this.currentContainer.containerCache.over = 1;
+ }
+ return;
+ }
+
+ itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
+ this._trigger("change", event, this._uiHash());
+ this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+ this.currentContainer = this.containers[innermostIndex];
+
+ //Update the placeholder
+ this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+
+
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
+
+ //Add the helper to the DOM if that didn't happen already
+ if(!helper.parents("body").length) {
+ $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+ }
+
+ if(helper[0] === this.currentItem[0]) {
+ this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+ }
+
+ if(!helper[0].style.width || o.forceHelperSize) {
+ helper.width(this.currentItem.width());
+ }
+ if(!helper[0].style.height || o.forceHelperSize) {
+ helper.height(this.currentItem.height());
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+
+ //Get the offsetParent and cache its position
+ this.offsetParent = this.helper.offsetParent();
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ // This needs to be actually done for all browsers, since pageX/pageY includes this information
+ // with an ugly IE fix
+ if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.currentItem.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+ top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var ce, co, over,
+ o = this.options;
+ if(o.containment === "parent") {
+ o.containment = this.helper[0].parentNode;
+ }
+ if(o.containment === "document" || o.containment === "window") {
+ this.containment = [
+ 0 - this.offset.relative.left - this.offset.parent.left,
+ 0 - this.offset.relative.top - this.offset.parent.top,
+ o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
+ (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ if(!(/^(document|window|parent)$/).test(o.containment)) {
+ ce = $(o.containment)[0];
+ co = $(o.containment).offset();
+ over = ($(ce).css("overflow") !== "hidden");
+
+ this.containment = [
+ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+ co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+ co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
+ co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
+ scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var top, left,
+ o = this.options,
+ pageX = event.pageX,
+ pageY = event.pageY,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ // This is another very weird special case that only happens for relative elements:
+ // 1. If the css position is relative
+ // 2. and the scroll parent is the document or similar to the offset parent
+ // we have to refresh the relative offset during the scroll so there are no jumps
+ if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
+ this.offset.relative = this._getRelativeOffset();
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+
+ if(this.containment) {
+ if(event.pageX - this.offset.click.left < this.containment[0]) {
+ pageX = this.containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < this.containment[1]) {
+ pageY = this.containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > this.containment[2]) {
+ pageX = this.containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > this.containment[3]) {
+ pageY = this.containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+ pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+ pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+ )
+ };
+
+ },
+
+ _rearrange: function(event, i, a, hardRefresh) {
+
+ a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
+
+ //Various things done here to improve the performance:
+ // 1. we create a setTimeout, that calls refreshPositions
+ // 2. on the instance, we have a counter variable, that get's higher after every append
+ // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+ // 4. this lets only the last addition to the timeout stack through
+ this.counter = this.counter ? ++this.counter : 1;
+ var counter = this.counter;
+
+ this._delay(function() {
+ if(counter === this.counter) {
+ this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+ }
+ });
+
+ },
+
+ _clear: function(event, noPropagation) {
+
+ this.reverting = false;
+ // We delay all events that have to be triggered to after the point where the placeholder has been removed and
+ // everything else normalized again
+ var i,
+ delayedTriggers = [];
+
+ // We first have to update the dom position of the actual currentItem
+ // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
+ if(!this._noFinalSort && this.currentItem.parent().length) {
+ this.placeholder.before(this.currentItem);
+ }
+ this._noFinalSort = null;
+
+ if(this.helper[0] === this.currentItem[0]) {
+ for(i in this._storedCSS) {
+ if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
+ this._storedCSS[i] = "";
+ }
+ }
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ if(this.fromOutside && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+ }
+ if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+ }
+
+ // Check if the items Container has Changed and trigger appropriate
+ // events.
+ if (this !== this.currentContainer) {
+ if(!noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ }
+ }
+
+
+ //Post events to containers
+ function delayEvent( type, instance, container ) {
+ return function( event ) {
+ container._trigger( type, event, instance._uiHash( instance ) );
+ };
+ }
+ for (i = this.containers.length - 1; i >= 0; i--){
+ if (!noPropagation) {
+ delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
+ }
+ if(this.containers[i].containerCache.over) {
+ delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ //Do what was originally in plugins
+ if ( this.storedCursor ) {
+ this.document.find( "body" ).css( "cursor", this.storedCursor );
+ this.storedStylesheet.remove();
+ }
+ if(this._storedOpacity) {
+ this.helper.css("opacity", this._storedOpacity);
+ }
+ if(this._storedZIndex) {
+ this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
+ }
+
+ this.dragging = false;
+
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ }
+
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+ if ( !this.cancelHelperRemoval ) {
+ if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
+ this.helper.remove();
+ }
+ this.helper = null;
+ }
+
+ if(!noPropagation) {
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return !this.cancelHelperRemoval;
+
+ },
+
+ _trigger: function() {
+ if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
+ this.cancel();
+ }
+ },
+
+ _uiHash: function(_inst) {
+ var inst = _inst || this;
+ return {
+ helper: inst.helper,
+ placeholder: inst.placeholder || $([]),
+ position: inst.position,
+ originalPosition: inst.originalPosition,
+ offset: inst.positionAbs,
+ item: inst.currentItem,
+ sender: _inst ? _inst.element : null
+ };
+ }
+
+});
+
+
+
+}));
\ No newline at end of file
diff --git a/src/addons/slider/lib/jquery.ui.widget.js b/src/addons/slider/lib/jquery.ui.widget.js
new file mode 100644
index 0000000000..9c07bc110a
--- /dev/null
+++ b/src/addons/slider/lib/jquery.ui.widget.js
@@ -0,0 +1,521 @@
+/*!
+ * jQuery UI Widget 1.10.2
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/jQuery.widget/
+ */
+(function( $, undefined ) {
+
+var uuid = 0,
+ slice = Array.prototype.slice,
+ _cleanData = $.cleanData;
+$.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+};
+
+$.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
+ }, 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 );
+};
+
+$.widget.extend = function( target ) {
+ var input = 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 = slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.widget.extend.apply( null, [ options ].concat(args) ) :
+ options;
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var methodValue,
+ instance = $.data( this, fullName );
+ 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 {
+ this.each(function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} )._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 = 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 ) {
+ $.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 ] ) {
+ 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();
+ });
+ }
+ };
+});
+
+})( jQuery );
\ No newline at end of file
diff --git a/src/addons/slider/slider/singleslider/button/iconbutton.slider.js b/src/addons/slider/slider/singleslider/button/iconbutton.slider.js
new file mode 100644
index 0000000000..bdf0a2c351
--- /dev/null
+++ b/src/addons/slider/slider/singleslider/button/iconbutton.slider.js
@@ -0,0 +1,33 @@
+/**
+ * Created by zcf on 2016/9/22.
+ */
+BI.Slider = BI.inherit(BI.Widget, {
+ _defaultConfig: function () {
+ return BI.extend(BI.Slider.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: "bi-single-button-button"
+ });
+ },
+ _init: function () {
+ BI.extend(BI.Slider.superclass._init.apply(this, arguments));
+ this.slider = BI.createWidget({
+ type: "bi.icon_button",
+ cls: "widget-button-icon button-button",
+ iconWidth: 14,
+ iconHeight: 14,
+ height: 14,
+ width: 14
+ });
+ BI.createWidget({
+ type: "bi.absolute",
+ element: this,
+ items: [{
+ el: this.slider,
+ top: 7,
+ left: -7
+ }],
+ width: 0,
+ height: 14
+ });
+ }
+});
+BI.shortcut("bi.single_slider_slider", BI.Slider);
\ No newline at end of file
diff --git a/src/addons/slider/slider/singleslider/singleslider.js b/src/addons/slider/slider/singleslider/singleslider.js
new file mode 100644
index 0000000000..7f7b8c5471
--- /dev/null
+++ b/src/addons/slider/slider/singleslider/singleslider.js
@@ -0,0 +1,279 @@
+/**
+ * Created by zcf on 2016/9/22.
+ */
+BI.SingleSlider = BI.inherit(BI.Widget, {
+ _constant: {
+ EDITOR_WIDTH: 90,
+ EDITOR_HEIGHT: 30,
+ HEIGHT: 28,
+ SLIDER_WIDTH_HALF: 15,
+ SLIDER_WIDTH: 30,
+ SLIDER_HEIGHT: 30,
+ TRACK_HEIGHT: 24
+ },
+ _defaultConfig: function () {
+ return BI.extend(BI.SingleSlider.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: "bi-single-button bi-button-track"
+ });
+ },
+ _init: function () {
+ BI.SingleSlider.superclass._init.apply(this, arguments);
+
+ var self = this;
+ var c = this._constant;
+ this.enable = false;
+ this.value = "";
+
+ this.grayTrack = BI.createWidget({
+ type: "bi.layout",
+ cls: "gray-track",
+ height: 6
+ });
+ this.blueTrack = BI.createWidget({
+ type: "bi.layout",
+ cls: "blue-track bi-high-light-background",
+ height: 6
+ });
+ this.track = this._createTrackWrapper();
+
+ this.slider = BI.createWidget({
+ type: "bi.single_slider_slider"
+ });
+ this.slider.element.draggable({
+ axis: "x",
+ containment: this.grayTrack.element,
+ scroll: false,
+ drag: function (e, ui) {
+ var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+ var significantPercent = BI.parseFloat(percent.toFixed(1));//直接对计算出来的百分数保留到小数点后一位,相当于分成了1000份。
+ self._setBlueTrack(significantPercent);
+ self._setLabelPosition(significantPercent);
+ var v = self._getValueByPercent(significantPercent);
+ self.label.setValue(v);
+ self.value = v;
+ },
+ stop: function (e, ui) {
+ var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+ var significantPercent = BI.parseFloat(percent.toFixed(1));
+ self._setSliderPosition(significantPercent);
+ self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+ }
+ });
+ var sliderVertical = BI.createWidget({
+ type: "bi.vertical",
+ items: [{
+ type: "bi.absolute",
+ items: [this.slider]
+ }],
+ hgap: c.SLIDER_WIDTH_HALF,
+ height: c.SLIDER_HEIGHT
+ });
+ sliderVertical.element.click(function (e) {
+ if (self.enable) {
+ var offset = e.clientX - self.element.offset().left - c.SLIDER_WIDTH_HALF;
+ var trackLength = self.track.element[0].scrollWidth;
+ var percent = 0;
+ if (offset < 0) {
+ percent = 0
+ }
+ if (offset > 0 && offset < (trackLength - c.SLIDER_WIDTH)) {
+ percent = offset * 100 / self._getGrayTrackLength();
+ }
+ if (offset > (trackLength - c.SLIDER_WIDTH)) {
+ percent = 100
+ }
+ var significantPercent = BI.parseFloat(percent.toFixed(1));
+ self._setAllPosition(significantPercent);
+ var v = self._getValueByPercent(significantPercent);
+ self.label.setValue(v);
+ self.value = v;
+ self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+ }
+ });
+ this.label = BI.createWidget({
+ type: "bi.sign_editor",
+ cls: "button-editor-button bi-border",
+ errorText: "",
+ height: c.HEIGHT,
+ width: c.EDITOR_WIDTH,
+ allowBlank: false,
+ validationChecker: function (v) {
+ return self._checkValidation(v);
+ },
+ quitChecker: function (v) {
+ return self._checkValidation(v);
+ }
+ });
+ this.label.on(BI.SignEditor.EVENT_CONFIRM, function () {
+ var percent = self._getPercentByValue(this.getValue());
+ var significantPercent = BI.parseFloat(percent.toFixed(1));
+ self._setAllPosition(significantPercent);
+ self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+ });
+ this._setVisible(false);
+ BI.createWidget({
+ type: "bi.absolute",
+ element: this,
+ items: [{
+ el: {
+ type: "bi.vertical",
+ items: [{
+ type: "bi.absolute",
+ items: [{
+ el: this.track,
+ width: "100%",
+ height: c.TRACK_HEIGHT
+ }]
+ }],
+ hgap: 7,
+ height: c.TRACK_HEIGHT
+ },
+ top: 33,
+ left: 0,
+ width: "100%"
+ }, {
+ el: sliderVertical,
+ top: 30,
+ left: 0,
+ width: "100%"
+ }, {
+ el: {
+ type: "bi.vertical",
+ items: [{
+ type: "bi.absolute",
+ items: [this.label]
+ }],
+ rgap: c.EDITOR_WIDTH,
+ height: c.EDITOR_HEIGHT
+ },
+ top: 0,
+ left: 0,
+ width: "100%"
+ }]
+ })
+ },
+
+ _createTrackWrapper: function () {
+ return BI.createWidget({
+ type: "bi.absolute",
+ items: [{
+ el: {
+ type: "bi.vertical",
+ items: [{
+ type: "bi.absolute",
+ items: [{
+ el: this.grayTrack,
+ top: 0,
+ left: 0,
+ width: "100%"
+ }, {
+ el: this.blueTrack,
+ top: 0,
+ left: 0,
+ width: "0%"
+ }]
+ }],
+ hgap: 8,
+ height: 8
+ },
+ top: 8,
+ left: 0,
+ width: "100%"
+ }]
+ })
+ },
+
+ _checkValidation: function (v) {
+ return !(BI.isNull(v) || v < this.min || v > this.max)
+ },
+
+ _setBlueTrack: function (percent) {
+ this.blueTrack.element.css({"width": percent + "%"});
+ },
+
+ _setLabelPosition: function (percent) {
+ this.label.element.css({"left": percent + "%"});
+ },
+
+ _setSliderPosition: function (percent) {
+ this.slider.element.css({"left": percent + "%"});
+ },
+
+ _setAllPosition: function (percent) {
+ this._setSliderPosition(percent);
+ this._setLabelPosition(percent);
+ this._setBlueTrack(percent);
+ },
+
+ _setVisible: function (visible) {
+ this.slider.setVisible(visible);
+ this.label.setVisible(visible);
+ },
+
+ _getGrayTrackLength: function () {
+ return this.grayTrack.element[0].scrollWidth
+ },
+
+ _getValueByPercent: function (percent) {
+ var thousandth = BI.parseInt(percent * 10);
+ return (((this.max - this.min) * thousandth) / 1000 + this.min);
+ },
+
+ _getPercentByValue: function (v) {
+ return (v - this.min) * 100 / (this.max - this.min);
+ },
+
+ getValue: function () {
+ return this.value;
+ },
+
+ setValue: function (v) {
+ var value = BI.parseFloat(v);
+ if ((!isNaN(value))) {
+ if (this._checkValidation(value)) {
+ this.value = value;
+ }
+ if (value > this.max) {
+ this.value = this.max;
+ }
+ if (value < this.min) {
+ this.value = this.min;
+ }
+ }
+ },
+
+ setMinAndMax: function (v) {
+ var minNumber = BI.parseFloat(v.min);
+ var maxNumber = BI.parseFloat(v.max);
+ if ((!isNaN(minNumber)) && (!isNaN(maxNumber)) && (maxNumber > minNumber )) {
+ this.min = minNumber;
+ this.max = maxNumber;
+ }
+ },
+
+ reset: function () {
+ this._setVisible(false);
+ this.enable = false;
+ this.value = "";
+ this.min = 0;
+ this.max = 0;
+ this._setBlueTrack(0);
+ },
+
+ populate: function () {
+ if (!isNaN(this.min) && !isNaN(this.max)) {
+ this._setVisible(true);
+ this.enable = true;
+ this.label.setErrorText(BI.i18nText("BI-Please_Enter") + this.min + "-" + this.max + BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Basic_Number"));
+ if (BI.isNumeric(this.value) || BI.isNotEmptyString(this.value)) {
+ this.label.setValue(this.value);
+ this._setAllPosition(this._getPercentByValue(this.value));
+ } else {
+ this.label.setValue(this.max);
+ this._setAllPosition(100);
+ }
+ }
+ }
+});
+BI.SingleSlider.EVENT_CHANGE = "EVENT_CHANGE";
+BI.shortcut("bi.single_slider", BI.SingleSlider);
\ No newline at end of file
diff --git a/src/addons/slider/slider/singleslider/singleslider.normal.js b/src/addons/slider/slider/singleslider/singleslider.normal.js
new file mode 100644
index 0000000000..ef591e52f2
--- /dev/null
+++ b/src/addons/slider/slider/singleslider/singleslider.normal.js
@@ -0,0 +1,244 @@
+/**
+ * normal single slider
+ * Created by Young on 2017/6/21.
+ */
+BI.SingleSliderNormal = BI.inherit(BI.Widget, {
+
+ _constant: {
+ EDITOR_WIDTH: 90,
+ EDITOR_HEIGHT: 30,
+ HEIGHT: 28,
+ SLIDER_WIDTH_HALF: 15,
+ SLIDER_WIDTH: 30,
+ SLIDER_HEIGHT: 30,
+ TRACK_HEIGHT: 24
+ },
+
+ props: {
+ baseCls: "bi-single-button bi-button-track",
+ minMax: {
+ min: 0,
+ max: 100
+ },
+ color: "#3f8ce8"
+ },
+
+ render: function () {
+ var self = this;
+ var c = this._constant;
+ var track = this._createTrack();
+ this.slider = BI.createWidget({
+ type: "bi.single_slider_slider"
+ });
+ this.slider.element.draggable({
+ axis: "x",
+ containment: this.grayTrack.element,
+ scroll: false,
+ drag: function (e, ui) {
+ var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+ var significantPercent = BI.parseFloat(percent.toFixed(1));//直接对计算出来的百分数保留到小数点后一位,相当于分成了1000份。
+ self._setBlueTrack(significantPercent);
+ var v = self._getValueByPercent(significantPercent);
+ self.value = v;
+ self.fireEvent(BI.SingleSliderNormal.EVENT_DRAG, v);
+ },
+ stop: function (e, ui) {
+ var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+ var significantPercent = BI.parseFloat(percent.toFixed(1));
+ self._setSliderPosition(significantPercent);
+ self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+ }
+ });
+
+ var sliderVertical = BI.createWidget({
+ type: "bi.vertical",
+ items: [{
+ type: "bi.absolute",
+ items: [this.slider]
+ }],
+ hgap: c.SLIDER_WIDTH_HALF,
+ height: c.SLIDER_HEIGHT
+ });
+ sliderVertical.element.click(function (e) {
+ if (self.enable) {
+ var offset = e.clientX - self.element.offset().left - c.SLIDER_WIDTH_HALF;
+ var trackLength = self.track.element[0].scrollWidth;
+ var percent = 0;
+ if (offset < 0) {
+ percent = 0
+ }
+ if (offset > 0 && offset < (trackLength - c.SLIDER_WIDTH)) {
+ percent = offset * 100 / self._getGrayTrackLength();
+ }
+ if (offset > (trackLength - c.SLIDER_WIDTH)) {
+ percent = 100
+ }
+ var significantPercent = BI.parseFloat(percent.toFixed(1));
+ self._setAllPosition(significantPercent);
+ var v = self._getValueByPercent(significantPercent);
+ self.value = v;
+ self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+ }
+ });
+
+ return {
+ type: "bi.absolute",
+ element: this,
+ items: [{
+ el: {
+ type: "bi.vertical",
+ items: [{
+ type: "bi.absolute",
+ items: [{
+ el: track,
+ width: "100%",
+ height: c.TRACK_HEIGHT
+ }]
+ }],
+ hgap: 7,
+ height: c.TRACK_HEIGHT
+ },
+ top: 3,
+ left: 0,
+ width: "100%"
+ }, {
+ el: sliderVertical,
+ top: 0,
+ left: 0,
+ width: "100%"
+ }]
+ }
+ },
+
+ _createTrack: function () {
+ var self = this;
+ var c = this._constant;
+ this.grayTrack = BI.createWidget({
+ type: "bi.layout",
+ cls: "gray-track",
+ height: 6
+ });
+ this.blueTrack = BI.createWidget({
+ type: "bi.layout",
+ cls: "blue-track",
+ height: 6
+ });
+ this.blueTrack.element.css({"background-color": this.options.color});
+
+ return {
+ type: "bi.absolute",
+ items: [{
+ el: {
+ type: "bi.vertical",
+ items: [{
+ type: "bi.absolute",
+ items: [{
+ el: this.grayTrack,
+ top: 0,
+ left: 0,
+ width: "100%"
+ }, {
+ el: this.blueTrack,
+ top: 0,
+ left: 0,
+ width: "0%"
+ }]
+ }],
+ hgap: 8,
+ height: 8
+ },
+ top: 8,
+ left: 0,
+ width: "100%"
+ }],
+ ref: function (ref) {
+ self.track = ref;
+ }
+ }
+ },
+
+ _checkValidation: function (v) {
+ return !(BI.isNull(v) || v < this.min || v > this.max)
+ },
+
+ _setBlueTrack: function (percent) {
+ this.blueTrack.element.css({"width": percent + "%"});
+ },
+
+ _setSliderPosition: function (percent) {
+ this.slider.element.css({"left": percent + "%"});
+ },
+
+ _setAllPosition: function (percent) {
+ this._setSliderPosition(percent);
+ this._setBlueTrack(percent);
+ },
+
+ _setVisible: function (visible) {
+ this.slider.setVisible(visible);
+ },
+
+ _getGrayTrackLength: function () {
+ return this.grayTrack.element[0].scrollWidth
+ },
+
+ _getValueByPercent: function (percent) {
+ var thousandth = BI.parseInt(percent * 10);
+ return (((this.max - this.min) * thousandth) / 1000 + this.min);
+ },
+
+ _getPercentByValue: function (v) {
+ return (v - this.min) * 100 / (this.max - this.min);
+ },
+
+ getValue: function () {
+ return this.value;
+ },
+
+ setValue: function (v) {
+ var value = BI.parseFloat(v);
+ if ((!isNaN(value))) {
+ if (this._checkValidation(value)) {
+ this.value = value;
+ }
+ if (value > this.max) {
+ this.value = this.max;
+ }
+ if (value < this.min) {
+ this.value = this.min;
+ }
+ }
+ },
+
+ setMinAndMax: function (v) {
+ var minNumber = BI.parseFloat(v.min);
+ var maxNumber = BI.parseFloat(v.max);
+ if ((!isNaN(minNumber)) && (!isNaN(maxNumber)) && (maxNumber > minNumber )) {
+ this.min = minNumber;
+ this.max = maxNumber;
+ }
+ },
+
+ reset: function () {
+ this._setVisible(false);
+ this.enable = false;
+ this.value = "";
+ this.min = 0;
+ this.max = 0;
+ this._setBlueTrack(0);
+ },
+
+ populate: function () {
+ if (!isNaN(this.min) && !isNaN(this.max)) {
+ this._setVisible(true);
+ this.enable = true;
+ if (BI.isNumeric(this.value) || BI.isNotEmptyString(this.value)) {
+ this._setAllPosition(this._getPercentByValue(this.value));
+ } else {
+ this._setAllPosition(100);
+ }
+ }
+ }
+});
+BI.SingleSliderNormal.EVENT_DRAG = "EVENT_DRAG";
+BI.shortcut("bi.single_slider_normal", BI.SingleSliderNormal);
\ No newline at end of file
diff --git a/src/widget/slider/slider.button.js b/src/addons/slider/slider/slider.button.js
similarity index 100%
rename from src/widget/slider/slider.button.js
rename to src/addons/slider/slider/slider.button.js
diff --git a/src/widget/slider/slider.js b/src/addons/slider/slider/slider.js
similarity index 100%
rename from src/widget/slider/slider.js
rename to src/addons/slider/slider/slider.js
diff --git a/src/widget/multidate/abstract.multidate.datepane.js b/src/widget/multidate/abstract.multidate.datepane.js
new file mode 100644
index 0000000000..81cc8a095d
--- /dev/null
+++ b/src/widget/multidate/abstract.multidate.datepane.js
@@ -0,0 +1,151 @@
+/**
+ * 普通控件
+ *
+ * @class BI.MultiDateCard
+ * @extends BI.Widget
+ * @abstract
+ */
+BI.MultiDateCard = BI.inherit(BI.Widget, {
+
+ constants: {
+ lgap: 80,
+ itemHeight: 35,
+ defaultEditorValue: "1"
+ },
+
+ _defaultConfig: function () {
+ return $.extend(BI.MultiDateCard.superclass._defaultConfig.apply(this, arguments), {});
+ },
+
+ dateConfig: function () {
+
+ },
+
+ defaultSelectedItem: function () {
+
+ },
+
+ _init: function () {
+ BI.MultiDateCard.superclass._init.apply(this, arguments);
+ var self = this, opts = this.options;
+
+ this.label = BI.createWidget({
+ type: 'bi.label',
+ height: this.constants.itemHeight,
+ textAlign: "left",
+ text: BI.i18nText("BI-Multi_Date_Relative_Current_Time"),
+ cls: 'bi-multidate-inner-label bi-tips'
+ });
+ this.radioGroup = BI.createWidget({
+ type: "bi.button_group",
+ chooseType: 0,
+ items: BI.createItems(this.dateConfig(), {
+ type: 'bi.multidate_segment',
+ height: this.constants.itemHeight
+ }),
+ layouts: [{
+ type: "bi.vertical"
+ }]
+ });
+
+ this.radioGroup.on(BI.Controller.EVENT_CHANGE, function (type) {
+ if (type === BI.Events.CONFIRM) {
+ self.fireEvent(BI.MultiDateCard.EVENT_CHANGE);
+ }
+ });
+ this.radioGroup.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+ self.setValue(self.getValue());
+ self.fireEvent(BI.MultiDateCard.EVENT_CHANGE);
+ });
+ BI.createWidget({
+ element: this,
+ type: 'bi.center_adapt',
+ lgap: this.constants.lgap,
+ items: [{
+ type: 'bi.vertical',
+ items: [this.label, this.radioGroup]
+ }]
+ });
+ },
+
+ getValue: function () {
+ var button = this.radioGroup.getSelectedButtons()[0];
+ var type = button.getValue(), value = button.getInputValue();
+ return {
+ type: type,
+ value: value
+ }
+ },
+
+ _isTypeAvaliable: function (type) {
+ var res = false;
+ BI.find(this.dateConfig(), function (i, item) {
+ if (item.value === type) {
+ res = true;
+ return true;
+ }
+ });
+ return res;
+ },
+
+ setValue: function (v) {
+ var self = this;
+ if (BI.isNotNull(v) && this._isTypeAvaliable(v.type)) {
+ this.radioGroup.setValue(v.type);
+ BI.each(this.radioGroup.getAllButtons(), function (i, button) {
+ if (button.isEditorExist() === true && button.isSelected()) {
+ button.setInputValue(v.value);
+ } else {
+ button.setInputValue(self.constants.defaultEditorValue);
+ }
+ });
+ } else {
+ this.radioGroup.setValue(this.defaultSelectedItem());
+ BI.each(this.radioGroup.getAllButtons(), function (i, button) {
+ button.setInputValue(self.constants.defaultEditorValue);
+ });
+ }
+ },
+
+ getCalculationValue: function () {
+ var valueObject = this.getValue();
+ var type = valueObject.type, value = valueObject.value;
+ switch (type) {
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_PREV:
+ return new Date().getOffsetDate(-1 * value);
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_AFTER:
+ return new Date().getOffsetDate(value);
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_TODAY:
+ return new Date();
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_PREV:
+ return new Date().getBeforeMultiMonth(value);
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_AFTER:
+ return new Date().getAfterMultiMonth(value);
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_BEGIN:
+ return new Date(new Date().getFullYear(), new Date().getMonth(), 1);
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_END:
+ return new Date(new Date().getFullYear(), new Date().getMonth(), (new Date().getLastDateOfMonth()).getDate());
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_PREV:
+ return new Date().getBeforeMulQuarter(value);
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_AFTER:
+ return new Date().getAfterMulQuarter(value);
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_BEGIN:
+ return new Date().getQuarterStartDate();
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_END:
+ return new Date().getQuarterEndDate();
+ case BICst.DATE_TYPE.MULTI_DATE_WEEK_PREV:
+ return new Date().getOffsetDate(-7 * value);
+ case BICst.DATE_TYPE.MULTI_DATE_WEEK_AFTER:
+ return new Date().getOffsetDate(7 * value);
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_PREV:
+ return new Date((new Date().getFullYear() - 1 * value), new Date().getMonth(), new Date().getDate());
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_AFTER:
+ return new Date((new Date().getFullYear() + 1 * value), new Date().getMonth(), new Date().getDate());
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_BEGIN:
+ return new Date(new Date().getFullYear(), 0, 1);
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_END:
+ return new Date(new Date().getFullYear(), 11, 31);
+ }
+ }
+});
+BI.MultiDateCard.EVENT_CHANGE = "EVENT_CHANGE";
diff --git a/src/widget/multidate/multidate.combo.js b/src/widget/multidate/multidate.combo.js
new file mode 100644
index 0000000000..56cec94991
--- /dev/null
+++ b/src/widget/multidate/multidate.combo.js
@@ -0,0 +1,247 @@
+/**
+ * 日期控件
+ * @class BI.MultiDateCombo
+ * @extends BI.Widget
+ */
+BI.MultiDateCombo = BI.inherit(BI.Single, {
+ constants: {
+ popupHeight: 259,
+ popupWidth: 270,
+ comboAdjustHeight: 1,
+ border: 1,
+ DATE_MIN_VALUE: "1900-01-01",
+ DATE_MAX_VALUE: "2099-12-31"
+ },
+ _defaultConfig: function () {
+ return BI.extend(BI.MultiDateCombo.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: 'bi-multidate-combo bi-border',
+ height: 24
+ });
+ },
+ _init: function () {
+ BI.MultiDateCombo.superclass._init.apply(this, arguments);
+ var self = this, opts = this.options;
+ this.storeTriggerValue = "";
+ var date = new Date();
+ this.storeValue = null;
+ this.trigger = BI.createWidget({
+ type: 'bi.date_trigger',
+ min: this.constants.DATE_MIN_VALUE,
+ max: this.constants.DATE_MAX_VALUE
+ });
+ this.trigger.on(BI.DateTrigger.EVENT_KEY_DOWN, function () {
+ if (self.combo.isViewVisible()) {
+ self.combo.hideView();
+ }
+ });
+ this.trigger.on(BI.DateTrigger.EVENT_STOP, function () {
+ if (!self.combo.isViewVisible()) {
+ self.combo.showView();
+ }
+ });
+ this.trigger.on(BI.DateTrigger.EVENT_TRIGGER_CLICK, function () {
+ self.combo.toggle();
+ });
+ this.trigger.on(BI.DateTrigger.EVENT_FOCUS, function () {
+ self.storeTriggerValue = self.trigger.getKey();
+ if (!self.combo.isViewVisible()) {
+ self.combo.showView();
+ }
+ self.fireEvent(BI.MultiDateCombo.EVENT_FOCUS);
+ });
+ this.trigger.on(BI.DateTrigger.EVENT_ERROR, function () {
+ self.storeValue = {
+ year: date.getFullYear(),
+ month: date.getMonth()
+ };
+ self.popup.setValue();
+ self.fireEvent(BI.MultiDateCombo.EVENT_ERROR);
+ });
+ this.trigger.on(BI.DateTrigger.EVENT_VALID, function () {
+ self.fireEvent(BI.MultiDateCombo.EVENT_VALID);
+ });
+ this.trigger.on(BI.DateTrigger.EVENT_CHANGE, function () {
+ self.fireEvent(BI.MultiDateCombo.EVENT_CHANGE);
+ });
+ this.trigger.on(BI.DateTrigger.EVENT_CONFIRM, function () {
+ if (self.combo.isViewVisible()) {
+ return;
+ }
+ var dateStore = self.storeTriggerValue;
+ var dateObj = self.trigger.getKey();
+ if (BI.isNotEmptyString(dateObj) && !BI.isEqual(dateObj, dateStore)) {
+ self.storeValue = self.trigger.getValue();
+ self.setValue(self.trigger.getValue());
+ } else if (BI.isEmptyString(dateObj)) {
+ self.storeValue = null;
+ self.trigger.setValue();
+ }
+ self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+ });
+ this.popup = BI.createWidget({
+ type: "bi.multidate_popup",
+ min: this.constants.DATE_MIN_VALUE,
+ max: this.constants.DATE_MAX_VALUE
+ });
+ this.popup.on(BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE, function () {
+ self.setValue();
+ self.combo.hideView();
+ self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+ });
+ this.popup.on(BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE, function () {
+ var date = new Date();
+ self.setValue({
+ year: date.getFullYear(),
+ month: date.getMonth(),
+ day: date.getDate()
+ });
+ self.combo.hideView();
+ self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+ });
+ this.popup.on(BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE, function () {
+ self.setValue(self.popup.getValue());
+ self.combo.hideView();
+ self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+ });
+ this.popup.on(BI.MultiDatePopup.CALENDAR_EVENT_CHANGE, function () {
+ self.setValue(self.popup.getValue());
+ self.combo.hideView();
+ //self.fireEvent(BI.MultiDateCombo.EVENT_CHANGE);
+ self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+ });
+ this.combo = BI.createWidget({
+ type: 'bi.combo',
+ toggle: false,
+ isNeedAdjustHeight: false,
+ isNeedAdjustWidth: false,
+ el: this.trigger,
+ adjustLength: this.constants.comboAdjustHeight,
+ popup: {
+ el: this.popup,
+ maxHeight: this.constants.popupHeight,
+ width: this.constants.popupWidth,
+ stopPropagation: false
+ }
+ });
+ this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+ self.popup.setValue(self.storeValue);
+ self.fireEvent(BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW);
+ });
+
+ var triggerBtn = BI.createWidget({
+ type: "bi.trigger_icon_button",
+ cls: "bi-trigger-date-button chart-date-normal-font",
+ width: 30,
+ height: 23
+ });
+ triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () {
+ if (self.combo.isViewVisible()) {
+ self.combo.hideView();
+ } else {
+ self.combo.showView();
+ }
+ });
+ this.changeIcon = BI.createWidget({
+ type: "bi.icon_button",
+ cls: "bi-trigger-date-change widget-date-h-change-font",
+ width: 30,
+ height: 23
+ });
+
+
+ var leftPart = BI.createWidget({
+ type: "bi.absolute",
+ items: [{
+ el: this.combo,
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0
+ }, {
+ el: triggerBtn,
+ top: 0,
+ left: 0
+ }]
+ });
+
+ BI.createWidget({
+ type: "bi.htape",
+ element: this,
+ items: [leftPart, {
+ el: this.changeIcon,
+ width: 30
+ }],
+ ref: function (_ref) {
+ self.comboWrapper = _ref;
+ }
+ })
+ },
+
+ _checkDynamicValue: function (v) {
+ var type = null;
+ if (BI.isNotNull(v)) {
+ type = v.type
+ }
+ switch (type) {
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_BEGIN:
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_END:
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_BEGIN:
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_END:
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_BEGIN:
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_END:
+ case BICst.DATE_TYPE.MULTI_DATE_WEEK_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_WEEK_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_TODAY:
+ this.changeIcon.setVisible(true);
+ this.comboWrapper.attr("items")[1].width = 30;
+ this.comboWrapper.resize();
+ break;
+ default:
+ this.comboWrapper.attr("items")[1].width = 0;
+ this.comboWrapper.resize();
+ this.changeIcon.setVisible(false);
+ break;
+ }
+ },
+
+ setValue: function (v) {
+ this.storeValue = v;
+ this.popup.setValue(v);
+ this.trigger.setValue(v);
+ this._checkDynamicValue(v)
+ },
+ getValue: function () {
+ return this.storeValue;
+ },
+ getKey: function () {
+ return this.trigger.getKey();
+ },
+ hidePopupView: function () {
+ this.combo.hideView();
+ }
+});
+BI.shortcut('bi.multidate_combo', BI.MultiDateCombo);
+
+BI.MultiDateCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.MultiDateCombo.EVENT_FOCUS = "EVENT_FOCUS";
+BI.MultiDateCombo.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiDateCombo.EVENT_VALID = "EVENT_VALID";
+BI.MultiDateCombo.EVENT_ERROR = "EVENT_ERROR";
+BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW = "BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW";
+
+BI.extend(BI.MultiDateCombo, {
+ MULTI_DATE_YMD_CARD: 1,
+ MULTI_DATE_YEAR_CARD: 2,
+ MULTI_DATE_QUARTER_CARD: 3,
+ MULTI_DATE_MONTH_CARD: 4,
+ MULTI_DATE_WEEK_CARD: 5,
+ MULTI_DATE_DAY_CARD: 6
+});
diff --git a/src/widget/multidate/multidate.day.js b/src/widget/multidate/multidate.day.js
new file mode 100644
index 0000000000..fc663997a2
--- /dev/null
+++ b/src/widget/multidate/multidate.day.js
@@ -0,0 +1,43 @@
+/**
+ * 普通控件
+ *
+ * @class BI.DayCard
+ * @extends BI.MultiDateCard
+ */
+BI.DayCard = BI.inherit(BI.MultiDateCard, {
+
+ _defaultConfig: function () {
+ return $.extend(BI.DayCard.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: 'bi-multidate-daycard'
+ });
+ },
+
+ _init: function () {
+ BI.DayCard.superclass._init.apply(this, arguments);
+ },
+
+ dateConfig: function () {
+ return [{
+ isEditorExist: true,
+ selected: true,
+ text: BI.i18nText("BI-Multi_Date_Day_Prev"),
+ value: BICst.DATE_TYPE.MULTI_DATE_DAY_PREV
+ },
+ {
+ isEditorExist: true,
+ text: BI.i18nText("BI-Multi_Date_Day_Next"),
+ value: BICst.DATE_TYPE.MULTI_DATE_DAY_AFTER
+ },
+ {
+ isEditorExist: false,
+ value: BICst.DATE_TYPE.MULTI_DATE_DAY_TODAY,
+ text: BI.i18nText("BI-Multi_Date_Today")
+ }];
+ },
+
+ defaultSelectedItem: function () {
+ return BICst.DATE_TYPE.MULTI_DATE_DAY_PREV
+ }
+});
+BI.DayCard.EVENT_CHANGE = "EVENT_CHANGE";
+BI.shortcut('bi.daycard', BI.DayCard);
diff --git a/src/widget/multidate/multidate.month.js b/src/widget/multidate/multidate.month.js
new file mode 100644
index 0000000000..d78ccfddc8
--- /dev/null
+++ b/src/widget/multidate/multidate.month.js
@@ -0,0 +1,47 @@
+/**
+ * 普通控件
+ *
+ * @class BI.MonthCard
+ * @extends BI.MultiDateCard
+ */
+BI.MonthCard = BI.inherit(BI.MultiDateCard, {
+ _defaultConfig: function () {
+ return $.extend(BI.MonthCard.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: 'bi-multidate-monthcard'
+ });
+ },
+
+ _init: function () {
+ BI.MonthCard.superclass._init.apply(this, arguments);
+ },
+
+ dateConfig: function () {
+ return [{
+ selected: true,
+ isEditorExist: true,
+ value: BICst.DATE_TYPE.MULTI_DATE_MONTH_PREV,
+ text: BI.i18nText("BI-Multi_Date_Month_Prev")
+ },
+ {
+ isEditorExist: true,
+ value: BICst.DATE_TYPE.MULTI_DATE_MONTH_AFTER,
+ text: BI.i18nText("BI-Multi_Date_Month_Next")
+ },
+ {
+ value: BICst.DATE_TYPE.MULTI_DATE_MONTH_BEGIN,
+ isEditorExist: false,
+ text: BI.i18nText("BI-Multi_Date_Month_Begin")
+ },
+ {
+ value: BICst.DATE_TYPE.MULTI_DATE_MONTH_END,
+ isEditorExist: false,
+ text: BI.i18nText("BI-Multi_Date_Month_End")
+ }];
+ },
+
+ defaultSelectedItem: function () {
+ return BICst.DATE_TYPE.MULTI_DATE_MONTH_PREV;
+ }
+});
+BI.MonthCard.EVENT_CHANGE = "EVENT_CHANGE";
+BI.shortcut('bi.monthcard', BI.MonthCard);
diff --git a/src/widget/multidate/multidate.popup.js b/src/widget/multidate/multidate.popup.js
new file mode 100644
index 0000000000..f164744134
--- /dev/null
+++ b/src/widget/multidate/multidate.popup.js
@@ -0,0 +1,312 @@
+/**
+ * 日期控件
+ * @class BI.MultiDatePopup
+ * @extends BI.Widget
+ */
+BI.MultiDatePopup = BI.inherit(BI.Widget, {
+ constants: {
+ tabHeight: 30,
+ tabWidth: 42,
+ titleHeight: 27,
+ itemHeight: 30,
+ triggerHeight: 24,
+ buttonWidth: 90,
+ buttonHeight: 25,
+ cardHeight: 229,
+ cardWidth: 270,
+ popupHeight: 259,
+ popupWidth: 270,
+ comboAdjustHeight: 1,
+ ymdWidth: 58,
+ lgap: 2,
+ border: 1
+ },
+ _defaultConfig: function () {
+ return BI.extend(BI.MultiDatePopup.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: 'bi-multidate-popup',
+ width: 268,
+ height: 260
+ });
+ },
+ _init: function () {
+ BI.MultiDatePopup.superclass._init.apply(this, arguments);
+ var self = this, opts = this.options;
+ this.storeValue = "";
+ this.textButton = BI.createWidget({
+ type: 'bi.text_button',
+ forceCenter: true,
+ cls: 'bi-multidate-popup-label bi-border-left bi-border-right bi-border-top',
+ shadow: true,
+ text: BI.i18nText("BI-Multi_Date_Today")
+ });
+ this.textButton.on(BI.TextButton.EVENT_CHANGE, function () {
+ self.fireEvent(BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE);
+ });
+ this.clearButton = BI.createWidget({
+ type: "bi.text_button",
+ forceCenter: true,
+ cls: 'bi-multidate-popup-button bi-border-top',
+ shadow: true,
+ text: BI.i18nText("BI-Basic_Clear")
+ });
+ this.clearButton.on(BI.TextButton.EVENT_CHANGE, function () {
+ self.fireEvent(BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE);
+ });
+ this.okButton = BI.createWidget({
+ type: "bi.text_button",
+ forceCenter: true,
+ cls: 'bi-multidate-popup-button bi-border-top',
+ shadow: true,
+ text: BI.i18nText("BI-Basic_OK")
+ });
+ this.okButton.on(BI.TextButton.EVENT_CHANGE, function () {
+ self.fireEvent(BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE);
+ });
+ this.dateTab = BI.createWidget({
+ type: 'bi.tab',
+ tab: {
+ cls: "bi-multidate-popup-tab bi-border-bottom",
+ height: this.constants.tabHeight,
+ items: BI.createItems([{
+ text: BI.i18nText("BI-Multi_Date_YMD"),
+ value: BI.MultiDateCombo.MULTI_DATE_YMD_CARD,
+ width: this.constants.ymdWidth
+ }, {
+ text: BI.i18nText("BI-Multi_Date_Year"),
+ value: BI.MultiDateCombo.MULTI_DATE_YEAR_CARD
+ }, {
+ text: BI.i18nText("BI-Multi_Date_Quarter"),
+ value: BI.MultiDateCombo.MULTI_DATE_QUARTER_CARD
+ }, {
+ text: BI.i18nText("BI-Multi_Date_Month"),
+ value: BI.MultiDateCombo.MULTI_DATE_MONTH_CARD
+ }, {
+ text: BI.i18nText("BI-Multi_Date_Week"),
+ value: BI.MultiDateCombo.MULTI_DATE_WEEK_CARD
+ }, {
+ text: BI.i18nText("BI-Multi_Date_Day"),
+ value: BI.MultiDateCombo.MULTI_DATE_DAY_CARD
+ }], {
+ width: this.constants.tabWidth,
+ textAlign: "center",
+ height: this.constants.itemHeight,
+ cls: 'bi-multidate-popup-item bi-list-item-active'
+ }),
+ layouts: [{
+ type: 'bi.left'
+ }]
+ },
+ cardCreator: function (v) {
+ switch (v) {
+ case BI.MultiDateCombo.MULTI_DATE_YMD_CARD:
+ self.ymd = BI.createWidget({
+ type: "bi.date_calendar_popup",
+ min: self.options.min,
+ max: self.options.max
+ });
+ self.ymd.on(BI.DateCalendarPopup.EVENT_CHANGE, function () {
+ self.fireEvent(BI.MultiDatePopup.CALENDAR_EVENT_CHANGE);
+ });
+ return self.ymd;
+ case BI.MultiDateCombo.MULTI_DATE_YEAR_CARD:
+ self.year = BI.createWidget({
+ type: "bi.yearcard"
+ });
+ self.year.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+ self._setInnerValue(self.year, v);
+ });
+ return self.year;
+ case BI.MultiDateCombo.MULTI_DATE_QUARTER_CARD:
+ self.quarter = BI.createWidget({
+ type: 'bi.quartercard'
+ });
+ self.quarter.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+ self._setInnerValue(self.quarter, v);
+ });
+ return self.quarter;
+ case BI.MultiDateCombo.MULTI_DATE_MONTH_CARD:
+ self.month = BI.createWidget({
+ type: 'bi.monthcard'
+ });
+ self.month.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+ self._setInnerValue(self.month, v);
+ });
+ return self.month;
+ case BI.MultiDateCombo.MULTI_DATE_WEEK_CARD:
+ self.week = BI.createWidget({
+ type: 'bi.weekcard'
+ });
+ self.week.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+ self._setInnerValue(self.week, v);
+ });
+ return self.week;
+ case BI.MultiDateCombo.MULTI_DATE_DAY_CARD:
+ self.day = BI.createWidget({
+ type: 'bi.daycard'
+ });
+ self.day.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+ self._setInnerValue(self.day, v);
+ });
+ return self.day;
+ }
+ }
+ });
+ this.dateTab.setSelect(BI.MultiDateCombo.MULTI_DATE_YMD_CARD);
+ this.cur = BI.MultiDateCombo.MULTI_DATE_YMD_CARD;
+ this.dateTab.on(BI.Tab.EVENT_CHANGE, function () {
+ var v = self.dateTab.getSelect();
+ switch (v) {
+ case BI.MultiDateCombo.MULTI_DATE_YMD_CARD:
+ var date = this.getTab(self.cur).getCalculationValue();
+ self.ymd.setValue({
+ year: date.getFullYear(),
+ month: date.getMonth(),
+ day: date.getDate()
+ });
+ self._setInnerValue(self.ymd);
+ break;
+ case BI.MultiDateCombo.MULTI_DATE_YEAR_CARD:
+ self.year.setValue(self.storeValue);
+ self._setInnerValue(self.year);
+ break;
+ case BI.MultiDateCombo.MULTI_DATE_QUARTER_CARD:
+ self.quarter.setValue(self.storeValue);
+ self._setInnerValue(self.quarter);
+ break;
+ case BI.MultiDateCombo.MULTI_DATE_MONTH_CARD:
+ self.month.setValue(self.storeValue);
+ self._setInnerValue(self.month);
+ break;
+ case BI.MultiDateCombo.MULTI_DATE_WEEK_CARD:
+ self.week.setValue(self.storeValue);
+ self._setInnerValue(self.week);
+ break;
+ case BI.MultiDateCombo.MULTI_DATE_DAY_CARD:
+ self.day.setValue(self.storeValue);
+ self._setInnerValue(self.day);
+ break;
+ }
+ self.cur = v;
+ });
+ this.dateButton = BI.createWidget({
+ type: "bi.grid",
+ items: [[this.clearButton, this.textButton, this.okButton]]
+ });
+ BI.createWidget({
+ element: this,
+ type: "bi.vtape",
+ items: [{
+ el: this.dateTab
+ }, {
+ el: this.dateButton,
+ height: 30
+ }]
+ });
+ },
+ _setInnerValue: function (obj) {
+ if (this.dateTab.getSelect() === BI.MultiDateCombo.MULTI_DATE_YMD_CARD) {
+ this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+ this.textButton.setEnable(true);
+ } else {
+ var date = obj.getCalculationValue();
+ date = date.print("%Y-%x-%e");
+ this.textButton.setValue(date);
+ this.textButton.setEnable(false);
+ }
+ },
+ setValue: function (v) {
+ this.storeValue = v;
+ var self = this, date;
+ var type, value;
+ if (BI.isNotNull(v)) {
+ type = v.type || BICst.DATE_TYPE.MULTI_DATE_CALENDAR;
+ value = v.value;
+ if (BI.isNull(value)) {
+ value = v;
+ }
+ }
+ switch (type) {
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_BEGIN:
+ case BICst.DATE_TYPE.MULTI_DATE_YEAR_END:
+ this.dateTab.setSelect(BICst.MULTI_DATE_YEAR_CARD);
+ this.year.setValue({type: type, value: value});
+ this.cur = BICst.MULTI_DATE_YEAR_CARD;
+ self._setInnerValue(this.year);
+ break;
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_BEGIN:
+ case BICst.DATE_TYPE.MULTI_DATE_QUARTER_END:
+ this.dateTab.setSelect(BICst.MULTI_DATE_QUARTER_CARD);
+ this.cur = BICst.MULTI_DATE_QUARTER_CARD;
+ this.quarter.setValue({type: type, value: value});
+ self._setInnerValue(this.quarter);
+ break;
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_BEGIN:
+ case BICst.DATE_TYPE.MULTI_DATE_MONTH_END:
+ this.dateTab.setSelect(BICst.MULTI_DATE_MONTH_CARD);
+ this.cur = BICst.MULTI_DATE_MONTH_CARD;
+ this.month.setValue({type: type, value: value});
+ self._setInnerValue(this.month);
+ break;
+ case BICst.DATE_TYPE.MULTI_DATE_WEEK_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_WEEK_AFTER:
+ this.dateTab.setSelect(BICst.MULTI_DATE_WEEK_CARD);
+ this.cur = BICst.MULTI_DATE_WEEK_CARD;
+ this.week.setValue({type: type, value: value});
+ self._setInnerValue(this.week);
+ break;
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_PREV:
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_AFTER:
+ case BICst.DATE_TYPE.MULTI_DATE_DAY_TODAY:
+ this.dateTab.setSelect(BICst.MULTI_DATE_DAY_CARD);
+ this.cur = BICst.MULTI_DATE_DAY_CARD;
+ this.day.setValue({type: type, value: value});
+ self._setInnerValue(this.day);
+ break;
+ default:
+ if (BI.isNull(value) || BI.isEmptyObject(value)) {
+ var date = new Date();
+ this.dateTab.setSelect(BI.MultiDateCombo.MULTI_DATE_YMD_CARD);
+ this.ymd.setValue({
+ year: date.getFullYear(),
+ month: date.getMonth(),
+ day: date.getDate()
+ });
+ this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+ } else {
+ this.dateTab.setSelect(BI.MultiDateCombo.MULTI_DATE_YMD_CARD);
+ this.ymd.setValue(value);
+ this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+ }
+ this.textButton.setEnable(true);
+ break;
+ }
+ },
+ getValue: function () {
+ var tab = this.dateTab.getSelect();
+ switch (tab) {
+ case BI.MultiDateCombo.MULTI_DATE_YMD_CARD:
+ return this.ymd.getValue();
+ case BI.MultiDateCombo.MULTI_DATE_YEAR_CARD:
+ return this.year.getValue();
+ case BI.MultiDateCombo.MULTI_DATE_QUARTER_CARD:
+ return this.quarter.getValue();
+ case BI.MultiDateCombo.MULTI_DATE_MONTH_CARD:
+ return this.month.getValue();
+ case BI.MultiDateCombo.MULTI_DATE_WEEK_CARD:
+ return this.week.getValue();
+ case BI.MultiDateCombo.MULTI_DATE_DAY_CARD:
+ return this.day.getValue();
+ }
+ }
+});
+BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE = "BUTTON_OK_EVENT_CHANGE";
+BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE = "BUTTON_lABEL_EVENT_CHANGE";
+BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE = "BUTTON_CLEAR_EVENT_CHANGE";
+BI.MultiDatePopup.CALENDAR_EVENT_CHANGE = "CALENDAR_EVENT_CHANGE";
+BI.shortcut('bi.multidate_popup', BI.MultiDatePopup);
diff --git a/src/widget/multidate/multidate.quarter.js b/src/widget/multidate/multidate.quarter.js
new file mode 100644
index 0000000000..508e73dbc0
--- /dev/null
+++ b/src/widget/multidate/multidate.quarter.js
@@ -0,0 +1,48 @@
+/**
+ * 普通控件
+ *
+ * @class BI.QuarterCard
+ * @extends BI.MultiDateCard
+ */
+BI.QuarterCard = BI.inherit(BI.MultiDateCard, {
+
+ _defaultConfig: function () {
+ return $.extend(BI.QuarterCard.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: 'bi-multidate-quartercard'
+ });
+ },
+
+ _init: function () {
+ BI.QuarterCard.superclass._init.apply(this, arguments);
+ },
+
+ dateConfig: function () {
+ return [{
+ selected: true,
+ value: BICst.DATE_TYPE.MULTI_DATE_QUARTER_PREV,
+ isEditorExist: true,
+ text: BI.i18nText("BI-Multi_Date_Quarter_Prev")
+ },
+ {
+ value: BICst.DATE_TYPE.MULTI_DATE_QUARTER_AFTER,
+ isEditorExist: true,
+ text: BI.i18nText("BI-Multi_Date_Quarter_Next")
+ },
+ {
+ value: BICst.DATE_TYPE.MULTI_DATE_QUARTER_BEGIN,
+ isEditorExist: false,
+ text: BI.i18nText("BI-Multi_Date_Quarter_Begin")
+ },
+ {
+ value: BICst.DATE_TYPE.MULTI_DATE_QUARTER_END,
+ isEditorExist: false,
+ text: BI.i18nText("BI-Multi_Date_Quarter_End")
+ }]
+ },
+
+ defaultSelectedItem: function () {
+ return BICst.DATE_TYPE.MULTI_DATE_QUARTER_PREV;
+ }
+});
+BI.QuarterCard.EVENT_CHANGE = "EVENT_CHANGE";
+BI.shortcut('bi.quartercard', BI.QuarterCard);
diff --git a/src/widget/multidate/multidate.segment.js b/src/widget/multidate/multidate.segment.js
new file mode 100644
index 0000000000..2ac7de01f1
--- /dev/null
+++ b/src/widget/multidate/multidate.segment.js
@@ -0,0 +1,127 @@
+/**
+ * 普通控件
+ *
+ * @class BI.MultiDateSegment
+ * @extends BI.Single
+ */
+BI.MultiDateSegment = BI.inherit(BI.Single, {
+ constants: {
+ itemHeight: 24,
+ maxGap: 15,
+ minGap: 10,
+ textWidth: 30,
+ defaultEditorValue: "1"
+ },
+
+ _defaultConfig: function () {
+ return $.extend(BI.MultiDateSegment.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: 'bi-multidate-segment',
+ text: "",
+ width: 130,
+ height: 30,
+ isEditorExist: true,
+ selected: false,
+ defaultEditorValue: "1"
+ });
+ },
+
+ _init: function () {
+ BI.MultiDateSegment.superclass._init.apply(this, arguments);
+ var self = this, opts = this.options;
+ this.radio = BI.createWidget({
+ type: "bi.radio",
+ selected: opts.selected
+ });
+ this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+ self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+ });
+ this.textEditor = BI.createWidget({
+ type: 'bi.text_editor',
+ value: this.constants.defaultEditorValue,
+ title: function () {
+ return self.textEditor.getValue();
+ },
+ cls: 'bi-multidate-editor',
+ width: this.constants.textWidth,
+ height: this.constants.itemHeight
+ });
+ this.textEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+ self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+ });
+ this.text = BI.createWidget({
+ type: "bi.label",
+ textAlign: "left",
+ cls: 'bi-multidate-normal-label',
+ text: opts.text,
+ height: this.constants.itemHeight
+ });
+ this._createSegment();
+ },
+ _createSegment: function () {
+ if (this.options.isEditorExist === true) {
+ return BI.createWidget({
+ element: this,
+ type: 'bi.left',
+ items: [{
+ el: {
+ type: "bi.center_adapt",
+ items: [this.radio],
+ height: this.constants.itemHeight
+ },
+ lgap: 0
+ },
+ {
+ el: {
+ type: "bi.center_adapt",
+ items: [this.textEditor],
+ widgetName: 'textEditor'
+ },
+ lgap: this.constants.maxGap
+ },
+ {
+ el: this.text,
+ lgap: this.constants.minGap
+ }]
+ });
+ }
+ return BI.createWidget({
+ element: this,
+ type: 'bi.left',
+ items: [{
+ el: {
+ type: "bi.center_adapt",
+ items: [this.radio],
+ height: this.constants.itemHeight
+ },
+ lgap: 0
+ },
+ {
+ el: this.text,
+ lgap: this.constants.maxGap
+ }]
+ })
+ },
+ setSelected: function (v) {
+ if (BI.isNotNull(this.radio)) {
+ this.radio.setSelected(v);
+ this.textEditor.setEnable(v);
+ }
+ },
+ isSelected: function () {
+ return this.radio.isSelected();
+ },
+ getValue: function () {
+ return this.options.value;
+ },
+ getInputValue: function () {
+ return this.textEditor.getValue() | 0;
+ },
+ setInputValue: function (v) {
+ this.textEditor.setValue(v);
+ },
+ isEditorExist: function () {
+ return this.options.isEditorExist;
+ }
+});
+BI.MultiDateSegment.EVENT_CHANGE = "EVENT_CHANGE";
+BI.shortcut('bi.multidate_segment', BI.MultiDateSegment);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.week.js b/src/widget/multidate/multidate.week.js
new file mode 100644
index 0000000000..d81903e277
--- /dev/null
+++ b/src/widget/multidate/multidate.week.js
@@ -0,0 +1,37 @@
+/**
+ * 普通控件
+ *
+ * @class BI.WeekCard
+ * @extends BI.MultiDateCard
+ */
+BI.WeekCard = BI.inherit(BI.MultiDateCard, {
+ _defaultConfig: function () {
+ return $.extend(BI.WeekCard.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: 'bi-multidate-weekcard'
+ });
+ },
+
+ _init: function () {
+ BI.WeekCard.superclass._init.apply(this, arguments);
+ },
+
+ dateConfig: function () {
+ return [{
+ selected: true,
+ isEditorExist: true,
+ text: BI.i18nText("BI-Multi_Date_Week_Prev"),
+ value: BICst.DATE_TYPE.MULTI_DATE_WEEK_PREV
+ },
+ {
+ isEditorExist: true,
+ text: BI.i18nText("BI-Multi_Date_Week_Next"),
+ value: BICst.DATE_TYPE.MULTI_DATE_WEEK_AFTER
+ }];
+ },
+
+ defaultSelectedItem: function () {
+ return BICst.DATE_TYPE.MULTI_DATE_WEEK_PREV;
+ }
+});
+BI.WeekCard.EVENT_CHANGE = "EVENT_CHANGE";
+BI.shortcut('bi.weekcard', BI.WeekCard);
diff --git a/src/widget/multidate/multidate.year.js b/src/widget/multidate/multidate.year.js
new file mode 100644
index 0000000000..e1fce8b649
--- /dev/null
+++ b/src/widget/multidate/multidate.year.js
@@ -0,0 +1,47 @@
+/**
+ * 普通控件
+ *
+ * @class BI.YearCard
+ * @extends BI.MultiDateCard
+ */
+BI.YearCard = BI.inherit(BI.MultiDateCard, {
+ _defaultConfig: function () {
+ return $.extend(BI.YearCard.superclass._defaultConfig.apply(this, arguments), {
+ baseCls: 'bi-multidate-yearcard'
+ });
+ },
+
+ _init: function () {
+ BI.YearCard.superclass._init.apply(this, arguments);
+ },
+
+ dateConfig: function () {
+ return [{
+ selected: true,
+ isEditorExist: true,
+ text: BI.i18nText("BI-Multi_Date_Year_Prev"),
+ value: BICst.DATE_TYPE.MULTI_DATE_YEAR_PREV
+ },
+ {
+ isEditorExist: true,
+ text: BI.i18nText("BI-Multi_Date_Year_Next"),
+ value: BICst.DATE_TYPE.MULTI_DATE_YEAR_AFTER
+ },
+ {
+ isEditorExist: false,
+ value: BICst.DATE_TYPE.MULTI_DATE_YEAR_BEGIN,
+ text: BI.i18nText("BI-Multi_Date_Year_Begin")
+ },
+ {
+ isEditorExist: false,
+ value: BICst.DATE_TYPE.MULTI_DATE_YEAR_END,
+ text: BI.i18nText("BI-Multi_Date_Year_End")
+ }]
+ },
+
+ defaultSelectedItem: function () {
+ return BICst.DATE_TYPE.MULTI_DATE_YEAR_PREV;
+ }
+});
+BI.YearCard.EVENT_CHANGE = "EVENT_CHANGE";
+BI.shortcut('bi.yearcard', BI.YearCard);
diff --git a/src/widget/timeinterval/timeinterval.js b/src/widget/timeinterval/timeinterval.js
new file mode 100644
index 0000000000..e79fe3cbd3
--- /dev/null
+++ b/src/widget/timeinterval/timeinterval.js
@@ -0,0 +1,189 @@
+/**
+ * Created by Baron on 2015/10/19.
+ */
+BI.TimeInterval = BI.inherit(BI.Single, {
+ constants: {
+ height: 25,
+ width: 25,
+ lgap: 15,
+ offset: -15,
+ timeErrorCls: "time-error",
+ DATE_MIN_VALUE: "1900-01-01",
+ DATE_MAX_VALUE: "2099-12-31"
+ },
+ _defaultConfig: function () {
+ var conf = BI.TimeInterval.superclass._defaultConfig.apply(this, arguments);
+ return BI.extend(conf, {
+ extraCls: "bi-time-interval"
+ })
+ },
+ _init: function () {
+ var self = this;
+ BI.TimeInterval.superclass._init.apply(this, arguments);
+
+ this.left = this._createCombo();
+ this.right = this._createCombo();
+ this.label = BI.createWidget({
+ type: 'bi.label',
+ height: this.constants.height,
+ width: this.constants.width,
+ text: "-"
+ });
+ BI.createWidget({
+ element: self,
+ type: "bi.center",
+ hgap: 15,
+ height: this.constants.height,
+ items: [{
+ type: "bi.absolute",
+ items: [{
+ el: self.left,
+ left: this.constants.offset,
+ right: 0,
+ top: 0,
+ bottom: 0
+ }]
+ }, {
+ type: "bi.absolute",
+ items: [{
+ el: self.right,
+ left: 0,
+ right: this.constants.offset,
+ top: 0,
+ bottom: 0
+ }]
+ }]
+ });
+ BI.createWidget({
+ type: "bi.horizontal_auto",
+ element: this,
+ items: [
+ self.label
+ ]
+ });
+ },
+
+ _createCombo: function () {
+ var self = this;
+ var combo = BI.createWidget({
+ type: 'bi.multidate_combo'
+ });
+ combo.on(BI.MultiDateCombo.EVENT_ERROR, function () {
+ self._clearTitle();
+ self.element.removeClass(self.constants.timeErrorCls);
+ self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+ });
+
+ combo.on(BI.MultiDateCombo.EVENT_VALID, function(){
+ BI.Bubbles.hide("error");
+ var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+ if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+ self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+ self.element.addClass(self.constants.timeErrorCls);
+ BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+ offsetStyle: "center"
+ });
+ self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+ } else {
+ self._clearTitle();
+ self.element.removeClass(self.constants.timeErrorCls);
+ }
+ });
+
+ combo.on(BI.MultiDateCombo.EVENT_FOCUS, function(){
+ BI.Bubbles.hide("error");
+ var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+ if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+ self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+ self.element.addClass(self.constants.timeErrorCls);
+ BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+ offsetStyle: "center"
+ });
+ self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+ } else {
+ self._clearTitle();
+ self.element.removeClass(self.constants.timeErrorCls);
+ }
+ });
+
+ combo.on(BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW, function () {
+ self.left.hidePopupView();
+ self.right.hidePopupView();
+ });
+ //combo.on(BI.MultiDateCombo.EVENT_CHANGE, function () {
+ // BI.Bubbles.hide("error");
+ // var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+ // if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+ // self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+ // self.element.addClass(self.constants.timeErrorCls);
+ // BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+ // offsetStyle: "center"
+ // });
+ // self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+ // } else {
+ // self._clearTitle();
+ // self.element.removeClass(self.constants.timeErrorCls);
+ // }
+ //});
+
+ combo.on(BI.MultiDateCombo.EVENT_CONFIRM, function(){
+ BI.Bubbles.hide("error");
+ var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+ if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+ self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+ self.element.addClass(self.constants.timeErrorCls);
+ self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+ }else{
+ self._clearTitle();
+ self.element.removeClass(self.constants.timeErrorCls);
+ self.fireEvent(BI.TimeInterval.EVENT_CHANGE);
+ }
+ });
+ return combo;
+ },
+ _dateCheck: function (date) {
+ return Date.parseDateTime(date, "%Y-%x-%d").print("%Y-%x-%d") == date || Date.parseDateTime(date, "%Y-%X-%d").print("%Y-%X-%d") == date || Date.parseDateTime(date, "%Y-%x-%e").print("%Y-%x-%e") == date || Date.parseDateTime(date, "%Y-%X-%e").print("%Y-%X-%e") == date;
+ },
+ _checkVoid: function (obj) {
+ return !Date.checkVoid(obj.year, obj.month, obj.day, this.constants.DATE_MIN_VALUE, this.constants.DATE_MAX_VALUE)[0];
+ },
+ _check: function (smallDate, bigDate) {
+ var smallObj = smallDate.match(/\d+/g), bigObj = bigDate.match(/\d+/g);
+ return this._dateCheck(smallDate) && Date.checkLegal(smallDate) && this._checkVoid({
+ year: smallObj[0],
+ month: smallObj[1],
+ day: smallObj[2]
+ }) && this._dateCheck(bigDate) && Date.checkLegal(bigDate) && this._checkVoid({
+ year: bigObj[0],
+ month: bigObj[1],
+ day: bigObj[2]
+ });
+ },
+ _compare: function (smallDate, bigDate) {
+ smallDate = Date.parseDateTime(smallDate, "%Y-%X-%d").print("%Y-%X-%d");
+ bigDate = Date.parseDateTime(bigDate, "%Y-%X-%d").print("%Y-%X-%d");
+ return BI.isNotNull(smallDate) && BI.isNotNull(bigDate) && smallDate > bigDate;
+ },
+ _setTitle: function (v) {
+ this.left.setTitle(v);
+ this.right.setTitle(v);
+ this.label.setTitle(v);
+ },
+ _clearTitle: function () {
+ this.left.setTitle("");
+ this.right.setTitle("");
+ this.label.setTitle("");
+ },
+ setValue: function (date) {
+ date = date || {};
+ this.left.setValue(date.start);
+ this.right.setValue(date.end);
+ },
+ getValue: function () {
+ return {start: this.left.getValue(), end: this.right.getValue()};
+ }
+});
+BI.TimeInterval.EVENT_VALID = "EVENT_VALID";
+BI.TimeInterval.EVENT_ERROR = "EVENT_ERROR";
+BI.TimeInterval.EVENT_CHANGE = "EVENT_CHANGE";
+BI.shortcut("bi.time_interval", BI.TimeInterval);
\ No newline at end of file