From c4ca729ed5fcfd0ce8402d835576c117ca8dc371 Mon Sep 17 00:00:00 2001 From: adham-khatean Date: Sun, 12 Jul 2020 13:47:41 +0200 Subject: [PATCH] Make the maps object editable from the TemplateData dialog - Enable multiline. - Enable updating the model with user changes if user clicks "Done". - Disable "Done" button if the user inserts invalid JSON to handle JSON errors the user might cause, and "Done" is enabled again if the JSON is valid. - Create "cancel" button/action which will be for maps panel only, to discard all changes made by the user. Bug: T257503 Change-Id: Icd495290bae0b1684f8cd53864904a35e60fffe7 --- i18n/en.json | 2 +- i18n/qqq.json | 2 +- .../ext.templateDataGenerator.data/Model.js | 38 +++++++++++--- .../Dialog.js | 52 +++++++++++++++---- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/i18n/en.json b/i18n/en.json index 06efe3c6..9f424616 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -64,7 +64,7 @@ "templatedata-modal-button-changelang": "Change language", "templatedata-modal-button-delparam": "Remove parameter information", "templatedata-modal-button-done": "Done", - "templatedata-modal-button-map": "View map", + "templatedata-modal-button-map": "Edit maps", "templatedata-modal-button-importParams": "Import parameters", "templatedata-modal-button-restoreparam": "Restore parameter", "templatedata-modal-button-saveparam": "Save", diff --git a/i18n/qqq.json b/i18n/qqq.json index 3af20edb..fd6de958 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -75,7 +75,7 @@ "templatedata-modal-button-changelang": "Label for the button to change language in the edit dialog.\n{{Identical|Change language}}", "templatedata-modal-button-delparam": "Button to remove a parameter.", "templatedata-modal-button-done": "Label of the done button.\n{{Identical|Done}}", - "templatedata-modal-button-map": "Label of the view map button", + "templatedata-modal-button-map": "Label of the Edit maps button", "templatedata-modal-button-importParams": "Label of the import button", "templatedata-modal-button-restoreparam": "Label for the button to restore a previously deleted parameter in the edit dialog.", "templatedata-modal-button-saveparam": "Label for the button to save parameter details in the templatedata edit dialog.\n{{Identical|Save}}", diff --git a/modules/ext.templateDataGenerator.data/Model.js b/modules/ext.templateDataGenerator.data/Model.js index c409ad89..dd534306 100644 --- a/modules/ext.templateDataGenerator.data/Model.js +++ b/modules/ext.templateDataGenerator.data/Model.js @@ -13,6 +13,7 @@ mw.TemplateData.Model = function mwTemplateDataModel() { // Properties this.params = {}; this.description = {}; + this.originalMaps = {}; this.maps = {}; this.paramOrder = []; this.format = null; @@ -20,6 +21,7 @@ mw.TemplateData.Model = function mwTemplateDataModel() { this.paramIdentifierCounter = 0; this.originalTemplateDataObject = null; this.sourceCodeParameters = []; + this.mapsChanged = false; }; /* Inheritance */ @@ -271,7 +273,7 @@ mw.TemplateData.Model.static.newFromObject = function ( tdObject, paramsInSource } // maps - model.setMapInfo( JSON.stringify( tdObject.maps, null, 4 ) ); + model.setMapInfo( tdObject.maps ); model.setTemplateDescription( tdObject.description ); @@ -537,13 +539,12 @@ mw.TemplateData.Model.prototype.getTemplateDescription = function ( language ) { */ mw.TemplateData.Model.prototype.setMapInfo = function ( map ) { if ( !this.constructor.static.compare( this.maps, map ) ) { - if ( typeof map === 'object' ) { - $.extend( this.maps, map ); - this.emit( 'change-map', map ); - } else { - this.maps = map; - this.emit( 'change-map', map ); + if ( this.mapsChanged === false ) { + this.originalMaps = map; + this.mapsChanged = true; } + this.maps = map; + this.emit( 'change-map', map ); this.emit( 'change' ); } }; @@ -557,6 +558,15 @@ mw.TemplateData.Model.prototype.getMapInfo = function () { return this.maps; }; +/** + * Get the template info. + * + * @return {Object} The Original template map info. + */ +mw.TemplateData.Model.prototype.getOriginalMapsInfo = function () { + return this.originalMaps; +}; + /** * Get a specific parameter's localized property * @@ -905,6 +915,13 @@ mw.TemplateData.Model.prototype.getParentPage = function () { return this.parentPage; }; +/** + * Get original Parameters/Info from the model and discard any changes + */ +mw.TemplateData.Model.prototype.restoreOriginalMaps = function () { + this.setMapInfo( this.getOriginalMapsInfo() ); +}; + /** * Get original templatedata object * @@ -940,6 +957,13 @@ mw.TemplateData.Model.prototype.outputTemplateData = function () { delete result.description; } + // Template maps + if ( this.maps !== undefined ) { + result.maps = this.maps; + } else { + delete result.maps; + } + // Param order if ( original.paramOrder || this.paramOrderChanged ) { result.paramOrder = this.paramOrder; diff --git a/modules/ext.templateDataGenerator.editTemplatePage/Dialog.js b/modules/ext.templateDataGenerator.editTemplatePage/Dialog.js index a5b61aea..b2d43c92 100644 --- a/modules/ext.templateDataGenerator.editTemplatePage/Dialog.js +++ b/modules/ext.templateDataGenerator.editTemplatePage/Dialog.js @@ -57,6 +57,12 @@ mw.TemplateData.Dialog.static.actions = [ modes: 'edit', flags: 'destructive' }, + { + action: 'cancel', + label: mw.msg( 'templatedata-modal-button-cancel' ), + modes: 'maps', + flags: 'destructive' + }, { label: mw.msg( 'templatedata-modal-button-cancel' ), flags: [ 'safe', 'close' ], @@ -66,7 +72,7 @@ mw.TemplateData.Dialog.static.actions = [ action: 'back', label: mw.msg( 'templatedata-modal-button-back' ), flags: [ 'safe', 'back' ], - modes: [ 'language', 'add', 'maps' ] + modes: [ 'language', 'add' ] } ]; @@ -123,7 +129,6 @@ mw.TemplateData.Dialog.prototype.initialize = function () { this.templateMapsInput = new OO.ui.MultilineTextInputWidget( { classes: [ 'mw-tempateData-template-maps-input' ], autosize: true, - disabled: true, rows: 5, maxRows: 200, placeholder: mw.msg( 'templatedata-modal-placeholder-mapinfo' ) @@ -311,7 +316,7 @@ mw.TemplateData.Dialog.prototype.onModelChangeDescription = function ( descripti * @param {string} map New description */ mw.TemplateData.Dialog.prototype.onModelChangeMapInfo = function ( map ) { - this.templateMapsInput.setValue( map ); + this.templateMapsInput.setValue( JSON.stringify( map, null, 4 ) ); }; /** @@ -403,8 +408,18 @@ mw.TemplateData.Dialog.prototype.onDescriptionInputChange = function ( value ) { * @param {string} value map info value */ mw.TemplateData.Dialog.prototype.onMapInfoChange = function ( value ) { + // Update map Info if ( this.model.getMapInfo() !== value ) { - this.model.setMapInfo( value ); + // Disable Done button in case of invalid JSON + try { + // This parsing method keeps only the last key/value pair if duplicate keys are defined, and does not throw an error. + // Our model will be updated with a valid maps object, but the user may lose their input if it has duplicate key. + this.mapValue = JSON.parse( value ); + this.actions.setAbilities( { done: true } ); + } catch ( err ) { + // Otherwise disable the done button + this.actions.setAbilities( { done: false } ); + } } }; @@ -1047,8 +1062,8 @@ mw.TemplateData.Dialog.prototype.getSetupProcess = function ( data ) { // Events this.model.connect( this, { 'change-description': 'onModelChangeDescription', - 'change-paramOrder': 'onModelChangeParamOrder', 'change-map': 'onModelChangeMapInfo', + 'change-paramOrder': 'onModelChangeParamOrder', 'change-property': 'onModelChangeProperty', change: 'onModelChange' } ); @@ -1112,7 +1127,7 @@ mw.TemplateData.Dialog.prototype.setupDetailsFromModel = function () { this.descriptionInput.setValue( this.model.getTemplateDescription( this.language ) ); // set up maps - this.templateMapsInput.setValue( this.model.getMapInfo() ); + this.templateMapsInput.setValue( JSON.stringify( this.model.getMapInfo(), null, 4 ) ); // Set up format format = this.model.getTemplateFormat(); @@ -1208,21 +1223,36 @@ mw.TemplateData.Dialog.prototype.switchPanels = function ( panel ) { * @return {OO.ui.Process} Action process */ mw.TemplateData.Dialog.prototype.getActionProcess = function ( action ) { - if ( action === 'back' || action === 'done' ) { - return new OO.ui.Process( function () { - this.switchPanels( 'listParams' ); - }, this ); - } if ( action === 'add' ) { return new OO.ui.Process( function () { this.switchPanels( 'addParam' ); }, this ); } + if ( action === 'done' ) { + return new OO.ui.Process( function () { + // setMapInfo with the value and keep the done button active + this.model.setMapInfo( this.mapValue ); + this.model.originalMaps = this.mapValue; + this.switchPanels( 'listParams' ); + }, this ); + } + if ( action === 'back' ) { + return new OO.ui.Process( function () { + this.switchPanels( 'listParams' ); + }, this ); + } if ( action === 'maps' ) { return new OO.ui.Process( function () { this.switchPanels( 'editMaps' ); }, this ); } + if ( action === 'cancel' ) { + return new OO.ui.Process( function () { + this.templateMapsInput.setValue( JSON.stringify( this.model.originalMaps, null, 4 ) ); + this.model.restoreOriginalMaps(); + this.switchPanels( 'listParams' ); + }, this ); + } if ( action === 'delete' ) { return new OO.ui.Process( function () { this.model.deleteParam( this.selectedParamKey );