mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-16 10:59:56 +00:00
74b8807df5
This is done by using the computed property value rather than the literal attribute value when rendering href and src attributes. Helpfully, this provides perfect URL resolution natively in the browser, which means the document's <base> is respected and all that good stuff. For GeneratedContentNodes, we also need to find all DOM elements inside the rendered DOM that have href or src attributes and resolve those. This is done in the new getRenderedDomElements() function, which the existing cleanup steps (remove <link>/<meta>/<style>, clone for correct document) were moved into. In order to make sure that the computed values are always computed correctly, we need to make sure that in cases where HTML strings in data-mw are parsed, they're parsed in the context of the correct document so the correct <base> is applied. We still need to solve this problem for models that actually store and edit an href or src as an attribute. I'll post more about that on bug 48915. Bug: 48915 Change-Id: Iaccb9e3fc05cd151a0f5e632c8d3bd3568735309
165 lines
3.9 KiB
JavaScript
165 lines
3.9 KiB
JavaScript
/*!
|
|
* VisualEditor ContentEditable View class.
|
|
*
|
|
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
/**
|
|
* Generic base class for CE views.
|
|
*
|
|
* @abstract
|
|
* @extends ve.Element
|
|
* @mixins OO.EventEmitter
|
|
*
|
|
* @constructor
|
|
* @param {ve.dm.Model} model Model to observe
|
|
* @param {Object} [config] Configuration options
|
|
*/
|
|
ve.ce.View = function VeCeView( model, config ) {
|
|
// Setting this property before calling the parent constructor allows overriden #getTagName
|
|
// methods in view classes to have access to the model when they are called for the first time
|
|
// inside of ve.Element
|
|
this.model = model;
|
|
|
|
// Parent constructor
|
|
ve.Element.call( this, config );
|
|
|
|
// Mixin constructors
|
|
OO.EventEmitter.call( this );
|
|
|
|
// Properties
|
|
this.live = false;
|
|
|
|
// Events
|
|
this.connect( this, {
|
|
'setup': 'onSetup',
|
|
'teardown': 'onTeardown'
|
|
} );
|
|
|
|
// Initialization
|
|
this.renderAttributes();
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
OO.inheritClass( ve.ce.View, ve.Element );
|
|
|
|
OO.mixinClass( ve.ce.View, OO.EventEmitter );
|
|
|
|
/* Events */
|
|
|
|
/**
|
|
* @event live
|
|
* @param {boolean} live The view is being set live
|
|
*/
|
|
|
|
/**
|
|
* @event setup
|
|
*/
|
|
|
|
/**
|
|
* @event teardown
|
|
*/
|
|
|
|
/* Static members */
|
|
|
|
/**
|
|
* Allowed attributes for DOM elements, in the same format as ve.dm.Model#static.storeHtmlAttributes
|
|
*
|
|
* This list includes attributes that are generally safe to include in HTML loaded from a
|
|
* foreign source and displaying it inside the browser. It doesn't include any event attributes,
|
|
* for instance, which would allow arbitrary JavaScript execution. This alone is not enough to
|
|
* make HTML safe to display, but it helps.
|
|
*
|
|
* TODO: Rather than use a single global list, set these on a per-view basis to something that makes
|
|
* sense for that view in particular.
|
|
*
|
|
* @static
|
|
* @property {boolean|string|RegExp|Array|Object} static.renderHtmlAttributes
|
|
* @inheritable
|
|
*/
|
|
ve.ce.View.static.renderHtmlAttributes = [
|
|
'abbr', 'about', 'align', 'alt', 'axis', 'bgcolor', 'border', 'cellpadding', 'cellspacing',
|
|
'char', 'charoff', 'cite', 'class', 'clear', 'color', 'colspan', 'datatype', 'datetime',
|
|
'dir', 'face', 'frame', 'headers', 'height', 'href', 'id', 'itemid', 'itemprop', 'itemref',
|
|
'itemscope', 'itemtype', 'lang', 'noshade', 'nowrap', 'property', 'rbspan', 'rel',
|
|
'resource', 'rev', 'rowspan', 'rules', 'scope', 'size', 'span', 'src', 'start', 'style',
|
|
'summary', 'title', 'type', 'typeof', 'valign', 'value', 'width'
|
|
];
|
|
|
|
/* Methods */
|
|
|
|
/**
|
|
* Handle setup event.
|
|
*
|
|
* @method
|
|
*/
|
|
ve.ce.View.prototype.onSetup = function () {
|
|
this.$.data( 'view', this );
|
|
};
|
|
|
|
/**
|
|
* Handle teardown event.
|
|
*
|
|
* @method
|
|
*/
|
|
ve.ce.View.prototype.onTeardown = function () {
|
|
this.$.removeData( 'view' );
|
|
};
|
|
|
|
/**
|
|
* Get the model the view observes.
|
|
*
|
|
* @method
|
|
* @returns {ve.dm.Model} Model the view observes
|
|
*/
|
|
ve.ce.View.prototype.getModel = function () {
|
|
return this.model;
|
|
};
|
|
|
|
/**
|
|
* Check if the view is attached to the live DOM.
|
|
*
|
|
* @method
|
|
* @returns {boolean} View is attached to the live DOM
|
|
*/
|
|
ve.ce.View.prototype.isLive = function () {
|
|
return this.live;
|
|
};
|
|
|
|
/**
|
|
* Set live state.
|
|
*
|
|
* @method
|
|
* @param {boolean} live The view has been attached to the live DOM (use false on detach)
|
|
* @fires live
|
|
* @fires setup
|
|
* @fires teardown
|
|
*/
|
|
ve.ce.View.prototype.setLive = function ( live ) {
|
|
this.live = live;
|
|
this.emit( 'live' );
|
|
if ( this.live ) {
|
|
this.emit( 'setup' );
|
|
} else {
|
|
this.emit( 'teardown' );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Render an HTML attribute list onto this.$
|
|
*
|
|
* If no attributeList is given, the attribute list stored in the linear model will be used.
|
|
*
|
|
* @param {Object[]} [attributeList] HTML attribute list, see ve.dm.Converter#buildHtmlAttributeList
|
|
*/
|
|
ve.ce.View.prototype.renderAttributes = function ( attributeList ) {
|
|
ve.dm.Converter.renderHtmlAttributeList(
|
|
attributeList || this.model.getHtmlAttributes(),
|
|
this.$,
|
|
this.constructor.static.renderHtmlAttributes,
|
|
true // computed attributes
|
|
);
|
|
};
|