Mooeypoo has uploaded a new change for review.
https://gerrit.wikimedia.org/r/172325
Change subject: [wip] Adding DraggableGroupElement and DraggableElement mixins
......................................................................
[wip] Adding DraggableGroupElement and DraggableElement mixins
Adding a GroupDragElement and DragElement to ooui for a drag/drop
usability.
Change-Id: I859ff276ea97628fde28327d200ed059d018c178
---
M build/modules.json
A src/elements/DraggableElement.js
A src/elements/DraggableGroupElement.js
M src/styles/core.less
A src/styles/elements/DraggableElement.less
A src/styles/elements/DraggableGroupElement.less
6 files changed, 339 insertions(+), 0 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/oojs/ui refs/changes/25/172325/1
diff --git a/build/modules.json b/build/modules.json
index 6422127..b76b247 100644
--- a/build/modules.json
+++ b/build/modules.json
@@ -21,6 +21,8 @@
"src/elements/ButtonElement.js",
"src/elements/GroupElement.js",
+ "src/elements/DraggableElement.js",
+ "src/elements/DraggableGroupElement.js",
"src/elements/IconElement.js",
"src/elements/IndicatorElement.js",
"src/elements/LabelElement.js",
diff --git a/src/elements/DraggableElement.js b/src/elements/DraggableElement.js
new file mode 100644
index 0000000..7bab9cf
--- /dev/null
+++ b/src/elements/DraggableElement.js
@@ -0,0 +1,104 @@
+/**
+ * A mixin for an element that can be dragged and dropped.
+ * Use in conjunction with DragGroupWidget
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.DraggableElement = function OoUiDraggableElement( config ) {
+ // Configuration
+ config = config || {};
+
+ // Properties
+ this.index = null;
+
+ // Initialize and events
+ this.$element
+ .attr( 'draggable', true )
+ .addClass( 'oo-ui-DraggableElement' )
+ // This is only here until I figure out the CSS issue
+ // TODO: Remove this display rule - it should be in the css
file!!!!
+ .css( 'display', 'inline-block' )
+ .on( {
+ dragstart: this.onDragStart.bind( this ),
+ dragover: this.onDragOver.bind( this ),
+ dragend: this.onDragEnd.bind( this ),
+ drop: this.onDrop.bind( this )
+ } );
+};
+
+/**
+ * Respond to dragstart event.
+ * @param {jQuery.Event} event jQuery event
+ * @return {boolean} True
+ * @fires dragstart
+ */
+OO.ui.DraggableElement.prototype.onDragStart = function ( event ) {
+ // Define drop effect
+ event.originalEvent.dataTransfer.dropEffect = 'move';
+ event.originalEvent.dataTransfer.effectAllowed = 'move';
+
+ // Add dragging class
+ this.$element.addClass( 'oo-ui-DraggableElement-dragging' );
+
+ // Emit event
+ this.emit( 'dragstart', this );
+ return true;
+};
+
+/**
+ * Respond to dragend event.
+ * @param {jQuery.Event} event jQuery event
+ * @return {boolean} False
+ * @fires dragend
+ */
+OO.ui.DraggableElement.prototype.onDragEnd = function () {
+ this.$element.removeClass( 'oo-ui-DraggableElement-dragging' );
+
+ this.emit( 'dragend' );
+ // Return false and prevent propogation
+ return false;
+};
+
+/**
+ * Handle drop event.
+ * @param {jQuery.Event} event jQuery event
+ * @fires drop
+ */
+OO.ui.DraggableElement.prototype.onDrop = function () {
+ this.emit( 'drop', this );
+};
+
+/**
+ * In order for drag/drop to work, the dragover event must
+ * return false and stop propogation.
+ * @return {boolean} False
+ * @fires dragover
+ */
+OO.ui.DraggableElement.prototype.onDragOver = function () {
+ this.emit( 'dragover', this.index );
+ return false;
+};
+
+/**
+ * Set item index.
+ * Store it in the dom so we can access from the widget drag event
+ * @param {number} Item index
+ */
+OO.ui.DraggableElement.prototype.setIndex = function ( index ) {
+ if ( this.index !== index ) {
+ this.index = index;
+ this.$element.data( 'index', index );
+ }
+};
+
+/**
+ * Get item index
+ * @return {number} Item index
+ */
+OO.ui.DraggableElement.prototype.getIndex = function () {
+ return this.index;
+};
diff --git a/src/elements/DraggableGroupElement.js
b/src/elements/DraggableGroupElement.js
new file mode 100644
index 0000000..6db334f
--- /dev/null
+++ b/src/elements/DraggableGroupElement.js
@@ -0,0 +1,213 @@
+/**
+ * Element containing a sequence of child elements that can be dragged
+ * and dropped.
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$group] Container node, assigned to #$group, omit to use a
generated `<div>`
+ */
+OO.ui.DraggableGroupElement = function OoUiDraggableGroupElement( config ) {
+ // Configuration intialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.GroupElement.call( this, config );
+
+ // Properties
+ this.dragItem = null;
+ this.itemKeys = {};
+ this.sideInsertion = '';
+
+ // Aggregate drag drop events in items
+ this.aggregate( {
+ dragstart: 'itemDragStart',
+ dragend: 'itemDragEnd',
+ drop: 'itemDrop'
+ } );
+
+ // Item events
+ this.connect( this, {
+ itemDragStart: 'onItemDragStart',
+ itemDrop: 'onItemDrop',
+ itemDragEnd: 'onItemDragEnd'
+ } );
+
+ // Group events
+ this.$element.on( {
+ drag: $.proxy( this.onDrag, this ),
+ dragover: $.proxy( this.onDragOver, this )
+ } );
+
+ // Add items
+ if ( $.isArray( config.items ) ) {
+ this.addItems( config.items );
+ }
+
+ // Initialize
+ this.$placeholder = $( '<div>' )
+ .addClass( 'oo-ui-draggableGroupElement-placeholder' );
+ this.$element
+ .addClass( 'oo-ui-draggableGroupElement' )
+ .prepend( this.$placeholder );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.DraggableGroupElement, OO.ui.GroupElement );
+
+/* Methods */
+
+/**
+ * Respond to item drag start event
+ * @param {OO.ui.DraggableElement} item Dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {
+ // Set the height of the indicator
+ this.$placeholder.css( 'height', this.items[0].$element.outerHeight()
|| 20 );
+ this.setDragItem( item );
+};
+
+/**
+ * Respond to item drag end event
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDragEnd = function () {
+ this.unsetDragItem();
+};
+
+/**
+ * Handle drop event and switch the order of the items accordingly
+ * @param {OO.ui.DraggableElement} item Dropped item
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDrop = function ( item ) {
+ this.placeItemAtIndex( this.getDragItem(), item.getIndex() );
+};
+
+/**
+ * Switch the place of two items
+ * @param {OO.ui.DraggableElement} fromIndex [description]
+ * @param {number} toIndex [description]
+ */
+OO.ui.DraggableGroupElement.prototype.placeItemAtIndex = function ( item,
toIndex ) {
+ // If the insertion point is 'after', the insertion index
+ // is shifted to the right
+ if ( this.sideInsertion === 'after' ) {
+ toIndex++;
+ }
+
+ // Change the item position
+ this.addItems( [ item ], toIndex );
+};
+
+/**
+ * Respond to mouse move event
+ * @param {jQuery.Event} event Event details
+ */
+OO.ui.DraggableGroupElement.prototype.onDrag = function ( event ) {
+ var dragOverObj, $optionWidget, itemOffset, itemWidth, itemMidpoint,
+ dragPosition, itemIndex, sidePosition,
+ pageX = event.originalEvent.pageX,
+ pageY = event.originalEvent.pageY,
+ widgetOffset = this.$element.offset();
+
+ // Get the OptionWidget item we are dragging over
+ dragOverObj = this.getElementDocument().elementFromPoint( pageX, pageY
);
+ $optionWidget = $( dragOverObj ).closest( '.oo-ui-draggableElement' );
+ itemOffset = $optionWidget.offset();
+ itemIndex = $optionWidget.data( 'index' );
+
+ if (
+ itemOffset &&
+ this.isDragging() &&
+ itemIndex !== this.getDragItem().getIndex()
+ ) {
+ // Calculate where the mouse is relative to the item
+ itemWidth = $optionWidget.outerWidth();
+ itemMidpoint = itemOffset.left + itemWidth / 2;
+ dragPosition = pageX - widgetOffset.left;
+
+ // Which side of the item we hover over will dictate
+ // where the placeholder will appear, on the left or
+ // on the right
+ sidePosition = dragPosition < itemMidpoint ? itemOffset.left :
itemOffset.left + itemWidth;
+ // Store whether we are before or after an item to rearrange
+ // Also account for RTL, as this is flipped
+ if ( this.$element.css( 'direction' ) === 'rtl' ) {
+ this.sideInsertion = dragPosition < itemMidpoint ?
'after' : 'before';
+ } else {
+ this.sideInsertion = dragPosition < itemMidpoint ?
'before' : 'after';
+ }
+
+ // Add drop indicator between objects
+ if ( this.sideInsertion ) {
+ this.$placeholder
+ .css( {
+ left: sidePosition,
+ top: itemOffset.top
+ } )
+ .show();
+ } else {
+ this.$placeholder
+ .css( {
+ left: 0,
+ top: itemOffset.top
+ } )
+ .hide();
+ }
+ } else {
+ // This means the item was dragged outside the widget
+ this.$placeholder
+ .css( 'left', 0 )
+ .hide();
+ }
+
+};
+
+/**
+ * Set a dragged item
+ * @param {OO.ui.DraggableElement} item Dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.setDragItem = function ( item ) {
+ this.dragItem = item;
+};
+
+/**
+ * Unset the current dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.unsetDragItem = function () {
+ this.dragItem = null;
+ this.$placeholder.hide();
+ this.sideInsertion = '';
+};
+
+/**
+ * Get the current dragged item
+ * @return {OO.ui.DraggableElement|null} item Dragged item or null if no item
is dragged
+ */
+OO.ui.DraggableGroupElement.prototype.getDragItem = function () {
+ return this.dragItem;
+};
+
+/**
+ * Check if there's an item being dragged.
+ * @return {Boolean} Item is being dragged
+ */
+OO.ui.DraggableGroupElement.prototype.isDragging = function () {
+ return this.getDragItem() !== null;
+};
+
+/**
+ * Expand the addItems method to store item indeces
+ */
+OO.ui.DraggableGroupElement.prototype.addItems = function ( items, index ) {
+ var i;
+ // Parent
+ OO.ui.GroupElement.prototype.addItems.call( this, items, index );
+
+ // Map the index of each object
+ for ( i = 0; i < this.items.length; i++ ) {
+ this.items[i].setIndex( i );
+ }
+};
diff --git a/src/styles/core.less b/src/styles/core.less
index 139384c..89d4745 100644
--- a/src/styles/core.less
+++ b/src/styles/core.less
@@ -19,6 +19,8 @@
@import 'elements/ButtonElement.less';
@import 'elements/ClippableElement.less';
@import 'elements/FlaggedElement.less';
+@import 'elements/DraggableElement.less';
+@import 'elements/DraggableGroupElement.less';
@import 'elements/GroupElement.less';
@import 'elements/IconElement.less';
@import 'elements/IndicatorElement.less';
diff --git a/src/styles/elements/DraggableElement.less
b/src/styles/elements/DraggableElement.less
new file mode 100644
index 0000000..6485580
--- /dev/null
+++ b/src/styles/elements/DraggableElement.less
@@ -0,0 +1,10 @@
+@import '../common';
+
+.oo-ui-draggableElement {
+ display: inline-block;
+}
+
+.oo-ui-draggableElement-dragging {
+ background: #666666;
+ opacity: 0.4;
+}
diff --git a/src/styles/elements/DraggableGroupElement.less
b/src/styles/elements/DraggableGroupElement.less
new file mode 100644
index 0000000..7a5860f
--- /dev/null
+++ b/src/styles/elements/DraggableGroupElement.less
@@ -0,0 +1,8 @@
+@import '../common';
+
+.oo-ui-draggableGroupElement-placeholder {
+ position: absolute;
+ display: block;
+ width: 2px;
+ background-color: #2947C2;
+}
--
To view, visit https://gerrit.wikimedia.org/r/172325
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I859ff276ea97628fde28327d200ed059d018c178
Gerrit-PatchSet: 1
Gerrit-Project: oojs/ui
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits