Merge "Add suppressredirect right to the createeditmovepage grant"
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / ui / SavedLinksListItemWidget.js
1 /**
2 * Quick links menu option widget
3 *
4 * @class mw.rcfilters.ui.SavedLinksListItemWidget
5 * @extends OO.ui.Widget
6 * @mixins OO.ui.mixin.LabelElement
7 * @mixins OO.ui.mixin.IconElement
8 * @mixins OO.ui.mixin.TitledElement
9 *
10 * @constructor
11 * @param {mw.rcfilters.dm.SavedQueryItemModel} model View model
12 * @param {Object} [config] Configuration object
13 * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
14 */
15 var SavedLinksListItemWidget = function MwRcfiltersUiSavedLinksListWidget( model, config ) {
16 config = config || {};
17
18 this.model = model;
19
20 // Parent
21 SavedLinksListItemWidget.parent.call( this, $.extend( {
22 data: this.model.getID()
23 }, config ) );
24
25 // Mixin constructors
26 OO.ui.mixin.LabelElement.call( this, $.extend( {
27 label: this.model.getLabel()
28 }, config ) );
29 OO.ui.mixin.IconElement.call( this, $.extend( {
30 icon: ''
31 }, config ) );
32 OO.ui.mixin.TitledElement.call( this, $.extend( {
33 title: this.model.getLabel()
34 }, config ) );
35
36 this.edit = false;
37 this.$overlay = config.$overlay || this.$element;
38
39 this.popupButton = new OO.ui.ButtonWidget( {
40 classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-button' ],
41 icon: 'ellipsis',
42 framed: false
43 } );
44 this.menu = new OO.ui.MenuSelectWidget( {
45 classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-menu' ],
46 widget: this.popupButton,
47 width: 200,
48 horizontalPosition: 'end',
49 $floatableContainer: this.popupButton.$element,
50 items: [
51 new OO.ui.MenuOptionWidget( {
52 data: 'edit',
53 icon: 'edit',
54 label: mw.msg( 'rcfilters-savedqueries-rename' )
55 } ),
56 new OO.ui.MenuOptionWidget( {
57 data: 'delete',
58 icon: 'trash',
59 label: mw.msg( 'rcfilters-savedqueries-remove' )
60 } ),
61 new OO.ui.MenuOptionWidget( {
62 data: 'default',
63 icon: 'pushPin',
64 label: mw.msg( 'rcfilters-savedqueries-setdefault' )
65 } )
66 ]
67 } );
68
69 this.editInput = new OO.ui.TextInputWidget( {
70 classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-input' ]
71 } );
72 this.saveButton = new OO.ui.ButtonWidget( {
73 icon: 'check',
74 flags: [ 'primary', 'progressive' ]
75 } );
76 this.toggleEdit( false );
77
78 // Events
79 this.model.connect( this, { update: 'onModelUpdate' } );
80 this.popupButton.connect( this, { click: 'onPopupButtonClick' } );
81 this.menu.connect( this, {
82 choose: 'onMenuChoose'
83 } );
84 this.saveButton.connect( this, { click: 'save' } );
85 this.editInput.connect( this, {
86 change: 'onInputChange',
87 enter: 'save'
88 } );
89 this.editInput.$input.on( {
90 blur: this.onInputBlur.bind( this ),
91 keyup: this.onInputKeyup.bind( this )
92 } );
93 this.$element.on( { click: this.onClick.bind( this ) } );
94 this.$label.on( { click: this.onClick.bind( this ) } );
95 this.$icon.on( { click: this.onDefaultIconClick.bind( this ) } );
96 // Prevent propagation on mousedown for the save button
97 // so the menu doesn't close
98 this.saveButton.$element.on( { mousedown: function () {
99 return false;
100 } } );
101
102 // Initialize
103 this.toggleDefault( !!this.model.isDefault() );
104 this.$overlay.append( this.menu.$element );
105 this.$element
106 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget' )
107 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-query-' + this.model.getID() )
108 .append(
109 $( '<div>' )
110 .addClass( 'mw-rcfilters-ui-table' )
111 .append(
112 $( '<div>' )
113 .addClass( 'mw-rcfilters-ui-row' )
114 .append(
115 $( '<div>' )
116 .addClass( 'mw-rcfilters-ui-cell' )
117 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-content' )
118 .append(
119 this.$label
120 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-label' ),
121 this.editInput.$element,
122 this.saveButton.$element
123 ),
124 $( '<div>' )
125 .addClass( 'mw-rcfilters-ui-cell' )
126 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-icon' )
127 .append( this.$icon ),
128 this.popupButton.$element
129 .addClass( 'mw-rcfilters-ui-cell' )
130 )
131 )
132 );
133 };
134
135 /* Initialization */
136 OO.inheritClass( SavedLinksListItemWidget, OO.ui.Widget );
137 OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.LabelElement );
138 OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.IconElement );
139 OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.TitledElement );
140
141 /* Events */
142
143 /**
144 * @event delete
145 *
146 * The delete option was selected for this item
147 */
148
149 /**
150 * @event default
151 * @param {boolean} default Item is default
152 *
153 * The 'make default' option was selected for this item
154 */
155
156 /**
157 * @event edit
158 * @param {string} newLabel New label for the query
159 *
160 * The label has been edited
161 */
162
163 /* Methods */
164
165 /**
166 * Respond to model update event
167 */
168 SavedLinksListItemWidget.prototype.onModelUpdate = function () {
169 this.setLabel( this.model.getLabel() );
170 this.toggleDefault( this.model.isDefault() );
171 };
172
173 /**
174 * Respond to click on the element or label
175 *
176 * @fires click
177 */
178 SavedLinksListItemWidget.prototype.onClick = function () {
179 if ( !this.editing ) {
180 this.emit( 'click' );
181 }
182 };
183
184 /**
185 * Respond to click on the 'default' icon. Open the submenu where the
186 * default state can be changed.
187 *
188 * @return {boolean} false
189 */
190 SavedLinksListItemWidget.prototype.onDefaultIconClick = function () {
191 this.menu.toggle();
192 return false;
193 };
194
195 /**
196 * Respond to popup button click event
197 */
198 SavedLinksListItemWidget.prototype.onPopupButtonClick = function () {
199 this.menu.toggle();
200 };
201
202 /**
203 * Respond to menu choose event
204 *
205 * @param {OO.ui.MenuOptionWidget} item Chosen item
206 * @fires delete
207 * @fires default
208 */
209 SavedLinksListItemWidget.prototype.onMenuChoose = function ( item ) {
210 var action = item.getData();
211
212 if ( action === 'edit' ) {
213 this.toggleEdit( true );
214 } else if ( action === 'delete' ) {
215 this.emit( 'delete' );
216 } else if ( action === 'default' ) {
217 this.emit( 'default', !this.default );
218 }
219 // Reset selected
220 this.menu.selectItem( null );
221 // Close the menu
222 this.menu.toggle( false );
223 };
224
225 /**
226 * Respond to input keyup event, this is the way to intercept 'escape' key
227 *
228 * @param {jQuery.Event} e Event data
229 * @return {boolean} false
230 */
231 SavedLinksListItemWidget.prototype.onInputKeyup = function ( e ) {
232 if ( e.which === OO.ui.Keys.ESCAPE ) {
233 // Return the input to the original label
234 this.editInput.setValue( this.getLabel() );
235 this.toggleEdit( false );
236 return false;
237 }
238 };
239
240 /**
241 * Respond to blur event on the input
242 */
243 SavedLinksListItemWidget.prototype.onInputBlur = function () {
244 this.save();
245
246 // Whether the save succeeded or not, the input-blur event
247 // means we need to cancel editing mode
248 this.toggleEdit( false );
249 };
250
251 /**
252 * Respond to input change event
253 *
254 * @param {string} value Input value
255 */
256 SavedLinksListItemWidget.prototype.onInputChange = function ( value ) {
257 value = value.trim();
258
259 this.saveButton.setDisabled( !value );
260 };
261
262 /**
263 * Save the name of the query
264 *
265 * @fires edit
266 */
267 SavedLinksListItemWidget.prototype.save = function () {
268 var value = this.editInput.getValue().trim();
269
270 if ( value ) {
271 this.emit( 'edit', value );
272 this.toggleEdit( false );
273 }
274 };
275
276 /**
277 * Toggle edit mode on this widget
278 *
279 * @param {boolean} isEdit Widget is in edit mode
280 */
281 SavedLinksListItemWidget.prototype.toggleEdit = function ( isEdit ) {
282 isEdit = isEdit === undefined ? !this.editing : isEdit;
283
284 if ( this.editing !== isEdit ) {
285 this.$element.toggleClass( 'mw-rcfilters-ui-savedLinksListItemWidget-edit', isEdit );
286 this.editInput.setValue( this.getLabel() );
287
288 this.editInput.toggle( isEdit );
289 this.$label.toggleClass( 'oo-ui-element-hidden', isEdit );
290 this.$icon.toggleClass( 'oo-ui-element-hidden', isEdit );
291 this.popupButton.toggle( !isEdit );
292 this.saveButton.toggle( isEdit );
293
294 if ( isEdit ) {
295 this.editInput.$input.trigger( 'focus' );
296 }
297 this.editing = isEdit;
298 }
299 };
300
301 /**
302 * Toggle default this widget
303 *
304 * @param {boolean} isDefault This item is default
305 */
306 SavedLinksListItemWidget.prototype.toggleDefault = function ( isDefault ) {
307 isDefault = isDefault === undefined ? !this.default : isDefault;
308
309 if ( this.default !== isDefault ) {
310 this.default = isDefault;
311 this.setIcon( this.default ? 'pushPin' : '' );
312 this.menu.findItemFromData( 'default' ).setLabel(
313 this.default ?
314 mw.msg( 'rcfilters-savedqueries-unsetdefault' ) :
315 mw.msg( 'rcfilters-savedqueries-setdefault' )
316 );
317 }
318 };
319
320 /**
321 * Get item ID
322 *
323 * @return {string} Query identifier
324 */
325 SavedLinksListItemWidget.prototype.getID = function () {
326 return this.model.getID();
327 };
328
329 module.exports = SavedLinksListItemWidget;