RCFilters UI: Define interaction states for filters
[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 // Check all filter interactions
43 this.filtersModel.reassessFilterInteractions();
44 };
45
46 /**
47 * Reset to default filters
48 */
49 mw.rcfilters.Controller.prototype.resetToDefaults = function () {
50 this.filtersModel.setFiltersToDefaults();
51 this.updateURL();
52 this.updateChangesList();
53 };
54
55 /**
56 * Empty all selected filters
57 */
58 mw.rcfilters.Controller.prototype.emptyFilters = function () {
59 this.filtersModel.emptyAllFilters();
60 this.updateURL();
61 this.updateChangesList();
62 };
63
64 /**
65 * Update the state of a filter
66 *
67 * @param {string} filterName Filter name
68 * @param {boolean} isSelected Filter selected state
69 */
70 mw.rcfilters.Controller.prototype.updateFilter = function ( filterName, isSelected ) {
71 var obj = {};
72
73 obj[ filterName ] = isSelected;
74
75 this.filtersModel.updateFilters( obj );
76 this.updateURL();
77 this.updateChangesList();
78
79 // Check filter interactions
80 this.filtersModel.reassessFilterInteractions( this.filtersModel.getItemByName( filterName ) );
81 };
82
83 /**
84 * Update the URL of the page to reflect current filters
85 */
86 mw.rcfilters.Controller.prototype.updateURL = function () {
87 var uri = new mw.Uri();
88
89 // Add to existing queries in URL
90 // TODO: Clean up the list of filters; perhaps 'falsy' filters
91 // shouldn't appear at all? Or compare to existing query string
92 // and see if current state of a specific filter is needed?
93 uri.extend( this.filtersModel.getParametersFromFilters() );
94
95 // Update the URL itself
96 window.history.pushState( { tag: 'rcfilters' }, document.title, uri.toString() );
97 };
98
99 /**
100 * Fetch the list of changes from the server for the current filters
101 *
102 * @returns {jQuery.Promise} Promise object that will resolve with the changes list
103 */
104 mw.rcfilters.Controller.prototype.fetchChangesList = function () {
105 var uri = new mw.Uri(),
106 requestId = ++this.requestCounter,
107 latestRequest = function () {
108 return requestId === this.requestCounter;
109 }.bind( this );
110 uri.extend( this.filtersModel.getParametersFromFilters() );
111 return $.ajax( uri.toString(), { contentType: 'html' } )
112 .then( function ( html ) {
113 return latestRequest() ?
114 $( $.parseHTML( html ) ).find( '.mw-changeslist' ).first().contents() :
115 null;
116 } ).then( null, function () {
117 return latestRequest() ? 'NO_RESULTS' : null;
118 } );
119 };
120
121 /**
122 * Update the list of changes and notify the model
123 */
124 mw.rcfilters.Controller.prototype.updateChangesList = function () {
125 this.changesListModel.invalidate();
126 this.fetchChangesList()
127 .always( function ( changesListContent ) {
128 if ( changesListContent ) {
129 this.changesListModel.update( changesListContent );
130 }
131 }.bind( this ) );
132 };
133 }( mediaWiki, jQuery ) );