mediawiki-extensions-Visual.../modules/ve-mw/ce/nodes/ve.ce.MWExtensionNode.js
Ed Sanders 7982ecf2c3 Render MW extension node wikitext with XML
MW extensions are XML not HTML, so we shouldn't build them as XML
to prevent HTML specific rules being applied, such as <source>
always being self closing.

Bug: 54577
Change-Id: I84af4a29cd1c4ae4d1db4f70a4012a8ad0f98bf6
2013-12-01 17:13:39 +00:00

117 lines
3.5 KiB
JavaScript

/*!
* VisualEditor ContentEditable MWExtensionNode class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/*global mw */
/**
* ContentEditable MediaWiki extension node.
*
* Configuration options for .update():
* - 'extsrc': override the contents of the tag (string)
* - 'attrs': override the attributes of the tag (object)
*
* @class
* @abstract
* @extends ve.ce.LeafNode
* @mixins ve.ce.FocusableNode
* @mixins ve.ce.ProtectedNode
* @mixins ve.ce.RelocatableNode
* @mixins ve.ce.GeneratedContentNode
*
* @constructor
* @param {ve.dm.MWExtensionNode} model Model to observe
* @param {Object} [config] Configuration options
*/
ve.ce.MWExtensionNode = function VeCeMWExtensionNode( model, config ) {
// Parent constructor
ve.ce.LeafNode.call( this, model, config );
// Mixin constructors
ve.ce.FocusableNode.call( this );
ve.ce.ProtectedNode.call( this );
ve.ce.RelocatableNode.call( this );
ve.ce.GeneratedContentNode.call( this );
// DOM changes
this.$element.addClass( 've-ce-mwExtensionNode' );
};
/* Inheritance */
OO.inheritClass( ve.ce.MWExtensionNode, ve.ce.LeafNode );
OO.mixinClass( ve.ce.MWExtensionNode, ve.ce.FocusableNode );
OO.mixinClass( ve.ce.MWExtensionNode, ve.ce.ProtectedNode );
OO.mixinClass( ve.ce.MWExtensionNode, ve.ce.RelocatableNode );
OO.mixinClass( ve.ce.MWExtensionNode, ve.ce.GeneratedContentNode );
/* Methods */
/** */
ve.ce.MWExtensionNode.prototype.generateContents = function ( config ) {
var xhr,
deferred = $.Deferred(),
mwData = this.getModel().getAttribute( 'mw' ),
extsrc = config && config.extsrc !== undefined ? config.extsrc : mwData.body.extsrc,
attrs = config && config.attrs || mwData.attrs,
xmlDoc = ( new DOMParser() ).parseFromString( '<' + this.getModel().getExtensionName() + '/>', 'text/xml' ),
wikitext = ( new XMLSerializer() ).serializeToString(
$( xmlDoc.documentElement ).attr( attrs ).text( extsrc )[0]
);
xhr = $.ajax( {
'url': mw.util.wikiScript( 'api' ),
'data': {
'action': 'visualeditor',
'paction': 'parsefragment',
'page': mw.config.get( 'wgRelevantPageName' ),
'wikitext': wikitext,
'token': mw.user.tokens.get( 'editToken' ),
'format': 'json'
},
'dataType': 'json',
'type': 'POST',
// Wait up to 100 seconds before giving up
'timeout': 100000,
'cache': 'false'
} )
.done( ve.bind( this.onParseSuccess, this, deferred ) )
.fail( ve.bind( this.onParseError, this, deferred ) );
return deferred.promise( { abort: xhr.abort } );
};
/**
* Handle a successful response from the parser for the wikitext fragment.
*
* @param {jQuery.Deferred} deferred The Deferred object created by generateContents
* @param {Object} response Response data
*/
ve.ce.MWExtensionNode.prototype.onParseSuccess = function ( deferred, response ) {
var data = response.visualeditor, contentNodes = this.$( data.content ).get();
deferred.resolve( contentNodes );
};
/** */
ve.ce.MWExtensionNode.prototype.afterRender = function () {
// Rerender after images load
// TODO: ignore shields, and count multiple images
this.$element.find( 'img' ).on( 'load', ve.bind( function () {
this.emit( 'rerender' );
}, this ) );
};
/**
* Handle an unsuccessful response from the parser for the wikitext fragment.
*
* @param {jQuery.Deferred} deferred The promise object created by generateContents
* @param {Object} response Response data
*/
ve.ce.MWExtensionNode.prototype.onParseError = function ( deferred ) {
deferred.reject();
};