mediawiki-extensions-Visual.../modules/ve-mw/dm/nodes/ve.dm.MWExtensionNode.js
Bartosz Dziewoński 98351fbcf3 Do not "resolve attributes" in toDomElements() overrides
Resolving attributes means turning 'href' and 'src' URLs from possibly
relative to absolute, so that they don't depend on the base URI of the
document.

This is necessary when rendering for clipboard (and in some other
cases), but at the point when toDomElements() is called, the document
these elements are in does not necessary have a sane base URI set,
giving us hrefs pointing to nonexistent pages.

Don't do it here; it will happen later when we know what the right
document (and right base URI) is, e.g. in ve.ce.Surface#onCopy or
ve.ui.PreviewElement#replaceWithModelDom.

Bug: T169675
Bug: T175157
Change-Id: Ie0a5d6e1c57b8efdbbfba0c24f31ca91d156e200
2017-09-07 14:06:24 +02:00

228 lines
6.1 KiB
JavaScript

/*!
* VisualEditor DataModel MWExtensionNode class.
*
* @copyright 2011-2017 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* DataModel MediaWiki extension node.
*
* @class
* @abstract
* @extends ve.dm.LeafNode
* @mixins ve.dm.FocusableNode
* @mixins ve.dm.GeneratedContentNode
*
* @constructor
*/
ve.dm.MWExtensionNode = function VeDmMWExtensionNode() {
// Parent constructor
ve.dm.MWExtensionNode.super.apply( this, arguments );
// Mixin constructors
ve.dm.GeneratedContentNode.call( this );
ve.dm.FocusableNode.call( this );
};
/* Inheritance */
OO.inheritClass( ve.dm.MWExtensionNode, ve.dm.LeafNode );
OO.mixinClass( ve.dm.MWExtensionNode, ve.dm.FocusableNode );
OO.mixinClass( ve.dm.MWExtensionNode, ve.dm.GeneratedContentNode );
/* Static members */
ve.dm.MWExtensionNode.static.enableAboutGrouping = true;
ve.dm.MWExtensionNode.static.matchTagNames = null;
ve.dm.MWExtensionNode.static.childNodeTypes = [];
/**
* HTML tag name.
* @static
* @property {string}
* @inheritable
*/
ve.dm.MWExtensionNode.static.tagName = null;
/**
* Name of the extension and the parser tag name.
* @static
* @property {string}
* @inheritable
*/
ve.dm.MWExtensionNode.static.extensionName = null;
ve.dm.MWExtensionNode.static.getMatchRdfaTypes = function () {
return [ 'mw:Extension/' + this.extensionName ];
};
/**
* @inheritdoc
* @param {Node[]} domElements
* @param {ve.dm.Converter} converter
* @param {string} [type] Type to give dataElement, defaults to static.name
*/
ve.dm.MWExtensionNode.static.toDataElement = function ( domElements, converter, type ) {
var dataElement,
mwDataJSON = domElements[ 0 ].getAttribute( 'data-mw' ),
mwData = mwDataJSON ? JSON.parse( mwDataJSON ) : {};
dataElement = {
type: type || this.name,
attributes: {
mw: mwData,
originalMw: mwDataJSON
}
};
this.storeGeneratedContents( dataElement, domElements, converter.getStore() );
// Sub-classes should not modify dataElement beyond this point as it will invalidate the cache
return dataElement;
};
/** */
ve.dm.MWExtensionNode.static.cloneElement = function () {
// Parent method
var clone = ve.dm.MWExtensionNode.super.static.cloneElement.apply( this, arguments );
delete clone.attributes.originalMw;
return clone;
};
ve.dm.MWExtensionNode.static.toDomElements = function ( dataElement, doc, converter ) {
var el, els, value,
store = converter.getStore(),
originalMw = dataElement.attributes.originalMw;
// If the transclusion is unchanged just send back the
// original DOM elements so selser can skip over it
if (
dataElement.originalDomElementsIndex &&
originalMw && ve.compare( dataElement.attributes.mw, JSON.parse( originalMw ) )
) {
// originalDomElements is also used for CE rendering so return a copy
els = ve.copyDomElements( converter.getStore().value( dataElement.originalDomElementsIndex ), doc );
} else {
if (
converter.isForClipboard() &&
// Use getHashObjectForRendering to get the rendering from the store
( value = store.value( store.indexOfValue( null, OO.getHash( [ this.getHashObjectForRendering( dataElement ), undefined ] ) ) ) )
) {
// For the clipboard use the current DOM contents so the user has something
// meaningful to paste into external applications
els = ve.copyDomElements( value, doc );
} else {
el = doc.createElement( this.tagName );
el.setAttribute( 'typeof', 'mw:Extension/' + this.getExtensionName( dataElement ) );
el.setAttribute( 'data-mw', JSON.stringify( dataElement.attributes.mw ) );
els = [ el ];
}
}
return els;
};
ve.dm.MWExtensionNode.static.getHashObject = function ( dataElement ) {
return {
type: dataElement.type,
mw: ve.copy( dataElement.attributes.mw )
};
};
/**
* Get the extension's name
*
* Static version for toDomElements
*
* @static
* @param {Object} dataElement Data element
* @return {string} Extension name
*/
ve.dm.MWExtensionNode.static.getExtensionName = function () {
return this.extensionName;
};
ve.dm.MWExtensionNode.static.describeChanges = function ( attributeChanges, change, element ) {
// HACK: Try to generate an '<Extension> has changed' message using associated tool's title
// Extensions should provide more detailed change descriptions
var tools = ve.ui.toolFactory.getRelatedItems( [ ve.dm.nodeFactory.createFromElement( element ) ] );
if ( tools.length ) {
return [ ve.msg( 'visualeditor-changedesc-unknown',
OO.ui.resolveMsg( ve.ui.toolFactory.lookup( tools[ 0 ].name ).static.title )
) ];
}
// Parent method
return ve.dm.MWExtensionNode.super.static.describeChanges.apply( this, arguments );
};
ve.dm.MWExtensionNode.static.describeChange = function ( key ) {
if ( key === 'originalMw' ) {
return null;
}
// Parent method
return ve.dm.MWExtensionNode.super.static.describeChange.apply( this, arguments );
};
/* Methods */
/**
* Get the extension's name
*
* @method
* @return {string} Extension name
*/
ve.dm.MWExtensionNode.prototype.getExtensionName = function () {
return this.constructor.static.getExtensionName( this.element );
};
/**
* DataModel MediaWiki inline extension node.
*
* @class
* @abstract
* @extends ve.dm.MWExtensionNode
*
* @constructor
* @param {Object} [element] Reference to element in linear model
*/
ve.dm.MWInlineExtensionNode = function VeDmMWInlineExtensionNode() {
// Parent constructor
ve.dm.MWInlineExtensionNode.super.apply( this, arguments );
};
/* Inheritance */
OO.inheritClass( ve.dm.MWInlineExtensionNode, ve.dm.MWExtensionNode );
/* Static members */
ve.dm.MWInlineExtensionNode.static.isContent = true;
ve.dm.MWInlineExtensionNode.static.tagName = 'span';
/**
* DataModel MediaWiki block extension node.
*
* @class
* @abstract
* @extends ve.dm.MWExtensionNode
*
* @constructor
* @param {Object} [element] Reference to element in linear model
* @param {ve.dm.Node[]} [children]
*/
ve.dm.MWBlockExtensionNode = function VeDmMWBlockExtensionNode() {
// Parent constructor
ve.dm.MWBlockExtensionNode.super.apply( this, arguments );
};
/* Inheritance */
OO.inheritClass( ve.dm.MWBlockExtensionNode, ve.dm.MWExtensionNode );
/* Static members */
ve.dm.MWBlockExtensionNode.static.tagName = 'div';