2013-07-17 19:09:30 +00:00
|
|
|
/*!
|
|
|
|
* VisualEditor UserInterface MediaWiki MWReferenceDialog class.
|
|
|
|
*
|
|
|
|
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
|
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dialog for editing MediaWiki references.
|
|
|
|
*
|
|
|
|
* @class
|
|
|
|
* @extends ve.ui.MWDialog
|
|
|
|
*
|
|
|
|
* @constructor
|
|
|
|
* @param {ve.ui.Surface} surface
|
2013-09-25 10:21:09 +00:00
|
|
|
* @param {Object} [config] Configuration options
|
2013-07-17 19:09:30 +00:00
|
|
|
*/
|
|
|
|
ve.ui.MWReferenceDialog = function VeUiMWReferenceDialog( surface, config ) {
|
|
|
|
// Parent constructor
|
|
|
|
ve.ui.MWDialog.call( this, surface, config );
|
|
|
|
|
|
|
|
// Properties
|
|
|
|
this.ref = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Inheritance */
|
|
|
|
|
|
|
|
ve.inheritClass( ve.ui.MWReferenceDialog, ve.ui.MWDialog );
|
|
|
|
|
|
|
|
/* Static Properties */
|
|
|
|
|
2013-08-27 23:28:29 +00:00
|
|
|
ve.ui.MWReferenceDialog.static.name = 'reference';
|
|
|
|
|
2013-07-17 19:09:30 +00:00
|
|
|
ve.ui.MWReferenceDialog.static.titleMessage = 'visualeditor-dialog-reference-title';
|
|
|
|
|
|
|
|
ve.ui.MWReferenceDialog.static.icon = 'reference';
|
|
|
|
|
2013-08-09 18:29:09 +00:00
|
|
|
ve.ui.MWReferenceDialog.static.toolbarGroups = [
|
2013-08-27 23:28:29 +00:00
|
|
|
{ 'include': [ 'undo', 'redo' ] },
|
|
|
|
{ 'include': [ 'bold', 'italic', 'link', 'clear' ] },
|
|
|
|
{ 'include': [ 'number', 'bullet', 'outdent', 'indent' ] },
|
2013-09-05 00:32:50 +00:00
|
|
|
{ 'include': '*', 'exclude': [ { 'group': 'format' }, 'reference', 'referenceList' ] }
|
2013-07-17 19:09:30 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
ve.ui.MWReferenceDialog.static.surfaceCommands = [
|
2013-08-27 23:28:29 +00:00
|
|
|
'undo', 'redo', 'bold', 'italic', 'link', 'clear'
|
2013-07-17 19:09:30 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
/* Methods */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWReferenceDialog.prototype.initialize = function () {
|
|
|
|
// Parent method
|
|
|
|
ve.ui.MWDialog.prototype.initialize.call( this );
|
|
|
|
|
|
|
|
// Properties
|
|
|
|
this.panels = new ve.ui.StackPanelLayout( { '$$': this.frame.$$ } );
|
|
|
|
this.editPanel = new ve.ui.PanelLayout( {
|
|
|
|
'$$': this.frame.$$, 'scrollable': true, 'padded': true
|
|
|
|
} );
|
|
|
|
this.searchPanel = new ve.ui.PanelLayout( { '$$': this.frame.$$ } );
|
2013-10-02 00:00:57 +00:00
|
|
|
this.applyButton = new ve.ui.PushButtonWidget( {
|
2013-07-17 19:09:30 +00:00
|
|
|
'$$': this.frame.$$,
|
|
|
|
'label': ve.msg( 'visualeditor-dialog-action-apply' ),
|
|
|
|
'flags': ['primary']
|
|
|
|
} );
|
2013-10-02 00:00:57 +00:00
|
|
|
this.insertButton = new ve.ui.PushButtonWidget( {
|
2013-07-17 19:09:30 +00:00
|
|
|
'$$': this.frame.$$,
|
|
|
|
'label': ve.msg( 'visualeditor-dialog-reference-insert-button' ),
|
|
|
|
'flags': ['constructive']
|
|
|
|
} );
|
2013-10-02 00:00:57 +00:00
|
|
|
this.selectButton = new ve.ui.PushButtonWidget( {
|
2013-07-17 19:09:30 +00:00
|
|
|
'$$': this.frame.$$,
|
|
|
|
'label': ve.msg ( 'visualeditor-dialog-reference-useexisting-label' )
|
|
|
|
} );
|
2013-10-02 00:00:57 +00:00
|
|
|
this.backButton = new ve.ui.PushButtonWidget( {
|
2013-07-17 19:09:30 +00:00
|
|
|
'$$': this.frame.$$,
|
|
|
|
'label': ve.msg( 'visualeditor-dialog-action-goback' )
|
|
|
|
} );
|
|
|
|
this.contentFieldset = new ve.ui.FieldsetLayout( { '$$': this.frame.$$ } );
|
|
|
|
this.optionsFieldset = new ve.ui.FieldsetLayout( {
|
|
|
|
'$$': this.frame.$$,
|
|
|
|
'label': ve.msg( 'visualeditor-dialog-reference-options-section' ),
|
|
|
|
'icon': 'settings'
|
|
|
|
} );
|
|
|
|
// TODO: Use a drop-down or something, and populate with existing groups instead of free-text
|
|
|
|
this.referenceGroupInput = new ve.ui.TextInputWidget( { '$$': this.frame.$$ } );
|
|
|
|
this.referenceGroupLabel = new ve.ui.InputLabelWidget( {
|
|
|
|
'$$': this.frame.$$,
|
|
|
|
'input': this.referenceGroupInput,
|
|
|
|
'label': ve.msg( 'visualeditor-dialog-reference-options-group-label' )
|
|
|
|
} );
|
|
|
|
this.search = new ve.ui.MWReferenceSearchWidget( this.surface, { '$$': this.frame.$$ } );
|
|
|
|
|
|
|
|
// Events
|
|
|
|
this.applyButton.connect( this, { 'click': [ 'close', 'apply' ] } );
|
|
|
|
this.insertButton.connect( this, { 'click': [ 'close', 'insert' ] } );
|
|
|
|
this.selectButton.connect( this, { 'click': function () {
|
|
|
|
this.backButton.$.show();
|
|
|
|
this.insertButton.$.hide();
|
|
|
|
this.selectButton.$.hide();
|
|
|
|
this.panels.showItem( this.searchPanel );
|
|
|
|
this.search.getQuery().$input.focus().select();
|
|
|
|
} } );
|
|
|
|
this.backButton.connect( this, { 'click': function () {
|
|
|
|
this.backButton.$.hide();
|
|
|
|
this.insertButton.$.show();
|
|
|
|
this.selectButton.$.show();
|
|
|
|
this.panels.showItem( this.editPanel );
|
|
|
|
this.editPanel.$.find( '.ve-ce-documentNode' ).focus();
|
|
|
|
} } );
|
|
|
|
this.search.connect( this, { 'select': 'onSearchSelect' } );
|
|
|
|
|
|
|
|
// Initialization
|
|
|
|
this.panels.addItems( [ this.editPanel, this.searchPanel ] );
|
|
|
|
this.editPanel.$.append( this.contentFieldset.$, this.optionsFieldset.$ );
|
|
|
|
this.optionsFieldset.$.append( this.referenceGroupLabel.$, this.referenceGroupInput.$ );
|
|
|
|
this.searchPanel.$.append( this.search.$ );
|
|
|
|
this.$body.append( this.panels.$ );
|
|
|
|
this.$foot.append(
|
|
|
|
this.applyButton.$,
|
|
|
|
this.insertButton.$,
|
|
|
|
this.selectButton.$,
|
|
|
|
this.backButton.$
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle search select events.
|
|
|
|
*
|
|
|
|
* @param {Object|null} item Reference attributes or null if no item is selected
|
|
|
|
*/
|
|
|
|
ve.ui.MWReferenceDialog.prototype.onSearchSelect = function ( item ) {
|
|
|
|
if ( item ) {
|
|
|
|
this.useReference( item );
|
|
|
|
this.close( 'insert' );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWReferenceDialog.prototype.onOpen = function () {
|
|
|
|
var ref,
|
|
|
|
focusedNode = this.surface.getView().getFocusedNode();
|
|
|
|
|
|
|
|
// Parent method
|
|
|
|
ve.ui.MWDialog.prototype.onOpen.call( this );
|
|
|
|
|
|
|
|
if ( focusedNode instanceof ve.ce.MWReferenceNode ) {
|
|
|
|
ref = focusedNode.getModel().getAttributes();
|
|
|
|
this.applyButton.$.show();
|
|
|
|
this.insertButton.$.hide();
|
|
|
|
this.selectButton.$.hide();
|
|
|
|
} else {
|
|
|
|
this.applyButton.$.hide();
|
|
|
|
this.insertButton.$.show();
|
|
|
|
this.selectButton.$.show();
|
|
|
|
}
|
|
|
|
this.backButton.$.hide();
|
|
|
|
this.panels.showItem( this.editPanel );
|
|
|
|
this.useReference( ref );
|
2013-08-30 17:55:58 +00:00
|
|
|
this.search.buildIndex();
|
|
|
|
this.selectButton.setDisabled( !this.search.getResults().getItems().length );
|
2013-07-17 19:09:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWReferenceDialog.prototype.onClose = function ( action ) {
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
var i, len, txs, item, newDoc, group, refGroup, listGroup, keyIndex, refNodes,
|
2013-07-17 19:09:30 +00:00
|
|
|
surfaceModel = this.surface.getModel(),
|
2013-08-20 17:18:37 +00:00
|
|
|
// Store the original selection browsers may reset it after
|
|
|
|
// the first model change.
|
|
|
|
selection = surfaceModel.getSelection().clone(),
|
2013-07-17 19:09:30 +00:00
|
|
|
doc = surfaceModel.getDocument(),
|
|
|
|
internalList = doc.getInternalList();
|
|
|
|
|
|
|
|
// Parent method
|
|
|
|
ve.ui.MWDialog.prototype.onClose.call( this, action );
|
|
|
|
|
|
|
|
if ( action === 'insert' || action === 'apply' ) {
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
newDoc = this.referenceSurface.getSurface().getModel().getDocument();
|
2013-08-20 17:06:28 +00:00
|
|
|
refGroup = this.referenceGroupInput.getValue();
|
2013-07-17 19:09:30 +00:00
|
|
|
listGroup = 'mwReference/' + refGroup;
|
|
|
|
|
|
|
|
// Internal item changes
|
|
|
|
if ( this.ref ) {
|
|
|
|
// Group/key has changed
|
|
|
|
if ( this.ref.listGroup !== listGroup ) {
|
|
|
|
// Get all reference nodes with the same group and key
|
|
|
|
group = internalList.getNodeGroup( this.ref.listGroup );
|
|
|
|
refNodes = group.keyedNodes[this.ref.listKey] ?
|
|
|
|
group.keyedNodes[this.ref.listKey].slice() :
|
|
|
|
[ group.firstNodes[this.ref.listIndex] ];
|
|
|
|
// Check for name collision when moving items between groups
|
|
|
|
keyIndex = internalList.getKeyIndex( this.ref.listGroup, this.ref.listKey );
|
|
|
|
if ( keyIndex !== undefined ) {
|
|
|
|
// Resolve name collision by generating a new list key
|
2013-09-19 22:57:08 +00:00
|
|
|
this.ref.listKey = 'auto/' + internalList.getNextUniqueNumber();
|
2013-07-17 19:09:30 +00:00
|
|
|
}
|
|
|
|
// Update the group name of all references nodes with the same group and key
|
|
|
|
txs = [];
|
|
|
|
for ( i = 0, len = refNodes.length; i < len; i++ ) {
|
|
|
|
// HACK: Removing and re-inserting nodes to/from the internal list is done
|
|
|
|
// because internal list doesn't yet support attribute changes
|
|
|
|
refNodes[i].removeFromInternalList();
|
|
|
|
txs.push( ve.dm.Transaction.newFromAttributeChanges(
|
|
|
|
doc,
|
|
|
|
refNodes[i].getOuterRange().start,
|
|
|
|
{ 'refGroup': refGroup, 'listGroup': listGroup }
|
|
|
|
) );
|
|
|
|
}
|
|
|
|
surfaceModel.change( txs );
|
|
|
|
// HACK: Same as above, internal list issues
|
|
|
|
for ( i = 0, len = refNodes.length; i < len; i++ ) {
|
|
|
|
refNodes[i].addToInternalList();
|
|
|
|
}
|
|
|
|
this.ref.listGroup = listGroup;
|
|
|
|
this.ref.refGroup = refGroup;
|
|
|
|
}
|
|
|
|
// Update internal node content
|
|
|
|
surfaceModel.change(
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
ve.dm.Transaction.newFromDocumentReplace(
|
|
|
|
doc, internalList.getItemNode( this.ref.listIndex ), newDoc
|
2013-07-17 19:09:30 +00:00
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Content changes
|
|
|
|
if ( action === 'insert' ) {
|
2013-08-27 20:51:48 +00:00
|
|
|
if ( !this.ref ) {
|
|
|
|
listGroup = 'mwReference/' + refGroup;
|
2013-07-17 19:09:30 +00:00
|
|
|
// Create new internal item
|
|
|
|
this.ref = {
|
2013-09-19 22:57:08 +00:00
|
|
|
'listKey': 'auto/' + internalList.getNextUniqueNumber(),
|
2013-08-27 20:51:48 +00:00
|
|
|
'listGroup': listGroup,
|
2013-07-17 19:09:30 +00:00
|
|
|
'refGroup': refGroup
|
|
|
|
};
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
// Insert an internal item, then inject the subdocument into it
|
|
|
|
item = internalList.getItemInsertion( this.ref.listGroup, this.ref.listKey, [] );
|
2013-07-17 19:09:30 +00:00
|
|
|
surfaceModel.change( item.transaction );
|
|
|
|
this.ref.listIndex = item.index;
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
surfaceModel.change(
|
|
|
|
ve.dm.Transaction.newFromDocumentReplace(
|
|
|
|
doc, internalList.getItemNode( this.ref.listIndex ), newDoc
|
|
|
|
)
|
|
|
|
);
|
2013-07-17 19:09:30 +00:00
|
|
|
}
|
|
|
|
// Add reference at cursor
|
2013-08-20 17:18:37 +00:00
|
|
|
surfaceModel.getFragment( selection ).collapseRangeToEnd().insertContent( [
|
2013-07-17 19:09:30 +00:00
|
|
|
{ 'type': 'mwReference', 'attributes': this.ref }, { 'type': '/mwReference' }
|
|
|
|
] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.referenceSurface.destroy();
|
|
|
|
this.referenceSurface = null;
|
|
|
|
this.ref = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Work on a specific reference.
|
|
|
|
*
|
|
|
|
* @param {Object} [ref] Reference attributes, omit to work on a new reference
|
|
|
|
* @chainable
|
|
|
|
*/
|
|
|
|
ve.ui.MWReferenceDialog.prototype.useReference = function ( ref ) {
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
var newDoc, refGroup,
|
2013-07-17 19:09:30 +00:00
|
|
|
doc = this.surface.getModel().getDocument();
|
|
|
|
|
|
|
|
if ( ref ) {
|
|
|
|
// Use an existing reference
|
|
|
|
this.ref = {
|
|
|
|
'listKey': ref.listKey,
|
|
|
|
'listGroup': ref.listGroup,
|
|
|
|
'refGroup': ref.refGroup,
|
|
|
|
'listIndex': ref.listIndex
|
|
|
|
};
|
2013-10-03 09:52:21 +00:00
|
|
|
newDoc = doc.cloneFromRange( doc.getInternalList().getItemNode( ref.listIndex ).getRange() );
|
2013-07-17 19:09:30 +00:00
|
|
|
refGroup = ref.refGroup;
|
|
|
|
} else {
|
|
|
|
// Create a new reference
|
|
|
|
this.ref = null;
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
newDoc = new ve.dm.Document( [
|
2013-07-17 19:09:30 +00:00
|
|
|
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
{ 'type': '/paragraph' },
|
|
|
|
{ 'type': 'internalList' },
|
|
|
|
{ 'type': '/internalList' }
|
|
|
|
] );
|
2013-07-17 19:09:30 +00:00
|
|
|
refGroup = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
if ( this.referenceSurface ) {
|
|
|
|
this.referenceSurface.destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Properties
|
|
|
|
this.referenceSurface = new ve.ui.SurfaceWidget(
|
Introduce newFromDocumentReplace() transaction builder
Replaces newFromNodeReplacement(). newFromNodeReplacement was very
simplistic and didn't support metadata or internal list items, so
if you had comments or references inside of the data you were editing
(reference contents or an image caption), they'd get mangled.
With this, you can do:
newDoc = doc.getDocumentSlice( node );
// Edit newDoc
tx = ve.dm.Transaction.newFromDocumentReplace( doc, node, newDoc );
surface.change( newDoc );
and that takes care of metadata, internal list items, and things like
references that reference internal list items.
ve.dm.Document.js:
* In getDocumentSlice(), store a reference to the original document
and the number of items in its InternalList at the time of slicing
in the created slice. This is used for reconciliation when the
modified slice is injected back into the parent document with
newFromDocumentReplace().
ve.dm.InternalList.js:
* Add a method for merging in another InternalList. This provides a
mapping from old to new InternalList indexes so the linear model data
being injected by newFromDocumentReplace() can have its InternalList
indexes remapped.
ve.dm.Transaction.js:
* Replace newFromNodeReplacement() with newFromDocumentReplace()
ve.ui.MWMediaEditDialog.js, ve.ui.MWReferenceDialog.js:
* Use getDocumentSlice/newFromDocumentReplace for editing captions/refs
* Change insertion code path to insert an empty internalItem/caption, then
newFromDocumentReplace into that
* Add empty internalList to new mini-documents
ve/test/dm/ve.dm.Transaction.test.js:
* Replace newFromNodeReplacement tests with newFromDocumentReplace tests
ve-mw/test/dm/ve.dm.Transaction.test.js (new):
* Add tests for newFromDocumentReplace with mwReference nodes
ve.dm.mwExample.js:
* Add data for newFromDocumentReplace with mwReference tests
VisualEditor.hooks.php:
* Add new test file
Bug: 52102
Change-Id: I4aa980780114b391924f04df588e81c990c32983
2013-09-05 01:05:07 +00:00
|
|
|
newDoc,
|
2013-07-17 19:09:30 +00:00
|
|
|
{
|
|
|
|
'$$': this.frame.$$,
|
2013-08-09 18:29:09 +00:00
|
|
|
'tools': this.constructor.static.toolbarGroups,
|
2013-07-17 19:09:30 +00:00
|
|
|
'commands': this.constructor.static.surfaceCommands
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2013-08-27 23:29:55 +00:00
|
|
|
// Event handlers
|
|
|
|
this.referenceSurface.getSurface().getModel().connect( this, { 'change': 'onSurfaceChange' } );
|
|
|
|
|
2013-07-17 19:09:30 +00:00
|
|
|
// Initialization
|
|
|
|
this.referenceGroupInput.setValue( refGroup );
|
|
|
|
this.contentFieldset.$.append( this.referenceSurface.$ );
|
|
|
|
this.referenceSurface.initialize();
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2013-08-27 23:29:55 +00:00
|
|
|
/**
|
|
|
|
* Handle reference surface change events
|
|
|
|
*/
|
|
|
|
ve.ui.MWReferenceDialog.prototype.onSurfaceChange = function () {
|
|
|
|
var data = this.referenceSurface.getContent(),
|
|
|
|
// TODO: Check for other types of empty, e.g. only whitespace?
|
|
|
|
disabled = data.length <= 2;
|
|
|
|
|
|
|
|
this.insertButton.setDisabled( disabled );
|
|
|
|
this.applyButton.setDisabled( disabled );
|
|
|
|
};
|
|
|
|
|
2013-07-17 19:09:30 +00:00
|
|
|
/* Registration */
|
|
|
|
|
2013-08-27 23:28:29 +00:00
|
|
|
ve.ui.dialogFactory.register( ve.ui.MWReferenceDialog );
|