Make dialogs, inspectors windows and window sets generic

Objective:
* Remove surface dependencies in dialogs, inspectors, windows and window sets
* Introduce surface-specific versions of dialogs, inspectors and window sets

Change-Id: I2db59127d2085b02e173a3605e174317e419e213
This commit is contained in:
Trevor Parscal 2013-10-04 10:51:44 -07:00
parent 45a222a863
commit 4aa86d0f87
18 changed files with 192 additions and 64 deletions

View file

@ -105,6 +105,7 @@
"ve.ui.TargetToolbar",
"ve.ui.Window",
"ve.ui.WindowSet",
"ve.ui.SurfaceWindowSet",
"ve.ui.Action",
"ve.ui.Trigger"
]

View file

@ -429,9 +429,12 @@ $wgResourceModules += array(
've/ui/ve.ui.Frame.js',
've/ui/ve.ui.Window.js',
've/ui/ve.ui.WindowSet.js',
've/ui/ve.ui.SurfaceWindowSet.js',
've/ui/ve.ui.Inspector.js',
've/ui/ve.ui.SurfaceInspector.js',
've/ui/ve.ui.InspectorFactory.js',
've/ui/ve.ui.Dialog.js',
've/ui/ve.ui.SurfaceDialog.js',
've/ui/ve.ui.DialogFactory.js',
've/ui/ve.ui.Layout.js',
've/ui/ve.ui.Widget.js',

View file

@ -229,9 +229,12 @@ $html = file_get_contents( $page );
<script src="../../modules/ve/ui/ve.ui.Frame.js"></script>
<script src="../../modules/ve/ui/ve.ui.Window.js"></script>
<script src="../../modules/ve/ui/ve.ui.WindowSet.js"></script>
<script src="../../modules/ve/ui/ve.ui.SurfaceWindowSet.js"></script>
<script src="../../modules/ve/ui/ve.ui.Inspector.js"></script>
<script src="../../modules/ve/ui/ve.ui.SurfaceInspector.js"></script>
<script src="../../modules/ve/ui/ve.ui.InspectorFactory.js"></script>
<script src="../../modules/ve/ui/ve.ui.Dialog.js"></script>
<script src="../../modules/ve/ui/ve.ui.SurfaceDialog.js"></script>
<script src="../../modules/ve/ui/ve.ui.DialogFactory.js"></script>
<script src="../../modules/ve/ui/ve.ui.Layout.js"></script>
<script src="../../modules/ve/ui/ve.ui.Widget.js"></script>

View file

@ -9,15 +9,15 @@
* Document dialog.
*
* @class
* @extends ve.ui.Dialog
* @extends ve.ui.MWDialog
*
* @constructor
* @param {ve.ui.Surface} surface
* @param {ve.ui.WindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Config options
*/
ve.ui.MWSyntaxHighlightDialog = function VeUiMWSyntaxHighlightDialog( surface, config ) {
ve.ui.MWSyntaxHighlightDialog = function VeUiMWSyntaxHighlightDialog( windowSet, config ) {
// Parent constructor
ve.ui.MWDialog.call( this, surface, config );
ve.ui.MWDialog.call( this, windowSet, config );
};
/* Inheritance */
@ -41,7 +41,7 @@ ve.ui.MWSyntaxHighlightDialog.static.name = 'mwSyntaxHighlight';
*/
ve.ui.MWSyntaxHighlightDialog.prototype.initialize = function () {
// Call parent method
ve.ui.Dialog.prototype.initialize.call( this );
ve.ui.MWDialog.prototype.initialize.call( this );
this.editPanel = new ve.ui.PanelLayout( {
'$$': this.frame.$$, 'scrollable': false, 'padded': false
} );
@ -60,7 +60,7 @@ ve.ui.MWSyntaxHighlightDialog.prototype.initialize = function () {
*/
ve.ui.MWSyntaxHighlightDialog.prototype.onOpen = function () {
// Parent method
ve.ui.Dialog.prototype.onOpen.call( this );
ve.ui.MWDialog.prototype.onOpen.call( this );
// Properties
this.sourceNode = this.surface.getView().getFocusedNode();
this.sourceText = this.sourceNode.getModel().getAttribute( 'body' );
@ -81,7 +81,7 @@ ve.ui.MWSyntaxHighlightDialog.prototype.onClose = function ( action ) {
var tx,
doc = this.surface.getModel().getDocument();
// Parent method
ve.ui.Dialog.prototype.onClose.call( this );
ve.ui.MWDialog.prototype.onClose.call( this );
// Save changes via Transaction
if ( action === 'apply' ) {
tx = ve.dm.Transaction.newFromAttributeChanges(

View file

@ -10,7 +10,7 @@
*
* @class
* @abstract
* @extends ve.ui.Inspector
* @extends ve.ui.SurfaceInspector
*
* @constructor
* @param {ve.ui.Surface} surface
@ -18,12 +18,12 @@
*/
ve.ui.MWExtensionInspector = function VeUiMWExtensionInspector( surface, config ) {
// Parent constructor
ve.ui.Inspector.call( this, surface, config );
ve.ui.SurfaceInspector.call( this, surface, config );
};
/* Inheritance */
ve.inheritClass( ve.ui.MWExtensionInspector, ve.ui.Inspector );
ve.inheritClass( ve.ui.MWExtensionInspector, ve.ui.SurfaceInspector );
/* Static properties */
@ -42,7 +42,7 @@ ve.ui.MWExtensionInspector.static.removeable = false;
*/
ve.ui.MWExtensionInspector.prototype.initialize = function () {
// Parent method
ve.ui.Inspector.prototype.initialize.call( this );
ve.ui.SurfaceInspector.prototype.initialize.call( this );
this.input = new ve.ui.TextInputWidget( {
'$$': this.frame.$$,
@ -63,7 +63,7 @@ ve.ui.MWExtensionInspector.prototype.onOpen = function () {
var extsrc = '';
// Parent method
ve.ui.Inspector.prototype.onOpen.call( this );
ve.ui.SurfaceInspector.prototype.onOpen.call( this );
this.node = this.surface.getView().getFocusedNode();
@ -89,7 +89,7 @@ ve.ui.MWExtensionInspector.prototype.onClose = function ( action ) {
surfaceModel = this.surface.getModel();
// Parent method
ve.ui.Inspector.prototype.onClose.call( this, action );
ve.ui.SurfaceInspector.prototype.onClose.call( this, action );
if ( this.node instanceof this.constructor.static.nodeView ) {
mwData = ve.copy( this.node.getModel().getAttribute( 'mw' ) );

View file

@ -98,7 +98,7 @@ ve.ui.MWMathInspector.prototype.onClose = function ( action ) {
ve.ui.MWExtensionInspector.prototype.onClose.call( this, action );
} else {
// Grandparent method; we're overriding the parent behavior in this case
ve.ui.Inspector.prototype.onClose.call( this, action );
ve.ui.SurfaceInspector.prototype.onClose.call( this, action );
// The user tried to empty the node, remove it
surfaceModel.change( ve.dm.Transaction.newFromRemoval(

View file

@ -10,17 +10,17 @@
*
* @class
* @abstract
* @extends ve.ui.Dialog
* @extends ve.ui.SurfaceDialog
*
* @constructor
* @param {ve.ui.Surface} surface
* @param {ve.ui.SurfaceWindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Configuration options
*/
ve.ui.MWDialog = function VeUiMWDialog( surface, config ) {
ve.ui.MWDialog = function VeUiMWDialog( windowSet, config ) {
// Parent constructor
ve.ui.Dialog.call( this, surface, config );
ve.ui.SurfaceDialog.call( this, windowSet, config );
};
/* Inheritance */
ve.inheritClass( ve.ui.MWDialog, ve.ui.Dialog );
ve.inheritClass( ve.ui.MWDialog, ve.ui.SurfaceDialog );

View file

@ -174,9 +174,12 @@
<script src="../../ve/ui/ve.ui.Frame.js"></script>
<script src="../../ve/ui/ve.ui.Window.js"></script>
<script src="../../ve/ui/ve.ui.WindowSet.js"></script>
<script src="../../ve/ui/ve.ui.SurfaceWindowSet.js"></script>
<script src="../../ve/ui/ve.ui.Inspector.js"></script>
<script src="../../ve/ui/ve.ui.SurfaceInspector.js"></script>
<script src="../../ve/ui/ve.ui.InspectorFactory.js"></script>
<script src="../../ve/ui/ve.ui.Dialog.js"></script>
<script src="../../ve/ui/ve.ui.SurfaceDialog.js"></script>
<script src="../../ve/ui/ve.ui.DialogFactory.js"></script>
<script src="../../ve/ui/ve.ui.Layout.js"></script>
<script src="../../ve/ui/ve.ui.Widget.js"></script>

View file

@ -10,7 +10,7 @@
*
* @class
* @abstract
* @extends ve.ui.Inspector
* @extends ve.ui.SurfaceInspector
*
* @constructor
* @param {ve.ui.Surface} surface
@ -18,7 +18,7 @@
*/
ve.ui.AnnotationInspector = function VeUiAnnotationInspector( surface, config ) {
// Parent constructor
ve.ui.Inspector.call( this, surface, config );
ve.ui.SurfaceInspector.call( this, surface, config );
// Properties
this.initialAnnotation = null;
@ -29,7 +29,7 @@ ve.ui.AnnotationInspector = function VeUiAnnotationInspector( surface, config )
/* Inheritance */
ve.inheritClass( ve.ui.AnnotationInspector, ve.ui.Inspector );
ve.inheritClass( ve.ui.AnnotationInspector, ve.ui.SurfaceInspector );
/**
* Annotation models this inspector can edit.
@ -59,7 +59,7 @@ ve.ui.AnnotationInspector.prototype.onSetup = function () {
annotation = this.getMatchingAnnotations( fragment, true ).get( 0 );
// Parent method
ve.ui.Inspector.prototype.onSetup.call( this );
ve.ui.SurfaceInspector.prototype.onSetup.call( this );
// Initialize range
if ( !annotation ) {
if ( fragment.getRange().isCollapsed() && !this.surface.view.hasSlugAtOffset( fragment.getRange().start ) ) {
@ -102,7 +102,7 @@ ve.ui.AnnotationInspector.prototype.onOpen = function () {
initialAnnotation = this.getMatchingAnnotations( fragment ).get( 0 );
// Parent method
ve.ui.Inspector.prototype.onOpen.call( this );
ve.ui.SurfaceInspector.prototype.onOpen.call( this );
// Initialization
this.initialAnnotation = initialAnnotation;
@ -116,7 +116,7 @@ ve.ui.AnnotationInspector.prototype.onOpen = function () {
*/
ve.ui.AnnotationInspector.prototype.onClose = function ( action ) {
// Parent method
ve.ui.Inspector.prototype.onClose.call( this, action );
ve.ui.SurfaceInspector.prototype.onClose.call( this, action );
var i, len, annotations,
insert = false,

View file

@ -31,7 +31,7 @@ ve.ui.Context = function VeUiContext( surface, config ) {
this.toolbar = null;
this.popup = new ve.ui.PopupWidget( { '$$': this.$$, '$container': this.surface.getView().$ } );
this.$menu = this.$$( '<div>' );
this.inspectors = new ve.ui.WindowSet( surface, ve.ui.inspectorFactory );
this.inspectors = new ve.ui.SurfaceWindowSet( surface, ve.ui.inspectorFactory );
// Initialization
this.$.addClass( 've-ui-context' ).append( this.popup.$ );
@ -134,7 +134,7 @@ ve.ui.Context.prototype.onRelocationEnd = function () {
* Handle an inspector being setup.
*
* @method
* @param {ve.ui.Inspector} inspector Inspector that's been setup
* @param {ve.ui.SurfaceInspector} inspector Inspector that's been setup
*/
ve.ui.Context.prototype.onInspectorSetup = function () {
this.selection = this.surface.getModel().getSelection();
@ -144,7 +144,7 @@ ve.ui.Context.prototype.onInspectorSetup = function () {
* Handle an inspector being opened.
*
* @method
* @param {ve.ui.Inspector} inspector Inspector that's been opened
* @param {ve.ui.SurfaceInspector} inspector Inspector that's been opened
*/
ve.ui.Context.prototype.onInspectorOpen = function () {
// Transition between menu and inspector
@ -155,7 +155,7 @@ ve.ui.Context.prototype.onInspectorOpen = function () {
* Handle an inspector being closed.
*
* @method
* @param {ve.ui.Inspector} inspector Inspector that's been opened
* @param {ve.ui.SurfaceInspector} inspector Inspector that's been opened
* @param {boolean} accept Changes have been accepted
*/
ve.ui.Context.prototype.onInspectorClose = function () {

View file

@ -13,16 +13,16 @@
* @extends ve.ui.Window
*
* @constructor
* @param {ve.ui.Surface} surface
* @param {ve.ui.WindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Configuration options
* @cfg {boolean} [footless] Hide foot
*/
ve.ui.Dialog = function VeUiDialog( surface, config ) {
ve.ui.Dialog = function VeUiDialog( windowSet, config ) {
// Configuration initialization
config = config || {};
// Parent constructor
ve.ui.Window.call( this, surface, config );
ve.ui.Window.call( this, windowSet, config );
// Properties
this.visible = false;

View file

@ -13,12 +13,12 @@
* @extends ve.ui.Window
*
* @constructor
* @param {ve.ui.Surface} surface
* @param {ve.ui.WindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Configuration options
*/
ve.ui.Inspector = function VeUiInspector( surface, config ) {
ve.ui.Inspector = function VeUiInspector( windowSet, config ) {
// Parent constructor
ve.ui.Window.call( this, surface, config );
ve.ui.Window.call( this, windowSet, config );
// Properties
this.initialSelection = null;
@ -139,21 +139,3 @@ ve.ui.Inspector.prototype.onFormKeyDown = function ( e ) {
return false;
}
};
/**
* Handle inspector setup events.
*
* @method
*/
ve.ui.Inspector.prototype.onSetup = function () {
this.previousSelection = this.surface.getModel().getSelection();
};
/**
* Handle inspector open events.
*
* @method
*/
ve.ui.Inspector.prototype.onOpen = function () {
this.initialSelection = this.surface.getModel().getSelection();
};

View file

@ -33,7 +33,7 @@ ve.ui.Surface = function VeUiSurface( dataOrDoc, config ) {
);
this.view = new ve.ce.Surface( this.model, this, { '$$': this.$$ } );
this.context = new ve.ui.Context( this, { '$$': this.$$ } );
this.dialogs = new ve.ui.WindowSet( this, ve.ui.dialogFactory );
this.dialogs = new ve.ui.SurfaceWindowSet( this, ve.ui.dialogFactory );
this.commands = {};
this.enabled = true;

View file

@ -0,0 +1,29 @@
/*!
* VisualEditor UserInterface SurfaceDialog class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* UserInterface surface dialog.
*
* @class
* @abstract
* @extends ve.ui.Window
*
* @constructor
* @param {ve.ui.SurfaceWindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Configuration options
*/
ve.ui.SurfaceDialog = function VeUiSurfaceDialog( windowSet, config ) {
// Parent constructor
ve.ui.Dialog.call( this, windowSet, config );
// Properties
this.surface = windowSet.getSurface();
};
/* Inheritance */
ve.inheritClass( ve.ui.SurfaceDialog, ve.ui.Dialog );

View file

@ -0,0 +1,49 @@
/*!
* VisualEditor UserInterface SurfaceInspector class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* UserInterface surface inspector.
*
* @class
* @abstract
* @extends ve.ui.Inspector
*
* @constructor
* @param {ve.ui.SurfaceWindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Configuration options
*/
ve.ui.SurfaceInspector = function VeUiSurfaceInspector( windowSet, config ) {
// Parent constructor
ve.ui.Inspector.call( this, windowSet, config );
// Properties
this.surface = windowSet.getSurface();
};
/* Inheritance */
ve.inheritClass( ve.ui.SurfaceInspector, ve.ui.Inspector );
/* Methods */
/**
* Handle inspector setup events.
*
* @method
*/
ve.ui.SurfaceInspector.prototype.onSetup = function () {
this.previousSelection = this.surface.getModel().getSelection();
};
/**
* Handle inspector open events.
*
* @method
*/
ve.ui.SurfaceInspector.prototype.onOpen = function () {
this.initialSelection = this.surface.getModel().getSelection();
};

View file

@ -0,0 +1,52 @@
/*!
* VisualEditor UserInterface SurfaceWindowSet class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* UserInterface surface window set.
*
* @class
* @extends ve.ui.WindowSet
*
* @constructor
* @param {ve.ui.Surface} surface
* @param {ve.Factory} factory Window factory
* @param {Object} [config] Configuration options
*/
ve.ui.SurfaceWindowSet = function VeUiSurfaceWindowSet( surface, factory, config ) {
// Parent constructor
ve.ui.WindowSet.call( this, factory, config );
// Properties
this.surface = surface;
// Initialization
this.$.addClass( 've-ui-surfaceWindowSet' );
};
/* Inheritance */
ve.inheritClass( ve.ui.SurfaceWindowSet, ve.ui.WindowSet );
/* Methods */
/**
* @inheritdoc
*/
ve.ui.SurfaceWindowSet.prototype.onWindowClose = function ( win, accept ) {
this.surface.getView().focus();
ve.ui.WindowSet.prototype.onWindowClose.call( this, win, accept );
};
/**
* Get the surface.
*
* @method
* @returns {ve.ui.Surface} Surface
*/
ve.ui.SurfaceWindowSet.prototype.getSurface = function () {
return this.surface;
};

View file

@ -14,11 +14,11 @@
* @mixins ve.EventEmitter
*
* @constructor
* @param {ve.ui.Surface} surface
* @param {ve.ui.WindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Configuration options
* @emits initialize
*/
ve.ui.Window = function VeUiWindow( surface, config ) {
ve.ui.Window = function VeUiWindow( windowSet, config ) {
// Parent constructor
ve.Element.call( this, config );
@ -26,7 +26,7 @@ ve.ui.Window = function VeUiWindow( surface, config ) {
ve.EventEmitter.call( this );
// Properties
this.surface = surface;
this.windowSet = windowSet;
this.visible = false;
this.opening = false;
this.closing = false;
@ -193,6 +193,16 @@ ve.ui.Window.prototype.getFrame = function () {
return this.frame;
};
/**
* Get the window set.
*
* @method
* @returns {ve.ui.WindowSet} Window set
*/
ve.ui.Window.prototype.getWindowSet = function () {
return this.windowSet;
};
/**
* Get the title of the window.
*
@ -290,10 +300,8 @@ ve.ui.Window.prototype.close = function ( action ) {
this.visible = false;
this.onClose( action );
this.frame.$content.find( ':focus' ).blur();
this.surface.getView().focus();
this.emit( 'close', action );
// Note that focussing the surface view calls an on focus event, which in turn will
// try to close the window again, hence we put this.closing = false right at the bottom
// This is at the bottom in case handlers of the close event try to close the window again
this.closing = false;
}
};

View file

@ -13,11 +13,10 @@
* @mixins ve.EventEmitter
*
* @constructor
* @param {ve.ui.Surface} surface
* @param {ve.Factory} factory Window factory
* @param {Object} [config] Configuration options
*/
ve.ui.WindowSet = function VeUiWindowSet( surface, factory, config ) {
ve.ui.WindowSet = function VeUiWindowSet( factory, config ) {
// Parent constructor
ve.Element.call( this, config );
@ -25,7 +24,6 @@ ve.ui.WindowSet = function VeUiWindowSet( surface, factory, config ) {
ve.EventEmitter.call( this );
// Properties
this.surface = surface;
this.factory = factory;
this.windows = {};
this.currentWindow = null;
@ -126,7 +124,7 @@ ve.ui.WindowSet.prototype.open = function ( name, config ) {
throw new Error( 'Cannot open another window while another one is active' );
}
if ( !( name in this.windows ) ) {
win = this.windows[name] = this.factory.create( name, this.surface, config );
win = this.windows[name] = this.factory.create( name, this, config );
win.connect( this, {
'setup': ['onWindowSetup', win],
'open': ['onWindowOpen', win],