Merge "Replace some usages of Linker::link with LinkRenderer"
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / ui / mw.rcfilters.ui.SavedLinksListItemWidget.js
1 ( function ( mw ) {
2 /**
3 * Quick links menu option widget
4 *
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 mw.rcfilters.ui.SavedLinksListItemWidget = function MwRcfiltersUiSavedLinksListWidget( model, config ) {
16 config = config || {};
17
18 this.model = model;
19
20 // Parent
21 mw.rcfilters.ui.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: 'close',
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: 'onSaveButtonClick' } );
85 this.editInput.connect( this, { enter: 'onEditInputEnter' } );
86 this.editInput.$input.on( {
87 blur: this.onInputBlur.bind( this ),
88 keyup: this.onInputKeyup.bind( this )
89 } );
90 this.$element.on( { click: this.onClick.bind( this ) } );
91 this.$label.on( { click: this.onClick.bind( this ) } );
92 // Prevent propagation on mousedown for the save button
93 // so the menu doesn't close
94 this.saveButton.$element.on( { mousedown: function () { return false; } } );
95
96 // Initialize
97 this.toggleDefault( !!this.model.isDefault() );
98 this.$overlay.append( this.menu.$element );
99 this.$element
100 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget' )
101 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-query-' + this.model.getID() )
102 .append(
103 $( '<div>' )
104 .addClass( 'mw-rcfilters-ui-table' )
105 .append(
106 $( '<div>' )
107 .addClass( 'mw-rcfilters-ui-row' )
108 .append(
109 $( '<div>' )
110 .addClass( 'mw-rcfilters-ui-cell' )
111 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-content' )
112 .append(
113 this.$label
114 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-label' ),
115 this.editInput.$element,
116 this.saveButton.$element
117 ),
118 $( '<div>' )
119 .addClass( 'mw-rcfilters-ui-cell' )
120 .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-icon' )
121 .append( this.$icon ),
122 this.popupButton.$element
123 .addClass( 'mw-rcfilters-ui-cell' )
124 )
125 )
126 );
127 };
128
129 /* Initialization */
130 OO.inheritClass( mw.rcfilters.ui.SavedLinksListItemWidget, OO.ui.Widget );
131 OO.mixinClass( mw.rcfilters.ui.SavedLinksListItemWidget, OO.ui.mixin.LabelElement );
132 OO.mixinClass( mw.rcfilters.ui.SavedLinksListItemWidget, OO.ui.mixin.IconElement );
133 OO.mixinClass( mw.rcfilters.ui.SavedLinksListItemWidget, OO.ui.mixin.TitledElement );
134
135 /* Events */
136
137 /**
138 * @event delete
139 *
140 * The delete option was selected for this item
141 */
142
143 /**
144 * @event default
145 * @param {boolean} default Item is default
146 *
147 * The 'make default' option was selected for this item
148 */
149
150 /**
151 * @event edit
152 * @param {string} newLabel New label for the query
153 *
154 * The label has been edited
155 */
156
157 /* Methods */
158
159 /**
160 * Respond to model update event
161 */
162 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.onModelUpdate = function () {
163 this.setLabel( this.model.getLabel() );
164 this.toggleDefault( this.model.isDefault() );
165 };
166
167 /**
168 * Respond to click on the element or label
169 *
170 * @fires click
171 */
172 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.onClick = function () {
173 if ( !this.editing ) {
174 this.emit( 'click' );
175 }
176 };
177 /**
178 * Respond to popup button click event
179 */
180 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.onPopupButtonClick = function () {
181 this.menu.toggle();
182 };
183
184 /**
185 * Respond to menu choose event
186 *
187 * @param {OO.ui.MenuOptionWidget} item Chosen item
188 * @fires delete
189 * @fires default
190 */
191 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.onMenuChoose = function ( item ) {
192 var action = item.getData();
193
194 if ( action === 'edit' ) {
195 this.toggleEdit( true );
196 } else if ( action === 'delete' ) {
197 this.emit( 'delete' );
198 } else if ( action === 'default' ) {
199 this.emit( 'default', !this.default );
200 }
201 // Reset selected
202 this.menu.selectItem( null );
203 // Close the menu
204 this.menu.toggle( false );
205 };
206
207 /**
208 * Respond to save button click
209 */
210 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.onSaveButtonClick = function () {
211 this.emit( 'edit', this.editInput.getValue() );
212 this.toggleEdit( false );
213 };
214
215 /**
216 * Respond to input enter event
217 */
218 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.onEditInputEnter = function () {
219 this.emit( 'edit', this.editInput.getValue() );
220 this.toggleEdit( false );
221 };
222
223 /**
224 * Respond to input keyup event, this is the way to intercept 'escape' key
225 *
226 * @param {jQuery.Event} e Event data
227 * @returns {boolean} false
228 */
229 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.onInputKeyup = function ( e ) {
230 if ( e.which === OO.ui.Keys.ESCAPE ) {
231 // Return the input to the original label
232 this.editInput.setValue( this.getLabel() );
233 this.toggleEdit( false );
234 return false;
235 }
236 };
237
238 /**
239 * Respond to blur event on the input
240 */
241 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.onInputBlur = function () {
242 this.emit( 'edit', this.editInput.getValue() );
243 this.toggleEdit( false );
244 };
245
246 /**
247 * Toggle edit mode on this widget
248 *
249 * @param {boolean} isEdit Widget is in edit mode
250 */
251 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.toggleEdit = function ( isEdit ) {
252 isEdit = isEdit === undefined ? !this.editing : isEdit;
253
254 if ( this.editing !== isEdit ) {
255 this.$element.toggleClass( 'mw-rcfilters-ui-savedLinksListItemWidget-edit', isEdit );
256 this.editInput.setValue( this.getLabel() );
257
258 this.editInput.toggle( isEdit );
259 this.$label.toggleClass( 'oo-ui-element-hidden', isEdit );
260 this.$icon.toggleClass( 'oo-ui-element-hidden', isEdit );
261 this.popupButton.toggle( !isEdit );
262 this.saveButton.toggle( isEdit );
263
264 if ( isEdit ) {
265 this.editInput.$input.focus();
266 }
267 this.editing = isEdit;
268 }
269 };
270
271 /**
272 * Toggle default this widget
273 *
274 * @param {boolean} isDefault This item is default
275 */
276 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.toggleDefault = function ( isDefault ) {
277 isDefault = isDefault === undefined ? !this.default : isDefault;
278
279 if ( this.default !== isDefault ) {
280 this.default = isDefault;
281 this.setIcon( this.default ? 'pushPin' : '' );
282 this.menu.getItemFromData( 'default' ).setLabel(
283 this.default ?
284 mw.msg( 'rcfilters-savedqueries-unsetdefault' ) :
285 mw.msg( 'rcfilters-savedqueries-setdefault' )
286 );
287 }
288 };
289
290 /**
291 * Get item ID
292 *
293 * @returns {string} Query identifier
294 */
295 mw.rcfilters.ui.SavedLinksListItemWidget.prototype.getID = function () {
296 return this.model.getID();
297 };
298
299 }( mediaWiki ) );