mediawiki-extensions-Templa.../modules/ext.templateDataGenerator.data.js
Moriel Schottlender df59f0179a Eventify TemplateDataGenerator and use oojs-ui
Change the ui/data behavior to work with oojs and event emitters,
and replace the gui from jquery ui to oojs-ui.

Changes made:
* Recreate the templatedata editor with oojs and ooui.
* Create a standalone templatedata model with internal validation.
* Allow the user to insert language-specific strings:
  * Allow adding arbitrary languages and values
  * Normalize output between language object and 'simple' string
  * Add new language code by searching for its name or code
* Import parameters from template code
  * If the template is in subpage and there is no code in the
    current page, the code will request the contents of the parent
    page.

Change-Id: I985ea03dfee58984ec22ec9a157a00968bfca878
2014-12-22 12:58:37 -05:00

1001 lines
28 KiB
JavaScript

( function ( $ ) {
/**
* TemplateData Dialog
* @param {Object} config Dialog configuration object
*/
TemplateDataModel = function TemplateDataModel( config ) {
config = config || {};
// Mixin constructors
OO.EventEmitter.call( this );
// Config
this.setParentPage( config.parentPage );
this.setPageSubLevel( config.isPageSubLevel );
// Properties
this.params = {};
this.description = {};
this.paramOrder = [];
this.paramIdentifierCounter = 0;
this.setPageSubLevel( !!config.isPageSubLevel );
this.setFullPageName( config.fullPageName || '' );
this.originalTemplateDataObject = null;
this.sourceCodeParameters = [];
this.templateSourceCodePromise = null;
};
/* Setup */
OO.initClass( TemplateDataModel );
OO.mixinClass( TemplateDataModel, OO.EventEmitter );
/* Events */
/**
* @event add-param
* @param {string} key Parameter key
* @param {Object} data Parameter data
*/
/**
* @event change-description
* @param {string} description New template description
* @param {Object} [language] Description language, if supplied
*/
/**
* @event change-paramOrder
* @param {string[]} orderArray Parameter key array in order
*/
/**
* @event change-property
* @param {string} paramKey Parameter key
* @param {string} prop Property name
* @param {Mixed...} value Property value
*/
/* Static Methods */
/**
* Get information from the mediaWiki API
* @param {string} page Page name
* @return {jQuery.Promise} API promise
*/
TemplateDataModel.static.getApi = function ( page ) {
var api = new mediaWiki.Api();
return api.get( {
action: 'query',
prop: 'revisions',
rvprop: 'content',
indexpageids: '1',
titles: page
} );
};
/**
* Compare two objects or strings
* @param {Object|string} obj1 Base object
* @param {Object|string} obj2 Compared object
* @param {boolean} [allowSubset] Allow the second object to be a
* partial object (or a subset) of the first.
* @return {boolean} Objects have equal values
*/
TemplateDataModel.static.compare = function ( obj1, obj2, allowSubset ) {
if ( allowSubset && obj2 === undefined ) {
return true;
}
// Make sure the objects are of the same type
if ( $.type( obj1 ) !== $.type( obj2 ) ) {
return false;
}
// Comparing objects or arrays
if ( typeof obj1 === 'object' ) {
return OO.compare( obj2, obj1, allowSubset );
}
// Everything else (primitive types, functions, etc)
return obj1 === obj2;
};
/**
* Translate obsolete parameter types into the new types
* @param {string} paramType Given type
* @return {string} Normalized non-obsolete type
*/
TemplateDataModel.static.translateObsoleteParamTypes = function ( paramType ) {
switch ( paramType ) {
case 'string/wiki-page-name':
return 'wiki-page-name';
case 'string/wiki-file-name':
return 'wiki-file-name';
case 'string/wiki-user-name':
return 'wiki-user-name';
default:
return paramType;
}
};
/**
* Retrieve information about all legal properties for a parameter.
* @param {boolean} getFullData Retrieve full information about each
* parameter. If false, the method will return an array of property
* names only.
* @return {Object|string[]} Legal property names with or without their
* definition data
*/
TemplateDataModel.static.getAllProperties = function ( getFullData ) {
var properties = {
name: {
type: 'string',
// Validation regex
restrict: /[\|=]|}}/
},
aliases: {
type: 'array',
delimiter: ','
},
label: {
type: 'string',
allowLanguages: true
},
description: {
type: 'string',
allowLanguages: true
},
type: {
type: 'select',
children: [
'boolean',
'content',
'wiki-file-name',
'line',
'number',
'date',
'wiki-page-name',
'string',
'unbalanced-wikitext',
'undefined',
'wiki-user-name'
],
'default': 'undefined'
},
'default': {
type: 'string',
multiline: true
},
autovalue: {
type: 'string'
},
required: {
type: 'boolean'
},
suggested: {
type: 'boolean'
}
};
if ( !getFullData ) {
return Object.keys( properties );
} else {
return properties;
}
};
/**
* Retrieve the list of property names that allow for multiple languages.
* @return {string[]} Property names
*/
TemplateDataModel.static.getPropertiesWithLanguage = function () {
var prop,
result = [],
propDefinitions = this.getAllProperties( true );
for ( prop in propDefinitions ) {
if ( propDefinitions[prop].allowLanguages ) {
result.push( prop );
}
}
return result;
};
/**
* Split a string into an array and clean/trim the values
* @param {string} str String to split
* @param {string} [delim] Delimeter
* @return {string[]} Clean array
*/
TemplateDataModel.static.splitAndTrimArray = function ( str, delim ) {
var arr = [];
delim = delim || ',';
$.each( str.split( delim ), function () {
var trimmed = $.trim( this );
if ( trimmed ) {
arr.push( trimmed );
}
} );
return arr;
};
/**
* This is an adjustment of OO.simpleArrayUnion that ignores
* empty values when inserting into the unified array.
* @param {Array...} arrays Arrays to union
* @return {Array} Union of the arrays
*/
TemplateDataModel.static.arrayUnionWithoutEmpty = function () {
var result = OO.simpleArrayUnion.apply( this, arguments );
// Filter empty strings
return result.filter( function ( i ) {
return i;
} );
};
/* Methods */
/**
* Load the model from the template data string. If no templatedata tags
* are available, the model will be initialized empty.
*
* After loading the model itself, fetch the parameter list from the template
* source code and update existing parameters in the model.
*
* @param {string} templateDataString Current page wikitext
*/
TemplateDataModel.prototype.loadModel = function ( tdString ) {
var original = {},
deferred = $.Deferred();
// Store existing templatedata into the model
this.setOriginalTemplateDataObject( this.getModelFromString( tdString ) );
original = this.getOriginalTemplateDataObject();
// Initialize model
this.params = {};
if ( original ) {
// Get parameter list from the template source code
this.getParametersFromTemplateSource( tdString ).done( $.proxy( function ( params ) {
this.sourceCodeParameters = params;
this.setTemplateDescription( original.description );
this.setTemplateParamOrder( original.paramOrder );
// Mark existing parameters in the model
if ( original.params ) {
for ( var param in original.params ) {
this.addParam( param, original.params[param] );
}
}
deferred.resolve();
}, this ) );
} else {
// Bad syntax for JSON
deferred.reject();
}
return deferred.promise();
};
/**
* Go over the importable parameters and check if they are
* included in the parameter model. Return the parameter names
* that are not included yet.
* @return {string[]} Parameters that are not yet included in
* the model
*/
TemplateDataModel.prototype.getMissingParams = function () {
var i,
result = [],
allParamNames = this.getAllParamNames();
// Check source code params
for ( i = 0; i < this.sourceCodeParameters.length; i++ ) {
if ( $.inArray( this.sourceCodeParameters[i], allParamNames ) === -1 ) {
result.push( this.sourceCodeParameters[i] );
}
}
return result;
};
/**
* Add imported parameters into the model
* @return {Object} Parameters added. -1 for failure.
*/
TemplateDataModel.prototype.importSourceCodeParameters = function () {
var i, paramKey,
allParamNames = this.getAllParamNames(),
existingArray = [],
importedArray = [],
skippedArray = [];
// Check existing params
for ( i = 0; i < allParamNames.length; i++ ) {
paramKey = allParamNames[i];
if ( $.inArray( paramKey, this.sourceCodeParameters ) !== -1 ) {
existingArray.push( paramKey );
}
}
// Add sourceCodeParameters to the model
for ( i = 0; i < this.sourceCodeParameters.length; i++ ) {
if (
$.inArray( this.sourceCodeParameters[i], existingArray ) === -1 &&
this.addParam( this.sourceCodeParameters[i] )
) {
importedArray.push( this.sourceCodeParameters[i]);
} else {
skippedArray.push( this.sourceCodeParameters[i]);
}
}
return {
imported: importedArray,
skipped: skippedArray,
existing: existingArray
};
};
/**
* Look for a templatedata json string and convert it into
* the and object, if it exists.
* @param {string} templateDataString Wikitext templatedata string
* @return {Object|null} The parsed json string. Empty if no
* templatedata string was found. Null if the json string
* failed to parse.
*/
TemplateDataModel.prototype.getModelFromString = function ( templateDataString ) {
var parts;
parts = templateDataString.match(
/<templatedata>([\s\S]*?)<\/templatedata>/i
);
// Check if <templatedata> exists
if ( parts && parts[1] && $.trim( parts[1] ).length > 0 ) {
// Parse the json string
try {
return $.parseJSON( $.trim( parts[1] ) );
} catch ( err ) {
return null;
}
} else {
// Return empty model
return { params: {} };
}
};
/**
* Retrieve all existing language codes in the current templatedata model
* @return {string[]} Language codes in use
*/
TemplateDataModel.prototype.getExistingLanguageCodes = function () {
var param, prop, lang,
result = [],
languageProps = this.constructor.static.getPropertiesWithLanguage();
// Take languages from the template description
if ( $.isPlainObject( this.description ) ) {
result.concat( Object.keys( this.description ) );
}
// Go over description
if ( $.type( this.description ) ) {
for ( lang in this.description ) {
result.push( lang );
}
}
// Go over the parameters
for ( param in this.params ) {
// Go over the properties
for ( prop in this.params[param] ) {
if ( $.inArray( prop, languageProps ) !== -1 ) {
result = this.constructor.static.arrayUnionWithoutEmpty( result, Object.keys( this.params[param][prop] ) );
}
}
}
return result;
};
/**
* Retrieve parameters from the template code from source in this order:
*
* 1. Check if there's a template in the given 'wikitext' parameter. If not,
* 2. Check if there's a template in the current page. If not,
* 3. Check if the page is a subpage and go up a level to check for template code. If none found,
* 4. Repeat until we are in the root of the template
* 5. Save the name of the page where the template is taken from
*
* Cache the templateCodePromise so we don't have to do this all over again on each
* template code request.
*
* @param {string} [wikitext] Optional. Source of the template.
* @returns {jQuery.Promise} Promise resolving into template parameter array
*/
TemplateDataModel.prototype.getParametersFromTemplateSource = function ( templateDataString ) {
var params = [];
if ( !this.templateSourceCodePromise ) {
// Check given page text first
if ( templateDataString ) {
params = this.extractParametersFromTemplateCode( templateDataString );
}
if ( params.length > 0 ) {
// Cache list of parameters found in template source
this.sourceCodeParameters = params;
// There are parameters found; Resolve.
this.templateSourceCodePromise = $.Deferred().resolve( params );
} else {
// Try to find the template code
this.templateSourceCodePromise = $.Deferred();
if ( this.isPageSubLevel() && this.getParentPage() ) {
// Get the content of the parent
this.constructor.static.getApi( this.getParentPage() )
.done( $.proxy( function ( resp ) {
var pageContent = '';
// Verify that we have a sane response from the API.
// This is particularly important for unit tests, since the
// requested page from the API is the Qunit module and has no content
if (
resp.query.pages[resp.query.pageids[0]].revisions &&
resp.query.pages[resp.query.pageids[0]].revisions[0]
) {
pageContent = resp.query.pages[resp.query.pageids[0]].revisions[0]['*'];
// Get the parameters from the code
this.sourceCodeParameters = this.extractParametersFromTemplateCode( pageContent );
}
this.templateSourceCodePromise.resolve( this.sourceCodeParameters );
}, this ) )
.fail( $.proxy( function () {
// Resolve an empty parameters array
return this.templateSourceCodePromise.resolve( [] );
}, this ) );
} else {
// No template found. Resolve to empty array of parameters
this.templateSourceCodePromise.resolve( [] );
}
}
}
return this.templateSourceCodePromise;
};
/**
* Retrieve template parameters from the template code.
*
* Adapted from https://he.wikipedia.org/wiki/MediaWiki:Gadget-TemplateParamWizard.js
*
* @param {string} templateSource Source of the template.
* @returns {jQuery.Promise} A promise that resolves into an
* array of parameters that appear in the template code
*/
TemplateDataModel.prototype.extractParametersFromTemplateCode = function ( templateCode ) {
var matches,
paramNames = [],
paramExtractor = /{{3,}(.*?)[<|}]/mg;
while ( ( matches = paramExtractor.exec( templateCode ) ) !== null ) {
if ( $.inArray( matches[1], paramNames ) === -1 ) {
paramNames.push( $.trim( matches[1] ) );
}
}
return paramNames;
};
/**
* Add parameter to the model
* @param {string} key Parameter key
* @param {Object} [data] Parameter data
* @return {boolean} Parameter was added successfully
*/
TemplateDataModel.prototype.addParam = function ( key, paramData ) {
var prop, name, lang,
existingNames = this.getAllParamNames(),
data = $.extend( true, {}, paramData ),
language = this.getDefaultLanguage(),
propertiesWithLanguage = this.constructor.static.getPropertiesWithLanguage();
name = key;
// Check that the parameter is not already in the model
if ( this.params[key] || $.inArray( key, existingNames ) !== -1 ) {
// Change parameter key
key = this.getNewValidParameterKey( key );
}
// Initialize
this.params[key] = {};
// Store the key
this.params[key].name = name;
// Mark the parameter if it is in the template source
if ( $.inArray( key, this.sourceCodeParameters ) !== -1 ) {
this.params[key].inSource = true;
}
// Translate types
if ( this.params[key].type !== undefined ) {
this.params[key].normalizedType = this.constructor.static.translateObsoleteParamTypes( this.params[key].type );
}
// Go over the rest of the data
if ( data ) {
for ( prop in data ) {
if (
$.inArray( prop, propertiesWithLanguage ) !== -1 &&
$.isPlainObject( data[prop] )
) {
// Add all language properties
for ( lang in data[prop] ) {
this.setParamProperty( key, prop, data[prop], lang );
}
} else {
this.setParamProperty( key, prop, data[prop], language );
}
}
}
// Trigger the add parameter event
this.emit( 'add-param', key, this.params[key] );
return true;
};
/**
* Retrieve an array of all used parameter names. Note that parameter
* names can be different than their stored keys.
* @return {string[]} Used parameter names
*/
TemplateDataModel.prototype.getAllParamNames = function () {
var param,
result = [];
for ( param in this.params ) {
result.push( this.params[param].name );
}
return result;
};
/**
* Set the template description
* @param {string} description New template description
* @param {Object} [language] Description language, if supplied. If not given,
* will default to the wiki language.
* @fires change-description
*/
TemplateDataModel.prototype.setTemplateDescription = function ( desc, language ) {
language = language || this.getDefaultLanguage();
if ( !this.constructor.static.compare( this.description[language], desc ) ) {
if ( $.type( desc ) === 'object' ) {
$.extend( this.description, desc );
this.emit( 'change-description', desc[language], language );
} else {
this.description[language] = desc;
this.emit( 'change-description', desc, language );
}
}
};
/**
* Get the template description.
* @param {string} [language] Optional language key
* @return {string|Object} The template description. If it is set
* as multilanguage object and no language is set, the whole object
* will be returned.
*/
TemplateDataModel.prototype.getTemplateDescription = function ( language ) {
language = language || this.getDefaultLanguage();
return this.description[language];
};
/**
* Get a specific parameter's description
* @param {string} paramKey Parameter key
* @param {string} [language] Optional language key
* @return {string} Parameter description in given language.
*/
TemplateDataModel.prototype.getParamDescription = function ( paramKey, language ) {
language = language || this.getDefaultLanguage();
if ( this.params[paramKey] && this.params[paramKey].description ) {
// Return description in this language or fall back
return this.params[paramKey].description[language] || '';
}
return '';
};
/**
* Get the current wiki language code. Defaults on 'en'.
* @return {string} Wiki language
*/
TemplateDataModel.prototype.getDefaultLanguage = function () {
return mw.config.get( 'wgContentLanguage' ) || 'en';
};
/**
* Set template param order array.
* @param {string[]} orderArray Parameter key array in order
*/
TemplateDataModel.prototype.setTemplateParamOrder = function ( orderArray ) {
orderArray = orderArray || [];
// TODO: Make the compare method verify order of array?
// Copy the array
this.paramOrder = orderArray.slice();
this.emit( 'change-paramOrder', orderArray );
};
/**
* Retrieve the template paramOrder array
* @return {string[]} orderArray Parameter keys in order
*/
TemplateDataModel.prototype.getTemplateParamOrder = function () {
return this.paramOrder;
};
/**
* Set a specific parameter's property
* @param {string} paramKey Parameter key
* @param {string} prop Property name
* @param {Mixed...} value Property value
* @param {string} [language] Value language
* @returns {boolean} Operation was successful
* @fires change-property
*/
TemplateDataModel.prototype.setParamProperty = function ( paramKey, prop, value, language ) {
var propertiesWithLanguage = this.constructor.static.getPropertiesWithLanguage(),
allProps = this.constructor.static.getAllProperties( true );
language = language || this.getDefaultLanguage();
if ( !allProps[prop] ) {
// The property isn't supported yet
return false;
}
if ( allProps[prop].type === 'array' && $.type( value ) === 'string' ) {
value = this.constructor.static.splitAndTrimArray( value, allProps[prop].delimiter );
}
// Check if the property is split by language code
if ( $.inArray( prop, propertiesWithLanguage ) !== -1 ) {
// Initialize property if necessary
if ( !$.isPlainObject( this.params[paramKey][prop] ) ) {
this.params[paramKey][prop] = {};
}
value = $.isPlainObject( value ) ? value[language] : value;
// Compare with language
if ( !this.constructor.static.compare( this.params[paramKey][prop][language], value ) ) {
this.params[paramKey][prop][language] = value;
this.emit( 'change-property', paramKey, prop, value, language );
return true;
}
} else {
// Compare without language
if ( !this.constructor.static.compare( this.params[paramKey][prop], value ) ) {
this.params[paramKey][prop] = value;
this.emit( 'change-property', paramKey, prop, value, language );
return true;
}
}
return false;
};
/**
* Mark a parameter for deletion.
* Don't actually delete the parameter so we can make sure it is removed
* from the final output.
* @param {string} paramKey Parameter key
*/
TemplateDataModel.prototype.deleteParam = function ( paramKey ) {
this.params[paramKey].deleted = true;
};
/**
* Get a parameter property.
* @param {string} paramKey Parameter key
* @param {string} prop Parameter property
* @return {Mixed...|null} Property value if it exists. Returns null if the
* parameter key itself doesn't exist.
*/
TemplateDataModel.prototype.getParamProperty = function ( paramKey, prop ) {
if ( this.params[paramKey] ) {
return this.params[paramKey][prop];
}
return null;
};
/**
* Retrieve a specific parameter data
* @param {string} key Parameter key
* @return {Object} Parameter data
*/
TemplateDataModel.prototype.getParamData = function ( key ) {
return this.params[key];
};
/**
* Return the complete object of all parameters.
* @return {Object} All parameters and their data
*/
TemplateDataModel.prototype.getParams = function () {
return this.params;
};
/**
* Set the original templatedata object
* @param {Object} templatedataObj TemplateData object
*/
TemplateDataModel.prototype.setOriginalTemplateDataObject = function ( templatedataObj ) {
this.originalTemplateDataObject = $.extend( true, {}, templatedataObj );
};
/**
* Set is page sublevel
* @param {Boolean} isSubLevel Page is sublevel
*/
TemplateDataModel.prototype.setPageSubLevel = function ( isSubLevel ) {
this.subLevel = isSubLevel;
};
/**
* Get full page name
* @param {string} pageName Page name
*/
TemplateDataModel.prototype.setFullPageName = function ( pageName ) {
this.fullPageName = pageName;
};
/**
* Set parent page
* @param {string} Parent page
*/
TemplateDataModel.prototype.setParentPage = function ( parent ) {
this.parentPage = parent;
};
/**
* Get is page sublevel
* @return {boolean} Page is sublevel
*/
TemplateDataModel.prototype.isPageSubLevel = function () {
return this.subLevel;
};
/**
* Get page full name
* @return {string} Page full name
*/
TemplateDataModel.prototype.getFullPageName = function () {
return this.fullPageName;
};
/**
* Get parent page
* @return {string} Parent page
*/
TemplateDataModel.prototype.getParentPage = function () {
return this.parentPage;
};
/**
* Get original templatedata object
* @return {Object} Templatedata object
*/
TemplateDataModel.prototype.getOriginalTemplateDataObject = function () {
return this.originalTemplateDataObject;
};
/**
* Process the current model and output it as a complete templatedata string
* @return {string} Templatedata String
*/
TemplateDataModel.prototype.outputTemplateDataString = function () {
var param, paramKey, key, prop, oldKey, name, compareOrig, normalizedValue,
allProps = this.constructor.static.getAllProperties( true ),
original = this.getOriginalTemplateDataObject(),
result = $.extend( true, {}, this.getOriginalTemplateDataObject() ),
defaultLang = this.getDefaultLanguage();
// Template description
if ( this.description[defaultLang] !== undefined ) {
normalizedValue = this.propRemoveUnusedLanguages( this.description );
if ( this.isOutputInLanguageObject( result.description, normalizedValue ) ) {
result.description = normalizedValue;
} else {
// Store only one language as a string
result.description = normalizedValue[defaultLang];
}
} else {
// Delete description
delete result.description;
}
// Param order
if ( this.paramOrder.length > 0 ) {
result.paramOrder = this.paramOrder;
} else if ( result.paramOrder && this.paramOrder.length === 0 ) {
delete result.paramOrder;
}
// Attach sets as-is for now
// TODO: Work properly with sets
if ( original.sets ) {
result.sets = original.sets;
}
// Go over parameters in data
for ( paramKey in this.params ) {
key = paramKey;
if ( this.params[key].deleted ) {
delete result.params[key];
continue;
}
// Check if name was changed and change the key accordingly
name = this.params[key].name;
oldKey = key;
if ( key !== this.params[key].name ) {
key = this.params[key].name;
// See if the parameters already has something with this new key
if ( this.params[key] ) {
// Change the key to be something else
key += this.getNewValidParameterKey( key );
}
// Copy param details to new name in the model
this.params[key] = this.params[oldKey];
// Update the references to the key and param data
param = result.params[name];
// Delete the old param in both the result and model param
delete result.params[oldKey];
delete this.params[oldKey];
}
// Notice for clarity:
// Whether the parameter name was changed or not the following
// consistency with object keys will be observed:
// * oldKey: original will use oldKey (for comparison to the old value)
// * key: this.params will use key (for storing without conflict)
// * name: result will use name (for valid output)
// Check if param is new
if ( !result.params[name] ) {
// New param. Initialize it
result.params[name] = {};
}
// Go over all properties
for ( prop in allProps ) {
switch ( prop ) {
case 'name':
continue;
case 'type':
// Only include type if the original included type
// or if the current type is not undefined
if (
original.type !== undefined ||
this.params[key].type !== 'undefined'
) {
result.params[name][prop] = this.params[key].type;
}
break;
case 'required':
case 'suggested':
if ( !this.params[key][prop] ) {
// Only add a literal false value if there was a false
// value before
if ( original.params[oldKey] && original.params[oldKey][prop] === false ) {
result.params[name][prop] = false;
}
} else {
result.params[name][prop] = this.params[key][prop];
}
break;
case 'aliases':
// Only add if there's anything inside the array
if (
$.type( this.params[key][prop] ) === 'array' &&
this.params[key][prop].length > 0
) {
result.params[name][prop] = this.params[key][prop];
}
break;
default:
// Check if there's a value in the model
if ( this.params[key][prop] !== undefined ) {
if ( allProps[prop].allowLanguages ) {
normalizedValue = this.propRemoveUnusedLanguages( this.params[key][prop] );
// Check if this should be displayed with language object or directly as string
compareOrig = original.params[oldKey] ? original.params[oldKey][prop] : {};
if ( this.isOutputInLanguageObject( compareOrig, normalizedValue ) ) {
result.params[name][prop] = normalizedValue;
} else {
// Store only one language as a string
result.params[name][prop] = normalizedValue[defaultLang];
}
} else {
result.params[name][prop] = this.params[key][prop];
}
}
break;
}
}
}
return JSON.stringify( result, null, '\t' );
};
/**
* Check the key if it already exists in the parameter list. If it does,
* find a new key that doesn't, and return it.
* @param {string} key New parameter key
* @return {string} Valid new parameter key
*/
TemplateDataModel.prototype.getNewValidParameterKey = function ( key ) {
var allParamNames = this.getAllParamNames();
if ( this.params[key] || $.inArray( key, allParamNames ) !== -1 ) {
// Change the key to be something else
key += this.paramIdentifierCounter;
this.paramIdentifierCounter++;
this.getNewValidParameterKey( key );
} else {
return key;
}
};
/**
* Go over a language property and remove empty language key values
* @return {Object} Property data with only used language keys
*/
TemplateDataModel.prototype.propRemoveUnusedLanguages = function ( propData ) {
var key,
result = {};
if ( $.isPlainObject( propData ) ) {
for ( key in propData ) {
if ( propData[key] ) {
result[key] = propData[key];
}
}
}
return result;
};
/**
* Check whether the output of the current parameter property should be
* outputted in full language mode (object) or a simple string.
* @param {string} paramKey Parameter key
* @param {string} prop Param property
* @return {boolean} Output should be a full language object
*/
TemplateDataModel.prototype.isOutputInLanguageObject = function ( originalPropValue, newPropValue ) {
if (
(
// The original was already split to languages
$.type( originalPropValue ) === 'object' &&
// Original was not an empty object
!$.isEmptyObject( originalPropValue )
) ||
(
// The new value is split to languages
$.type( newPropValue ) === 'object' &&
// New object is not empty
!$.isEmptyObject( newPropValue ) &&
(
// The new value doesn't have the default language
newPropValue[this.getDefaultLanguage()] === undefined ||
// There is more than just one language in the new property
Object.keys( newPropValue ).length > 1
)
)
) {
return true;
}
return false;
};
}( jQuery ) );