mediawiki-extensions-Visual.../modules/ve-mw/ce/nodes/ve.ce.MWImageNode.js
Moriel Schottlender f1123f87f5 Render CE MWBlockImageNodes as styled <figure>s
This change is meant to transform the current block image node rendering
in ContentEditable from the nested <div> structure to a <figure> tag more
closely matching Parsoid's output, with CSS to style it the same. This is
mostly so we can work with and display attribute changes, like 'type' and
'alignment', without constantly destroying and rebuilding nested <div>
structures.

This change also includes all the attribute changes that will be called
when the media edit dialog changes image type, alignment, size, etc.

Node: The mw-classes 'thumb', 'thumbinner' and 'thumbcaption' are
preserved in the structure of the <figure> but CSS designers should note
these styles are no longer necessarily attached to <div> elements.

Bug: 53436
Change-Id: I40065acd9fd59d30f94b5336736d4986e8de15aa
2013-12-11 15:54:55 -08:00

115 lines
3 KiB
JavaScript

/*!
* VisualEditor ContentEditable MWImageNode class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/*global mw */
/**
* ContentEditable MediaWiki image node.
*
* @class
* @abstract
* @extends ve.ce.GeneratedContentNode
* @mixins ve.ce.ProtectedNode
* @mixins ve.ce.FocusableNode
* @mixins ve.ce.RelocatableNode
* @mixins ve.ce.MWResizableNode
*
* @constructor
* @param {Object} [config] Configuration options
*/
ve.ce.MWImageNode = function VeCeMWImageNode( $figure, $image, config ) {
// Parent constructor
ve.ce.GeneratedContentNode.call( this );
this.$figure = $figure;
this.$image = $image;
// Mixin constructors
ve.ce.ProtectedNode.call( this, this.$figure, config );
ve.ce.FocusableNode.call( this, this.$figure, config );
ve.ce.RelocatableNode.call( this, this.$figure, config );
ve.ce.MWResizableNode.call( this, this.$image, config );
};
/* Inheritance */
OO.inheritClass( ve.ce.MWImageNode, ve.ce.GeneratedContentNode );
OO.mixinClass( ve.ce.MWImageNode, ve.ce.ProtectedNode );
OO.mixinClass( ve.ce.MWImageNode, ve.ce.FocusableNode );
OO.mixinClass( ve.ce.MWImageNode, ve.ce.RelocatableNode );
// Need to mixin base class as well
OO.mixinClass( ve.ce.MWImageNode, ve.ce.ResizableNode );
OO.mixinClass( ve.ce.MWImageNode, ve.ce.MWResizableNode );
/* Methods */
/** */
ve.ce.MWImageNode.prototype.generateContents = function () {
var xhr, deferred = $.Deferred();
xhr = $.ajax( {
'url': mw.util.wikiScript( 'api' ),
'data': {
'action': 'query',
'prop': 'imageinfo',
'iiprop': 'url',
'iiurlwidth': this.model.getAttribute( 'width' ),
'iiurlheight': this.model.getAttribute( 'height' ),
'titles': this.model.getAttribute( 'resource' ).replace( /^(.+\/)*/, '' ),
'format': 'json'
},
'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 image src.
*
* @param {jQuery.Deferred} deferred The Deferred object created by generateContents
* @param {Object} response Response data
*/
ve.ce.MWImageNode.prototype.onParseSuccess = function ( deferred, response ) {
var id, src, pages = ve.getProp( response, 'query', 'pages' );
for ( id in pages ) {
if ( pages[id].imageinfo ) {
src = pages[id].imageinfo[0].thumburl;
}
}
if ( src ) {
deferred.resolve( src );
} else {
deferred.reject();
}
};
/** */
ve.ce.MWImageNode.prototype.render = function ( generateContents ) {
this.$image.attr( 'src', generateContents );
if ( this.live ) {
this.afterRender();
}
};
/**
* Handle an unsuccessful response from the parser for the image src.
*
* @param {jQuery.Deferred} deferred The promise object created by generateContents
* @param {Object} response Response data
*/
ve.ce.MWImageNode.prototype.onParseError = function ( deferred ) {
deferred.reject();
};