From cb48f4ea9cf7f8e7acaa7336ec39e5b8a52d058a Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Wed, 22 May 2019 19:54:04 +0100 Subject: [PATCH] Upstream CopyTextLayout from UrlShortener extension Provides a generic widget feature a read-only text input and a copy button, that writes the text to the clipboard. Change-Id: Ibeb5df2a2928a68297f4209562d7ab3f17cad6f0 --- languages/i18n/en.json | 3 + languages/i18n/qqq.json | 3 + resources/Resources.php | 10 ++ .../mw.widgets.CopyTextLayout.css | 11 ++ .../mw.widgets.CopyTextLayout.js | 103 ++++++++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css create mode 100644 resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 71f56332d2..0dd9fe0e77 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -4044,6 +4044,9 @@ "mw-widgets-abandonedit-discard": "Discard edits", "mw-widgets-abandonedit-keep": "Continue editing", "mw-widgets-abandonedit-title": "Are you sure?", + "mw-widgets-copytextlayout-copy": "Copy", + "mw-widgets-copytextlayout-copy-fail": "Failed to copy to clipboard.", + "mw-widgets-copytextlayout-copy-success": "Copied to clipboard.", "mw-widgets-dateinput-no-date": "No date selected", "mw-widgets-dateinput-placeholder-day": "YYYY-MM-DD", "mw-widgets-dateinput-placeholder-month": "YYYY-MM", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 10fdb84333..683e975bd4 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -4252,6 +4252,9 @@ "mw-widgets-abandonedit-discard": "Text shown on the button which closes an editor and discards changes when the user confirms that they want to leave the editor.\n\nPreceded by the prompt {{msg-mw|mw-widgets-abandonedit}}.\n\nFollowed by the button {{msg-mw|mw-widgets-abandonedit-keep}}.", "mw-widgets-abandonedit-keep": "Text shown on the button which does not do anything when the user decides that they do not want to leave the editor.\n\nPreceded by the button {{msg-mw|mw-widgets-abandonedit-discard}}.", "mw-widgets-abandonedit-title": "Title of the dialog shown when the user tries to leave the editor without saving their changes.\n\nFollowed by the following buttons:\n* {{msg-mw|mw-widgets-abandonedit-discard}}\n* {{msg-mw|mw-widgets-abandonedit-keep}}\n{{Identical|Are you sure?}}", + "mw-widgets-copytextlayout-copy": "Label of button to copy text to clipboard.", + "mw-widgets-copytextlayout-copy-fail": "Message shown when copying to clipboard failed.", + "mw-widgets-copytextlayout-copy-success": "Message shown when copying to clipboard failed.", "mw-widgets-dateinput-no-date": "Label of a date input field when no date has been selected.", "mw-widgets-dateinput-placeholder-day": "[[File:DateInputWidget active, empty.png|frame|Screenshot]]\nPlaceholder displayed in a date input field when it's empty, representing a date format with 4 digits for year, 2 digits for month, and 2 digits for day, separated with hyphens. This should be uppercase, if possible, and must not include any additional explanations. If there is no good way to translate it, make this message blank.", "mw-widgets-dateinput-placeholder-month": "Placeholder displayed in a date input field when it's empty, representing a date format with 4 digits for year and 2 digits for month, separated with hyphens (without a day). This should be uppercase, if possible, and must not include any additional explanations. If there is no good way to translate it, make this message blank.", diff --git a/resources/Resources.php b/resources/Resources.php index 4c359ee727..c0ece91e6e 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -2503,12 +2503,16 @@ return [ 'scripts' => [ 'resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js', 'resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.js', + 'resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js', 'resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js', 'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js', 'resources/src/mediawiki.widgets/mw.widgets.TitleSearchWidget.js', 'resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.js', 'resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js', ], + 'styles' => [ + 'resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css', + ], 'skinStyles' => [ 'default' => [ 'resources/src/mediawiki.widgets/mw.widgets.TitleWidget.less', @@ -2522,11 +2526,17 @@ return [ 'mediawiki.Title', 'mediawiki.api', 'mediawiki.String', + // CopyTextLayout + 'mediawiki.notify', ], 'messages' => [ // NamespaceInputWidget 'blanknamespace', 'namespacesall', + // CopyTextLayout + 'mw-widgets-copytextlayout-copy', + 'mw-widgets-copytextlayout-copy-fail', + 'mw-widgets-copytextlayout-copy-success', // TitleInputWidget 'mw-widgets-titleinput-description-new-page', 'mw-widgets-titleinput-description-redirect', diff --git a/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css b/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css new file mode 100644 index 0000000000..b336fa285f --- /dev/null +++ b/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css @@ -0,0 +1,11 @@ +/*! + * MediaWiki Widgets – CopyTextLayout styles. + * + * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt + * @license The MIT License (MIT); see LICENSE.txt + */ + +.mw-widget-copyTextLayout > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field { + /* TODO: This should be upstreamed to OOUI */ + max-width: 50em; +} diff --git a/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js b/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js new file mode 100644 index 0000000000..48c14b62b1 --- /dev/null +++ b/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js @@ -0,0 +1,103 @@ +/*! + * MediaWiki Widgets - CopyTextLayout class. + * + * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt + * @license The MIT License (MIT); see LICENSE.txt + */ +( function () { + + /** + * An action field layout containing some readonly text and a button to copy + * it to the clipboard. + * + * @class + * @extends OO.ui.ActionFieldLayout + * + * @constructor + * @param {Object} [config] Configuration options + * @cfg {string} copyText Text to copy, can also be provided as textInput.value + * @cfg {Object} textInput Config for text input + * @cfg {Object} button Config for button + * @cfg {string} successMessage Success message, + * defaults to 'mw-widgets-copytextlayout-copy-success'. + * @cfg {string} failMessage Failure message, + * defaults to 'mw-widgets-copytextlayout-copy-fail'. + */ + mw.widgets.CopyTextLayout = function MwWidgetsCopyTextLayout( config ) { + config = config || {}; + + // Properties + this.textInput = new OO.ui.TextInputWidget( $.extend( { + value: config.copyText, + readOnly: true + }, config.textInput ) ); + this.button = new OO.ui.ButtonWidget( $.extend( { + label: mw.msg( 'mw-widgets-copytextlayout-copy' ), + icon: 'articles' + }, config.button ) ); + this.successMessage = config.successMessage || mw.msg( 'mw-widgets-copytextlayout-copy-success' ); + this.failMessage = config.failMessage || mw.msg( 'mw-widgets-copytextlayout-copy-fail' ); + + // Parent constructor + mw.widgets.CopyTextLayout.super.call( this, this.textInput, this.button, config ); + + // Events + this.button.connect( this, { click: 'onButtonClick' } ); + this.textInput.$input.on( 'click', this.onInputClick.bind( this ) ); + + this.$element.addClass( 'mw-widget-copyTextLayout' ); + }; + + /* Inheritence */ + + OO.inheritClass( mw.widgets.CopyTextLayout, OO.ui.ActionFieldLayout ); + + /* Methods */ + + /** + * Handle button click events + * + * @fires copy + */ + mw.widgets.CopyTextLayout.prototype.onButtonClick = function () { + var copied; + + this.selectText(); + + try { + copied = document.execCommand( 'copy' ); + } catch ( e ) { + copied = false; + } + if ( copied ) { + mw.notify( this.successMessage ); + } else { + mw.notify( this.failMessage, { type: 'error' } ); + } + + this.emit( 'copy', copied ); + }; + + /** + * Handle button click events + */ + mw.widgets.CopyTextLayout.prototype.onInputClick = function () { + this.selectText(); + }; + + /** + * Select the text to copy + */ + mw.widgets.CopyTextLayout.prototype.selectText = function () { + var input = this.textInput.$input[ 0 ], + scrollTop = input.scrollTop, + scrollLeft = input.scrollLeft; + + this.textInput.select(); + + // Restore scroll position + input.scrollTop = scrollTop; + input.scrollLeft = scrollLeft; + }; + +}() ); -- 2.20.1