Skip to content

Commit ca74115

Browse files
committed
Merge pull request #58 from wmde/editCoordPrecision
Support editing arbitrary precisions for GlobeCoordinates
2 parents 3944cdf + e5a4e95 commit ca74115

File tree

6 files changed

+138
-45
lines changed

6 files changed

+138
-45
lines changed

i18n/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"valueview-expert-unsupportedvalue-unsupporteddatatype": "Handling of values for \"$1\" data type is not yet supported.",
1212
"valueview-expert-emptyvalue-empty": "empty",
1313
"valueview-expert-globecoordinateinput-precision": "Precision:",
14+
"valueview-expert-globecoordinateinput-customprecision": "special ($1)",
1415
"valueview-expert-timevalue-calendar-gregorian": "Gregorian",
1516
"valueview-expert-timevalue-calendar-julian": "Julian",
1617
"valueview-expert-timeinput-precision": "Precision:",
@@ -22,4 +23,4 @@
2223
"valueview-preview-label": "will be displayed as:",
2324
"valueview-preview-novalue": "no valid value recognized",
2425
"valueview-listrotator-auto": "auto"
25-
}
26+
}

lib/jquery.ui/jquery.ui.listrotator.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -339,25 +339,29 @@
339339
.appendTo( $( 'body' ) ).hide();
340340

341341
$.each( this.options.values, function( i, v ) {
342-
self.$menu.append(
343-
$( '<li/>' )
344-
.append(
345-
$( '<a/>' )
346-
.attr( 'href', 'javascript:void(0);')
347-
.text( v.label )
348-
.on( 'click', function( event ) {
349-
event.stopPropagation();
350-
self._trigger( 'selected', null, [ self.value( v.value ) ] );
351-
self.$menu.hide();
352-
} )
353-
)
354-
.data( 'value', v.value )
355-
);
342+
self._addMenuItem( v );
356343
} );
357344

358345
this.$menu.menu();
359346
},
360347

348+
_addMenuItem: function( item ) {
349+
var self = this;
350+
return $( '<li/>' )
351+
.append(
352+
$( '<a/>' )
353+
.attr( 'href', 'javascript:void(0);')
354+
.text( item.label )
355+
.on( 'click', function( event ) {
356+
event.stopPropagation();
357+
self._trigger( 'selected', null, [ self.value( item.value ) ] );
358+
self.$menu.hide();
359+
} )
360+
)
361+
.data( 'value', item.value )
362+
.appendTo( this.$menu );
363+
},
364+
361365
/**
362366
* Sets/Gets the widget's value. Setting the value involves setting the rotator to the
363367
* specified value without any animation.

src/ExpertExtender/ExpertExtender.Listrotator.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
_onValueChange: null,
3333
_getUpstreamValue: null,
3434

35+
_$customItem: null,
36+
3537
rotator: null,
3638

3739
/**
@@ -59,9 +61,29 @@
5961
*/
6062
draw: function() {
6163
var value = this._getUpstreamValue();
62-
if( value && this.rotator.autoActive() ) {
64+
if( !value ) {
65+
return;
66+
}
67+
68+
if( this._$customItem ) {
69+
this.rotator.options.values.splice(this._customValue, 1);
70+
this._$customItem.remove();
71+
this._$customItem = null;
72+
this._customValue = null;
73+
}
74+
if( value.custom ) {
75+
this._customValue = this.rotator.options.values.push( value ) - 1;
76+
this._$customItem = this.rotator._addMenuItem( value );
77+
value = value.value;
78+
}
79+
80+
if( this.rotator.autoActive() || this._$customItem ) {
6381
this.rotator.value( value );
6482
this.rotator._setValue( value );
83+
if( this._$customItem ) {
84+
this.rotator.$menu.data( 'menu' ).refresh();
85+
this.rotator.activate(); // disables autoActive state
86+
}
6587
}
6688
},
6789

src/experts/GlobeCoordinateInput.js

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @author H. Snater < mediawiki@snater.com >
33
* @author Daniel Werner < daniel.werner@wikimedia.de >
44
*/
5-
( function( $, vv, GlobeCoordinate, Formatter ) {
5+
( function( $, vv, Formatter ) {
66
'use strict';
77

88
var PARENT = vv.experts.StringValue;
@@ -38,7 +38,15 @@
3838
},
3939
function(){
4040
var value = self.viewState().value();
41-
return value && roundPrecision( value.getValue().getPrecision() );
41+
if( !value ) {
42+
return value;
43+
}
44+
value = value.getValue().getPrecision();
45+
return getPrecisionSetting( value ) || {
46+
custom: true,
47+
value: value,
48+
label: self._messageProvider.getMessage('valueview-expert-globecoordinateinput-customprecision', [ Formatter.PRECISIONTEXT( value ) ] )
49+
};
4250
}
4351
);
4452

@@ -89,7 +97,7 @@
8997
}
9098

9199
var options = {},
92-
precision = getPrecisionSetting( this.precisionRotator.getValue() );
100+
precision = this.precisionRotator.getValue();
93101

94102
if( precision !== null ) {
95103
options.precision = precision;
@@ -111,43 +119,29 @@
111119
/**
112120
* Rounds a given precision for being able to use it as internal "constant".
113121
*
114-
* TODO: Calculated numbers used for the precision (e.g. 1/60) may result in different values
115-
* in front- and back-end. Either use dedicated float numbers in front- and back-end or
116-
* integrate the rounding in GlobeCoordinate.
117-
*
118122
* @since 0.1
119123
*
120124
* @param {number} precision
121125
* @return {number}
122126
*/
123127
function roundPrecision( precision ) {
124-
var precisions = GlobeCoordinate.PRECISIONS,
125-
highestPrecision = precisions[precisions.length - 1],
126-
multiplier = 1;
127-
128-
// To make sure that not too much digits are cut off for the "constant" precisions to be
129-
// distinctive, we round with a multiplier that rounds the most precise precision to a
130-
// number greater than 1:
131-
while( highestPrecision * multiplier < 1 ) {
132-
multiplier *= 10;
133-
}
134-
135-
return Math.round( precision * multiplier ) / multiplier;
128+
return Number( precision.toPrecision(4) );
136129
}
137130

138131
/**
139-
* Returns the original precision level for a rounded precision.
132+
* Returns the original precision level for an unrounded precision.
140133
*
141134
* @since 0.1
142135
*
143-
* @param {number} roundedPrecision
136+
* @param {number} precision
144137
* @return {number|null}
145138
*/
146-
function getPrecisionSetting( roundedPrecision ) {
139+
function getPrecisionSetting( precision ) {
147140
var rounded,
148-
actualPrecision = null;
141+
actualPrecision = null,
142+
roundedPrecision = roundPrecision( precision );
149143

150-
$.each( GlobeCoordinate.PRECISIONS, function( i, precision ) {
144+
$.each( PRECISIONS, function( i, precision ) {
151145
rounded = roundPrecision( precision );
152146
if( rounded === roundedPrecision ) {
153147
actualPrecision = precision;
@@ -160,7 +154,7 @@
160154

161155
function getPrecisionValues() {
162156
var precisionValues = [];
163-
$.each( GlobeCoordinate.PRECISIONS, function( i, precision ) {
157+
$.each( PRECISIONS, function( i, precision ) {
164158
var label = Formatter.PRECISIONTEXT( precision );
165159
precisionValues.unshift( {
166160
value: roundPrecision( precision ),
@@ -170,4 +164,20 @@
170164
return precisionValues;
171165
}
172166

173-
}( jQuery, jQuery.valueview, globeCoordinate.GlobeCoordinate, globeCoordinate.Formatter ) );
167+
var PRECISIONS = [
168+
10,
169+
1,
170+
0.1,
171+
1 / 60,
172+
0.01,
173+
0.001,
174+
1 / 3600,
175+
0.0001,
176+
1 / 36000,
177+
0.00001,
178+
1 / 360000,
179+
0.000001,
180+
1 / 3600000
181+
];
182+
183+
}( jQuery, jQuery.valueview, globeCoordinate.Formatter ) );

src/experts/resources.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
),
7070
'messages' => array(
7171
'valueview-expert-globecoordinateinput-precision',
72+
'valueview-expert-globecoordinateinput-customprecision',
7273
),
7374
),
7475

tests/src/ExpertExtender/ExpertExtender.Listrotator.tests.js

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,71 @@
1616

1717
testExpertExtenderExtension.constructor(
1818
ExpertExtender.Listrotator,
19-
new ExpertExtender.Listrotator( '', [ 'value' ] )
19+
new ExpertExtender.Listrotator( '', [ { value: 'value', label: 'label' } ] )
2020
);
2121
testExpertExtenderExtension.destroy(
2222
ExpertExtender.Listrotator,
23-
new ExpertExtender.Listrotator( '', [ 'value' ] )
23+
new ExpertExtender.Listrotator( '', [ { value: 'value', label: 'label' } ] )
2424
);
2525
testExpertExtenderExtension.init(
26-
new ExpertExtender.Listrotator( '', [ 'value' ] )
26+
new ExpertExtender.Listrotator( '', [ { value: 'value', label: 'label' } ] )
2727
);
2828

29+
QUnit.test( 'supports custom values', function( assert ) {
30+
var getUpstreamValue = function() {
31+
return {
32+
custom: true,
33+
value: 'custom value',
34+
label: 'label for custom value'
35+
};
36+
};
37+
var $extender = $( '<div />' );
38+
39+
var listrotator = new ExpertExtender.Listrotator(
40+
'',
41+
[ { value: 'fixed value', label: 'label for fixed value' } ],
42+
null,
43+
getUpstreamValue
44+
);
45+
46+
listrotator.init( $extender );
47+
listrotator.draw();
48+
49+
assert.equal( listrotator.getValue(), 'custom value' );
50+
} );
51+
52+
QUnit.asyncTest( 'supports switching away from custom values', function( assert ) {
53+
var onValueChange = sinon.spy();
54+
var upstreamValue = {
55+
custom: true,
56+
value: 'custom value',
57+
label: 'label for custom value'
58+
};
59+
var getUpstreamValue = function() {
60+
return upstreamValue;
61+
};
62+
var $extender = $( '<div />' );
63+
64+
var listrotator = new ExpertExtender.Listrotator(
65+
'',
66+
[ { value: 'fixed value', label: 'label for fixed value' } ],
67+
onValueChange,
68+
getUpstreamValue
69+
);
70+
71+
listrotator.init( $extender );
72+
listrotator.draw();
73+
listrotator.rotator.prev();
74+
75+
setTimeout( function() {
76+
sinon.assert.calledOnce( onValueChange );
77+
assert.equal( listrotator.getValue(), 'fixed value' );
78+
79+
QUnit.start();
80+
}, 200 );
81+
82+
} );
83+
2984
} )(
3085
jQuery,
3186
jQuery.valueview.ExpertExtender,

0 commit comments

Comments
 (0)