2 * JavaScript for Special:RecentChanges
12 var filtersModel
= new mw
.rcfilters
.dm
.FiltersViewModel(),
13 changesListModel
= new mw
.rcfilters
.dm
.ChangesListViewModel(),
14 controller
= new mw
.rcfilters
.Controller( filtersModel
, changesListModel
),
15 $overlay
= $( '<div>' )
16 .addClass( 'mw-rcfilters-ui-overlay' ),
17 filtersWidget
= new mw
.rcfilters
.ui
.FilterWrapperWidget(
18 controller
, filtersModel
, { $overlay
: $overlay
} );
20 // eslint-disable-next-line no-new
21 new mw
.rcfilters
.ui
.ChangesListWrapperWidget(
22 changesListModel
, $( '.mw-changeslist, .mw-changeslist-empty' ) );
24 // eslint-disable-next-line no-new
25 new mw
.rcfilters
.ui
.FormWrapperWidget(
26 changesListModel
, $( '.rcoptions form' ) );
28 controller
.initialize( {
30 title
: mw
.msg( 'rcfilters-filtergroup-registration' ),
31 type
: 'send_unselected_if_any',
36 label
: mw
.msg( 'rcfilters-filter-registered-label' ),
37 description
: mw
.msg( 'rcfilters-filter-registered-description' )
41 label
: mw
.msg( 'rcfilters-filter-unregistered-label' ),
42 description
: mw
.msg( 'rcfilters-filter-unregistered-description' )
47 title
: mw
.msg( 'rcfilters-filtergroup-userExpLevel' ),
48 // Type 'string_options' means that the group is evaluated by
49 // string values separated by comma; for example, param=opt1,opt2
50 // If all options are selected they are replaced by the term "all".
51 // The filters are the values for the parameter defined by the group.
52 // ** In this case, the parameter name is the group name. **
53 type
: 'string_options',
59 label
: mw
.msg( 'rcfilters-filter-userExpLevel-newcomer-label' ),
60 description
: mw
.msg( 'rcfilters-filter-userExpLevel-newcomer-description' ),
61 conflicts
: [ 'hideanons' ]
65 label
: mw
.msg( 'rcfilters-filter-userExpLevel-learner-label' ),
66 description
: mw
.msg( 'rcfilters-filter-userExpLevel-learner-description' ),
67 conflicts
: [ 'hideanons' ]
71 label
: mw
.msg( 'rcfilters-filter-userExpLevel-experienced-label' ),
72 description
: mw
.msg( 'rcfilters-filter-userExpLevel-experienced-description' ),
73 conflicts
: [ 'hideanons' ]
78 title
: mw
.msg( 'rcfilters-filtergroup-authorship' ),
79 // Type 'send_unselected_if_any' means that the controller will go over
80 // all unselected filters in the group and use their parameters
81 // as truthy in the query string.
82 // This is to handle the "negative" filters. We are showing users
83 // a positive message ("Show xxx") but the filters themselves are
84 // based on "hide YYY". The purpose of this is to correctly map
85 // the functionality to the UI, whether we are dealing with 2
86 // parameters in the group or more.
87 type
: 'send_unselected_if_any',
92 label
: mw
.msg( 'rcfilters-filter-editsbyself-label' ),
93 description
: mw
.msg( 'rcfilters-filter-editsbyself-description' )
97 label
: mw
.msg( 'rcfilters-filter-editsbyother-label' ),
98 description
: mw
.msg( 'rcfilters-filter-editsbyother-description' )
103 title
: mw
.msg( 'rcfilters-filtergroup-automated' ),
104 type
: 'send_unselected_if_any',
109 label
: mw
.msg( 'rcfilters-filter-bots-label' ),
110 description
: mw
.msg( 'rcfilters-filter-bots-description' ),
115 label
: mw
.msg( 'rcfilters-filter-humans-label' ),
116 description
: mw
.msg( 'rcfilters-filter-humans-description' ),
122 title
: mw
.msg( 'rcfilters-filtergroup-significance' ),
123 type
: 'send_unselected_if_any',
128 label
: mw
.msg( 'rcfilters-filter-minor-label' ),
129 description
: mw
.msg( 'rcfilters-filter-minor-description' )
133 label
: mw
.msg( 'rcfilters-filter-major-label' ),
134 description
: mw
.msg( 'rcfilters-filter-major-description' )
139 title
: mw
.msg( 'rcfilters-filtergroup-changetype' ),
140 type
: 'send_unselected_if_any',
144 name
: 'hidepageedits',
145 label
: mw
.msg( 'rcfilters-filter-pageedits-label' ),
146 description
: mw
.msg( 'rcfilters-filter-pageedits-description' ),
150 name
: 'hidenewpages',
151 label
: mw
.msg( 'rcfilters-filter-newpages-label' ),
152 description
: mw
.msg( 'rcfilters-filter-newpages-description' ),
156 name
: 'hidecategorization',
157 label
: mw
.msg( 'rcfilters-filter-categorization-label' ),
158 description
: mw
.msg( 'rcfilters-filter-categorization-description' ),
163 label
: mw
.msg( 'rcfilters-filter-logactions-label' ),
164 description
: mw
.msg( 'rcfilters-filter-logactions-description' ),
171 $( '.rcoptions' ).before( filtersWidget
.$element
);
172 $( 'body' ).append( $overlay
);
174 // HACK: Remove old-style filter links for filters handled by the widget
175 // Ideally the widget would handle all filters and we'd just remove .rcshowhide entirely
176 $( '.rcshowhide' ).children().each( function () {
177 // HACK: Interpret the class name to get the filter name
178 // This should really be set as a data attribute
181 // Some of the older browsers we support don't have .classList,
182 // so we have to interpret the class attribute manually.
183 classes
= this.getAttribute( 'class' ).split( ' ' );
184 for ( i
= 0; i
< classes
.length
; i
++ ) {
185 if ( classes
[ i
].substr( 0, 'rcshow'.length
) === 'rcshow' ) {
186 name
= classes
[ i
].substr( 'rcshow'.length
);
190 if ( name
=== null ) {
193 if ( name
=== 'hidemine' ) {
194 // HACK: the span for hidemyself is called hidemine
197 // This span corresponds to a filter that's in our model, so remove it
198 if ( filtersModel
.getItemByName( name
) ) {
199 // HACK: Remove the text node after the span.
200 // If there isn't one, we're at the end, so remove the text node before the span.
201 // This would be unnecessary if we added separators with CSS.
202 if ( this.nextSibling
&& this.nextSibling
.nodeType
=== Node
.TEXT_NODE
) {
203 this.parentNode
.removeChild( this.nextSibling
);
204 } else if ( this.previousSibling
&& this.previousSibling
.nodeType
=== Node
.TEXT_NODE
) {
205 this.parentNode
.removeChild( this.previousSibling
);
207 // Remove the span itself
208 this.parentNode
.removeChild( this );
212 window
.addEventListener( 'popstate', function () {
213 controller
.updateFromURL();
214 controller
.updateChangesList();
221 module
.exports
= rcfilters
;
223 }( mediaWiki
, jQuery
) );