Abstract out editor manipulation form UI

Create target classes with get/setWikitext methods.

Also refactor some of the window manager code.

Bug: T152230
Change-Id: I7dcc137d79e029b69467ca282d8c52683e022598
This commit is contained in:
Ed Sanders 2016-12-03 16:18:51 +00:00
parent 6565ee4cf5
commit a586d54e93
4 changed files with 144 additions and 68 deletions

View file

@ -73,6 +73,7 @@
"ext.templateDataGenerator.ui": {
"styles": "modules/ext.templateDataGenerator.ui.css",
"scripts": [
"modules/ext.templateDataGenerator.target.js",
"modules/ext.templateDataGenerator.ui.js",
"modules/widgets/ext.templateDataGenerator.paramSelectWidget.js",
"modules/widgets/ext.templateDataGenerator.paramWidget.js",
@ -165,6 +166,9 @@
"localBasePath": "",
"remoteExtPath": "TemplateData"
},
"VisualEditorPluginModules": [
"ext.templateDataGenerator.editPage"
],
"config": {
"TemplateDataUseGUI": true
},

View file

@ -8,7 +8,7 @@
'use strict';
$( function () {
var pieces, isDocPage,
var pieces, isDocPage, target,
pageName = mw.config.get( 'wgPageName' ),
config = {
pageName: pageName,
@ -16,26 +16,34 @@
},
$textbox = $( '#wpTextbox1' );
// Check if there's an editor textarea and if we're in the proper namespace
if ( $textbox.length && mw.config.get( 'wgCanonicalNamespace' ) === 'Template' ) {
pieces = pageName.split( '/' );
isDocPage = pieces.length > 1 && pieces[ pieces.length - 1 ] === 'doc';
// Check if we're in the proper namespace
if ( mw.config.get( 'wgCanonicalNamespace' ) !== 'Template' ) {
return;
}
config = {
pageName: pageName,
isPageSubLevel: pieces.length > 1,
parentPage: pageName,
isDocPage: isDocPage
};
pieces = pageName.split( '/' );
isDocPage = pieces.length > 1 && pieces[ pieces.length - 1 ] === 'doc';
// Only if we are in a doc page do we set the parent page to
// the one above. Otherwise, all parent pages are current pages
if ( isDocPage ) {
pieces.pop();
config.parentPage = pieces.join( '/' );
}
config = {
pageName: pageName,
isPageSubLevel: pieces.length > 1,
parentPage: pageName,
isDocPage: isDocPage
};
// Only if we are in a doc page do we set the parent page to
// the one above. Otherwise, all parent pages are current pages
if ( isDocPage ) {
pieces.pop();
config.parentPage = pieces.join( '/' );
}
// Textbox wikitext editor
if ( $textbox.length ) {
// Prepare the editor
mw.libs.tdgUi.init( $( '#mw-content-text' ), $textbox, config );
target = new mw.TemplateData.TextareaTarget( $textbox ),
mw.libs.tdgUi.init( target, config );
$( '#mw-content-text' ).prepend( target.$element );
}
} );

View file

@ -0,0 +1,74 @@
/**
* Template data edit ui target
*
* @class
* @abstract
* @extends OO.ui.Element
* @mixin OO.EventEmitter
*
* @constructor
*/
mw.TemplateData.Target = function mwTemplateDataTarget() {
// Parent constructor
mw.TemplateData.Target.super.apply( this, arguments );
// Mixin constructor
OO.EventEmitter.call( this );
this.$element.addClass( 'tdg-editscreen-main' );
// TODO: Move more init code into this class
};
/* Inheritance */
OO.inheritClass( mw.TemplateData.Target, OO.ui.Element );
OO.mixinClass( mw.TemplateData.Target, OO.EventEmitter );
/* Methods */
/**
* Get wikitext from the editor
*
* @method
* @abstract
* @return {string} Wikitext
*/
mw.TemplateData.Target.prototype.getWikitext = null;
/**
* Write wikitext back to the target
*
* @method
* @abstract
* @param {string} newWikitext New wikitext
*/
mw.TemplateData.Target.prototype.setWikitext = null;
/**
* Textarea target
*
* @class
* @extends mw.TemplateData.Target
*
* @constructor
* @param {jQuery} $textarea Editor textarea
*/
mw.TemplateData.TextareaTarget = function mwTemplateDataTextareaTarget( $textarea ) {
// Parent constructor
mw.TemplateData.TextareaTarget.super.call( this );
this.$textarea = $textarea;
};
/* Inheritance */
OO.inheritClass( mw.TemplateData.TextareaTarget, mw.TemplateData.Target );
mw.TemplateData.TextareaTarget.prototype.getWikitext = function () {
return this.$textarea.val();
};
mw.TemplateData.TextareaTarget.prototype.setWikitext = function ( newWikitext ) {
this.$textarea.val( newWikitext );
};

View file

@ -1,5 +1,6 @@
( function () {
'use strict';
/**
* TemplateData Generator data model.
* This singleton is independent of any UI; it expects
@ -14,17 +15,17 @@
isDocPage,
pageName,
parentPage,
$textbox,
target,
originalWikitext,
// ooui Window Manager
sourceHandler,
tdgDialog,
messageDialog,
windowManager,
// Edit window elements
editOpenDialogButton,
editNoticeLabel,
editArea, openEditDialog, onEditOpenDialogButton,
replaceTemplateData, onDialogApply;
replaceTemplateData, onDialogApply,
windowManager = OO.ui.getWindowManager();
editArea = {
/**
@ -82,8 +83,10 @@
// Reset notice message
editArea.resetNoticeMessage();
originalWikitext = target.getWikitext();
// Build the model
sourceHandler.buildModel( $textbox.val() )
sourceHandler.buildModel( originalWikitext )
.then(
// Success
function ( model ) {
@ -92,9 +95,10 @@
// Failure
function () {
// Open a message dialog
windowManager.openWindow( messageDialog, {
windowManager.openWindow( 'messageDialog', {
title: mw.msg( 'templatedata-modal-title' ),
message: mw.msg( 'templatedata-errormsg-jsonbadformat' ),
verbose: true,
actions: [
{
action: 'accept',
@ -107,24 +111,21 @@
flags: 'safe'
}
]
} )
.then( function ( opening ) {
return opening;
} )
.then( function ( opened ) {
return opened;
} )
.then( function ( data ) {
var model;
if ( data && data.action === 'accept' ) {
// Open the dialog with an empty model
model = mw.TemplateData.Model.static.newFromObject(
{ params: {} },
sourceHandler.getTemplateSourceCodeParams()
);
openEditDialog( model );
}
} ).then( function ( opened ) {
return opened.then( function ( closing ) {
return closing.then( function ( data ) {
var model;
if ( data && data.action === 'accept' ) {
// Open the dialog with an empty model
model = mw.TemplateData.Model.static.newFromObject(
{ params: {} },
sourceHandler.getTemplateSourceCodeParams()
);
openEditDialog( model );
}
} );
} );
} );
}
);
},
@ -140,20 +141,19 @@
*/
replaceTemplateData = function ( newTemplateData ) {
var finalOutput,
fullWikitext = $textbox.val(),
endNoIncludeLength = '</noinclude>'.length,
// NB: This pattern contains no matching groups: (). This avoids
// corruption if the template data JSON contains $1 etc.
templatedataPattern = /<templatedata>[\s\S]*?<\/templatedata>/i;
if ( fullWikitext.match( templatedataPattern ) ) {
if ( originalWikitext.match( templatedataPattern ) ) {
// <templatedata> exists. Replace it
finalOutput = fullWikitext.replace(
finalOutput = originalWikitext.replace(
templatedataPattern,
'<templatedata>\n' + JSON.stringify( newTemplateData, null, '\t' ) + '\n</templatedata>'
);
} else {
finalOutput = fullWikitext;
finalOutput = originalWikitext;
if ( finalOutput.substr( -1 ) !== '\n' ) {
finalOutput += '\n';
}
@ -186,10 +186,10 @@
Object.keys( templateData ).length > 1 ||
Object.keys( templateData.params ).length > 0
) {
$textbox.val( replaceTemplateData( templateData ) );
target.setWikitext( replaceTemplateData( templateData ) );
} else {
windowManager.closeWindow( windowManager.getCurrentWindow() );
windowManager.openWindow( messageDialog, {
windowManager.openWindow( 'messageDialog', {
title: mw.msg( 'templatedata-modal-title' ),
message: mw.msg( 'templatedata-errormsg-insertblank' ),
actions: [
@ -207,7 +207,7 @@
.then( function ( opened ) { return opened; } )
.then( function ( data ) {
if ( data && data.action === 'apply' ) {
$textbox.val( replaceTemplateData( templateData ) );
target.setWikitext( replaceTemplateData( templateData ) );
}
} );
}
@ -217,15 +217,14 @@
/**
* Initialize UI
*
* @param {jQuery} $container The container to attach UI buttons to
* @param {jQuery} $editorTextbox The editor textbox to take the
* current wikitext from.
* @param {mw.TemplateData.Target} target Edit UI target
* @param {Object} userConfig Config options
*/
init: function ( $container, $editorTextbox, userConfig ) {
init: function ( editTarget, userConfig ) {
var $helpLink, relatedPage,
config = userConfig;
$textbox = $editorTextbox;
target = editTarget;
pageName = config.pageName;
parentPage = config.parentPage;
@ -250,10 +249,8 @@
.text( mw.msg( 'templatedata-helplink' ) );
// Dialog
windowManager = new OO.ui.WindowManager();
tdgDialog = new mw.TemplateData.Dialog( config );
messageDialog = new OO.ui.MessageDialog();
windowManager.addWindows( [ tdgDialog, messageDialog ] );
windowManager.addWindows( [ tdgDialog ] );
sourceHandler = new mw.TemplateData.SourceHandler( {
fullPageName: pageName,
@ -292,19 +289,12 @@
}
} );
// Prepend to container
$container
.prepend(
$( '<div>' )
.addClass( 'tdg-editscreen-main' )
.append(
editOpenDialogButton.$element,
$helpLink,
editNoticeLabel.$element
)
target.$element
.append(
editOpenDialogButton.$element,
$helpLink,
editNoticeLabel.$element
);
$( 'body' )
.append( windowManager.$element );
// UI events
editOpenDialogButton.connect( this, { click: onEditOpenDialogButton } );