diff --git a/modules/ve-mw/dm/nodes/ve.dm.MWImageNode.js b/modules/ve-mw/dm/nodes/ve.dm.MWImageNode.js index 7636dfb995..658ad5e266 100644 --- a/modules/ve-mw/dm/nodes/ve.dm.MWImageNode.js +++ b/modules/ve-mw/dm/nodes/ve.dm.MWImageNode.js @@ -5,6 +5,8 @@ * @license The MIT License (MIT); see LICENSE.txt */ +/*global mw */ + /** * DataModel generated content node. * @@ -24,6 +26,86 @@ ve.dm.MWImageNode = function VeDmMWImageNode() { OO.inheritClass( ve.dm.MWImageNode, ve.dm.GeneratedContentNode ); +/* Methods */ + +/** + * Get the original size of the media object from the API, if it exists + * + * @returns {jQuery.Promise} Promise which resolves with a width, height and mediatype object + */ +ve.dm.MWImageNode.prototype.getImageInfo = function () { + var node = this, + store = this.getDocument().getStore(), + index = store.indexOfHash( this.getSizeHash() ), + deferred = $.Deferred(); + + if ( index ) { + // The dimensions already stored + deferred.resolve( store.value( index ) ); + } else { + // Look for the media size through the API + $.ajax( { + 'url': mw.util.wikiScript( 'api' ), + 'data': { + 'action': 'query', + 'prop': 'imageinfo', + 'indexpageids': '1', + 'iiprop': 'size|mediatype', + 'format': 'json', + 'titles': this.getFilename() + }, + 'dataType': 'json', + 'type': 'POST', + // Wait up to 100 seconds before giving up + 'timeout': 100000, + 'cache': false + } ) + .done( function ( resp ) { + var originalSize, + page = resp.query && resp.query.pages[resp.query.pageids[0]], + imageinfo = page && page.imageinfo && page.imageinfo[0]; + + if ( imageinfo ) { + originalSize = { + 'width': imageinfo.width, + 'height': imageinfo.height, + 'mediatype': imageinfo.mediatype + }; + + // Store result and resolve + store.index( originalSize, node.getSizeHash() ); + deferred.resolve( originalSize ); + } else { + deferred.reject(); + } + } ) + .fail( function () { + deferred.reject(); + } ); + } + return deferred.promise(); +}; + +/** + * Get the normalised filename of the image + * + * @returns {string} Filename + */ +ve.dm.MWImageNode.prototype.getFilename = function () { + // Strip the raw filename up to the 'File:' namespage + var resource = this.getAttribute( 'resource' ); + return resource.substring( resource.indexOf( 'File:' ) ); +}; + +/** + * Get the store hash for the original dimensions of the image + * + * @returns {string} Store hash + */ +ve.dm.MWImageNode.prototype.getSizeHash = function () { + return 'MWImageOriginalSize:' + this.getFilename(); +}; + /* Static methods */ ve.dm.MWImageNode.static.getHashObject = function ( dataElement ) { diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWMediaEditDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWMediaEditDialog.js index af31b03279..ba329cc713 100644 --- a/modules/ve-mw/ui/dialogs/ve.ui.MWMediaEditDialog.js +++ b/modules/ve-mw/ui/dialogs/ve.ui.MWMediaEditDialog.js @@ -5,8 +5,6 @@ * @license The MIT License (MIT); see LICENSE.txt */ -/*global mw */ - /** * Dialog for editing MediaWiki media objects. * @@ -25,7 +23,6 @@ ve.ui.MWMediaEditDialog = function VeUiMWMediaEditDialog( windowSet, config ) { this.mediaNode = null; this.captionNode = null; this.store = null; - this.filename = null; }; /* Inheritance */ @@ -124,10 +121,6 @@ ve.ui.MWMediaEditDialog.prototype.initialize = function () { // Parent method ve.ui.MWDialog.prototype.initialize.call( this ); - // TODO: Create a ve-wide spinner class instead of the local - // classes using spinners - this.$spinner = this.$( '
' ).addClass( 've-specialchar-spinner' ); - // Set up the booklet layout this.bookletLayout = new OO.ui.BookletLayout( { '$': this.$, @@ -177,11 +170,9 @@ ve.ui.MWMediaEditDialog.prototype.initialize = function () { this.sizeFieldset.$element.append( [ this.sizeWidget.$element, - this.sizeErrorLabel.$element, - this.$spinner + this.sizeErrorLabel.$element ] ); this.sizeErrorLabel.$element.hide(); - this.$spinner.hide(); this.applyButton = new OO.ui.ButtonWidget( { '$': this.$, @@ -200,58 +191,11 @@ ve.ui.MWMediaEditDialog.prototype.initialize = function () { this.$foot.append( this.applyButton.$element ); }; -/** - * Get the original size of the media object from the API, if it exists - * @returns {jQuery.Promise} - */ -ve.ui.MWMediaEditDialog.prototype.getOriginalDimensions = function () { - var index = this.store.indexOfHash( this.constructor.static.getSizeHash( this.filename ) ), - deferred = $.Deferred(); - - if ( index ) { - // The image size is already cached - deferred.resolve( this.store.value( index ) ); - } else { - // Look for the media size through the API - $.ajax( { - 'url': mw.util.wikiScript( 'api' ), - 'data': { - 'action': 'query', - 'prop': 'imageinfo', - 'indexpageids': '1', - 'iiprop': 'size|mediatype', - 'format': 'json', - 'titles': this.filename - }, - 'dataType': 'json', - 'type': 'POST', - // Wait up to 100 seconds before giving up - 'timeout': 100000, - 'cache': false - } ) - .done( function ( resp ) { - var imginfo = resp.query.pages[ resp.query.pageids[0] ]; - - // Resolve with the size parameters - deferred.resolve( { - 'height': imginfo.imageinfo[0].height, - 'width': imginfo.imageinfo[0].width, - 'mediatype': imginfo.imageinfo[0].mediatype - } ); - } ) - .fail( function () { - deferred.resolve( false ); - } ); - } - return deferred.promise(); -}; - /** * @inheritdoc */ ve.ui.MWMediaEditDialog.prototype.setup = function ( data ) { - var attrs, newDoc, originalSize, resource, - dimensions = {}, + var newDoc, doc = this.surface.getModel().getDocument(); // Parent method @@ -262,10 +206,6 @@ ve.ui.MWMediaEditDialog.prototype.setup = function ( data ) { this.captionNode = this.mediaNode.getCaptionNode(); this.store = this.surface.getModel().getDocument().getStore(); - // Strip the raw filename up to the 'File:' namespage - resource = this.mediaNode.getAttribute( 'resource' ); - this.filename = resource.substring( resource.indexOf( 'File:' ) ); - if ( this.captionNode && this.captionNode.getLength() > 0 ) { newDoc = doc.cloneFromRange( this.captionNode.getRange() ); } else { @@ -287,52 +227,30 @@ ve.ui.MWMediaEditDialog.prototype.setup = function ( data ) { } ); - attrs = this.mediaNode.getAttributes(); - - // Show the spinner - this.$spinner.show(); + // Set initial size in inputs + this.sizeWidget.setDimensions( { + 'width': this.mediaNode.getAttribute( 'width' ), + 'height': this.mediaNode.getAttribute( 'height' ), + } ); // Save original size for later calculations - this.getOriginalDimensions().done( ve.bind( function ( sizeObj ) { - if ( sizeObj && sizeObj.width && sizeObj.height ) { - // Set the original dimensions in the widget - this.sizeWidget.setOriginalDimensions( { - 'width': sizeObj.width, - 'height': sizeObj.height - } ); - - // Check if we need to limit the size - if ( sizeObj.mediatype === 'BITMAP' ) { - // Set the max dimensions - this.sizeWidget.setMaxDimensions( { - 'width': sizeObj.width, - 'height': sizeObj.height - } ); - } - - // Cache the originalSize and mediatype - originalSize = { - 'height': sizeObj.height, - 'width': sizeObj.width, - 'mediatype': sizeObj.mediatype + this.mediaNode.getImageInfo().done( ve.bind( function ( imageInfo ) { + if ( imageInfo && imageInfo.width && imageInfo.height ) { + var dimensions = { + 'width': imageInfo.width, + 'height': imageInfo.height }; - this.store.index( originalSize, this.constructor.static.getSizeHash( this.filename ) ); + // Set the original dimensions in the widget + this.sizeWidget.setOriginalDimensions( dimensions ); + + // Bitmaps also have a maximum size of originalDimensions + if ( imageInfo.mediatype === 'BITMAP' ) { + this.sizeWidget.setMaxDimensions( dimensions ); + } } else { // Original dimensions couldn't be fetched. Display an error message this.sizeErrorLabel.$element.hide(); } - - // Set initial size in inputs - dimensions = {}; - if ( attrs.height !== undefined && Number( attrs.height ) > 0 ) { - dimensions.height = attrs.height; - } - if ( attrs.width !== undefined && Number( attrs.width ) > 0 ) { - dimensions.width = attrs.width; - } - this.sizeWidget.setDimensions( dimensions ); - - this.$spinner.hide(); }, this ) ); // Initialization @@ -391,18 +309,6 @@ ve.ui.MWMediaEditDialog.prototype.teardown = function ( data ) { ve.ui.MWDialog.prototype.teardown.call( this, data ); }; -/* Static methods */ - -/** - * Get the store hash for the original dimensions of a given filename - * - * @param {string} filename Filename - * @returns {string} Store hash - */ -ve.ui.MWMediaEditDialog.static.getSizeHash = function ( filename ) { - return 'MWOriginalSize:' + filename; -}; - /* Registration */ ve.ui.dialogFactory.register( ve.ui.MWMediaEditDialog );