RCFilters UI: Select filter when searching and add it on 'enter'
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / ui / mw.rcfilters.ui.FiltersListWidget.js
1 ( function ( mw, $ ) {
2 /**
3 * List displaying all filter groups
4 *
5 * @extends OO.ui.Widget
6 * @mixins OO.ui.mixin.GroupWidget
7 * @mixins OO.ui.mixin.LabelElement
8 *
9 * @constructor
10 * @param {mw.rcfilters.Controller} controller Controller
11 * @param {mw.rcfilters.dm.FiltersViewModel} model View model
12 * @param {Object} config Configuration object
13 */
14 mw.rcfilters.ui.FiltersListWidget = function MwRcfiltersUiFiltersListWidget( controller, model, config ) {
15 config = config || {};
16
17 // Parent
18 mw.rcfilters.ui.FiltersListWidget.parent.call( this, config );
19 // Mixin constructors
20 OO.ui.mixin.GroupWidget.call( this, config );
21 OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, {
22 $label: $( '<div>' )
23 .addClass( 'mw-rcfilters-ui-filtersListWidget-title' )
24 } ) );
25
26 this.controller = controller;
27 this.model = model;
28 this.$overlay = config.$overlay || this.$element;
29 this.groups = {};
30 this.selected = null;
31
32 this.highlightButton = new OO.ui.ButtonWidget( {
33 label: mw.message( 'rcfilters-highlightbutton-title' ).text(),
34 classes: [ 'mw-rcfilters-ui-filtersListWidget-hightlightButton' ]
35 } );
36
37 this.$label.append( this.highlightButton.$element );
38
39 this.noResultsLabel = new OO.ui.LabelWidget( {
40 label: mw.msg( 'rcfilters-filterlist-noresults' ),
41 classes: [ 'mw-rcfilters-ui-filtersListWidget-noresults' ]
42 } );
43
44 // Events
45 this.highlightButton.connect( this, { click: 'onHighlightButtonClick' } );
46 this.model.connect( this, {
47 initialize: 'onModelInitialize',
48 highlightChange: 'onHighlightChange'
49 } );
50
51 // Initialize
52 this.showNoResultsMessage( false );
53 this.$element
54 .addClass( 'mw-rcfilters-ui-filtersListWidget' )
55 .append(
56 this.$label,
57 this.$group
58 .addClass( 'mw-rcfilters-ui-filtersListWidget-group' ),
59 this.noResultsLabel.$element
60 );
61 };
62
63 /* Initialization */
64
65 OO.inheritClass( mw.rcfilters.ui.FiltersListWidget, OO.ui.Widget );
66 OO.mixinClass( mw.rcfilters.ui.FiltersListWidget, OO.ui.mixin.GroupWidget );
67 OO.mixinClass( mw.rcfilters.ui.FiltersListWidget, OO.ui.mixin.LabelElement );
68
69 /* Methods */
70
71 /**
72 * Respond to initialize event from the model
73 */
74 mw.rcfilters.ui.FiltersListWidget.prototype.onModelInitialize = function () {
75 var widget = this;
76
77 // Reset
78 this.clearItems();
79 this.groups = {};
80
81 this.addItems(
82 Object.keys( this.model.getFilterGroups() ).map( function ( groupName ) {
83 var groupWidget = new mw.rcfilters.ui.FilterGroupWidget(
84 widget.controller,
85 widget.model.getGroup( groupName ),
86 {
87 $overlay: widget.$overlay
88 }
89 );
90
91 widget.groups[ groupName ] = groupWidget;
92 return groupWidget;
93 } )
94 );
95 };
96
97 mw.rcfilters.ui.FiltersListWidget.prototype.onHighlightChange = function ( highlightEnabled ) {
98 this.highlightButton.setActive( highlightEnabled );
99 };
100
101 /**
102 * Respond to highlight button click
103 */
104 mw.rcfilters.ui.FiltersListWidget.prototype.onHighlightButtonClick = function () {
105 this.controller.toggleHighlight();
106 };
107
108 /**
109 * Find the filter item widget that corresponds to the item name
110 *
111 * @param {string} itemName Filter name
112 * @return {mw.rcfilters.ui.FilterItemWidget} Filter widget
113 */
114 mw.rcfilters.ui.FiltersListWidget.prototype.getItemWidget = function ( itemName ) {
115 var filterItem = this.model.getItemByName( itemName ),
116 // Find the group
117 groupWidget = this.groups[ filterItem.getGroupName() ];
118
119 // Find the item inside the group
120 return groupWidget.getItemWidget( itemName );
121 };
122
123 /**
124 * Get the current selection
125 *
126 * @return {string|null} Selected filter. Null if none is selected.
127 */
128 mw.rcfilters.ui.FiltersListWidget.prototype.getSelectedFilter = function () {
129 return this.selected;
130 };
131
132 /**
133 * Mark an item widget as selected
134 *
135 * @param {string} itemName Filter name
136 */
137 mw.rcfilters.ui.FiltersListWidget.prototype.select = function ( itemName ) {
138 var filterWidget;
139
140 if ( this.selected !== itemName ) {
141 // Unselect previous
142 if ( this.selected ) {
143 filterWidget = this.getItemWidget( this.selected );
144 filterWidget.toggleSelected( false );
145 }
146
147 // Select new one
148 this.selected = itemName;
149 if ( this.selected ) {
150 filterWidget = this.getItemWidget( this.selected );
151 filterWidget.toggleSelected( true );
152 }
153 }
154 };
155
156 /**
157 * Reset selection and remove selected states from all items
158 */
159 mw.rcfilters.ui.FiltersListWidget.prototype.resetSelection = function () {
160 if ( this.selected !== null ) {
161 this.selected = null;
162 this.getItems().forEach( function ( groupWidget ) {
163 groupWidget.getItems().forEach( function ( filterItemWidget ) {
164 filterItemWidget.toggleSelected( false );
165 } );
166 } );
167 }
168 };
169
170 /**
171 * Switch between showing the 'no results' message for filtering results or the result list.
172 *
173 * @param {boolean} showNoResults Show no results message
174 */
175 mw.rcfilters.ui.FiltersListWidget.prototype.showNoResultsMessage = function ( showNoResults ) {
176 this.noResultsLabel.toggle( !!showNoResults );
177 this.$group.toggleClass( 'oo-ui-element-hidden', !!showNoResults );
178 };
179
180 /**
181 * Show only the items matching with the models in the given list
182 *
183 * @param {Object} groupItems An object of items to show
184 * arranged by their group names
185 */
186 mw.rcfilters.ui.FiltersListWidget.prototype.filter = function ( groupItems ) {
187 var i, j, groupName, itemWidgets, topItem, isVisible,
188 groupWidgets = this.getItems(),
189 hasItemWithName = function ( itemArr, name ) {
190 return !!itemArr.filter( function ( item ) {
191 return item.getName() === name;
192 } ).length;
193 };
194
195 this.resetSelection();
196
197 if ( $.isEmptyObject( groupItems ) ) {
198 // No results. Hide everything, show only 'no results'
199 // message
200 this.showNoResultsMessage( true );
201 return;
202 }
203
204 this.showNoResultsMessage( false );
205 for ( i = 0; i < groupWidgets.length; i++ ) {
206 groupName = groupWidgets[ i ].getName();
207
208 // If this group widget is in the filtered results,
209 // show it - otherwise, hide it
210 groupWidgets[ i ].toggle( !!groupItems[ groupName ] );
211
212 if ( !groupItems[ groupName ] ) {
213 // Continue to next group
214 continue;
215 }
216
217 // We have items to show
218 itemWidgets = groupWidgets[ i ].getItems();
219 for ( j = 0; j < itemWidgets.length; j++ ) {
220 isVisible = hasItemWithName( groupItems[ groupName ], itemWidgets[ j ].getName() );
221 // Only show items that are in the filtered list
222 itemWidgets[ j ].toggle( isVisible );
223
224 if ( !topItem && isVisible ) {
225 topItem = itemWidgets[ j ];
226 }
227 }
228 }
229
230 // Select the first item
231 if ( topItem ) {
232 this.select( topItem.getName() );
233 }
234 };
235 }( mediaWiki, jQuery ) );