/*! * VisualEditor DataModel MWReferenceNode class. * * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt */ /** * DataModel MediaWiki reference node. * * @class * @extends ve.dm.LeafNode * @constructor * @param {number} [length] Length of content data in document; ignored and overridden to 0 * @param {Object} [element] Reference to element in linear model */ ve.dm.MWReferenceNode = function VeDmMWReferenceNode( length, element ) { // Parent constructor ve.dm.LeafNode.call( this, 0, element ); // Event handlers this.connect( this, { 'root': 'onRoot', 'unroot': 'onUnroot' } ); }; /* Inheritance */ ve.inheritClass( ve.dm.MWReferenceNode, ve.dm.LeafNode ); /* Static members */ ve.dm.MWReferenceNode.static.name = 'mwReference'; ve.dm.MWReferenceNode.static.matchTagNames = null; ve.dm.MWReferenceNode.static.matchRdfaTypes = [ 'mw:Extension/ref' ]; ve.dm.MWReferenceNode.static.isContent = true; ve.dm.MWReferenceNode.static.toDataElement = function ( domElements, converter ) { var dataElement, mwDataJSON = domElements[0].getAttribute( 'data-mw' ), mwData = mwDataJSON ? JSON.parse( mwDataJSON ) : {}, body = mwData.body ? mwData.body.html : '', refGroup = mwData.attrs && mwData.attrs.group || '', listGroup = this.name + '/' + refGroup, autoKeyed = !mwData.attrs || mwData.attrs.name === undefined, listKey = autoKeyed ? 'auto/' + converter.internalList.getNextUniqueNumber() : 'literal/' + mwData.attrs.name, queueResult = converter.internalList.queueItemHtml( listGroup, listKey, body ), listIndex = queueResult.index, contentsUsed = ( body !== '' && queueResult.isNew ); dataElement = { 'type': this.name, 'attributes': { 'mw': mwData, 'originalMw': mwDataJSON, 'childDomElements': ve.copy( Array.prototype.slice.apply( domElements[0].childNodes ) ), 'listIndex': listIndex, 'listGroup': listGroup, 'listKey': listKey, 'refGroup': refGroup, 'contentsUsed': contentsUsed } }; return dataElement; }; ve.dm.MWReferenceNode.static.toDomElements = function ( dataElement, doc, converter ) { var itemNodeHtml, originalHtml, mwData, i, iLen, keyedNodes, setContents, contentsAlreadySet, originalMw, childDomElements, listKeyParts, name, el = doc.createElement( 'span' ), itemNodeWrapper = doc.createElement( 'div' ), itemNode = converter.internalList.getItemNode( dataElement.attributes.listIndex ), itemNodeRange = itemNode.getRange(); el.setAttribute( 'typeof', 'mw:Extension/ref' ); mwData = dataElement.attributes.mw ? ve.copy( dataElement.attributes.mw ) : {}; mwData.name = 'ref'; setContents = dataElement.attributes.contentsUsed; keyedNodes = converter.internalList .getNodeGroup( dataElement.attributes.listGroup ) .keyedNodes[dataElement.attributes.listKey]; if ( setContents ) { // Check if a previous node has already set the content. If so, we don't overwrite this // node's contents. contentsAlreadySet = false; if ( keyedNodes ) { for ( i = 0, iLen = keyedNodes.length; i < iLen; i++ ) { if ( keyedNodes[i].element === dataElement ) { break; } if ( keyedNodes[i].element.attributes.contentsUsed ) { contentsAlreadySet = true; break; } } } } else { // Check if any other nodes with this key provided content. If not // then we attach the contents to the first reference with this key // Check that this the first reference with its key if ( keyedNodes && dataElement === keyedNodes[0].element ) { setContents = true; // Check no other reference originally defined the contents // As this is keyedNodes[0] we can start at 1 for ( i = 1, iLen = keyedNodes.length; i < iLen; i++ ) { if ( keyedNodes[i].element.attributes.contentsUsed ) { setContents = false; break; } } } } if ( setContents && !contentsAlreadySet ) { converter.getDomSubtreeFromData( itemNode.getDocument().getFullData( new ve.Range( itemNodeRange.start, itemNodeRange.end ), true ), itemNodeWrapper ); itemNodeHtml = $( itemNodeWrapper ).html(); // Returns '' if itemNodeWrapper is empty originalHtml = ve.getProp( mwData, 'body', 'html' ) || ''; // Only set body.html if itemNodeHtml and originalHtml are actually different if ( !$( '