jenkins-bot has submitted this change and it was merged.

Change subject: Reference name and group editing
......................................................................


Reference name and group editing

Objective:

* Allow editing reference groups and names in the reference dialog

Bonus:

* Modify attribute transaction builder to support multiple attribute
  changes in a single transaction

Changes:

ve.ui.MWReferenceDialog.js
* Load ref name and group from model
* Save ref name and group, if changed, to model

ve.ui.ListAction.js, ve.ui.Transaction.test.js, ve.ce.ResizableNode.js
* Update use of newFromAttributeChange to newFromAttributeChanges

ve.dm.SurfaceFragment.test.js
* Add test for new changeAttributes method

ve.dm.InternalList.js
* Missing new line at end of file

ve.dm.Transaction.js
* Change newFromAttributeChange to accept an list of attribute changes and
  produce a single transaction that applies one or more attribute changes
  at once

ve.dm.SurfaceFragment.js
* Fix bug in getCoveredNodes where the wrong mode name was being used
* Add changeAttributes method, which applies attributes to all covered
  nodes and allows filtering of which types of nodes the attributes are
  applied to

ve.dm.MWReferenceNode.js
* Actually write key and group back to DOM
* Separate onRoot functionality into addToInternalList so it can be called
  separately (similarly onUnroot/removeFromInternalList)

ve.ce.MWReferenceListNode.js
* Clone internal item CE node before appending to avoid rendering bug.

*.php
* Add links to messages and sort them

Change-Id: Ic4121e4fcfc09265d5863af6f078cdeb77926c8e
---
M VisualEditor.i18n.php
M VisualEditor.php
M modules/ve/ce/nodes/ve.ce.MWReferenceListNode.js
M modules/ve/ce/ve.ce.ResizableNode.js
M modules/ve/dm/nodes/ve.dm.MWReferenceNode.js
M modules/ve/dm/ve.dm.SurfaceFragment.js
M modules/ve/dm/ve.dm.Transaction.js
M modules/ve/test/dm/ve.dm.InternalList.test.js
M modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
M modules/ve/test/dm/ve.dm.Transaction.test.js
M modules/ve/ui/actions/ve.ui.ListAction.js
M modules/ve/ui/dialogs/ve.ui.MWReferenceDialog.js
12 files changed, 219 insertions(+), 77 deletions(-)

Approvals:
  Catrope: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/VisualEditor.i18n.php b/VisualEditor.i18n.php
index ee73510..2bace7b 100644
--- a/VisualEditor.i18n.php
+++ b/VisualEditor.i18n.php
@@ -55,14 +55,14 @@
        'visualeditor-dialog-reference-options-group-label' => 'Use this group',
        'visualeditor-dialog-reference-title' => 'Reference',
        'visualeditor-dialog-media-title' => 'Media settings',
-       'visualeditor-dialog-transclusion-title' => 'Transclusion',
+       'visualeditor-dialog-transclusion-add-param' => 'Add parameter',
        'visualeditor-dialog-transclusion-content' => 'Content',
        'visualeditor-dialog-transclusion-options' => 'Options',
-       'visualeditor-dialog-transclusion-remove-content' => 'Remove content',
-       'visualeditor-dialog-transclusion-remove-template' => 'Remove template',
-       'visualeditor-dialog-transclusion-remove-param' => 'Remove parameter',
-       'visualeditor-dialog-transclusion-add-param' => 'Add parameter',
        'visualeditor-dialog-transclusion-param-name' => 'Parameter name',
+       'visualeditor-dialog-transclusion-remove-content' => 'Remove content',
+       'visualeditor-dialog-transclusion-remove-param' => 'Remove parameter',
+       'visualeditor-dialog-transclusion-remove-template' => 'Remove template',
+       'visualeditor-dialog-transclusion-title' => 'Transclusion',
        'visualeditor-dialogbutton-media-tooltip' => 'Media',
        'visualeditor-dialogbutton-meta-tooltip' => 'Page settings',
        'visualeditor-dialogbutton-reference-tooltip' => 'Reference',
@@ -220,20 +220,24 @@
 {{Identical|Language}}',
        'visualeditor-dialog-meta-title' => 'MetaData dialog title text.
 {{Identical|Page settings}}',
+       'visualeditor-dialog-reference-content-section' => 'Label for the 
reference content sub-section',
+       'visualeditor-dialog-reference-options-section' => 'Label for the 
reference options sub-section',
+       'visualeditor-dialog-reference-options-name-label' => 'Label for the 
reference name input',
+       'visualeditor-dialog-reference-options-group-label' => 'Label for the 
reference group input',
        'visualeditor-dialog-reference-title' => '{{Identical|Reference}}',
-       'visualeditor-dialog-transclusion-title' => 
'{{Identical|Transclusion}}',
+       'visualeditor-dialog-transclusion-add-param' => 'Label for button that 
adds parameter a parameter to a template.
+{{Identical|Add parameter}}',
        'visualeditor-dialog-transclusion-content' => 'Label for editor of 
content between transclusion parts.
 {{Identical|Content}}',
        'visualeditor-dialog-transclusion-options' => 'Label for section with 
options for templates, content or parameters.
 {{Identical|Options}}',
-       'visualeditor-dialog-transclusion-remove-content' => 'Label for button 
that removes content between transclusion parts',
-       'visualeditor-dialog-transclusion-remove-template' => 'Label for button 
that removes a template from a transclusion.
-{{Identical|Remove template}}',
-       'visualeditor-dialog-transclusion-remove-param' => 'Label for button 
that removes a parameter from a template',
-       'visualeditor-dialog-transclusion-add-param' => 'Label for button that 
adds parameter a parameter to a template.
-{{Identical|Add parameter}}',
        'visualeditor-dialog-transclusion-param-name' => 'Placeholder text 
label for an input for adding a parameter to a template.
 {{Identical|Parameter name}}',
+       'visualeditor-dialog-transclusion-remove-content' => 'Label for button 
that removes content between transclusion parts',
+       'visualeditor-dialog-transclusion-remove-param' => 'Label for button 
that removes a parameter from a template',
+       'visualeditor-dialog-transclusion-remove-template' => 'Label for button 
that removes a template from a transclusion.
+{{Identical|Remove template}}',
+       'visualeditor-dialog-transclusion-title' => 
'{{Identical|Transclusion}}',
        'visualeditor-dialogbutton-media-tooltip' => '{{Identical|Media}}',
        'visualeditor-dialogbutton-meta-tooltip' => '{{Identical|Page 
Settings}}',
        'visualeditor-dialogbutton-reference-tooltip' => 
'{{Identical|Reference}}',
diff --git a/VisualEditor.php b/VisualEditor.php
index 2f01f88..b3bcfd6 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -585,20 +585,21 @@
                'messages' => array(
                        // VE messages needed by code that is only in 
experimental mode
                        'visualeditor-dialog-reference-content-section',
-                       'visualeditor-dialog-reference-options-section',
-                       'visualeditor-dialog-reference-options-name-label',
                        'visualeditor-dialog-reference-options-group-label',
+                       'visualeditor-dialog-reference-options-name-label',
+                       'visualeditor-dialog-reference-options-section',
                        'visualeditor-dialog-reference-title',
-                       'visualeditor-dialog-transclusion-title',
-                       'visualeditor-dialogbutton-reference-tooltip',
-                       'visualeditor-dialogbutton-transclusion-tooltip',
+                       'visualeditor-dialog-transclusion-add-param',
                        'visualeditor-dialog-transclusion-content',
                        'visualeditor-dialog-transclusion-options',
-                       'visualeditor-dialog-transclusion-remove-content',
-                       'visualeditor-dialog-transclusion-remove-template',
-                       'visualeditor-dialog-transclusion-remove-param',
-                       'visualeditor-dialog-transclusion-add-param',
                        'visualeditor-dialog-transclusion-param-name',
+                       'visualeditor-dialog-transclusion-remove-content',
+                       'visualeditor-dialog-transclusion-remove-param',
+                       'visualeditor-dialog-transclusion-remove-template',
+                       'visualeditor-dialog-transclusion-title',
+                       'visualeditor-dialog-transclusion-wikitext-label',
+                       'visualeditor-dialogbutton-reference-tooltip',
+                       'visualeditor-dialogbutton-transclusion-tooltip',
                ),
        ),
        'ext.visualEditor.icons-raster' => $wgVisualEditorResourceTemplate + 
array(
diff --git a/modules/ve/ce/nodes/ve.ce.MWReferenceListNode.js 
b/modules/ve/ce/nodes/ve.ce.MWReferenceListNode.js
index 0a165e4..f8ab16b 100644
--- a/modules/ve/ce/nodes/ve.ce.MWReferenceListNode.js
+++ b/modules/ve/ce/nodes/ve.ce.MWReferenceListNode.js
@@ -129,7 +129,7 @@
                        // HACK: ProtectedNode crashes when dealing with an 
unattached node
                        this.attachedItems.push( itemNode );
                        itemNode.attach( this );
-                       $li.append( $( '<span class="reference-text">' ).html( 
itemNode.$.show() ) );
+                       $li.append( $( '<span class="reference-text">' ).html( 
itemNode.$.clone().show() ) );
                        this.$reflist.append( $li );
                }
        } // TODO: Show a placeholder for an empty reference list in the 'else' 
section
diff --git a/modules/ve/ce/ve.ce.ResizableNode.js 
b/modules/ve/ce/ve.ce.ResizableNode.js
index 771b4ad..36bb9a5 100644
--- a/modules/ve/ce/ve.ce.ResizableNode.js
+++ b/modules/ve/ce/ve.ce.ResizableNode.js
@@ -245,7 +245,8 @@
                height = this.$resizeHandles.outerHeight(),
                surfaceModel = this.getRoot().getSurface().getModel(),
                documentModel = surfaceModel.getDocument(),
-               selection = surfaceModel.getSelection();
+               selection = surfaceModel.getSelection(),
+               attrChanges = {};
 
        this.$resizeHandles.removeClass( 've-ce-resizableNode-handles-resizing' 
);
        $( this.getElementDocument() ).off( '.ve-ce-resizableNode' );
@@ -259,8 +260,6 @@
 
        // Allow resize to occur before re-rendering
        setTimeout( ve.bind( function () {
-               var txs = [];
-
                if ( transition ) {
                        // Prevent further transitioning
                        this.$resizable.removeClass( 
've-ce-resizableNode-transitioning' );
@@ -268,17 +267,16 @@
 
                // Apply changes to the model
                if ( this.model.getAttribute( 'width' ) !== width ) {
-                       txs.push( ve.dm.Transaction.newFromAttributeChange(
-                               documentModel, offset, 'width', width
-                       ) );
+                       attrChanges.width = width;
                }
                if ( this.model.getAttribute( 'height' ) !== height ) {
-                       txs.push( ve.dm.Transaction.newFromAttributeChange(
-                               documentModel, offset, 'height', height
-                       ) );
+                       attrChanges.height = height;
                }
-               if ( txs.length > 0 ) {
-                       surfaceModel.change( txs, selection );
+               if ( !ve.isEmptyObject( attrChanges ) ) {
+                       surfaceModel.change(
+                               ve.dm.Transaction.newFromAttributeChanges( 
documentModel, offset, attrChanges ),
+                               selection
+                       );
                }
 
                this.emit( 'resize' );
diff --git a/modules/ve/dm/nodes/ve.dm.MWReferenceNode.js 
b/modules/ve/dm/nodes/ve.dm.MWReferenceNode.js
index 0a16b8e..2423a1a 100644
--- a/modules/ve/dm/nodes/ve.dm.MWReferenceNode.js
+++ b/modules/ve/dm/nodes/ve.dm.MWReferenceNode.js
@@ -110,6 +110,19 @@
                ve.setProp( mwAttr, 'body', 'html', itemNodeHtml );
        }
 
+       // Set or clear key
+       if ( dataElement.attributes.listKey !== null ) {
+               ve.setProp( mwAttr, 'attrs', 'name', 
dataElement.attributes.listKey );
+       } else if ( mwAttr.attrs ) {
+               delete mwAttr.attrs.listKey;
+       }
+       // Set or clear group
+       if ( dataElement.attributes.refGroup !== '' ) {
+               ve.setProp( mwAttr, 'attrs', 'group', 
dataElement.attributes.refGroup );
+       } else if ( mwAttr.attrs ) {
+               delete mwAttr.attrs.refGroup;
+       }
+
        span.setAttribute( 'data-mw', JSON.stringify( mwAttr ) );
 
        return [ span ];
@@ -135,6 +148,22 @@
  * @method
  */
 ve.dm.MWReferenceNode.prototype.onRoot = function () {
+       this.addToInternalList();
+};
+
+/**
+ * Handle the node being detatched from the root
+ * @method
+ */
+ve.dm.MWReferenceNode.prototype.onUnroot = function () {
+       this.removeFromInternalList();
+};
+
+/**
+ * Register the node with the internal list
+ * @method
+ */
+ve.dm.MWReferenceNode.prototype.addToInternalList = function () {
        if ( this.getRoot() === this.getDocument().getDocumentNode() ) {
                this.getDocument().getInternalList().addNode(
                        this.element.attributes.listGroup,
@@ -146,10 +175,10 @@
 };
 
 /**
- * Handle the node being detatched from the root
+ * Unregister the node from the internal list
  * @method
  */
-ve.dm.MWReferenceNode.prototype.onUnroot = function () {
+ve.dm.MWReferenceNode.prototype.removeFromInternalList = function () {
        this.getDocument().getInternalList().removeNode(
                this.element.attributes.listGroup,
                this.element.attributes.listKey,
diff --git a/modules/ve/dm/ve.dm.SurfaceFragment.js 
b/modules/ve/dm/ve.dm.SurfaceFragment.js
index d672789..f38fdec 100644
--- a/modules/ve/dm/ve.dm.SurfaceFragment.js
+++ b/modules/ve/dm/ve.dm.SurfaceFragment.js
@@ -401,7 +401,7 @@
        if ( !this.surface ) {
                return [];
        }
-       return this.document.selectNodes( this.getRange(), 'coveredNodes' );
+       return this.document.selectNodes( this.getRange(), 'covered' );
 };
 
 /**
@@ -450,6 +450,48 @@
 };
 
 /**
+ * Change one or more attributes on covered nodes.
+ *
+ * @method
+ * @param {Object} attr List of attributes to change, use undefined to remove 
an attribute
+ * @param {string} [type] Node type to restrict changes to
+ * @chainable
+ */
+ve.dm.SurfaceFragment.prototype.changeAttributes = function ( attr, type ) {
+       // Handle null fragment
+       if ( !this.surface ) {
+               return this;
+       }
+
+       var i, len, result,
+               txs = [],
+               covered = this.getCoveredNodes();
+
+       for ( i = 0, len = covered.length; i < len; i++ ) {
+               result = covered[i];
+               if (
+                       // Non-wrapped nodes have no attributes
+                       !result.node.isWrapped() ||
+                       // Filtering by node type
+                       ( type && result.node.getType() !== type ) ||
+                       // Ignore zero-length results
+                       ( result.range && result.range.isCollapsed() )
+               ) {
+                       continue;
+               }
+               txs.push(
+                       ve.dm.Transaction.newFromAttributeChanges(
+                               this.document, result.nodeOuterRange.start, attr
+                       )
+               );
+       }
+       if ( txs.length ) {
+               this.surface.change( txs );
+       }
+       return this;
+};
+
+/**
  * Apply an annotation to content in the fragment.
  *
  * To avoid problems identified in bug 33108, use the 
{ve.dm.SurfaceFragment.trimRange} method.
diff --git a/modules/ve/dm/ve.dm.Transaction.js 
b/modules/ve/dm/ve.dm.Transaction.js
index e8e5dbe..3f64305 100644
--- a/modules/ve/dm/ve.dm.Transaction.js
+++ b/modules/ve/dm/ve.dm.Transaction.js
@@ -179,20 +179,21 @@
 };
 
 /**
- * Generate a transaction that changes an attribute.
+ * Generate a transaction that changes one or more attributes.
  *
  * @static
  * @method
  * @param {ve.dm.Document} doc Document to create transaction for
  * @param {number} offset Offset of element
- * @param {string} key Attribute name
- * @param {Mixed} value New value, or undefined to remove the attribute
+ * @param {Object.<string,Mixed>} attr List of attribute key and value pairs, 
use undefined value
+ *   to remove an attribute
  * @returns {ve.dm.Transaction} Transaction that changes an element
  * @throws {Error} Cannot set attributes to non-element data
  * @throws {Error} Cannot set attributes on closing element
  */
-ve.dm.Transaction.newFromAttributeChange = function ( doc, offset, key, value 
) {
-       var tx = new ve.dm.Transaction(),
+ve.dm.Transaction.newFromAttributeChanges = function ( doc, offset, attr ) {
+       var key,
+               tx = new ve.dm.Transaction(),
                data = doc.getData();
        // Verify element exists at offset
        if ( data[offset].type === undefined ) {
@@ -205,9 +206,11 @@
        // Retain up to element
        tx.pushRetain( offset );
        // Change attribute
-       tx.pushReplaceElementAttribute(
-               key, 'attributes' in data[offset] ? 
data[offset].attributes[key] : undefined, value
-       );
+       for ( key in attr ) {
+               tx.pushReplaceElementAttribute(
+                       key, 'attributes' in data[offset] ? 
data[offset].attributes[key] : undefined, attr[key]
+               );
+       }
        // Retain to end of document
        tx.pushRetain( data.length - offset );
        return tx;
diff --git a/modules/ve/test/dm/ve.dm.InternalList.test.js 
b/modules/ve/test/dm/ve.dm.InternalList.test.js
index 59e11a5..959eeaa 100644
--- a/modules/ve/test/dm/ve.dm.InternalList.test.js
+++ b/modules/ve/test/dm/ve.dm.InternalList.test.js
@@ -261,4 +261,4 @@
        insertion = internalList.getItemInsertion( 'mwReference/', 'foo', [] );
        assert.equal( insertion.index, index, 'Insertion with duplicate key 
reuses old index' );
        assert.equal( insertion.transaction, null, 'Insertion with duplicate 
key has null transaction' );
-} );
\ No newline at end of file
+} );
diff --git a/modules/ve/test/dm/ve.dm.SurfaceFragment.test.js 
b/modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
index 93b8c1b..f50c96f 100644
--- a/modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
+++ b/modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
@@ -224,6 +224,18 @@
        );
 } );
 
+QUnit.test( 'changeAttributes', 1, function ( assert ) {
+       var doc = ve.dm.example.createExampleDocument(),
+               surface = new ve.dm.Surface( doc ),
+               fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 0, 
5 ) );
+       fragment.changeAttributes( { 'level': 3 } );
+       assert.deepEqual(
+               doc.getData( new ve.Range( 0, 1 ) ),
+               [ { 'type': 'heading', 'attributes': { 'level': 3 } } ],
+               'changing attributes affects covered nodes'
+       );
+} );
+
 QUnit.test( 'wrapNodes/unwrapNodes', 10, function ( assert ) {
        var doc = ve.dm.example.createExampleDocument(),
                originalDoc = ve.dm.example.createExampleDocument(),
diff --git a/modules/ve/test/dm/ve.dm.Transaction.test.js 
b/modules/ve/test/dm/ve.dm.Transaction.test.js
index dabbc9d..63e2c6c 100644
--- a/modules/ve/test/dm/ve.dm.Transaction.test.js
+++ b/modules/ve/test/dm/ve.dm.Transaction.test.js
@@ -689,12 +689,11 @@
        QUnit.expect( ve.getObjectKeys( cases ).length );
        runConstructorTests( assert, ve.dm.Transaction.newFromNodeReplacement, 
cases );
 } );
-
-QUnit.test( 'newFromAttributeChange', function ( assert ) {
+QUnit.test( 'newFromAttributeChanges', function ( assert ) {
        var doc = ve.dm.example.createExampleDocument(),
                cases = {
                        'first element': {
-                               'args': [doc, 0, 'level', 2],
+                               'args': [doc, 0, { 'level': 2 }],
                                'ops': [
                                        {
                                                'type': 'attribute',
@@ -706,7 +705,7 @@
                                ]
                        },
                        'middle element': {
-                               'args': [doc, 17, 'style', 'number'],
+                               'args': [doc, 17, { 'style': 'number'} ],
                                'ops': [
                                        { 'type': 'retain', 'length': 17 },
                                        {
@@ -718,17 +717,36 @@
                                        { 'type': 'retain', 'length': 44 }
                                ]
                        },
+                       'multiple attributes': {
+                               'args': [doc, 17, { 'style': 'number', 'level': 
1 } ],
+                               'ops': [
+                                       { 'type': 'retain', 'length': 17 },
+                                       {
+                                               'type': 'attribute',
+                                               'key': 'style',
+                                               'from': 'bullet',
+                                               'to': 'number'
+                                       },
+                                       {
+                                               'type': 'attribute',
+                                               'key': 'level',
+                                               'from': undefined,
+                                               'to': 1
+                                       },
+                                       { 'type': 'retain', 'length': 44 }
+                               ]
+                       },
                        'non-element': {
-                               'args': [doc, 1, 'level', 2],
+                               'args': [doc, 1, { 'level': 2 }],
                                'exception': Error
                        },
                        'closing element': {
-                               'args': [doc, 4, 'level', 2],
+                               'args': [doc, 4, { 'level': 2 }],
                                'exception': Error
                        }
                };
        QUnit.expect( ve.getObjectKeys( cases ).length );
-       runConstructorTests( assert, ve.dm.Transaction.newFromAttributeChange, 
cases );
+       runConstructorTests( assert, ve.dm.Transaction.newFromAttributeChanges, 
cases );
 } );
 
 QUnit.test( 'newFromAnnotation', function ( assert ) {
diff --git a/modules/ve/ui/actions/ve.ui.ListAction.js 
b/modules/ve/ui/actions/ve.ui.ListAction.js
index f17d0f9..38b26d9 100644
--- a/modules/ve/ui/actions/ve.ui.ListAction.js
+++ b/modules/ve/ui/actions/ve.ui.ListAction.js
@@ -56,8 +56,8 @@
                        if ( group.grandparent !== previousList ) {
                                // Change the list style
                                surfaceModel.change(
-                                       
ve.dm.Transaction.newFromAttributeChange(
-                                               documentModel, 
group.grandparent.getOffset(), 'style', style
+                                       
ve.dm.Transaction.newFromAttributeChanges(
+                                               documentModel, 
group.grandparent.getOffset(), { 'style': style }
                                        ),
                                        selection
                                );
diff --git a/modules/ve/ui/dialogs/ve.ui.MWReferenceDialog.js 
b/modules/ve/ui/dialogs/ve.ui.MWReferenceDialog.js
index e179f10..9d4cc07 100644
--- a/modules/ve/ui/dialogs/ve.ui.MWReferenceDialog.js
+++ b/modules/ve/ui/dialogs/ve.ui.MWReferenceDialog.js
@@ -106,7 +106,7 @@
  * @method
  */
 ve.ui.MWReferenceDialog.prototype.onOpen = function () {
-       var focusedNode, data,
+       var focusedNode, data, refGroup, listKey,
                doc = this.surface.getModel().getDocument();
 
        // Parent method
@@ -117,6 +117,8 @@
        if ( focusedNode instanceof ve.ce.MWReferenceNode ) {
                this.internalItem = focusedNode.getModel().getInternalItem();
                data = doc.getData( this.internalItem.getRange(), true );
+               listKey = focusedNode.getModel().getAttribute( 'listKey' );
+               refGroup = focusedNode.getModel().getAttribute( 'refGroup' );
        } else {
                data = [
                        { 'type': 'paragraph', 'internal': { 'generated': 
'wrapper' } },
@@ -124,13 +126,14 @@
                ];
        }
 
-       // Properties
        this.referenceSurface = new ve.ui.Surface(
                new ve.dm.ElementLinearData( doc.getStore(), data ), { '$$': 
this.frame.$$ }
        );
        this.referenceToolbar = new ve.ui.Toolbar( this.referenceSurface, { 
'$$': this.frame.$$ } );
 
        // Initialization
+       this.nameInput.setValue( listKey );
+       this.groupInput.setValue( refGroup );
        this.referenceToolbar.$.addClass( 've-ui-mwReferenceDialog-toolbar' );
        this.contentFieldset.$.append( this.referenceToolbar.$, 
this.referenceSurface.$ );
        this.referenceToolbar.addTools( this.constructor.static.toolbarTools );
@@ -146,8 +149,9 @@
  * @param {string} action Action that caused the window to be closed
  */
 ve.ui.MWReferenceDialog.prototype.onClose = function ( action ) {
-       var data, doc, groupName, key, newItem,
-               txs = [];
+       var data, doc, listIndex, listGroup, listKey, refGroup, newItem, 
refNode, oldListGroup,
+               oldListKey, oldNodes, internalList, attrChanges,
+               surfaceModel = this.surface.getModel();
 
        // Parent method
        ve.ui.Dialog.prototype.onOpen.call( this );
@@ -155,32 +159,63 @@
        // Save changes
        if ( action === 'apply' ) {
                data = this.referenceSurface.getModel().getDocument().getData();
-               doc = this.surface.getModel().getDocument();
+               doc = surfaceModel.getDocument();
+               listKey = this.nameInput.getValue() !== '' ? 
this.nameInput.getValue() : null;
+               refGroup = this.groupInput.getValue();
+               listGroup = 'mwReference/' + refGroup;
                if ( this.internalItem ) {
-                       txs.push(
-                               ve.dm.Transaction.newFromNodeReplacement(
-                                       doc, this.internalItem.getRange(), data
-                               )
-                       );
-                       this.surface.getModel().change( txs );
-               } else {
-                       // TODO: pass in group and key from UI if they exist
-                       groupName = '';
-                       key = null;
-                       newItem = doc.getInternalList().getItemInsertion( 
groupName, key, data );
-                       if ( newItem.transaction ) {
-                               txs.push( newItem.transaction );
+                       // Edit reference: handle various replacement cases
+                       refNode = 
this.surface.getView().getFocusedNode().getModel();
+                       oldListGroup = refNode.getAttribute( 'listGroup' );
+                       oldListKey = refNode.getAttribute( 'listKey' );
+                       // Group/key has changed
+                       if ( listGroup !== oldListGroup || listKey !== 
oldListKey ) {
+                               internalList = doc.getInternalList();
+                               oldNodes = internalList.getNodeGroup( 
oldListGroup ).keyedNodes[oldListKey] || [];
+                               listIndex = internalList.getKeyIndex( 
listGroup, listKey );
+                               attrChanges = {};
+                               if ( listIndex !== undefined ) {
+                                       // If the new key exists, reuse its 
internal node
+                                       attrChanges.listIndex = listIndex;
+                               } else if ( oldNodes.length > 1 ) {
+                                       // If the old internal node was being 
shared, create a new one
+                                       newItem = 
internalList.getItemInsertion( listGroup, listKey, data );
+                                       attrChanges.listIndex = newItem.index;
+                               }
+                               attrChanges.listGroup = listGroup;
+                               attrChanges.listKey = listKey;
+                               attrChanges.refGroup = refGroup;
+
+                               // Manually re-register the node before and 
after change
+                               refNode.removeFromInternalList();
+                               surfaceModel.change(
+                                       
ve.dm.Transaction.newFromAttributeChanges(
+                                               doc, 
refNode.getOuterRange().start, attrChanges
+                                       )
+                               );
+                               refNode.addToInternalList();
                        }
-                       this.surface.getModel().change( txs );
-                       
this.surface.getModel().getFragment().collapseRangeToEnd().insertContent( [
+                       // Process the internal node create/edit transaction
+                       if ( !newItem ) {
+                               surfaceModel.change(
+                                       
ve.dm.Transaction.newFromNodeReplacement( doc, this.internalItem, data )
+                               );
+                       } else {
+                               surfaceModel.change( newItem.transaction );
+                       }
+               } else {
+                       // Create reference: just create new nodes
+                       newItem = doc.getInternalList().getItemInsertion( 
listGroup, listKey, data );
+                       surfaceModel.change( newItem.transaction );
+                       
surfaceModel.getFragment().collapseRangeToEnd().insertContent( [
                                {
                                        'type': 'mwReference',
                                        'attributes': {
                                                'mw': { 'name': 'ref' },
                                                'listIndex': newItem.index,
-                                               'listGroup': 'mwReference/' + 
groupName,
-                                               'listKey': key,
-                                               'refGroup': groupName
+                                               'listGroup': listGroup,
+                                               'listKey': listKey,
+                                               'refGroup': refGroup
                                        }
                                },
                                { 'type': '/mwReference' }

-- 
To view, visit https://gerrit.wikimedia.org/r/67466
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ic4121e4fcfc09265d5863af6f078cdeb77926c8e
Gerrit-PatchSet: 22
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Trevor Parscal <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Trevor Parscal <[email protected]>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to