Mooeypoo has uploaded a new change for review.
https://gerrit.wikimedia.org/r/243068
Change subject: [wip] Add an OO.List object
......................................................................
[wip] Add an OO.List object
Upstream ooui's GroupElement into a stripped-down OO.List that
handles a group of items and their events.
Change-Id: Ib94e4e4a49011736b3027239e6836343901a9022
---
A src/List.js
1 file changed, 246 insertions(+), 0 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/oojs/core refs/changes/68/243068/1
diff --git a/src/List.js b/src/List.js
new file mode 100644
index 0000000..5224a7f
--- /dev/null
+++ b/src/List.js
@@ -0,0 +1,246 @@
+( function () {
+
+ /**
+ * @class OO.List
+ * @mixin
+ * Contains and manages a list of OO.EventEmitter items.
+ *
+ * @constructor
+ */
+ oo.List = function OoList() {
+ this.items = [];
+ this.aggregateItemEvents = {};
+ };
+
+ /* Events */
+
+ /**
+ * @event add Items have been added
+ * @param {OO.EventEmitter[]} items Added items
+ * @param {number} index Index items were added at
+ */
+
+ /**
+ * @event remove Items have been removed
+ * @param {OO.EventEmitter[]} items Removed items
+ */
+
+ /* Methods */
+
+ /**
+ * Get all items
+ *
+ * @return {OO.EventEmitter[]} Items in the list
+ */
+ oo.List.prototype.getItems = function () {
+ return this.items.slice( 0 );
+ };
+
+ /**
+ * Get the index of a specific item
+ *
+ * @param {OO.EventEmitter} item Requested item
+ * @return {number} Index of the item
+ */
+ oo.List.prototype.getItemIndex = function ( item ) {
+ return this.items.indexOf( item );
+ };
+
+ /**
+ * Get number of items
+ *
+ * @return {number} Number of items in the list
+ */
+ oo.List.prototype.getItemCount = function () {
+ return this.items.length;
+ };
+
+ /**
+ * Check if a list contains no items.
+ *
+ * @return {boolean} Group is empty
+ */
+ oo.List.prototype.isEmpty = function () {
+ return !this.items.length;
+ };
+
+ /**
+ * Aggregate the events emitted by the group.
+ *
+ * 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.List.prototype.aggregate = function ( events ) {
+ var i, item, add, remove, itemEvent, groupEvent;
+
+ for ( itemEvent in events ) {
+ groupEvent = events[ itemEvent ];
+
+ // 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; i < this.items.length; 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 ];
+ }
+
+ // Add new aggregate event
+ if ( groupEvent ) {
+ // Make future items aggregate event
+ this.aggregateItemEvents[ itemEvent ] =
groupEvent;
+ // Add event aggregation to existing items
+ for ( i = 0; i < this.items.length; i++ ) {
+ item = this.items[ i ];
+ if ( item.connect && item.disconnect ) {
+ add = {};
+ add[ itemEvent ] = [ 'emit',
groupEvent, item ];
+ item.connect( this, add );
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Add items
+ *
+ * @param {OO.EventEmitter[]} items Items to add
+ * @param {number} index Index to add items at
+ * @chainable
+ * @fires add
+ */
+ oo.List.prototype.addItems = function ( items, index ) {
+ var i, item, event, events, currentIndex, existingItem, at;
+
+ if ( items.length === 0 ) {
+ return this;
+ }
+
+ // Support adding existing items at new locations
+ for ( i = 0; i < items.length; i++ ) {
+ item = items[ i ];
+ existingItem = this.getItemById( item.getId() );
+
+ // Check if item exists then remove it first,
effectively "moving" it
+ currentIndex = this.items.indexOf( existingItem );
+ if ( currentIndex >= 0 ) {
+ this.removeItems( [ existingItem ] );
+ // Adjust index to compensate for removal
+ if ( currentIndex < index ) {
+ index--;
+ }
+ }
+
+ // Add the item
+ if ( item.connect && item.disconnect ) {
+ events = {};
+ for ( event in this.aggregateItemEvents ) {
+ events[ event ] = [ 'emit',
this.aggregateItemEvents[ event ], item ];
+ }
+ item.connect( this, events );
+ }
+ }
+ if ( index === undefined || index < 0 || index >=
this.items.length ) {
+ at = this.items.length;
+ } else {
+ at = index;
+ }
+
+ this.items.splice.apply( this.items, [ at, 0 ].concat( items )
);
+
+ // if ( index === undefined || index < 0 || index >=
this.items.length ) {
+ // at = this.items.length;
+ // this.items.push.apply( this.items, items );
+ // } else if ( index === 0 ) {
+ // at = 0;
+ // this.items.unshift.apply( this.items, items );
+ // } else {
+ // at = index;
+ // this.items.splice.apply( this.items, [ index, 0
].concat( items ) );
+ // }
+ this.emit( 'add', items, at );
+
+ return this;
+ };
+
+ /**
+ * Remove items
+ *
+ * @param {OO.EventEmitter[]} items Items to remove
+ * @chainable
+ * @fires remove
+ */
+ oo.List.prototype.removeItems = function ( items ) {
+ var i, item, index, remove, itemEvent,
+ removed = [];
+
+ if ( items.length === 0 ) {
+ return this;
+ }
+
+ // Remove specific items
+ for ( i = 0; i < items.length; i++ ) {
+ item = items[ i ];
+ index = this.items.indexOf( item );
+ if ( index !== -1 ) {
+ if ( item.connect && item.disconnect ) {
+ remove = {};
+ if (
Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
+ remove[ itemEvent ] = [ 'emit',
this.aggregateItemEvents[ itemEvent ], item ];
+ }
+ item.disconnect( this, remove );
+ }
+ this.items.splice( index, 1 );
+ }
+ }
+ this.emit( 'remove', removed );
+
+ return this;
+ };
+
+ /**
+ * Clear all items
+ *
+ * @fires clear
+ */
+ oo.List.prototype.clearItems = function () {
+ var i, item, remove, itemEvent,
+ items = this.items.splice( 0, this.items.length );
+
+ // Remove all items
+ for ( i = 0; i < items.length; i++ ) {
+ item = items[ i ];
+ if ( item.connect && item.disconnect ) {
+ remove = {};
+ if ( Object.prototype.hasOwnProperty.call(
this.aggregateItemEvents, itemEvent ) ) {
+ remove[ itemEvent ] = [ 'emit',
this.aggregateItemEvents[ itemEvent ], item ];
+ }
+ item.disconnect( this, remove );
+ }
+ }
+
+ this.emit( 'clear' );
+
+ return this;
+ };
+
+}() );
--
To view, visit https://gerrit.wikimedia.org/r/243068
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib94e4e4a49011736b3027239e6836343901a9022
Gerrit-PatchSet: 1
Gerrit-Project: oojs/core
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits