RCFilters UI: Highlight behavior
[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 this.updateURL();
63 this.updateChangesList();
64 };
65
66 /**
67 * Empty all selected filters
68 */
69 mw.rcfilters.Controller.prototype.emptyFilters = function () {
70 this.filtersModel.emptyAllFilters();
71 this.filtersModel.clearAllHighlightColors();
72 this.updateURL();
73 this.updateChangesList();
74 };
75
76 /**
77 * Update the state of a filter
78 *
79 * @param {string} filterName Filter name
80 * @param {boolean} isSelected Filter selected state
81 */
82 mw.rcfilters.Controller.prototype.updateFilter = function ( filterName, isSelected ) {
83 var obj = {},
84 filterItem = this.filtersModel.getItemByName( filterName );
85
86 if ( filterItem.isSelected() !== isSelected ) {
87 obj[ filterName ] = isSelected;
88 this.filtersModel.updateFilters( obj );
89
90 this.updateURL();
91 this.updateChangesList();
92
93 // Check filter interactions
94 this.filtersModel.reassessFilterInteractions( this.filtersModel.getItemByName( filterName ) );
95 }
96 };
97
98 /**
99 * Update the URL of the page to reflect current filters
100 */
101 mw.rcfilters.Controller.prototype.updateURL = function () {
102 var uri = this.getUpdatedUri();
103 window.history.pushState( { tag: 'rcfilters' }, document.title, uri.toString() );
104 };
105
106 /**
107 * Get an updated mw.Uri object based on the model state
108 *
109 * @return {mw.Uri} Updated Uri
110 */
111 mw.rcfilters.Controller.prototype.getUpdatedUri = function () {
112 var uri = new mw.Uri(),
113 highlightParams = this.filtersModel.getHighlightParameters();
114
115 // Add to existing queries in URL
116 // TODO: Clean up the list of filters; perhaps 'falsy' filters
117 // shouldn't appear at all? Or compare to existing query string
118 // and see if current state of a specific filter is needed?
119 uri.extend( this.filtersModel.getParametersFromFilters() );
120
121 // highlight params
122 Object.keys( highlightParams ).forEach( function ( paramName ) {
123 if ( highlightParams[ paramName ] ) {
124 uri.query[ paramName ] = highlightParams[ paramName ];
125 } else {
126 delete uri.query[ paramName ];
127 }
128 } );
129
130 return uri;
131 };
132
133 /**
134 * Fetch the list of changes from the server for the current filters
135 *
136 * @return {jQuery.Promise} Promise object that will resolve with the changes list
137 */
138 mw.rcfilters.Controller.prototype.fetchChangesList = function () {
139 var uri = this.getUpdatedUri(),
140 requestId = ++this.requestCounter,
141 latestRequest = function () {
142 return requestId === this.requestCounter;
143 }.bind( this );
144 uri.extend( this.filtersModel.getParametersFromFilters() );
145 return $.ajax( uri.toString(), { contentType: 'html' } )
146 .then( function ( html ) {
147 return latestRequest() ?
148 $( $.parseHTML( html ) ).find( '.mw-changeslist' ).first().contents() :
149 null;
150 } ).then( null, function () {
151 return latestRequest() ? 'NO_RESULTS' : null;
152 } );
153 };
154
155 /**
156 * Update the list of changes and notify the model
157 */
158 mw.rcfilters.Controller.prototype.updateChangesList = function () {
159 this.changesListModel.invalidate();
160 this.fetchChangesList()
161 .always( function ( changesListContent ) {
162 if ( changesListContent ) {
163 this.changesListModel.update( changesListContent );
164 }
165 }.bind( this ) );
166 };
167
168 /**
169 * Toggle the highlight feature on and off
170 */
171 mw.rcfilters.Controller.prototype.toggleHighlight = function () {
172 this.filtersModel.toggleHighlight();
173 this.updateURL();
174 };
175
176 /**
177 * Set the highlight color for a filter item
178 *
179 * @param {string} filterName Name of the filter item
180 * @param {string} color Selected color
181 */
182 mw.rcfilters.Controller.prototype.setHighlightColor = function ( filterName, color ) {
183 this.filtersModel.setHighlightColor( filterName, color );
184 this.updateURL();
185 };
186
187 /**
188 * Clear highlight for a filter item
189 *
190 * @param {string} filterName Name of the filter item
191 */
192 mw.rcfilters.Controller.prototype.clearHighlightColor = function ( filterName ) {
193 this.filtersModel.clearHighlightColor( filterName );
194 this.updateURL();
195 };
196 }( mediaWiki, jQuery ) );