Merge "Log a backtrace from the culprit location if headers were already sent"
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / mw.rcfilters.Controller.js
1 ( function ( mw, $ ) {
2 /**
3 * Controller for the filters in Recent Changes
4 *
5 * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters view model
6 * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel Changes list view model
7 */
8 mw.rcfilters.Controller = function MwRcfiltersController( filtersModel, changesListModel ) {
9 this.filtersModel = filtersModel;
10 this.changesListModel = changesListModel;
11 this.requestCounter = 0;
12 };
13
14 /* Initialization */
15 OO.initClass( mw.rcfilters.Controller );
16
17 /**
18 * Initialize the filter and parameter states
19 *
20 * @param {Object} filterStructure Filter definition and structure for the model
21 */
22 mw.rcfilters.Controller.prototype.initialize = function ( filterStructure ) {
23 var uri = new mw.Uri();
24
25 // Initialize the model
26 this.filtersModel.initializeFilters( filterStructure );
27
28 // Set filter states based on defaults and URL params
29 this.filtersModel.updateFilters(
30 this.filtersModel.getFiltersFromParameters(
31 // Merge defaults with URL params for initialization
32 $.extend(
33 true,
34 {},
35 this.filtersModel.getDefaultParams(),
36 // URI query overrides defaults
37 uri.query
38 )
39 )
40 );
41
42 // Initialize highlights
43 this.filtersModel.toggleHighlight( !!uri.query.highlight );
44 this.filtersModel.getItems().forEach( function ( filterItem ) {
45 var color = uri.query[ filterItem.getName() + '_color' ];
46 if ( !color ) {
47 return;
48 }
49
50 filterItem.setHighlightColor( color );
51 } );
52
53 // Check all filter interactions
54 this.filtersModel.reassessFilterInteractions();
55 };
56
57 /**
58 * Reset to default filters
59 */
60 mw.rcfilters.Controller.prototype.resetToDefaults = function () {
61 this.filtersModel.setFiltersToDefaults();
62 // Check all filter interactions
63 this.filtersModel.reassessFilterInteractions();
64
65 this.updateURL();
66 this.updateChangesList();
67 };
68
69 /**
70 * Empty all selected filters
71 */
72 mw.rcfilters.Controller.prototype.emptyFilters = function () {
73 this.filtersModel.emptyAllFilters();
74 this.filtersModel.clearAllHighlightColors();
75 // Check all filter interactions
76 this.filtersModel.reassessFilterInteractions();
77
78 this.updateURL();
79 this.updateChangesList();
80 };
81
82 /**
83 * Update the state of a filter
84 *
85 * @param {string} filterName Filter name
86 * @param {boolean} isSelected Filter selected state
87 */
88 mw.rcfilters.Controller.prototype.updateFilter = function ( filterName, isSelected ) {
89 var obj = {},
90 filterItem = this.filtersModel.getItemByName( filterName );
91
92 if ( filterItem.isSelected() !== isSelected ) {
93 obj[ filterName ] = isSelected;
94 this.filtersModel.updateFilters( obj );
95
96 this.updateURL();
97 this.updateChangesList();
98
99 // Check filter interactions
100 this.filtersModel.reassessFilterInteractions( this.filtersModel.getItemByName( filterName ) );
101 }
102 };
103
104 /**
105 * Update the URL of the page to reflect current filters
106 */
107 mw.rcfilters.Controller.prototype.updateURL = function () {
108 var uri = this.getUpdatedUri();
109 window.history.pushState( { tag: 'rcfilters' }, document.title, uri.toString() );
110 };
111
112 /**
113 * Get an updated mw.Uri object based on the model state
114 *
115 * @return {mw.Uri} Updated Uri
116 */
117 mw.rcfilters.Controller.prototype.getUpdatedUri = function () {
118 var uri = new mw.Uri(),
119 highlightParams = this.filtersModel.getHighlightParameters();
120
121 // Add to existing queries in URL
122 // TODO: Clean up the list of filters; perhaps 'falsy' filters
123 // shouldn't appear at all? Or compare to existing query string
124 // and see if current state of a specific filter is needed?
125 uri.extend( this.filtersModel.getParametersFromFilters() );
126
127 // highlight params
128 Object.keys( highlightParams ).forEach( function ( paramName ) {
129 if ( highlightParams[ paramName ] ) {
130 uri.query[ paramName ] = highlightParams[ paramName ];
131 } else {
132 delete uri.query[ paramName ];
133 }
134 } );
135
136 return uri;
137 };
138
139 /**
140 * Fetch the list of changes from the server for the current filters
141 *
142 * @return {jQuery.Promise} Promise object that will resolve with the changes list
143 */
144 mw.rcfilters.Controller.prototype.fetchChangesList = function () {
145 var uri = this.getUpdatedUri(),
146 requestId = ++this.requestCounter,
147 latestRequest = function () {
148 return requestId === this.requestCounter;
149 }.bind( this );
150 uri.extend( this.filtersModel.getParametersFromFilters() );
151 return $.ajax( uri.toString(), { contentType: 'html' } )
152 .then( function ( html ) {
153 return latestRequest() ?
154 $( $.parseHTML( html ) ).find( '.mw-changeslist' ).first().contents() :
155 null;
156 } ).then( null, function () {
157 return latestRequest() ? 'NO_RESULTS' : null;
158 } );
159 };
160
161 /**
162 * Update the list of changes and notify the model
163 */
164 mw.rcfilters.Controller.prototype.updateChangesList = function () {
165 this.changesListModel.invalidate();
166 this.fetchChangesList()
167 .always( function ( changesListContent ) {
168 if ( changesListContent ) {
169 this.changesListModel.update( changesListContent );
170 }
171 }.bind( this ) );
172 };
173
174 /**
175 * Toggle the highlight feature on and off
176 */
177 mw.rcfilters.Controller.prototype.toggleHighlight = function () {
178 this.filtersModel.toggleHighlight();
179 this.updateURL();
180 };
181
182 /**
183 * Set the highlight color for a filter item
184 *
185 * @param {string} filterName Name of the filter item
186 * @param {string} color Selected color
187 */
188 mw.rcfilters.Controller.prototype.setHighlightColor = function ( filterName, color ) {
189 this.filtersModel.setHighlightColor( filterName, color );
190 this.updateURL();
191 };
192
193 /**
194 * Clear highlight for a filter item
195 *
196 * @param {string} filterName Name of the filter item
197 */
198 mw.rcfilters.Controller.prototype.clearHighlightColor = function ( filterName ) {
199 this.filtersModel.clearHighlightColor( filterName );
200 this.updateURL();
201 };
202 }( mediaWiki, jQuery ) );