Also render attributes of the form html/i-j/attrName in CE

Factored the parsing of html/* attributes out into a static function.
Factored attribute (re)rendering out into ce.View, attribute updates
are much simpler now.

Change-Id: I4caa6d5e1e2c21c28ddff61c3c864e47f66cc6b2
This commit is contained in:
Catrope 2013-05-08 00:38:50 -07:00 committed by Gerrit Code Review
parent 05828cc3f1
commit 31c2165770
3 changed files with 49 additions and 33 deletions

View file

@ -63,19 +63,7 @@ ve.ce.Node.static.canBeSplit = false;
* @param {string} to New value * @param {string} to New value
*/ */
ve.ce.Node.prototype.onAttributeChange = function ( key, from, to ) { ve.ce.Node.prototype.onAttributeChange = function ( key, from, to ) {
var htmlKey = key.substr( 7 ).toLowerCase(); this.renderAttributes( { key: to } );
if (
this.constructor.static.renderHtmlAttributes &&
key.indexOf( 'html/0/' ) === 0 &&
htmlKey.length &&
this.constructor.static.domAttributeWhitelist.indexOf( htmlKey ) !== -1
) {
if ( to === undefined ) {
this.$.removeAttr( htmlKey );
} else {
this.$.attr( htmlKey, to );
}
}
}; };
/** /**

View file

@ -26,13 +26,7 @@ ve.ce.View = function VeCeView( model, $element ) {
// Initialization // Initialization
this.$.data( 'view', this ); this.$.data( 'view', this );
if ( this.constructor.static.renderHtmlAttributes ) { this.renderAttributes( this.model.getAttributes() );
ve.setDomAttributes(
this.$[0],
this.model.getAttributes( 'html/0/' ),
this.constructor.static.domAttributeWhitelist
);
}
}; };
/* Inheritance */ /* Inheritance */
@ -116,3 +110,21 @@ ve.ce.View.prototype.setLive = function ( live ) {
this.live = live; this.live = live;
this.emit( 'live' ); this.emit( 'live' );
}; };
ve.ce.View.prototype.renderAttributes = function ( attributes ) {
var key, parsed,
whitelist = this.constructor.static.domAttributeWhitelist;
if ( !this.constructor.static.renderHtmlAttributes ) {
return;
}
for ( key in attributes ) {
parsed = ve.dm.Converter.parseHtmlAttribute( key, this.$ );
if ( parsed && whitelist.indexOf( parsed.attribute ) !== -1 ) {
if ( attributes[key] === undefined ) {
parsed.domElement.removeAttribute( parsed.attribute );
} else {
parsed.domElement.setAttribute( parsed.attribute, attributes[key] );
}
}
}
};

View file

@ -100,6 +100,31 @@ ve.dm.Converter.openAndCloseAnnotations = function ( currentSet, targetSet, open
} }
}; };
/**
* Parse a linear model attribute name of the form html/i-j-k/attrName.
*
* @param {string} attribute Name of a linear model attribute
* @param {HTMLElement[]|jQuery} domElements DOM elements array that the attribute indexes into
* @returns {Object|null} Object with domElement and attribute keys, or null
*/
ve.dm.Converter.parseHtmlAttribute = function ( attribute, domElements ) {
var i, ilen, indexes, child,
/*jshint regexp:false */
matches = attribute.match( /^html\/((?:\d+\-)*\d)\/(.*)$/ );
if ( !matches ) {
return null;
}
indexes = matches[1].split( '-' ); // matches[1] like '1-2-3'
child = domElements[indexes[0]];
for ( i = 1, ilen = indexes.length; i < ilen; i++ ) {
child = child && child.childNodes[indexes[i]];
}
if ( !child ) {
return null;
}
return { 'domElement': child, 'attribute': matches[2] };
};
/* Methods */ /* Methods */
/** /**
@ -201,7 +226,7 @@ ve.dm.Converter.prototype.canCloseWrapper = function () {
* @returns {HTMLElement|boolean} DOM element, or false if the element cannot be converted * @returns {HTMLElement|boolean} DOM element, or false if the element cannot be converted
*/ */
ve.dm.Converter.prototype.getDomElementsFromDataElement = function ( dataElements, doc ) { ve.dm.Converter.prototype.getDomElementsFromDataElement = function ( dataElements, doc ) {
var domElements, dataElementAttributes, key, matches, indexes, i, ilen, child, var domElements, dataElementAttributes, key, parsed,
dataElement = ve.isArray( dataElements ) ? dataElements[0] : dataElements, dataElement = ve.isArray( dataElements ) ? dataElements[0] : dataElements,
nodeClass = this.modelRegistry.lookup( dataElement.type ); nodeClass = this.modelRegistry.lookup( dataElement.type );
@ -218,18 +243,9 @@ ve.dm.Converter.prototype.getDomElementsFromDataElement = function ( dataElement
dataElementAttributes = dataElement.attributes; dataElementAttributes = dataElement.attributes;
if ( dataElementAttributes ) { if ( dataElementAttributes ) {
for ( key in dataElementAttributes ) { for ( key in dataElementAttributes ) {
// Only include 'html/*' attributes and strip the prefix parsed = ve.dm.Converter.parseHtmlAttribute( key, domElements );
/*jshint regexp:false */ if ( parsed && !parsed.domElement.hasAttribute( parsed.attribute ) ) {
matches = key.match( /^html\/((?:\d+\-)*\d)\/(.*)$/ ); parsed.domElement.setAttribute( parsed.attribute, dataElementAttributes[key] );
if ( matches ) {
indexes = matches[1].split( '-' ); // matches[1] like '1-2-3'
child = domElements[indexes[0]];
for ( i = 1, ilen = indexes.length; i < ilen; i++ ) {
child = child && child.childNodes[indexes[i]];
}
if ( child && !child.hasAttribute( matches[2] ) ) {
child.setAttribute( matches[2], dataElementAttributes[key] );
}
} }
} }
} }