Merge "ChangeTags: Remove $wgRequest abuse in modifyDisplayQuery()"
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / ui / mw.rcfilters.ui.ChangesListWrapperWidget.js
1 ( function ( mw ) {
2 /**
3 * List of changes
4 *
5 * @extends OO.ui.Widget
6 *
7 * @constructor
8 * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel View model
9 * @param {mw.rcfilters.dm.ChangesListViewModel} changesListViewModel View model
10 * @param {jQuery} $changesListRoot Root element of the changes list to attach to
11 * @param {Object} config Configuration object
12 */
13 mw.rcfilters.ui.ChangesListWrapperWidget = function MwRcfiltersUiChangesListWrapperWidget(
14 filtersViewModel,
15 changesListViewModel,
16 $changesListRoot,
17 config
18 ) {
19 config = $.extend( {}, config, {
20 $element: $changesListRoot
21 } );
22
23 // Parent
24 mw.rcfilters.ui.ChangesListWrapperWidget.parent.call( this, config );
25
26 this.filtersViewModel = filtersViewModel;
27 this.changesListViewModel = changesListViewModel;
28
29 // Events
30 this.filtersViewModel.connect( this, {
31 itemUpdate: 'onItemUpdate',
32 highlightChange: 'onHighlightChange'
33 } );
34 this.changesListViewModel.connect( this, {
35 invalidate: 'onModelInvalidate',
36 update: 'onModelUpdate'
37 } );
38
39 this.$element
40 .addClass( 'mw-rcfilters-ui-changesListWrapperWidget' )
41 // We handle our own display/hide of the empty results message
42 .removeClass( 'mw-changeslist-empty' );
43
44 // Set up highlight containers
45 this.setupHighlightContainers( this.$element );
46 };
47
48 /* Initialization */
49
50 OO.inheritClass( mw.rcfilters.ui.ChangesListWrapperWidget, OO.ui.Widget );
51
52 /**
53 * Respond to the highlight feature being toggled on and off
54 *
55 * @param {boolean} highlightEnabled
56 */
57 mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onHighlightChange = function ( highlightEnabled ) {
58 if ( highlightEnabled ) {
59 this.applyHighlight();
60 } else {
61 this.clearHighlight();
62 }
63 };
64
65 /**
66 * Respond to a filter item model update
67 */
68 mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onItemUpdate = function () {
69 if ( this.filtersViewModel.isHighlightEnabled() ) {
70 this.clearHighlight();
71 this.applyHighlight();
72 }
73 };
74
75 /**
76 * Respond to changes list model invalidate
77 */
78 mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onModelInvalidate = function () {
79 $( '.rcfilters-head' ).removeClass( 'mw-rcfilters-ui-ready' );
80 $( '.rcfilters-spinner' ).removeClass( 'mw-rcfilters-ui-ready' );
81 this.$element.removeClass( 'mw-rcfilters-ui-ready' );
82 };
83
84 /**
85 * Respond to changes list model update
86 *
87 * @param {jQuery|string} $changesListContent The content of the updated changes list
88 * @param {jQuery} $fieldset The content of the updated fieldset
89 * @param {boolean} isInitialDOM Whether $changesListContent is the existing (already attached) DOM
90 */
91 mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onModelUpdate = function ( $changesListContent, $fieldset, isInitialDOM ) {
92 var conflictItem,
93 $message = $( '<div>' )
94 .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results' ),
95 isEmpty = $changesListContent === 'NO_RESULTS';
96
97 this.$element.toggleClass( 'mw-changeslist', !isEmpty );
98 if ( isEmpty ) {
99 this.$changesListContent = null;
100 this.$element.empty();
101
102 if ( this.filtersViewModel.hasConflict() ) {
103 conflictItem = this.filtersViewModel.getFirstConflictedItem();
104
105 $message
106 .append(
107 $( '<div>' )
108 .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-conflict' )
109 .text( mw.message( 'rcfilters-noresults-conflict' ).text() ),
110 $( '<div>' )
111 .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-message' )
112 .text( mw.message( conflictItem.getCurrentConflictResultMessage() ).text() )
113 );
114 } else {
115 $message
116 .append(
117 $( '<div>' )
118 .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-noresult' )
119 .text( mw.message( 'recentchanges-noresult' ).text() )
120 );
121 }
122
123 this.$element.append( $message );
124 } else {
125 this.$changesListContent = $changesListContent;
126 if ( !isInitialDOM ) {
127 this.$element.empty().append( this.$changesListContent );
128 }
129 // Set up highlight containers
130 this.setupHighlightContainers( this.$element );
131
132 // Apply highlight
133 this.applyHighlight();
134
135 if ( !isInitialDOM ) {
136 // Make sure enhanced RC re-initializes correctly
137 mw.hook( 'wikipage.content' ).fire( this.$element );
138 }
139 }
140
141 $( '.rcfilters-head' ).addClass( 'mw-rcfilters-ui-ready' );
142 $( '.rcfilters-spinner' ).addClass( 'mw-rcfilters-ui-ready' );
143 this.$element.addClass( 'mw-rcfilters-ui-ready' );
144 };
145
146 /**
147 * Set up the highlight containers with all color circle indicators.
148 *
149 * @param {jQuery|string} $content The content of the updated changes list
150 */
151 mw.rcfilters.ui.ChangesListWrapperWidget.prototype.setupHighlightContainers = function ( $content ) {
152 var uri = new mw.Uri(),
153 $highlights = $( '<div>' )
154 .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlights' )
155 .append(
156 $( '<div>' )
157 .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlights-color-none' )
158 .prop( 'data-color', 'none' )
159 );
160
161 if ( $( '.mw-rcfilters-ui-changesListWrapperWidget-highlights' ).length ) {
162 // Already set up
163 return;
164 }
165
166 mw.rcfilters.HighlightColors.forEach( function ( color ) {
167 $highlights.append(
168 $( '<div>' )
169 .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlights-color-' + color )
170 .prop( 'data-color', color )
171 );
172 } );
173
174 if (
175 ( uri.query.enhanced !== undefined && Number( uri.query.enhanced ) ) ||
176 ( uri.query.enhanced === undefined && Number( mw.user.options.get( 'usenewrc' ) ) )
177 ) {
178 // Enhanced RC
179 $content.find( 'td.mw-enhanced-rc' )
180 .parent()
181 .prepend(
182 $( '<td>' )
183 .append( $highlights.clone() )
184 );
185 } else {
186 // Regular RC
187 $content.find( 'ul.special li' )
188 .prepend( $highlights.clone() );
189 }
190 };
191
192 /**
193 * Apply color classes based on filters highlight configuration
194 */
195 mw.rcfilters.ui.ChangesListWrapperWidget.prototype.applyHighlight = function () {
196 if ( !this.filtersViewModel.isHighlightEnabled() ) {
197 return;
198 }
199
200 this.filtersViewModel.getHighlightedItems().forEach( function ( filterItem ) {
201 // Add highlight class to all highlighted list items
202 this.$element.find( '.' + filterItem.getCssClass() )
203 .addClass( 'mw-rcfilters-highlight-color-' + filterItem.getHighlightColor() );
204 }.bind( this ) );
205
206 // Turn on highlights
207 this.$element.addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlighted' );
208 };
209
210 /**
211 * Remove all color classes
212 */
213 mw.rcfilters.ui.ChangesListWrapperWidget.prototype.clearHighlight = function () {
214 // Remove highlight classes
215 mw.rcfilters.HighlightColors.forEach( function ( color ) {
216 this.$element.find( '.mw-rcfilters-highlight-color-' + color ).removeClass( 'mw-rcfilters-highlight-color-' + color );
217 }.bind( this ) );
218
219 // Turn off highlights
220 this.$element.removeClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlighted' );
221 };
222 }( mediaWiki ) );