Merge "Add HTML text to embed tab"

This commit is contained in:
jenkins-bot 2014-03-19 14:39:01 +00:00 committed by Gerrit Code Review
commit 9cc429506e
5 changed files with 717 additions and 14 deletions

View file

@ -15,7 +15,7 @@
* along with MediaViewer. If not, see <http://www.gnu.org/licenses/>. * along with MediaViewer. If not, see <http://www.gnu.org/licenses/>.
*/ */
( function( mw ) { ( function( mw, $ ) {
var AFP; var AFP;
/** /**
@ -56,5 +56,98 @@
caption ? caption.plain : title.getNameText() ); caption ? caption.plain : title.getNameText() );
}; };
/**
* Byline construction
* @param {{html: string, plain: string}} [author]
* @param {{html: string, plain: string}} [source]
* @return {{html: string, plain: string}} byline in plain text and html
*/
AFP.getBylines = function ( author, source ) {
var bylines = {};
if ( author && source) {
bylines.plain = mw.message(
'multimediaviewer-credit',
author.plain,
source.plain
).text();
bylines.html = mw.message(
'multimediaviewer-credit',
author.html,
source.html
).parse();
} else if ( author ) {
bylines.plain = author.plain;
bylines.html = author.html;
} else if ( source ) {
bylines.plain = source.plain;
bylines.html = source.html;
}
return bylines;
};
/**
* Generates the HTML embed code for the image credit line.
* @param {mw.mmv.model.EmbedFileInfo} info
* @return {string}
*/
AFP.getCreditHtml = function ( info ) {
var creditText, creditFormat, creditParams,
title = info.title.getNameText(),
bylines = this.getBylines( info.author, info.source );
creditFormat = 't';
creditParams = [ title ];
if ( bylines.html ) {
creditFormat += 'b';
creditParams.push( bylines.html );
}
if ( info.license && info.license.plain.length ) {
creditFormat += 'l';
creditParams.push( info.license.plain );
}
if ( info.siteName ) {
creditFormat += 's';
creditParams.push( info.siteName );
}
if ( creditFormat === 't' || creditFormat === 'ts' ) {
creditText = '"' + title + '"';
} else {
creditParams.unshift( 'multimediaviewer-html-embed-credit-text-' + creditFormat );
creditText = mw.message.apply( mw, creditParams ).plain();
}
return creditText;
};
/**
* Generates the HTML embed code for the image.
*
* @param {mw.mmv.model.EmbedFileInfo} info
* @param {string} imgUrl URL to the file itself.
* @param {number} [width] Width to put into the image element.
* @param {number} [height] Height to put into the image element.
* @return {string} Embed code.
*/
AFP.getThumbnailHtml = function ( info, imgUrl, width, height ) {
return $( '<div>' ).append(
$( '<p>' ).append(
$( '<a>' )
.attr( 'href', info.url )
.append(
$( '<img>' )
.attr( 'src', imgUrl )
.attr( 'height', height )
.attr( 'width', width )
),
$( '<br>' ),
this.getCreditHtml( info )
)
).html();
};
mw.mmv.EmbedFileFormatter = EmbedFileFormatter; mw.mmv.EmbedFileFormatter = EmbedFileFormatter;
}( mediaWiki ) ); }( mediaWiki, jQuery ) );

View file

@ -627,6 +627,12 @@
viewer.prevImage(); viewer.prevImage();
} ).on( 'mmv-resize.mmvp', function () { } ).on( 'mmv-resize.mmvp', function () {
viewer.resize( viewer.ui ); viewer.resize( viewer.ui );
} ).on( 'mmv-request-thumbnail.mmvp', function ( e, size ) {
if ( viewer.currentImageFileTitle ) {
return viewer.thumbnailInfoProvider.get( viewer.currentImageFileTitle, size );
} else {
return $.Deferred().reject();
}
} ); } );
}; };

View file

@ -42,6 +42,7 @@
this.$pane.appendTo( this.$container ); this.$pane.appendTo( this.$container );
this.createSnippetTextAreas( this.$pane ); this.createSnippetTextAreas( this.$pane );
this.createSnippetSelectionButtons( this.$pane );
this.createSizePulldownMenus( this.$pane ); this.createSizePulldownMenus( this.$pane );
/** /**
@ -59,6 +60,12 @@
oo.inheritClass( Embed, mw.mmv.ui.reuse.Tab ); oo.inheritClass( Embed, mw.mmv.ui.reuse.Tab );
EP = Embed.prototype; EP = Embed.prototype;
/** @property {number} Width threshold at which an image is to be considered "large" */
EP.LARGE_IMAGE_WIDTH_THRESHOLD = 1200;
/** @property {number} Height threshold at which an image is to be considered "large" */
EP.LARGE_IMAGE_HEIGHT_THRESHOLD = 900;
/** /**
* Creates text areas for html and wikitext snippets. * Creates text areas for html and wikitext snippets.
@ -66,6 +73,12 @@
* @param {jQuery} $container * @param {jQuery} $container
*/ */
EP.createSnippetTextAreas = function( $container ) { EP.createSnippetTextAreas = function( $container ) {
this.embedTextHtml = new oo.ui.TextInputWidget( {
classes: [ 'mw-mlb-embed-text-html' ],
multiline: true,
readOnly: true
} );
this.embedTextWikitext = new oo.ui.TextInputWidget( { this.embedTextWikitext = new oo.ui.TextInputWidget( {
classes: [ 'mw-mlb-embed-text-wt', 'active' ], classes: [ 'mw-mlb-embed-text-wt', 'active' ],
multiline: true, multiline: true,
@ -74,11 +87,46 @@
$( '<p>' ) $( '<p>' )
.append( .append(
this.embedTextHtml.$element,
this.embedTextWikitext.$element this.embedTextWikitext.$element
) )
.appendTo( $container ); .appendTo( $container );
}; };
/**
* Creates snippet selection buttons.
*
* @param {jQuery} $container
*/
EP.createSnippetSelectionButtons = function( $container ) {
var wikitextButtonOption,
htmlButtonOption;
this.embedSwitch = new oo.ui.ButtonSelectWidget( {
classes: [ 'mw-mlb-embed-select' ]
} );
wikitextButtonOption = new oo.ui.ButtonOptionWidget( 'wt', {
label: mw.message( 'multimediaviewer-embed-wt' ).text(),
selected: true
} );
htmlButtonOption = new oo.ui.ButtonOptionWidget( 'html', {
label: mw.message( 'multimediaviewer-embed-html' ).text()
} );
this.embedSwitch.addItems( [
wikitextButtonOption,
htmlButtonOption
] );
$( '<p>' )
.append( this.embedSwitch.$element )
.appendTo( $container );
// Default to 'wikitext'
this.embedSwitch.selectItem( wikitextButtonOption );
};
/** /**
* Creates pulldown menus to select file sizes. * Creates pulldown menus to select file sizes.
* *
@ -128,8 +176,57 @@
this.embedWtSizeSwitch.getMenu().selectItem( this.embedWtSizeChoices.default ); this.embedWtSizeSwitch.getMenu().selectItem( this.embedWtSizeChoices.default );
// Html sizes pulldown menu
this.embedHtmlSizeSwitch = new oo.ui.InlineMenuWidget( {
classes: [ 'mw-mlb-embed-size' ]
} );
this.embedHtmlSizeChoices = {};
this.embedHtmlSizeSwitch.getMenu().addItems( [
this.embedHtmlSizeChoices.small = new oo.ui.MenuItemWidget( {
name: 'small',
height: null,
width: null
},
{
label: mw.message( 'multimediaviewer-small-embed-size', 0, 0 ).text(),
selected: true
} ),
this.embedHtmlSizeChoices.medium = new oo.ui.MenuItemWidget( {
name: 'medium',
height: null,
width: null
},
{
label: mw.message( 'multimediaviewer-medium-embed-size', 0, 0 ).text()
} ),
this.embedHtmlSizeChoices.large = new oo.ui.MenuItemWidget( {
name: 'large',
height: null,
width: null
},
{
label: mw.message( 'multimediaviewer-large-embed-size', 0, 0 ).text()
} ),
this.embedHtmlSizeChoices.original = new oo.ui.MenuItemWidget( {
name: 'original',
height: null,
width: null
},
{
label: mw.message( 'multimediaviewer-original-embed-size', 0, 0 ).text()
} )
] );
this.embedHtmlSizeSwitch.getMenu().selectItem( this.embedHtmlSizeChoices.small );
$( '<p>' ) $( '<p>' )
.append( .append(
this.embedHtmlSizeSwitch.$element,
this.embedWtSizeSwitch.$element this.embedWtSizeSwitch.$element
) )
.appendTo( $container ); .appendTo( $container );
@ -140,13 +237,20 @@
*/ */
EP.attach = function() { EP.attach = function() {
var embed = this, var embed = this,
$htmlTextarea = this.embedTextHtml.$element.find( 'textarea' ),
$wikitextTextarea = this.embedTextWikitext.$element.find( 'textarea' ); $wikitextTextarea = this.embedTextWikitext.$element.find( 'textarea' );
// Select all text once element gets focus // Select all text once element gets focus
this.embedTextHtml.onDOMEvent( 'focus', $.proxy( this.selectAllOnEvent, $htmlTextarea ) );
this.embedTextWikitext.onDOMEvent( 'focus', $.proxy( this.selectAllOnEvent, $wikitextTextarea ) ); this.embedTextWikitext.onDOMEvent( 'focus', $.proxy( this.selectAllOnEvent, $wikitextTextarea ) );
this.embedTextHtml.onDOMEvent( 'mousedown click', $.proxy( this.onlyFocus, $htmlTextarea ) );
this.embedTextWikitext.onDOMEvent( 'mousedown click', $.proxy( this.onlyFocus, $wikitextTextarea ) ); this.embedTextWikitext.onDOMEvent( 'mousedown click', $.proxy( this.onlyFocus, $wikitextTextarea ) );
// Register handler for switching between wikitext/html snippets
this.embedSwitch.on( 'select', $.proxy( embed.handleTypeSwitch, embed ) );
// Register handlers for switching between file sizes // Register handlers for switching between file sizes
this.embedHtmlSizeSwitch.getMenu().on( 'select', $.proxy( embed.handleSizeSwitch, embed ) );
this.embedWtSizeSwitch.getMenu().on( 'select', $.proxy( embed.handleSizeSwitch, embed ) ); this.embedWtSizeSwitch.getMenu().on( 'select', $.proxy( embed.handleSizeSwitch, embed ) );
}; };
@ -156,7 +260,10 @@
EP.unattach = function() { EP.unattach = function() {
this.constructor.super.prototype.unattach.call( this ); this.constructor.super.prototype.unattach.call( this );
this.embedTextHtml.offDOMEvent( 'focus mousedown click' );
this.embedTextWikitext.offDOMEvent( 'focus mousedown click' ); this.embedTextWikitext.offDOMEvent( 'focus mousedown click' );
this.embedSwitch.off( 'select' );
this.embedHtmlSizeSwitch.getMenu().off( 'select' );
this.embedWtSizeSwitch.getMenu().off( 'select' ); this.embedWtSizeSwitch.getMenu().off( 'select' );
}; };
@ -169,17 +276,87 @@
this.changeSize( value.width, value.height ); this.changeSize( value.width, value.height );
}; };
/**
* Handles snippet type switch.
*/
EP.handleTypeSwitch = function ( item ) {
var value = item.getData();
if ( value === 'html' ) {
this.$currentMainEmbedText = this.embedTextHtml.$element;
this.currentSizeMenu = this.embedHtmlSizeSwitch.getMenu();
this.embedWtSizeSwitch.getMenu().hide();
} else if ( value === 'wt' ) {
this.$currentMainEmbedText = this.embedTextWikitext.$element;
this.currentSizeMenu = this.embedWtSizeSwitch.getMenu();
this.embedHtmlSizeSwitch.getMenu().hide();
}
this.embedTextHtml.$element
.add( this.embedHtmlSizeSwitch.$element )
.toggleClass( 'active', value === 'html' );
this.embedTextWikitext.$element
.add( this.embedWtSizeSwitch.$element )
.toggleClass( 'active', value === 'wt' );
this.select();
this.currentSizeMenu.selectItem( this.currentSizeMenu.getSelectedItem() );
};
/** /**
* Changes the size, takes different actions based on which sort of * Changes the size, takes different actions based on which sort of
* embed is currently chosen. * embed is currently chosen.
* *
* @param {number} width New width to set * @param {number} width New width to set
* @param {number} height New height to set
*/ */
EP.changeSize = function ( width ) { EP.changeSize = function ( width, height ) {
this.updateWtEmbedText( width ); var currentItem = this.embedSwitch.getSelectedItem();
if ( currentItem === null ) {
return;
}
switch ( currentItem.getData() ) {
case 'html':
this.setThumbnailURL( {}, width, height );
break;
case 'wt':
this.updateWtEmbedText( width );
break;
}
this.select(); this.select();
}; };
/**
* Sets the value of the thumbnail URL to use for the HTML embed text.
*
* Assumes that the set method has already been called.
* @param {mw.mmv.model.Thumbnail} thumbnail (can be just an empty object)
* @param {number} width New width to set
* @param {number} height New height to set
*/
EP.setThumbnailURL = function ( thumbnail, width, height ) {
var src;
if ( !this.embedFileInfo ) {
return;
}
src = thumbnail.url || this.embedFileInfo.src;
// If the image dimension requested are "large", use the current image url
if ( width > EP.LARGE_IMAGE_WIDTH_THRESHOLD || height > EP.LARGE_IMAGE_HEIGHT_THRESHOLD ) {
src = this.embedFileInfo.src;
}
this.embedTextHtml.setValue(
this.formatter.getThumbnailHtml( this.embedFileInfo, src, width, height ) );
};
/** /**
* Updates the wikitext embed text with a new value for width. * Updates the wikitext embed text with a new value for width.
* *
@ -206,6 +383,69 @@
this.select(); this.select();
}; };
/**
* Calculates possible image sizes for html snippets. It returns up to
* three possible snippet frame sizes (small, medium, large) plus the
* original image size.
*
* @param {number} width
* @param {number} height
* @returns {Object}
* @returns { {width: number, height: number} } return.small
* @returns { {width: number, height: number} } return.medium
* @returns { {width: number, height: number} } return.large
* @returns { {width: number, height: number} } return.original
*/
EP.getPossibleImageSizesForHtml = function ( width, height ) {
var i, bucketName,
currentGuess, dimensions,
bucketWidth, bucketHeight,
buckets = {
'small': { width: 220, height: 145 },
'medium': { width: 640, height: 480 },
'large': { width: 1200, height: 900 }
},
sizes = {},
bucketNames = Object.keys( buckets ),
widthToHeight = height / width,
heightToWidth = width / height;
for ( i = 0; i < bucketNames.length; i++ ) {
bucketName = bucketNames[i];
dimensions = buckets[bucketName];
bucketWidth = dimensions.width;
bucketHeight = dimensions.height;
if ( width > bucketWidth ) {
// Width fits in the current bucket
currentGuess = bucketWidth;
if ( currentGuess * widthToHeight > bucketHeight ) {
// Constrain in height, resize width accordingly
sizes[bucketName] = {
width: Math.round( bucketHeight * heightToWidth ),
height: bucketHeight
};
} else {
sizes[bucketName] = {
width: currentGuess,
height: Math.round( currentGuess * widthToHeight )
};
}
} else if ( height > bucketHeight ) {
// Height fits in the current bucket, resize width accordingly
sizes[bucketName] = {
width: Math.round( bucketHeight * heightToWidth ),
height: bucketHeight
};
}
}
sizes.original = { width: width, height: height };
return sizes;
};
/** /**
* Calculates possible image sizes for wikitext snippets. It returns up to * Calculates possible image sizes for wikitext snippets. It returns up to
* three possible snippet frame sizes (small, medium, large). * three possible snippet frame sizes (small, medium, large).
@ -256,6 +496,7 @@
EP.getSizeOptions = function ( width, height ) { EP.getSizeOptions = function ( width, height ) {
var sizes = {}; var sizes = {};
sizes.html = this.getPossibleImageSizesForHtml( width, height );
sizes.wikitext = this.getPossibleImageSizesForWikitext( width, height ); sizes.wikitext = this.getPossibleImageSizesForWikitext( width, height );
return sizes; return sizes;
@ -268,15 +509,40 @@
* @param {mw.mmv.model.EmbedFileInfo} embedFileInfo * @param {mw.mmv.model.EmbedFileInfo} embedFileInfo
*/ */
EP.set = function ( image, embedFileInfo ) { EP.set = function ( image, embedFileInfo ) {
var wtSizeSwitch = this.embedWtSizeSwitch.getMenu(), var embed = this,
htmlSizeSwitch = this.embedHtmlSizeSwitch.getMenu(),
htmlSizeOptions = htmlSizeSwitch.getItems(),
wtSizeSwitch = this.embedWtSizeSwitch.getMenu(),
wtSizeOptions = wtSizeSwitch.getItems(), wtSizeOptions = wtSizeSwitch.getItems(),
sizes = this.getSizeOptions( image.width, image.height ); sizes = this.getSizeOptions( image.width, image.height );
this.embedFileInfo = embedFileInfo; this.embedFileInfo = embedFileInfo;
this.updateMenuOptions( sizes.html, htmlSizeOptions );
this.updateMenuOptions( sizes.wikitext, wtSizeOptions ); this.updateMenuOptions( sizes.wikitext, wtSizeOptions );
this.currentSizeMenu.selectItem( this.currentSizeMenu.getSelectedItem() ); this.currentSizeMenu.selectItem( this.currentSizeMenu.getSelectedItem() );
this.getThumbnailUrlPromise().done( function ( thumbnail ) {
embed.setThumbnailURL( thumbnail );
} );
};
/**
* @private
*
* Gets a promise for the large thumbnail URL. This is needed because thumbnail URLs cannot
* be reliably guessed, even if we know the full size of the image - most of the time replacing
* the size in another thumbnail URL works (as long as the new size is not larger than the full
* size), but if the file name is very long and with the larger size the URL length would
* exceed a certain threshold, a different schema is used instead.
*
* FIXME document this better - why is this only needed for the large thumbnail?
*
* @return {jQuery.Promise.<string>}
*/
EP.getThumbnailUrlPromise = function () {
return $( document ).triggerHandler( 'mmv-request-thumbnail',
this.LARGE_IMAGE_WIDTH_THRESHOLD ) || $.Deferred().reject();
}; };
/** /**
@ -324,8 +590,10 @@
* @inheritdoc * @inheritdoc
*/ */
EP.empty = function () { EP.empty = function () {
this.embedTextHtml.setValue( '' );
this.embedTextWikitext.setValue( '' ); this.embedTextWikitext.setValue( '' );
this.embedHtmlSizeSwitch.getMenu().hide();
this.embedWtSizeSwitch.getMenu().hide(); this.embedWtSizeSwitch.getMenu().hide();
}; };

View file

@ -1,4 +1,4 @@
( function ( mw ) { ( function ( mw, $ ) {
QUnit.module( 'mmv.EmbedFileFormatter', QUnit.newMwEnvironment() ); QUnit.module( 'mmv.EmbedFileFormatter', QUnit.newMwEnvironment() );
QUnit.test( 'EmbedFileFormatter constructor sanity check', 1, function ( assert ) { QUnit.test( 'EmbedFileFormatter constructor sanity check', 1, function ( assert ) {
@ -6,6 +6,192 @@
assert.ok( formatter, 'constructor with no argument works'); assert.ok( formatter, 'constructor with no argument works');
} ); } );
QUnit.test( 'getBylines():', 7, function ( assert ) {
var formatter = new mw.mmv.EmbedFileFormatter(),
$author = $( '<span class="mw-mlb-author">Homer</span>' ),
$source = $( '<span class="mw-mlb-source">Iliad</span>' ),
author = {
plain: $author.text(),
html: $author.get( 0 ).outerHTML
},
source = {
plain: $source.text(),
html: $source.get( 0 ).outerHTML
},
bylines;
// Works with no arguments
bylines = formatter.getBylines();
assert.deepEqual( bylines, {}, 'No argument case handled correctly.' );
// Author and source present
bylines = formatter.getBylines( author, source );
assert.ok( bylines.plain.match( /Homer|Iliad/ ), 'Author and source found in plain bylines' );
assert.ok( bylines.html.match ( /Homer|Iliad/ ), 'Author and source found in html bylines' );
// Only author present
bylines = formatter.getBylines( author );
assert.ok( bylines.plain.match( /^Homer$/ ), 'Author found in plain bylines.' );
assert.ok( bylines.html.match ( /Homer/ ), 'Author found in html bylines.' );
// Only source present
bylines = formatter.getBylines( undefined, source );
assert.ok( bylines.plain.match( /^Iliad$/ ), 'Source found in plain bylines.' );
assert.ok( bylines.html.match ( /Iliad/ ), 'Source found in html bylines.' );
} );
QUnit.test( 'getThumbnailHtml():', 72, function ( assert ) {
var formatter = new mw.mmv.EmbedFileFormatter(),
title = 'Music Room',
imgUrl = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg',
filePageUrl = 'https://commons.wikimedia.org/wiki/File:Foobar.jpg',
siteName = 'Site Name',
$license = $( '<a class="mw-mlb-license empty" href="/wiki/File:License.txt">Public License</a>' ),
$author = $( '<span class="mw-mlb-author">Homer</span>' ),
$source = $( '<span class="mw-mlb-source">Iliad</span>' ),
license = {
plain: $license && $license.text(),
html: $license && $license.get( 0 ).outerHTML
},
author = {
plain: $author && $author.text(),
html: $author && $author.get( 0 ).outerHTML
},
source = {
plain: $source && $source.text(),
html: $source && $source.get( 0 ).outerHTML
},
thumbUrl = 'https://upload.wikimedia.org/wikipedia/thumb/Foobar.jpg',
width = 700,
height = 500,
info,
generatedHtml;
// No bylines, no license and no site
info = new mw.mmv.model.EmbedFileInfo( new mw.Title( title ), imgUrl, filePageUrl );
generatedHtml = formatter.getThumbnailHtml( info, thumbUrl );
assert.ok( generatedHtml.match( title ), 'Title appears in generated HTML.');
assert.ok( generatedHtml.match( filePageUrl ), 'Page url appears in generated HTML.' );
assert.ok( generatedHtml.match( thumbUrl ), 'Thumbnail url appears in generated HTML' );
assert.ok( ! generatedHtml.match( siteName ), 'Site name should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Public License' ), 'License should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Homer' ), 'Author should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Iliad' ), 'Source should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( width ), 'Width should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( height ), 'Height should not appear in generated HTML' );
// Bylines, license and site
info = new mw.mmv.model.EmbedFileInfo( new mw.Title( title ), imgUrl, filePageUrl,
siteName, license, author, source );
generatedHtml = formatter.getThumbnailHtml( info, thumbUrl, width, height);
assert.ok( generatedHtml.match( title ), 'Title appears in generated HTML.' );
assert.ok( generatedHtml.match( filePageUrl ), 'Page url appears in generated HTML.' );
assert.ok( generatedHtml.match( thumbUrl ), 'Thumbnail url appears in generated HTML' );
assert.ok( generatedHtml.match( siteName ), 'Site name appears in generated HTML' );
assert.ok( generatedHtml.match( 'Public License' ), 'License appears in generated HTML' );
assert.ok( generatedHtml.match( 'Homer' ), 'Author appears in generated HTML' );
assert.ok( generatedHtml.match( 'Iliad' ), 'Source appears in generated HTML' );
assert.ok( generatedHtml.match( width ), 'Width appears in generated HTML' );
assert.ok( generatedHtml.match( height ), 'Height appears in generated HTML' );
// Bylines, license and no site
info = new mw.mmv.model.EmbedFileInfo( new mw.Title( title ), imgUrl, filePageUrl,
undefined, license, author, source );
generatedHtml = formatter.getThumbnailHtml( info, thumbUrl, width, height);
assert.ok( generatedHtml.match( title ), 'Title appears in generated HTML.' );
assert.ok( generatedHtml.match( filePageUrl ), 'Page url appears in generated HTML.' );
assert.ok( generatedHtml.match( thumbUrl ), 'Thumbnail url appears in generated HTML' );
assert.ok( ! generatedHtml.match( siteName ), 'Site name should not appear in generated HTML' );
assert.ok( generatedHtml.match( 'Public License' ), 'License appears in generated HTML' );
assert.ok( generatedHtml.match( 'Homer' ), 'Author appears in generated HTML' );
assert.ok( generatedHtml.match( 'Iliad' ), 'Source appears in generated HTML' );
assert.ok( generatedHtml.match( width ), 'Width appears in generated HTML' );
assert.ok( generatedHtml.match( height ), 'Height appears in generated HTML' );
// Bylines, no license and site
info = new mw.mmv.model.EmbedFileInfo( new mw.Title( title ), imgUrl, filePageUrl,
siteName, undefined, author, source );
generatedHtml = formatter.getThumbnailHtml( info, thumbUrl, width, height);
assert.ok( generatedHtml.match( title ), 'Title appears in generated HTML.' );
assert.ok( generatedHtml.match( filePageUrl ), 'Page url appears in generated HTML.' );
assert.ok( generatedHtml.match( thumbUrl ), 'Thumbnail url appears in generated HTML' );
assert.ok( generatedHtml.match( siteName ), 'Site name appears in generated HTML' );
assert.ok( ! generatedHtml.match( 'Public License' ), 'License should not appear in generated HTML' );
assert.ok( generatedHtml.match( 'Homer' ), 'Author appears in generated HTML' );
assert.ok( generatedHtml.match( 'Iliad' ), 'Source appears in generated HTML' );
assert.ok( generatedHtml.match( width ), 'Width appears in generated HTML' );
assert.ok( generatedHtml.match( height ), 'Height appears in generated HTML' );
// Bylines, no license and no site
info = new mw.mmv.model.EmbedFileInfo( new mw.Title( title ), imgUrl, filePageUrl,
undefined, undefined, author, source );
generatedHtml = formatter.getThumbnailHtml( info, thumbUrl, width, height);
assert.ok( generatedHtml.match( title ), 'Title appears in generated HTML.' );
assert.ok( generatedHtml.match( filePageUrl ), 'Page url appears in generated HTML.' );
assert.ok( generatedHtml.match( thumbUrl ), 'Thumbnail url appears in generated HTML' );
assert.ok( ! generatedHtml.match( siteName ), 'Site name should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Public License' ), 'License should not appear in generated HTML' );
assert.ok( generatedHtml.match( 'Homer' ), 'Author appears in generated HTML' );
assert.ok( generatedHtml.match( 'Iliad' ), 'Source appears in generated HTML' );
assert.ok( generatedHtml.match( width ), 'Width appears in generated HTML');
assert.ok( generatedHtml.match( height ), 'Height appears in generated HTML');
// No bylines, license and site
info = new mw.mmv.model.EmbedFileInfo( new mw.Title( title ), imgUrl, filePageUrl,
siteName, license );
generatedHtml = formatter.getThumbnailHtml( info, thumbUrl, width, height);
assert.ok( generatedHtml.match( title ), 'Title appears in generated HTML.');
assert.ok( generatedHtml.match( filePageUrl ), 'Page url appears in generated HTML.' );
assert.ok( generatedHtml.match( thumbUrl ), 'Thumbnail url appears in generated HTML' );
assert.ok( generatedHtml.match( siteName ), 'Site name appears in generated HTML' );
assert.ok( generatedHtml.match( 'Public License' ), 'License appears in generated HTML' );
assert.ok( ! generatedHtml.match( 'Homer' ), 'Author should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Iliad' ), 'Source should not appear in generated HTML' );
assert.ok( generatedHtml.match( width ), 'Width appears in generated HTML' );
assert.ok( generatedHtml.match( height ), 'Height appears in generated HTML' );
// No bylines, license and no site
info = new mw.mmv.model.EmbedFileInfo( new mw.Title( title ), imgUrl, filePageUrl,
undefined, license );
generatedHtml = formatter.getThumbnailHtml( info, thumbUrl, width, height);
assert.ok( generatedHtml.match( title ), 'Title appears in generated HTML.');
assert.ok( generatedHtml.match( filePageUrl ), 'Page url appears in generated HTML.' );
assert.ok( generatedHtml.match( thumbUrl ), 'Thumbnail url appears in generated HTML' );
assert.ok( ! generatedHtml.match( siteName ), 'Site name should not appear in generated HTML' );
assert.ok( generatedHtml.match( 'Public License' ), 'License appears in generated HTML' );
assert.ok( ! generatedHtml.match( 'Homer' ), 'Author should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Iliad' ), 'Source should not appear in generated HTML' );
assert.ok( generatedHtml.match( width ), 'Width appears in generated HTML' );
assert.ok( generatedHtml.match( height ), 'Height appears in generated HTML' );
// No bylines, no license and site
info = new mw.mmv.model.EmbedFileInfo( new mw.Title( title ), imgUrl, filePageUrl,
siteName );
generatedHtml = formatter.getThumbnailHtml( info, thumbUrl, width, height);
assert.ok( generatedHtml.match( title ), 'Title appears in generated HTML.');
assert.ok( generatedHtml.match( filePageUrl ), 'Page url appears in generated HTML.' );
assert.ok( generatedHtml.match( thumbUrl ), 'Thumbnail url appears in generated HTML' );
assert.ok( ! generatedHtml.match( siteName ), 'Site name should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Public License' ), 'License should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Homer' ), 'Author should not appear in generated HTML' );
assert.ok( ! generatedHtml.match( 'Iliad' ), 'Source should not appear in generated HTML' );
assert.ok( generatedHtml.match( width ), 'Width appears in generated HTML' );
assert.ok( generatedHtml.match( height ), 'Height appears in generated HTML' );
} );
QUnit.test( 'getThumbnailWikitext():', 3, function ( assert ) { QUnit.test( 'getThumbnailWikitext():', 3, function ( assert ) {
var formatter = new mw.mmv.EmbedFileFormatter(), var formatter = new mw.mmv.EmbedFileFormatter(),
title = mw.Title.newFromText( 'File:Foobar.jpg' ), title = mw.Title.newFromText( 'File:Foobar.jpg' ),
@ -45,4 +231,4 @@
'Wikitext generated correctly.' ); 'Wikitext generated correctly.' );
} ); } );
}( mediaWiki ) ); }( mediaWiki, jQuery ) );

View file

@ -20,22 +20,72 @@
QUnit.module( 'mmv.ui.reuse.Embed', QUnit.newMwEnvironment() ); QUnit.module( 'mmv.ui.reuse.Embed', QUnit.newMwEnvironment() );
QUnit.test( 'Sanity test, object creation and UI construction', 6, function ( assert ) { QUnit.test( 'Sanity test, object creation and UI construction', 9, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ); var embed = new mw.mmv.ui.reuse.Embed( $qf );
assert.ok( embed, 'Embed UI element is created.' ); assert.ok( embed, 'Embed UI element is created.' );
assert.strictEqual( embed.$pane.length, 1, 'Pane div is created.' ); assert.strictEqual( embed.$pane.length, 1, 'Pane div is created.' );
assert.ok( embed.embedTextHtml, 'Html snipped text area created.' );
assert.ok( embed.embedTextWikitext, 'Wikitext snipped text area created.' ); assert.ok( embed.embedTextWikitext, 'Wikitext snipped text area created.' );
assert.ok( embed.embedSwitch, 'Snipped selection buttons created.' );
assert.ok( embed.embedWtSizeSwitch, 'Size selection menu for wikitext created.' ); assert.ok( embed.embedWtSizeSwitch, 'Size selection menu for wikitext created.' );
assert.ok( embed.embedHtmlSizeSwitch, 'Size selection menu for html created.' );
assert.strictEqual( embed.$currentMainEmbedText.length, 1, 'Size selection menu for html created.' ); assert.strictEqual( embed.$currentMainEmbedText.length, 1, 'Size selection menu for html created.' );
assert.ok( embed.currentSizeMenu, 'Size selection menu for html created.' ); assert.ok( embed.currentSizeMenu, 'Size selection menu for html created.' );
} ); } );
QUnit.test( 'changeSize(): Skip if no item selected.', 0, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ),
width = 10,
height = 20;
// deselect items
embed.embedSwitch.selectItem();
embed.setThumbnailURL = function() {
assert.ok( false, 'No item selected, this should not have been called.' );
};
embed.updateWtEmbedText = function() {
assert.ok( false, 'No item selected, this should not have been called.' );
};
embed.changeSize( width, height );
} );
QUnit.test( 'changeSize(): HTML size menu item selected.', 4, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ),
width = 10,
height = 20;
embed.embedSwitch.getSelectedItem = function() {
return { getData: function() { return 'html'; } };
};
embed.setThumbnailURL = function( thumb, w, h ) {
assert.strictEqual( thumb.url, undefined, 'Empty thumbnail passed.' );
assert.strictEqual( w, width, 'Correct width passed.' );
assert.strictEqual( h, height, 'Correct height passed.' );
};
embed.updateWtEmbedText = function () {
assert.ok( false, 'Dealing with HTML menu, this should not have been called.' );
};
embed.select = function( ) {
assert.ok( true, 'Item selected after update.' );
};
embed.changeSize( width, height );
} );
QUnit.test( 'changeSize(): Wikitext size menu item selected.', 2, function ( assert ) { QUnit.test( 'changeSize(): Wikitext size menu item selected.', 2, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ), var embed = new mw.mmv.ui.reuse.Embed( $qf ),
width = 10, width = 10,
height = 20; height = 20;
embed.embedSwitch.getSelectedItem = function() {
return { getData: function() { return 'wt'; } };
};
embed.setThumbnailURL = function() {
assert.ok( false, 'Dealing with wikitext menu, this should not have been called.' );
};
embed.updateWtEmbedText = function( w ) { embed.updateWtEmbedText = function( w ) {
assert.strictEqual( w, width, 'Correct width passed.' ); assert.strictEqual( w, width, 'Correct width passed.' );
}; };
@ -46,6 +96,52 @@
embed.changeSize( width, height ); embed.changeSize( width, height );
} ); } );
QUnit.test( 'setThumbnailURL(): Do nothing if set() not called before.', 0, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ),
width = 10,
height = 20;
embed.formatter.getThumbnailHtml = function() {
assert.ok( false, 'formatter.getThumbnailHtml() should not have been called.' );
};
embed.setThumbnailURL( {}, width, height );
} );
QUnit.test( 'setThumbnailURL():', 6, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ),
title = mw.Title.newFromText( 'File:Foobar.jpg' ),
src = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg',
url = 'https://commons.wikimedia.org/wiki/File:Foobar.jpg',
thumbUrl = 'https://upload.wikimedia.org/wikipedia/thumb/Foobar.jpg',
embedFileInfo = new mw.mmv.model.EmbedFileInfo( title, src, url ),
width = 10,
height = 20;
embed.set( { width: width, height: height }, embedFileInfo );
// Small image, no thumbnail info is passed
embed.formatter.getThumbnailHtml = function( info, url, w, h ) {
assert.strictEqual( info, embedFileInfo, 'Info passed correctly.' );
assert.strictEqual( url, src, 'Image src passed correctly.' );
assert.strictEqual( w, width, 'Correct width passed.' );
assert.strictEqual( h, height, 'Correct height passed.' );
};
embed.setThumbnailURL( {}, width, height );
// Small image, thumbnail info present
embed.formatter.getThumbnailHtml = function( info, url ) {
assert.strictEqual( url, thumbUrl, 'Image src passed correctly.' );
};
embed.setThumbnailURL( { url: thumbUrl }, width, height );
// Big image, thumbnail info present
embed.formatter.getThumbnailHtml = function( info, url ) {
assert.strictEqual( url, src, 'Image src passed correctly.' );
};
width = 1300;
embed.setThumbnailURL( { url: thumbUrl }, width, height );
} );
QUnit.test( 'updateWtEmbedText(): Do nothing if set() not called before.', 0, function ( assert ) { QUnit.test( 'updateWtEmbedText(): Do nothing if set() not called before.', 0, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ), var embed = new mw.mmv.ui.reuse.Embed( $qf ),
width = 10; width = 10;
@ -82,6 +178,12 @@
{ {
width: 2048, height: 1536, width: 2048, height: 1536,
expected: { expected: {
html: {
small: { width: 193, height: 145 },
medium: { width: 640, height: 480 },
large: { width: 1200, height: 900 },
original: { width: 2048, height: 1536 }
},
wikitext: { wikitext: {
small: { width: 300, height: 225 }, small: { width: 300, height: 225 },
medium: { width: 400, height: 300 }, medium: { width: 400, height: 300 },
@ -94,6 +196,12 @@
{ {
width: 201, height: 1536, width: 201, height: 1536,
expected: { expected: {
html: {
small: { width: 19, height: 145 },
medium: { width: 63, height: 480 },
large: { width: 118, height: 900 },
original: { width: 201, height: 1536 }
},
wikitext: {} wikitext: {}
} }
}, },
@ -102,6 +210,9 @@
{ {
width: 15, height: 20, width: 15, height: 20,
expected: { expected: {
html: {
original: { width: 15, height: 20 }
},
wikitext: {} wikitext: {}
} }
} }
@ -114,7 +225,7 @@
} }
} ); } );
QUnit.test( 'set():', 3, function ( assert ) { QUnit.test( 'set():', 4, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ), var embed = new mw.mmv.ui.reuse.Embed( $qf ),
title = mw.Title.newFromText( 'File:Foobar.jpg' ), title = mw.Title.newFromText( 'File:Foobar.jpg' ),
src = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg', src = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg',
@ -136,24 +247,24 @@
QUnit.test( 'updateMenuOptions():', 3, function ( assert ) { QUnit.test( 'updateMenuOptions():', 3, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ), var embed = new mw.mmv.ui.reuse.Embed( $qf ),
options = embed.embedWtSizeSwitch.getMenu().getItems(), options = embed.embedHtmlSizeSwitch.getMenu().getItems(),
width = 700, width = 700,
height = 500, height = 500,
sizes = embed.getSizeOptions( width, height ), sizes = embed.getSizeOptions( width, height ),
oldMessage = mw.message; oldMessage = mw.message;
mw.message = function( messageKey ) { mw.message = function( messageKey ) {
assert.ok( messageKey.match(/^multimediaviewer-(small|medium|large)/), 'messageKey passed correctly.' ); assert.ok( messageKey.match(/^multimediaviewer-(small|medium|original)/), 'messageKey passed correctly.' );
return { text: $.noop }; return { text: $.noop };
}; };
embed.updateMenuOptions( sizes.wikitext, options ); embed.updateMenuOptions( sizes.html, options );
mw.message = oldMessage; mw.message = oldMessage;
} ); } );
QUnit.test( 'empty():', 3, function ( assert ) { QUnit.test( 'empty():', 6, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ), var embed = new mw.mmv.ui.reuse.Embed( $qf ),
title = mw.Title.newFromText( 'File:Foobar.jpg' ), title = mw.Title.newFromText( 'File:Foobar.jpg' ),
src = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg', src = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg',
@ -163,17 +274,21 @@
height = 20; height = 20;
embed.set( { width: width, height: height }, embedFileInfo ); embed.set( { width: width, height: height }, embedFileInfo );
embed.setThumbnailURL( {}, width, height );
embed.updateWtEmbedText( width ); embed.updateWtEmbedText( width );
assert.notStrictEqual( embed.embedTextHtml.getValue(), '', 'embedTextHtml is not empty.' );
assert.notStrictEqual( embed.embedTextWikitext.getValue(), '', 'embedTextWikitext is not empty.' ); assert.notStrictEqual( embed.embedTextWikitext.getValue(), '', 'embedTextWikitext is not empty.' );
embed.empty(); embed.empty();
assert.strictEqual( embed.embedTextHtml.getValue(), '', 'embedTextHtml is empty.' );
assert.strictEqual( embed.embedTextWikitext.getValue(), '', 'embedTextWikitext is empty.' ); assert.strictEqual( embed.embedTextWikitext.getValue(), '', 'embedTextWikitext is empty.' );
assert.ok( ! embed.embedHtmlSizeSwitch.getMenu().isVisible(), 'Html size menu should be hidden.' );
assert.ok( ! embed.embedWtSizeSwitch.getMenu().isVisible(), 'Wikitext size menu should be hidden.' ); assert.ok( ! embed.embedWtSizeSwitch.getMenu().isVisible(), 'Wikitext size menu should be hidden.' );
} ); } );
QUnit.test( 'attach()/unattach():', 2, function ( assert ) { QUnit.test( 'attach()/unattach():', 5, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf ), var embed = new mw.mmv.ui.reuse.Embed( $qf ),
title = mw.Title.newFromText( 'File:Foobar.jpg' ), title = mw.Title.newFromText( 'File:Foobar.jpg' ),
src = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg', src = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg',
@ -187,18 +302,28 @@
embed.selectAllOnEvent = function() { embed.selectAllOnEvent = function() {
assert.ok( false, 'selectAllOnEvent should not have been called.' ); assert.ok( false, 'selectAllOnEvent should not have been called.' );
}; };
embed.handleTypeSwitch = function() {
assert.ok( false, 'handleTypeSwitch should not have been called.' );
};
embed.handleSizeSwitch = function() { embed.handleSizeSwitch = function() {
assert.ok( false, 'handleTypeSwitch should not have been called.' ); assert.ok( false, 'handleTypeSwitch should not have been called.' );
}; };
// Triggering action events before attaching should do nothing // Triggering action events before attaching should do nothing
embed.embedTextHtml.$element.focus();
embed.embedTextWikitext.$element.focus(); embed.embedTextWikitext.$element.focus();
embed.embedSwitch.emit( 'select' );
embed.embedHtmlSizeSwitch.getMenu().emit(
'select', embed.embedHtmlSizeSwitch.getMenu().getSelectedItem() );
embed.embedWtSizeSwitch.getMenu().emit( embed.embedWtSizeSwitch.getMenu().emit(
'select', embed.embedWtSizeSwitch.getMenu().getSelectedItem() ); 'select', embed.embedWtSizeSwitch.getMenu().getSelectedItem() );
embed.selectAllOnEvent = function() { embed.selectAllOnEvent = function() {
assert.ok( true, 'selectAllOnEvent was called.' ); assert.ok( true, 'selectAllOnEvent was called.' );
}; };
embed.handleTypeSwitch = function() {
assert.ok( true, 'handleTypeSwitch was called.' );
};
embed.handleSizeSwitch = function() { embed.handleSizeSwitch = function() {
assert.ok( true, 'handleTypeSwitch was called.' ); assert.ok( true, 'handleTypeSwitch was called.' );
}; };
@ -206,7 +331,11 @@
embed.attach(); embed.attach();
// Action events should be handled now // Action events should be handled now
embed.embedTextHtml.$element.focus();
embed.embedTextWikitext.$element.focus(); embed.embedTextWikitext.$element.focus();
embed.embedSwitch.emit( 'select' );
embed.embedHtmlSizeSwitch.getMenu().emit(
'select', embed.embedHtmlSizeSwitch.getMenu().getSelectedItem() );
embed.embedWtSizeSwitch.getMenu().emit( embed.embedWtSizeSwitch.getMenu().emit(
'select', embed.embedWtSizeSwitch.getMenu().getSelectedItem() ); 'select', embed.embedWtSizeSwitch.getMenu().getSelectedItem() );
@ -214,6 +343,9 @@
embed.selectAllOnEvent = function() { embed.selectAllOnEvent = function() {
assert.ok( false, 'selectAllOnEvent should not have been called.' ); assert.ok( false, 'selectAllOnEvent should not have been called.' );
}; };
embed.handleTypeSwitch = function() {
assert.ok( false, 'handleTypeSwitch should not have been called.' );
};
embed.handleSizeSwitch = function() { embed.handleSizeSwitch = function() {
assert.ok( false, 'handleTypeSwitch should not have been called.' ); assert.ok( false, 'handleTypeSwitch should not have been called.' );
}; };
@ -221,9 +353,27 @@
embed.unattach(); embed.unattach();
// Triggering action events now that we are unattached should do nothing // Triggering action events now that we are unattached should do nothing
embed.embedTextHtml.$element.focus();
embed.embedTextWikitext.$element.focus(); embed.embedTextWikitext.$element.focus();
embed.embedSwitch.emit( 'select' );
embed.embedHtmlSizeSwitch.getMenu().emit(
'select', embed.embedHtmlSizeSwitch.getMenu().getSelectedItem() );
embed.embedWtSizeSwitch.getMenu().emit( embed.embedWtSizeSwitch.getMenu().emit(
'select', embed.embedWtSizeSwitch.getMenu().getSelectedItem() ); 'select', embed.embedWtSizeSwitch.getMenu().getSelectedItem() );
} ); } );
QUnit.test( 'handleTypeSwitch():', 2, function ( assert ) {
var embed = new mw.mmv.ui.reuse.Embed( $qf );
// HTML selected
embed.handleTypeSwitch( { getData: function() { return 'html'; } } );
assert.ok( ! embed.embedWtSizeSwitch.getMenu().isVisible(), 'Wikitext size menu should be hidden.' );
// Wikitext selected
embed.handleTypeSwitch( { getData: function() { return 'wt'; } } );
assert.ok( ! embed.embedHtmlSizeSwitch.getMenu().isVisible(), 'HTML size menu should be hidden.' );
} );
}( mediaWiki, jQuery ) ); }( mediaWiki, jQuery ) );