Tobias Gritschacher has submitted this change and it was merged.

Change subject: Reverts valueview.Expert interfaces changes from I30cb202 and 
compensates
......................................................................


Reverts valueview.Expert interfaces changes from I30cb202 and compensates

- Removes usage of parser from GlobeCoordinateInput expert
- Introduces valueview.Expert.valueCharacteristics
- Adds some TODOs for what to do move preview and advanced options out of the 
experts. This still requires some additional thought though.

Change-Id: Ie12d52609ce9c83f8f4d1f8254f09c668585dff5
---
M ValueParsers/resources/ValueParser.js
M ValueParsers/resources/parsers/GlobeCoordinateParser.js
M ValueParsers/tests/qunit/parsers/GlobeCoordinateParser.tests.js
M ValueView/resources/jquery.valueview/valueview.BifidExpert.js
M ValueView/resources/jquery.valueview/valueview.Expert.js
M ValueView/resources/jquery.valueview/valueview.MockViewState.js
M 
ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
M 
ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateValue.js
M ValueView/resources/jquery.valueview/valueview.experts/experts.StaticDom.js
M ValueView/resources/jquery.valueview/valueview.preview.css
M ValueView/resources/jquery.valueview/valueview.valueview.js
M 
ValueView/tests/qunit/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.tests.js
M ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js
13 files changed, 208 insertions(+), 208 deletions(-)

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



diff --git a/ValueParsers/resources/ValueParser.js 
b/ValueParsers/resources/ValueParser.js
index f9355e4..92764b6 100644
--- a/ValueParsers/resources/ValueParser.js
+++ b/ValueParsers/resources/ValueParser.js
@@ -17,7 +17,7 @@
         * @param {Object} options
         */
        var SELF = vp.ValueParser = function VpValueParser( options ) {
-               this._options = options || {};
+               this._options = $.extend( {}, options || {} );
        };
 
        $.extend( SELF.prototype, {
@@ -30,6 +30,17 @@
                _options: {},
 
                /**
+                * Returns the parser's options as set in the constructor.
+                *
+                * @since 0.1
+                *
+                * @returns Object
+                */
+               getOptions: function() {
+                       return $.extend( {}, this._options );
+               },
+
+               /**
                 * Parses a value. Will return a jQuery.Promise which will be 
resolved if the parsing is
                 * successful or rejected if it fails. There can be various 
reasons for the parsing to fail,
                 * e.g. the parser is using the API and the API can't be 
reached. In case of success, the
diff --git a/ValueParsers/resources/parsers/GlobeCoordinateParser.js 
b/ValueParsers/resources/parsers/GlobeCoordinateParser.js
index 91527d6..4d4b709 100644
--- a/ValueParsers/resources/parsers/GlobeCoordinateParser.js
+++ b/ValueParsers/resources/parsers/GlobeCoordinateParser.js
@@ -6,7 +6,7 @@
  *
  * @author H. Snater < [email protected] >
  */
-( function( vp, dv, $, GlobeCoordinate ) {
+( function( vp, dv ) {
        'use strict';
 
        var PARENT = vp.ApiBasedValueParser;
@@ -22,26 +22,7 @@
                /**
                 * @see vp.ApiBasedValueParser.API_VALUE_PARSER_ID
                 */
-               API_VALUE_PARSER_ID: 'globecoordinate',
-
-               /**
-                * @see vp.ValueParser.parse
-                * @since 0.1
-                *
-                * TODO: Make this accept strings only.
-                *
-                * @param {globeCoordinate.GlobeCoordinate|string} rawValue
-                * @return $.Promise
-                */
-               parse: function( rawValue ) {
-                       if( rawValue instanceof GlobeCoordinate ) {
-                               var globeCoordinateValue = new 
dv.GlobeCoordinateValue( rawValue ),
-                                       deferred = $.Deferred().resolve( 
globeCoordinateValue );
-                               return deferred.promise();
-                       } else {
-                               return PARENT.prototype.parse.call( this, 
rawValue );
-                       }
-               }
+               API_VALUE_PARSER_ID: 'globecoordinate'
        } );
 
-}( valueParsers, dataValues, jQuery, globeCoordinate.GlobeCoordinate ) );
+}( valueParsers, dataValues ) );
diff --git a/ValueParsers/tests/qunit/parsers/GlobeCoordinateParser.tests.js 
b/ValueParsers/tests/qunit/parsers/GlobeCoordinateParser.tests.js
index f7aab25..17ddd80 100644
--- a/ValueParsers/tests/qunit/parsers/GlobeCoordinateParser.tests.js
+++ b/ValueParsers/tests/qunit/parsers/GlobeCoordinateParser.tests.js
@@ -34,20 +34,12 @@
                getParseArguments: function() {
                        return [
                                [
-                                       '-1.5, -1.25',
-                                       new dv.GlobeCoordinateValue( new 
GlobeCoordinate( '-1.5, -1.25' ) )
+                                       '1.5, 1.25',
+                                       new dv.GlobeCoordinateValue( new 
GlobeCoordinate( '1.5, 1.25' ) )
                                ],
                                [
-                                       '10, 12',
-                                       new dv.GlobeCoordinateValue( new 
GlobeCoordinate( '10, 12' ) )
-                               ],
-                               [
-                                       new GlobeCoordinate( '1.5 1.25' ),
-                                       new dv.GlobeCoordinateValue( new 
GlobeCoordinate( '1.5 1.25' ) )
-                               ],
-                               [
-                                       new GlobeCoordinate( '-50 -20' ),
-                                       new dv.GlobeCoordinateValue( new 
GlobeCoordinate( '-50 -20' ) )
+                                       '-50, -20',
+                                       new dv.GlobeCoordinateValue( new 
GlobeCoordinate( '-50, -20' ) )
                                ]
                        ];
                }
diff --git a/ValueView/resources/jquery.valueview/valueview.BifidExpert.js 
b/ValueView/resources/jquery.valueview/valueview.BifidExpert.js
index 6116a98..57bb979 100644
--- a/ValueView/resources/jquery.valueview/valueview.BifidExpert.js
+++ b/ValueView/resources/jquery.valueview/valueview.BifidExpert.js
@@ -120,6 +120,13 @@
                },
 
                /**
+                * @see jQuery.valueview.Expert.valueCharacteristics
+                */
+               valueCharacteristics: function() {
+                       return this._currentExpert.valueCharacteristics();
+               },
+
+               /**
                 * @see jQuery.valueview.Expert._getRawValue
                 */
                _getRawValue: function() {
diff --git a/ValueView/resources/jquery.valueview/valueview.Expert.js 
b/ValueView/resources/jquery.valueview/valueview.Expert.js
index 98c3348..c13701d 100644
--- a/ValueView/resources/jquery.valueview/valueview.Expert.js
+++ b/ValueView/resources/jquery.valueview/valueview.Expert.js
@@ -165,8 +165,11 @@
                /**
                 * Returns a parser suitable for parsing the raw value returned 
by rawValue().
                 *
+                * TODO: Get rid of this in here. rawValue should just always 
return a string or a
+                *  DataValue, in case of a string, in the valueview, we would 
just get the parser from a
+                *  ValueParserFactory composited into the valueview.
+                *
                 * @since 0.1
-                * @abstract
                 *
                 * @return valueParsers.ValueParser
                 */
@@ -175,6 +178,19 @@
                },
 
                /**
+                * Returns an object with characteristics specified for the 
value. The object can be used
+                * as parser options definition in the parser returned by 
parser().
+                *
+                * TODO: This should actually move out of here together with 
all the advanced input features
+                *  of certain experts (time/coordinate).
+                *
+                * @since 0.1
+                */
+               valueCharacteristics: function() {
+                       return {};
+               },
+
+               /**
                 * Returns an object offering information about the related 
valueview's current state.
                 * The expert reflects that state, so everything that is true 
for the related view, is also
                 * true for the expert (e.g. whether it is in edit mode or 
disabled).
diff --git a/ValueView/resources/jquery.valueview/valueview.MockViewState.js 
b/ValueView/resources/jquery.valueview/valueview.MockViewState.js
index fa3234d..18d6898 100644
--- a/ValueView/resources/jquery.valueview/valueview.MockViewState.js
+++ b/ValueView/resources/jquery.valueview/valueview.MockViewState.js
@@ -14,7 +14,7 @@
         * @extends jQuery.valueview.ViewState
         * @since 0.1
         *
-        * @param {Object} [definition={}] A plain object with the fiels 
"isInEditMode", "isDisabled",
+        * @param {Object} [definition={}] A plain object with the fields 
"isInEditMode", "isDisabled",
         *        "value" and "options". This will just keep a reference to the 
object, so changing the
         *        object from the outside will also update the ViewState's 
functions return values.
         */
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
index 8f75709..fdb0c7e 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
@@ -4,6 +4,7 @@
  * @licence GNU GPL v2+
  *
  * @author H. Snater < [email protected] >
+ * @author Daniel Werner < [email protected] >
  */
 // TODO: Remove mediaWiki dependency
 ( function( dv, vp, $, vv, globeCoordinate, mw ) {
@@ -34,17 +35,9 @@
                 * the new value has been called. The use of this, basically, 
is a structural improvement
                 * which allows moving setting the displayed value to the 
draw() method which is supposed to
                 * handle all visual manners.
-                * @type {globeCoordinate.GlobeCoordinate|null|false}
+                * @type {string|null|false}
                 */
                _newValue: null,
-
-               /**
-                * Current value. Needs to be cached because the value cannot 
simply be parsed from the
-                * current input element value since that would lead to the 
precision being set in the
-                * sexagesimal system even when not intended.
-                * @type {globeCoordinate.GlobeCoordinate|null}
-                */
-               _value: null,
 
                /**
                 * The preview widget.
@@ -69,9 +62,10 @@
                 */
                _init: function() {
                        var self = this,
-                               listrotatorEvents = 'listrotatorauto.' + 
this.uiBaseClass
-                                       + ' listrotatorselected.' + 
this.uiBaseClass,
-                               precisionValues = [];
+                               notifier = this._viewNotifier,
+                               precisionValues = [],
+                               listrotatorEvents = 'listrotatorauto 
listrotatorselected'
+                                       .replace( /(\w+)/g, '$1.' + 
this.uiBaseClass );
 
                        this.$precisionContainer = $( '<div/>' )
                        .addClass( this.uiBaseClass + '-precisioncontainer' )
@@ -93,21 +87,24 @@
                                        values: precisionValues.reverse(),
                                        deferInit: true
                                } )
-                               .on( listrotatorEvents, function( event, 
newValue ) {
-                                       var rawValue = self._getRawValue(),
-                                               roundedPrecision = 
roundPrecision( rawValue.getPrecision() ) ;
+                               .on( listrotatorEvents, function( event, 
newPrecisionLevel ) {
+                                       var currentValue = 
self.viewState().value();
 
-                                       if( rawValue === null || newValue === 
roundedPrecision ) {
-                                               // Listrotator has been rotated 
automatically, the value covering the new
-                                               // precision has already been 
generated or the current input is invalid.
+                                       if( currentValue === null ) {
+                                               // current rawValue must be 
invalid anyhow
                                                return;
                                        }
 
-                                       self._updateValue().done( function( gc 
) {
-                                               if( event.type === 
'listrotatorauto' ) {
-                                                       self.$precision.data( 
'listrotator' ).rotate( gc.getValue().getPrecision() );
-                                               }
-                                       } );
+                                       var currentPrecision = roundPrecision(
+                                                       
currentValue.getValue().getPrecision() );
+
+                                       if( newPrecisionLevel === 
currentPrecision ) {
+                                               // Listrotator has been rotated 
automatically or the value covering the new
+                                               // precision has already been 
generated.
+                                               return;
+                                       }
+
+                                       notifier.notify( 'change' );
                                } )
                                .appendTo( this.$precisionContainer );
 
@@ -125,42 +122,7 @@
                        this.preview = $preview.data( 'preview' );
 
                        this.$input.eachchange( function( event, oldValue ) {
-                               var currentInputValue = self.$input.val();
-
-                               self._setRawValue( currentInputValue );
-
-                               // No need to update the preview when the input 
element is cleared since it will
-                               // be hidden anyway.
-                               if( self.$input.val() === '' ) {
-                                       self._updatePreview( null );
-                                       return;
-                               }
-
-                               self.preview.showSpinner();
-
-                               self.parser().parse( self.$input.val() )
-                               .done( function( dataValue ) {
-                                       // Throw away outdated requests:
-                                       if( currentInputValue !== 
self.$input.val() ) {
-                                               return;
-                                       }
-
-                                       self._setRawValue( dataValue.getValue() 
);
-
-                                       self.$precision.data( 'listrotator' 
).rotate(
-                                               roundPrecision( 
dataValue.getValue().getPrecision() )
-                                       );
-
-                                       self._newValue = false; // value, not 
yet handled by draw(), is outdated now
-                                       self._updatePreview( 
dataValue.getValue() );
-                                       self._viewNotifier.notify( 'change' );
-                               } )
-                               .fail( function() {
-                                       if( currentInputValue !== 
self.$input.val() ) {
-                                               return;
-                                       }
-                                       self._updatePreview( null );
-                               } );
+                               notifier.notify( 'change' );
                        } )
                        .inputextender( {
                                content: [ $preview, $toggler, 
this.$precisionContainer ],
@@ -192,79 +154,60 @@
                },
 
                /**
-                * Builds a GlobeCoordinate object from the widget's current 
input taking the precision into
-                * account if set manually.
-                * @since 0.1
-                *
-                * @return {jQuery.Promise}
-                */
-               _updateValue: function() {
-                       var currentInputValue = this.$input.val();
-
-                       this.preview.showSpinner();
-
-                       var self = this;
-                       return this.parser().parse( this.$input.val() )
-                       .done( function( gc ) {
-                               // Throw away outdated requests:
-                               if( currentInputValue !== self.$input.val() ) {
-                                       return;
-                               }
-                               self._setRawValue( gc.getValue() );
-                               self._updatePreview( gc.getValue() );
-                               self._viewNotifier.notify( 'change' );
-                       } )
-                       .fail( function() {
-                               if( currentInputValue !== self.$input.val() ) {
-                                       return;
-                               }
-                               self._setRawValue( null );
-                               self._updatePreview( null );
-                               self._viewNotifier.notify( 'change' );
-                       } );
-               },
-
-               /**
-                * Updates the preview.
-                * @since 0.1
-                *
-                * @param {globeCoordinate.GlobeCoordinate|null} gc
-                */
-               _updatePreview: function( gc ) {
-                       if( gc !== null ) {
-                               gc = gc.degreeText();
-                       }
-                       this.preview.update( gc );
-               },
-
-               /**
                 * @see jQuery.valueview.Expert.parser
                 */
                parser: function() {
-                       var precisionWidget = this.$precision.data( 
'listrotator' ),
-                               options = ( !precisionWidget.$auto.hasClass( 
'ui-state-active' ) )
-                                       ? { precision: getPrecisionSetting( 
precisionWidget.value() ) }
-                                       : {};
+                       return new vp.GlobeCoordinateParser();
+               },
 
-                       return new vp.GlobeCoordinateParser( options );
+               /**
+                * @see jQuery.valueview.Expert.valueCharacteristics
+                */
+               valueCharacteristics: function() {
+                       if( !this.$precision ) { // happens when used by 
BifidExpert ...
+                               return {};
+                       }
+
+                       var options = {},
+                               precisionWidget = this.$precision.data( 
'listrotator' );
+
+                       // TODO: Don't access the widget's internals here, 
check this via some function.
+                       if( !precisionWidget.$auto.hasClass( 'ui-state-active' 
) ) {
+                               var precision = getPrecisionSetting( 
precisionWidget.value() );
+
+                               if( precision !== null ) {
+                                       options.precision = precision;
+                               }
+                       }
+
+                       return options;
                },
 
                /**
                 * @see jQuery.valueview.Expert._getRawValue
                 *
-                * @return {globeCoordinate.GlobeCoordinate|string|null}
+                * @return {string|null}
                 */
                _getRawValue: function() {
-                       return ( this._newValue !== false ) ? this._newValue : 
this._value;
+                       var value = this._newValue !== false ? this._newValue : 
this.$input.val();
+
+                       if( $.trim( value ) === '' ) {
+                               return null;
+                       }
+                       return value;
                },
 
                /**
                 * @see jQuery.valueview.Expert._setRawValue
-                *
-                * @param {globeCoordinate.GlobeCoordinate|string|null} 
globeCoordinate
                 */
-               _setRawValue: function( globeCoordinate ) {
-                       this._newValue = this._value = globeCoordinate;
+               _setRawValue: function( rawValue ) {
+                       if( rawValue instanceof GlobeCoordinate ) {
+                               rawValue = rawValue.degreeText();
+                       }
+                       else if( typeof rawValue !== 'string' ) {
+                               rawValue = null;
+                       }
+                       this._newValue = rawValue;
                },
 
                /**
@@ -292,41 +235,40 @@
 
                /**
                 * @see jQuery.valueview.Expert.draw
-                *
-                * @return {jQuery.Promise|null}
-                *
-                * TODO: Get rid of this LSP violation, should not be necessary 
to return a promise here.
                 */
                draw: function() {
-                       var self = this,
-                               promise = null;
+                       var geoValue = this.viewState().value(),
+                               $input = this.$input;
 
                        if( this._viewState.isDisabled() ) {
-                               var deferred = $.Deferred().reject();
-                               promise = deferred.promise();
-                               this.$input.prop( 'disabled', true ).addClass( 
'ui-state-disabled' );
+                               $input.prop( 'disabled', true ).addClass( 
'ui-state-disabled' );
                        } else {
-                               this.$input.prop( 'disabled', false 
).removeClass( 'ui-state-disabled' );
+                               $input.prop( 'disabled', false ).removeClass( 
'ui-state-disabled' );
+                       }
 
-                               if( this._newValue !== false ) {
-                                       if( this._newValue !== null ) {
-                                               promise = this.parser().parse( 
this._newValue )
-                                               .done( function( dataValue ) {
-                                                       var gc = 
dataValue.getValue();
-                                                       self.$input.val( 
gc.degreeText() );
-                                                       self.$precision.data( 
'listrotator' ).value(
-                                                               roundPrecision( 
gc.getPrecision() )
-                                                       );
-                                                       self._updatePreview( gc 
);
-                                               } ).fail( function() {
-                                                       self._updatePreview( 
null );
-                                               } );
-                                       }
-                                       this._newValue = false;
+                       if( this._newValue !== false ) {
+                               var newText = this._newValue || '';
+
+                               if( $input.val() !== newText ) {
+                                       $input.val( newText );
                                }
                        }
 
-                       return promise;
+                       if( this._newValue
+                               || this.$precision.data( 'listrotator' 
).$auto.hasClass( 'ui-state-active' )
+                       ) {
+                               // hacky update of precision, just assume the 
raw value is the value we have in
+                               // the valueview right now.
+                               if( geoValue ) {
+                                       this.$precision.data( 'listrotator' 
).value(
+                                               roundPrecision( 
geoValue.getValue().getPrecision() ) );
+                               }
+                       }
+
+                       this._newValue = false;
+
+                       // Update preview:
+                       this.preview.update( geoValue && 
geoValue.getValue().degreeText() );
                },
 
                /**
@@ -345,7 +287,11 @@
        } );
 
        /**
-        * Rounds a given precision for being able to use is as internal 
"constant".
+        * Rounds a given precision for being able to use it as internal 
"constant".
+        *
+        * TODO: This should not even be necessary. Make sure 
GlobeCoordinateValue objects can be
+        *  used without having to take care of their precision first if they 
are generated by the
+        *  backend parser.
         *
         * @since 0.1
         *
@@ -373,11 +319,11 @@
         * @since 0.1
         *
         * @param {number} roundedPrecision
-        * @return {number}
+        * @return {number|null}
         */
        function getPrecisionSetting( roundedPrecision ) {
                var rounded,
-                       precision;
+                       precision = null;
 
                $.each( globeCoordinateSettings.precisions, function( i, 
precisionDefinition ) {
                        rounded = roundPrecision( precisionDefinition.level );
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateValue.js
 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateValue.js
index 882ab78..34305f1 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateValue.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateValue.js
@@ -40,22 +40,15 @@
                 */
                _staticExpertOptions: {
                        /**
-                        * @param {string|globeCoordinate.GlobeCoordinate|null} 
currentRawValue
-                        * @param {jQuery.valueview.ViewState} [viewState]
+                        * @param {globeCoordinate.GlobeCoordinate|string|null} 
currentRawValue
+                        * @param {jQuery.valueview.ViewState} viewState
                         */
                        domBuilder: function( currentRawValue, viewState ) {
-                               var $node = $( '<span/>' );
-
-                               if( !currentRawValue ) {
-                                       return $node;
+                               if( currentRawValue instanceof GlobeCoordinate 
) {
+                                       currentRawValue = 
currentRawValue.degreeText();
                                }
 
-                               // On initialization, the static expert will be 
fed with a GlobeCoordinate instance.
-                               var text = ( currentRawValue instanceof 
GlobeCoordinate )
-                                       ? currentRawValue.degreeText()
-                                       : currentRawValue;
-
-                               return $node.text( text );
+                               return $( '<span/>' ).text( currentRawValue || 
'' );
                        },
                        baseExpert: editableExpert
                }
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.StaticDom.js 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.StaticDom.js
index 53b3e03..fd9d068 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.StaticDom.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.StaticDom.js
@@ -49,18 +49,20 @@
                },
 
                /**
-                * Returns a parser suitable for parsing the raw value returned 
by rawValue().
-                *
-                * @since 0.1
-                * @abstract
-                *
-                * @return valueParsers.Parser
+                * @see jQuery.valueview.Expert.parser
                 */
                parser: function() {
                        return this._options.baseExpert.prototype.parser.call( 
this );
                },
 
                /**
+                * @see jQuery.valueview.Expert.valueCharacteristics
+                */
+               valueCharacteristics: function() {
+                       return 
this._options.baseExpert.prototype.valueCharacteristics.call( this );
+               },
+
+               /**
                 * @see jQuery.valueview.Expert.destroy
                 */
                _getRawValue: function() {
diff --git a/ValueView/resources/jquery.valueview/valueview.preview.css 
b/ValueView/resources/jquery.valueview/valueview.preview.css
index e4103fc..2d77f3b 100644
--- a/ValueView/resources/jquery.valueview/valueview.preview.css
+++ b/ValueView/resources/jquery.valueview/valueview.preview.css
@@ -16,3 +16,9 @@
 .valueview-preview-novalue {
        font-style: italic;
 }
+
+.valueview-preview-label .mw-small-spinner {
+       position: relative;
+       top: 0;
+       left: 0;
+}
\ No newline at end of file
diff --git a/ValueView/resources/jquery.valueview/valueview.valueview.js 
b/ValueView/resources/jquery.valueview/valueview.valueview.js
index 55b4f20..56a9211 100644
--- a/ValueView/resources/jquery.valueview/valueview.valueview.js
+++ b/ValueView/resources/jquery.valueview/valueview.valueview.js
@@ -507,9 +507,28 @@
 
                this.__lastUpdateValue = rawValue;
 
-               expert.parser().parse(
+               // TODO: Get rid of parsers in experts, instead, inject a 
ValueParserFactory in here.
+               var parserOptions = expert.valueCharacteristics(),
+                       valueParser = expert.parser();
+
+               parserOptions = $.extend( valueParser.getOptions(), 
parserOptions );
+               valueParser = new valueParser.constructor( parserOptions );
+
+               // TODO: Hacky preview spinner activation. Necessary until we 
move the responsibility for
+               //  previews out of the experts. The preview should be handled 
in the same place for all
+               //  value types, could perhaps move into its own widget, 
listening to valueview events.
+               if( expert._currentExpert && expert._currentExpert.preview ) {
+                       expert._currentExpert.preview.showSpinner();
+               }
+
+               valueParser.parse(
                        rawValue
                ).done( function( parsedValue ) {
+                       // Paranoia check against ValueParser interface:
+                       if( parsedValue !== null && !( parsedValue instanceof 
dv.DataValue ) ) {
+                               throw new Error( 'Unexpected value parser 
result' );
+                       }
+
                        if( self.__lastUpdateValue === undefined ) {
                                // latest update job is done, this one must be 
a late response for some weird reason
                                return;
@@ -528,6 +547,9 @@
                        // TODO: display some message if parsing failed due to 
bad API connection etc.
                        self._value = null;
                } ).always( function() {
+                       // Call experts draw() for allowing update of "advanced 
adjustments" in some experts.
+                       expert.draw();
+
                        self._trigger( 'afterparse' );
                } );
        },
@@ -568,11 +590,27 @@
                                // the expert will get that new value's raw 
value while we already have the parsed
                                // version of the value.
                                var value = self.value(),
-                                       rawValue = value ? value.getValue() : 
null;
+                                       rawValue = value ? value.getValue() : 
null,
+                                       differentValueCharacteristics = false,
+                                       newValueCharacteristics = 
self._expert.valueCharacteristics(),
+                                       lastValueCharacteristics = 
self.__lastValueCharacteristics || {};
 
-                               if( !self._expert.rawValueCompare( rawValue )
-                                       && !self._setValueIsOngoing
+                               for( var i in newValueCharacteristics ) {
+                                       differentValueCharacteristics = 
differentValueCharacteristics ||
+                                               newValueCharacteristics[i] !== 
lastValueCharacteristics[i];
+                               }
+                               for( var i in lastValueCharacteristics ) {
+                                       differentValueCharacteristics = 
differentValueCharacteristics ||
+                                               newValueCharacteristics[i] !== 
lastValueCharacteristics[i];
+                               }
+
+                               if( !self._setValueIsOngoing
+                                       && (
+                                               differentValueCharacteristics
+                                               || 
!self._expert.rawValueCompare( rawValue )
+                                       )
                                ) {
+                                       self.__lastValueCharacteristics = 
newValueCharacteristics;
                                        self._trigger( 'change' );
                                        self._updateValue();
                                }
diff --git 
a/ValueView/tests/qunit/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.tests.js
 
b/ValueView/tests/qunit/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.tests.js
index a5f9bb9..8dd81bf 100644
--- 
a/ValueView/tests/qunit/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.tests.js
+++ 
b/ValueView/tests/qunit/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.tests.js
@@ -16,13 +16,12 @@
                expertConstructor: valueview.experts.GlobeCoordinateInput,
                rawValues: {
                        valid: [
-                               new GlobeCoordinate( '30, 30' ),
-                               new GlobeCoordinate( '-1.5 -1.25' )
+                               '-1.5, -1.25',
+                               '30, 30',
+                               'foo' // Might not be a valid coordinate, but 
that's for the parser to decide, the expert shouldn't care.
                        ],
                        unknown: 
testExpert.basicTestDefinition.rawValues.unknown.concat( [
-                               'foo', // NOTE: this is only "unknown" because 
the expert is overly smart since it is using the parser internally (while it 
shouldn't)
                                42,
-                               '1 1'
                        ] )
                },
                relatedValueParser: GlobeCoordinateParser
diff --git 
a/ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js 
b/ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js
index 5c65480..2fa30e0 100644
--- a/ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js
+++ b/ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js
@@ -130,6 +130,15 @@
                );
        } );
 
+       expertCases.test( 'valueCharacteristics', function( args, assert ) {
+               var valueCharacteristics = args.expert.valueCharacteristics();
+
+               assert.ok(
+                       $.isPlainObject( valueCharacteristics ),
+                       'valueCharacteristics() returns a plain object'
+               );
+       } );
+
        expertCases.test( 'viewState', function( args, assert ) {
                var viewState = args.expert.viewState();
                assert.ok(

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

Gerrit-MessageType: merged
Gerrit-Change-Id: Ie12d52609ce9c83f8f4d1f8254f09c668585dff5
Gerrit-PatchSet: 6
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

Reply via email to