jenkins-bot has submitted this change and it was merged.
Change subject: Frontend quantities
......................................................................
Frontend quantities
(requires follow-up Ic89b54e39b3fd759bad568fc412e192b237da320 to work properly)
Change-Id: Iaaa1e0ac05f025be85a95d9a99d60329e89a98db
---
M DataValues/DataValues.resources.php
M DataValues/DataValues.tests.qunit.php
A DataValues/resources/values/QuantityValue.js
M DataValues/tests/qunit/dataValues.DataValue.tests.js
M DataValuesCommon/DataValuesCommon.mw.php
M DataValuesCommon/js/ValueParsers.resources.php
A DataValuesCommon/js/src/ValueParsers/parsers/QuantityParser.js
A DataValuesCommon/js/tests/ValueParsers/parsers/QuantityParser.tests.js
A ValueView/resources/jquery.valueview/valueview.experts/experts.QuantityType.js
M ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
10 files changed, 319 insertions(+), 4 deletions(-)
Approvals:
Tobias Gritschacher: Looks good to me, approved
jenkins-bot: Verified
diff --git a/DataValues/DataValues.resources.php
b/DataValues/DataValues.resources.php
index 31e4d09..e67ee6a 100644
--- a/DataValues/DataValues.resources.php
+++ b/DataValues/DataValues.resources.php
@@ -46,7 +46,6 @@
'scripts' => array(
// Note: The order here is relevant, scripts
should be places after the ones they
// depend on.
- // TODO: Make one module per data value type.
'values/BoolValue.js',
'values/GlobeCoordinateValue.js',
'values/MonolingualTextValue.js',
@@ -54,6 +53,7 @@
'values/StringValue.js',
'values/NumberValue.js',
'values/TimeValue.js',
+ 'values/QuantityValue.js',
'values/UnknownValue.js',
'values/UnUnserializableValue.js',
),
diff --git a/DataValues/DataValues.tests.qunit.php
b/DataValues/DataValues.tests.qunit.php
index d309a18..d1e0a48 100644
--- a/DataValues/DataValues.tests.qunit.php
+++ b/DataValues/DataValues.tests.qunit.php
@@ -47,6 +47,7 @@
"$bp/values/StringValue.tests.js",
"$bp/values/NumberValue.tests.js",
"$bp/values/TimeValue.tests.js",
+ "$bp/values/QuantityValue.tests.js",
"$bp/values/UnknownValue.tests.js",
"$bp/values/UnUnserializableValue.tests.js",
),
diff --git a/DataValues/resources/values/QuantityValue.js
b/DataValues/resources/values/QuantityValue.js
new file mode 100644
index 0000000..150df01
--- /dev/null
+++ b/DataValues/resources/values/QuantityValue.js
@@ -0,0 +1,203 @@
+/**
+ * @licence GNU GPL v2+
+ * @author Daniel Werner < [email protected] >
+ */
+dataValues.QuantityValue = ( function( inherit, dv, $ ) {
+ 'use strict';
+
+ var PARENT = dv.DataValue;
+
+ /**
+ * Constructor for a data value representing a quantity.
+ *
+ * @since 0.1
+ *
+ * @param {string|number} amount Numeric string or a number.
+ * @param {string|null} [unit] A unit identifier, or null for unit-less
quantities.
+ * @param {number} [significantDigits] The number of significant digits
in the amount, counting
+ * from the most significant digit, not counting the sign or
decimal separator.
+ *
+ * @throws {Error}
+ */
+ var constructor = function( amount, unit, significantDigits ) {
+ if( typeof unit === 'number' ) {
+ significantDigits = unit;
+ unit = null;
+ }
+ var amount = processAmount( amount );
+ this._unit = processUnit( unit );
+ this._significantDigits = processSignificantDigits(
significantDigits, amount );
+ this._amount = enforceSignificanceOnAmount( amount,
this._significantDigits );
+ };
+
+ function processAmount( amount ) {
+ if( typeof amount === 'number' ) {
+ amount = '' + amount;
+ if( amount.indexOf( 'e' ) !== -1 ) {
+ throw new Error( 'Can not cast huge numbers to
the string format required for ' +
+ 'representing quantity values' );
+ }
+ // The next check will also handle NaN and Infinity.
+ }
+
+ if( typeof amount !== 'string'
+ || amount.match( /^[+-]?(?:[1-9]\d*|\d)(?:\.\d+)?$/ )
=== null
+ ) {
+ throw new Error(
+ 'Amount has to be a number or a numeric string
using "." as decimal separator.' );
+ }
+
+ return amount.replace( /^(\d)/, '+$1' );
+ }
+
+ function processUnit( unit ) {
+ if( unit === undefined ) {
+ unit = null;
+ }
+ else if( unit !== null && typeof unit !== 'string' ) {
+ throw new Error( 'The unit has to be a string or null'
);
+ }
+ return unit;
+ }
+
+ function processSignificantDigits( significantDigits, amount ) {
+ if( significantDigits === undefined ) {
+ var hasDecimalSeparator = amount.indexOf( '.' ) !== -1;
+ significantDigits = amount.length - 1 -
hasDecimalSeparator;
+ }
+ else if( typeof significantDigits !== 'number' ||
significantDigits <= 0 ) {
+ throw new Error( '' );
+ }
+ return significantDigits;
+ }
+
+ function enforceSignificanceOnAmount( amount, significantDigits ) {
+ function padRight( string, desiredLength ) {
+ while( string.length < desiredLength ) {
+ string += '0';
+ }
+ return string;
+ }
+
+ var decimalSeparatorIndex = amount.indexOf( '.' );
+ var hasDecimalSeparator = decimalSeparatorIndex !== -1;
+ var significantChars = significantDigits + 1 +
hasDecimalSeparator;
+ var significantPart = amount.substr( 0, significantChars );
+
+ if( significantChars > decimalSeparatorIndex ) {
+ significantPart = significantPart.replace( /\.?$/, '.'
);
+ }
+ significantPart = padRight( significantPart,
decimalSeparatorIndex );
+ return significantPart.replace( /\.$/, '' );
+ }
+
+ var QuantityValue = inherit( 'DvQuantityValue', PARENT, constructor, {
+ /**
+ * @see dv.DataValue.getSortKey
+ *
+ * @since 0.1
+ *
+ * @return string
+ */
+ getSortKey: function() {
+ return this.getAmount();
+ },
+
+ /**
+ * Returns a self-reference.
+ * @see dv.DataValue.getValue
+ *
+ * @since 0.1
+ *
+ * @return dataValues.QuantityValue
+ */
+ getValue: function() {
+ return this;
+ },
+
+ /**
+ * Returns the amount held by this quantity, as a string in
standard format.
+ *
+ * @since 0.1
+ *
+ * @return string
+ */
+ getAmount: function() {
+ return this._amount;
+ },
+
+ /**
+ * Returns the unit held by this quantity. Returns null in case
of unit-less quantities.
+ *
+ * @since 0.1
+ *
+ * @return string|null
+ */
+ getUnit: function() {
+ return this._unit;
+ },
+
+ /**
+ * Returns the number of significant digits in the amount,
counting from the most
+ * significant digit, not counting the sign or decimal
separator.
+ *
+ * @since 0.1
+ *
+ * @return number
+ */
+ getSignificantDigits: function() {
+ return this._significantDigits;
+ },
+
+ /**
+ * @see dv.DataValue.equals
+ *
+ * @since 0.1
+ */
+ equals: function( value ) {
+ if ( !( value instanceof this.constructor ) ) {
+ return false;
+ }
+
+ return this.getAmount() === value.getAmount()
+ && this.getUnit() === value.getUnit()
+ && this.getSignificantDigits() ===
value.getSignificantDigits();
+ },
+
+ /**
+ * @see dv.DataValue.toJSON
+ *
+ * @since 0.1
+ *
+ * @return Object
+ */
+ toJSON: function() {
+ return {
+ amount: this.getAmount(),
+ unit: this.getUnit(),
+ digits: this.getSignificantDigits()
+ };
+ }
+ } );
+
+ /**
+ * @see dv.DataValue.newFromJSON
+ */
+ QuantityValue.newFromJSON = function( json ) {
+ return new QuantityValue(
+ json.amount,
+ json.unit,
+ json.digits
+ );
+ };
+
+ /**
+ * @see dv.DataValue.TYPE
+ */
+ QuantityValue.TYPE = 'quantity';
+
+ return QuantityValue;
+
+}( dataValues.util.inherit, dataValues, jQuery ) );
+
+dataValues.registerDataValue( dataValues.StringValue );
diff --git a/DataValues/tests/qunit/dataValues.DataValue.tests.js
b/DataValues/tests/qunit/dataValues.DataValue.tests.js
index 69f3608..ce1c809 100644
--- a/DataValues/tests/qunit/dataValues.DataValue.tests.js
+++ b/DataValues/tests/qunit/dataValues.DataValue.tests.js
@@ -116,7 +116,10 @@
instance instanceof dv.DataValue,
'is instance of DataValue'
);
-
+ assert.ok(
+ instance instanceof
this.getConstructor(),
+ 'is instance of actual data value
implementation\'s constructor'
+ );
assert.equal(
typeof( instance.getType() ),
'string',
diff --git a/DataValuesCommon/DataValuesCommon.mw.php
b/DataValuesCommon/DataValuesCommon.mw.php
index b344729..537f6b8 100644
--- a/DataValuesCommon/DataValuesCommon.mw.php
+++ b/DataValuesCommon/DataValuesCommon.mw.php
@@ -140,6 +140,7 @@
'parsers/IntParser.tests.js',
'parsers/StringParser.tests.js',
'parsers/TimeParser.tests.js',
+ 'parsers/QuantityParser.tests.js',
'parsers/NullParser.tests.js',
),
'dependencies' => array(
diff --git a/DataValuesCommon/js/ValueParsers.resources.php
b/DataValuesCommon/js/ValueParsers.resources.php
index 2b71b7c..4ce51df 100644
--- a/DataValuesCommon/js/ValueParsers.resources.php
+++ b/DataValuesCommon/js/ValueParsers.resources.php
@@ -56,6 +56,7 @@
'parsers/IntParser.js',
'parsers/StringParser.js',
'parsers/TimeParser.js',
+ 'parsers/QuantityParser.js',
'parsers/NullParser.js',
),
'dependencies' => array(
diff --git a/DataValuesCommon/js/src/ValueParsers/parsers/QuantityParser.js
b/DataValuesCommon/js/src/ValueParsers/parsers/QuantityParser.js
new file mode 100644
index 0000000..cf15c8b
--- /dev/null
+++ b/DataValuesCommon/js/src/ValueParsers/parsers/QuantityParser.js
@@ -0,0 +1,28 @@
+/**
+ * @file
+ * @ingroup ValueParsers
+ *
+ * @licence GNU GPL v2+
+ *
+ * @author Daniel Werner < [email protected] >
+ */
+( function( vp, dv ) {
+ 'use strict';
+
+ var PARENT = vp.ApiBasedValueParser;
+
+ /**
+ * Constructor for globe coordinate parsers.
+ *
+ * @constructor
+ * @extends vp.ApiBasedValueParser
+ * @since 0.1
+ */
+ vp.QuantityParser = dv.util.inherit( PARENT, {
+ /**
+ * @see vp.ApiBasedValueParser.API_VALUE_PARSER_ID
+ */
+ API_VALUE_PARSER_ID: 'quantity'
+ } );
+
+}( valueParsers, dataValues ) );
diff --git
a/DataValuesCommon/js/tests/ValueParsers/parsers/QuantityParser.tests.js
b/DataValuesCommon/js/tests/ValueParsers/parsers/QuantityParser.tests.js
new file mode 100644
index 0000000..77f1c5a
--- /dev/null
+++ b/DataValuesCommon/js/tests/ValueParsers/parsers/QuantityParser.tests.js
@@ -0,0 +1,51 @@
+/**
+ * @licence GNU GPL v2+
+ * @author Daniel Werner < [email protected] >
+ *
+ * Constructor for creating a test object holding tests for the QuantityParser
data value parser.
+ *
+ * @since 0.1
+ */
+valueParsers.tests.QuantityParserTest = ( function(
+ inherit, ValueParserTest, QuantityValue, QuantityParser, $
+) {
+ 'use strict';
+
+ var PARENT = ValueParserTest;
+ var QuantityParserTest = inherit( PARENT, {
+ /**
+ * @see vp.tests.ValueParserTest.getObject
+ */
+ getObject: function() {
+ return QuantityParser;
+ },
+
+ /**
+ * @see vp.tests.ValueParserTest.getParseArguments
+ */
+ getParseArguments: function() {
+ return [
+ [
+ '1.5, 1.25',
+ new QuantityValue( {} )
+ ], [
+ '-50, -20',
+ new QuantityValue( {} )
+ ]
+ ];
+ }
+
+ } );
+
+ var test = new QuantityParserTest();
+ test.runTests( 'valueParsers.QuantityParser' );
+
+ return QuantityParserTest;
+
+}(
+ valueParsers.util.inherit,
+ valueParsers.tests.ValueParserTest,
+ dataValues.QuantityValue,
+ valueParsers.QuantityParser,
+ jQuery
+) );
diff --git
a/ValueView/resources/jquery.valueview/valueview.experts/experts.QuantityType.js
b/ValueView/resources/jquery.valueview/valueview.experts/experts.QuantityType.js
new file mode 100644
index 0000000..151dd99
--- /dev/null
+++
b/ValueView/resources/jquery.valueview/valueview.experts/experts.QuantityType.js
@@ -0,0 +1,27 @@
+/**
+ * @licence GNU GPL v2+
+ * @author Daniel Werner < [email protected] >
+ *
+ * Valueview expert for values of quantity data type.
+ *
+ * @since 0.1
+ *
+ * @constructor
+ * @extends jQuery.valueview.experts.BifidExpert
+ */
+jQuery.valueview.experts.QuantityType = ( function( dv, vp, $, vv ) {
+ 'use strict';
+
+ var PARENT = vv.StringValue;
+// var editableExpert = vv.experts.StringValue;
+
+ return vv.expert( 'quantitytype', PARENT, {
+ /**
+ * @see Query.valueview.Expert.parser
+ */
+ parser: function() {
+ return new vp.QuantityParser();
+ }
+ } );
+
+}( dataValues, valueParsers, jQuery, jQuery.valueview ) );
diff --git
a/ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
b/ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
index 39a3a33..aecd0b8 100644
---
a/ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
+++
b/ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
@@ -111,8 +111,8 @@
// Resize textarea to fit the value (which might be
empty):
this._resizeInput();
- // We always use the textare for displaying the value,
only in edit mode we format the
- // textare as an input field though.
+ // We always use the textarea for displaying the value,
only in edit mode we format the
+ // textarea as an input field though.
if( this._viewState.isInEditMode() ) {
// in EDIT MODE:
this.$input.prop( {
--
To view, visit https://gerrit.wikimedia.org/r/84754
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Iaaa1e0ac05f025be85a95d9a99d60329e89a98db
Gerrit-PatchSet: 4
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Daniel Werner <[email protected]>
Gerrit-Reviewer: Henning Snater <[email protected]>
Gerrit-Reviewer: Tobias Gritschacher <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits