summaryrefslogtreecommitdiff
path: root/vendor/oojs/oojs-ui/src/elements/GroupElement.js
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/oojs/oojs-ui/src/elements/GroupElement.js')
-rw-r--r--vendor/oojs/oojs-ui/src/elements/GroupElement.js290
1 files changed, 290 insertions, 0 deletions
diff --git a/vendor/oojs/oojs-ui/src/elements/GroupElement.js b/vendor/oojs/oojs-ui/src/elements/GroupElement.js
new file mode 100644
index 00000000..51cf5d25
--- /dev/null
+++ b/vendor/oojs/oojs-ui/src/elements/GroupElement.js
@@ -0,0 +1,290 @@
+/**
+ * Any OOjs UI widget that contains other widgets (such as {@link OO.ui.ButtonWidget buttons} or
+ * {@link OO.ui.OptionWidget options}) mixes in GroupElement. Adding, removing, and clearing
+ * items from the group is done through the interface the class provides.
+ * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Groups
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$group] The container element created by the class. If this configuration
+ * is omitted, the group element will use a generated `<div>`.
+ */
+OO.ui.GroupElement = function OoUiGroupElement( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties
+ this.$group = null;
+ this.items = [];
+ this.aggregateItemEvents = {};
+
+ // Initialization
+ this.setGroupElement( config.$group || $( '<div>' ) );
+};
+
+/* Methods */
+
+/**
+ * Set the group element.
+ *
+ * If an element is already set, items will be moved to the new element.
+ *
+ * @param {jQuery} $group Element to use as group
+ */
+OO.ui.GroupElement.prototype.setGroupElement = function ( $group ) {
+ var i, len;
+
+ this.$group = $group;
+ 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.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.GroupElement.prototype.getItems = function () {
+ return this.items.slice( 0 );
+};
+
+/**
+ * Get an item by its data.
+ *
+ * Only the first item with matching data will be returned. To return all matching items,
+ * use the #getItemsFromData method.
+ *
+ * @param {Object} data Item data to search for
+ * @return {OO.ui.Element|null} Item with equivalent data, `null` if none exists
+ */
+OO.ui.GroupElement.prototype.getItemFromData = function ( data ) {
+ var i, len, item,
+ hash = OO.getHash( data );
+
+ for ( i = 0, len = this.items.length; i < len; i++ ) {
+ item = this.items[ i ];
+ if ( hash === OO.getHash( item.getData() ) ) {
+ return item;
+ }
+ }
+
+ return null;
+};
+
+/**
+ * Get items by their data.
+ *
+ * All items with matching data will be returned. To return only the first match, use the #getItemFromData method instead.
+ *
+ * @param {Object} data Item data to search for
+ * @return {OO.ui.Element[]} Items with equivalent data
+ */
+OO.ui.GroupElement.prototype.getItemsFromData = function ( data ) {
+ var i, len, item,
+ hash = OO.getHash( data ),
+ items = [];
+
+ for ( i = 0, len = this.items.length; i < len; i++ ) {
+ item = this.items[ i ];
+ if ( hash === OO.getHash( item.getData() ) ) {
+ items.push( item );
+ }
+ }
+
+ return items;
+};
+
+/**
+ * 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.ui.GroupElement.prototype.aggregate = function ( events ) {
+ var i, len, 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, len = this.items.length; i < len; i++ ) {
+ item = this.items[ i ];
+ if ( item.connect && item.disconnect ) {
+ remove = {};
+ remove[ itemEvent ] = [ 'emit', groupEvent, 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, 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 );
+ }
+ }
+ }
+ }
+};
+
+/**
+ * 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.GroupElement.prototype.addItems = function ( items, index ) {
+ var i, len, item, event, events, currentIndex,
+ itemElements = [];
+
+ for ( i = 0, len = items.length; i < len; i++ ) {
+ item = items[ i ];
+
+ // Check if item exists then remove it first, effectively "moving" it
+ currentIndex = $.inArray( item, this.items );
+ 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 ( event in this.aggregateItemEvents ) {
+ events[ event ] = [ 'emit', this.aggregateItemEvents[ event ], 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 ) );
+ }
+
+ return this;
+};
+
+/**
+ * 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.GroupElement.prototype.removeItems = function ( items ) {
+ var i, len, item, index, remove, itemEvent;
+
+ // Remove specific items
+ for ( i = 0, len = items.length; i < len; i++ ) {
+ item = items[ i ];
+ index = $.inArray( item, this.items );
+ if ( index !== -1 ) {
+ 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 );
+ this.items.splice( index, 1 );
+ item.$element.detach();
+ }
+ }
+
+ 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.GroupElement.prototype.clearItems = function () {
+ 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();
+ }
+
+ this.items = [];
+ return this;
+};