From 8b5a5cad684b095d62653f55f66c03288cba0941 Mon Sep 17 00:00:00 2001 From: Prateek Saxena Date: Wed, 2 Sep 2015 16:18:37 +0530 Subject: [PATCH] Add mw.ForeignStructuredUpload.BookletLayout Bug: T91717 Change-Id: Ibf283fd185e191ed6ac8668efe6409f11e73f439 --- includes/DefaultSettings.php | 8 + .../ResourceLoaderStartUpModule.php | 1 + languages/i18n/en.json | 9 + languages/i18n/qqq.json | 10 + maintenance/jsduck/categories.json | 2 +- resources/Resources.php | 20 ++ ...i.ForeignStructuredUpload.BookletLayout.js | 196 ++++++++++++++++++ .../mediawiki.Upload.BookletLayout.js | 3 + .../src/mediawiki/mediawiki.Upload.Dialog.js | 16 +- 9 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 5fd85743ec..1472490371 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -525,6 +525,14 @@ $wgForeignFileRepos = array(); */ $wgUseInstantCommons = false; +/** + * Name of the remote repository to which users will be allowed to upload + * files in their editors. Used to find a set of message names to describe + * the legal requirements for uploading to that wiki, and suggestions for + * when those requirements are not met. + */ +$wgRemoteUploadTarget = 'default'; + /** * File backend structure configuration. * diff --git a/includes/resourceloader/ResourceLoaderStartUpModule.php b/includes/resourceloader/ResourceLoaderStartUpModule.php index 0553df09a2..e5f3fb8bc2 100644 --- a/includes/resourceloader/ResourceLoaderStartUpModule.php +++ b/includes/resourceloader/ResourceLoaderStartUpModule.php @@ -102,6 +102,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { 'wgResourceLoaderStorageVersion' => $conf->get( 'ResourceLoaderStorageVersion' ), 'wgResourceLoaderStorageEnabled' => $conf->get( 'ResourceLoaderStorageEnabled' ), 'wgResourceLoaderLegacyModules' => self::getLegacyModules(), + 'wgRemoteUploadTarget' => $conf->get( 'RemoteUploadTarget' ), ); Hooks::run( 'ResourceLoaderGetConfigVars', array( &$vars ) ); diff --git a/languages/i18n/en.json b/languages/i18n/en.json index df552983b1..360f012d91 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1415,6 +1415,15 @@ "upload-form-label-infoform-description": "Description", "upload-form-label-usage-title": "Usage", "upload-form-label-usage-filename": "File name", + "foreign-structured-upload-form-label-own-work": "This is my own work", + "foreign-structured-upload-form-label-infoform-categories": "Categories", + "foreign-structured-upload-form-label-infoform-date": "Date", + "foreign-structured-upload-form-label-own-work-message-default": "I understand that I am uploading this file to a shared repository. I confirm that I am doing so following the terms of service and licensing policies there.", + "foreign-structured-upload-form-label-not-own-work-message-default": "If you are not able to upload this file under the policies of the shared repository, please close this dialog and try another method.", + "foreign-structured-upload-form-label-not-own-work-local-default": "You may also want to try using [[Special:Upload|the upload page on {{SITENAME}}]], if this file can be uploaded there under their policies.", + "foreign-structured-upload-form-label-own-work-message-wikimediacommons": "I attest that I own the copyright on this file, and agree to irrevocably release this file to Wikimedia Commons under the [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] license, and I agree to the [https://wikimediafoundation.org/wiki/Terms_of_Use Terms of Use].", + "foreign-structured-upload-form-label-not-own-work-message-wikimediacommons": "If you do not own the copyright on this file, or you wish to release it under a different license, consider using the [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Upload Wizard].", + "foreign-structured-upload-form-label-not-own-work-local-wikimediacommons": "You may also want to try using [[Special:Upload|the upload page on {{SITENAME}}]], if the site allows the upload of this file under their policies.", "backend-fail-stream": "Could not stream file \"$1\".", "backend-fail-backup": "Could not backup file \"$1\".", "backend-fail-notexists": "The file $1 does not exist.", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 6c3f459646..208e39502b 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -1588,6 +1588,16 @@ "upload-form-label-infoform-description": "Label for the file description input\n{{Identical|Description}}", "upload-form-label-usage-title": "Title for the insert form showing how to use the uploaded item.\n{{Identical|Usage}}", "upload-form-label-usage-filename": "Label for the file name input\n{{Identical|Filename}}", + "foreign-structured-upload-form-label-own-work": "Label for own work toggle", + "foreign-structured-upload-form-label-infoform-categories": "Label for category selector input", + "foreign-structured-upload-form-label-infoform-date": "Label for date input", + "foreign-structured-upload-form-label-own-work-message-default": "Message shown by default when a user affirms that they are allowed to upload a file to a remote wiki.", + "foreign-structured-upload-form-label-not-own-work-message-default": "Message shown by default when a user cannot upload a file to a remote wiki.", + "foreign-structured-upload-form-label-not-own-work-local-default": "Suggests uploading a file locally instead of to a remote wiki. $1 is the name of the local wiki.", + "foreign-structured-upload-form-label-own-work-message-wikimediacommons": "Legal message to show when the work is made by the uploader.", + "foreign-structured-upload-form-label-not-own-work-message-wikimediacommons": "Message to show when the work isn't owned by the uploader.", + "foreign-structured-upload-form-label-not-own-work-local-wikimediacommons": "Message suggesting the user might want to upload a file locally instead of to Wikimedia Commons. $1 is the name of the local wiki.", + "upload-form-label-usage-filename": "Label for the file name input\n{{Identical|Filename}}", "backend-fail-stream": "Parameters:\n* $1 - a filename", "backend-fail-backup": "Parameters:\n* $1 - a filename", "backend-fail-notexists": "Parameters:\n* $1 - a filename", diff --git a/maintenance/jsduck/categories.json b/maintenance/jsduck/categories.json index d142556a2c..ef264c3296 100644 --- a/maintenance/jsduck/categories.json +++ b/maintenance/jsduck/categories.json @@ -63,7 +63,7 @@ "mw.Feedback*", "mw.Upload*", "mw.ForeignUpload", - "mw.ForeignStructuredUpload" + "mw.ForeignStructuredUpload*" ] }, { diff --git a/resources/Resources.php b/resources/Resources.php index d6e13ed3f4..14ab8fe19e 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -1184,6 +1184,26 @@ return array( 'upload-form-label-usage-filename', ), ), + 'mediawiki.ForeignStructuredUpload.BookletLayout' => array( + 'scripts' => 'resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js', + 'dependencies' => array( + 'mediawiki.ForeignStructuredUpload', + 'mediawiki.Upload.BookletLayout', + 'mediawiki.widgets', + 'mediawiki.jqueryMsg', + ), + 'messages' => array( + 'foreign-structured-upload-form-label-own-work', + 'foreign-structured-upload-form-label-infoform-categories', + 'foreign-structured-upload-form-label-infoform-date', + 'foreign-structured-upload-form-label-own-work-message-default', + 'foreign-structured-upload-form-label-not-own-work-message-default', + 'foreign-structured-upload-form-label-not-own-work-local-default', + 'foreign-structured-upload-form-label-own-work-message-wikimediacommons', + 'foreign-structured-upload-form-label-not-own-work-message-wikimediacommons', + 'foreign-structured-upload-form-label-not-own-work-local-wikimediacommons', + ), + ), 'mediawiki.toc' => array( 'scripts' => 'resources/src/mediawiki/mediawiki.toc.js', 'dependencies' => 'mediawiki.cookie', diff --git a/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js b/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js new file mode 100644 index 0000000000..3051d52e73 --- /dev/null +++ b/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js @@ -0,0 +1,196 @@ +/*global moment */ +( function ( $, mw ) { + + /** + * mw.ForeignStructuredUpload.BookletLayout encapsulates the process + * of uploading a file to MediaWiki using the mw.ForeignStructuredUpload model. + * + * var uploadDialog = new mw.Upload.Dialog( { + * bookletClass: mw.ForeignStructuredUpload.BookletLayout, + * booklet: { + * targetHost: 'localhost:8080' + * } + * } ); + * var windowManager = new OO.ui.WindowManager(); + * $( 'body' ).append( windowManager.$element ); + * windowManager.addWindows( [ uploadDialog ] ); + * + * @class mw.ForeignStructuredUpload.BookletLayout + * @uses mw.ForeignStructuredUpload + * @extends mw.Upload.BookletLayout + * @cfg {string} [targetHost] Used to set up the target wiki. + * If nothing is passed, the {@link mw.ForeignUpload#property-targetHost default} is used. + */ + mw.ForeignStructuredUpload.BookletLayout = function ( config ) { + config = config || {}; + // Parent constructor + mw.ForeignStructuredUpload.BookletLayout.parent.call( this, config ); + + this.targetHost = config.targetHost; + }; + + /* Setup */ + + OO.inheritClass( mw.ForeignStructuredUpload.BookletLayout, mw.Upload.BookletLayout ); + + /* Uploading */ + + /** + * Returns a {@link mw.ForeignStructuredUpload mw.ForeignStructuredUpload} + * with the {@link #cfg-targetHost targetHost} specified in config. + * + * @protected + * @return {mw.Upload} + */ + mw.ForeignStructuredUpload.BookletLayout.prototype.createUpload = function () { + return new mw.ForeignStructuredUpload( this.targetHost ); + }; + + /* Form renderers */ + + /** + * @inheritdoc + */ + mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm = function () { + var fieldset, + target = mw.config.get( 'wgRemoteUploadTarget' ), + $ownWorkMessage = $( '

' ).html( + mw.message( 'foreign-structured-upload-form-label-own-work-message-' + target ).parse() + ), + $notOwnWorkMessage = $( '

' ).append( + $( '

' ).html( + mw.message( 'foreign-structured-upload-form-label-not-own-work-message-' + target ).parse() + ), + $( '

' ).html( + mw.message( 'foreign-structured-upload-form-label-not-own-work-local-' + target ).parse() + ) + ), + layout = this; + + this.selectFileWidget = new OO.ui.SelectFileWidget(); + this.messageLabel = new OO.ui.LabelWidget( { + label: $notOwnWorkMessage + } ); + this.ownWorkCheckbox = new OO.ui.CheckboxInputWidget().on( 'change', function ( on ) { + if ( on ) { + layout.messageLabel.setLabel( $ownWorkMessage ); + } else { + layout.messageLabel.setLabel( $notOwnWorkMessage ); + } + } ); + + fieldset = new OO.ui.FieldsetLayout(); + fieldset.addItems( [ + new OO.ui.FieldLayout( this.selectFileWidget, { + align: 'top', + label: mw.msg( 'upload-form-label-select-file' ) + } ), + new OO.ui.FieldLayout( this.ownWorkCheckbox, { + align: 'inline', + label: mw.msg( 'foreign-structured-upload-form-label-own-work' ) + } ), + this.messageLabel + ] ); + this.uploadForm = new OO.ui.FormLayout( { items: [ fieldset ] } ); + + // Validation + this.selectFileWidget.on( 'change', this.onUploadFormChange.bind( this ) ); + this.ownWorkCheckbox.on( 'change', this.onUploadFormChange.bind( this ) ); + + return this.uploadForm; + }; + + /** + * @inheritdoc + */ + mw.ForeignStructuredUpload.BookletLayout.prototype.onUploadFormChange = function () { + var file = this.selectFileWidget.getValue(), + ownWork = this.ownWorkCheckbox.isSelected(), + valid = !!file && ownWork; + this.emit( 'uploadValid', valid ); + }; + + /** + * @inheritdoc + */ + mw.ForeignStructuredUpload.BookletLayout.prototype.renderInfoForm = function () { + var fieldset; + + this.filenameWidget = new OO.ui.TextInputWidget( { + required: true, + validate: /.+/ + } ); + this.descriptionWidget = new OO.ui.TextInputWidget( { + required: true, + validate: /.+/, + multiline: true, + autosize: true + } ); + this.dateWidget = new mw.widgets.DateInputWidget( { + $overlay: this.$overlay, + required: true, + mustBeBefore: moment().add( 1, 'day' ).locale( 'en' ).format( 'YYYY-MM-DD' ) // Tomorrow + } ); + this.categoriesWidget = new mw.widgets.CategorySelector( { + $overlay: this.$overlay + } ); + + fieldset = new OO.ui.FieldsetLayout( { + label: mw.msg( 'upload-form-label-infoform-title' ) + } ); + fieldset.addItems( [ + new OO.ui.FieldLayout( this.filenameWidget, { + label: mw.msg( 'upload-form-label-infoform-name' ), + align: 'top' + } ), + new OO.ui.FieldLayout( this.categoriesWidget, { + label: mw.msg( 'foreign-structured-upload-form-label-infoform-categories' ), + align: 'top' + } ), + new OO.ui.FieldLayout( this.descriptionWidget, { + label: mw.msg( 'upload-form-label-infoform-description' ), + align: 'top' + } ), + new OO.ui.FieldLayout( this.dateWidget, { + label: mw.msg( 'foreign-structured-upload-form-label-infoform-date' ), + align: 'top' + } ) + ] ); + this.infoForm = new OO.ui.FormLayout( { items: [ fieldset ] } ); + + // Validation + this.filenameWidget.on( 'change', this.onInfoFormChange.bind( this ) ); + this.descriptionWidget.on( 'change', this.onInfoFormChange.bind( this ) ); + this.dateWidget.on( 'change', this.onInfoFormChange.bind( this ) ); + + return this.infoForm; + }; + + /** + * @inheritdoc + */ + mw.ForeignStructuredUpload.BookletLayout.prototype.onInfoFormChange = function () { + var layout = this; + $.when( + this.filenameWidget.getValidity(), + this.descriptionWidget.getValidity(), + this.dateWidget.getValidity() + ).done( function () { + layout.emit( 'infoValid', true ); + } ).fail( function () { + layout.emit( 'infoValid', false ); + } ); + }; + + /* Getters */ + + /** + * @inheritdoc + */ + mw.ForeignStructuredUpload.BookletLayout.prototype.getText = function () { + this.upload.addDescription( 'en', this.descriptionWidget.getValue() ); + this.upload.setDate( this.dateWidget.getValue() ); + this.upload.addCategories( this.categoriesWidget.getItemsData() ); + return this.upload.getText(); + }; +}( jQuery, mediaWiki ) ); diff --git a/resources/src/mediawiki/mediawiki.Upload.BookletLayout.js b/resources/src/mediawiki/mediawiki.Upload.BookletLayout.js index cb532c3800..41200d3ea6 100644 --- a/resources/src/mediawiki/mediawiki.Upload.BookletLayout.js +++ b/resources/src/mediawiki/mediawiki.Upload.BookletLayout.js @@ -59,11 +59,14 @@ * * @constructor * @param {Object} config Configuration options + * @cfg {jQuery} [$overlay] Overlay to use for widgets in the booklet */ mw.Upload.BookletLayout = function ( config ) { // Parent constructor mw.Upload.BookletLayout.parent.call( this, config ); + this.$overlay = config.$overlay; + this.renderUploadForm(); this.renderInfoForm(); this.renderInsertForm(); diff --git a/resources/src/mediawiki/mediawiki.Upload.Dialog.js b/resources/src/mediawiki/mediawiki.Upload.Dialog.js index de005f8a68..03e397180c 100644 --- a/resources/src/mediawiki/mediawiki.Upload.Dialog.js +++ b/resources/src/mediawiki/mediawiki.Upload.Dialog.js @@ -19,10 +19,22 @@ * @class mw.Upload.Dialog * @uses mw.Upload * @extends OO.ui.ProcessDialog + * @cfg {Function} [bookletClass=mw.Upload.BookletLayout] Booklet class to be + * used for the steps + * @cfg {Object} [booklet] Booklet constructor configuration */ mw.Upload.Dialog = function ( config ) { + // Config initialization + config = $.extend( { + bookletClass: mw.Upload.BookletLayout + }, config ); + // Parent constructor mw.Upload.Dialog.parent.call( this, config ); + + // Initialize + this.bookletClass = config.bookletClass; + this.bookletConfig = config.booklet; }; /* Setup */ @@ -97,7 +109,9 @@ * @return {mw.Upload.BookletLayout} An upload booklet */ mw.Upload.Dialog.prototype.createUploadBooklet = function () { - return new mw.Upload.BookletLayout(); + return new this.bookletClass( $.extend( { + $overlay: this.$overlay + }, this.bookletConfig ) ); }; /** -- 2.20.1