jenkins-bot has submitted this change and it was merged.

Change subject: Adding a MediaSizeWidget
......................................................................


Adding a MediaSizeWidget

The widget is responsible for presenting width/height values and storing
original media size values that aspect ratio is calculated from.

Change-Id: I3d0f9348a52ac39f68dd09394778369026928c9d
---
M modules/ve/i18n/en.json
M modules/ve/i18n/qqq.json
M modules/ve/ui/styles/ve.ui.Widget.css
A modules/ve/ui/widgets/ve.ui.MediaSizeWidget.js
4 files changed, 384 insertions(+), 2 deletions(-)

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



diff --git a/modules/ve/i18n/en.json b/modules/ve/i18n/en.json
index d9bea05..4094ce2 100644
--- a/modules/ve/i18n/en.json
+++ b/modules/ve/i18n/en.json
@@ -60,6 +60,10 @@
     "visualeditor-languageinspector-widget-label-langcode": "Language code",
     "visualeditor-languageinspector-widget-label-language": "Language",
     "visualeditor-linkinspector-title": "Hyperlink",
+    "visualeditor-mediasizewidget-button-originaldimensions": "Set to original 
dimensions",
+    "visualeditor-mediasizewidget-label-defaulterror": "Size values are 
invalid.",
+    "visualeditor-mediasizewidget-label-height": "Height",
+    "visualeditor-mediasizewidget-label-width": "Width",
     "visualeditor-listbutton-bullet-tooltip": "Bullet list",
     "visualeditor-listbutton-number-tooltip": "Numbered list",
     "visualeditor-shortcuts-clipboard": "Clipboard",
@@ -72,4 +76,4 @@
     "visualeditor-specialcharinspector-characterlist-insert": 
"{\n\t\"symbols\": {\n\t\t\"−\": \"−\",\n\t\t\"—\": \"—\",\n\t\t\"°\": 
\"°\",\n\t\t\"″\": \"″\",\n\t\t\"′\": \"′\",\n\t\t\"←\": \"←\",\n\t\t\"→\": 
\"→\",\n\t\t\"·\": \"·\",\n\t\t\"§\": \"§\"\n\t},\n\t\"accents\": {\n\t\t\"à\": 
\"à\",\n\t\t\"á\": \"á\",\n\t\t\"â\": \"â\",\n\t\t\"ä\": \"ä\",\n\t\t\"ç\": 
\"ç\",\n\t\t\"è\": \"è\",\n\t\t\"é\": \"é\",\n\t\t\"ê\": \"ê\",\n\t\t\"ë\": 
\"ë\",\n\t\t\"ì\": \"ì\",\n\t\t\"í\": \"í\",\n\t\t\"î\": \"î\",\n\t\t\"ï\": 
\"ï\",\n\t\t\"ò\": \"ò\",\n\t\t\"ó\": \"ó\",\n\t\t\"ô\": \"ô\",\n\t\t\"ö\": 
\"ö\",\n\t\t\"ø\": \"ø\",\n\t\t\"ù\": \"ù\",\n\t\t\"ú\": \"ú\",\n\t\t\"û\": 
\"û\",\n\t\t\"ü\": \"ü\"\n\t},\n\t\"math\": {\n\t\t\"−\": \"−\",\n\t\t\"×\": 
\"×\",\n\t\t\"÷\": \"÷\",\n\t\t\"≈\": \"≈\",\n\t\t\"≠\": \"≠\",\n\t\t\"≤\": 
\"≤\",\n\t\t\"≥\": \"≥\",\n\t\t\"±\": \"±\"\n\t}\n}",
     "visualeditor-toolbar-insert": "Insert",
     "visualeditor-version-label": "Version"
-}
\ No newline at end of file
+}
diff --git a/modules/ve/i18n/qqq.json b/modules/ve/i18n/qqq.json
index b71c960..975a971 100644
--- a/modules/ve/i18n/qqq.json
+++ b/modules/ve/i18n/qqq.json
@@ -65,6 +65,10 @@
     "visualeditor-linkinspector-title": "Title of the link inspector 
dialog.\n{{Identical|Hyperlink}}",
     "visualeditor-listbutton-bullet-tooltip": "Tooltip text for the bullet 
list button",
     "visualeditor-listbutton-number-tooltip": "Tooltip text for the numbered 
list button",
+    "visualeditor-mediasizewidget-button-originaldimensions": "Label for the 
button that sets media to its original dimensions.",
+    "visualeditor-mediasizewidget-label-defaulterror": "An error label 
notifying the user the size inputs are invalid.",
+    "visualeditor-mediasizewidget-label-height": "Label for the height input.",
+    "visualeditor-mediasizewidget-label-width": "Label for the width input.",
     "visualeditor-shortcuts-clipboard": "Heading for clipboard shortcuts",
     "visualeditor-shortcuts-formatting": "Heading for paragraph formatting 
shortcuts",
     "visualeditor-shortcuts-history": "Heading for history shortcuts",
@@ -75,4 +79,4 @@
     "visualeditor-specialcharinspector-characterlist-insert": "This is a JSON 
string defining the special characters that can be inserted using the special 
character insertion tool.\n{{doc-important|Please make sure it is a valid JSON 
string.}}\n{{Optional}}",
     "visualeditor-toolbar-insert": "Label text for insert menu in 
toolbar.\n{{Identical|Insert}}",
     "visualeditor-version-label": "Label text for version 
number\n{{Identical|Version}}"
-}
\ No newline at end of file
+}
diff --git a/modules/ve/ui/styles/ve.ui.Widget.css 
b/modules/ve/ui/styles/ve.ui.Widget.css
index e70ec20..d04cf1f 100644
--- a/modules/ve/ui/styles/ve.ui.Widget.css
+++ b/modules/ve/ui/styles/ve.ui.Widget.css
@@ -114,3 +114,8 @@
 .ve-ui-groupButtonWidget {
        white-space: normal;
 }
+
+/* ve.ui.MediaSizeWidget */
+.ve-ui-mediaSizeWidget-input-hasError input[type="text"] {
+       background: #ffc2c2;
+}
diff --git a/modules/ve/ui/widgets/ve.ui.MediaSizeWidget.js 
b/modules/ve/ui/widgets/ve.ui.MediaSizeWidget.js
new file mode 100644
index 0000000..942c814
--- /dev/null
+++ b/modules/ve/ui/widgets/ve.ui.MediaSizeWidget.js
@@ -0,0 +1,369 @@
+/*!
+ * VisualEditor UserInterface MediaSizeWidget class.
+ *
+ * @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * Widget that lets the user edit dimensions (width and height),
+ * optionally with a fixed aspect ratio.
+ *
+ * The widget is designed to work in one of two ways:
+ * 1. Instantiated with size configuration already set up
+ * 2. Instantiated empty, and size details added when the
+ *    data is available.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {number} [width] Initial width value
+ * @cfg {number} [height] Initial heigh value
+ * @cfg {Object} [originalDimensions] Original dimensions (width and height)
+ * @cfg {Object} [maxDimensions] Maximum dimensions the user is not allowed to 
exceed
+ */
+ve.ui.MediaSizeWidget = function VeUiMediaSizeWidget( config ) {
+       var heightLabel, widthLabel;
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Configuration
+       config = config || {};
+
+       this.width = config.width || '';
+       this.height = config.height || '';
+       this.originalDimensions = config.originalDimensions || {};
+       this.maxDimensions = config.maxDimensions || {};
+
+       // Cache for the aspect ratio, which is set by setOriginalDimensions()
+       this.aspectRatio = null;
+
+       // Validation
+       this.valid = false;
+
+       // Define dimension input widgets
+       this.widthInput = new OO.ui.TextInputWidget( {
+               '$': this.$
+       } );
+       this.heightInput = new OO.ui.TextInputWidget( {
+               '$': this.$
+       } );
+
+       // Define dimension labels
+       widthLabel = new OO.ui.InputLabelWidget( {
+               '$': this.$,
+               'input': this.widthInput,
+               'label': ve.msg( 'visualeditor-mediasizewidget-label-width' )
+       } );
+       heightLabel = new OO.ui.InputLabelWidget( {
+               '$': this.$,
+               'input': this.heightInput,
+               'label': ve.msg( 'visualeditor-mediasizewidget-label-height' )
+       } );
+       // Error label
+       this.errorLabel = new OO.ui.InputLabelWidget( {
+               '$': this.$,
+               'label': ve.msg( 
'visualeditor-mediasizewidget-label-defaulterror' )
+       } );
+
+       // Define buttons
+       this.originalDimensionsButton = new OO.ui.PushButtonWidget( {
+               '$': this.$,
+               'label': ve.msg( 
'visualeditor-mediasizewidget-button-originaldimensions' )
+       } );
+
+       // Build the GUI
+       this.$element.append( [
+               this.$( '<div>' )
+                       .addClass( 've-ui-mediaSizeWidget-section-width' )
+                       .append( [
+                               widthLabel.$element,
+                               this.widthInput.$element
+                       ] ),
+               this.$( '<div>' )
+                       .addClass( 've-ui-mediaSizeWidget-section-height' )
+                       .append( [
+                               heightLabel.$element,
+                               this.heightInput.$element
+                       ] ),
+               this.$( '<div>' )
+                       .addClass( 've-ui-mediaSizeWidget-button-originalSize' )
+                       .append( this.originalDimensionsButton.$element ),
+               this.$( '<div>' )
+                       .addClass( 've-ui-mediaSizeWidget-label-error' )
+                       .append( this.errorLabel.$element ),
+       ] );
+
+       this.originalDimensionsButton.setDisabled( true );
+
+       // Events
+       this.originalDimensionsButton.connect( this, { 'click': 
'onButtonOriginalDimensionsClick' } );
+
+       this.widthInput.connect( this, { 'change': 'onWidthChange' } );
+       this.heightInput.connect( this, { 'change': 'onHeightChange' } );
+
+       // Initialization
+       this.$element.addClass( 've-ui-mediaSizeWidget' );
+       this.setOriginalDimensions( this.originalDimensions );
+       this.setMaxDimensions( this.maxDimensions );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.MediaSizeWidget, OO.ui.Widget );
+
+/* Methods */
+
+/**
+ * Get the currently set rounded dimensions.
+ *
+ * @returns {Object} Current dimensions, rounded to integer values
+ * @returns {number} return.width Width
+ * @returns {number} return.height Height
+ */
+ve.ui.MediaSizeWidget.prototype.getDimensions = function () {
+       return {
+               'width': Number( this.widthInput.getValue() ),
+               'height': Number( this.heightInput.getValue() )
+       };
+};
+
+/**
+ * Set the current width and height dimensions.
+ * This method accepts either both values or a single value.
+ *
+ * In general, it is expected that the original dimensions will
+ * be supplied before the current dimensions, but in case they
+ * are not, several fallback options exist.
+ *
+ * The method will accept and handle either of the following:
+ * 1. Both width/height dimensions are supplied:
+ *    a. If original dimensions already set the inputs are filled
+ *       in without calculation, trusting the verification method
+ *       to notify the user in case there are errors.
+ *    b. If original dimensions or aspectRatio are not set image
+ *       will not be bound to aspect ratio.
+ * 2. Only width or only height are supplied:
+ *    a. If original dimensions are already set, the corresponding
+ *       input value is calculated.
+ *    b. If original dimensions and aspectRatio are not set, the
+ *       corresponding value will not be updated.
+ *
+ * All raw values are catched internally for accurate calculations
+ * and the values are rounded for display inside the inputs.
+ *
+ * @param {Object} dimensions Dimensions to set
+ * @param {number} [dimensions.width] Width to set
+ * @param {number} [dimensions.height] Height to set
+ */
+ve.ui.MediaSizeWidget.prototype.setDimensions = function ( dimensions ) {
+
+       // Recursion protection
+       if ( this.preventChangeRecursion ) {
+               return;
+       }
+
+       this.preventChangeRecursion = true;
+
+       if ( dimensions.width && dimensions.height ) {
+               // If both dimensions are set up, use them directly
+               this.width = dimensions.width;
+               this.height = dimensions.height;
+       } else if ( dimensions.width && !dimensions.height ) {
+               // If only width is defined
+               this.width = dimensions.width;
+               if ( this.aspectRatio !== null ) {
+                       // If aspect ratio is available, calculate
+                       this.height = Math.round( this.width / 
this.getAspectRatio() );
+               }
+       } else if ( dimensions.height && !dimensions.width ) {
+               // If only height is defined
+               this.height = dimensions.height;
+               if ( this.aspectRatio !== null ) {
+                       // If aspect ratio is available, calculate
+                       this.width = Math.round( this.height * 
this.getAspectRatio() );
+               }
+       }
+
+       // This will only update if the value has changed
+       this.widthInput.setValue( this.width );
+       this.heightInput.setValue( this.height );
+
+       // Check if we need to notify the user that the dimensions
+       // have a problem
+       this.validateDimensions();
+
+       this.preventChangeRecursion = false;
+};
+
+/**
+ * Get the height and width values of the maximum allowed dimensions, if set.
+ *
+ * @returns {Object} Maximum dimensions
+ * @returns {number} [return.width] Maximum width, if set
+ * @returns {number} [return.height] Maximum height, if set
+ */
+ve.ui.MediaSizeWidget.prototype.getMaxDimensions = function () {
+       return this.originalDimensions;
+};
+
+/**
+ * Set maximum width and/or height.
+ * @param {Object} dimensions Maximum dimensions
+ * @param {number} [dimensions.width] Maximum width
+ * @param {number} [dimensions.height] Maximum height
+ */
+ve.ui.MediaSizeWidget.prototype.setMaxDimensions = function ( dimensions ) {
+       this.maxDimensions = {
+               'width': dimensions.width,
+               'height': dimensions.height
+       };
+};
+
+/**
+ * Get the original dimensions of the image, if set.
+ * @returns {Object} Original dimensions
+ * @returns {number} [return.width] Original width, if set
+ * @returns {number} [return.height] Original height, if set
+ */
+ve.ui.MediaSizeWidget.prototype.getOriginalDimensions = function () {
+       return this.originalDimensions;
+};
+
+/**
+ * Set the original dimensions and cache the aspect ratio.
+ * @param {Object} dimensions Original dimensions
+ * @param {number} dimensions.width Original width
+ * @param {number} dimensions.height Original height
+ */
+ve.ui.MediaSizeWidget.prototype.setOriginalDimensions = function ( dimensions 
) {
+       this.originalDimensions = {
+               'width': dimensions.width,
+               'height': dimensions.height
+       };
+       // Cache the aspect ratio
+       this.aspectRatio = this.originalDimensions.width / 
this.originalDimensions.height;
+       // Enable the 'original dimensions' button
+       this.originalDimensionsButton.setDisabled( false );
+};
+
+/**
+ * Explicitly set the aspect ratio, overriding what setOriginalDimensions() 
computed.
+ * @param {number} ratio Aspect ratio (width/height)
+ */
+ve.ui.MediaSizeWidget.prototype.setAspectRatio = function ( ratio ) {
+       this.aspectRatio = ratio;
+};
+
+/**
+ * Retrieve the aspect ratio. This is only known if set through 
setAspectRatio() or
+ * computed by setOriginalDimensions().
+ *
+ * @returns {number|null} Aspect ratio (width/height)
+ */
+ve.ui.MediaSizeWidget.prototype.getAspectRatio = function () {
+       return this.aspectRatio;
+};
+
+/**
+ * Checks whether the input values are valid. If the inputs are
+ * not valid, an error class will be added to the inputs.
+ */
+ve.ui.MediaSizeWidget.prototype.validateDimensions = function () {
+
+       // Check for an error in the values
+       if (
+               !$.isNumeric( this.width ) ||
+               !$.isNumeric( this.height ) ||
+               Number( this.width ) <= 0 ||
+               Number( this.height ) <= 0 ||
+               // Check if the size exceeds max dimensions,
+               // but only if the maxDimensions are set
+               // TODO use a separate error message for this case,
+               // and put the max dimensions in the error message
+               (
+                       $.isNumeric( this.maxDimensions.width ) &&
+                       Number( this.width ) > this.maxDimensions.width
+               ) || (
+                       $.isNumeric( this.maxDimensions.height ) &&
+                       Number( this.height ) > this.maxDimensions.height
+               )
+       ) {
+               this.valid = false;
+               // Show error message
+               this.errorLabel.$element.show();
+       } else {
+               this.valid = true;
+               // Hide the error message
+               this.errorLabel.$element.hide();
+       }
+
+       // Add or remove the error class
+       this.$element.toggleClass( 've-ui-mediaSizeWidget-input-hasError', 
!this.valid );
+};
+
+/**
+ * Respond to a change in the width input.
+ */
+ve.ui.MediaSizeWidget.prototype.onWidthChange = function () {
+       var val = this.widthInput.getValue();
+       if ( $.isNumeric( val ) ) {
+               // Calculate and update the corresponding value
+               this.setDimensions( { 'width': val } );
+       } else {
+               this.width = val;
+               // We didn't perform an actual change, but we should still 
validate
+               // the input values
+               this.validateDimensions();
+       }
+};
+
+/**
+ * Respond to a change in the height input.
+ */
+ve.ui.MediaSizeWidget.prototype.onHeightChange = function () {
+       var val = this.heightInput.getValue();
+       if ( $.isNumeric( val ) ) {
+               // Calculate and update the corresponding value
+               this.setDimensions( { 'height': val } );
+       } else {
+               this.height = val;
+               // We didn't perform an actual change, but we should still 
validate
+               // the input values
+               this.validateDimensions();
+       }
+};
+
+/**
+ * Set the width/height values to the original media dimensions
+ *
+ * @param {jQuery.Event} e Click event
+ */
+ve.ui.MediaSizeWidget.prototype.onButtonOriginalDimensionsClick = function () {
+       this.setDimensions( this.originalDimensions );
+};
+
+/**
+ * Checks whether there is an error with the widget
+ * @returns {boolean} Values are valid
+ */
+ve.ui.MediaSizeWidget.prototype.isValid = function () {
+       return this.valid;
+};
+
+/**
+ * Clear all values.
+ * This is useful to update the widget values between different
+ * images that have other dimensions or restrictions while the
+ * widget is already instantiated.
+ */
+ve.ui.MediaSizeWidget.prototype.clear = function () {
+       this.aspectRatio = null;
+       this.originalDimensions = {};
+       this.maxDimensions = {};
+       this.width = '';
+       this.height = '';
+};

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I3d0f9348a52ac39f68dd09394778369026928c9d
Gerrit-PatchSet: 15
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Mooeypoo <[email protected]>
Gerrit-Reviewer: Robmoen <[email protected]>
Gerrit-Reviewer: Trevor Parscal <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to