Merge "Improve sorting on SpecialWanted*-Pages"
[mediawiki.git] / resources / src / mediawiki.rcfilters / ui / mw.rcfilters.ui.FilterCapsuleMultiselectWidget.js
bloba06b103bf5e0df1185daa10b60d60c98e7dcf019
1 ( function ( mw, $ ) {
2 /**
3 * Filter-specific CapsuleMultiselectWidget
5 * @class
6 * @extends OO.ui.CapsuleMultiselectWidget
8 * @constructor
9 * @param {mw.rcfilters.Controller} controller RCFilters controller
10 * @param {mw.rcfilters.dm.FiltersViewModel} model RCFilters view model
11 * @param {OO.ui.InputWidget} filterInput A filter input that focuses the capsule widget
12 * @param {Object} config Configuration object
13 * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
15 mw.rcfilters.ui.FilterCapsuleMultiselectWidget = function MwRcfiltersUiFilterCapsuleMultiselectWidget( controller, model, filterInput, config ) {
16 var title = new OO.ui.LabelWidget( {
17 label: mw.msg( 'rcfilters-activefilters' ),
18 classes: [ 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-wrapper-content-title' ]
19 } ),
20 $contentWrapper = $( '<div>' )
21 .addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-wrapper' );
23 this.$overlay = config.$overlay || this.$element;
25 // Parent
26 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.parent.call( this, $.extend( true, {
27 popup: { $autoCloseIgnore: filterInput.$element.add( this.$overlay ) }
28 }, config ) );
30 this.controller = controller;
31 this.model = model;
32 this.filterInput = filterInput;
33 this.isSelecting = false;
34 this.selected = null;
36 this.resetButton = new OO.ui.ButtonWidget( {
37 icon: 'trash',
38 framed: false,
39 title: mw.msg( 'rcfilters-clear-all-filters' ),
40 classes: [ 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-resetButton' ]
41 } );
43 this.emptyFilterMessage = new OO.ui.LabelWidget( {
44 label: mw.msg( 'rcfilters-empty-filter' ),
45 classes: [ 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-emptyFilters' ]
46 } );
47 this.$content.append( this.emptyFilterMessage.$element );
49 // Events
50 this.resetButton.connect( this, { click: 'onResetButtonClick' } );
51 this.model.connect( this, {
52 itemUpdate: 'onModelItemUpdate',
53 highlightChange: 'onModelHighlightChange'
54 } );
55 this.aggregate( { click: 'capsuleItemClick' } );
57 // Add the filterInput as trigger
58 this.filterInput.$input
59 .on( 'focus', this.focus.bind( this ) );
61 // Build the content
62 $contentWrapper.append(
63 title.$element,
64 $( '<div>' )
65 .addClass( 'mw-rcfilters-ui-table' )
66 .append(
67 // The filter list and button should appear side by side regardless of how
68 // wide the button is; the button also changes its width depending
69 // on language and its state, so the safest way to present both side
70 // by side is with a table layout
71 $( '<div>' )
72 .addClass( 'mw-rcfilters-ui-row' )
73 .append(
74 this.$content
75 .addClass( 'mw-rcfilters-ui-cell' )
76 .addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-cell-filters' ),
77 $( '<div>' )
78 .addClass( 'mw-rcfilters-ui-cell' )
79 .addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-cell-reset' )
80 .append( this.resetButton.$element )
85 // Initialize
86 this.$handle.append( $contentWrapper );
88 this.$element
89 .addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget' );
91 this.reevaluateResetRestoreState();
94 /* Initialization */
96 OO.inheritClass( mw.rcfilters.ui.FilterCapsuleMultiselectWidget, OO.ui.CapsuleMultiselectWidget );
98 /* Events */
101 * @event remove
102 * @param {string[]} filters Array of names of removed filters
104 * Filters were removed
107 /* Methods */
110 * Respond to model itemUpdate event
112 * @param {mw.rcfilters.dm.FilterItem} item Filter item model
114 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onModelItemUpdate = function ( item ) {
115 if (
116 item.isSelected() ||
118 this.model.isHighlightEnabled() &&
119 item.isHighlightSupported() &&
120 item.getHighlightColor()
123 this.addItemByName( item.getName() );
124 } else {
125 this.removeItemByName( item.getName() );
128 // Re-evaluate reset state
129 this.reevaluateResetRestoreState();
133 * Respond to highlightChange event
135 * @param {boolean} isHighlightEnabled Highlight is enabled
137 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onModelHighlightChange = function ( isHighlightEnabled ) {
138 var highlightedItems = this.model.getHighlightedItems();
140 if ( isHighlightEnabled ) {
141 // Add capsule widgets
142 highlightedItems.forEach( function ( filterItem ) {
143 this.addItemByName( filterItem.getName() );
144 }.bind( this ) );
145 } else {
146 // Remove capsule widgets if they're not selected
147 highlightedItems.forEach( function ( filterItem ) {
148 if ( !filterItem.isSelected() ) {
149 this.removeItemByName( filterItem.getName() );
151 }.bind( this ) );
156 * Respond to click event on the reset button
158 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onResetButtonClick = function () {
159 if ( this.model.areCurrentFiltersEmpty() ) {
160 // Reset to default filters
161 this.controller.resetToDefaults();
162 } else {
163 // Reset to have no filters
164 this.controller.emptyFilters();
169 * Reevaluate the restore state for the widget between setting to defaults and clearing all filters
171 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.reevaluateResetRestoreState = function () {
172 var defaultsAreEmpty = this.model.areDefaultFiltersEmpty(),
173 currFiltersAreEmpty = this.model.areCurrentFiltersEmpty(),
174 hideResetButton = currFiltersAreEmpty && defaultsAreEmpty;
176 this.resetButton.setIcon(
177 currFiltersAreEmpty ? 'history' : 'trash'
180 this.resetButton.setLabel(
181 currFiltersAreEmpty ? mw.msg( 'rcfilters-restore-default-filters' ) : ''
184 this.resetButton.toggle( !hideResetButton );
185 this.emptyFilterMessage.toggle( currFiltersAreEmpty );
189 * Mark an item widget as selected
191 * @param {mw.rcfilters.ui.CapsuleItemWidget} item Capsule widget
193 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.select = function ( item ) {
194 if ( this.selected !== item ) {
195 // Unselect previous
196 if ( this.selected ) {
197 this.selected.toggleSelected( false );
200 // Select new one
201 this.selected = item;
202 if ( this.selected ) {
203 item.toggleSelected( true );
209 * Reset selection and remove selected states from all items
211 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.resetSelection = function () {
212 if ( this.selected !== null ) {
213 this.selected = null;
214 this.getItems().forEach( function ( capsuleWidget ) {
215 capsuleWidget.toggleSelected( false );
216 } );
221 * @inheritdoc
223 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.createItemWidget = function ( data ) {
224 var item = this.model.getItemByName( data );
226 if ( !item ) {
227 return;
230 return new mw.rcfilters.ui.CapsuleItemWidget(
231 this.controller,
232 item,
233 { $overlay: this.$overlay }
238 * Add items by their filter name
240 * @param {string} name Filter name
242 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.addItemByName = function ( name ) {
243 var item = this.model.getItemByName( name );
245 if ( !item ) {
246 return;
249 // Check that the item isn't already added
250 if ( !this.getItemFromData( name ) ) {
251 this.addItems( [ this.createItemWidget( name ) ] );
256 * Remove items by their filter name
258 * @param {string} name Filter name
260 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.removeItemByName = function ( name ) {
261 this.removeItemsFromData( [ name ] );
265 * @inheritdoc
267 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.focus = function () {
268 // Override this method; we don't want to focus on the popup, and we
269 // don't want to bind the size to the handle.
270 if ( !this.isDisabled() ) {
271 this.popup.toggle( true );
272 this.filterInput.$input.get( 0 ).focus();
274 return this;
278 * @inheritdoc
280 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onFocusForPopup = function () {
281 // HACK can be removed once I21b8cff4048 is merged in oojs-ui
282 this.focus();
286 * @inheritdoc
288 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onKeyDown = function () {};
291 * @inheritdoc
293 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onPopupFocusOut = function () {};
296 * @inheritdoc
298 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.clearInput = function () {
299 if ( this.filterInput ) {
300 this.filterInput.setValue( '' );
302 this.menu.toggle( false );
303 this.menu.selectItem();
304 this.menu.highlightItem();
308 * @inheritdoc
310 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.removeItems = function ( items ) {
311 // Parent call
312 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.parent.prototype.removeItems.call( this, items );
314 // Destroy the item widget when it is removed
315 // This is done because we re-add items by recreating them, rather than hiding them
316 // and items include popups, that will just continue to be created and appended
317 // unnecessarily.
318 items.forEach( function ( widget ) {
319 widget.destroy();
320 } );
324 * Override 'editItem' since it tries to use $input which does
325 * not exist when a popup is available.
327 mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.editItem = function () {};
328 }( mediaWiki, jQuery ) );