jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/386413 )

Change subject: Add patent license agreement
......................................................................


Add patent license agreement

Bug: T178513
Change-Id: I5194beef2378c636f06f0a61cc3daf9a7cec99bd
---
M UploadWizard.config.php
M extension.json
M i18n/en.json
M i18n/qqq.json
M resources/controller/uw.controller.Details.js
A resources/deed/dialog/uw.deed.dialog.PatentDialog.js
A resources/deed/dialog/uw.deed.dialog.base.js
M resources/deed/uw.deed.Abstract.js
M resources/deed/uw.deed.OwnWork.js
M resources/deed/uw.deed.ThirdParty.js
A resources/images/no-weapons.svg
M resources/ui/steps/uw.ui.Details.js
M resources/uploadWizard.css
M tests/qunit/controller/uw.controller.Deed.test.js
14 files changed, 582 insertions(+), 47 deletions(-)

Approvals:
  MarkTraceur: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/UploadWizard.config.php b/UploadWizard.config.php
index 06148ba..35371bf 100644
--- a/UploadWizard.config.php
+++ b/UploadWizard.config.php
@@ -523,6 +523,16 @@
                ]
        ],
 
+       'patents' => [
+               'extensions' => [ 'stl' ],
+               'url' => [
+                       'legalcode' => 
'//wikimediafoundation.org/wiki/Wikimedia_3D_file_patent_license',
+                       'warranty' => 
'//meta.wikimedia.org/wiki/Wikilegal/3D_files_and_3D_printing',
+                       'license' => 
'//meta.wikimedia.org/wiki/Wikilegal/3D_files_and_3D_printing',
+                       'weapons' => 
'//meta.wikimedia.org/wiki/Wikilegal/3D_files_and_3D_printing#Weapons',
+               ],
+       ],
+
        // Max author string length
        'maxAuthorLength' => 10000,
 
diff --git a/extension.json b/extension.json
index 12a8366..85d4017 100644
--- a/extension.json
+++ b/extension.json
@@ -675,7 +675,9 @@
                        ],
                        "messages": [
                                "mwe-upwiz-file-some-failed",
-                               "mwe-upwiz-file-all-failed"
+                               "mwe-upwiz-file-all-failed",
+                               "mwe-upwiz-patent-weapon-policy",
+                               "mwe-upwiz-patent-weapon-policy-link"
                        ],
                        "targets": [ "desktop", "mobile" ],
                        "group": "ext.uploadWizard"
@@ -761,6 +763,9 @@
                        "dependencies": [
                                "uw.deed.base"
                        ],
+                       "messages": [
+                               "mwe-upwiz-patent-dialog-title-filename"
+                       ],
                        "targets": [ "desktop", "mobile" ],
                        "group": "ext.uploadWizard"
                },
@@ -770,7 +775,8 @@
                        ],
                        "dependencies": [
                                "oojs",
-                               "uw.deed.Abstract"
+                               "uw.deed.Abstract",
+                               "uw.deed.dialog.PatentDialog"
                        ],
                        "messages": [
                                "mwe-upwiz-tooltip-sign",
@@ -810,6 +816,8 @@
                                "mwe-upwiz-source-ownwork-cc-zero-explain",
                                "mwe-upwiz-source-ownwork-assert-generic",
                                "mwe-upwiz-source-ownwork-generic-explain",
+                               "mwe-upwiz-patent",
+                               "mwe-upwiz-error-patent-disagree",
                                "mwe-upwiz-error-signature-blank",
                                "mwe-upwiz-error-signature-too-long",
                                "mwe-upwiz-error-signature-too-short",
@@ -865,6 +873,42 @@
                        "targets": [ "desktop", "mobile" ],
                        "group": "ext.uploadWizard"
                },
+               "uw.deed.dialog.base": {
+                       "scripts": [
+                               "resources/deed/dialog/uw.deed.dialog.base.js"
+                       ],
+                       "dependencies": [
+                               "uw.deed.base"
+                       ],
+                       "targets": [ "desktop", "mobile" ],
+                       "group": "ext.uploadWizard"
+               },
+               "uw.deed.dialog.PatentDialog": {
+                       "scripts": [
+                               
"resources/deed/dialog/uw.deed.dialog.PatentDialog.js"
+                       ],
+                       "dependencies": [
+                               "mediawiki.language",
+                               "oojs",
+                               "oojs-ui-core",
+                               "oojs-ui-windows",
+                               "uw.deed.dialog.base"
+                       ],
+                       "messages": [
+                               "mwe-upwiz-patent-dialog-title",
+                               "mwe-upwiz-patent-dialog-button-back",
+                               "mwe-upwiz-patent-dialog-button-next",
+                               "mwe-upwiz-patent-dialog-title-warranty",
+                               "mwe-upwiz-patent-dialog-text-warranty",
+                               "mwe-upwiz-patent-dialog-link-warranty",
+                               "mwe-upwiz-patent-dialog-title-license",
+                               "mwe-upwiz-patent-dialog-text-license",
+                               "mwe-upwiz-patent-dialog-link-license",
+                               "mwe-upwiz-patent-dialog-checkbox-label"
+                       ],
+                       "targets": [ "desktop", "mobile" ],
+                       "group": "ext.uploadWizard"
+               },
                "uw.units": {
                        "scripts": [
                                "resources/uw.units.js"
diff --git a/i18n/en.json b/i18n/en.json
index 80bbba3..e4720d9 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -121,6 +121,20 @@
        "mwe-upwiz-source-thirdparty-cases": "Now tell us why you are sure you 
have the right to publish {{PLURAL:$1|this work|these works}}:",
        "mwe-upwiz-source-thirdparty-accept": "OK",
        "mwe-upwiz-source-custom": "Provide copyright information for each file 
individually on the next page.",
+       "mwe-upwiz-patent": "I, $2, would like to grant a permanent patent 
license to any users of {{PLURAL:$1|the file|the files}} and related 3D objects 
([$3 legal code]).",
+       "mwe-upwiz-patent-dialog-title": "Patent rights",
+       "mwe-upwiz-patent-dialog-title-filename": "Legal rights for: $1",
+       "mwe-upwiz-patent-dialog-button-back": "Back",
+       "mwe-upwiz-patent-dialog-button-next": "Next",
+       "mwe-upwiz-patent-dialog-title-warranty": "Warranty about Patents",
+       "mwe-upwiz-patent-dialog-text-warranty": "Use of {{PLURAL:$1|this 
file|these files}} and any objects depicted in {{PLURAL:$1|the file|the files}} 
will not knowingly or recklessly infringe any patents.",
+       "mwe-upwiz-patent-dialog-link-warranty": "Learn more",
+       "mwe-upwiz-patent-dialog-title-license": "Patent License",
+       "mwe-upwiz-patent-dialog-text-license": "Any 3D objects depicted in 
{{PLURAL:$1|the file|the files}} are my own work.",
+       "mwe-upwiz-patent-dialog-link-license": "Learn more",
+       "mwe-upwiz-patent-dialog-checkbox-label": "I agree with these terms",
+       "mwe-upwiz-patent-weapon-policy": "Users should avoid uploading any 3D 
models that could be viewed as a weapon or \"defense article\".\nThe Commons 
community might remove such items upon moderation.",
+       "mwe-upwiz-patent-weapon-policy-link": "Read policy details",
        "mwe-upwiz-more-options": "Add location and more information …",
        "mwe-upwiz-copy-metadata": "Copy information to all uploads following 
…",
        "mwe-upwiz-copy-metadata-button": "Copy",
@@ -220,6 +234,7 @@
        "mwe-upwiz-error-license-wikitext-too-short": "The wikitext here is too 
short to be a license",
        "mwe-upwiz-error-license-wikitext-too-long": "The wikitext you entered 
is too long.",
        "mwe-upwiz-error-license-wikitext-missing-template": "The wikitext you 
entered doesn't contain a valid license template.",
+       "mwe-upwiz-error-patent-disagree": "You need to agree with the terms.",
        "mwe-upwiz-warning-categories-missing": "It is recommended that you 
fill in some categories for your uploads.",
        "mwe-upwiz-warning-postdate": "The date that you selected is in the 
future.",
        "mwe-upwiz-details-error-count": "There {{PLURAL:$1|is one error|are $1 
errors}} with the {{PLURAL:$2|form|forms}} above. Correct the 
{{PLURAL:$1|error|errors}}, and try submitting again.",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 7086a39..90d2bf3 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -148,6 +148,20 @@
        "mwe-upwiz-source-thirdparty-cases": "This message is followed by the 
License form. Parameters:\n* $1 - number of works. i.e. number of uploads",
        "mwe-upwiz-source-thirdparty-accept": "{{Identical|OK}}",
        "mwe-upwiz-source-custom": "Prompts the user for the copyright 
information for each file.",
+       "mwe-upwiz-patent": "Parameters:\n* $1 - number of works (number of 3D 
uploads)\n* $2 - author name\n* $3 - full URL\n* $4 - a user object, which can 
be used for GENDER",
+       "mwe-upwiz-patent-dialog-title": "Title for the dialog to confirm 
agreement with patent rights.",
+       "mwe-upwiz-patent-dialog-title-filename": "Title for the dialog to 
confirm agreement with patent rights for a single file. Parameters:\n$ $1 - the 
upload filename",
+       "mwe-upwiz-patent-dialog-button-back": "Title text for the \"back\" 
button in the patent rights dialog.",
+       "mwe-upwiz-patent-dialog-button-next": "Text for the \"next\" button in 
the patent rights dialog.",
+       "mwe-upwiz-patent-dialog-title-warranty": "Title for the patent rights 
dialog paragraph about patents warranty.",
+       "mwe-upwiz-patent-dialog-text-warranty": "Text for the patent rights 
dialog paragraph about patents warranty.\n\nParameters:\n* $1 - the number of 
uploads for PLURAL",
+       "mwe-upwiz-patent-dialog-link-warranty": "Link text for the patent 
rights dialog paragraph about patents warranty.",
+       "mwe-upwiz-patent-dialog-title-license": "Title for the patent rights 
dialog paragraph about patents license.",
+       "mwe-upwiz-patent-dialog-text-license": "Text for the patent rights 
dialog paragraph about patents license.\n\nParameters:\n* $1 - the number of 
uploads for PLURAL",
+       "mwe-upwiz-patent-dialog-link-license": "Link text for the patent 
rights dialog paragraph about patents license.",
+       "mwe-upwiz-patent-dialog-checkbox-label": "Label for the checbox to 
agree with the patent terms.",
+       "mwe-upwiz-patent-weapon-policy": "Text to instruct users not to upload 
3D models that could be viewed as a weapon or \"defense article\".",
+       "mwe-upwiz-patent-weapon-policy-link": "Link text to the policy 
details",
        "mwe-upwiz-more-options": "Text for a 'more options' toggle that opens 
more of a form so a user can make more detailed descriptions/add more 
properties for uploaded images.",
        "mwe-upwiz-copy-metadata": "Toggler which expands/collapses a selection 
of checkboxes vertically which allow the user to selectively copy metadata from 
the first upload to other uploads.",
        "mwe-upwiz-copy-metadata-button": "Label of the button which copies the 
selected metadata from the first upload to all other 
uploads.\n{{Identical|Copy}}",
@@ -247,6 +261,7 @@
        "mwe-upwiz-error-license-wikitext-too-short": "Message for a failed 
minimum length validation on the license form.",
        "mwe-upwiz-error-license-wikitext-too-long": "Message for a failed 
maximum length validation on the license form.",
        "mwe-upwiz-error-license-wikitext-missing-template": "Message for when 
the wikitext doesn't contain a valid license template.",
+       "mwe-upwiz-error-patent-disagree": "Error message for when the uploader 
doesn't agree with the patent terms.",
        "mwe-upwiz-warning-categories-missing": "Warning message displayed when 
the user has not selected any categories.",
        "mwe-upwiz-warning-postdate": "Warning message displayed when the user 
selects a file creation date that is in the future.",
        "mwe-upwiz-details-error-count": "Used as error message. Parameters:\n* 
$1 - number of errors\n* $2 - number of forms. i.e. number of uploads",
diff --git a/resources/controller/uw.controller.Details.js 
b/resources/controller/uw.controller.Details.js
index eac65f8..f64b4ca 100644
--- a/resources/controller/uw.controller.Details.js
+++ b/resources/controller/uw.controller.Details.js
@@ -314,7 +314,6 @@
 
                // Disable edit interface
                this.ui.disableEdits();
-               this.ui.previousButton.$element.hide();
                this.removeCopyMetadataFeature();
 
                return this.transitionAll().then( function () {
@@ -331,7 +330,7 @@
         * See UI class for more.
         */
        uw.controller.Details.prototype.showErrors = function () {
-               this.ui.previousButton.$element.show();
+               this.ui.enableEdits();
 
                this.removeCopyMetadataFeature();
                this.addCopyMetadataFeature();
diff --git a/resources/deed/dialog/uw.deed.dialog.PatentDialog.js 
b/resources/deed/dialog/uw.deed.dialog.PatentDialog.js
new file mode 100644
index 0000000..60439b9
--- /dev/null
+++ b/resources/deed/dialog/uw.deed.dialog.PatentDialog.js
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the MediaWiki extension UploadWizard.
+ *
+ * UploadWizard 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.
+ *
+ * UploadWizard 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 UploadWizard.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+( function ( mw, uw, $, OO ) {
+       /**
+        * @param {Object} config Dialog config
+        * @param {Object} uwConfig UploadWizard config
+        * @param {mw.UploadWizardUpload[]} uploads
+        * @constructor
+        */
+       uw.PatentDialog = function PatentDialog( config, uwConfig, uploads ) {
+               uw.PatentDialog.super.call( this, config );
+               this.config = uwConfig;
+               this.panels = config.panels || [];
+               this.uploads = uploads;
+       };
+
+       OO.inheritClass( uw.PatentDialog, OO.ui.ProcessDialog );
+       OO.mixinClass( uw.PatentDialog, OO.EventEmitter );
+
+       uw.PatentDialog.static.name = 'uwPatentDialog';
+       uw.PatentDialog.static.title = mw.msg( 'mwe-upwiz-patent-dialog-title' 
);
+       uw.PatentDialog.static.actions = [
+               {
+                       flags: [ 'primary', 'progressive' ],
+                       indicator: 'next',
+                       action: 'confirm',
+                       label: OO.ui.deferMsg( 
'mwe-upwiz-patent-dialog-button-next' ),
+                       disabled: true
+               },
+               {
+                       flags: [ 'safe', 'back' ],
+                       icon: 'previous',
+                       title: OO.ui.deferMsg( 
'mwe-upwiz-patent-dialog-button-back' ),
+                       framed: false
+               }
+       ];
+
+       uw.PatentDialog.prototype.initialize = function () {
+               var filenames = [],
+                       label = new OO.ui.LabelWidget(),
+                       panels = new OO.ui.PanelLayout( { padded: true, 
expanded: false } );
+
+               uw.PatentDialog.super.prototype.initialize.apply( this, 
arguments );
+
+               $.each( this.uploads, function ( i, upload ) {
+                       filenames.push(
+                               // use given title (if available already) or 
fall back to filename
+                               upload.details ? 
upload.details.getTitle().getMainText() : upload.title.getMainText()
+                       );
+               } );
+
+               this.content = new OO.ui.PanelLayout( { padded: false, 
expanded: false } );
+               this.content.$element.addClass( 'mwe-upwiz-patent-rights' );
+
+               if ( $.inArray( 'filelist', this.panels ) >= 0 ) {
+                       label.setLabel( mw.msg( 
'mwe-upwiz-patent-dialog-title-filename', mw.language.listToText( filenames ) ) 
);
+                       label.$element.addClass( 'oo-ui-processDialog-title 
mwe-upwiz-patent-rights-filelist' );
+                       this.content.$element.append( label.$element );
+               }
+
+               if ( $.inArray( 'warranty', this.panels ) >= 0 ) {
+                       panels.$element.append( 
this.getWarrantyLayout().$element );
+               }
+
+               if ( $.inArray( 'license', this.panels ) >= 0 ) {
+                       panels.$element.append( 
this.getLicenseLayout().$element );
+               }
+
+               this.checkbox = new OO.ui.CheckboxInputWidget();
+               this.checkbox.connect( this, { change: 'onCheckboxChange' } );
+               panels.$element.append( this.getCheckboxLayout().$element );
+
+               this.content.$element.append( panels.$element );
+               this.$body.append( this.content.$element );
+       };
+
+       /**
+        * @return {OO.ui.PanelLayout}
+        */
+       uw.PatentDialog.prototype.getWarrantyLayout = function () {
+               var layout = new OO.ui.PanelLayout( { padded: true, expanded: 
false } );
+
+               layout.$element.append(
+                       $( '<strong>' ).text( mw.msg( 
'mwe-upwiz-patent-dialog-title-warranty' ) ),
+                       $( '<p>' ).text( mw.msg( 
'mwe-upwiz-patent-dialog-text-warranty', this.uploads.length ) ),
+                       $( '<a>' )
+                               .text( mw.msg( 
'mwe-upwiz-patent-dialog-link-warranty' ) )
+                               .attr( { target: '_blank', href: 
this.config.patents.url.warranty } )
+               );
+
+               return layout;
+       };
+
+       /**
+        * @return {OO.ui.PanelLayout}
+        */
+       uw.PatentDialog.prototype.getLicenseLayout = function () {
+               var layout = new OO.ui.PanelLayout( { padded: true, expanded: 
false } );
+
+               layout.$element.append(
+                       $( '<strong>' ).text( mw.msg( 
'mwe-upwiz-patent-dialog-title-license' ) ),
+                       $( '<p>' ).text( mw.msg( 
'mwe-upwiz-patent-dialog-text-license', this.uploads.length ) ),
+                       $( '<a>' )
+                               .text( mw.msg( 
'mwe-upwiz-patent-dialog-link-license' ) )
+                               .attr( { target: '_blank', href: 
this.config.patents.url.license } )
+               );
+
+               return layout;
+       };
+
+       /**
+        * @return {OO.ui.PanelLayout}
+        */
+       uw.PatentDialog.prototype.getCheckboxLayout = function () {
+               var checkbox = new OO.ui.FieldLayout( this.checkbox, {
+                       label: mw.msg( 'mwe-upwiz-patent-dialog-checkbox-label' 
),
+                       align: 'inline'
+               } );
+
+               return new OO.ui.PanelLayout( {
+                       padded: true,
+                       expanded: false,
+                       $content: checkbox.$element
+               } );
+       };
+
+       /**
+        * @param {boolean} checked
+        */
+       uw.PatentDialog.prototype.onCheckboxChange = function ( checked ) {
+               var button = this.actions.get( { flags: 'primary' } )[ 0 ];
+               button.setDisabled( !checked );
+       };
+
+       /**
+        * @param {string} action
+        * @return {OO.ui.Process} Action process
+        */
+       uw.PatentDialog.prototype.getActionProcess = function ( action ) {
+               var dialog = this;
+
+               if ( action === '' ) {
+                       this.emit( 'disagree' );
+               } else if ( action === 'confirm' ) {
+                       return new OO.ui.Process( function () {
+                               dialog.emit( 'agree' );
+                               dialog.close( { action: action } );
+                       } );
+               }
+
+               return uw.PatentDialog.super.prototype.getActionProcess.call( 
this, action );
+       };
+
+       uw.PatentDialog.prototype.getBodyHeight = function () {
+               return this.content.$element.outerHeight( true );
+       };
+}( mediaWiki, mediaWiki.uploadWizard, jQuery, OO ) );
diff --git a/resources/deed/dialog/uw.deed.dialog.base.js 
b/resources/deed/dialog/uw.deed.dialog.base.js
new file mode 100644
index 0000000..43b9e8c
--- /dev/null
+++ b/resources/deed/dialog/uw.deed.dialog.base.js
@@ -0,0 +1,21 @@
+/*
+ * This file is part of the MediaWiki extension UploadWizard.
+ *
+ * UploadWizard 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.
+ *
+ * UploadWizard 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 UploadWizard.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+( function ( uw ) {
+       // create UploadWizard deed.dialog namespace
+       uw.deed.dialog = {};
+}( mediaWiki.uploadWizard ) );
diff --git a/resources/deed/uw.deed.Abstract.js 
b/resources/deed/uw.deed.Abstract.js
index 05fdcaf..10dced8 100644
--- a/resources/deed/uw.deed.Abstract.js
+++ b/resources/deed/uw.deed.Abstract.js
@@ -37,7 +37,7 @@
        uw.deed.Abstract.prototype.instanceCount = 0;
 
        /**
-        * @returns {number}
+        * @return {number}
         */
        uw.deed.Abstract.prototype.getInstanceCount = function () {
                return this.instanceCount;
@@ -103,4 +103,86 @@
                        this.name = serialized.name;
                }
        };
+
+       /**
+        * @param {mw.UploadWizardUpload[]} uploads Array of uploads
+        * @return {number}
+        */
+       uw.deed.Abstract.prototype.get3DCount = function ( uploads ) {
+               var extensions = this.config.patents ? 
this.config.patents.extensions : [],
+                       threeDCount = 0;
+
+               $.each( uploads, function ( i, upload ) {
+                       if ( $.inArray( 
upload.title.getExtension().toLowerCase(), extensions ) >= 0 ) {
+                               threeDCount++;
+                       }
+               } );
+
+               return threeDCount;
+       };
+
+       /**
+        * @param {mw.UploadWizardUpload[]} uploads
+        * @return {uw.FieldLayout}
+        */
+       uw.deed.Abstract.prototype.getPatentAgreementField = function ( uploads 
) {
+               var field = new OO.ui.HiddenInputWidget();
+               field.getErrors = this.getPatentAgreementErrors.bind( this, 
field, uploads );
+               field.getWarnings = $.Deferred().resolve( [] ).promise.bind();
+
+               return new uw.FieldLayout( field );
+       };
+
+       /**
+        * @param {mw.UploadWizardUpload[]} uploads
+        * @return {uw.PatentDialog}
+        */
+       uw.deed.Abstract.prototype.getPatentDialog = function ( uploads ) {
+               var config = { panels: [ 'warranty' ] };
+
+               // Only show filename list when in "details" step & we're 
showing the dialog for individual files
+               if ( uploads[ 0 ] && uploads[ 0 ].state === 'details' ) {
+                       config.panels.unshift( 'filelist' );
+               }
+
+               return new uw.PatentDialog( config, this.config, uploads );
+       };
+
+       /**
+        * @param {OO.ui.InputWidget} input
+        * @param {mw.UploadWizardUpload[]} uploads
+        * @param {boolean} thorough
+        * @return {jQuery.Promise}
+        */
+       uw.deed.Abstract.prototype.getPatentAgreementErrors = function ( input, 
uploads, thorough ) {
+               var deed = this,
+                       windowManager, dialog, deferred;
+
+               // We only want to test this on submit
+               if ( !thorough ) {
+                       return $.Deferred().resolve( [] ).promise();
+               }
+
+               if ( this.patentAgreed !== true ) {
+                       deferred = $.Deferred();
+                       windowManager = new OO.ui.WindowManager();
+                       dialog = this.getPatentDialog( uploads );
+
+                       $( 'body' ).append( windowManager.$element );
+                       windowManager.addWindows( [ dialog ] );
+                       windowManager.openWindow( dialog );
+
+                       dialog.on( 'disagree', function () {
+                               deferred.resolve( [ mw.message( 
'mwe-upwiz-error-patent-disagree' ) ] );
+                       } );
+                       dialog.on( 'agree', function () {
+                               deed.patentAgreed = true;
+                               deferred.resolve( [] );
+                       } );
+
+                       return deferred.promise();
+               } else {
+                       return $.Deferred().resolve( [] ).promise();
+               }
+       };
 }( mediaWiki, mediaWiki.uploadWizard ) );
diff --git a/resources/deed/uw.deed.OwnWork.js 
b/resources/deed/uw.deed.OwnWork.js
index f5f008a..e046800 100644
--- a/resources/deed/uw.deed.OwnWork.js
+++ b/resources/deed/uw.deed.OwnWork.js
@@ -32,6 +32,7 @@
                uw.deed.Abstract.call( this, 'ownwork', config );
 
                this.uploadCount = uploads.length;
+               this.threeDCount = this.get3DCount( uploads );
 
                if ( !prefAuthName ) {
                        prefAuthName = mw.config.get( 'wgUserName' );
@@ -65,6 +66,26 @@
                        this.licenseInput.$element.addClass( 
'mwe-upwiz-deed-license' );
                        this.licenseInputField = new uw.FieldLayout( 
this.licenseInput );
                }
+
+               // grant patent license
+               if ( this.threeDCount > 0 ) {
+                       this.patentAuthorInput = new OO.ui.TextInputWidget( {
+                               name: 'patent-author',
+                               title: mw.message( 'mwe-upwiz-tooltip-sign' 
).text(),
+                               value: prefAuthName,
+                               classes: [ 'mwe-upwiz-sign' ]
+                       } );
+                       // keep authors in sync!
+                       this.patentAuthorInput.on( 'change', function () {
+                               deed.authorInput.setValue( 
deed.patentAuthorInput.getValue() );
+                               deed.fakeAuthorInput.setValue( 
deed.patentAuthorInput.getValue() );
+                       } );
+                       this.authorInput.on( 'change', function () {
+                               deed.patentAuthorInput.setValue( 
deed.authorInput.getValue() );
+                       } );
+
+                       this.patentAgreementField = 
this.getPatentAgreementField( uploads );
+               }
        };
 
        OO.inheritClass( uw.deed.OwnWork, uw.deed.Abstract );
@@ -77,13 +98,18 @@
                if ( this.showCustomDiv ) {
                        fields.push( this.licenseInputField );
                }
+               if ( this.threeDCount > 0 ) {
+                       fields.push( this.patentAuthorInputField );
+                       fields.push( this.patentAgreementField );
+               }
                return fields;
        };
 
        uw.deed.OwnWork.prototype.setFormFields = function ( $selector ) {
                var $customDiv, $formFields, $toggler, crossfaderWidget, 
defaultLicense,
                        defaultLicenseURL, defaultLicenseMsg, 
defaultLicenseExplainMsg,
-                       defaultLicenseLink, $standardDiv, $crossfader, deed, 
languageCode;
+                       defaultLicenseLink, $standardDiv, $crossfader, deed, 
languageCode,
+                       patentMsg, patentLink, $patentDiv, patentWidget;
 
                this.$selector = $selector;
                deed = this;
@@ -128,27 +154,9 @@
                crossfaderWidget = new OO.ui.Widget();
                crossfaderWidget.$element.append( $crossfader );
                // See uw.DetailsWidget
-               crossfaderWidget.getErrors = function () {
-                       var
-                               errors = [],
-                               minLength = deed.config.minAuthorLength,
-                               maxLength = deed.config.maxAuthorLength,
-                               text = deed.authorInput.getValue().trim();
+               crossfaderWidget.getErrors = this.getAuthorErrors.bind( this, 
this.authorInput );
+               crossfaderWidget.getWarnings = this.getAuthorWarnings.bind( 
this, this.authorInput );
 
-                       if ( text === '' ) {
-                               errors.push( mw.message( 
'mwe-upwiz-error-signature-blank' ) );
-                       } else if ( text.length < minLength ) {
-                               errors.push( mw.message( 
'mwe-upwiz-error-signature-too-short', minLength ) );
-                       } else if ( text.length > maxLength ) {
-                               errors.push( mw.message( 
'mwe-upwiz-error-signature-too-long', maxLength ) );
-                       }
-
-                       return $.Deferred().resolve( errors ).promise();
-               };
-               // See uw.DetailsWidget
-               crossfaderWidget.getWarnings = function () {
-                       return $.Deferred().resolve( [] ).promise();
-               };
                this.authorInputField = new uw.FieldLayout( crossfaderWidget );
                // Aggregate 'change' event
                this.authorInput.on( 'change', OO.ui.debounce( function () {
@@ -156,24 +164,51 @@
                }, 500 ) );
 
                $formFields = $( '<div class="mwe-upwiz-deed-form-internal" />' 
)
-                       .append(
-                               this.authorInputField.$element,
-                               this.showCustomDiv ? 
this.licenseInputField.$element.hide() : ''
-               );
-
-               $toggler = $( '<p class="mwe-more-options" style="text-align: 
right"></p>' )
-                       .append( $( '<a />' )
-                               .msg( 'mwe-upwiz-license-show-all' )
-                               .click( function () {
-                                       if ( $crossfader.data( 
'crossfadeDisplay' ).get( 0 ) === $customDiv.get( 0 ) ) {
-                                               deed.standardLicense();
-                                       } else {
-                                               deed.customLicense();
-                                       }
-                               } ) );
+                       .append( this.authorInputField.$element );
 
                if ( this.showCustomDiv ) {
-                       $formFields.append( $toggler );
+                       $toggler = $( '<p class="mwe-more-options" 
style="text-align: right"></p>' )
+                               .append( $( '<a />' )
+                                       .msg( 'mwe-upwiz-license-show-all' )
+                                       .click( function () {
+                                               if ( $crossfader.data( 
'crossfadeDisplay' ).get( 0 ) === $customDiv.get( 0 ) ) {
+                                                       deed.standardLicense();
+                                               } else {
+                                                       deed.customLicense();
+                                               }
+                                       } ) );
+
+                       $formFields.append( 
this.licenseInputField.$element.hide(), $toggler );
+               }
+
+               if ( this.threeDCount > 0 ) {
+                       patentMsg = 'mwe-upwiz-patent';
+                       patentLink = $( '<a>' ).attr( { target: '_blank', href: 
this.config.patents.url.legalcode } );
+
+                       $patentDiv = $( '<div class="mwe-upwiz-patent" />' 
).append(
+                               $( '<p>' ).msg(
+                                       patentMsg,
+                                       this.threeDCount,
+                                       this.patentAuthorInput.$element,
+                                       patentLink,
+                                       mw.user
+                               )
+                       );
+
+                       patentWidget = new OO.ui.Widget();
+                       patentWidget.$element.append( $patentDiv );
+
+                       // See uw.DetailsWidget
+                       patentWidget.getErrors = this.getAuthorErrors.bind( 
this, this.patentAuthorInput );
+                       patentWidget.getWarnings = this.getAuthorWarnings.bind( 
this, this.patentAuthorInput );
+
+                       this.patentAuthorInputField = new uw.FieldLayout( 
patentWidget );
+                       deed.patentAuthorInput.on( 'change', OO.ui.debounce( 
function () {
+                               patentWidget.emit( 'change' );
+                       }, 500 ) );
+
+                       $formFields.append( 
this.patentAuthorInputField.$element );
+                       $formFields.append( this.patentAgreementField.$element 
);
                }
 
                this.$form.append( $formFields ).appendTo( $selector );
@@ -234,6 +269,10 @@
                        serialized.license = this.licenseInput.getSerialized();
                }
 
+               if ( this.threeDCount > 0 ) {
+                       serialized.patentAuthor = 
this.patentAuthorInput.getValue();
+               }
+
                return serialized;
        };
 
@@ -254,6 +293,10 @@
                                this.customLicense();
                                this.licenseInput.setSerialized( 
serialized.license );
                        }
+               }
+
+               if ( this.threeDCount > 0 && serialized.patentAuthor ) {
+                       this.patentAuthorInput.setValue( 
serialized.patentAuthor );
                }
        };
 
@@ -315,4 +358,48 @@
 
                $toggler.msg( 'mwe-upwiz-license-show-recommended' );
        };
+
+       /**
+        * @param {OO.ui.InputWidget} input
+        * @return {jQuery.Promise}
+        */
+       uw.deed.OwnWork.prototype.getAuthorErrors = function ( input ) {
+               var
+                       errors = [],
+                       minLength = this.config.minAuthorLength,
+                       maxLength = this.config.maxAuthorLength,
+                       text = input.getValue().trim();
+
+               if ( text === '' ) {
+                       errors.push( mw.message( 
'mwe-upwiz-error-signature-blank' ) );
+               } else if ( text.length < minLength ) {
+                       errors.push( mw.message( 
'mwe-upwiz-error-signature-too-short', minLength ) );
+               } else if ( text.length > maxLength ) {
+                       errors.push( mw.message( 
'mwe-upwiz-error-signature-too-long', maxLength ) );
+               }
+
+               return $.Deferred().resolve( errors ).promise();
+       };
+
+       /**
+        * @return {jQuery.Promise}
+        */
+       uw.deed.OwnWork.prototype.getAuthorWarnings = function () {
+               return $.Deferred().resolve( [] ).promise();
+       };
+
+       /**
+        * @param {mw.UploadWizardUpload[]} uploads
+        * @return {uw.PatentDialog}
+        */
+       uw.deed.OwnWork.prototype.getPatentDialog = function ( uploads ) {
+               var config = { panels: [ 'warranty', 'license' ] };
+
+               // Only show filename list when in "details" step & we're 
showing the dialog for individual files
+               if ( uploads[ 0 ] && uploads[ 0 ].state === 'details' ) {
+                       config.panels.unshift( 'filelist' );
+               }
+
+               return new uw.PatentDialog( config, this.config, uploads );
+       };
 }( mediaWiki, mediaWiki.uploadWizard, jQuery, OO ) );
diff --git a/resources/deed/uw.deed.ThirdParty.js 
b/resources/deed/uw.deed.ThirdParty.js
index ec8ed59..09b3b66 100644
--- a/resources/deed/uw.deed.ThirdParty.js
+++ b/resources/deed/uw.deed.ThirdParty.js
@@ -31,6 +31,7 @@
                uw.deed.Abstract.call( this, 'thirdparty', config );
 
                this.uploadCount = uploads.length;
+               this.threeDCount = this.get3DCount( uploads );
 
                this.sourceInput = new OO.ui.MultilineTextInputWidget( {
                        autosize: true,
@@ -111,6 +112,10 @@
                this.licenseInputField = new uw.FieldLayout( this.licenseInput, 
{
                        label: mw.message( 'mwe-upwiz-source-thirdparty-cases', 
this.uploadCount ).text()
                } );
+
+               if ( this.threeDCount > 0 ) {
+                       this.patentAgreementField = 
this.getPatentAgreementField( uploads );
+               }
        };
 
        OO.inheritClass( uw.deed.ThirdParty, uw.deed.Abstract );
@@ -119,7 +124,11 @@
         * @return {uw.FieldLayout[]} Fields that need validation
         */
        uw.deed.ThirdParty.prototype.getFields = function () {
-               return [ this.authorInputField, this.sourceInputField, 
this.licenseInputField ];
+               var fields = [ this.authorInputField, this.sourceInputField, 
this.licenseInputField ];
+               if ( this.threeDCount > 0 ) {
+                       fields.push( this.patentAgreementField );
+               }
+               return fields;
        };
 
        uw.deed.ThirdParty.prototype.setFormFields = function ( $selector ) {
@@ -144,6 +153,10 @@
                                .append( this.licenseInputField.$element )
                );
 
+               if ( this.threeDCount > 0 ) {
+                       $formFields.append( this.patentAgreementField.$element 
);
+               }
+
                this.$form.append( $formFields );
 
                $selector.append( this.$form );
diff --git a/resources/images/no-weapons.svg b/resources/images/no-weapons.svg
new file mode 100644
index 0000000..c7c0db7
--- /dev/null
+++ b/resources/images/no-weapons.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg";>
+<title>Group 5</title>
+<desc>Created with Sketch.</desc>
+<g fill="none" fill-rule="evenodd">
+<g transform="translate(-237 -711)">
+<g transform="translate(238 712)">
+<circle cx="12" cy="12" r="12" stroke="#000" stroke-width="2"/>
+<path d="m6.7059 1.7647l10.684 20.7" stroke="#000" stroke-linecap="square" 
stroke-width="2"/>
+<path d="m19.951 7.0363h-0.68282l-0.47409 
0.47289h-11.527l-0.27797-0.42606h-0.4985l-0.38043 0.88374h-0.85812v1.3294c0 
0.057435-0.29478 0.30018-0.33841 0.36863-0.093657 0.14689-0.20392 
0.44527-0.027217 0.55774 0.11787 0.072444 0.36122 0.044627 0.4971 0.08105 
0.10707 0.027817 0.20392 0.064039 0.29738 0.11967 0 0 0.63639 0.25376 0.63639 
1.1571 0 0 0 0.94878-0.6482 2.1291-0.3234 0.59016-1.9186 2.6824-1.9186 4.3 0 
0.67101 0.74005 0.57855 0.74005 0.57855h3.7677s0.51071-0.1629 
0.51071-0.87874l1.4683-4.0591s0.24755-0.8247 0.89134-0.38063c0.36262 0.25095 
2.1451 0.12187 2.7011 0.12187 0.56214 0 1.1273-0.47329 
1.23-0.97119l0.13868-1.1401s0.093857-0.34621 
1.2027-0.34621h4.0713s0.64179-0.024215 
0.64179-0.76447v-1.3294l-0.68862-1.331-0.47449-0.47289zm-6.2332 
5.7485h-1.8507s-0.88994 0.044627-0.88994-0.92817c0-0.79168 0.59837-0.9834 
0.92477-0.9834-0.14529 1.4279 0.99701 1.6154 0.70703 0.92036-0.29038-0.69663 
0.45308-1.017 0.45308-1.017l0.79469 0.0078048s0.67081 0.03262 0.67081 
0.99121c-2.001e-4 0.66-0.3234 1.0092-0.80969 1.0092z" fill="#000" 
fill-rule="nonzero"/>
+</g>
+</g>
+</g>
+</svg>
diff --git a/resources/ui/steps/uw.ui.Details.js 
b/resources/ui/steps/uw.ui.Details.js
index 5e1a041..582ef80 100644
--- a/resources/ui/steps/uw.ui.Details.js
+++ b/resources/ui/steps/uw.ui.Details.js
@@ -72,6 +72,21 @@
        uw.ui.Details.prototype.load = function ( uploads ) {
                uw.ui.Step.prototype.load.call( this, uploads );
 
+               if ( this.get3DCount( uploads ) > 0 ) {
+                       this.$div.prepend(
+                               $( '<div>' )
+                                       .addClass( 
'mwe-upwiz-patent-weapon-policy ui-corner-all' )
+                                       .append(
+                                               $( '<p>' ).append( mw.msg( 
'mwe-upwiz-patent-weapon-policy' ) ),
+                                               $( '<p>' ).append(
+                                                       $( '<a>' )
+                                                               .text( mw.msg( 
'mwe-upwiz-patent-weapon-policy-link' ) )
+                                                               .attr( { 
target: '_blank', href: mw.UploadWizard.config.patents.url.weapons } )
+                                               )
+                                       )
+                       );
+               }
+
                this.$div.prepend(
                        $( '<div>' )
                                .attr( 'id', 'mwe-upwiz-macro-files' )
@@ -145,6 +160,17 @@
                this.$div
                        .find( '.mwe-upwiz-data' )
                        .morphCrossfade( '.mwe-upwiz-submitting' );
+
+               this.previousButton.$element.hide();
+               this.$div.find( '.mwe-upwiz-patent-weapon-policy' ).hide();
+       };
+
+       /**
+        * Re-enabled edits to the details.
+        */
+       uw.ui.Details.prototype.enableEdits = function () {
+               this.previousButton.$element.show();
+               this.$div.find( '.mwe-upwiz-patent-weapon-policy' ).show();
        };
 
        /**
@@ -213,4 +239,21 @@
                }
        };
 
+       /**
+        * @param {mw.UploadWizardUpload[]} uploads Array of uploads
+        * @return {number}
+        */
+       uw.ui.Details.prototype.get3DCount = function ( uploads ) {
+               var extensions = mw.UploadWizard.config.patents.extensions,
+                       threeDCount = 0;
+
+               $.each( uploads, function ( i, upload ) {
+                       if ( $.inArray( 
upload.title.getExtension().toLowerCase(), extensions ) >= 0 ) {
+                               threeDCount++;
+                       }
+               } );
+
+               return threeDCount;
+       };
+
 }( mediaWiki, jQuery, mediaWiki.uploadWizard, OO ) );
diff --git a/resources/uploadWizard.css b/resources/uploadWizard.css
index 6c30f3c..fa7bd62 100644
--- a/resources/uploadWizard.css
+++ b/resources/uploadWizard.css
@@ -186,6 +186,26 @@
        width: 300px;
 }
 
+.mwe-upwiz-patent-rights .oo-ui-panelLayout 
.oo-ui-panelLayout:not(:last-child) {
+       box-shadow: 0 1em 1px -1em #bbb;
+}
+
+.mwe-upwiz-patent-rights-filelist {
+       display: block;
+       text-align: center;
+       box-shadow: 0 0 1px 0 #bbb;
+}
+
+.mwe-upwiz-patent-weapon-policy {
+       margin-top: 1em;
+       padding: 0 1em 0 calc( 32px + 2em );
+       border: 1px solid #c8ccd1;
+       white-space: pre-wrap;
+       /* @embed */
+       background: #f2f4f7 url( images/no-weapons.svg ) no-repeat 1em 1em;
+       background-size: 32px 32px;
+}
+
 /* Flickr Interface CSS*/
 
 #mwe-upwiz-upload-ctr-divide {
diff --git a/tests/qunit/controller/uw.controller.Deed.test.js 
b/tests/qunit/controller/uw.controller.Deed.test.js
index 526f57a..5235665 100644
--- a/tests/qunit/controller/uw.controller.Deed.test.js
+++ b/tests/qunit/controller/uw.controller.Deed.test.js
@@ -32,10 +32,10 @@
                        ),
                        ststub = this.sandbox.stub().returns( 
$.Deferred().promise() ),
                        uploads = [
-                               { file: { fromURL: true }, getThumbnail: 
ststub, on: $.noop },
-                               { file: {}, getThumbnail: ststub, on: $.noop },
-                               { file: { fromURL: true }, getThumbnail: 
ststub, on: $.noop },
-                               { file: {}, getThumbnail: ststub, on: $.noop }
+                               { file: { fromURL: true }, getThumbnail: 
ststub, on: $.noop, title: mw.Title.newFromText( 'Test1.jpg', 6 ) },
+                               { file: {}, getThumbnail: ststub, on: $.noop, 
title: mw.Title.newFromText( 'Test2.jpg', 6 ) },
+                               { file: { fromURL: true }, getThumbnail: 
ststub, on: $.noop, title: mw.Title.newFromText( 'Test3.jpg', 6 ) },
+                               { file: {}, getThumbnail: ststub, on: $.noop, 
title: mw.Title.newFromText( 'Test4.jpg', 6 ) }
                        ];
 
                this.sandbox.stub( step.ui, 'load' );

-- 
To view, visit https://gerrit.wikimedia.org/r/386413
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I5194beef2378c636f06f0a61cc3daf9a7cec99bd
Gerrit-PatchSet: 17
Gerrit-Project: mediawiki/extensions/UploadWizard
Gerrit-Branch: master
Gerrit-Owner: Matthias Mullie <mmul...@wikimedia.org>
Gerrit-Reviewer: MarkTraceur <mholmqu...@wikimedia.org>
Gerrit-Reviewer: Matthias Mullie <mmul...@wikimedia.org>
Gerrit-Reviewer: Siebrand <siebr...@kitano.nl>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to