From 43c2865f90d74da269250f475ab03fd767b6c4cd Mon Sep 17 00:00:00 2001 From: Thalia Date: Sat, 14 Jan 2017 15:03:36 -0800 Subject: [PATCH] Update actions on live inspectors and preview dialogs Make inspectors inheriting from MWLiveExtensionInspector and dialogs inheriting from MWExtensionPreviewDialog update their 'done' action every time updatePreview is called. Since both mix in ExtensionWindow, two new methods, updateActions and isModified are added there. This should make it more difficult to insert an empty node accidentally or create a transaction just by opening and closing an inspector or dialog. For more complicated dialogs, or inspectors or dialogs that don't live-update, this behaviour will have to be implemented separately. Bug: T155330 Change-Id: Iacafa01fcd419faaec9b112c96be86693a57d561 --- .../dialogs/ve.ui.MWExtensionPreviewDialog.js | 13 ++++++- .../ve.ui.MWLiveExtensionInspector.js | 13 ++++++- modules/ve-mw/ui/ve.ui.MWExtensionWindow.js | 39 +++++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWExtensionPreviewDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWExtensionPreviewDialog.js index d956d1eae9..7da260ac98 100644 --- a/modules/ve-mw/ui/dialogs/ve.ui.MWExtensionPreviewDialog.js +++ b/modules/ve-mw/ui/dialogs/ve.ui.MWExtensionPreviewDialog.js @@ -19,8 +19,7 @@ ve.ui.MWExtensionPreviewDialog = function VeUiMWExtensionPreviewDialog() { // Parent constructor ve.ui.MWExtensionPreviewDialog.super.apply( this, arguments ); - // Late bind onChangeHandler to a debounced updatePreview - this.onChangeHandler = ve.debounce( this.updatePreview.bind( this ), 250 ); + this.updatePreviewDebounced = ve.debounce( this.updatePreview.bind( this ), 250 ); }; /* Inheritance */ @@ -72,6 +71,16 @@ ve.ui.MWExtensionPreviewDialog.prototype.getSetupProcess = function ( data ) { }, this ); }; +/** + * @inheritdoc + */ +ve.ui.MWExtensionPreviewDialog.prototype.onChange = function () { + // Parent method + ve.ui.MWExtensionPreviewDialog.super.prototype.onChange.call( this ); + + this.updatePreviewDebounced(); +}; + /** * Update the node rendering to reflect the current content in the dialog. */ diff --git a/modules/ve-mw/ui/inspectors/ve.ui.MWLiveExtensionInspector.js b/modules/ve-mw/ui/inspectors/ve.ui.MWLiveExtensionInspector.js index ce9b00040d..595dec9943 100644 --- a/modules/ve-mw/ui/inspectors/ve.ui.MWLiveExtensionInspector.js +++ b/modules/ve-mw/ui/inspectors/ve.ui.MWLiveExtensionInspector.js @@ -19,8 +19,7 @@ ve.ui.MWLiveExtensionInspector = function VeUiMWLiveExtensionInspector() { // Parent constructor ve.ui.MWLiveExtensionInspector.super.apply( this, arguments ); - // Late bind onChangeHandler to a debounced updatePreview - this.onChangeHandler = ve.debounce( this.updatePreview.bind( this ), 250 ); + this.updatePreviewDebounced = ve.debounce( this.updatePreview.bind( this ), 250 ); }; /* Inheritance */ @@ -113,6 +112,16 @@ ve.ui.MWLiveExtensionInspector.prototype.removeNode = function () { ve.ui.MWLiveExtensionInspector.super.prototype.removeNode.call( this ); }; +/** + * @inheritdoc + */ +ve.ui.MWLiveExtensionInspector.prototype.onChange = function () { + // Parent method + ve.ui.MWLiveExtensionInspector.super.prototype.onChange.call( this ); + + this.updatePreviewDebounced(); +}; + /** * Update the node rendering to reflect the current content in the inspector. */ diff --git a/modules/ve-mw/ui/ve.ui.MWExtensionWindow.js b/modules/ve-mw/ui/ve.ui.MWExtensionWindow.js index 203007c8b3..0794f5eeb1 100644 --- a/modules/ve-mw/ui/ve.ui.MWExtensionWindow.js +++ b/modules/ve-mw/ui/ve.ui.MWExtensionWindow.js @@ -17,6 +17,9 @@ ve.ui.MWExtensionWindow = function VeUiMWExtensionWindow() { this.whitespace = null; this.input = null; + this.originalMwData = null; + + this.onChangeHandler = ve.debounce( this.onChange.bind( this ), 0 ); }; /* Inheritance */ @@ -80,6 +83,7 @@ ve.ui.MWExtensionWindow.prototype.getSetupProcess = function ( data, process ) { if ( this.selectedNode ) { this.input.setValueAndWhitespace( this.selectedNode.getAttribute( 'mw' ).body.extsrc ); + this.originalMwData = this.selectedNode.getAttribute( 'mw' ); } else { if ( !this.constructor.static.modelClasses[ 0 ].static.isContent ) { // New nodes should use linebreaks for blocks @@ -92,6 +96,9 @@ ve.ui.MWExtensionWindow.prototype.getSetupProcess = function ( data, process ) { dir = this.constructor.static.dir || data.dir; this.input.setDir( dir ); + + this.actions.setAbilities( { done: false } ); + this.input.connect( this, { change: 'onChangeHandler' } ); }, this ); }; @@ -126,6 +133,38 @@ ve.ui.MWExtensionWindow.prototype.getActionProcess = function ( action, process }, this ); }; +/** + * Handle change event. + */ +ve.ui.MWExtensionWindow.prototype.onChange = function () { + this.updateActions(); +}; + +/** + * Update the 'done' action according to whether there are changes + */ +ve.ui.MWExtensionWindow.prototype.updateActions = function () { + this.actions.setAbilities( { done: this.isModified() } ); +}; + +/** + * Check if mwData would be modified if window contents were applied + * + * @return {boolean} mwData would be modified + */ +ve.ui.MWExtensionWindow.prototype.isModified = function () { + var mwDataCopy, modified; + + if ( this.originalMwData ) { + mwDataCopy = ve.copy( this.originalMwData ); + this.updateMwData( mwDataCopy ); + modified = !ve.compare( this.originalMwData, mwDataCopy ); + } else { + modified = true; + } + return modified; +}; + /** * Create an new data element for the model class associated with this inspector *