X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=resources%2Fsrc%2Fmediawiki.rcfilters%2Fdm%2FSavedQueriesModel.js;h=19de282e39db060a12a90192f7e8ab283dd76492;hb=7ecbff2360a07755f771c648ed1e27ee3dca8ad5;hp=aa407b91ee89b1845508456043ccc31b35557675;hpb=1005e91c8c855ef76656d1b644116449e41db434;p=lhc%2Fweb%2Fwiklou.git diff --git a/resources/src/mediawiki.rcfilters/dm/SavedQueriesModel.js b/resources/src/mediawiki.rcfilters/dm/SavedQueriesModel.js index aa407b91ee..19de282e39 100644 --- a/resources/src/mediawiki.rcfilters/dm/SavedQueriesModel.js +++ b/resources/src/mediawiki.rcfilters/dm/SavedQueriesModel.js @@ -1,415 +1,413 @@ -( function () { - var SavedQueryItemModel = require( './SavedQueryItemModel.js' ), - SavedQueriesModel; - - /** - * View model for saved queries - * - * @class mw.rcfilters.dm.SavedQueriesModel - * @mixins OO.EventEmitter - * @mixins OO.EmitterList - * - * @constructor - * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters model - * @param {Object} [config] Configuration options - * @cfg {string} [default] Default query ID - */ - SavedQueriesModel = function MwRcfiltersDmSavedQueriesModel( filtersModel, config ) { - config = config || {}; - - // Mixin constructor - OO.EventEmitter.call( this ); - OO.EmitterList.call( this ); - - this.default = config.default; - this.filtersModel = filtersModel; - this.converted = false; - - // Events - this.aggregate( { update: 'itemUpdate' } ); - }; - - /* Initialization */ - - OO.initClass( SavedQueriesModel ); - OO.mixinClass( SavedQueriesModel, OO.EventEmitter ); - OO.mixinClass( SavedQueriesModel, OO.EmitterList ); - - /* Events */ - - /** - * @event initialize - * - * Model is initialized - */ - - /** - * @event itemUpdate - * @param {mw.rcfilters.dm.SavedQueryItemModel} Changed item - * - * An item has changed - */ - - /** - * @event default - * @param {string} New default ID - * - * The default has changed - */ - - /* Methods */ - - /** - * Initialize the saved queries model by reading it from the user's settings. - * The structure of the saved queries is: - * { - * version: (string) Version number; if version 2, the query represents - * parameters. Otherwise, the older version represented filters - * and needs to be readjusted, - * default: (string) Query ID - * queries:{ - * query_id_1: { - * data:{ - * filters: (Object) Minimal definition of the filters - * highlights: (Object) Definition of the highlights - * }, - * label: (optional) Name of this query - * } - * } - * } - * - * @param {Object} [savedQueries] An object with the saved queries with - * the above structure. - * @fires initialize - */ - SavedQueriesModel.prototype.initialize = function ( savedQueries ) { - var model = this; - - savedQueries = savedQueries || {}; - - this.clearItems(); - this.default = null; - this.converted = false; - - if ( savedQueries.version !== '2' ) { - // Old version dealt with filter names. We need to migrate to the new structure - // The new structure: - // { - // version: (string) '2', - // default: (string) Query ID, - // queries: { - // query_id: { - // label: (string) Name of the query - // data: { - // params: (object) Representing all the parameter states - // highlights: (object) Representing all the filter highlight states - // } - // } - // } - // eslint-disable-next-line no-jquery/no-each-util - $.each( savedQueries.queries || {}, function ( id, obj ) { - if ( obj.data && obj.data.filters ) { - obj.data = model.convertToParameters( obj.data ); - } - } ); - - this.converted = true; - savedQueries.version = '2'; - } - - // Initialize the query items +var SavedQueryItemModel = require( './SavedQueryItemModel.js' ), + SavedQueriesModel; + +/** + * View model for saved queries + * + * @class mw.rcfilters.dm.SavedQueriesModel + * @mixins OO.EventEmitter + * @mixins OO.EmitterList + * + * @constructor + * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters model + * @param {Object} [config] Configuration options + * @cfg {string} [default] Default query ID + */ +SavedQueriesModel = function MwRcfiltersDmSavedQueriesModel( filtersModel, config ) { + config = config || {}; + + // Mixin constructor + OO.EventEmitter.call( this ); + OO.EmitterList.call( this ); + + this.default = config.default; + this.filtersModel = filtersModel; + this.converted = false; + + // Events + this.aggregate( { update: 'itemUpdate' } ); +}; + +/* Initialization */ + +OO.initClass( SavedQueriesModel ); +OO.mixinClass( SavedQueriesModel, OO.EventEmitter ); +OO.mixinClass( SavedQueriesModel, OO.EmitterList ); + +/* Events */ + +/** + * @event initialize + * + * Model is initialized + */ + +/** + * @event itemUpdate + * @param {mw.rcfilters.dm.SavedQueryItemModel} Changed item + * + * An item has changed + */ + +/** + * @event default + * @param {string} New default ID + * + * The default has changed + */ + +/* Methods */ + +/** + * Initialize the saved queries model by reading it from the user's settings. + * The structure of the saved queries is: + * { + * version: (string) Version number; if version 2, the query represents + * parameters. Otherwise, the older version represented filters + * and needs to be readjusted, + * default: (string) Query ID + * queries:{ + * query_id_1: { + * data:{ + * filters: (Object) Minimal definition of the filters + * highlights: (Object) Definition of the highlights + * }, + * label: (optional) Name of this query + * } + * } + * } + * + * @param {Object} [savedQueries] An object with the saved queries with + * the above structure. + * @fires initialize + */ +SavedQueriesModel.prototype.initialize = function ( savedQueries ) { + var model = this; + + savedQueries = savedQueries || {}; + + this.clearItems(); + this.default = null; + this.converted = false; + + if ( savedQueries.version !== '2' ) { + // Old version dealt with filter names. We need to migrate to the new structure + // The new structure: + // { + // version: (string) '2', + // default: (string) Query ID, + // queries: { + // query_id: { + // label: (string) Name of the query + // data: { + // params: (object) Representing all the parameter states + // highlights: (object) Representing all the filter highlight states + // } + // } + // } // eslint-disable-next-line no-jquery/no-each-util $.each( savedQueries.queries || {}, function ( id, obj ) { - var normalizedData = obj.data, - isDefault = String( savedQueries.default ) === String( id ); - - if ( normalizedData && normalizedData.params ) { - // Backwards-compat fix: Remove sticky parameters from - // the given data, if they exist - normalizedData.params = model.filtersModel.removeStickyParams( normalizedData.params ); - - // Correct the invert state for effective selection - if ( normalizedData.params.invert && !normalizedData.params.namespace ) { - delete normalizedData.params.invert; - } - - model.cleanupHighlights( normalizedData ); - - id = String( id ); - - // Skip the addNewQuery method because we don't want to unnecessarily manipulate - // the given saved queries unless we literally intend to (like in backwards compat fixes) - // And the addNewQuery method also uses a minimization routine that checks for the - // validity of items and minimizes the query. This isn't necessary for queries loaded - // from the backend, and has the risk of removing values if they're temporarily - // invalid (example: if we temporarily removed a cssClass from a filter in the backend) - model.addItems( [ - new SavedQueryItemModel( - id, - obj.label, - normalizedData, - { default: isDefault } - ) - ] ); - - if ( isDefault ) { - model.default = id; - } + if ( obj.data && obj.data.filters ) { + obj.data = model.convertToParameters( obj.data ); } } ); - this.emit( 'initialize' ); - }; - - /** - * Clean up highlight parameters. - * 'highlight' used to be stored, it's not inferred based on the presence of absence of - * filter colors. - * - * @param {Object} data Saved query data - */ - SavedQueriesModel.prototype.cleanupHighlights = function ( data ) { - if ( - data.params.highlight === '0' && - data.highlights && Object.keys( data.highlights ).length - ) { - data.highlights = {}; - } - delete data.params.highlight; - }; - - /** - * Convert from representation of filters to representation of parameters - * - * @param {Object} data Query data - * @return {Object} New converted query data - */ - SavedQueriesModel.prototype.convertToParameters = function ( data ) { - var newData = {}, - defaultFilters = this.filtersModel.getFiltersFromParameters( this.filtersModel.getDefaultParams() ), - fullFilterRepresentation = $.extend( true, {}, defaultFilters, data.filters ), - highlightEnabled = data.highlights.highlight; - - delete data.highlights.highlight; - - // Filters - newData.params = this.filtersModel.getMinimizedParamRepresentation( - this.filtersModel.getParametersFromFilters( fullFilterRepresentation ) - ); + this.converted = true; + savedQueries.version = '2'; + } - // Highlights: appending _color to keys - newData.highlights = {}; - // eslint-disable-next-line no-jquery/no-each-util - $.each( data.highlights, function ( highlightedFilterName, value ) { - if ( value ) { - newData.highlights[ highlightedFilterName + '_color' ] = data.highlights[ highlightedFilterName ]; - } - } ); + // Initialize the query items + // eslint-disable-next-line no-jquery/no-each-util + $.each( savedQueries.queries || {}, function ( id, obj ) { + var normalizedData = obj.data, + isDefault = String( savedQueries.default ) === String( id ); - // Add highlight - newData.params.highlight = String( Number( highlightEnabled || 0 ) ); - - return newData; - }; - - /** - * Add a query item - * - * @param {string} label Label for the new query - * @param {Object} fulldata Full data representation for the new query, combining highlights and filters - * @param {boolean} isDefault Item is default - * @param {string} [id] Query ID, if exists. If this isn't given, a random - * new ID will be created. - * @return {string} ID of the newly added query - */ - SavedQueriesModel.prototype.addNewQuery = function ( label, fulldata, isDefault, id ) { - var normalizedData = { params: {}, highlights: {} }, - highlightParamNames = Object.keys( this.filtersModel.getEmptyHighlightParameters() ), - randomID = String( id || ( new Date() ).getTime() ), - data = this.filtersModel.getMinimizedParamRepresentation( fulldata ); - - // Split highlight/params - // eslint-disable-next-line no-jquery/no-each-util - $.each( data, function ( param, value ) { - if ( param !== 'highlight' && highlightParamNames.indexOf( param ) > -1 ) { - normalizedData.highlights[ param ] = value; - } else { - normalizedData.params[ param ] = value; + if ( normalizedData && normalizedData.params ) { + // Backwards-compat fix: Remove sticky parameters from + // the given data, if they exist + normalizedData.params = model.filtersModel.removeStickyParams( normalizedData.params ); + + // Correct the invert state for effective selection + if ( normalizedData.params.invert && !normalizedData.params.namespace ) { + delete normalizedData.params.invert; } - } ); - // Correct the invert state for effective selection - if ( normalizedData.params.invert && !this.filtersModel.areNamespacesEffectivelyInverted() ) { - delete normalizedData.params.invert; + model.cleanupHighlights( normalizedData ); + + id = String( id ); + + // Skip the addNewQuery method because we don't want to unnecessarily manipulate + // the given saved queries unless we literally intend to (like in backwards compat fixes) + // And the addNewQuery method also uses a minimization routine that checks for the + // validity of items and minimizes the query. This isn't necessary for queries loaded + // from the backend, and has the risk of removing values if they're temporarily + // invalid (example: if we temporarily removed a cssClass from a filter in the backend) + model.addItems( [ + new SavedQueryItemModel( + id, + obj.label, + normalizedData, + { default: isDefault } + ) + ] ); + + if ( isDefault ) { + model.default = id; + } } - - // Add item - this.addItems( [ - new SavedQueryItemModel( - randomID, - label, - normalizedData, - { default: isDefault } - ) - ] ); - - if ( isDefault ) { - this.setDefault( randomID ); + } ); + + this.emit( 'initialize' ); +}; + +/** + * Clean up highlight parameters. + * 'highlight' used to be stored, it's not inferred based on the presence of absence of + * filter colors. + * + * @param {Object} data Saved query data + */ +SavedQueriesModel.prototype.cleanupHighlights = function ( data ) { + if ( + data.params.highlight === '0' && + data.highlights && Object.keys( data.highlights ).length + ) { + data.highlights = {}; + } + delete data.params.highlight; +}; + +/** + * Convert from representation of filters to representation of parameters + * + * @param {Object} data Query data + * @return {Object} New converted query data + */ +SavedQueriesModel.prototype.convertToParameters = function ( data ) { + var newData = {}, + defaultFilters = this.filtersModel.getFiltersFromParameters( this.filtersModel.getDefaultParams() ), + fullFilterRepresentation = $.extend( true, {}, defaultFilters, data.filters ), + highlightEnabled = data.highlights.highlight; + + delete data.highlights.highlight; + + // Filters + newData.params = this.filtersModel.getMinimizedParamRepresentation( + this.filtersModel.getParametersFromFilters( fullFilterRepresentation ) + ); + + // Highlights: appending _color to keys + newData.highlights = {}; + // eslint-disable-next-line no-jquery/no-each-util + $.each( data.highlights, function ( highlightedFilterName, value ) { + if ( value ) { + newData.highlights[ highlightedFilterName + '_color' ] = data.highlights[ highlightedFilterName ]; } - - return randomID; - }; - - /** - * Remove query from model - * - * @param {string} queryID Query ID - */ - SavedQueriesModel.prototype.removeQuery = function ( queryID ) { - var query = this.getItemByID( queryID ); - - if ( query ) { - // Check if this item was the default - if ( String( this.getDefault() ) === String( queryID ) ) { - // Nulify the default - this.setDefault( null ); - } - - this.removeItems( [ query ] ); + } ); + + // Add highlight + newData.params.highlight = String( Number( highlightEnabled || 0 ) ); + + return newData; +}; + +/** + * Add a query item + * + * @param {string} label Label for the new query + * @param {Object} fulldata Full data representation for the new query, combining highlights and filters + * @param {boolean} isDefault Item is default + * @param {string} [id] Query ID, if exists. If this isn't given, a random + * new ID will be created. + * @return {string} ID of the newly added query + */ +SavedQueriesModel.prototype.addNewQuery = function ( label, fulldata, isDefault, id ) { + var normalizedData = { params: {}, highlights: {} }, + highlightParamNames = Object.keys( this.filtersModel.getEmptyHighlightParameters() ), + randomID = String( id || ( new Date() ).getTime() ), + data = this.filtersModel.getMinimizedParamRepresentation( fulldata ); + + // Split highlight/params + // eslint-disable-next-line no-jquery/no-each-util + $.each( data, function ( param, value ) { + if ( param !== 'highlight' && highlightParamNames.indexOf( param ) > -1 ) { + normalizedData.highlights[ param ] = value; + } else { + normalizedData.params[ param ] = value; } - }; - - /** - * Get an item that matches the requested query - * - * @param {Object} fullQueryComparison Object representing all filters and highlights to compare - * @return {mw.rcfilters.dm.SavedQueryItemModel} Matching item model - */ - SavedQueriesModel.prototype.findMatchingQuery = function ( fullQueryComparison ) { - // Minimize before comparison - fullQueryComparison = this.filtersModel.getMinimizedParamRepresentation( fullQueryComparison ); - - // Correct the invert state for effective selection - if ( fullQueryComparison.invert && !this.filtersModel.areNamespacesEffectivelyInverted() ) { - delete fullQueryComparison.invert; + } ); + + // Correct the invert state for effective selection + if ( normalizedData.params.invert && !this.filtersModel.areNamespacesEffectivelyInverted() ) { + delete normalizedData.params.invert; + } + + // Add item + this.addItems( [ + new SavedQueryItemModel( + randomID, + label, + normalizedData, + { default: isDefault } + ) + ] ); + + if ( isDefault ) { + this.setDefault( randomID ); + } + + return randomID; +}; + +/** + * Remove query from model + * + * @param {string} queryID Query ID + */ +SavedQueriesModel.prototype.removeQuery = function ( queryID ) { + var query = this.getItemByID( queryID ); + + if ( query ) { + // Check if this item was the default + if ( String( this.getDefault() ) === String( queryID ) ) { + // Nulify the default + this.setDefault( null ); } - return this.getItems().filter( function ( item ) { - return OO.compare( - item.getCombinedData(), - fullQueryComparison - ); - } )[ 0 ]; - }; - - /** - * Get query by its identifier - * - * @param {string} queryID Query identifier - * @return {mw.rcfilters.dm.SavedQueryItemModel|undefined} Item matching - * the search. Undefined if not found. - */ - SavedQueriesModel.prototype.getItemByID = function ( queryID ) { - return this.getItems().filter( function ( item ) { - return item.getID() === queryID; - } )[ 0 ]; - }; - - /** - * Get the full data representation of the default query, if it exists - * - * @return {Object|null} Representation of the default params if exists. - * Null if default doesn't exist or if the user is not logged in. - */ - SavedQueriesModel.prototype.getDefaultParams = function () { - return ( !mw.user.isAnon() && this.getItemParams( this.getDefault() ) ) || {}; - }; - - /** - * Get a full parameter representation of an item data - * - * @param {Object} queryID Query ID - * @return {Object} Parameter representation - */ - SavedQueriesModel.prototype.getItemParams = function ( queryID ) { - var item = this.getItemByID( queryID ), - data = item ? item.getData() : {}; - - return !$.isEmptyObject( data ) ? this.buildParamsFromData( data ) : {}; - }; - - /** - * Build a full parameter representation given item data and model sticky values state - * - * @param {Object} data Item data - * @return {Object} Full param representation - */ - SavedQueriesModel.prototype.buildParamsFromData = function ( data ) { - data = data || {}; - // Return parameter representation - return this.filtersModel.getMinimizedParamRepresentation( $.extend( true, {}, - data.params, - data.highlights - ) ); - }; - - /** - * Get the object representing the state of the entire model and items - * - * @return {Object} Object representing the state of the model and items - */ - SavedQueriesModel.prototype.getState = function () { - var obj = { queries: {}, version: '2' }; - - // Translate the items to the saved object + this.removeItems( [ query ] ); + } +}; + +/** + * Get an item that matches the requested query + * + * @param {Object} fullQueryComparison Object representing all filters and highlights to compare + * @return {mw.rcfilters.dm.SavedQueryItemModel} Matching item model + */ +SavedQueriesModel.prototype.findMatchingQuery = function ( fullQueryComparison ) { + // Minimize before comparison + fullQueryComparison = this.filtersModel.getMinimizedParamRepresentation( fullQueryComparison ); + + // Correct the invert state for effective selection + if ( fullQueryComparison.invert && !this.filtersModel.areNamespacesEffectivelyInverted() ) { + delete fullQueryComparison.invert; + } + + return this.getItems().filter( function ( item ) { + return OO.compare( + item.getCombinedData(), + fullQueryComparison + ); + } )[ 0 ]; +}; + +/** + * Get query by its identifier + * + * @param {string} queryID Query identifier + * @return {mw.rcfilters.dm.SavedQueryItemModel|undefined} Item matching + * the search. Undefined if not found. + */ +SavedQueriesModel.prototype.getItemByID = function ( queryID ) { + return this.getItems().filter( function ( item ) { + return item.getID() === queryID; + } )[ 0 ]; +}; + +/** + * Get the full data representation of the default query, if it exists + * + * @return {Object|null} Representation of the default params if exists. + * Null if default doesn't exist or if the user is not logged in. + */ +SavedQueriesModel.prototype.getDefaultParams = function () { + return ( !mw.user.isAnon() && this.getItemParams( this.getDefault() ) ) || {}; +}; + +/** + * Get a full parameter representation of an item data + * + * @param {Object} queryID Query ID + * @return {Object} Parameter representation + */ +SavedQueriesModel.prototype.getItemParams = function ( queryID ) { + var item = this.getItemByID( queryID ), + data = item ? item.getData() : {}; + + return !$.isEmptyObject( data ) ? this.buildParamsFromData( data ) : {}; +}; + +/** + * Build a full parameter representation given item data and model sticky values state + * + * @param {Object} data Item data + * @return {Object} Full param representation + */ +SavedQueriesModel.prototype.buildParamsFromData = function ( data ) { + data = data || {}; + // Return parameter representation + return this.filtersModel.getMinimizedParamRepresentation( $.extend( true, {}, + data.params, + data.highlights + ) ); +}; + +/** + * Get the object representing the state of the entire model and items + * + * @return {Object} Object representing the state of the model and items + */ +SavedQueriesModel.prototype.getState = function () { + var obj = { queries: {}, version: '2' }; + + // Translate the items to the saved object + this.getItems().forEach( function ( item ) { + obj.queries[ item.getID() ] = item.getState(); + } ); + + if ( this.getDefault() ) { + obj.default = this.getDefault(); + } + + return obj; +}; + +/** + * Set a default query. Null to unset default. + * + * @param {string} itemID Query identifier + * @fires default + */ +SavedQueriesModel.prototype.setDefault = function ( itemID ) { + if ( this.default !== itemID ) { + this.default = itemID; + + // Set for individual itens this.getItems().forEach( function ( item ) { - obj.queries[ item.getID() ] = item.getState(); + item.toggleDefault( item.getID() === itemID ); } ); - if ( this.getDefault() ) { - obj.default = this.getDefault(); - } - - return obj; - }; - - /** - * Set a default query. Null to unset default. - * - * @param {string} itemID Query identifier - * @fires default - */ - SavedQueriesModel.prototype.setDefault = function ( itemID ) { - if ( this.default !== itemID ) { - this.default = itemID; - - // Set for individual itens - this.getItems().forEach( function ( item ) { - item.toggleDefault( item.getID() === itemID ); - } ); - - this.emit( 'default', itemID ); - } - }; - - /** - * Get the default query ID - * - * @return {string} Default query identifier - */ - SavedQueriesModel.prototype.getDefault = function () { - return this.default; - }; - - /** - * Check if the saved queries were converted - * - * @return {boolean} Saved queries were converted from the previous - * version to the new version - */ - SavedQueriesModel.prototype.isConverted = function () { - return this.converted; - }; - - module.exports = SavedQueriesModel; -}() ); + this.emit( 'default', itemID ); + } +}; + +/** + * Get the default query ID + * + * @return {string} Default query identifier + */ +SavedQueriesModel.prototype.getDefault = function () { + return this.default; +}; + +/** + * Check if the saved queries were converted + * + * @return {boolean} Saved queries were converted from the previous + * version to the new version + */ +SavedQueriesModel.prototype.isConverted = function () { + return this.converted; +}; + +module.exports = SavedQueriesModel;