Merge "Do not linkify the namespace URI in 'uploadscriptednamespace' error message"
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / mw.rcfilters.init.js
1 /*!
2 * JavaScript for Special:RecentChanges
3 */
4 ( function ( mw, $ ) {
5 /**
6 * @class mw.rcfilters
7 * @singleton
8 */
9 var rcfilters = {
10 /** */
11 init: function () {
12 var model = new mw.rcfilters.dm.FiltersViewModel(),
13 controller = new mw.rcfilters.Controller( model ),
14 widget = new mw.rcfilters.ui.FilterWrapperWidget( controller, model );
15
16 model.initializeFilters( {
17 registration: {
18 title: mw.msg( 'rcfilters-filtergroup-registration' ),
19 type: 'send_unselected_if_any',
20 filters: [
21 {
22 name: 'hideliu',
23 label: mw.msg( 'rcfilters-filter-registered-label' ),
24 description: mw.msg( 'rcfilters-filter-registered-description' )
25 },
26 {
27 name: 'hideanons',
28 label: mw.msg( 'rcfilters-filter-unregistered-label' ),
29 description: mw.msg( 'rcfilters-filter-unregistered-description' )
30 }
31 ]
32 },
33 userExpLevel: {
34 title: mw.msg( 'rcfilters-filtergroup-userExpLevel' ),
35 // Type 'string_options' means that the group is evaluated by
36 // string values separated by comma; for example, param=opt1,opt2
37 // If all options are selected they are replaced by the term "all".
38 // The filters are the values for the parameter defined by the group.
39 // ** In this case, the parameter name is the group name. **
40 type: 'string_options',
41 separator: ',',
42 filters: [
43 {
44 name: 'newcomer',
45 label: mw.msg( 'rcfilters-filter-userExpLevel-newcomer-label' ),
46 description: mw.msg( 'rcfilters-filter-userExpLevel-newcomer-description' )
47 },
48 {
49 name: 'learner',
50 label: mw.msg( 'rcfilters-filter-userExpLevel-learner-label' ),
51 description: mw.msg( 'rcfilters-filter-userExpLevel-learner-description' )
52 },
53 {
54 name: 'experienced',
55 label: mw.msg( 'rcfilters-filter-userExpLevel-experienced-label' ),
56 description: mw.msg( 'rcfilters-filter-userExpLevel-experienced-description' )
57 }
58 ]
59 },
60 authorship: {
61 title: mw.msg( 'rcfilters-filtergroup-authorship' ),
62 // Type 'send_unselected_if_any' means that the controller will go over
63 // all unselected filters in the group and use their parameters
64 // as truthy in the query string.
65 // This is to handle the "negative" filters. We are showing users
66 // a positive message ("Show xxx") but the filters themselves are
67 // based on "hide YYY". The purpose of this is to correctly map
68 // the functionality to the UI, whether we are dealing with 2
69 // parameters in the group or more.
70 type: 'send_unselected_if_any',
71 filters: [
72 {
73 name: 'hidemyself',
74 label: mw.msg( 'rcfilters-filter-editsbyself-label' ),
75 description: mw.msg( 'rcfilters-filter-editsbyself-description' )
76 },
77 {
78 name: 'hidebyothers',
79 label: mw.msg( 'rcfilters-filter-editsbyother-label' ),
80 description: mw.msg( 'rcfilters-filter-editsbyother-description' )
81 }
82 ]
83 },
84 automated: {
85 title: mw.msg( 'rcfilters-filtergroup-automated' ),
86 type: 'send_unselected_if_any',
87 filters: [
88 {
89 name: 'hidebots',
90 label: mw.msg( 'rcfilters-filter-bots-label' ),
91 description: mw.msg( 'rcfilters-filter-bots-description' ),
92 'default': true
93 },
94 {
95 name: 'hidehumans',
96 label: mw.msg( 'rcfilters-filter-humans-label' ),
97 description: mw.msg( 'rcfilters-filter-humans-description' ),
98 'default': false
99 }
100 ]
101 },
102 significance: {
103 title: mw.msg( 'rcfilters-filtergroup-significance' ),
104 type: 'send_unselected_if_any',
105 filters: [
106 {
107 name: 'hideminor',
108 label: mw.msg( 'rcfilters-filter-minor-label' ),
109 description: mw.msg( 'rcfilters-filter-minor-description' )
110 },
111 {
112 name: 'hidemajor',
113 label: mw.msg( 'rcfilters-filter-major-label' ),
114 description: mw.msg( 'rcfilters-filter-major-description' )
115 }
116 ]
117 },
118 changetype: {
119 title: mw.msg( 'rcfilters-filtergroup-changetype' ),
120 type: 'send_unselected_if_any',
121 filters: [
122 {
123 name: 'hidepageedits',
124 label: mw.msg( 'rcfilters-filter-pageedits-label' ),
125 description: mw.msg( 'rcfilters-filter-pageedits-description' ),
126 'default': false
127 },
128 {
129 name: 'hidenewpages',
130 label: mw.msg( 'rcfilters-filter-newpages-label' ),
131 description: mw.msg( 'rcfilters-filter-newpages-description' ),
132 'default': false
133 },
134 {
135 name: 'hidecategorization',
136 label: mw.msg( 'rcfilters-filter-categorization-label' ),
137 description: mw.msg( 'rcfilters-filter-categorization-description' ),
138 'default': true
139 },
140 {
141 name: 'hidelog',
142 label: mw.msg( 'rcfilters-filter-logactions-label' ),
143 description: mw.msg( 'rcfilters-filter-logactions-description' ),
144 'default': false
145 }
146 ]
147 }
148 } );
149
150 $( '.rcoptions' ).before( widget.$element );
151
152 // Initialize values
153 controller.initialize();
154
155 // HACK: Remove old-style filter links for filters handled by the widget
156 // Ideally the widget would handle all filters and we'd just remove .rcshowhide entirely
157 $( '.rcshowhide' ).children().each( function () {
158 // HACK: Interpret the class name to get the filter name
159 // This should really be set as a data attribute
160 var i,
161 name = null,
162 // Some of the older browsers we support don't have .classList,
163 // so we have to interpret the class attribute manually.
164 classes = this.getAttribute( 'class' ).split( ' ' );
165 for ( i = 0; i < classes.length; i++ ) {
166 if ( classes[ i ].substr( 0, 'rcshow'.length ) === 'rcshow' ) {
167 name = classes[ i ].substr( 'rcshow'.length );
168 break;
169 }
170 }
171 if ( name === null ) {
172 return;
173 }
174 if ( name === 'hidemine' ) {
175 // HACK: the span for hidemyself is called hidemine
176 name = 'hidemyself';
177 }
178 // This span corresponds to a filter that's in our model, so remove it
179 if ( model.getItemByName( name ) ) {
180 // HACK: Remove the text node after the span.
181 // If there isn't one, we're at the end, so remove the text node before the span.
182 // This would be unnecessary if we added separators with CSS.
183 if ( this.nextSibling && this.nextSibling.nodeType === Node.TEXT_NODE ) {
184 this.parentNode.removeChild( this.nextSibling );
185 } else if ( this.previousSibling && this.previousSibling.nodeType === Node.TEXT_NODE ) {
186 this.parentNode.removeChild( this.previousSibling );
187 }
188 // Remove the span itself
189 this.parentNode.removeChild( this );
190 }
191 } );
192
193 $( '.rcoptions form' ).submit( function () {
194 var $form = $( this );
195
196 // Get current filter values
197 $.each( model.getParametersFromFilters(), function ( paramName, paramValue ) {
198 var $existingInput = $form.find( 'input[name=' + paramName + ']' );
199 // Check if the hidden input already exists
200 // This happens if the parameter was already given
201 // on load
202 if ( $existingInput.length ) {
203 // Update the value
204 $existingInput.val( paramValue );
205 } else {
206 // Append hidden fields with filter values
207 $form.append(
208 $( '<input>' )
209 .attr( 'type', 'hidden' )
210 .attr( 'name', paramName )
211 .val( paramValue )
212 );
213 }
214 } );
215
216 // Continue the submission process
217 return true;
218 } );
219 }
220 };
221
222 $( rcfilters.init );
223
224 module.exports = rcfilters;
225
226 }( mediaWiki, jQuery ) );