Change attribution and download interface

- Use Codex styles for mmv.ui.reuse
- Replace unofficial component dropdown with Codex Select and Button
components.
- Drop OOUI dependencies

Bug: T340258
Change-Id: I539d1b5f0d7e3c02f767807da57324ea6a36ad5b
This commit is contained in:
Simon Legner 2024-05-04 17:00:17 +03:00 committed by Jdlrobson
parent 842cdb1a24
commit e0aa14529c
18 changed files with 256 additions and 789 deletions

View file

@ -222,6 +222,7 @@
"oojs-ui"
],
"messages": [
"multimediaviewer-copy-button",
"multimediaviewer-default-embed-dimensions",
"multimediaviewer-original-embed-dimensions",
"multimediaviewer-xl-embed-dimensions",
@ -248,9 +249,7 @@
"codex-styles",
"mediawiki.widgets",
"mmv",
"mmv.ui.ondemandshareddependencies",
"oojs",
"oojs-ui"
"mmv.ui.ondemandshareddependencies"
],
"messages": [
"multimediaviewer-download",
@ -258,7 +257,6 @@
"multimediaviewer-download-attribution-cta-header",
"multimediaviewer-download-link",
"multimediaviewer-download-optional-attribution-cta-header",
"multimediaviewer-download-attribution-copy-button",
"multimediaviewer-download-attribution-copy",
"multimediaviewer-download-attribution",
"multimediaviewer-attr-plain",
@ -268,7 +266,6 @@
"mmv.ui.reuse.shareembed": {
"packageFiles": [
"mmv.ui.reuse.shareembed/index.js",
"mmv.ui.reuse.shareembed/mmv.ui.reuse.tab.js",
"mmv.ui.reuse.shareembed/mmv.ui.reuse.share.js",
"mmv.ui.reuse.shareembed/mmv.ui.reuse.embed.js"
],
@ -277,8 +274,7 @@
"mmv.ui.reuse.shareembed/mmv.ui.reuse.embed.less"
],
"dependencies": [
"oojs",
"oojs-ui",
"codex-styles",
"mediawiki.user",
"mediawiki.widgets",
"mmv.ui.ondemandshareddependencies"
@ -390,7 +386,6 @@
"tests/qunit/mmv/ui/mmv.ui.reuse.dialog.test.js",
"tests/qunit/mmv/ui/mmv.ui.reuse.embed.test.js",
"tests/qunit/mmv/ui/mmv.ui.reuse.share.test.js",
"tests/qunit/mmv/ui/mmv.ui.reuse.tab.test.js",
"tests/qunit/mmv/ui/mmv.ui.reuse.utils.test.js",
"tests/qunit/mmv/ui/mmv.ui.truncatableTextField.test.js",
"tests/qunit/mmv/ui/mmv.ui.viewingOptions.test.js",

View file

@ -129,7 +129,7 @@
"multimediaviewer-download-attribution-cta-header": "You need to attribute the author",
"multimediaviewer-download-optional-attribution-cta-header": "You can attribute the author",
"multimediaviewer-download-attribution-cta": "Show me how",
"multimediaviewer-download-attribution-copy-button": "Copy",
"multimediaviewer-copy-button": "Copy",
"multimediaviewer-download-attribution-copy": "Select and copy (if supported) the attribution text for this file",
"multimediaviewer-reuse-warning-deletion": "This file is considered for deletion.",
"multimediaviewer-reuse-warning-nonfree": "This file does not have a free license.",

View file

@ -142,7 +142,7 @@
"multimediaviewer-download-attribution-cta-header": "Header for telling the user that the author of an image must be attributed, during a download action. See also {{msg-mw|multimediaviewer-download-optional-attribution-cta-header}}.",
"multimediaviewer-download-optional-attribution-cta-header": "Header for inviting the user to attribute author of the image during a download action. This is used for images where attribution is not a legal requirement. See also {{msg-mw|multimediaviewer-download-attribution-cta-header}}.",
"multimediaviewer-download-attribution-cta": "Call to action for a user to find out how to attribute the author of an image.",
"multimediaviewer-download-attribution-copy-button": "Tooltip for a button that to select and copy the attribution of a file (if supported by the browser) in the download panel, that is displayed when hovered over.",
"multimediaviewer-copy-button": "Tooltip for a button that to select and copy the displayed attribution or reuse code of a file (if supported by the browser).",
"multimediaviewer-download-attribution-copy": "Text of the tooltip for the button to select and copy the attribution of a file (if supported by the browser) in the download panel, that is displayed when hovered over.",
"multimediaviewer-reuse-warning-deletion": "Warning message shown in the share/embed/download panels for files tagged with a deletion template ('''not just deleted!'''). Followed by {{msg-mw|multimediaviewer-reuse-warning-generic}}.",
"multimediaviewer-reuse-warning-nonfree": "Warning message shown in the share/embed/download panels for files under a nonfree license / copyright tag, such as fair use. Followed by {{msg-mw|multimediaviewer-reuse-warning-generic}}.",

View file

@ -114,7 +114,9 @@ const { EmbedFileFormatter, Utils } = require( 'mmv.ui.ondemandshareddependencie
}
createAttributionButton( $container ) {
this.$attributionInput = $( '<input>' ).addClass( 'cdx-text-input__input' );
[ this.$attributionInput, this.$attributionInputDiv ] = this.utils.createInputWithCopy(
mw.message( 'multimediaviewer-download-attribution-copy' ).text(), ''
);
const $header = $( '<div>' )
.addClass( 'cdx-dialog__header' )
@ -143,29 +145,12 @@ const { EmbedFileFormatter, Utils } = require( 'mmv.ui.ondemandshareddependencie
);
this.selectAttribution( 'plain' );
const $copyButton = $( '<button>' )
.addClass( 'cdx-button cdx-button--action-default cdx-button--weight-normal cdx-button--size-medium cdx-button--framed' )
.addClass( 'mw-mmv-pt-0 mw-mmv-pb-0' ) // override padding provided by ".oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button, button"
.attr( 'title', mw.msg( 'multimediaviewer-download-attribution-copy' ) )
.append( $( '<span>' ).addClass( 'cdx-button__icon cdx-button__icon--copy' ).attr( 'aria-hidden', 'true' ) )
.append( mw.message( 'multimediaviewer-download-attribution-copy-button' ).text() )
// navigator.clipboard() is not supported in Safari 11.1, iOS Safari 11.3-11.4
// eslint-disable-next-line compat/compat
.on( 'click', () => navigator.clipboard && navigator.clipboard.writeText && navigator.clipboard.writeText( this.$attributionInput.val() ) );
$( '<div>' )
.addClass( 'cdx-dialog__body mw-mmv-pt-0 mw-mmv-pb-150' )
.append(
this.$attributionHowHeader,
$attributionTabs,
$( '<div>' )
.addClass( 'mw-mmv-flex mw-mmv-gap-50 mw-mmv-mt-75' )
.append(
$( '<div>' )
.addClass( 'cdx-text-input mw-mmv-flex-grow-1' )
.append( this.$attributionInput ),
$copyButton
)
this.$attributionInputDiv.addClass( ' mw-mmv-mt-75' )
)
.appendTo( $container );
}

View file

@ -28,6 +28,53 @@ const { HtmlUtils } = require( 'mmv.bootstrap' );
this.htmlUtils = new HtmlUtils();
}
/**
* Creates header from given options.
*
* @param {string} text
* @return {jQuery}
*/
createHeader( text ) {
const $header = $( '<div>' ).addClass( 'cdx-dialog__header' );
$( '<p>' )
.addClass( 'cdx-dialog__header__title' )
.text( text )
.appendTo( $header );
return $header;
}
/**
* Creates input element with copy button from given options.
*
* @param {string} title
* @param {string} placeholder
* @return {jQuery[]} [$input, $div]
*/
createInputWithCopy( title, placeholder ) {
const $input = $( '<input>' )
.addClass( 'cdx-text-input__input' )
.attr( 'placeholder', placeholder );
const $copyButton = $( '<button>' )
.addClass( 'cdx-button cdx-button--action-default cdx-button--weight-normal cdx-button--size-medium cdx-button--framed' )
.addClass( 'mw-mmv-pt-0 mw-mmv-pb-0' ) // override padding provided by ".oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button, button"
.attr( 'title', title )
.append( $( '<span>' ).addClass( 'cdx-button__icon cdx-button__icon--copy' ).attr( 'aria-hidden', 'true' ) )
.append( mw.message( 'multimediaviewer-copy-button' ).text() )
// navigator.clipboard() is not supported in Safari 11.1, iOS Safari 11.3-11.4
// eslint-disable-next-line compat/compat
.on( 'click', () => navigator.clipboard && navigator.clipboard.writeText && navigator.clipboard.writeText( $input.val() ) );
const $div = $( '<div>' )
.addClass( 'mw-mmv-flex mw-mmv-gap-50' )
.append(
$( '<div>' )
.addClass( 'cdx-text-input mw-mmv-flex-grow-1' )
.append( $input ),
$copyButton
);
return [ $input, $div ];
}
/**
* Creates select menu from given options.
*
@ -48,46 +95,6 @@ const { HtmlUtils } = require( 'mmv.bootstrap' );
return $select;
}
/**
* Creates pulldown menu from given options.
*
* @param {string[]} options
* @param {string[]} classes
* @param {string} def
* @return {OO.ui.DropdownWidget}
*/
createPulldownMenu( options, classes, def ) {
const items = [];
const choices = {};
// eslint-disable-next-line mediawiki/class-doc
const dropdown = new OO.ui.DropdownWidget( {
classes: classes
} );
for ( let i = 0; i < options.length; i++ ) {
const option = options[ i ];
choices[ option ] = new OO.ui.MenuOptionWidget( {
data: {
name: option,
height: null,
width: null
},
label: this.getDimensionsMessageHtml( option, 0, 0 ),
autoFitLabel: false
} );
items.push( choices[ option ] );
}
dropdown.getMenu()
.addItems( items )
.chooseItem( choices[ def ] );
return dropdown;
}
/**
* 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
@ -105,34 +112,6 @@ const { HtmlUtils } = require( 'mmv.bootstrap' );
$.Deferred().reject();
}
/**
* Updates the menu options based on calculated sizes.
*
* @private
* @param {Object} sizes
* @param {OO.ui.MenuOptionWidget[]} options
*/
updateMenuOptions( sizes, options ) {
for ( let i = 0; i < options.length; i++ ) {
const option = options[ i ];
const data = option.getData();
if ( sizes[ data.name ] ) {
option.setDisabled( false );
// These values are later used when the item is selected
data.width = sizes[ data.name ].width;
data.height = sizes[ data.name ].height;
const $label = $( '<span>' ).html( this.getDimensionsMessageHtml( data.name, data.width, data.height ) );
option.setLabel( $label );
} else {
option.setDisabled( true );
}
}
}
/**
* Updates the select options based on calculated sizes.
*

View file

@ -17,6 +17,5 @@
const Embed = require( './mmv.ui.reuse.embed.js' );
const Share = require( './mmv.ui.reuse.share.js' );
const Tab = require( './mmv.ui.reuse.tab.js' );
module.exports = { Embed, Share, Tab };
module.exports = { Embed, Share };

View file

@ -16,7 +16,7 @@
*/
const { EmbedFileFormatter, Utils } = require( 'mmv.ui.ondemandshareddependencies' );
const Tab = require( './mmv.ui.reuse.tab.js' );
const { UiElement } = require( 'mmv' );
( function () {
@ -24,7 +24,7 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
* UI component that provides the user html/wikitext snippets needed to share
* and/or embed a media asset.
*/
class Embed extends Tab {
class Embed extends UiElement {
/**
* @param {jQuery} $container
*/
@ -41,56 +41,16 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
/** @property {Utils} utils - */
this.utils = new Utils();
/**
* Indicates whether or not the default option has been reset for both size menus.
*
* @property {boolean}
*/
this.isSizeMenuDefaultReset = false;
this.utils.createHeader( mw.message( 'multimediaviewer-embed-tab' ).text() )
.appendTo( $container );
this.$pane.addClass( 'mw-mmv-embed-pane' );
const $body = $( '<div>' )
.addClass( 'cdx-dialog__body mw-mmv-pt-0 mw-mmv-pb-150' )
.appendTo( $container );
this.$pane.appendTo( this.$container );
this.createSnippetTextAreas( this.$pane );
this.createSnippetSelectionButtons( this.$pane );
this.createSizePulldownMenus( this.$pane );
/**
* Currently selected embed snippet.
*
* @property {mw.widgets.CopyTextLayout}
*/
this.currentMainEmbedText = mw.user.isAnon() ? this.embedTextHtml : this.embedTextWikitext;
/**
* Default item for the html size menu.
*
* @property {OO.ui.MenuOptionWidget}
*/
this.defaultHtmlItem = this.embedSizeSwitchHtml.getMenu().findSelectedItem();
/**
* Default item for the wikitext size menu.
*
* @property {OO.ui.MenuOptionWidget}
*/
this.defaultWikitextItem = this.embedSizeSwitchWikitext.getMenu().findSelectedItem();
/**
* Currently selected size menu.
*
* @property {OO.ui.MenuSelectWidget}
*/
this.currentSizeMenu = mw.user.isAnon() ? this.embedSizeSwitchHtml.getMenu() : this.embedSizeSwitchWikitext.getMenu();
/**
* Current default item.
*
* @property {OO.ui.MenuOptionWidget}
*/
this.currentDefaultItem = mw.user.isAnon() ? this.defaultHtmlItem : this.defaultWikitextItem;
this.createSnippetSelectionButtons( $body );
this.createSizePulldownMenus( $body );
this.createSnippetTextAreas( $body );
}
/**
@ -99,44 +59,21 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
* @param {jQuery} $container
*/
createSnippetTextAreas( $container ) {
this.embedTextHtml = new mw.widgets.CopyTextLayout( {
help: mw.message( 'multimediaviewer-embed-explanation' ).text(),
helpInline: true,
align: 'top',
multiline: true,
textInput: {
placeholder: mw.message( 'multimediaviewer-reuse-loading-placeholder' ).text(),
autosize: true,
maxRows: 5
},
button: {
title: mw.msg( 'multimediaviewer-reuse-copy-embed' )
}
} );
[ this.$embedTextHtml, this.$embedTextHtmlDiv ] = this.utils.createInputWithCopy(
mw.message( 'multimediaviewer-reuse-copy-embed' ).text(),
mw.message( 'multimediaviewer-reuse-loading-placeholder' ).text()
);
this.$embedTextHtml.attr( 'title', mw.message( 'multimediaviewer-embed-explanation' ).text() );
this.embedTextWikitext = new mw.widgets.CopyTextLayout( {
help: mw.message( 'multimediaviewer-embed-explanation' ).text(),
helpInline: true,
align: 'top',
multiline: true,
textInput: {
// The following classes are used here:
// * mw-editfont-monospace
// * mw-editfont-sans-serif
// * mw-editfont-serif
classes: [ `mw-editfont-${ mw.user.options.get( 'editfont' ) }` ],
placeholder: mw.message( 'multimediaviewer-reuse-loading-placeholder' ).text(),
autosize: true,
maxRows: 5
},
button: {
title: mw.msg( 'multimediaviewer-reuse-copy-embed' )
}
} );
[ this.$embedTextWikitext, this.$embedTextWikitextDiv ] = this.utils.createInputWithCopy(
mw.message( 'multimediaviewer-reuse-copy-embed' ).text(),
mw.message( 'multimediaviewer-reuse-loading-placeholder' ).text()
);
this.$embedTextWikitext.attr( 'title', mw.message( 'multimediaviewer-embed-explanation' ).text() );
$container.append(
this.embedTextHtml.$element,
this.embedTextWikitext.$element
this.$embedTextHtmlDiv,
this.$embedTextWikitextDiv
);
}
@ -146,30 +83,17 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
* @param {jQuery} $container
*/
createSnippetSelectionButtons( $container ) {
this.embedSwitch = new OO.ui.ButtonSelectWidget( {
classes: [ 'mw-mmv-embed-select' ]
} );
const wikitextButtonOption = new OO.ui.ButtonOptionWidget( {
data: 'wikitext',
label: mw.message( 'multimediaviewer-embed-wt' ).text()
} );
const htmlButtonOption = new OO.ui.ButtonOptionWidget( {
data: 'html',
label: mw.message( 'multimediaviewer-embed-html' ).text()
} );
this.embedSwitch.addItems( [
wikitextButtonOption,
htmlButtonOption
] );
$( '<p>' )
.append( this.embedSwitch.$element )
.appendTo( $container );
// Logged-out defaults to 'html', logged-in to 'wikitext'
this.embedSwitch.selectItem( mw.user.isAnon() ? htmlButtonOption : wikitextButtonOption );
const $embedSwitch = $( '<div>' ).addClass( 'cdx-tabs mw-mmv-mb-75' ).appendTo( $container );
const $embedSwitchHeader = $( '<div>' ).addClass( 'cdx-tabs__header' ).appendTo( $embedSwitch );
this.$embedSwitchList = $( '<div>' ).addClass( 'cdx-tabs__list' ).attr( 'role', 'tablist' ).appendTo( $embedSwitchHeader );
[ 'wikitext', 'html' ].forEach( ( name ) => $( '<button>' )
.addClass( 'cdx-tabs__list__item' )
.attr( 'role', 'tab' )
.attr( 'data-name', name )
.text( mw.message( name === 'wikitext' ? 'multimediaviewer-embed-wt' : 'multimediaviewer-embed-html' ).text() )
.on( 'click', () => this.handleTypeSwitch( name ) )
.appendTo( this.$embedSwitchList )
);
}
/**
@ -179,40 +103,33 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
*/
createSizePulldownMenus( $container ) {
// Wikitext sizes pulldown menu
this.embedSizeSwitchWikitext = this.utils.createPulldownMenu(
this.$embedSizeSwitchWikitext = this.utils.createSelectMenu(
[ 'default', 'small', 'medium', 'large' ],
[],
'default'
);
// Html sizes pulldown menu
this.embedSizeSwitchHtml = this.utils.createPulldownMenu(
this.$embedSizeSwitchHtml = this.utils.createSelectMenu(
[ 'small', 'medium', 'large', 'original' ],
[],
'original'
);
this.embedSizeSwitchHtmlLayout = new OO.ui.FieldLayout( this.embedSizeSwitchHtml, { align: 'top' } );
this.embedSizeSwitchWikitextLayout = new OO.ui.FieldLayout( this.embedSizeSwitchWikitext, { align: 'top' } );
$container.append(
this.embedSizeSwitchHtmlLayout.$element,
this.embedSizeSwitchWikitextLayout.$element
);
$( '<div>' ).addClass( 'mw-mmv-flex mw-mmv-mb-75' ).append(
this.$embedSizeSwitchHtml,
this.$embedSizeSwitchWikitext
).appendTo( $container );
}
/**
* Registers listeners.
*/
attach() {
// Register handler for switching between wikitext/html snippets
this.embedSwitch.on( 'select', this.handleTypeSwitch.bind( this ) );
this.handleTypeSwitch( this.embedSwitch.findSelectedItem() );
// Logged-out defaults to 'html', logged-in to 'wikitext'
this.handleTypeSwitch( mw.user.isAnon() ? 'html' : 'wikitext' );
// Register handlers for switching between file sizes
this.embedSizeSwitchHtml.getMenu().on( 'choose', this.handleSizeSwitch.bind( this ) );
this.embedSizeSwitchWikitext.getMenu().on( 'choose', this.handleSizeSwitch.bind( this ) );
this.$embedSizeSwitchHtml.on( 'change', () => this.handleSizeSwitch() );
this.$embedSizeSwitchWikitext.on( 'change', () => this.handleSizeSwitch() );
}
/**
@ -221,94 +138,51 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
unattach() {
super.unattach();
this.embedSwitch.off( 'select' );
this.embedSizeSwitchHtml.getMenu().off( 'choose' );
this.embedSizeSwitchWikitext.getMenu().off( 'choose' );
this.$embedSizeSwitchHtml.off( 'change' );
this.$embedSizeSwitchWikitext.off( 'change' );
}
/**
* Handles size menu change events.
*
* @param {OO.ui.MenuOptionWidget} item
*/
handleSizeSwitch( item ) {
const value = item.getData();
this.changeSize( value.width, value.height );
handleSizeSwitch() {
// eslint-disable-next-line no-jquery/no-sizzle
const $html = this.$embedSizeSwitchHtml.find( ':selected' );
if ( $html.length ) {
this.updateEmbedHtml( {}, $html.attr( 'data-width' ), $html.attr( 'data-height' ) );
}
// eslint-disable-next-line no-jquery/no-sizzle
const $wikitext = this.$embedSizeSwitchWikitext.find( ':selected' );
if ( $wikitext.length ) {
this.updateEmbedWikitext( $wikitext.attr( 'data-width' ) );
}
}
/**
* Handles snippet type switch.
*
* @param {OO.ui.MenuOptionWidget} item
* @param {string} value 'html' or 'wikitext'
*/
handleTypeSwitch( item ) {
const value = item.getData();
handleTypeSwitch( value ) {
this.$embedSwitchList.children().each( ( _i, element ) => {
const $element = $( element );
$element.attr( 'aria-selected', $element.attr( 'data-name' ) === value );
} );
if ( value === 'html' ) {
this.currentMainEmbedText = this.embedTextHtml;
this.embedSizeSwitchWikitext.getMenu().toggle( false );
this.$embedTextHtmlDiv.toggle( value === 'html' );
this.$embedSizeSwitchHtml.toggle( value === 'html' );
this.currentSizeMenu = this.embedSizeSwitchHtml.getMenu();
this.currentDefaultItem = this.defaultHtmlItem;
} else if ( value === 'wikitext' ) {
this.currentMainEmbedText = this.embedTextWikitext;
this.embedSizeSwitchHtml.getMenu().toggle( false );
this.currentSizeMenu = this.embedSizeSwitchWikitext.getMenu();
this.currentDefaultItem = this.defaultWikitextItem;
}
this.embedTextHtml.toggle( value === 'html' );
this.embedSizeSwitchHtmlLayout.toggle( value === 'html' );
this.embedTextWikitext.toggle( value === 'wikitext' );
this.embedSizeSwitchWikitextLayout.toggle( value === 'wikitext' );
// Reset current selection to default when switching the first time
if ( !this.isSizeMenuDefaultReset ) {
this.resetCurrentSizeMenuToDefault();
this.isSizeMenuDefaultReset = true;
}
this.select();
this.$embedTextWikitextDiv.toggle( value === 'wikitext' );
this.$embedSizeSwitchWikitext.toggle( value === 'wikitext' );
}
/**
* Reset current menu selection to default item.
*/
resetCurrentSizeMenuToDefault() {
this.currentSizeMenu.chooseItem( this.currentDefaultItem );
// Force select logic to update the selected item bar, otherwise we end up
// with the wrong label. This is implementation dependent and maybe it should
// be done via a to flag to OO.ui.SelectWidget.prototype.chooseItem()?
this.currentSizeMenu.emit( 'select', this.currentDefaultItem );
}
/**
* Changes the size, takes different actions based on which sort of
* embed is currently chosen.
*
* @param {number} width New width to set
* @param {number} height New height to set
*/
changeSize( width, height ) {
const currentItem = this.embedSwitch.findSelectedItem();
if ( currentItem === null ) {
return;
}
switch ( currentItem.getData() ) {
case 'html':
this.updateEmbedHtml( {}, width, height );
break;
case 'wikitext':
this.updateEmbedWikitext( width );
break;
}
this.select();
this.$embedSizeSwitchWikitext.val( 'default' );
this.$embedSizeSwitchHtml.val( 'original' );
this.handleSizeSwitch();
}
/**
@ -332,7 +206,7 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
src = this.embedFileInfo.imageInfo.url;
}
this.embedTextHtml.textInput.setValue(
this.$embedTextHtml.val(
this.formatter.getThumbnailHtml( this.embedFileInfo, src, width, height )
);
}
@ -349,25 +223,11 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
return;
}
this.embedTextWikitext.textInput.setValue(
this.$embedTextWikitext.val(
this.formatter.getThumbnailWikitextFromEmbedFileInfo( this.embedFileInfo, width )
);
}
/**
* Shows the pane.
*/
show() {
super.show();
// Force update size on multiline inputs, as they may have be
// calculated while not visible.
this.currentMainEmbedText.textInput.valCache = null;
this.currentMainEmbedText.textInput.adjustSize();
this.select();
}
/**
* Gets size options for html and wikitext snippets.
*
@ -395,10 +255,6 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
* @param {string} [alt]
*/
set( image, repo, caption, alt ) {
const htmlSizeSwitch = this.embedSizeSwitchHtml.getMenu();
const htmlSizeOptions = htmlSizeSwitch.getItems();
const wikitextSizeSwitch = this.embedSizeSwitchWikitext.getMenu();
const wikitextSizeOptions = wikitextSizeSwitch.getItems();
const sizes = this.getSizeOptions( image.width, image.height );
this.embedFileInfo = { imageInfo: image, repoInfo: repo };
@ -409,17 +265,15 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
this.embedFileInfo.alt = alt;
}
this.utils.updateMenuOptions( sizes.html, htmlSizeOptions );
this.utils.updateMenuOptions( sizes.wikitext, wikitextSizeOptions );
this.utils.updateSelectOptions( sizes.html, this.$embedSizeSwitchHtml.children() );
this.utils.updateSelectOptions( sizes.wikitext, this.$embedSizeSwitchWikitext.children() );
// Reset defaults
this.isSizeMenuDefaultReset = false;
this.resetCurrentSizeMenuToDefault();
this.utils.getThumbnailUrlPromise( this.LARGE_IMAGE_WIDTH_THRESHOLD )
.done( ( thumbnail ) => {
this.updateEmbedHtml( thumbnail );
this.select();
} );
}
@ -427,18 +281,11 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
* @inheritdoc
*/
empty() {
this.embedTextHtml.textInput.setValue( '' );
this.embedTextWikitext.textInput.setValue( '' );
this.$embedTextHtml.val( '' );
this.$embedTextWikitext.val( '' );
this.embedSizeSwitchHtml.getMenu().toggle( false );
this.embedSizeSwitchWikitext.getMenu().toggle( false );
}
/**
* Selects the text in the current textbox by triggering a focus event.
*/
select() {
this.currentMainEmbedText.selectText();
this.$embedSizeSwitchHtml.toggle( false );
this.$embedSizeSwitchWikitext.toggle( false );
}
/**

View file

@ -16,49 +16,35 @@
*/
const { getMediaHash } = require( 'mmv.head' );
const Tab = require( './mmv.ui.reuse.tab.js' );
const { Utils } = require( 'mmv.ui.ondemandshareddependencies' );
const { UiElement } = require( 'mmv' );
( function () {
/**
* Represents the file reuse dialog and link to open it.
*/
class Share extends Tab {
class Share extends UiElement {
/**
* @param {jQuery} $container
*/
constructor( $container ) {
super( $container );
this.init();
}
init() {
this.$pane.addClass( 'mw-mmv-share-pane' )
.appendTo( this.$container );
this.utils = new Utils();
this.utils.createHeader( mw.message( 'multimediaviewer-share-tab' ).text() )
.appendTo( $container );
this.pageInput = new mw.widgets.CopyTextLayout( {
help: mw.message( 'multimediaviewer-share-explanation' ).text(),
helpInline: true,
align: 'top',
textInput: {
placeholder: mw.message( 'multimediaviewer-reuse-loading-placeholder' ).text()
},
button: {
label: '',
title: mw.msg( 'multimediaviewer-reuse-copy-share' )
}
} );
const $body = $( '<div>' )
.addClass( 'cdx-dialog__body mw-mmv-pt-0' )
.appendTo( $container );
this.$pageLink = $( '<a>' )
.addClass( 'mw-mmv-share-page-link' )
.prop( 'alt', mw.message( 'multimediaviewer-link-to-page' ).text() )
.prop( 'target', '_blank' )
.text( '\u00A0' )
.appendTo( this.$pane );
this.pageInput.$element.appendTo( this.$pane );
this.$pane.appendTo( this.$container );
[ this.$pageInput, this.$pageInputDiv ] = this.utils.createInputWithCopy(
mw.message( 'multimediaviewer-reuse-copy-share' ).text(),
mw.message( 'multimediaviewer-reuse-loading-placeholder' ).text()
);
this.$pageInput.attr( 'title', mw.message( 'multimediaviewer-share-explanation' ).text() );
this.$pageInputDiv.appendTo( $body );
}
/**
@ -66,7 +52,6 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
*/
show() {
super.show();
this.select();
}
/**
@ -75,27 +60,14 @@ const Tab = require( './mmv.ui.reuse.tab.js' );
*/
set( image ) {
const url = image.descriptionUrl + getMediaHash( image.title );
this.pageInput.textInput.setValue( url );
this.select();
this.$pageLink.prop( 'href', url );
this.$pageInput.val( url );
}
/**
* @inheritdoc
*/
empty() {
this.pageInput.textInput.setValue( '' );
this.$pageLink.prop( 'href', null );
}
/**
* Selects the text in the readonly textbox.
*/
select() {
this.pageInput.selectText();
this.$pageInput.val( '' );
}
}

View file

@ -1,57 +0,0 @@
/*
* This file is part of the MediaWiki extension MediaViewer.
*
* MediaViewer is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* MediaViewer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MediaViewer. If not, see <http://www.gnu.org/licenses/>.
*/
const { UiElement } = require( 'mmv' );
( function () {
/**
* A tab in a pane component
*/
class Tab extends UiElement {
/**
* @param {jQuery} $container
*/
constructor( $container ) {
super( $container );
/**
* Container for the tab.
*
* @property {jQuery}
*/
this.$pane = $( '<div>' ).addClass( 'mw-mmv-reuse-pane' );
}
/**
* Shows the pane.
*/
show() {
this.$pane.addClass( 'active' );
}
/**
* Hides the pane.
*/
hide() {
this.$pane.removeClass( 'active' );
}
}
module.exports = Tab;
}() );

View file

@ -61,4 +61,8 @@
.mw-mmv-flex-grow-1 {
flex-grow: 1;
}
.cdx-button__icon--copy {
.cdx-mixin-css-icon( @cdx-icon-copy, @param-is-button-icon: true );
}
}

View file

@ -22,8 +22,4 @@
.cdx-button__icon--download {
.cdx-mixin-css-icon( @cdx-icon-download, @param-is-button-icon: true );
}
.cdx-button__icon--copy {
.cdx-mixin-css-icon( @cdx-icon-copy, @param-is-button-icon: true );
}
}

View file

@ -31,16 +31,6 @@ const Dialog = require( './mmv.ui.dialog.js' );
constructor( $container, $openButton, config ) {
super( $container, $openButton, config );
/**
* @property {Object.<string, UiElement>} tabs List of tab ui objects.
*/
this.tabs = null;
/**
* @property {Object.<string, OO.ui.MenuOptionWidget>} ooTabs List of tab OOUI objects.
*/
this.ooTabs = null;
this.loadDependencies.push( 'mmv.ui.reuse.shareembed' );
this.$dialog.addClass( 'mw-mmv-reuse-dialog' );
@ -48,98 +38,6 @@ const Dialog = require( './mmv.ui.dialog.js' );
this.eventPrefix = 'use-this-file';
}
// FIXME this should happen outside the dialog and the tabs, but we need to improve
initTabs() {
const makeTab = ( type ) => new OO.ui.MenuOptionWidget( {
data: type,
// The following messages are used here:
// * multimediaviewer-embed-tab
// * multimediaviewer-share-tab
label: mw.message( `multimediaviewer-${ type }-tab` ).text()
} );
this.reuseTabs = new OO.ui.MenuSelectWidget( {
autoHide: false,
classes: [ 'mw-mmv-reuse-tabs' ]
} );
this.reuseTabs.$element.appendTo( this.$dialog );
const { Embed, Share } = require( 'mmv.ui.reuse.shareembed' );
this.tabs = {
share: new Share( this.$dialog ),
embed: new Embed( this.$dialog )
};
this.ooTabs = {
share: makeTab( 'share' ),
embed: makeTab( 'embed' )
};
this.reuseTabs.addItems( [
this.ooTabs.share,
this.ooTabs.embed
] );
// MenuSelectWidget has a nasty tendency to hide itself, maybe we're not using it right?
this.reuseTabs.toggle( true );
this.reuseTabs.toggle = () => { };
this.selectedTab = this.getLastUsedTab();
// In case nothing is saved in localStorage or it contains junk
if ( !Object.prototype.hasOwnProperty.call( this.tabs, this.selectedTab ) ) {
this.selectedTab = 'share';
}
this.reuseTabs.selectItem( this.ooTabs[ this.selectedTab ] );
if ( this.dependenciesNeedToBeAttached ) {
this.attachDependencies();
}
if ( this.tabsSetValues ) {
// This is a delayed set() for the elements we've just created on demand
this.tabs.share.set.apply( this.tabs.share, this.tabsSetValues.share );
this.tabs.embed.set.apply( this.tabs.embed, this.tabsSetValues.embed );
this.showImageWarnings( this.tabsSetValues.share[ 0 ] );
this.tabsSetValues = undefined;
}
}
toggleDialog() {
if ( this.tabs === null ) {
this.initTabs();
}
super.toggleDialog();
}
/**
* Handles tab selection.
*
* @param {OO.ui.MenuOptionWidget} option
*/
handleTabSelection( option ) {
this.selectedTab = option.getData();
for ( const tab in this.tabs ) {
if ( tab === this.selectedTab ) {
this.tabs[ tab ].show();
} else {
this.tabs[ tab ].hide();
}
}
this.config.setInLocalStorage( 'mmv-lastUsedTab', this.selectedTab );
}
/**
* @return {string} Last used tab
*/
getLastUsedTab() {
return this.config.getFromLocalStorage( 'mmv-lastUsedTab' );
}
/**
* Registers listeners.
*/
@ -148,47 +46,10 @@ const Dialog = require( './mmv.ui.dialog.js' );
this.handleEvent( 'mmv-download-open', this.closeDialog.bind( this ) );
this.handleEvent( 'mmv-options-open', this.closeDialog.bind( this ) );
this.attachDependencies();
}
/**
* Registers listeners for dependencies loaded on demand
*/
attachDependencies() {
if ( this.reuseTabs && this.tabs ) {
// This is a delayed attach() for the elements we've just created on demand
this.reuseTabs.on( 'select', this.handleTabSelection.bind( this ) );
for ( const tab in this.tabs ) {
this.tabs[ tab ].attach();
}
this.dependenciesNeedToBeAttached = false;
} else {
this.dependenciesNeedToBeAttached = true;
}
}
/**
* Clears listeners.
*/
unattach() {
super.unattach();
if ( this.reuseTabs ) {
this.reuseTabs.off( 'select' );
}
if ( this.tabs ) {
for ( const tab in this.tabs ) {
this.tabs[ tab ].unattach();
}
}
}
/**
* Sets data needed by contained tabs and makes dialog launch link visible.
* Sets data needed by contained panes and makes dialog launch link visible.
*
* @param {Image} image
* @param {Repo} repo
@ -196,27 +57,13 @@ const Dialog = require( './mmv.ui.dialog.js' );
* @param {string} alt
*/
set( image, repo, caption, alt ) {
if ( this.tabs !== null ) {
this.tabs.share.set( image );
this.tabs.embed.set( image, repo, caption, alt );
this.tabs.embed.set( image, repo, caption );
if ( this.share && this.embed ) {
this.share.set( image );
this.embed.set( image, repo, caption, alt );
this.embed.set( image, repo, caption );
this.showImageWarnings( image );
} else {
this.tabsSetValues = {
share: [ image ],
embed: [ image, repo, caption, alt ]
};
}
}
/**
* @inheritdoc
*/
empty() {
super.empty();
for ( const tab in this.tabs ) {
this.tabs[ tab ].empty();
this.setValues = [ image, repo, caption, alt ];
}
}
@ -230,12 +77,25 @@ const Dialog = require( './mmv.ui.dialog.js' );
* Opens a dialog with information about file reuse.
*/
openDialog() {
const { Embed, Share } = require( 'mmv.ui.reuse.shareembed' );
if ( !this.share ) {
this.share = new Share( this.$dialog );
this.share.attach();
}
if ( !this.embed ) {
this.embed = new Embed( this.$dialog );
this.embed.attach();
}
if ( this.setValues ) {
this.set( ...this.setValues );
this.setValues = undefined;
}
super.openDialog();
// move warnings after the tabs
this.$warning.insertAfter( this.reuseTabs.$element );
this.tabs[ this.selectedTab ].show();
this.$warning.insertAfter( this.$container );
$( document ).trigger( 'mmv-reuse-opened' );
}

View file

@ -51,7 +51,6 @@ require( './ui/mmv.ui.stripeButtons.test.js' );
require( './ui/mmv.ui.reuse.dialog.test.js' );
require( './ui/mmv.ui.reuse.embed.test.js' );
require( './ui/mmv.ui.reuse.share.test.js' );
require( './ui/mmv.ui.reuse.tab.test.js' );
require( './ui/mmv.ui.reuse.utils.test.js' );
require( './ui/mmv.ui.truncatableTextField.test.js' );
require( './ui/mmv.ui.viewingOptions.test.js' );

View file

@ -58,85 +58,40 @@ const { ReuseDialog, Repo } = require( 'mmv' );
reuseDialog.handleOpenCloseClick();
} );
QUnit.test( 'handleTabSelection():', function ( assert ) {
const reuseDialog = makeReuseDialog( this.sandbox );
reuseDialog.initTabs();
// Share pane is selected
reuseDialog.handleTabSelection( { getData: () => 'share' } );
assert.strictEqual( reuseDialog.tabs.share.$pane.hasClass( 'active' ), true, 'Share tab shown.' );
assert.strictEqual( reuseDialog.tabs.embed.$pane.hasClass( 'active' ), false, 'Embed tab hidden.' );
assert.strictEqual( reuseDialog.config.setInLocalStorage.calledWith( 'mmv-lastUsedTab', 'share' ), true,
'Tab state saved in local storage.' );
// Embed pane is selected
reuseDialog.handleTabSelection( { getData: () => 'embed' } );
assert.strictEqual( reuseDialog.tabs.share.$pane.hasClass( 'active' ), false, 'Share tab hidden.' );
assert.strictEqual( reuseDialog.tabs.embed.$pane.hasClass( 'active' ), true, 'Embed tab shown.' );
} );
QUnit.test( 'default tab:', function ( assert ) {
let reuseDialog = makeReuseDialog( this.sandbox );
reuseDialog.initTabs();
assert.strictEqual( reuseDialog.selectedTab, 'share', 'Share tab is default' );
reuseDialog = makeReuseDialog( this.sandbox );
reuseDialog.config.getFromLocalStorage.withArgs( 'mmv-lastUsedTab' ).returns( 'share' );
reuseDialog.initTabs();
assert.strictEqual( reuseDialog.selectedTab, 'share', 'Default can be overridden' );
} );
QUnit.test( 'attach()/unattach():', function ( assert ) {
const reuseDialog = makeReuseDialog( this.sandbox );
reuseDialog.initTabs();
reuseDialog.handleOpenCloseClick = function () {
assert.true( false, 'handleOpenCloseClick should not have been called.' );
};
reuseDialog.handleTabSelection = function () {
assert.true( false, 'handleTabSelection should not have been called.' );
};
// Triggering action events before attaching should do nothing
$( document ).trigger( 'mmv-reuse-open' );
reuseDialog.reuseTabs.emit( 'select' );
reuseDialog.handleOpenCloseClick = function () {
assert.true( true, 'handleOpenCloseClick called.' );
};
reuseDialog.handleTabSelection = function () {
assert.true( true, 'handleTabSelection called.' );
};
reuseDialog.attach();
// Action events should be handled now
$( document ).trigger( 'mmv-reuse-open' );
reuseDialog.reuseTabs.emit( 'select' );
// Test the unattach part
reuseDialog.handleOpenCloseClick = function () {
assert.true( false, 'handleOpenCloseClick should not have been called.' );
};
reuseDialog.handleTabSelection = function () {
assert.true( false, 'handleTabSelection should not have been called.' );
};
reuseDialog.unattach();
// Triggering action events now that we are unattached should do nothing
$( document ).trigger( 'mmv-reuse-open' );
reuseDialog.reuseTabs.emit( 'select' );
} );
QUnit.test( 'start/stopListeningToOutsideClick():', function ( assert ) {
const reuseDialog = makeReuseDialog( this.sandbox );
const realCloseDialog = reuseDialog.closeDialog;
reuseDialog.initTabs();
function clickOutsideDialog() {
const event = new $.Event( 'click', { target: reuseDialog.$container[ 0 ] } );
reuseDialog.$container.trigger( event );
@ -213,9 +168,8 @@ const { ReuseDialog, Repo } = require( 'mmv' );
};
const repoInfo = new Repo( 'Wikipedia', '//wikipedia.org/favicon.ico', true );
reuseDialog.initTabs();
reuseDialog.set( image, repoInfo );
reuseDialog.setValues = undefined;
assert.strictEqual( reuseDialog.isOpen, false, 'Dialog closed by default.' );

View file

@ -26,29 +26,19 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
const embed = new Embed( $qf );
assert.true( embed instanceof Embed, 'Embed UI element is created.' );
assert.strictEqual( embed.$pane.length, 1, 'Pane div is created.' );
assert.true( embed.embedTextHtml instanceof OO.ui.Element, 'Html snipped text area created.' );
assert.true( embed.embedTextWikitext instanceof OO.ui.Element, 'Wikitext snipped text area created.' );
assert.true( embed.embedSwitch instanceof OO.ui.Element, 'Snipped selection buttons created.' );
assert.true( embed.embedSizeSwitchWikitext instanceof OO.ui.Element, 'Size selection menu for wikitext created.' );
assert.true( embed.embedSizeSwitchHtml instanceof OO.ui.Element, 'Size selection menu for html created.' );
assert.true( embed.currentMainEmbedText instanceof OO.ui.Element, 'Current text area created.' );
assert.strictEqual( embed.isSizeMenuDefaultReset, false, 'Reset flag intialized correctly.' );
assert.true( embed.defaultHtmlItem instanceof OO.ui.Element, 'Default item for html size selection intialized.' );
assert.true( embed.defaultWikitextItem instanceof OO.ui.Element, 'Default item for wikitext size selection intialized.' );
assert.true( embed.currentSizeMenu instanceof OO.ui.Element, 'Current size menu intialized.' );
assert.true( embed.currentDefaultItem instanceof OO.ui.Element, 'Current default item intialized.' );
assert.true( embed.$embedTextHtml[ 0 ] instanceof HTMLElement, 'Html snipped text area created.' );
assert.true( embed.$embedTextWikitext[ 0 ] instanceof HTMLElement, 'Wikitext snipped text area created.' );
assert.true( embed.$embedSizeSwitchWikitext[ 0 ] instanceof HTMLElement, 'Size selection menu for wikitext created.' );
assert.true( embed.$embedSizeSwitchHtml[ 0 ] instanceof HTMLElement, 'Size selection menu for html created.' );
} );
QUnit.test( 'changeSize(): Skip if no item selected.', function ( assert ) {
QUnit.test( 'handleSizeSwitch(): Skip if no item selected.', function ( assert ) {
const embed = new Embed( $qf );
const width = 10;
const height = 20;
assert.expect( 0 );
// deselect items
embed.embedSwitch.selectItem();
embed.$embedSizeSwitchHtml.val( undefined );
embed.$embedSizeSwitchWikitext.val( undefined );
embed.updateEmbedHtml = function () {
assert.true( false, 'No item selected, this should not have been called.' );
@ -57,42 +47,46 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
assert.true( false, 'No item selected, this should not have been called.' );
};
embed.changeSize( width, height );
embed.handleSizeSwitch();
} );
QUnit.test( 'changeSize(): HTML size menu item selected.', function ( assert ) {
QUnit.test( 'handleSizeSwitch(): HTML/Wikitext size menu item selected.', function ( assert ) {
const embed = new Embed( $qf );
const width = 10;
const height = 20;
const width = '10';
const height = '20';
const $option = embed.$embedSizeSwitchHtml.children().first();
$option.attr( 'data-width', width );
$option.attr( 'data-height', height );
embed.$embedSizeSwitchHtml.val( $option.val() );
embed.embedSwitch.findSelectedItem = function () {
return { getData: () => 'html' };
};
embed.updateEmbedHtml = 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.updateEmbedWikitext = function () {
assert.true( false, 'Dealing with HTML menu, this should not have been called.' );
// ignore
};
embed.select = function () {
assert.true( true, 'Item selected after update.' );
};
embed.changeSize( width, height );
embed.handleSizeSwitch();
} );
QUnit.test( 'changeSize(): Wikitext size menu item selected.', function ( assert ) {
QUnit.test( 'handleSizeSwitch(): Wikitext size menu item selected.', function ( assert ) {
const embed = new Embed( $qf );
const width = 10;
const height = 20;
const width = '10';
const height = '20';
const $option = embed.$embedSizeSwitchWikitext.children().first();
$option.attr( 'data-width', width );
$option.attr( 'data-height', height );
embed.$embedSizeSwitchWikitext.val( $option.val() );
embed.embedSwitch.findSelectedItem = function () {
return { getData: () => 'wikitext' };
};
embed.updateEmbedHtml = function () {
assert.true( false, 'Dealing with wikitext menu, this should not have been called.' );
// ignore
};
embed.updateEmbedWikitext = function ( w ) {
assert.strictEqual( w, width, 'Correct width passed.' );
@ -101,7 +95,7 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
assert.true( true, 'Item selected after update.' );
};
embed.changeSize( width, height );
embed.handleSizeSwitch();
} );
QUnit.test( 'updateEmbedHtml(): Do nothing if set() not called before.', function ( assert ) {
@ -119,9 +113,10 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
QUnit.test( 'updateEmbedHtml():', function ( assert ) {
const embed = new Embed( $qf );
const title = mw.Title.newFromText( 'File:Foobar.jpg' );
const url = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg';
const thumbUrl = 'https://upload.wikimedia.org/wikipedia/thumb/Foobar.jpg';
const imageInfo = { url: url };
const imageInfo = { url, title };
const repoInfo = {};
const caption = '-';
const info = {
@ -132,6 +127,8 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
let width = 10;
const height = 20;
embed.resetCurrentSizeMenuToDefault = () => {};
embed.set( imageInfo, repoInfo, caption );
// Small image, no thumbnail info is passed
@ -171,7 +168,10 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
QUnit.test( 'updateEmbedWikitext():', function ( assert ) {
const embed = new Embed( $qf );
const imageInfo = {};
const title = mw.Title.newFromText( 'File:Foobar.jpg' );
const url = 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg';
const imageInfo = { url, title };
const repoInfo = {};
const caption = '-';
const info = {
@ -181,6 +181,8 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
};
const width = 10;
embed.resetCurrentSizeMenuToDefault = () => {};
embed.set( imageInfo, repoInfo, caption );
embed.formatter.getThumbnailWikitextFromEmbedFileInfo = function ( i, w ) {
@ -237,7 +239,6 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
repoInfo: src,
caption: url
};
let calledSelect = false;
const width = 15;
const height = 20;
@ -253,17 +254,12 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
embed.updateEmbedHtml = function () {
assert.true( true, 'updateEmbedHtml() is called after data is collected.' );
};
embed.select = function () {
calledSelect = true;
};
assert.false( $.isPlainObject( embed.embedFileInfo ), 'embedFileInfo not set yet.' );
embed.set( { width: width, height: height }, embedFileInfo );
assert.true( $.isPlainObject( embed.embedFileInfo ), 'embedFileInfo set.' );
assert.strictEqual( embed.isSizeMenuDefaultReset, false, 'Reset flag cleared.' );
assert.strictEqual( calledSelect, true, 'select() is called' );
} );
QUnit.test( 'empty():', function ( assert ) {
@ -284,15 +280,15 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
embed.updateEmbedHtml( { url: 'x' }, width, height );
embed.updateEmbedWikitext( width );
assert.notStrictEqual( embed.embedTextHtml.textInput.getValue(), '', 'embedTextHtml is not empty.' );
assert.notStrictEqual( embed.embedTextWikitext.textInput.getValue(), '', 'embedTextWikitext is not empty.' );
assert.notStrictEqual( embed.$embedTextHtml.val(), '', 'embedTextHtml is not empty.' );
assert.notStrictEqual( embed.$embedTextWikitext.val(), '', 'embedTextWikitext is not empty.' );
embed.empty();
assert.strictEqual( embed.embedTextHtml.textInput.getValue(), '', 'embedTextHtml is empty.' );
assert.strictEqual( embed.embedTextWikitext.textInput.getValue(), '', 'embedTextWikitext is empty.' );
assert.strictEqual( embed.embedSizeSwitchHtml.getMenu().isVisible(), false, 'Html size menu should be hidden.' );
assert.strictEqual( embed.embedSizeSwitchWikitext.getMenu().isVisible(), false, 'Wikitext size menu should be hidden.' );
assert.strictEqual( embed.$embedTextHtml.val(), '', 'embedTextHtml is empty.' );
assert.strictEqual( embed.$embedTextWikitext.val(), '', 'embedTextWikitext is empty.' );
assert.strictEqual( embed.$embedSizeSwitchHtml.css( 'display' ), 'none', 'Html size menu should be hidden.' );
assert.strictEqual( embed.$embedSizeSwitchWikitext.css( 'display' ), 'none', 'Wikitext size menu should be hidden.' );
} );
QUnit.test( 'attach()/unattach():', function ( assert ) {
@ -308,6 +304,8 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
const width = 15;
const height = 20;
embed.resetCurrentSizeMenuToDefault = () => {};
embed.set( { width: width, height: height }, embedFileInfo );
embed.handleTypeSwitch = function () {
@ -318,11 +316,8 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
};
// Triggering action events before attaching should do nothing
embed.embedSwitch.emit( 'select' );
embed.embedSizeSwitchHtml.getMenu().emit(
'choose', embed.embedSizeSwitchHtml.getMenu().findSelectedItem() );
embed.embedSizeSwitchWikitext.getMenu().emit(
'choose', embed.embedSizeSwitchWikitext.getMenu().findSelectedItem() );
embed.$embedSizeSwitchHtml.trigger( 'change' );
embed.$embedSizeSwitchWikitext.trigger( 'change' );
embed.handleTypeSwitch = function () {
assert.true( true, 'handleTypeSwitch was called.' );
@ -334,11 +329,8 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
embed.attach();
// Action events should be handled now
embed.embedSwitch.emit( 'select' );
embed.embedSizeSwitchHtml.getMenu().emit(
'choose', embed.embedSizeSwitchHtml.getMenu().findSelectedItem() );
embed.embedSizeSwitchWikitext.getMenu().emit(
'choose', embed.embedSizeSwitchWikitext.getMenu().findSelectedItem() );
embed.$embedSizeSwitchHtml.trigger( 'change' );
embed.$embedSizeSwitchWikitext.trigger( 'change' );
// Test the unattach part
embed.handleTypeSwitch = function () {
@ -351,37 +343,30 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
embed.unattach();
// Triggering action events now that we are unattached should do nothing
embed.embedSwitch.emit( 'select' );
embed.embedSizeSwitchHtml.getMenu().emit(
'choose', embed.embedSizeSwitchHtml.getMenu().findSelectedItem() );
embed.embedSizeSwitchWikitext.getMenu().emit(
'choose', embed.embedSizeSwitchWikitext.getMenu().findSelectedItem() );
embed.$embedSizeSwitchHtml.trigger( 'change' );
embed.$embedSizeSwitchWikitext.trigger( 'change' );
} );
QUnit.test( 'handleTypeSwitch():', function ( assert ) {
const embed = new Embed( $qf );
assert.strictEqual( embed.isSizeMenuDefaultReset, false, 'Reset flag intialized correctly.' );
embed.resetCurrentSizeMenuToDefault = function () {
assert.true( true, 'resetCurrentSizeMenuToDefault() called.' );
};
// HTML selected
embed.handleTypeSwitch( { getData: () => 'html' } );
embed.handleTypeSwitch( 'html' );
assert.strictEqual( embed.isSizeMenuDefaultReset, true, 'Reset flag updated correctly.' );
assert.strictEqual( embed.embedSizeSwitchWikitext.getMenu().isVisible(), false, 'Wikitext size menu should be hidden.' );
assert.strictEqual( embed.$embedSizeSwitchWikitext.css( 'display' ), 'none', 'Wikitext size menu should be hidden.' );
embed.resetCurrentSizeMenuToDefault = function () {
assert.true( false, 'resetCurrentSizeMenuToDefault() should not have been called.' );
};
// Wikitext selected, we are done resetting defaults
embed.handleTypeSwitch( { getData: () => 'wikitext' } );
embed.handleTypeSwitch( 'wikitext' );
assert.strictEqual( embed.isSizeMenuDefaultReset, true, 'Reset flag updated correctly.' );
assert.strictEqual( embed.embedSizeSwitchHtml.getMenu().isVisible(), false, 'HTML size menu should be hidden.' );
assert.strictEqual( embed.$embedSizeSwitchHtml.css( 'display' ), 'none', 'HTML size menu should be hidden.' );
} );
QUnit.test( 'Logged out', function ( assert ) {
@ -393,10 +378,10 @@ const { Embed } = require( 'mmv.ui.reuse.shareembed' );
embed.attach();
assert.strictEqual( embed.embedSizeSwitchWikitextLayout.isVisible(), false, 'Wikitext widget should be hidden.' );
assert.strictEqual( embed.embedSizeSwitchHtmlLayout.isVisible(), true, 'HTML widget should be visible.' );
assert.strictEqual( embed.embedTextWikitext.isVisible(), false, 'Wikitext input should be hidden.' );
assert.strictEqual( embed.embedTextHtml.isVisible(), true, 'HTML input should be visible.' );
assert.strictEqual( embed.$embedSizeSwitchWikitext.css( 'display' ), 'none', 'Wikitext widget should be hidden.' );
assert.strictEqual( embed.$embedSizeSwitchHtml.css( 'display' ), '', 'HTML widget should be visible.' );
assert.strictEqual( embed.$embedTextWikitextDiv.css( 'display' ), 'none', 'Wikitext input should be hidden.' );
assert.strictEqual( embed.$embedTextHtmlDiv.css( 'display' ), '', 'HTML input should be visible.' );
mw.user.isAnon = oldUserIsAnon;
} );

View file

@ -28,9 +28,7 @@ const { Share } = require( 'mmv.ui.reuse.shareembed' );
const share = makeShare();
assert.true( share instanceof Share, 'Share UI element is created.' );
assert.strictEqual( share.$pane.length, 1, 'Pane div created.' );
assert.true( share.pageInput instanceof mw.widgets.CopyTextLayout, 'Text field created.' );
assert.strictEqual( share.$pageLink.length, 1, 'Link created.' );
assert.true( share.$pageInput[ 0 ] instanceof HTMLElement, 'Text field created.' );
} );
QUnit.test( 'set()/empty():', function ( assert ) {
@ -41,7 +39,7 @@ const { Share } = require( 'mmv.ui.reuse.shareembed' );
descriptionUrl: '//commons.wikimedia.org/wiki/File:Foobar.jpg'
};
assert.notStrictEqual( !share.pageInput.textInput.getValue(), '', 'pageInput is empty.' );
assert.notStrictEqual( !share.$pageInput.val(), '', 'pageInput is empty.' );
share.select = function () {
assert.true( true, 'Text has been selected after data is set.' );
@ -49,11 +47,11 @@ const { Share } = require( 'mmv.ui.reuse.shareembed' );
share.set( image );
assert.notStrictEqual( share.pageInput.textInput.getValue(), '', 'pageInput is not empty.' );
assert.notStrictEqual( share.$pageInput.val(), '', 'pageInput is not empty.' );
share.empty();
assert.notStrictEqual( !share.pageInput.textInput.getValue(), '', 'pageInput is empty.' );
assert.notStrictEqual( !share.$pageInput.val(), '', 'pageInput is empty.' );
} );
}() );

View file

@ -1,45 +0,0 @@
/*
* This file is part of the MediaWiki extension MultimediaViewer.
*
* MultimediaViewer is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* MultimediaViewer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>.
*/
const { Tab } = require( 'mmv.ui.reuse.shareembed' );
( function () {
const $fixture = $( '#qunit-fixture' );
function makeReuseTab() {
return new Tab( $( '<div>' ).appendTo( $fixture ), $fixture );
}
QUnit.module( 'mmv.ui.reuse.Tab', QUnit.newMwEnvironment() );
QUnit.test( 'Object creation, UI construction and basic funtionality', function ( assert ) {
const reuseTab = makeReuseTab();
assert.true( reuseTab instanceof Tab, 'Reuse UI element is created.' );
assert.strictEqual( reuseTab.$pane.length, 1, 'Pane created.' );
assert.strictEqual( reuseTab.$pane.hasClass( 'active' ), false, 'Tab is not active.' );
reuseTab.show();
assert.strictEqual( reuseTab.$pane.hasClass( 'active' ), true, 'Tab is active.' );
reuseTab.hide();
assert.strictEqual( reuseTab.$pane.hasClass( 'active' ), false, 'Tab is not active.' );
} );
}() );

View file

@ -26,50 +26,46 @@ const { Utils } = require( 'mmv.ui.ondemandshareddependencies' );
assert.true( utils instanceof Utils, 'ReuseUtils object is created.' );
} );
QUnit.test( 'createPulldownMenu():', function ( assert ) {
QUnit.test( 'createSelectMenu():', function ( assert ) {
const utils = new Utils();
const menuItems = [ 'original', 'small', 'medium', 'large' ];
const def = 'large';
const menu = utils.createPulldownMenu(
const $select = utils.createSelectMenu(
menuItems,
[ 'mw-mmv-download-size' ],
def
);
const options = menu.getMenu().getItems();
const $options = $select.children();
assert.strictEqual( options.length, 4, 'Menu has correct number of items.' );
assert.strictEqual( $options.length, 4, 'Menu has correct number of items.' );
for ( let i = 0; i < menuItems.length; i++ ) {
const data = options[ i ].getData();
const $option = $( $options[ i ] );
assert.strictEqual( data.name, menuItems[ i ], 'Correct item name on the list.' );
assert.strictEqual( data.height, null, 'Correct item height on the list.' );
assert.strictEqual( data.width, null, 'Correct item width on the list.' );
assert.strictEqual( $option.attr( 'data-name' ), menuItems[ i ], 'Correct item name on the list.' );
assert.strictEqual( $option.attr( 'data-height' ), undefined, 'Correct item height on the list.' );
assert.strictEqual( $option.attr( 'data-width' ), undefined, 'Correct item width on the list.' );
}
assert.strictEqual( menu.getMenu().findSelectedItem(), options[ 3 ], 'Default set correctly.' );
} );
QUnit.test( 'updateMenuOptions():', function ( assert ) {
QUnit.test( 'updateSelectOptions():', function ( assert ) {
const utils = new Utils();
const menu = utils.createPulldownMenu(
const $select = utils.createSelectMenu(
[ 'original', 'small', 'medium', 'large' ],
[ 'mw-mmv-download-size' ],
'original'
);
const options = menu.getMenu().getItems();
const $options = $select.children();
const width = 700;
const height = 500;
const sizes = utils.getPossibleImageSizesForHtml( width, height );
const oldMessage = mw.message;
mw.message = function ( messageKey ) {
assert.true( /^multimediaviewer-(small|medium|original|embed-dimensions)/.test( messageKey ), 'messageKey passed correctly.' );
assert.true( /^multimediaviewer-(small|medium|large|original|embed-dimensions)/.test( messageKey ), 'messageKey passed correctly.' );
return { text: function () {} };
};
utils.updateMenuOptions( sizes, options );
utils.updateSelectOptions( sizes, $options );
mw.message = oldMessage;
} );