mediawiki-extensions-Visual.../modules/ve/dm/ve.dm.Annotation.js
Roan Kattouw 46c5192477 Allow annotations to render nothing
This effectively unwraps the annotation. Annotations can do this by
returning an empty array from their toDomElements() function.

Right now this is only supported for annotations, but once the converter
is rewritten to be entirely bottom-up, this is trivial to support for
other model types, and could even be used to implement unwrapping of
wrapper paragraph.

Change-Id: Ia572fd0610afccccfe795c257c0de9d003330f13
2013-07-16 15:09:08 -07:00

170 lines
5.4 KiB
JavaScript

/*!
* VisualEditor DataModel Annotation class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* Generic DataModel annotation.
*
* This is an abstract class, annotations should extend this and call this constructor from their
* constructor. You should not instantiate this class directly.
*
* Annotations in the linear model are instances of subclasses of this class. Subclasses should
* only override static properties and functions.
*
* @class
* @extends {ve.dm.Model}
* @constructor
* @param {Object} element Linear model annotation
*/
ve.dm.Annotation = function VeDmAnnotation( element ) {
// Parent constructor
ve.dm.Model.call( this, element );
// Properties
this.name = this.constructor.static.name; // For ease of filtering
};
/* Inheritance */
ve.inheritClass( ve.dm.Annotation, ve.dm.Model );
/* Static properties */
/**
* About grouping is not supported for annotations; setting this to true has no effect.
*
* @static
* @property {boolean} static.enableAboutGrouping
* @inheritable
*/
ve.dm.Annotation.static.enableAboutGrouping = false;
/**
* Automatically apply annotation to content inserted after it.
*
* @type {boolean}
*/
ve.dm.Annotation.static.applyToAppendedContent = true;
/**
* Static function to convert a linear model data element for this annotation type back to
* a DOM element.
*
* As special facilities for annotations, the annotated content that the returned element will
* wrap around is passed in as childDomElements, and this function may return an empty array to
* indicate that the annotation should produce no output. In that case, the child DOM elements will
* not be wrapped in anything and will be inserted directly into this annotation's parent.
*
* @static
* @inheritable
* @method
* @param {Object|Array} dataElement Linear model element or array of linear model data
* @param {HTMLDocument} doc HTML document for creating elements
* @param {ve.dm.Converter} converter Converter object to optionally call .getDomSubtreeFromData() on
* @param {HTMLElement[]} childDomElements Children that will be appended to the returned element
* @returns {HTMLElement[]} Array of DOM elements; only the first element is used; may be empty
*/
ve.dm.Annotation.static.toDomElements = function ( /*dataElement, doc, converter, childDomElements*/ ) {
throw new Error( 've.dm.Annotation subclass must implement toDomElements' );
};
/* Methods */
/**
* Convenience wrapper for .toDomElements() on the current annotation
* @method
* @param {HTMLDocument} [doc] HTML document to use to create elements
* @see ve.dm.Model#toDomElements
*/
ve.dm.Annotation.prototype.getDomElements = function ( doc ) {
return this.constructor.static.toDomElements( this.element, doc || document );
};
/**
* Get an object containing comparable annotation properties.
*
* This is used by the converter to merge adjacent annotations.
*
* @returns {Object} An object containing a subset of the annotation's properties
*/
ve.dm.Annotation.prototype.getComparableObject = function () {
return {
'type': this.getType(),
'attributes': this.getAttributes()
};
};
/**
* HACK: This method strips data-parsoid from HTML attributes for comparisons.
*
* This should be removed once similar annotation merging is handled correctly
* by Parsoid.
*
* @returns {Object} An object all HTML attributes except data-parsoid
*/
ve.dm.Annotation.prototype.getComparableHtmlAttributes = function () {
var comparableAttributes, attributes = this.getHtmlAttributes();
if ( attributes[0] ) {
comparableAttributes = ve.copyObject( attributes[0].values );
delete comparableAttributes['data-parsoid'];
return comparableAttributes;
} else {
return {};
}
};
/**
* HACK: This method adds in HTML attributes so comparable objects aren't serialized
* together if they have different HTML attributes.
*
* This method needs to be different from getComparableObject which is
* still used for editing annotations.
*
* @returns {Object} An object containing a subset of the annotation's properties and HTML attributes
*/
ve.dm.Annotation.prototype.getComparableObjectForSerialization = function () {
var object = this.getComparableObject(),
htmlAttributes = this.getComparableHtmlAttributes();
if ( !ve.isEmptyObject( htmlAttributes ) ) {
object.htmlAttributes = htmlAttributes;
}
return object;
};
/**
* HACK: Check if the annotation was generated by the converter
*
* Used by compareToForSerialization to avoid merging generated annotations.
*
* @returns {boolean} The annotation was generated
*/
ve.dm.Annotation.prototype.isGenerated = function () {
var attributes = this.getHtmlAttributes();
return attributes[0] && attributes[0].values && attributes[0].values['data-parsoid'];
};
/**
* HACK: Compare to another annotation for serialization
*
* Compares two annotations using getComparableObjectForSerialization, unless
* they are both generated annotations, in which case they must be identical.
*
* @param {ve.dm.Annotation} annotation Annotation to compare to
* @returns {boolean} The other annotation is similar to this one
*/
ve.dm.Annotation.prototype.compareToForSerialization = function ( annotation ) {
// If both annotations were generated
if ( this.isGenerated() && annotation.isGenerated() ) {
return ve.compare( this, annotation );
}
return ve.compare(
this.getComparableObjectForSerialization(),
annotation.getComparableObjectForSerialization()
);
};