Mooeypoo has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/194991

Change subject: Reorganize api calls and add sourceHandler and error message
......................................................................

Reorganize api calls and add sourceHandler and error message

Add a sourceHandler that deals with all source-related actions
like fetching template source and validating the existing
TemplateData string.

Also add a MessageDialog warning the user in case the TemplateData
is invalid. In this case, the user will be given the option either
to correct the JSON by hand or to start the editor to replace the
existing TemplateData with a new one.

Change-Id: I4e6d04f02565a02d8dcf5c70a575ab6433caa27f
---
M TemplateData.php
M i18n/en.json
M i18n/qqq.json
M modules/ext.templateDataGenerator.data.js
A modules/ext.templateDataGenerator.sourceHandler.js
M modules/ext.templateDataGenerator.ui.js
M modules/ext.templateDataGenerator.ui.tdDialog.js
M tests/ext.templateData.tests.js
8 files changed, 509 insertions(+), 90 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/TemplateData 
refs/changes/91/194991/1

diff --git a/TemplateData.php b/TemplateData.php
index 66cebbc..69d0aa1 100644
--- a/TemplateData.php
+++ b/TemplateData.php
@@ -77,7 +77,8 @@
        'remoteExtPath' => 'TemplateData',
        'scripts' => array(
                'modules/ext.templateDataGenerator.js',
-               'modules/ext.templateDataGenerator.data.js'
+               'modules/ext.templateDataGenerator.data.js',
+               'modules/ext.templateDataGenerator.sourceHandler.js'
        ),
        'dependencies' => array(
                'oojs'
@@ -121,6 +122,7 @@
                'templatedata-modal-errormsg',
                'templatedata-modal-errormsg-import-noparams',
                'templatedata-modal-errormsg-import-paramsalreadyexist',
+               'templatedata-modal-json-error-replace',
                'templatedata-modal-notice-import-numparams',
                'templatedata-modal-placeholder-paramkey',
                'templatedata-modal-search-input-placeholder',
diff --git a/i18n/en.json b/i18n/en.json
index 042cbb3..b92ab6c 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -27,7 +27,7 @@
        "templatedata-doc-param-type": "Type",
        "templatedata-doc-params": "Template parameters",
        "templatedata-editbutton": "Manage TemplateData",
-       "templatedata-errormsg-jsonbadformat": "Bad JSON format. Either correct 
it, or delete the current <templatedata> tags and try again.",
+       "templatedata-errormsg-jsonbadformat": "Bad JSON format. You can cancel 
this operation so you can correct it, or delete the current <templatedata> tags 
and try again, or you can continue to replace the current TemplateData with a 
new one.",
        "templatedata-exists-on-related-page": "Please note: there is already a 
TemplateData block on the related page '[[$1]]'.",
        "templatedata-helplink": "Information about TemplateData",
        "templatedata-helplink-target": 
"//www.mediawiki.org/wiki/Special:MyLanguage/Help:TemplateData",
@@ -54,6 +54,7 @@
        "templatedata-modal-errormsg": "Errors found. Please make sure there 
are no empty or duplicate parameter names, and that the parameter name does not 
include \"$1\", \"$2\" or \"$3\".",
        "templatedata-modal-errormsg-import-noparams": "No new parameters found 
during import.",
        "templatedata-modal-errormsg-import-paramsalreadyexist": "Some 
parameters were not imported, because they already exist in the editor: $1",
+       "templatedata-modal-json-error-replace": "Replace",
        "templatedata-modal-notice-import-numparams": "$1 new 
{{PLURAL:$1|parameter was|parameters were}} imported: $2",
        "templatedata-modal-placeholder-paramkey": "Parameter name",
        "templatedata-modal-search-input-placeholder": "Search by language name 
or code",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 0b75c73..2d5c4d7 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -34,7 +34,7 @@
        "templatedata-doc-param-type": "{{Identical|Type}}",
        "templatedata-doc-params": "Used as caption for the table which has the 
following headings:\n* {{msg-mw|Templatedata-doc-param-name}}\n* 
{{msg-mw|Templatedata-doc-param-desc}}\n* 
{{msg-mw|Templatedata-doc-param-default}}\n* 
{{msg-mw|Templatedata-doc-param-status}}\n{{Identical|Template parameter}}",
        "templatedata-editbutton": "The label of the button to manage 
templatedata, appearing above the editor field.",
-       "templatedata-errormsg-jsonbadformat": "Error message that appears in 
case the JSON string is not possible to parse. The user is asked to either 
correct the json syntax or delete the values between the &lt;templatedata&gt; 
tags and try again.",
+       "templatedata-errormsg-jsonbadformat": "Error message that appears in 
case the JSON string is not possible to parse. The user is asked to choose 
between correcting or deleting the json or continuing with the editing process 
and replacing the string completely.",
        "templatedata-exists-on-related-page": "A messaged that is displayed 
when there already is a templatedata string in a related page. $1: The page 
where templatedata already exists.",
        "templatedata-helplink": "The label of the link to the TemplateData 
documentation, appearing above the editor field.",
        "templatedata-helplink-target": "{{ignore}} The target of the link to 
the TemplateData documentation",
@@ -61,6 +61,7 @@
        "templatedata-modal-errormsg": "Error message that appears in the 
TemplateData generator GUI in case there are empty, duplicate or invalid 
parameter names.\n\nInvalid characters are supplied as parameters to avoid 
parsing errors in translation strings.\n\nParameters:\n* $1 - pipe 
(<code>|</code>)\n* $2 - equal sign (<code>=</code>)\n* $3 - double curly 
brackets (<code><nowiki>}}</nowiki></code>)",
        "templatedata-modal-errormsg-import-noparams": "Error message that 
appears in the TemplateData generator GUI in case no template parameters were 
found during the import attempt.",
        "templatedata-modal-errormsg-import-paramsalreadyexist": "Error message 
that appears when some parameters were not imported from the template code 
because they already exist in the editor.\n\nParameters:\n* $1 - list of 
parameters that were not imported",
+       "templatedata-modal-json-error-replace": "Label for the button in the 
error message, agreeing to replace the existing faulty TemplateData string with 
a new one.",
        "templatedata-modal-notice-import-numparams": "Message that appears in 
the TemplateData generator GUI showing how many new parameters were imported 
into the GUI from an existing template.\n\nParameters:\n* $1 - number of 
parameters. $2 - list of parameters that were imported",
        "templatedata-modal-placeholder-paramkey": "Placeholder for the input 
that contains new parameter name in the add parameter panel in the edit 
dialog.",
        "templatedata-modal-search-input-placeholder": "Placeholder text for 
language search panel.",
diff --git a/modules/ext.templateDataGenerator.data.js 
b/modules/ext.templateDataGenerator.data.js
index 1089f8c..e24eb78 100644
--- a/modules/ext.templateDataGenerator.data.js
+++ b/modules/ext.templateDataGenerator.data.js
@@ -8,9 +8,11 @@
        // Mixin constructors
        OO.EventEmitter.call( this );
 
-       // Config
-       this.setParentPage( config.parentPage );
-       this.setPageSubLevel( config.isPageSubLevel );
+       // // Config
+       // this.setParentPage( config.parentPage );
+       // this.setPageSubLevel( config.isPageSubLevel );
+       // this.setPageSubLevel( !!config.isPageSubLevel );
+       // this.setFullPageName( config.fullPageName || '' );
 
        // Properties
        this.params = {};
@@ -18,12 +20,10 @@
        this.paramOrder = [];
        this.paramOrderChanged = false;
        this.paramIdentifierCounter = 0;
-       this.setPageSubLevel( !!config.isPageSubLevel );
-       this.setFullPageName( config.fullPageName || '' );
 
        this.originalTemplateDataObject = null;
        this.sourceCodeParameters = [];
-       this.templateSourceCodePromise = null;
+//     this.templateSourceCodePromise = null;
 };
 
 /* Setup */
@@ -63,7 +63,7 @@
  * @param {string} page Page name
  * @param {boolean} [getTemplateData] Fetch the templatedata in the page.
  * @return {jQuery.Promise} API promise
- */
+ *
 mw.TemplateData.Model.static.getApi = function ( page, getTemplateData ) {
        var config,
                api = new mw.Api(),
@@ -258,6 +258,40 @@
        } );
 };
 
+/**
+ * Create a new mwTemplateData.Model from templatedata object.
+ *
+ * @param {Object} tdObject TemplateData parsed object
+ * @param {string[]} paramsInSource Parameter names found in template source
+ * @return {mw.TemplateData.Model} New model
+ */
+mw.TemplateData.Model.static.newFromObject = function ( tdObject, 
paramsInSource ) {
+       var param,
+               model = new mw.TemplateData.Model();
+
+       model.setSourceCodeParameters( paramsInSource || [] );
+
+       // Store the original templatedata object for comparison later
+       model.setOriginalTemplateDataObject( tdObject );
+
+       // Initialize the model
+       model.params = {};
+
+       // Add params
+       if ( tdObject.params ) {
+               for ( param in tdObject.params ) {
+                       model.addParam( param, tdObject.params[param] );
+               }
+       }
+       model.setTemplateDescription( tdObject.description );
+       // Override the param order if it exists in the templatedata string
+       if ( tdObject.paramOrder && tdObject.paramOrder.length > 0 ) {
+               model.setTemplateParamOrder( tdObject.paramOrder );
+       }
+
+       return model;
+};
+
 /* Methods */
 
 /**
@@ -268,19 +302,18 @@
  * source code and update existing parameters in the model.
  *
  * @param {string} templateDataString Current page wikitext
- */
+ *
 mw.TemplateData.Model.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 = {};
+       var deferred = $.Deferred(),
+               original = this.getModelFromString( tdString );
 
        if ( original ) {
+               // Store existing templatedata into the model
+               this.setOriginalTemplateDataObject( original );
+
+               // Initialize model
+               this.params = {};
+
                // Get parameter list from the template source code
                this.getParametersFromTemplateSource( tdString ).done( $.proxy( 
function ( params ) {
                        this.sourceCodeParameters = params;
@@ -300,9 +333,13 @@
                        deferred.resolve();
                }, this ) );
        } else {
-               // Bad syntax for JSON
+               // An error occured trying to read an existing templatedata 
string.
+               // If a TempateData string didn't exist, we'd be getting a 
default
+               // object. The only way to get null in the model is if there was
+               // an error trying to parse it.
                deferred.reject();
        }
+
        return deferred.promise();
 };
 
@@ -372,7 +409,7 @@
  * @return {Object|null} The parsed json string. Empty if no
  * templatedata string was found. Null if the json string
  * failed to parse.
- */
+ *
 mw.TemplateData.Model.prototype.getModelFromString = function ( 
templateDataString ) {
        var parts;
 
@@ -442,7 +479,7 @@
  *
  * @param {string} [wikitext] Optional. Source of the template.
  * @returns {jQuery.Promise} Promise resolving into template parameter array
- */
+ *
 mw.TemplateData.Model.prototype.getParametersFromTemplateSource = function ( 
templateDataString ) {
        var params = [];
 
@@ -462,7 +499,7 @@
                        this.templateSourceCodePromise = $.Deferred();
                        if ( this.isPageSubLevel() && this.getParentPage() ) {
                                // Get the content of the parent
-                               this.constructor.static.getApi( 
this.getParentPage() )
+                               mw.TemplateData.System.static.getApi( 
this.getParentPage() )
                                        .done( $.proxy( function ( resp ) {
                                                var pageContent = '';
 
@@ -501,7 +538,7 @@
  * @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
- */
+ *
 mw.TemplateData.Model.prototype.extractParametersFromTemplateCode = function ( 
templateCode ) {
        var matches,
        paramNames = [],
@@ -876,9 +913,17 @@
 /**
  * Set is page sublevel
  * @param {boolean} isSubLevel Page is sublevel
- */
+ *
 mw.TemplateData.Model.prototype.setPageSubLevel = function ( isSubLevel ) {
        this.subLevel = isSubLevel;
+};
+
+/**
+ * Get is page sublevel
+ * @return {boolean} Page is sublevel
+ *
+mw.TemplateData.Model.prototype.isPageSubLevel = function () {
+       return this.subLevel;
 };
 
 /**
@@ -895,14 +940,6 @@
  */
 mw.TemplateData.Model.prototype.setParentPage = function ( parent ) {
        this.parentPage = parent;
-};
-
-/**
- * Get is page sublevel
- * @return {boolean} Page is sublevel
- */
-mw.TemplateData.Model.prototype.isPageSubLevel = function () {
-       return this.subLevel;
 };
 
 /**
@@ -1155,3 +1192,19 @@
        }
        return false;
 };
+
+/**
+ * Set the parameters that are available in the template source code
+ * @param {string[]} sourceParams Parameters available in template source
+ */
+mw.TemplateData.Model.prototype.setSourceCodeParameters = function ( 
sourceParams ) {
+       this.sourceCodeParameters = sourceParams;
+};
+
+/**
+ * Get the parameters that are available in the template source code
+ * @returns {string[]} Parameters available in template source
+ */
+mw.TemplateData.Model.prototype.getSourceCodeParameters = function () {
+       return this.sourceCodeParameters;
+};
diff --git a/modules/ext.templateDataGenerator.sourceHandler.js 
b/modules/ext.templateDataGenerator.sourceHandler.js
new file mode 100644
index 0000000..4340713
--- /dev/null
+++ b/modules/ext.templateDataGenerator.sourceHandler.js
@@ -0,0 +1,274 @@
+/**
+ * TemplateData System
+ *
+ * Loads and validates the templatedata and template parameters
+ * whether in the page itself or from its parent.
+ *
+ * @param {Object} config Configuration object
+ */
+mw.TemplateData.SourceHandler = function mwTemplateDataSourceHander( config ) {
+       config = config || {};
+
+       // Config
+       this.setParentPage( config.parentPage );
+       this.setPageSubLevel( !!config.isPageSubLevel );
+       this.setFullPageName( config.fullPageName || '' );
+
+       this.apiCache = {};
+       this.templateSourceCodePromise = null;
+       this.templateSourceCodeParams = [];
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+};
+
+/* Setup */
+OO.initClass( mw.TemplateData.SourceHandler );
+OO.mixinClass( mw.TemplateData.SourceHandler, OO.EventEmitter );
+
+/**
+ * Get information from the mediaWiki API
+ * @param {string} page Page name
+ * @param {boolean} [getTemplateData] Fetch the templatedata in the page.
+ * @return {jQuery.Promise} API promise
+ */
+mw.TemplateData.SourceHandler.prototype.getApi = function ( page, 
getTemplateData ) {
+       var config,
+               api = new mw.Api(),
+               baseConfig = {
+                       action: getTemplateData ? 'templatedata' : 'query',
+                       titles: page
+               };
+       if ( getTemplateData ) {
+               config = $.extend( baseConfig, {
+                       redirects: '1'
+               } );
+       } else {
+               config = $.extend( baseConfig, {
+                       prop: 'revisions',
+                       rvprop: 'content',
+                       indexpageids: '1'
+               } );
+       }
+
+       // Cache
+       if ( !this.apiCache[page] || !this.apiCache[page][!!getTemplateData] ) {
+               this.apiCache[page] = this.apiCache[page] || {};
+               this.apiCache[page][!!getTemplateData] = api.get( config );
+       }
+       return this.apiCache[page][!!getTemplateData];
+};
+
+/**
+ * Go over the current wikitext and build a new model.
+ *
+ * @param {string} [wikitext] Optional. Source of the template.
+ * @returns {jQuery.Promise} Promise resolving into a new mw.TemplateData.Model
+ *  or is rejected if the model was impossible to create.
+ */
+mw.TemplateData.SourceHandler.prototype.buildModel = function ( wikitext ) {
+       var tdObject,
+               deferred = $.Deferred();
+
+       // Get the TemplateData and parse it
+       tdObject = this.parseModelFromString( wikitext );
+       if ( !tdObject ) {
+               // The json object is invalid. There's no need to continue.
+               deferred.reject();
+       } else {
+               // Get parameters from source code
+               // Mostly used for the import option
+               this.getParametersFromTemplateSource( wikitext )
+                       .then(
+                               // This is always successful by definition
+                               function ( templateSourceCodeParams ) {
+                                       var model = new 
mw.TemplateData.Model.static.newFromObject(
+                                               tdObject,
+                                               templateSourceCodeParams
+                                       );
+                                       deferred.resolve( model );
+                               }
+                       );
+       }
+
+       return deferred;
+};
+
+/**
+ * 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
+ */
+mw.TemplateData.SourceHandler.prototype.getParametersFromTemplateSource = 
function ( wikitext ) {
+       var params = [],
+               system = this;
+
+       if ( !this.templateSourceCodePromise ) {
+               // Check given page text first
+               if ( wikitext ) {
+                       params = this.extractParametersFromTemplateCode( 
wikitext );
+               }
+
+               if ( params.length > 0 ) {
+                       // 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.getApi( this.getParentPage() )
+                                       .done( 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]['*'];
+                                               }
+                                               
system.templateSourceCodePromise.resolve( 
system.extractParametersFromTemplateCode( pageContent ) );
+                                       } )
+                                       .fail( function () {
+                                               // Resolve an empty parameters 
array
+                                               return 
system.templateSourceCodePromise.resolve( [] );
+                                       } );
+                       } 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
+ */
+mw.TemplateData.SourceHandler.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;
+};
+
+/**
+ * Look for a templatedata json string and convert it into
+ * the 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.
+ */
+mw.TemplateData.SourceHandler.prototype.parseModelFromString = 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: {} };
+       }
+};
+
+/**
+ * Set is page sublevel
+ * @param {boolean} isSubLevel Page is sublevel
+ */
+mw.TemplateData.SourceHandler.prototype.setPageSubLevel = function ( 
isSubLevel ) {
+       this.subLevel = isSubLevel;
+};
+
+/**
+ * Get is page sublevel
+ * @return {boolean} Page is sublevel
+ */
+mw.TemplateData.SourceHandler.prototype.isPageSubLevel = function () {
+       return this.subLevel;
+};
+
+/**
+ * Get full page name
+ * @param {string} pageName Page name
+ */
+mw.TemplateData.SourceHandler.prototype.setFullPageName = function ( pageName 
) {
+       this.fullPageName = pageName;
+};
+
+/**
+ * Get page full name
+ * @return {string} Page full name
+ */
+mw.TemplateData.SourceHandler.prototype.getFullPageName = function () {
+       return this.fullPageName;
+};
+
+/**
+ * Set parent page
+ * @param {string} Parent page
+ */
+mw.TemplateData.SourceHandler.prototype.setParentPage = function ( parent ) {
+       this.parentPage = parent;
+};
+
+/**
+ * Get parent page
+ * @return {string} Parent page
+ */
+mw.TemplateData.SourceHandler.prototype.getParentPage = function () {
+       return this.parentPage;
+};
+
+/**
+ * Set template source code parameters
+ * @param {string[]} params Parameters from the template source code
+ */
+mw.TemplateData.SourceHandler.prototype.setTemplateSourceCodeParams = function 
( params ) {
+       this.templateSourceCodeParams = params;
+};
+
+/**
+ * Set template source code parameters
+ * @returns {string[]} Parameters from the template source code
+ */
+mw.TemplateData.SourceHandler.prototype.getTemplateSourceCodeParams = function 
() {
+       return this.templateSourceCodeParams;
+};
diff --git a/modules/ext.templateDataGenerator.ui.js 
b/modules/ext.templateDataGenerator.ui.js
index 285f5c5..3d55b59 100644
--- a/modules/ext.templateDataGenerator.ui.js
+++ b/modules/ext.templateDataGenerator.ui.js
@@ -14,10 +14,12 @@
                        pageName,
                        parentPage,
                        $textbox,
+                       sourceHandler,
                        /**
                         * ooui Window Manager
                         */
                        tdgDialog,
+                       messageDialog,
                        windowManager,
                        /**
                         * Edit window elements
@@ -61,13 +63,62 @@
                onEditOpenDialogButton = function () {
                        // Reset notice message
                        editArea.resetNoticeMessage();
-                       // Open the dialog
+
+                       // Build the model
+                       sourceHandler.buildModel( $textbox.val() )
+                               .then(
+                                       // Success
+                                       function ( model ) {
+                                               openEditDialog( model );
+                                       },
+                                       // Failure
+                                       function () {
+                                               // Open a message dialog
+                                               windowManager.openWindow( 
messageDialog, {
+                                                       title: mw.msg( 
'templatedata-modal-title' ),
+                                                       message: mw.msg( 
'templatedata-errormsg-jsonbadformat' ),
+                                                       actions: [
+                                                               {
+                                                                       action: 
'accept',
+                                                                       label: 
mw.msg( 'templatedata-modal-json-error-replace' ),
+                                                                       flags: 
[ 'primary', 'destructive' ]
+                                                               },
+                                                               {
+                                                                       action: 
'reject',
+                                                                       label: 
OO.ui.deferMsg( 'ooui-dialog-message-reject' ),
+                                                                       flags: 
'safe'
+                                                               }
+                                                       ]
+                                               } )
+                                                       .then( function ( 
opening ) {
+                                                               opening.then( 
function ( opened ) {
+                                                                       
opened.then( function ( data) {
+                                                                               
var model;
+                                                                               
if ( data && data.action === 'accept' ) {
+                                                                               
        // Open the dialog with an empty model
+                                                                               
        model = new mw.TemplateData.Model.static.newFromObject(
+                                                                               
                { params: {} },
+                                                                               
                sourceHandler.getTemplateSourceCodeParams()
+                                                                               
        );
+                                                                               
        openEditDialog( model );
+                                                                               
}
+                                                                       } );
+                                                               } );
+
+                                                       } );
+                                       }
+                               );
+               },
+
+               /**
+                * Open the templatedata edit dialog
+                * @param {mw.TemplateData.Model} dataModel The data model
+                * associated with this edit dialog.
+                */
+               openEditDialog = function ( dataModel ) {
+                       // Open the edit dialog
                        windowManager.openWindow( tdgDialog, {
-                               wikitext: $textbox.val(),
-                               config: {
-                                       parentPage: parentPage,
-                                       isPageSubLevel: !!isPageSubLevel
-                               }
+                               model: dataModel
                        } );
                },
 
@@ -153,12 +204,15 @@
                                // Dialog
                                windowManager = new OO.ui.WindowManager();
                                tdgDialog = new mw.TemplateData.Dialog( config 
);
-                               windowManager.addWindows( [ tdgDialog ] );
+                               messageDialog = new OO.ui.MessageDialog();
+                               windowManager.addWindows( [ tdgDialog, 
messageDialog ] );
+
+                               sourceHandler = new 
mw.TemplateData.SourceHandler();
 
                                // Check if there's already a templatedata in a 
related page
                                relatedPage = isDocPage ? parentPage : pageName 
+ '/doc';
                                editOpenDialogButton.setDisabled( true );
-                               mw.TemplateData.Model.static.getApi( 
relatedPage )
+                               sourceHandler.getApi( relatedPage )
                                        .then( function ( result ) {
                                                var msg, matches, content,
                                                        response = 
result.query.pages[ result.query.pageids[0] ];
diff --git a/modules/ext.templateDataGenerator.ui.tdDialog.js 
b/modules/ext.templateDataGenerator.ui.tdDialog.js
index c752ad6..a66ed27 100644
--- a/modules/ext.templateDataGenerator.ui.tdDialog.js
+++ b/modules/ext.templateDataGenerator.ui.tdDialog.js
@@ -768,7 +768,13 @@
 mw.TemplateData.Dialog.prototype.getSetupProcess = function ( data ) {
        return mw.TemplateData.Dialog.super.prototype.getSetupProcess.call( 
this, data )
                .next( function () {
+                       var i, language, languages,
+                               languageItems = [];
+
+                       data = data || {};
+
                        this.reset();
+
                        // Hide the panels and display a spinner
                        this.$spinner.show();
                        this.panels.$element.hide();
@@ -777,7 +783,8 @@
 
                        // Start with parameter list
                        this.switchPanels( 'listParams' );
-                       this.model = new mw.TemplateData.Model( data.config );
+
+                       this.model = data.model;
 
                        // Events
                        this.model.connect( this, {
@@ -787,54 +794,42 @@
                                'add-paramOrder': 'onModelAddKeyParamOrder'
                        } );
 
-                       // Load the model according to the string
-                       this.model.loadModel( data.wikitext )
-                               .done( $.proxy( function () {
-                                       var i,
-                                               language = 
this.model.getDefaultLanguage(),
-                                               languageItems = [],
-                                               languages = 
this.model.getExistingLanguageCodes();
+                       // Setup the dialog
+                       this.setupDetailsFromModel();
 
-                                       this.setupDetailsFromModel();
+                       languageItems = [];
+                       language = this.model.getDefaultLanguage();
+                       languages = this.model.getExistingLanguageCodes();
 
-                                       // Fill up the language selection
-                                       if (
-                                               languages.length === 0 ||
-                                               $.inArray( language, languages 
) === -1
-                                       ) {
-                                               // Add the default language
-                                               languageItems.push( new 
OO.ui.OptionWidget( {
-                                                       data: language,
-                                                       $: this.$,
-                                                       label: 
$.uls.data.getAutonym( language )
-                                               } ) );
-                                               this.availableLanguages.push( 
language );
-                                       }
+                       // Fill up the language selection
+                       if (
+                               languages.length === 0 ||
+                               $.inArray( language, languages ) === -1
+                       ) {
+                               // Add the default language
+                               languageItems.push( new OO.ui.OptionWidget( {
+                                       data: language,
+                                       label: $.uls.data.getAutonym( language )
+                               } ) );
+                               this.availableLanguages.push( language );
+                       }
 
-                                       // Add all available languages
-                                       for ( i = 0; i < languages.length; i++ 
) {
-                                               languageItems.push( new 
OO.ui.OptionWidget( {
-                                                       data: languages[i],
-                                                       $: this.$,
-                                                       label: 
$.uls.data.getAutonym( languages[i] )
-                                               } ) );
-                                               // Store available languages
-                                               this.availableLanguages.push( 
languages[i] );
-                                       }
-                                       
this.languageDropdownWidget.getMenu().addItems( languageItems );
-                                       // Trigger the initial language choice
-                                       
this.languageDropdownWidget.getMenu().chooseItem( 
this.languageDropdownWidget.getMenu().getItemFromData( language ) );
+                       // Add all available languages
+                       for ( i = 0; i < languages.length; i++ ) {
+                               languageItems.push( new OO.ui.OptionWidget( {
+                                       data: languages[i],
+                                       label: $.uls.data.getAutonym( 
languages[i] )
+                               } ) );
+                               // Store available languages
+                               this.availableLanguages.push( languages[i] );
+                       }
+                       this.languageDropdownWidget.getMenu().addItems( 
languageItems );
+                       // Trigger the initial language choice
+                       this.languageDropdownWidget.getMenu().chooseItem( 
this.languageDropdownWidget.getMenu().getItemFromData( language ) );
 
-                                       // Show the panel
-                                       this.$spinner.hide();
-                                       this.panels.$element.show();
-                               }, this ) )
-                               .fail( $.proxy( function () {
-                                       // Show error
-                                       this.actions.setMode( 'error' );
-                                       this.$spinner.hide();
-                                       this.toggleNoticeMessage( 'global', 
true, 'error', mw.msg( 'templatedata-errormsg-jsonbadformat' ) );
-                               }, this ) );
+                       // Show the panel
+                       this.$spinner.hide();
+                       this.panels.$element.show();
 
                }, this );
 };
diff --git a/tests/ext.templateData.tests.js b/tests/ext.templateData.tests.js
index 88be3ee..341757a 100644
--- a/tests/ext.templateData.tests.js
+++ b/tests/ext.templateData.tests.js
@@ -12,7 +12,6 @@
                resultDescMockLang = {},
                resultDescBothLang = {},
                currLanguage = mw.config.get( 'wgContentLanguage' ) || 'en',
-               model = new mw.TemplateData.Model(),
                originalWikitext = 'Some text here that is not templatedata 
information.' +
                        '<templatedata>' +
                        '{' +
@@ -409,6 +408,7 @@
        // Test model load
        QUnit.asyncTest( 'TemplateData model', function ( assert ) {
                var i,
+                       sourceHandler = new mw.TemplateData.SourceHandler(),
                        paramAddTest = [
                                {
                                        key: 'newParam1',
@@ -506,8 +506,8 @@
                        2
                );
 
-               model.loadModel( originalWikitext )
-                       .done( function () {
+               sourceHandler.buildModel( originalWikitext )
+                       .done( function ( model ) {
 
                                // Check description
                                assert.equal(
@@ -583,4 +583,43 @@
                        } );
        } );
 
+       // Test model fail
+       QUnit.asyncTest( 'TemplateData sourceHandler', function ( assert ) {
+               var sourceHandler = new mw.TemplateData.SourceHandler(),
+                       deferred = $.Deferred(),
+                       erronousString = '<templatedata>{\n' +
+                               '       "params": {\n' +
+                               // Open quote
+                               '               "user: {\n' +
+                               '                       "label": "Username",\n' 
+
+                               '                       "type": 
"wiki-user-name",\n' +
+                               '                       "required": true,\n' +
+                               '                       "description": "User 
name of person who forgot to sign their comment.",\n' +
+                               '                       "aliases": [\n' +
+                               '                               "1"\n' +
+                               '                       ]\n' +
+                               '               },\n' +
+                               '               "date": {\n' +
+                               '                       "label": "Date",\n' +
+                               '                       "description": {\n' +
+                               // Forgotten quotes
+                               '                               en: "Timestamp 
of when the comment was posted, in YYYY-MM-DD format."\n' +
+                               '                       }\n' +
+                               '                       "suggested": true\n' +
+                               '               }\n' +
+                               '       }\n' +
+                               '}</templatedata>';
+
+               QUnit.expect( 1 );
+
+               sourceHandler.buildModel( erronousString )
+                       .then( deferred.resolve.bind( deferred, false ), 
deferred.resolve.bind( deferred, true ) )
+                       .then( function ( result ) {
+                               assert.ok( result, 'Promise rejected on 
erronous json string.' );
+                       } )
+                       .always( function () {
+                               QUnit.start();
+                       } );
+       } );
+
 }() );

-- 
To view, visit https://gerrit.wikimedia.org/r/194991
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I4e6d04f02565a02d8dcf5c70a575ab6433caa27f
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/TemplateData
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to