Henning Snater has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/101876


Change subject: Implemented basic front-end value formatters
......................................................................

Implemented basic front-end value formatters

(bug 56261)
This change introduces a NullFormatter as well as a formatter for the string 
data type to
the front-end. In order to keep the change set size small, applying the 
formatters will be
dealt with in a subsequent change set.

Change-Id: I10481061ac0ee925cd70b5e321153ba433cd7c26
---
M .jshintrc
M DataValuesCommon/DataValuesCommon.mw.php
A DataValuesCommon/js/ValueFormatters.resources.php
A DataValuesCommon/js/src/ValueFormatters/formatters/NullFormatter.js
A DataValuesCommon/js/src/ValueFormatters/formatters/StringFormatter.js
A DataValuesCommon/js/src/ValueFormatters/formatters/ValueFormatter.js
A DataValuesCommon/js/src/ValueFormatters/valueFormatters.js
A DataValuesCommon/js/src/ValueFormatters/valueFormatters.util.js
A DataValuesCommon/js/tests/ValueFormatters/ValueFormatter.tests.js
A DataValuesCommon/js/tests/ValueFormatters/formatters/NullFormatter.tests.js
A DataValuesCommon/js/tests/ValueFormatters/formatters/StringFormatter.tests.js
11 files changed, 546 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DataValues 
refs/changes/76/101876/6

diff --git a/.jshintrc b/.jshintrc
index e5706a3..d9e8170 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -30,6 +30,7 @@
        "predef": [
                "dataValues",
                "dataTypes",
+               "valueFormatters",
                "valueParsers",
                "time",
                "globeCoordinate",
diff --git a/DataValuesCommon/DataValuesCommon.mw.php 
b/DataValuesCommon/DataValuesCommon.mw.php
index d2f6296..85b7f78 100644
--- a/DataValuesCommon/DataValuesCommon.mw.php
+++ b/DataValuesCommon/DataValuesCommon.mw.php
@@ -106,7 +106,51 @@
 };
 
 /**
- * Hook to add QUnit test cases.
+ * Adding valueFormatters QUnit tests.
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderTestModules
+ * @since 0.1
+ *
+ * @param array &$testModules
+ * @param \ResourceLoader &$resourceLoader
+ * @return boolean
+ */
+$wgHooks['ResourceLoaderTestModules'][] = function(
+       array &$testModules,
+       \ResourceLoader &$resourceLoader
+) {
+       // @codeCoverageIgnoreStart
+       $moduleTemplate = array(
+               'localBasePath' => __DIR__ . '/js/tests/ValueFormatters',
+               'remoteExtPath' => 
'DataValues/DataValuesCommon/js/tests/ValueFormatters',
+       );
+
+       $testModules['qunit']['ext.valueFormatters.tests'] = $moduleTemplate + 
array(
+               'scripts' => array(
+                       'ValueFormatter.tests.js',
+               ),
+               'dependencies' => array(
+                       'valueFormatters',
+                       'valueFormatters.ValueFormatter',
+               ),
+       );
+
+       $testModules['qunit']['ext.valueFormatters.formatters'] = 
$moduleTemplate + array(
+               'scripts' => array(
+                       'formatters/NullFormatter.tests.js',
+                       'formatters/StringFormatter.tests.js',
+               ),
+               'dependencies' => array(
+                       'ext.valueFormatters.tests',
+                       'valueFormatters.formatters',
+               ),
+       );
+
+       return true;
+       // @codeCoverageIgnoreEnd
+};
+
+/**
+ * Adding valueParsers QUnit tests.
  * @see https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderTestModules
  * @since 0.1
  *
@@ -164,5 +208,6 @@
 // Resource Loader module registration
 $GLOBALS['wgResourceModules'] = array_merge(
        $GLOBALS['wgResourceModules'],
+       include( __DIR__ . '/js/ValueFormatters.resources.php' ),
        include( __DIR__ . '/js/ValueParsers.resources.mw.php' )
 );
diff --git a/DataValuesCommon/js/ValueFormatters.resources.php 
b/DataValuesCommon/js/ValueFormatters.resources.php
new file mode 100644
index 0000000..d26c392
--- /dev/null
+++ b/DataValuesCommon/js/ValueFormatters.resources.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Definition of ResourceLoader modules of the ValueFormatters extension.
+ * When included this returns an array with all the modules introduced by 
ValueFormatters.
+ *
+ * @since 0.1
+ *
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ *
+ * @codeCoverageIgnoreStart
+ */
+return call_user_func( function() {
+
+       $moduleTemplate = array(
+               'localBasePath' => __DIR__ . '/src/ValueFormatters',
+               'remoteExtPath' =>  
'DataValues/DataValuesCommon/js/src/ValueFormatters',
+       );
+
+       return array(
+
+               'valueFormatters' => $moduleTemplate + array(
+                       'scripts' => array(
+                               'valueFormatters.js',
+                       ),
+               ),
+
+               'valueFormatters.ValueFormatter' => $moduleTemplate + array(
+                       'scripts' => array(
+                               'formatters/ValueFormatter.js',
+                       ),
+                       'dependencies' => array(
+                               'valueFormatters',
+                               'valueFormatters.util',
+                       ),
+               ),
+
+               'valueFormatters.formatters' => $moduleTemplate + array(
+                       'scripts' => array(
+                               'formatters/NullFormatter.js',
+                               'formatters/StringFormatter.js',
+                       ),
+                       'dependencies' => array(
+                               'dataValues.values',
+                               'valueFormatters.ValueFormatter',
+                       ),
+               ),
+
+               'valueFormatters.util' => $moduleTemplate + array(
+                               'scripts' => array(
+                                       'valueFormatters.util.js',
+                               ),
+                               'dependencies' => array(
+                                       'dataValues.util',
+                                       'valueFormatters',
+                               ),
+                       ),
+
+       );
+
+} );
diff --git 
a/DataValuesCommon/js/src/ValueFormatters/formatters/NullFormatter.js 
b/DataValuesCommon/js/src/ValueFormatters/formatters/NullFormatter.js
new file mode 100644
index 0000000..0cbc20d
--- /dev/null
+++ b/DataValuesCommon/js/src/ValueFormatters/formatters/NullFormatter.js
@@ -0,0 +1,47 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ */
+( function( $, vf, dv ) {
+       'use strict';
+
+       var PARENT = vf.ValueFormatter;
+
+       /**
+        * Null Formatter
+        * The Null Formatter formats any DataValue instance and may be used as 
a fallback for DataValue
+        * instances that cannot be identified (e.g. due to missing 
implementation). The formatted value
+        * will be an UnknownValue DataValue, except if null or a DataValue got 
passed in. In those
+        * cases, the value passed to the format function will be the format 
result.
+        *
+        * @constructor
+        * @extends valueFormatters.ValueFormatter
+        * @since 0.1
+        */
+       vf.NullFormatter = vf.util.inherit( PARENT, function() {}, {
+               /**
+                * @see valueFormatters.ValueFormatter.format
+                */
+               format: function( dataValue ) {
+                       var deferred = $.Deferred();
+
+                       if( dataValue === null ) {
+                               return deferred.resolve( null, null ).promise();
+                       }
+
+                       if( !( dataValue instanceof dv.DataValue ) ) {
+                               dataValue = new dv.UnknownValue( dataValue );
+                       }
+
+                       var formatted = dataValue.toJSON();
+
+                       if( formatted !== null ) {
+                               formatted = String( formatted );
+                       }
+
+                       return deferred.resolve( formatted, dataValue 
).promise();
+               }
+
+       } );
+
+}( jQuery, valueFormatters, dataValues ) );
diff --git 
a/DataValuesCommon/js/src/ValueFormatters/formatters/StringFormatter.js 
b/DataValuesCommon/js/src/ValueFormatters/formatters/StringFormatter.js
new file mode 100644
index 0000000..666d064
--- /dev/null
+++ b/DataValuesCommon/js/src/ValueFormatters/formatters/StringFormatter.js
@@ -0,0 +1,33 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ */
+( function( $, vf ) {
+       'use strict';
+
+       var PARENT = vf.ValueFormatter;
+
+       /**
+        * String formatter
+        * @constructor
+        * @extends valueFormatters.ValueFormatter
+        * @since 0.1
+        */
+       vf.StringFormatter = vf.util.inherit( PARENT, {
+               /**
+                * @see valueFormatters.ValueFormatter.format
+                * @since 0.1
+                *
+                * @param {dataValues.StringValue} dataValue
+                * @return {$.Promise}
+                */
+               format: function( dataValue ) {
+                       var deferred = $.Deferred();
+
+                       deferred.resolve( dataValue.toJSON(), dataValue );
+
+                       return deferred.promise();
+               }
+       } );
+
+}( jQuery, valueFormatters ) );
diff --git 
a/DataValuesCommon/js/src/ValueFormatters/formatters/ValueFormatter.js 
b/DataValuesCommon/js/src/ValueFormatters/formatters/ValueFormatter.js
new file mode 100644
index 0000000..e9707d1
--- /dev/null
+++ b/DataValuesCommon/js/src/ValueFormatters/formatters/ValueFormatter.js
@@ -0,0 +1,61 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ */
+( function( $, vf ) {
+       'use strict';
+
+       /**
+        * Base constructor for objects representing a value formatter.
+        * @constructor
+        * @abstract
+        * @since 0.1
+        *
+        * @param {Object} options
+        */
+       var SELF = vf.ValueFormatter = function VpValueFormatter( options ) {
+               this._options = $.extend( {}, options || {} );
+       };
+
+       $.extend( SELF.prototype, {
+               /**
+                * Formatter options.
+                * @type {Object}
+                */
+               _options: null,
+
+               /**
+                * Returns the formatter's options as set in the constructor.
+                * @since 0.1
+                *
+                * @return {Object}
+                */
+               getOptions: function() {
+                       return $.extend( {}, this._options );
+               },
+
+               /**
+                * Formats a value. Will return a jQuery.Promise which will be 
resolved if formatting is
+                * successful or rejected if it fails. There are various 
reasons why formatting could fail,
+                * e.g. the formatter is using the API and the API cannot be 
reached. In case of success,
+                * the callbacks will be passed a dataValues.DataValue object. 
In case of failure, the
+                * callback's parameter will be an error object of some sort 
(not implemented yet!).
+                *
+                * TODO: Specify Error object for formatter failure. Consider 
different error scenarios e.g.
+                *       API can not be reached or real formatting issues.
+                * TODO: Think about introducing formatter warnings or a status 
object in done() callbacks.
+                *
+                * @since 0.1
+                *
+                * @param {dataValues.DataValue} dataValue
+                *
+                * @return {$.Promise}
+                *         Parameters:
+                *         - {string|null} Formatted DataValue.
+                *         - {dataValues.DataValue|null} DataValue object that 
has been formatted.
+                */
+               format: vf.util.abstractMember
+
+       } );
+
+}( jQuery, valueFormatters ) );
diff --git a/DataValuesCommon/js/src/ValueFormatters/valueFormatters.js 
b/DataValuesCommon/js/src/ValueFormatters/valueFormatters.js
new file mode 100644
index 0000000..130a480
--- /dev/null
+++ b/DataValuesCommon/js/src/ValueFormatters/valueFormatters.js
@@ -0,0 +1,11 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ */
+
+/**
+ * Global 'valueFormatters' object
+ * @since 0.1
+ * @type {Object}
+ */
+this.valueFormatters = this.valueFormatters || {};
diff --git a/DataValuesCommon/js/src/ValueFormatters/valueFormatters.util.js 
b/DataValuesCommon/js/src/ValueFormatters/valueFormatters.util.js
new file mode 100644
index 0000000..0f97e79
--- /dev/null
+++ b/DataValuesCommon/js/src/ValueFormatters/valueFormatters.util.js
@@ -0,0 +1,27 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ */
+( function( $, vf, dv ) {
+       'use strict';
+
+       /**
+        * Module for utilities of the ValueFormatters extension.
+        * @since 0.1
+        * @type {Object}
+        */
+       vf.util = {};
+
+       /**
+        * @see dataValues.util.inherit
+        * @since 0.1
+        */
+       vf.util.inherit = dv.util.inherit;
+
+       /**
+        * @see dataValues.util.abstractMember
+        * @since 0.1
+        */
+       vf.util.abstractMember = dv.util.abstractMember;
+
+}( jQuery, valueFormatters, dataValues ) );
diff --git a/DataValuesCommon/js/tests/ValueFormatters/ValueFormatter.tests.js 
b/DataValuesCommon/js/tests/ValueFormatters/ValueFormatter.tests.js
new file mode 100644
index 0000000..47afaf5
--- /dev/null
+++ b/DataValuesCommon/js/tests/ValueFormatters/ValueFormatter.tests.js
@@ -0,0 +1,164 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ */
+( function( $, QUnit, vf ) {
+       'use strict';
+
+       vf.tests = {};
+
+       /**
+        * Base constructor for ValueFormatter object tests
+        *
+        * @constructor
+        * @abstract
+        * @since 0.1
+        */
+       vf.tests.ValueFormatterTest = function() {};
+       vf.tests.ValueFormatterTest.prototype = {
+
+               /**
+                * Data provider that provides valid format arguments.
+                * @since 0.1
+                *
+                * @return {*[]}
+                */
+               getFormatArguments: vf.util.abstractMember,
+
+               /**
+                * Returns the ValueFormatter constructor to be tested.
+                * @since 0.1
+                *
+                * @return {Function}
+                */
+               getConstructor: vf.util.abstractMember,
+
+               /**
+                * Returns the ValueFormatter instance to be tested.
+                * @since 0.1
+                *
+                * @param {*[]} constructorArguments
+                * @return {valueFormatters.ValueFormatter}
+                */
+               getInstance: function( constructorArguments ) {
+                       constructorArguments = constructorArguments || 
this.getDefaultConstructorArgs();
+
+                       var self = this;
+
+                       var ValueFormatterConstructor = function( 
constructorArguments ) {
+                                       self.getConstructor().apply( this, 
constructorArguments );
+                               };
+
+                       ValueFormatterConstructor.prototype = 
this.getConstructor().prototype;
+                       return new ValueFormatterConstructor( 
constructorArguments );
+               },
+
+               getDefaultConstructorArgs: function() {
+                       return [];
+               },
+
+               /**
+                * Runs the tests.
+                * @since 0.1
+                *
+                * @param {string} moduleName
+                */
+               runTests: function( moduleName ) {
+                       QUnit.module( moduleName );
+
+                       var self = this;
+
+                       $.each( this, function( property, value ) {
+                               if( property.substring( 0, 4 ) === 'test' && 
$.isFunction( self[property] ) ) {
+                                       QUnit.test(
+                                               property,
+                                               function( assert ) {
+                                                       self[property]( assert 
);
+                                               }
+                                       );
+                               }
+                       } );
+               },
+
+               /**
+                * Tests the format method.
+                * @since 0.1
+                *
+                * @param {Function} assert
+                */
+               testFormat: function( assert ) {
+                       var formatArguments = this.getFormatArguments(),
+                               formatter = this.getInstance(),
+                               requests = [];
+
+                       // Prevent continuing with subsequent tests until all 
formatter procedures have
+                       // finished:
+                       QUnit.stop();
+
+                       $.each( formatArguments, function( i, args ) {
+                               var formatInput = args[0],
+                                       expected = args[1],
+                                       expectedValue = expected,
+                                       expectedDataValue,
+                                       inputDetailMsg = typeof formatInput === 
'string'
+                                               ? 'for input "' + formatInput + 
'" '
+                                               : '',
+                                       request;
+
+                               if( $.isArray( expected ) ) {
+                                       expectedValue = expected[0];
+                                       expectedDataValue = expected[1];
+                               } else {
+                                       expectedDataValue = formatInput;
+                               }
+
+                               request = formatter.format( formatInput )
+                               .done( function( formattedValue, dataValue ) {
+                                       assert.ok( true, 'Formatting 
succeeded.' );
+
+                                       if( formattedValue === null ) {
+                                               assert.strictEqual(
+                                                       formattedValue,
+                                                       null,
+                                                       'Formatting result is 
null.'
+                                               );
+                                       } else {
+                                               assert.strictEqual(
+                                                       typeof formattedValue,
+                                                       'string',
+                                                       'Formatting result is a 
string: ' + formattedValue
+                                               );
+                                       }
+
+                                       assert.ok(
+                                               expectedValue === 
formattedValue,
+                                               'Formatting result ' + 
inputDetailMsg + 'matches the expected result.'
+                                       );
+
+                                       assert.ok(
+                                               dataValue === expectedDataValue 
|| dataValue.equals( expectedDataValue ),
+                                               'Returned DataValue ' + 
inputDetailMsg + 'is equal to the expected '
+                                                       + 'DataValue.'
+                                       );
+
+                               } )
+                               .fail( function( errorMessage ) {
+                                       assert.ok(
+                                               false,
+                                               'Formatting ' + inputDetailMsg 
+ 'failed: ' + errorMessage
+                                       );
+                               } );
+
+                               requests.push( request );
+                       } );
+
+                       // Only continue with next test after all formatter 
procedures are finished:
+                       $.when.apply( null, requests ).always( function() {
+                               QUnit.start();
+                       } );
+
+               }
+
+       };
+
+}( jQuery, QUnit, valueFormatters ) );
diff --git 
a/DataValuesCommon/js/tests/ValueFormatters/formatters/NullFormatter.tests.js 
b/DataValuesCommon/js/tests/ValueFormatters/formatters/NullFormatter.tests.js
new file mode 100644
index 0000000..094dcb9
--- /dev/null
+++ 
b/DataValuesCommon/js/tests/ValueFormatters/formatters/NullFormatter.tests.js
@@ -0,0 +1,51 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ */
+( function( vf, dv ) {
+       'use strict';
+
+       var PARENT = vf.tests.ValueFormatterTest,
+               constructor = function() {
+       };
+
+       /**
+        * Constructor for creating a test object containing tests for the 
NullFormatter.
+        *
+        * @constructor
+        * @extends valueFormatters.tests.ValueFormatterTest
+        * @since 0.1
+        */
+       vf.tests.NullParserTest = vf.util.inherit( PARENT, constructor, {
+
+               /**
+                * @see valueFormatters.tests.ValueFormatterTest.getConstructor
+                */
+               getConstructor: function() {
+                       return vf.NullFormatter;
+               },
+
+               /**
+                * @see 
valueFormatters.tests.ValueFormatterTest.getFormatArguments
+                */
+               getFormatArguments: function() {
+                       var date = new Date(),
+                               list = [ true, false, null ];
+
+                       return [
+                               [ new dv.UnknownValue( 'foo' ), 'foo' ],
+                               [ null, null ],
+                               [ 'plain string', [ 'plain string', new 
dv.UnknownValue( 'plain string' ) ] ],
+                               [ -99.9, [ '-99.9', new dv.UnknownValue( -99.9 
) ] ],
+                               [ date, [ String( date ), new dv.UnknownValue( 
date ) ] ],
+                               [ list, [ String( list ), new dv.UnknownValue( 
list ) ] ]
+                       ];
+               }
+
+       } );
+
+       var test = new vf.tests.NullParserTest();
+
+       test.runTests( 'valueFormatters.NullFormatter' );
+
+}( valueFormatters, dataValues ) );
diff --git 
a/DataValuesCommon/js/tests/ValueFormatters/formatters/StringFormatter.tests.js 
b/DataValuesCommon/js/tests/ValueFormatters/formatters/StringFormatter.tests.js
new file mode 100644
index 0000000..e428963
--- /dev/null
+++ 
b/DataValuesCommon/js/tests/ValueFormatters/formatters/StringFormatter.tests.js
@@ -0,0 +1,44 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < [email protected] >
+ */
+( function( vf, dv ) {
+       'use strict';
+
+       var PARENT = vf.tests.ValueFormatterTest;
+
+       /**
+        * Constructor for creating a test object containing tests for the 
StringFormatter.
+        *
+        * @constructor
+        * @extends valueFormatters.tests.ValueFormatterTest
+        * @since 0.1
+        */
+       vf.tests.StringFormatterTest = vf.util.inherit( PARENT, {
+
+               /**
+                * @see valueFormatters.tests.ValueFormatterTest.getObject
+                */
+               getConstructor: function() {
+                       return vf.StringFormatter;
+               },
+
+               /**
+                * @see 
valueFormatters.tests.ValueFormatterTest.getFormatArguments
+                */
+               getFormatArguments: function() {
+                       return [
+                               [ new dv.StringValue( 'some string' ), 'some 
string' ],
+                               [ new dv.StringValue( ' foo ' ), ' foo ' ],
+                               [ new dv.StringValue( ' xXx' ), ' xXx' ],
+                               [ new dv.StringValue( 'xXx ' ), 'xXx ' ]
+                       ];
+               }
+
+       } );
+
+       var test = new vf.tests.StringFormatterTest();
+
+       test.runTests( 'valueFormatters.StringFormatter' );
+
+}( valueFormatters, dataValues ) );

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I10481061ac0ee925cd70b5e321153ba433cd7c26
Gerrit-PatchSet: 6
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Henning Snater <[email protected]>
Gerrit-Reviewer: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Daniel Werner <[email protected]>
Gerrit-Reviewer: Jeroen De Dauw <[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

Reply via email to