Bartosz Dziewoński has uploaded a new change for review.
https://gerrit.wikimedia.org/r/251179
Change subject: Split off uw.DateDetailsWidget from UploadWizardDetails
(introduce uw.DetailsWidget)
......................................................................
Split off uw.DateDetailsWidget from UploadWizardDetails (introduce
uw.DetailsWidget)
This change adds uw.DetailsWidget and uw.FieldLayout.
* uw.DetailsWidget represents a single logical field in the "Details" step.
It can be composed of multiple smaller widgets (e.g. a "location" field
could be composed of "latitude" and "longitude" inputs).
* uw.FieldLayout is a small extension of OO.ui.FieldLayout to magically
display error and warnings messages about user input in uw.DetailsWidget.
With these we should be able to move away from jquery.validate, which has
been causing no end of trouble.
* uw.ui.Details has a small hack added to know about new-style error
messages.
* uw.controller.Details refactored to validate both old-style and
new-style fields before submitting the form.
As a first step of migration towards the new system, I converted the date
field, which was already using OOjs UI. The only user-visible change is
that the error message about the field being required looks different.
* uw.DateDetailsWidget is a new class implementing the UI (code moved from
UploadWizardDetails), the validation rules, the copying rules and
getting wikitext from user input.
* UploadWizardDetails only has to create the field, put it in the form,
and get the value back. (And prefill the initial one from EXIF.)
This change does not touch the hint system, using jquery.tipsy. While
OOjs UI has the code for this in place, I think it would be confusing
to users to have two very different-looking tooltip systems side-by-side.
We'll change this later.
Bug: T96917
Change-Id: I446b5b3e8ddb07fc31bbad77ca57ba50b7f96082
---
M UploadWizardHooks.php
M resources/controller/uw.controller.Details.js
A resources/details/uw.DateDetailsWidget.js
A resources/details/uw.DateDetailsWidget.less
M resources/mw.UploadWizardDetails.js
M resources/ui/uw.ui.Details.js
M resources/uploadWizard.css
A resources/uw.DetailsWidget.js
A resources/uw.FieldLayout.js
9 files changed, 381 insertions(+), 137 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/UploadWizard
refs/changes/79/251179/1
diff --git a/UploadWizardHooks.php b/UploadWizardHooks.php
index 89e3fde..5b02dc9 100644
--- a/UploadWizardHooks.php
+++ b/UploadWizardHooks.php
@@ -67,6 +67,11 @@
'resources/jquery/jquery.showThumbCtrl.js',
'resources/jquery/jquery.lazyload.js',
+ // OOjs UI interface elements
+ 'resources/uw.DetailsWidget.js',
+ 'resources/uw.FieldLayout.js',
+ 'resources/details/uw.DateDetailsWidget.js',
+
// common utilities
'resources/mw.fileApi.js',
'resources/mw.units.js',
@@ -110,6 +115,8 @@
'styles' => array(
'resources/uploadWizard.css',
'resources/jquery/jquery.showThumbCtrl.css',
+ // OOjs UI interface elements
+ 'resources/details/uw.DateDetailsWidget.less',
),
'messages' => array(
'comma-separator',
diff --git a/resources/controller/uw.controller.Details.js
b/resources/controller/uw.controller.Details.js
index d1ac4ca..b864e3d 100644
--- a/resources/controller/uw.controller.Details.js
+++ b/resources/controller/uw.controller.Details.js
@@ -105,8 +105,8 @@
* @return {jQuery.Promise}
*/
uw.controller.Details.prototype.valid = function () {
- var windowManager, confirmationDialog, title,
- valid = 0,
+ var
+ validityPromises = [],
necessary = 0,
total = 0,
titles = {};
@@ -116,38 +116,66 @@
return;
}
- total += 1;
+ // Update any error/warning messages about all
DetailsWidgets
+ upload.details.dateDetailsField.checkValidity();
- if ( upload.details.clearDuplicateTitleError().valid()
) {
- title = upload.title.getName() + '.' +
mw.Title.normalizeExtension( upload.title.getExtension() );
+ validityPromises.push( $.when(
+ upload.details.dateDetails.getErrors()
+ // Other DetailsWidgets errors go here...
+ ).then( function () {
+ var i, title, hasErrors = false;
+
+ for ( i = 0; i < arguments.length; i++ ) {
+ if ( arguments[ i ].length ) {
+ // One of the DetailsWidgets
has errors
+ hasErrors = true;
+ }
+ }
+
+ upload.details.clearDuplicateTitleError();
+ // This also updates legacy error messages
+ if ( !upload.details.valid() ) {
+ hasErrors = true;
+ }
// Seen this title before?
+ title = upload.title.getName() + '.' +
mw.Title.normalizeExtension( upload.title.getExtension() );
if ( titles[ title ] ) {
-
// Don't submit. Instead, set an error
in details step.
upload.details.setDuplicateTitleError();
- return;
+ hasErrors = true;
} else {
titles[ title ] = true;
}
- valid += 1;
if ( upload.details.necessaryFilled() ) {
necessary += 1;
}
- }
+
+ if ( hasErrors ) {
+ return $.Deferred().reject();
+ }
+ } ) );
+
+ total += 1;
} );
- if ( valid !== total ) {
- // Not all uploads valid, reject
- return $.Deferred().reject();
- } else if ( necessary === total ) {
- // All uploads valid, all necessary fields filled
- return $.Deferred().resolve();
- }
+ // If not all uploads are valid, $.when will reject this
+ return $.when.apply( $, validityPromises ).then( function () {
+ if ( necessary === total ) {
+ // All uploads valid, all necessary fields
filled
+ return $.Deferred().resolve();
+ } else {
+ // Valid, but recommended fields missing, ask
for confirmation
+ return this.confirmationDialog();
+ }
+ }.bind( this ) );
+ };
- windowManager = new OO.ui.WindowManager();
- confirmationDialog = new OO.ui.MessageDialog();
+ uw.controller.Details.prototype.confirmationDialog = function () {
+ var
+ windowManager = new OO.ui.WindowManager(),
+ confirmationDialog = new OO.ui.MessageDialog();
windowManager.addWindows( [ confirmationDialog ] );
$( 'body' ).append( windowManager.$element );
diff --git a/resources/details/uw.DateDetailsWidget.js
b/resources/details/uw.DateDetailsWidget.js
new file mode 100644
index 0000000..377cb4f
--- /dev/null
+++ b/resources/details/uw.DateDetailsWidget.js
@@ -0,0 +1,131 @@
+( function ( mw, uw, $, OO ) {
+
+ /**
+ * A date field in UploadWizard's "Details" step form.
+ *
+ * @extends uw.DetailsWidget
+ */
+ uw.DateDetailsWidget = function UWDateDetailsWidget() {
+ uw.DateDetailsWidget.parent.call( this );
+
+ this.dateInputWidgetMode = null; // or: 'calendar', 'arbitrary'
+ this.dateInputWidgetToggler = new OO.ui.ButtonSelectWidget( {
+ classes: [ 'mwe-upwiz-dateDetailsWidget-toggler' ],
+ items: [
+ new OO.ui.ButtonOptionWidget( {
+ data: 'calendar',
+ icon: 'calendar',
+ title: mw.msg(
'mwe-upwiz-calendar-date' )
+ } ),
+ new OO.ui.ButtonOptionWidget( {
+ data: 'arbitrary',
+ icon: 'edit',
+ title: mw.msg( 'mwe-upwiz-custom-date' )
+ } )
+ ]
+ } )
+ .selectItemByData( 'calendar' )
+ .on( 'choose', function ( selectedItem ) {
+ this.setupDateInput( selectedItem.getData() );
+ this.dateInputWidget.focus();
+ }.bind( this ) );
+
+ this.$element.addClass( 'mwe-upwiz-dateDetailsWidget' );
+ this.$element.append(
+ this.dateInputWidgetToggler.$element
+ // this.dateInputWidget.$element goes here after
setupDateInput() runs
+ );
+ this.setupDateInput();
+
+ // Aggregate 'change' event
+ this.dateInputWidgetToggler.connect( this, { choose: [ 'emit',
'change' ] } );
+ };
+ OO.inheritClass( uw.DateDetailsWidget, uw.DetailsWidget );
+
+ /**
+ * Set up the date input field, or switch between 'calendar' and
'arbitrary' mode.
+ *
+ * @param {string} [mode] Mode to switch to, 'calendar' or 'arbitrary'
+ * @private
+ */
+ uw.DateDetailsWidget.prototype.setupDateInput = function ( mode ) {
+ var
+ oldDateInputWidget = this.dateInputWidget;
+
+ if ( mode === undefined ) {
+ mode = this.dateInputWidgetMode === 'calendar' ?
'arbitrary' : 'calendar';
+ }
+ this.dateInputWidgetMode = mode;
+ this.dateInputWidgetToggler.selectItemByData( mode );
+
+ if ( mode === 'arbitrary' ) {
+ this.dateInputWidget = new OO.ui.TextInputWidget( {
+ classes: [ 'mwe-date',
'mwe-upwiz-dateDetailsWidget-date' ]
+ } );
+ } else {
+ this.dateInputWidget = new mw.widgets.DateInputWidget( {
+ classes: [ 'mwe-date',
'mwe-upwiz-dateDetailsWidget-date' ]
+ } );
+ // If the user types '{{', assume that they are trying
to input template wikitext and switch
+ // to 'arbitrary' mode. This might help confused
power-users (T110026#1567714).
+ this.dateInputWidget.textInput.on( 'change', function (
value ) {
+ if ( value === '{{' ) {
+ this.setupDateInput( 'arbitrary' );
+ this.dateInputWidget.setValue( '{{' );
+ this.dateInputWidget.moveCursorToEnd();
+ }
+ }.bind( this ) );
+ }
+
+ if ( oldDateInputWidget ) {
+ this.dateInputWidget.setValue(
oldDateInputWidget.getValue() );
+ oldDateInputWidget.$element.replaceWith(
this.dateInputWidget.$element );
+ } else {
+ this.dateInputWidgetToggler.$element.after(
this.dateInputWidget.$element );
+ }
+
+ // Aggregate 'change' event
+ this.dateInputWidget.connect( this, { change: [ 'emit',
'change' ] } );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ uw.DateDetailsWidget.prototype.getErrors = function () {
+ var errors = [];
+ if ( this.dateInputWidget.getValue().trim() === '' ) {
+ errors.push( mw.message( 'mwe-upwiz-error-blank' ) );
+ }
+ return $.Deferred().resolve( errors ).promise();
+ };
+
+ /**
+ * @inheritdoc
+ */
+ uw.DateDetailsWidget.prototype.getWikiText = function () {
+ return this.dateInputWidget.getValue().trim();
+ };
+
+ /**
+ * @inheritdoc
+ * @return {Object} See #setSerialized
+ */
+ uw.DateDetailsWidget.prototype.getSerialized = function () {
+ return {
+ mode: this.dateInputWidgetMode,
+ value: this.dateInputWidget.getValue()
+ };
+ };
+
+ /**
+ * @inheritdoc
+ * @param {Object} serialized
+ * @param {string} serialized.mode Date input mode ('calendar' or
'arbitrary')
+ * @param {string} serialized.value Date value for given mode
+ */
+ uw.DateDetailsWidget.prototype.setSerialized = function ( serialized ) {
+ this.setupDateInput( serialized.mode );
+ this.dateInputWidget.setValue( serialized.value );
+ };
+
+} )( mediaWiki, mediaWiki.uploadWizard, jQuery, OO );
diff --git a/resources/details/uw.DateDetailsWidget.less
b/resources/details/uw.DateDetailsWidget.less
new file mode 100644
index 0000000..e4d579e
--- /dev/null
+++ b/resources/details/uw.DateDetailsWidget.less
@@ -0,0 +1,22 @@
+.mwe-upwiz-dateDetailsWidget {
+ .mwe-upwiz-dateDetailsWidget-toggler,
+ .mwe-upwiz-dateDetailsWidget-date {
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ .mwe-upwiz-dateDetailsWidget-toggler {
+ // HACK Until T97631 is fixed, otherwise the icons look awful
+ .oo-ui-buttonOptionWidget.oo-ui-iconElement >
.oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ width: 24px;
+ }
+ }
+
+ .mwe-upwiz-dateDetailsWidget-date {
+ // Force width matching the date input for the text input
+ width: 21em;
+ // Date input has different margins
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+}
diff --git a/resources/mw.UploadWizardDetails.js
b/resources/mw.UploadWizardDetails.js
index 1e717dc..0a41a37 100644
--- a/resources/mw.UploadWizardDetails.js
+++ b/resources/mw.UploadWizardDetails.js
@@ -12,7 +12,7 @@
mw.UploadWizardDetails = function ( upload, containerDiv ) {
var descriptionAdderDiv, titleContainerDiv, $categoriesDiv,
categoriesHinter,
- categoriesId, dateInputId, dateErrorDiv, dateInputDiv,
+ categoriesId,
moreDetailsCtrlDiv, moreDetailsDiv, otherInformationId,
otherInformationDiv, latitudeDiv, longitudeDiv,
headingDiv,
showMap, linkDiv, locationHinter, locationDiv,
categories,
@@ -130,38 +130,13 @@
.text( mw.message( 'mwe-upwiz-categories' ).text() )
.addHint( 'mwe-upwiz-categories-hint', categoriesHinter
);
- dateInputId = 'dateInput' + ( this.upload.index ).toString();
-
- dateErrorDiv = $( '<div
class="mwe-upwiz-details-input-error"><label class="mwe-validator-error" for="'
+ dateInputId + '" generated="true"/></div>' );
-
- this.dateInputWidgetMode = null; // or: 'calendar', 'arbitrary'
- this.dateInputWidgetToggler = new OO.ui.ButtonSelectWidget( {
- items: [
- new OO.ui.ButtonOptionWidget( {
- data: 'calendar',
- icon: 'calendar',
- title: mw.msg(
'mwe-upwiz-calendar-date' )
- } ),
- new OO.ui.ButtonOptionWidget( {
- data: 'arbitrary',
- icon: 'edit',
- title: mw.msg( 'mwe-upwiz-custom-date' )
- } )
- ]
- } )
- .selectItemByData( 'calendar' )
- .on( 'choose', function ( selectedItem ) {
- details.setupDateInput( selectedItem.getData()
);
- details.dateInputWidget.focus();
- } );
-
- dateInputDiv = $( '<div
class="mwe-upwiz-details-fieldname-input ui-helper-clearfix"></div>' )
- .append(
- dateErrorDiv,
- $( '<div
class="mwe-upwiz-details-fieldname"></div>' ).text( mw.message(
'mwe-upwiz-date-created' ).text() ).requiredFieldLabel().addHint( 'date' ),
- new OO.ui.HorizontalLayout( { classes: [
'mwe-upwiz-details-input' ] } ).$element
- .append(
this.dateInputWidgetToggler.$element )
- );
+ this.dateDetails = new uw.DateDetailsWidget();
+ this.dateDetailsField = new uw.FieldLayout( this.dateDetails, {
+ label: mw.message( 'mwe-upwiz-date-created' ).text(),
+ required: true
+ } );
+ // TODO Rethink hints
+ this.dateDetailsField.$label.addHint( 'date' );
moreDetailsCtrlDiv = $( '<div
class="mwe-upwiz-details-more-options"></div>' );
@@ -223,7 +198,7 @@
this.descriptionsDiv,
descriptionAdderDiv,
this.copyrightInfoFieldset,
- dateInputDiv,
+ this.dateDetailsField.$element,
$categoriesDiv
);
@@ -318,7 +293,6 @@
);
this.$form.validate();
- this.setupDateInput();
$list = this.$form.find( '.mwe-loc-lat, .mwe-loc-lon' )
.on( 'input keyup change cut paste', function () {
@@ -531,62 +505,6 @@
},
/*
- * Set up the date input field, or switch between 'calendar'
and 'arbitrary' mode.
- * @param {string} [mode] Mode to switch to, 'calendar' or
'arbitrary'
- */
- setupDateInput: function ( mode ) {
- var
- oldDateInputWidget = this.dateInputWidget,
- dateInputId = 'dateInput' + ( this.upload.index
).toString();
-
- if ( mode === undefined ) {
- mode = this.dateInputWidgetMode === 'calendar'
? 'arbitrary' : 'calendar';
- }
- this.dateInputWidgetMode = mode;
- this.dateInputWidgetToggler.selectItemByData( mode );
-
- if ( mode === 'arbitrary' ) {
- this.dateInputWidget = new
OO.ui.TextInputWidget( {
- classes: [ 'mwe-date' ],
- id: dateInputId
- } );
- } else {
- this.dateInputWidget = new
mw.widgets.DateInputWidget( {
- classes: [ 'mwe-date' ],
- id: dateInputId
- } );
- // If the user types '{{', assume that they are
trying to input template wikitext and switch
- // to 'arbitrary' mode. This might help
confused power-users (T110026#1567714).
- this.dateInputWidget.textInput.on( 'change',
function ( value ) {
- if ( value === '{{' ) {
- this.setupDateInput(
'arbitrary' );
- this.dateInputWidget.setValue(
'{{' );
-
this.dateInputWidget.moveCursorToEnd();
- }
- }.bind( this ) );
- }
-
- if ( oldDateInputWidget ) {
- this.dateInputWidget.setValue(
oldDateInputWidget.getValue() );
- oldDateInputWidget.$element.replaceWith(
this.dateInputWidget.$element );
- } else {
- this.dateInputWidgetToggler.$element.after(
this.dateInputWidget.$element );
- }
-
- this.dateInputWidget.$input.data(
'mwe-error-placement', this.dateInputWidget.$element.parent() );
- this.$form.validate(); // this might not be necessary
here
- // jQuery validate requires a name, otherwise these
rules would get applied to all inputs with no name
- this.dateInputWidget.$input.attr( 'name', dateInputId );
- // FIXME Shouldn't abuse jQuery validate for this
- this.dateInputWidget.$input.rules( 'add', {
- required: true,
- messages: {
- required: mw.message(
'mwe-upwiz-error-blank' ).escaped()
- }
- } );
- },
-
- /*
* Display error message about multiple uploaded files with the
same title specified
*
* @chainable
@@ -632,9 +550,7 @@
* @param String metadataType One of the types defined in the
copyMetadataTypes property
*/
copyMetadata: function ( metadataType ) {
-
var titleZero, matches,
- i, sourceMode,
details = this,
uploads = this.upload.wizard.uploads,
sourceId = uploads[ 0 ].index;
@@ -720,13 +636,10 @@
} else if ( metadataType === 'date' ) {
- sourceMode = uploads[ 0
].details.dateInputWidgetMode;
-
- for ( i = 1; i < uploads.length; i++ ) {
- uploads[ i ].details.setupDateInput(
sourceMode );
- }
-
- oouiCopy( 'dateInputWidget' );
+ oouiCopy( 'dateDetails', {
+ get: 'getSerialized',
+ set: 'setSerialized'
+ } );
} else if ( metadataType === 'categories' ) {
@@ -1186,6 +1099,7 @@
*/
prefillDate: function () {
var dateObj, metadata, dateTimeRegex, matches, dateStr,
saneTime,
+ dateMode = 'calendar',
yyyyMmDdRegex =
/^(\d\d\d\d)[:\/\-](\d\d)[:\/\-](\d\d)\D.*/,
timeRegex = /\D(\d\d):(\d\d):(\d\d)/;
@@ -1236,7 +1150,10 @@
dateTimeRegex = /^\d\d\d\d-\d\d-\d\d
\d\d:\d\d:\d\d/;
matches = this.upload.file.date.match(
dateTimeRegex );
if ( !mw.isEmpty( matches ) ) {
- this.dateInputWidget.setValue(
this.upload.file.date );
+ this.dateDetails.setSerialized( {
+ mode: dateMode,
+ value: this.upload.file.date
+ } );
return;
}
}
@@ -1260,11 +1177,14 @@
dateStr += ' ' + saneTime;
// Switch to freeform date field.
DateInputWidget (with calendar) handles dates only, not times.
- this.setupDateInput( 'arbitrary' );
+ dateMode = 'arbitrary';
}
// ok by now we should definitely have a dateObj and a
date string
- this.dateInputWidget.setValue( dateStr );
+ this.dateDetails.setSerialized( {
+ mode: dateMode,
+ value: dateStr
+ } );
},
/**
@@ -1455,7 +1375,7 @@
}
} );
- information.date =
this.dateInputWidget.getValue();
+ information.date =
this.dateDetails.getWikiText();
deed = this.upload.deedChooser.deed;
diff --git a/resources/ui/uw.ui.Details.js b/resources/ui/uw.ui.Details.js
index 895572f..5cd2e35 100644
--- a/resources/ui/uw.ui.Details.js
+++ b/resources/ui/uw.ui.Details.js
@@ -144,7 +144,8 @@
*/
uw.ui.Details.prototype.showErrors = function () {
var $errorElements = this.$div
- .find(
'.mwe-error:not(:empty):not(#mwe-upwiz-details-error-count),
input.mwe-validator-error, textarea.mwe-validator-error' ),
+ // TODO Evil
+ .find(
'.mwe-error:not(:empty):not(#mwe-upwiz-details-error-count),
input.mwe-validator-error, textarea.mwe-validator-error,
.oo-ui-fieldLayout-messages-error' ),
errorCount = $errorElements.length;
// Open "more info" if that part of the form has errors
diff --git a/resources/uploadWizard.css b/resources/uploadWizard.css
index 49b0376..2864e1d 100644
--- a/resources/uploadWizard.css
+++ b/resources/uploadWizard.css
@@ -493,11 +493,6 @@
padding-top: 0.3em;
}
-/* HACK Until T97631 is fixed, otherwise the icons look awful */
-.mwe-upwiz-details-input .oo-ui-buttonOptionWidget.oo-ui-iconElement >
.oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- width: 24px;
-}
-
.mwe-upwiz-desc-lang-select {
width: 11.5em;
font-family: sans-serif;
@@ -666,15 +661,6 @@
.mwe-readonly {
background-color: #ffffff;
padding: 0.25em;
-}
-
-.mwe-date {
- display: inline-block;
- /* Force width matching the date input for the text input */
- width: 21em;
- /* Date input has different margins */
- margin-top: 0;
- margin-bottom: 0;
}
.mwe-upwiz-hint {
diff --git a/resources/uw.DetailsWidget.js b/resources/uw.DetailsWidget.js
new file mode 100644
index 0000000..90b5492
--- /dev/null
+++ b/resources/uw.DetailsWidget.js
@@ -0,0 +1,72 @@
+( function ( mw, uw, $, OO ) {
+
+ /**
+ * A single logical field in UploadWizard's "Details" step form.
+ *
+ * This can be composed of multiple smaller widgets, but represents a
single unit (e.g. a
+ * "location" field could be composed of "latitude" and "longitude"
inputs).
+ *
+ * @extends OO.ui.Widget
+ * @abstract
+ */
+ uw.DetailsWidget = function UWDetailsWidget() {
+ uw.DetailsWidget.parent.call( this );
+ };
+ OO.inheritClass( uw.DetailsWidget, OO.ui.Widget );
+
+ /**
+ * A 'change' event is emitted when the state of this widget (and the
serialized value) changes.
+ *
+ * @event change
+ */
+
+ /**
+ * Get the list of errors about the current state of the widget.
+ *
+ * @return {jQuery.Promise} Promise resolved with an array of
mw.Message objects
+ * representing errors. (Checking for errors might require API
queries, etc.)
+ */
+ uw.DetailsWidget.prototype.getErrors = function () {
+ return $.Deferred().resolve( [] ).promise();
+ };
+
+ /**
+ * Get the list of warnings about the current state of the widget.
+ *
+ * @return {jQuery.Promise} Promise resolved with an array of
mw.Message objects
+ * representing warnings. (Checking for warnings might require API
queries, etc.)
+ */
+ uw.DetailsWidget.prototype.getWarnings = function () {
+ return $.Deferred().resolve( [] ).promise();
+ };
+
+ /**
+ * Get a wikitext snippet generated from current state of the widget.
+ *
+ * @return {string} Wikitext
+ */
+ uw.DetailsWidget.prototype.getWikiText = function () {
+ throw new Error( 'Not implemented' );
+ };
+
+ /**
+ * Get a machine-readable representation of the current state of the
widget. It can be passed to
+ * #setSerialized to restore this state (or to set it for another
instance of the same class).
+ *
+ * @return {Object}
+ */
+ uw.DetailsWidget.prototype.getSerialized = function () {
+ throw new Error( 'Not implemented' );
+ };
+
+ /**
+ * Set the state of this widget from machine-readable representation,
as returned by
+ * #getSerialized.
+ *
+ * @param {Object} serialized
+ */
+ uw.DetailsWidget.prototype.setSerialized = function () {
+ throw new Error( 'Not implemented' );
+ };
+
+} )( mediaWiki, mediaWiki.uploadWizard, jQuery, OO );
diff --git a/resources/uw.FieldLayout.js b/resources/uw.FieldLayout.js
new file mode 100644
index 0000000..26570df
--- /dev/null
+++ b/resources/uw.FieldLayout.js
@@ -0,0 +1,77 @@
+( function ( mw, uw, $, OO ) {
+
+ /**
+ * FieldLayout with some UploadWizard-specific bonuses.
+ *
+ * @extends OO.ui.FieldLayout
+ *
+ * @constructor
+ * @inheritdoc
+ * @param {boolean} [config.required=false] Whether to mark this field
as required
+ * @param {boolean} [config.align='top']
+ */
+ uw.FieldLayout = function UWFieldLayout( fieldWidget, config ) {
+ config = $.extend( { align: 'top', required: false }, config );
+ uw.FieldLayout.parent.call( this, fieldWidget, config );
+
+ this.required = null;
+ this.$requiredMarker = $( '<span>' ).addClass(
'mwe-upwiz-required-marker' ).text( '*' );
+
+ this.$element.addClass( 'mwe-upwiz-details-fieldname-input' );
+ this.$label.addClass( 'mwe-upwiz-details-fieldname' );
+ this.$field.addClass( 'mwe-upwiz-details-input' );
+
+ this.fieldWidget.connect( this, {
+ change: 'checkValidity'
+ } );
+
+ this.setRequired( config.required );
+ };
+ OO.inheritClass( uw.FieldLayout, OO.ui.FieldLayout );
+
+ /**
+ * @return {boolean} Whether this field is marked as required
+ */
+ uw.FieldLayout.prototype.getRequired = function () {
+ return this.required;
+ };
+
+ /**
+ * @param {boolean} required Whether to mark this field as required
+ */
+ uw.FieldLayout.prototype.setRequired = function ( required ) {
+ this.required = !!required;
+ if ( this.required ) {
+ this.$body.prepend( this.$requiredMarker );
+ } else {
+ this.$requiredMarker.remove();
+ }
+ };
+
+ /**
+ * Check the field's widget for errors and warnings and display them in
the UI.
+ */
+ uw.FieldLayout.prototype.checkValidity = function () {
+ var layout = this;
+ $.when(
+ this.fieldWidget.getWarnings(),
+ this.fieldWidget.getErrors()
+ ).done( function ( warnings, errors ) {
+ // this.notices and this.errors are arrays of
mw.Messages and not strings in this subclass
+ layout.setNotices( warnings );
+ layout.setErrors( errors );
+ } );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ uw.FieldLayout.prototype.makeMessage = function ( kind, msg ) {
+ var
+ content = new OO.ui.HtmlSnippet( msg.parse() ),
+ $listItem =
uw.FieldLayout.parent.prototype.makeMessage.call( this, kind, content );
+ $listItem.addClass( 'mwe-upwiz-fieldLayout-' + kind + '-' +
msg.key );
+ return $listItem;
+ };
+
+} )( mediaWiki, mediaWiki.uploadWizard, jQuery, OO );
--
To view, visit https://gerrit.wikimedia.org/r/251179
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I446b5b3e8ddb07fc31bbad77ca57ba50b7f96082
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/UploadWizard
Gerrit-Branch: master
Gerrit-Owner: Bartosz Dziewoński <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits