"ext-iconv": "*",
"liuggio/statsd-php-client": "1.0.18",
"mediawiki/at-ease": "1.1.0",
- "oojs/oojs-ui": "0.15.4",
+ "oojs/oojs-ui": "0.16.0",
"oyejorge/less.php": "1.7.0.10",
"php": ">=5.5.9",
"psr/log": "1.0.0",
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Luuva"
+ ]
+ },
+ "ooui-dialog-message-accept": "Liáu-kái",
+ "ooui-dialog-message-reject": "Chhú-siau",
+ "ooui-dialog-process-error": "Ū mi̍h bô hó-sè",
+ "ooui-dialog-process-dismiss": "Koaiⁿ tiāu",
+ "ooui-dialog-process-retry": "Koh chhì khòaⁿ-māi",
+ "ooui-dialog-process-continue": "Kè-sio̍k",
+ "ooui-selectfile-button-select": "Soán-tek 1-ê tóng-àn",
+ "ooui-selectfile-not-supported": "Só͘ soán ê tóng-àn bô siū chi-chhî",
+ "ooui-selectfile-placeholder": "Iáu-bē soán tóng-àn",
+ "ooui-selectfile-dragdrop-placeholder": "Kā tóng-àn tàn chia"
+}
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:23Z
+ * Date: 2016-02-22T22:33:33Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:27Z
+ * Date: 2016-02-22T22:33:37Z
*/
.oo-ui-element-hidden {
display: none !important;
.oo-ui-indicatorElement.oo-ui-indicatorElement-indicator {
opacity: 0.8;
}
+.oo-ui-labelElement .oo-ui-labelElement-label-highlight {
+ font-weight: bold;
+}
.oo-ui-pendingElement-pending {
background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
}
width: 100%;
max-width: 50em;
}
+.oo-ui-dropdownInputWidget .oo-ui-dropdownWidget,
+.oo-ui-dropdownInputWidget select {
+ display: block;
+}
.oo-ui-dropdownInputWidget select {
- display: inline-block;
width: 100%;
resize: none;
-webkit-box-sizing: border-box;
}
.oo-ui-textInputWidget input,
.oo-ui-textInputWidget textarea {
- display: inline-block;
+ display: block;
width: 100%;
resize: none;
-webkit-box-sizing: border-box;
}
.oo-ui-dropdownWidget-handle {
width: 100%;
- display: inline-block;
+ display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: default;
opacity: 0.2;
}
-.oo-ui-comboBoxInputWidget > .oo-ui-selectWidget {
- margin-top: -3px;
-}
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:27Z
+ * Date: 2016-02-22T22:33:37Z
*/
.oo-ui-element-hidden {
display: none !important;
background-position: center center;
background-repeat: no-repeat;
}
+.oo-ui-labelElement .oo-ui-labelElement-label-highlight {
+ font-weight: bold;
+}
.oo-ui-pendingElement-pending {
background-image: /* @embed */ url(themes/mediawiki/images/textures/pending.gif);
}
width: 100%;
max-width: 50em;
}
+.oo-ui-dropdownInputWidget .oo-ui-dropdownWidget,
+.oo-ui-dropdownInputWidget select {
+ display: block;
+}
.oo-ui-dropdownInputWidget select {
- display: inline-block;
width: 100%;
resize: none;
-webkit-box-sizing: border-box;
}
.oo-ui-textInputWidget input,
.oo-ui-textInputWidget textarea {
- display: inline-block;
+ display: block;
width: 100%;
resize: none;
-webkit-box-sizing: border-box;
}
.oo-ui-dropdownWidget-handle {
width: 100%;
- display: inline-block;
+ display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.oo-ui-dropdownWidget.oo-ui-indicatorElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
margin-right: 2em;
}
-.oo-ui-dropdownWidget .oo-ui-selectWidget {
- border-top-color: #ffffff;
-}
.oo-ui-comboBoxInputWidget {
display: inline-block;
position: relative;
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:23Z
+ * Date: 2016-02-22T22:33:33Z
*/
( function ( OO ) {
if ( immediate && !timeout ) {
func.apply( context, args );
}
- clearTimeout( timeout );
- timeout = setTimeout( later, wait );
+ if ( !timeout || wait ) {
+ clearTimeout( timeout );
+ timeout = setTimeout( later, wait );
+ }
};
};
* @param {HTMLElement} node
* @param {string} eventName
* @param {Function} handler
- * @deprecated
+ * @deprecated since 0.15.0
*/
OO.ui.addCaptureEventListener = function ( node, eventName, handler ) {
node.addEventListener( eventName, handler, true );
* @param {HTMLElement} node
* @param {string} eventName
* @param {Function} handler
- * @deprecated
+ * @deprecated since 0.15.0
*/
OO.ui.removeCaptureEventListener = function ( node, eventName, handler ) {
node.removeEventListener( eventName, handler, true );
* as a plaintext string, a jQuery selection of elements, or a function that will produce a string
* in the future. See the [OOjs UI documentation on MediaWiki] [2] for examples.
* [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Labels
- * @cfg {boolean} [autoFitLabel=true] Fit the label to the width of the parent element.
- * The label will be truncated to fit if necessary.
*/
OO.ui.mixin.LabelElement = function OoUiMixinLabelElement( config ) {
// Configuration initialization
// Properties
this.$label = null;
this.label = null;
- this.autoFitLabel = config.autoFitLabel === undefined || !!config.autoFitLabel;
// Initialization
this.setLabel( config.label || this.constructor.static.label );
*/
OO.ui.mixin.LabelElement.static.label = null;
+/* Static methods */
+
+/**
+ * Highlight the first occurrence of the query in the given text
+ *
+ * @param {string} text Text
+ * @param {string} query Query to find
+ * @return {jQuery} Text with the first match of the query
+ * sub-string wrapped in highlighted span
+ */
+OO.ui.mixin.LabelElement.static.highlightQuery = function ( text, query ) {
+ var $result = $( '<span>' ),
+ offset = text.toLowerCase().indexOf( query.toLowerCase() );
+
+ if ( !query.length || offset === -1 ) {
+ return $result.text( text );
+ }
+ $result.append(
+ document.createTextNode( text.slice( 0, offset ) ),
+ $( '<span>' )
+ .addClass( 'oo-ui-labelElement-label-highlight' )
+ .text( text.slice( offset, offset + query.length ) ),
+ document.createTextNode( text.slice( offset + query.length ) )
+ );
+ return $result.contents();
+};
+
/* Methods */
/**
return this;
};
+/**
+ * Set the label as plain text with a highlighted query
+ *
+ * @param {string} text Text label to set
+ * @param {string} query Substring of text to highlight
+ * @chainable
+ */
+OO.ui.mixin.LabelElement.prototype.setHighlightedQuery = function ( text, query ) {
+ return this.setLabel( this.constructor.static.highlightQuery( text, query ) );
+};
+
/**
* Get the label.
*
* Fit the label.
*
* @chainable
+ * @deprecated since 0.16.0
*/
OO.ui.mixin.LabelElement.prototype.fitLabel = function () {
- if ( this.$label && this.$label.autoEllipsis && this.autoFitLabel ) {
- this.$label.autoEllipsis( { hasSpan: false, tooltip: true } );
- }
-
return this;
};
OO.ui.mixin.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
// Properties
- this.newItems = null;
this.autoHide = config.autoHide === undefined || !!config.autoHide;
this.filterFromInput = !!config.filterFromInput;
this.$input = config.$input ? config.$input : config.input ? config.input.$input : null;
* @inheritdoc
*/
OO.ui.MenuSelectWidget.prototype.addItems = function ( items, index ) {
- var i, len, item;
-
// Parent method
OO.ui.MenuSelectWidget.parent.prototype.addItems.call( this, items, index );
- // Auto-initialize
- if ( !this.newItems ) {
- this.newItems = [];
- }
-
- for ( i = 0, len = items.length; i < len; i++ ) {
- item = items[ i ];
- if ( this.isVisible() ) {
- // Defer fitting label until item has been attached
- item.fitLabel();
- } else {
- this.newItems.push( item );
- }
- }
-
// Reevaluate clipping
this.clip();
* @inheritdoc
*/
OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
- var i, len, change;
+ var change;
visible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;
change = visible !== this.isVisible();
this.bindKeyDownListener();
this.bindKeyPressListener();
- if ( this.newItems && this.newItems.length ) {
- for ( i = 0, len = this.newItems.length; i < len; i++ ) {
- this.newItems[ i ].fitLabel();
- }
- this.newItems = null;
- }
this.toggleClipping( true );
if ( this.getSelectedItem() ) {
/**
* Set the directionality of the input, either RTL (right-to-left) or LTR (left-to-right).
*
- * @deprecated since v0.13.1, use #setDir directly
+ * @deprecated since v0.13.1; use #setDir directly
* @param {boolean} isRTL Directionality is right-to-left
* @chainable
*/
* @protected
*/
OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
- return $( '<input type="checkbox" />' );
+ return $( '<input>' ).attr( 'type', 'checkbox' );
};
/**
if ( config.$input ) {
return config.$input.addClass( 'oo-ui-element-hidden' );
}
- return $( '<input type="hidden">' );
+ return $( '<input>' ).attr( 'type', 'hidden' );
};
/**
* @protected
*/
OO.ui.RadioInputWidget.prototype.getInputElement = function () {
- return $( '<input type="radio" />' );
+ return $( '<input>' ).attr( 'type', 'radio' );
};
/**
* @protected
*/
OO.ui.RadioSelectInputWidget.prototype.getInputElement = function () {
- return $( '<input type="hidden">' );
+ return $( '<input>' ).attr( 'type', 'hidden' );
};
/**
OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
return config.multiline ?
$( '<textarea>' ) :
- $( '<input type="' + this.getSaneType( config ) + '" />' );
+ $( '<input>' ).attr( 'type', this.getSaneType( config ) );
};
/**
* This method returns a promise that resolves with a boolean `true` if the current value is
* considered valid according to the supplied {@link #validate validation pattern}.
*
- * @deprecated
+ * @deprecated since v0.12.3
* @return {jQuery.Promise} A promise that resolves to a boolean `true` if the value is valid.
*/
OO.ui.TextInputWidget.prototype.isValid = function () {
*/
OO.ui.TextInputWidget.prototype.setLabelPosition = function ( labelPosition ) {
this.labelPosition = labelPosition;
- this.updatePosition();
+ if ( this.label ) {
+ // If there is no label and we only change the position, #updatePosition is a no-op,
+ // but it takes really a lot of work to do nothing.
+ this.updatePosition();
+ }
return this;
};
/**
* @class
- * @deprecated Use OO.ui.ComboBoxInputWidget instead.
+ * @deprecated since 0.13.2; use OO.ui.ComboBoxInputWidget instead
*/
OO.ui.ComboBoxWidget = OO.ui.ComboBoxInputWidget;
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:23Z
+ * Date: 2016-02-22T22:33:33Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:27Z
+ * Date: 2016-02-22T22:33:37Z
*/
.oo-ui-popupTool .oo-ui-popupWidget-popup,
.oo-ui-popupTool .oo-ui-popupWidget-anchor {
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:27Z
+ * Date: 2016-02-22T22:33:37Z
*/
.oo-ui-popupTool .oo-ui-popupWidget-popup,
.oo-ui-popupTool .oo-ui-popupWidget-anchor {
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:23Z
+ * Date: 2016-02-22T22:33:33Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:27Z
+ * Date: 2016-02-22T22:33:37Z
*/
-.oo-ui-draggableElement {
- cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
+.oo-ui-draggableElement-handle.oo-ui-widget-enabled {
+ cursor: move;
+ cursor: url(images/grab.cur );
+ cursor: -webkit-grab;
+ cursor: -moz-grab;
+ cursor: grab;
+}
+.oo-ui-draggableElement-placeholder {
+ opacity: 0.2;
}
-.oo-ui-draggableElement-dragging {
- cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
- background: rgba(0, 0, 0, 0.2);
- opacity: 0.4;
+.oo-ui-draggableElement.oo-ui-widget-enabled:active {
+ cursor: move;
+ cursor: url(images/grabbing.cur );
+ cursor: -webkit-grabbing;
+ cursor: -moz-grabbing;
+ cursor: grabbing;
}
.oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement.oo-ui-optionWidget {
display: inline-block;
}
-.oo-ui-draggableGroupElement-placeholder {
- position: absolute;
- display: block;
- background: rgba(0, 0, 0, 0.4);
-}
.oo-ui-lookupElement > .oo-ui-menuSelectWidget {
z-index: 1;
width: 100%;
}
.oo-ui-capsuleMultiSelectWidget-handle {
width: 100%;
- display: inline-block;
+ display: block;
position: relative;
}
.oo-ui-capsuleMultiSelectWidget-content {
.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
opacity: 0.2;
}
-.oo-ui-capsuleMultiSelectWidget .oo-ui-selectWidget {
- border-top-color: #ffffff;
-}
.oo-ui-capsuleItemWidget {
position: relative;
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
}
-.oo-ui-capsuleItemWidget .oo-ui-buttonElement {
- margin-top: -1.6em;
- padding-left: 0.3em;
-}
.oo-ui-capsuleItemWidget:focus {
outline: none;
border-color: #087ecc;
}
-.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-labelElement-label {
- padding-right: 1.3375em;
-}
-.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-indicatorElement-indicator {
- position: absolute;
- right: 0.4em;
- top: 0;
- width: 0.9375em;
- height: 100%;
- background-repeat: no-repeat;
-}
-.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-indicator-clear {
- cursor: pointer;
-}
.oo-ui-capsuleItemWidget.oo-ui-widget-disabled {
opacity: 0.5;
-webkit-transform: translate3d(0, 0, 0);
background: #eeeeee;
border-color: #cccccc;
}
-.oo-ui-capsuleItemWidget.oo-ui-widget-disabled > .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
+.oo-ui-capsuleItemWidget > .oo-ui-buttonElement {
+ float: right;
+ margin-top: -0.1em;
+ margin-right: -0.4em;
}
.oo-ui-searchWidget-query {
position: absolute;
.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget {
width: 2.25em;
}
-.oo-ui-numberInputWidget-minusButton.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+.oo-ui-numberInputWidget-minusButton.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right-width: 0;
}
-.oo-ui-numberInputWidget-plusButton.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+.oo-ui-numberInputWidget-plusButton.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left-width: 0;
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:27Z
+ * Date: 2016-02-22T22:33:37Z
*/
-.oo-ui-draggableElement {
- cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
+.oo-ui-draggableElement-handle.oo-ui-widget-enabled {
+ cursor: move;
+ cursor: url(images/grab.cur );
+ cursor: -webkit-grab;
+ cursor: -moz-grab;
+ cursor: grab;
+}
+.oo-ui-draggableElement-placeholder {
+ opacity: 0.2;
}
-.oo-ui-draggableElement-dragging {
- cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
- background: rgba(0, 0, 0, 0.2);
- opacity: 0.4;
+.oo-ui-draggableElement.oo-ui-widget-enabled:active {
+ cursor: move;
+ cursor: url(images/grabbing.cur );
+ cursor: -webkit-grabbing;
+ cursor: -moz-grabbing;
+ cursor: grabbing;
}
.oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement.oo-ui-optionWidget {
display: inline-block;
}
-.oo-ui-draggableGroupElement-placeholder {
- position: absolute;
- display: block;
- background: rgba(0, 0, 0, 0.4);
-}
.oo-ui-lookupElement > .oo-ui-menuSelectWidget {
z-index: 1;
width: 100%;
}
.oo-ui-capsuleMultiSelectWidget-handle {
width: 100%;
- display: inline-block;
+ display: block;
position: relative;
}
.oo-ui-capsuleMultiSelectWidget-content {
.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
opacity: 0.2;
}
-.oo-ui-capsuleMultiSelectWidget .oo-ui-selectWidget {
- border-top-color: #ffffff;
-}
.oo-ui-capsuleItemWidget {
position: relative;
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
}
-.oo-ui-capsuleItemWidget .oo-ui-buttonElement {
- margin-top: -1.6em;
- padding-left: 0.3em;
-}
.oo-ui-capsuleItemWidget:focus {
outline: none;
border-color: #347bff;
}
-.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-labelElement-label {
- padding-right: 1.3375em;
-}
-.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-indicatorElement-indicator {
- position: absolute;
- right: 0.4em;
- top: 0;
- width: 0.9375em;
- height: 100%;
- background-repeat: no-repeat;
-}
-.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-indicator-clear {
- cursor: pointer;
-}
.oo-ui-capsuleItemWidget.oo-ui-widget-disabled {
color: #cccccc;
text-shadow: 0 1px 1px #ffffff;
border-color: #dddddd;
background-color: #f3f3f3;
}
-.oo-ui-capsuleItemWidget.oo-ui-widget-disabled > .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
+.oo-ui-capsuleItemWidget > .oo-ui-buttonElement {
+ float: right;
+ margin-top: -0.2em;
+ margin-left: 0.4em;
}
.oo-ui-searchWidget-query {
position: absolute;
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:23Z
+ * Date: 2016-02-22T22:33:33Z
*/
( function ( OO ) {
* @class
*
* @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$handle] The part of the element which can be used for dragging, defaults to the whole element
*/
-OO.ui.mixin.DraggableElement = function OoUiMixinDraggableElement() {
+OO.ui.mixin.DraggableElement = function OoUiMixinDraggableElement( config ) {
+ config = config || {};
+
// Properties
this.index = null;
+ this.$handle = config.$handle || this.$element;
+ this.wasHandleUsed = null;
// Initialize and events
- this.$element
+ this.$element.addClass( 'oo-ui-draggableElement' )
+ // We make the entire element draggable, not just the handle, so that
+ // the whole element appears to move. wasHandleUsed prevents drags from
+ // starting outside the handle
.attr( 'draggable', true )
- .addClass( 'oo-ui-draggableElement' )
.on( {
+ mousedown: this.onDragMouseDown.bind( this ),
dragstart: this.onDragStart.bind( this ),
dragover: this.onDragOver.bind( this ),
dragend: this.onDragEnd.bind( this ),
drop: this.onDrop.bind( this )
} );
+ this.$handle.addClass( 'oo-ui-draggableElement-handle' );
};
OO.initClass( OO.ui.mixin.DraggableElement );
/* Methods */
+/**
+ * Respond to mousedown event.
+ *
+ * @private
+ * @param {jQuery.Event} event jQuery event
+ */
+OO.ui.mixin.DraggableElement.prototype.onDragMouseDown = function ( e ) {
+ this.wasHandleUsed =
+ // Optimization: if the handle is the whole element this is always true
+ this.$handle[ 0 ] === this.$element[ 0 ] ||
+ // Check the mousedown occurred inside the handle
+ OO.ui.contains( this.$handle[ 0 ], e.target, true );
+};
+
/**
* Respond to dragstart event.
*
* @fires dragstart
*/
OO.ui.mixin.DraggableElement.prototype.onDragStart = function ( e ) {
- var dataTransfer = e.originalEvent.dataTransfer;
+ var element = this,
+ dataTransfer = e.originalEvent.dataTransfer;
+
+ if ( !this.wasHandleUsed ) {
+ return false;
+ }
+
// Define drop effect
dataTransfer.dropEffect = 'none';
dataTransfer.effectAllowed = 'move';
} catch ( err ) {
// The above is only for Firefox. Move on if it fails.
}
- // Add dragging class
- this.$element.addClass( 'oo-ui-draggableElement-dragging' );
+ // Briefly add a 'clone' class to style the browser's native drag image
+ this.$element.addClass( 'oo-ui-draggableElement-clone' );
+ // Add placeholder class after the browser has rendered the clone
+ setTimeout( function () {
+ element.$element
+ .removeClass( 'oo-ui-draggableElement-clone' )
+ .addClass( 'oo-ui-draggableElement-placeholder' );
+ } );
// Emit event
this.emit( 'dragstart', this );
return true;
* @fires dragend
*/
OO.ui.mixin.DraggableElement.prototype.onDragEnd = function () {
- this.$element.removeClass( 'oo-ui-draggableElement-dragging' );
+ this.$element.removeClass( 'oo-ui-draggableElement-placeholder' );
this.emit( 'dragend' );
};
// Properties
this.orientation = config.orientation || 'vertical';
this.dragItem = null;
- this.itemDragOver = null;
this.itemKeys = {};
- this.sideInsertion = '';
+ this.dir = null;
+ this.itemsOrder = null;
// Events
this.aggregate( {
} );
this.connect( this, {
itemDragStart: 'onItemDragStart',
- itemDrop: 'onItemDrop',
- itemDragEnd: 'onItemDragEnd'
- } );
- this.$element.on( {
- dragover: this.onDragOver.bind( this ),
- dragleave: this.onDragLeave.bind( this )
+ itemDrop: 'onItemDropOrDragEnd',
+ itemDragEnd: 'onItemDropOrDragEnd'
} );
// Initialize
if ( Array.isArray( config.items ) ) {
this.addItems( config.items );
}
- this.$placeholder = $( '<div>' )
- .addClass( 'oo-ui-draggableGroupElement-placeholder' );
this.$element
.addClass( 'oo-ui-draggableGroupElement' )
.append( this.$status )
- .toggleClass( 'oo-ui-draggableGroupElement-horizontal', this.orientation === 'horizontal' )
- .prepend( this.$placeholder );
+ .toggleClass( 'oo-ui-draggableGroupElement-horizontal', this.orientation === 'horizontal' );
};
/* Setup */
/* Events */
/**
- * A 'reorder' event is emitted when the order of items in the group changes.
+ * An item has been dragged to a new position, but not yet dropped.
+ *
+ * @event drag
+ * @param {OO.ui.mixin.DraggableElement} item Dragged item
+ * @param {number} [newIndex] New index for the item
+ */
+
+/**
+ * And item has been dropped at a new position.
*
* @event reorder
* @param {OO.ui.mixin.DraggableElement} item Reordered item
* @param {OO.ui.mixin.DraggableElement} item Dragged item
*/
OO.ui.mixin.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {
- var i, len;
-
- // Map the index of each object
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- this.items[ i ].setIndex( i );
- }
-
+ // Make a shallow copy of this.items so we can re-order it during previews
+ // without affecting the original array.
+ this.itemsOrder = this.items.slice();
+ this.updateIndexes();
if ( this.orientation === 'horizontal' ) {
- // Set the height of the indicator
- this.$placeholder.css( {
- height: item.$element.outerHeight(),
- width: 2
- } );
- } else {
- // Set the width of the indicator
- this.$placeholder.css( {
- height: 2,
- width: item.$element.outerWidth()
- } );
+ // Calculate and cache directionality on drag start - it's a little
+ // expensive and it shouldn't change while dragging.
+ this.dir = this.$element.css( 'direction' );
}
this.setDragItem( item );
};
/**
- * Respond to item drag end event
- *
- * @private
+ * Update the index properties of the items
*/
-OO.ui.mixin.DraggableGroupElement.prototype.onItemDragEnd = function () {
- this.unsetDragItem();
- return false;
+OO.ui.mixin.DraggableGroupElement.prototype.updateIndexes = function () {
+ var i, len;
+
+ // Map the index of each object
+ for ( i = 0, len = this.itemsOrder.length; i < len; i++ ) {
+ this.itemsOrder[ i ].setIndex( i );
+ }
};
/**
- * Handle drop event and switch the order of the items accordingly
+ * Handle drop or dragend event and switch the order of the items accordingly
*
* @private
* @param {OO.ui.mixin.DraggableElement} item Dropped item
- * @fires reorder
*/
-OO.ui.mixin.DraggableGroupElement.prototype.onItemDrop = function ( item ) {
- var toIndex = item.getIndex();
- // Check if the dropped item is from the current group
+OO.ui.mixin.DraggableGroupElement.prototype.onItemDropOrDragEnd = function () {
+ var targetIndex, originalIndex,
+ item = this.getDragItem();
+
// TODO: Figure out a way to configure a list of legally droppable
// elements even if they are not yet in the list
- if ( this.getDragItem() ) {
- // If the insertion point is 'after', the insertion index
- // is shifted to the right (or to the left in RTL, hence 'after')
- if ( this.sideInsertion === 'after' ) {
- toIndex++;
- }
- // Emit change event
- this.emit( 'reorder', this.getDragItem(), toIndex );
+ if ( item ) {
+ originalIndex = this.items.indexOf( item );
+ // If the item has moved forward, add one to the index to account for the left shift
+ targetIndex = item.getIndex() + ( item.getIndex() > originalIndex ? 1 : 0 );
+ this.reorder( this.getDragItem(), targetIndex );
+ this.emit( 'reorder', this.getDragItem(), targetIndex );
+ this.updateIndexes();
}
this.unsetDragItem();
// Return false to prevent propogation
return false;
};
-/**
- * Handle dragleave event.
- *
- * @private
- */
-OO.ui.mixin.DraggableGroupElement.prototype.onDragLeave = function () {
- // This means the item was dragged outside the widget
- this.$placeholder
- .css( 'left', 0 )
- .addClass( 'oo-ui-element-hidden' );
-};
-
/**
* Respond to dragover event
*
* @private
- * @param {jQuery.Event} event Event details
+ * @param {jQuery.Event} event Dragover event
+ * @fires reorder
*/
OO.ui.mixin.DraggableGroupElement.prototype.onDragOver = function ( e ) {
var dragOverObj, $optionWidget, itemOffset, itemMidpoint, itemBoundingRect,
- itemSize, cssOutput, dragPosition, itemIndex, itemPosition,
+ itemSize, cssOutput, dragPosition, overIndex, itemPosition, after,
+ targetIndex = null,
+ item = this.getDragItem(),
+ dragItemIndex = item.getIndex(),
clientX = e.originalEvent.clientX,
clientY = e.originalEvent.clientY;
itemOffset = $optionWidget.offset();
itemBoundingRect = $optionWidget[ 0 ].getBoundingClientRect();
itemPosition = $optionWidget.position();
- itemIndex = $optionWidget.data( 'index' );
+ overIndex = $optionWidget.data( 'index' );
}
if (
itemOffset &&
- this.isDragging() &&
- itemIndex !== this.getDragItem().getIndex()
+ overIndex !== dragItemIndex
) {
if ( this.orientation === 'horizontal' ) {
// Calculate where the mouse is relative to the item width
itemMidpoint = itemBoundingRect.left + itemSize / 2;
dragPosition = clientX;
// Which side of the item we hover over will dictate
- // where the placeholder will appear, on the left or
+ // where to drop the selected item, on the left or
// on the right
cssOutput = {
left: dragPosition < itemMidpoint ? itemPosition.left : itemPosition.left + itemSize,
itemMidpoint = itemBoundingRect.top + itemSize / 2;
dragPosition = clientY;
// Which side of the item we hover over will dictate
- // where the placeholder will appear, on the top or
+ // where to drop the selected item, on the top or
// on the bottom
cssOutput = {
top: dragPosition < itemMidpoint ? itemPosition.top : itemPosition.top + itemSize,
}
// Store whether we are before or after an item to rearrange
// For horizontal layout, we need to account for RTL, as this is flipped
- if ( this.orientation === 'horizontal' && this.$element.css( 'direction' ) === 'rtl' ) {
- this.sideInsertion = dragPosition < itemMidpoint ? 'after' : 'before';
+ if ( this.orientation === 'horizontal' && this.dir === 'rtl' ) {
+ after = dragPosition < itemMidpoint;
} else {
- this.sideInsertion = dragPosition < itemMidpoint ? 'before' : 'after';
+ after = dragPosition > itemMidpoint;
+ }
+ targetIndex = overIndex + ( after ? 1 : 0 );
+ // Check the targetIndex isn't immediately to the left or right of the current item (a no-op)
+ if ( targetIndex === dragItemIndex || targetIndex === dragItemIndex + 1 ) {
+ targetIndex = null;
}
- // Add drop indicator between objects
- this.$placeholder
- .css( cssOutput )
- .removeClass( 'oo-ui-element-hidden' );
- } else {
- // This means the item was dragged outside the widget
- this.$placeholder
- .css( 'left', 0 )
- .addClass( 'oo-ui-element-hidden' );
+ }
+ if ( targetIndex !== null ) {
+ if ( targetIndex > 0 ) {
+ this.$group.children().eq( targetIndex - 1 ).after( item.$element );
+ } else {
+ this.$group.prepend( item.$element );
+ }
+ // Move item in itemsOrder array. Needs to account for left shift if the item is moved forward.
+ this.itemsOrder.splice( targetIndex - ( targetIndex > dragItemIndex ? 1 : 0 ), 0,
+ this.itemsOrder.splice( dragItemIndex, 1 )[ 0 ]
+ );
+ this.updateIndexes();
+ this.emit( 'drag', item, targetIndex );
}
// Prevent default
e.preventDefault();
};
+/**
+ * Reorder the items in the group
+ *
+ * @param {OO.ui.mixin.DraggableElement} item Reordered item
+ * @param {number} newIndex New index
+ */
+OO.ui.mixin.DraggableGroupElement.prototype.reorder = function ( item, newIndex ) {
+ this.addItems( [ item ], newIndex );
+};
+
/**
* Set a dragged item
*
*/
OO.ui.mixin.DraggableGroupElement.prototype.setDragItem = function ( item ) {
this.dragItem = item;
+ this.$element.on( 'dragover', this.onDragOver.bind( this ) );
+ this.$element.addClass( 'oo-ui-draggableGroupElement-dragging' );
};
/**
*/
OO.ui.mixin.DraggableGroupElement.prototype.unsetDragItem = function () {
this.dragItem = null;
- this.itemDragOver = null;
- this.$placeholder.addClass( 'oo-ui-element-hidden' );
- this.sideInsertion = '';
+ this.$element.off( 'dragover' );
+ this.$element.removeClass( 'oo-ui-draggableGroupElement-dragging' );
};
/**
return this.dragItem;
};
-/**
- * Check if an item in the group is currently being dragged.
- *
- * @return {Boolean} Item is being dragged
- */
-OO.ui.mixin.DraggableGroupElement.prototype.isDragging = function () {
- return this.getDragItem() !== null;
-};
-
/**
* RequestManager is a mixin that manages the lifecycle of a promise-backed request for a widget, such as
* the {@link OO.ui.mixin.LookupElement}.
* @cfg {string} [notsupported] Text to display when file support is missing in the browser.
* @cfg {boolean} [droppable=true] Whether to accept files by drag and drop.
* @cfg {boolean} [showDropTarget=false] Whether to show a drop target. Requires droppable to be true.
- * @cfg {boolean} [dragDropUI=false] Deprecated alias for showDropTarget
* @cfg {Number} [thumbnailSizeLimit=20] File size limit in MiB above which to not try and show a
* preview (for performance)
*/
OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {
var dragHandler;
- // TODO: Remove in next release
- if ( config && config.dragDropUI ) {
- config.showDropTarget = true;
- }
-
// Configuration initialization
config = $.extend( {
accept: null,
OO.ui.mixin.IconElement.call( this, config );
OO.ui.mixin.IndicatorElement.call( this, config );
OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$info } ) );
- OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, { autoFitLabel: true } ) );
+ OO.ui.mixin.LabelElement.call( this, config );
// Properties
this.$info = $( '<span>' );
OO.ui.SelectFileWidget.static.isSupported = function () {
var $input;
if ( OO.ui.SelectFileWidget.static.isSupportedCache === null ) {
- $input = $( '<input type="file">' );
+ $input = $( '<input>' ).attr( 'type', 'file' );
OO.ui.SelectFileWidget.static.isSupportedCache = $input[ 0 ].files !== undefined;
}
return OO.ui.SelectFileWidget.static.isSupportedCache;
return;
}
- this.$input = $( '<input type="file">' );
+ this.$input = $( '<input>' ).attr( 'type', 'file' );
this.$input.on( 'change', this.onFileSelectedHandler );
this.$input.on( 'click', function ( e ) {
// Prevents dropTarget to get clicked which calls
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:27Z
+ * Date: 2016-02-22T22:33:37Z
*/
.oo-ui-actionWidget.oo-ui-pendingElement-pending {
background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:27Z
+ * Date: 2016-02-22T22:33:37Z
*/
.oo-ui-window {
background: transparent;
/*!
- * OOjs UI v0.15.4
+ * OOjs UI v0.16.0
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-02-17T02:03:23Z
+ * Date: 2016-02-22T22:33:33Z
*/
( function ( OO ) {
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
- <path d="M12 8C7 8 1 14 1 14s6 6 11 6l11-6s-6-6-11-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"/>
+ <path d="M12 8c-5 0-11 6-11 6s6 6 11 6 11-6 11-6-6-6-11-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"/>
<circle cx="12" cy="14" r="2"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 8C7 8 1 14 1 14s6 6 11 6l11-6s-6-6-11-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"/>
+ <path d="M12 8c-5 0-11 6-11 6s6 6 11 6 11-6 11-6-6-6-11-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"/>
<circle cx="12" cy="14" r="2"/>
</svg>