mediawiki-extensions-Visual.../modules/ve/ce/ve.ce.View.js
Roan Kattouw 74b8807df5 Resolve rendered URLs according to the provided <base>
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
2013-10-28 15:16:05 +00:00

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
);
};