Jforrester has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/306296

Change subject: Revert "Have GroupElement use OO.EmitterList"
......................................................................

Revert "Have GroupElement use OO.EmitterList"

This reverts commit 6278adf528abd334c353031cbb66b146696dfc74.

Breaks the toolbars demo, didn't notice in testing on other widgets.

Change-Id: I2cb6e4722f3ac7eaf38c2142f771acdae2bdddec
---
M src/mixins/GroupElement.js
1 file changed, 171 insertions(+), 80 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/oojs/ui refs/changes/96/306296/1

diff --git a/src/mixins/GroupElement.js b/src/mixins/GroupElement.js
index d07bb35..49908d4 100644
--- a/src/mixins/GroupElement.js
+++ b/src/mixins/GroupElement.js
@@ -8,7 +8,6 @@
  *
  * @abstract
  * @class
- * @mixins OO.EmitterList
  *
  * @constructor
  * @param {Object} [config] Configuration options
@@ -19,17 +18,14 @@
        // Configuration initialization
        config = config || {};
 
-       // Mixin constructors
-       OO.EmitterList.call( this );
-
        // Properties
        this.$group = null;
+       this.items = [];
+       this.aggregateItemEvents = {};
 
        // Initialization
        this.setGroupElement( config.$group || $( '<div>' ) );
 };
-
-OO.mixinClass( OO.ui.mixin.GroupElement, OO.EmitterList );
 
 /* Events */
 
@@ -57,6 +53,28 @@
        for ( i = 0, len = this.items.length; i < len; i++ ) {
                this.$group.append( this.items[ i ].$element );
        }
+};
+
+/**
+ * Check if a group contains no items.
+ *
+ * @return {boolean} Group is empty
+ */
+OO.ui.mixin.GroupElement.prototype.isEmpty = function () {
+       return !this.items.length;
+};
+
+/**
+ * Get all items in the group.
+ *
+ * The method returns an array of item references (e.g., [button1, button2, 
button3]) and is useful
+ * when synchronizing groups of items, or whenever the references are required 
(e.g., when removing items
+ * from a group).
+ *
+ * @return {OO.ui.Element[]} An array of items.
+ */
+OO.ui.mixin.GroupElement.prototype.getItems = function () {
+       return this.items.slice( 0 );
 };
 
 /**
@@ -106,104 +124,177 @@
 };
 
 /**
- * @inheritdoc
- */
-OO.ui.mixin.GroupElement.prototype.addItems = function ( items, index ) {
-       // Mixin method
-       OO.EmitterList.prototype.addItems.call( this, items, index );
-
-       // Event
-       this.emit( 'change', this.getItems() );
-
-       return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.mixin.GroupElement.prototype.moveItem = function ( item, newIndex ) {
-       // Get the normalized index for the move by calling the parent
-       var index = OO.EmitterList.prototype.insertItem.call( this, item, 
newIndex );
-
-       this.attachElementToDom( item, index );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.mixin.GroupElement.prototype.insertItem = function ( item, index ) {
-       // Get the normalized index for the move by calling the parent
-       index = OO.EmitterList.prototype.insertItem.call( this, item, index );
-
-       item.setElementGroup( this );
-       this.attachElementToDom( item, index );
-
-       return index;
-};
-
-/**
- * Attach the item element into the DOM in its proper place.
+ * Aggregate the events emitted by the group.
  *
- * @private
- * @param {OO.EventEmitter} item Item
- * @param {number} index Insertion index
+ * When events are aggregated, the group will listen to all contained items 
for the event,
+ * and then emit the event under a new name. The new event will contain an 
additional leading
+ * parameter containing the item that emitted the original event. Other 
arguments emitted from
+ * the original event are passed through.
+ *
+ * @param {Object.<string,string|null>} events An object keyed by the name of 
the event that should be
+ *  aggregated  (e.g., ‘click’) and the value of the new name to use (e.g., 
‘groupClick’).
+ *  A `null` value will remove aggregated events.
+
+ * @throws {Error} An error is thrown if aggregation already exists.
  */
-OO.ui.mixin.GroupElement.prototype.attachElementToDom = function ( item, index 
) {
-       if ( index === undefined || index < 0 || index >= this.items.length - 1 
) {
-               this.$group.append( item.$element.get( 0 ) );
-       } else {
-               this.items[ index + 1 ].$element.before( item.$element.get( 0 ) 
);
-       }
-};
+OO.ui.mixin.GroupElement.prototype.aggregate = function ( events ) {
+       var i, len, item, add, remove, itemEvent, groupEvent;
 
-/**
- * @inheritdoc
- */
-OO.ui.mixin.GroupElement.prototype.removeItems = function ( items ) {
-       var i, item, index;
+       for ( itemEvent in events ) {
+               groupEvent = events[ itemEvent ];
 
-       if ( !Array.isArray( items ) ) {
-               items = [ items ];
-       }
+               // Remove existing aggregated event
+               if ( Object.prototype.hasOwnProperty.call( 
this.aggregateItemEvents, itemEvent ) ) {
+                       // Don't allow duplicate aggregations
+                       if ( groupEvent ) {
+                               throw new Error( 'Duplicate item event 
aggregation for ' + itemEvent );
+                       }
+                       // Remove event aggregation from existing items
+                       for ( i = 0, len = this.items.length; i < len; i++ ) {
+                               item = this.items[ i ];
+                               if ( item.connect && item.disconnect ) {
+                                       remove = {};
+                                       remove[ itemEvent ] = [ 'emit', 
this.aggregateItemEvents[ itemEvent ], item ];
+                                       item.disconnect( this, remove );
+                               }
+                       }
+                       // Prevent future items from aggregating event
+                       delete this.aggregateItemEvents[ itemEvent ];
+               }
 
-       if ( items.length > 0 ) {
-               // Remove specific items
-               for ( i = 0; i < items.length; i++ ) {
-                       item = items[ i ];
-                       index = this.items.indexOf( item );
-                       if ( index !== -1 ) {
-                               item.setElementGroup( null );
-                               item.$element.detach();
+               // Add new aggregate event
+               if ( groupEvent ) {
+                       // Make future items aggregate event
+                       this.aggregateItemEvents[ itemEvent ] = groupEvent;
+                       // Add event aggregation to existing items
+                       for ( i = 0, len = this.items.length; i < len; i++ ) {
+                               item = this.items[ i ];
+                               if ( item.connect && item.disconnect ) {
+                                       add = {};
+                                       add[ itemEvent ] = [ 'emit', 
groupEvent, item ];
+                                       item.connect( this, add );
+                               }
                        }
                }
        }
+};
 
-       // Mixin method
-       OO.EmitterList.prototype.removeItems.call( this, items );
+/**
+ * Add items to the group.
+ *
+ * Items will be added to the end of the group array unless the optional 
`index` parameter specifies
+ * a different insertion point. Adding an existing item will move it to the 
end of the array or the point specified by the `index`.
+ *
+ * @param {OO.ui.Element[]} items An array of items to add to the group
+ * @param {number} [index] Index of the insertion point
+ * @chainable
+ */
+OO.ui.mixin.GroupElement.prototype.addItems = function ( items, index ) {
+       var i, len, item, itemEvent, events, currentIndex,
+               itemElements = [];
 
-       // Event
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[ i ];
+
+               // Check if item exists then remove it first, effectively 
"moving" it
+               currentIndex = this.items.indexOf( item );
+               if ( currentIndex >= 0 ) {
+                       this.removeItems( [ item ] );
+                       // Adjust index to compensate for removal
+                       if ( currentIndex < index ) {
+                               index--;
+                       }
+               }
+               // Add the item
+               if ( item.connect && item.disconnect && !$.isEmptyObject( 
this.aggregateItemEvents ) ) {
+                       events = {};
+                       for ( itemEvent in this.aggregateItemEvents ) {
+                               events[ itemEvent ] = [ 'emit', 
this.aggregateItemEvents[ itemEvent ], item ];
+                       }
+                       item.connect( this, events );
+               }
+               item.setElementGroup( this );
+               itemElements.push( item.$element.get( 0 ) );
+       }
+
+       if ( index === undefined || index < 0 || index >= this.items.length ) {
+               this.$group.append( itemElements );
+               this.items.push.apply( this.items, items );
+       } else if ( index === 0 ) {
+               this.$group.prepend( itemElements );
+               this.items.unshift.apply( this.items, items );
+       } else {
+               this.items[ index ].$element.before( itemElements );
+               this.items.splice.apply( this.items, [ index, 0 ].concat( items 
) );
+       }
+
        this.emit( 'change', this.getItems() );
-
        return this;
 };
 
 /**
- * @inheritdoc
+ * Remove the specified items from a group.
+ *
+ * Removed items are detached (not removed) from the DOM so that they may be 
reused.
+ * To remove all items from a group, you may wish to use the #clearItems 
method instead.
+ *
+ * @param {OO.ui.Element[]} items An array of items to remove
+ * @chainable
+ */
+OO.ui.mixin.GroupElement.prototype.removeItems = function ( items ) {
+       var i, len, item, index, events, itemEvent;
+
+       // Remove specific items
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[ i ];
+               index = this.items.indexOf( item );
+               if ( index !== -1 ) {
+                       if ( item.connect && item.disconnect && 
!$.isEmptyObject( this.aggregateItemEvents ) ) {
+                               events = {};
+                               for ( itemEvent in this.aggregateItemEvents ) {
+                                       events[ itemEvent ] = [ 'emit', 
this.aggregateItemEvents[ itemEvent ], item ];
+                               }
+                               item.disconnect( this, events );
+                       }
+                       item.setElementGroup( null );
+                       this.items.splice( index, 1 );
+                       item.$element.detach();
+               }
+       }
+
+       this.emit( 'change', this.getItems() );
+       return this;
+};
+
+/**
+ * Clear all items from the group.
+ *
+ * Cleared items are detached from the DOM, not removed, so that they may be 
reused.
+ * To remove only a subset of items from a group, use the #removeItems method.
+ *
+ * @chainable
  */
 OO.ui.mixin.GroupElement.prototype.clearItems = function () {
-       var i, len, item;
+       var i, len, item, remove, itemEvent;
 
+       // Remove all items
        for ( i = 0, len = this.items.length; i < len; i++ ) {
                item = this.items[ i ];
+               if (
+                       item.connect && item.disconnect &&
+                       !$.isEmptyObject( this.aggregateItemEvents )
+               ) {
+                       remove = {};
+                       if ( Object.prototype.hasOwnProperty.call( 
this.aggregateItemEvents, itemEvent ) ) {
+                               remove[ itemEvent ] = [ 'emit', 
this.aggregateItemEvents[ itemEvent ], item ];
+                       }
+                       item.disconnect( this, remove );
+               }
                item.setElementGroup( null );
                item.$element.detach();
        }
 
-       // Mixin method
-       OO.EmitterList.prototype.clearItems.call( this );
-
-       // Event
        this.emit( 'change', this.getItems() );
-
+       this.items = [];
        return this;
 };

-- 
To view, visit https://gerrit.wikimedia.org/r/306296
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I2cb6e4722f3ac7eaf38c2142f771acdae2bdddec
Gerrit-PatchSet: 1
Gerrit-Project: oojs/ui
Gerrit-Branch: master
Gerrit-Owner: Jforrester <jforres...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to