Henning Snater has uploaded a new change for review. https://gerrit.wikimedia.org/r/70810
Change subject: Refactoring of globeCoordinate.js ...................................................................... Refactoring of globeCoordinate.js Moved settings to GlobeCoordinate object as well as some GlobeCoordinate object specific functions. Put precisions into a constant, cleaned up GlobeCoordinate's method structure, removed currently unused precisionTextEarth() function. Change-Id: Ib35451626c094624603497a0f62943134802333c --- M DataValues/resources/globeCoordinate.js/src/globeCoordinate.GlobeCoordinate.js M DataValues/resources/globeCoordinate.js/src/globeCoordinate.js M DataValues/resources/globeCoordinate.js/tests/globeCoordinate.GlobeCoordinate.tests.js M DataValues/resources/globeCoordinate.js/tests/globeCoordinate.tests.js M ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js 5 files changed, 417 insertions(+), 507 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DataValues refs/changes/10/70810/1 diff --git a/DataValues/resources/globeCoordinate.js/src/globeCoordinate.GlobeCoordinate.js b/DataValues/resources/globeCoordinate.js/src/globeCoordinate.GlobeCoordinate.js index 38b6da4..b33710b 100644 --- a/DataValues/resources/globeCoordinate.js/src/globeCoordinate.GlobeCoordinate.js +++ b/DataValues/resources/globeCoordinate.js/src/globeCoordinate.GlobeCoordinate.js @@ -14,6 +14,26 @@ globeCoordinate.GlobeCoordinate = ( function( globeCoordinate ) { 'use strict'; + var defaultOptions = { + north: 'N', + east: 'E', + south: 'S', + west: 'W', + dot: '.', + latLongCombinator: ', ', + degree: '°', + minute: '\'', + second: '"', + precisionTexts: [ + { precision: 1, text: 'to a degree' }, + { precision: 1 / 60, text: 'to an arcminute' }, + { precision: 1 / 3600, text: 'to an arcsecond' }, + { precision: 1 / 36000, text: 'to 1/10 of an arcsecond' }, + { precision: 1 / 360000, text: 'to 1/100 of an arcsecond' }, + { precision: 1 / 3600000, text: 'to 1/1000 of an arcsecond' } + ] + }; + /** * Constructor for an object representing a globe coordinate with a certain precision. * @@ -21,16 +41,31 @@ * - {number} latitude * - {number} longitude * - {number} precision + * @param {Object} [options] * * @constructor */ - function GlobeCoordinate( gcDef ) { + function GlobeCoordinate( gcDef, options ) { + options = options || {}; + + this._options = defaultOptions; + + for( var key in options ) { + if( options.hasOwnProperty( key ) && this._options[key] ) { + this._options[key] = options[key]; + } + } + if( !gcDef || typeof gcDef !== 'object' || gcDef.latitude === undefined || gcDef.longitude === undefined || gcDef.precision === undefined ) { throw new Error( 'No proper globe coordinate definition given' ); + } + + if( !isValidPrecision( gcDef.precision ) ) { + throw new Error( 'No valid precision given' ); } this._latitude = gcDef.latitude; @@ -48,19 +83,6 @@ throw new Error( 'Longitude (' + this._longitude + ') is out of bounds' ); } - // Keep precision boundaries: - // TODO: get definition of precisions out of global settings and put them into - // a globeCoordinate.GlobeCoordinate.PRECISION constant. - var precisions = globeCoordinate.settings.precisions, - minPrecision = precisions[0].level, - maxPrecision = precisions[precisions.length - 1].level; - - if( this._precision > minPrecision ) { - this._precision = minPrecision; - } else if( this._precision < maxPrecision ) { - this._precision = maxPrecision; - } - this._globe = 'http://www.wikidata.org/entity/Q2'; // TODO: Support other globes } @@ -69,16 +91,16 @@ constructor: GlobeCoordinate, /** + * Options + * @type {Object} + */ + _options: null, + + /** * Globe URI * @type {string} */ _globe: null, - - /** - * Raw input - * @type {string} - */ - _rawInput: null, /** * Latitude (decimal) @@ -129,55 +151,16 @@ getPrecision: function() { return this._precision; }, /** - * Returns the precision text. - * - * @return {string} - */ - getPrecisionText: function() { return globeCoordinate.precisionText( this._precision ); }, - - /** - * Returns the precision text in a common unit. - * - * @return {string} - */ - getPrecisionTextEarth: function() { - return globeCoordinate.precisionTextEarth( this._precision ); - }, - - /** - * Returns the decimal latitude. + * Returns an object with decimal latitude, longitude and precision. * * @return {Object} */ - latitudeDecimal: function() { - return globeCoordinate.toDecimal( this._latitude, this._precision ); - }, - - /** - * Returns the decimal longitude. - * - * @return {Object} - */ - longitudeDecimal: function() { - return globeCoordinate.toDecimal( this._longitude, this._precision ); - }, - - /** - * Returns the latitude in degree. - * - * @return {Object} - */ - latitudeDegree: function() { - return globeCoordinate.toDegree( this._latitude, this._precision ); - }, - - /** - * Returns the longitude in degree. - * - * @return {Object} - */ - longitudeDegree: function() { - return globeCoordinate.toDegree( this._longitude, this._precision ); + getDecimal: function() { + return { + latitude: this._latitude, + longitude: this._longitude, + precision: this._precision + }; }, /** @@ -186,7 +169,10 @@ * @return {string} */ decimalText: function() { - return globeCoordinate.decimalText( this._latitude, this._longitude, this._precision ); + return '' + + globeCoordinate.toDecimal( this._latitude, this._precision ) + + this._options.latLongCombinator + + globeCoordinate.toDecimal( this._longitude, this._precision ); }, /** @@ -195,67 +181,45 @@ * @return {string} */ degreeText: function() { - return globeCoordinate.degreeText( this._latitude, this._longitude, this._precision ); + var text = function( number, sign ) { + if( number === undefined ) { + return ''; + } + return number + sign; + }; + + var latDeg = globeCoordinate.toDegree( this._latitude, this._precision ), + longDeg = globeCoordinate.toDegree( this._longitude, this._precision ); + + return '' + + text( Math.abs( latDeg.degree ), this._options.degree ) + + text( latDeg.minute, this._options.minute ) + + text( latDeg.second, this._options.second ) + + ( ( this._latitude < 0 ) ? this._options.south : this._options.north ) + + this._options.latLongCombinator + + text( Math.abs( longDeg.degree ), this._options.degree ) + + text( longDeg.minute, this._options.minute ) + + text( longDeg.second, this._options.second ) + + ( ( this._longitude < 0 ) ? this._options.west : this._options.east ); }, /** - * Returns the coordinate's ISO 6709 string representation. + * Returns the precision's string representation. + * + * @return {string} + */ + precisionText: function() { + return globeCoordinate.GlobeCoordinate.PRECISIONTEXT( this._precision, this._options ); + }, + + /** + * Returns a coordinate's ISO 6709 string representation. + * @see globeCoordinate.iso6709 * * @return {string} */ iso6709: function() { - var lat = this.latitudeDegree(), - lon = this.longitudeDegree(), - latISO, - lonISO; - - /** - * Strips a number's sign and fills the number's integer part with zeroes according to a - * given string length. - * - * @param {number} number - * @param {string} length - */ - function pad( number, length ) { - var absolute = Math.abs( number || 0 ), - string = String( absolute ), - exploded = string.split( '.' ); - - if( exploded[0].length === length ) { - return string; - } - - return '' - + new Array( length - exploded[0].length + 1 ).join( '0' ) - + exploded[0] - + ( ( exploded[1] ) ? '.' + exploded[1] : '' ); - } - - latISO = '' - + ( ( ( this.getLatitude() < 0 ) ? '-' : '+' ) + pad( lat.degree, 2 ) ) - + ( ( this.getPrecision() < 1 ) ? pad( lat.minute, 2 ) : '' ) - + ( ( this.getPrecision() < 1 / 60 ) ? pad( lat.second, 2 ) : '' ); - - lonISO = '' - + ( ( ( this.getLongitude() < 0 ) ? '-' : '+' ) + pad( lon.degree, 3 ) ) - + ( ( this.getPrecision() < 1 ) ? pad( lon.minute, 2 ) : '' ) - + ( ( this.getPrecision() < 1 / 60 ) ? pad( lon.second, 2 ) : '' ); - - // Synchronize precision (longitude degree needs to be 1 digit longer): - if( lonISO.indexOf( '.' ) !== -1 && latISO.indexOf( '.' ) === -1 ) { - latISO += '.'; - } - while( latISO.length < lonISO.length - 1 ) { - latISO += '0'; - } - if( latISO.indexOf( '.' ) !== -1 && lonISO.indexOf( '.' ) === -1 ) { - lonISO += '.'; - } - while( lonISO.length < latISO.length + 1 ) { - lonISO += '0'; - } - - return latISO + lonISO + '/'; + return globeCoordinate.iso6709( this.getDecimal() ); }, /** @@ -270,12 +234,85 @@ return false; } + var gc1Iso6709 = globeCoordinate.iso6709( this.getDecimal() ), + gc2Iso6709 = globeCoordinate.iso6709( otherGlobeCoordinate.getDecimal() ); + return this.getPrecision() === otherGlobeCoordinate.getPrecision() - && this.iso6709() === otherGlobeCoordinate.iso6709(); + && gc1Iso6709 === gc2Iso6709; } }; + /** + * Checks if a specific precision is defined in the predefined constant. + * + * @param {number} precision + * @return {boolean} + */ + function isValidPrecision( precision ) { + var precisions = globeCoordinate.GlobeCoordinate.PRECISIONS; + + for( var i in precisions ) { + if( Math.abs( precision - precisions[i] ) < 0.0000001 ) { + return true; + } + } + + return false; + } + + /** + * Precisions a globe coordinate may feature. + * @type {number[]} + */ + GlobeCoordinate.PRECISIONS = [ + 10, + 1, + 0.1, + 1 / 60, + 0.01, + 0.001, + 1 / 3600, + 0.0001, + 1 / 36000, + 0.00001, + 1 / 360000, + 0.000001, + 1 / 3600000 + ]; + + /** + * Returns a precision's string representation. + * + * @param {number} precision + * @param {Object} [options] + * @return {string} + */ + GlobeCoordinate.PRECISIONTEXT = function( precision, options ) { + var precisionText, + combinedOptions = {}; + + options = options || {}; + + for( var key in defaultOptions ) { + combinedOptions[key] = ( options[key] ) ? options[key] : defaultOptions[key]; + } + + // Figure out if the precision is very close to a precision that can be expressed with a + // string: + for( var i in combinedOptions.precisionTexts ) { + if( Math.abs( precision - combinedOptions.precisionTexts[i].precision ) < 0.0000001 ) { + precisionText = combinedOptions.precisionTexts[i].text; + } + } + + if( !precisionText ) { + precisionText = '±' + precision + combinedOptions.degree; + } + + return precisionText; + }; + return GlobeCoordinate; }( globeCoordinate ) ); diff --git a/DataValues/resources/globeCoordinate.js/src/globeCoordinate.js b/DataValues/resources/globeCoordinate.js/src/globeCoordinate.js index bcbd5e7..06516dc 100644 --- a/DataValues/resources/globeCoordinate.js/src/globeCoordinate.js +++ b/DataValues/resources/globeCoordinate.js/src/globeCoordinate.js @@ -17,129 +17,7 @@ return { /** - * Default settings/texts. - * @type {Object} - */ - settings: { - north: 'N', - east: 'E', - south: 'S', - west: 'W', - dot: '.', - latLongCombinator: ', ', - degree: '°', - minute: '\'', - second: '"', - precisions: [ - { level: 10 }, - { level: 1, text: 'to a degree' }, - { level: 0.1 }, - { level: 1 / 60, text: 'to an arcminute' }, - { level: 0.01 }, - { level: 0.001 }, - { level: 1 / 3600, text: 'to an arcsecond' }, - { level: 0.0001 }, - { level: 1 / 36000, text: 'to 1/10 of an arcsecond' }, - { level: 0.00001 }, - { level: 1 / 360000, text: 'to 1/100 of an arcsecond' }, - { level: 0.000001 }, - { level: 1 / 3600000, text: 'to 1/1000 of an arcsecond' } - ] - }, - - /** - * Returns the index of a precision within the settings array containing the precisions or - * -1 if the precision could not be found. - * - * @param {number} precision - * @return {number} - */ - getPrecisionIndex: function( precision ) { - for( var i in this.settings.precisions ) { - if( - this.settings.precisions.hasOwnProperty( i ) - && Math.abs( precision - this.settings.precisions[i].level ) < 0.0000001 - ) { - return parseInt( i, 10 ); - } - } - return -1; - }, - - /** - * Returns a precision's string representation. - * - * @param {number} precision - * @return {string} - */ - precisionText: function( precision ) { - var precisionText; - - // Figure out if the precision is very close to a precision that can be expressed with a - // string: - for( var i in this.settings.precisions ) { - if( - this.settings.precisions.hasOwnProperty( i ) - && Math.abs( precision - this.settings.precisions[i].level ) < 0.0000001 - && this.settings.precisions[i].text - ) { - precisionText = this.settings.precisions[i].text; - } - } - - if( !precisionText ) { - precisionText = '±' + precision + this.settings.degree; - } - - return precisionText; - }, - - /** - * Returns a given precision as string with units commonly used on earth. - * - * @param {number} precision - * @return {string} - */ - precisionTextEarth: function( precision ) { - var km = 40000 / 360 * precision; - - if( km > 100 ) { - return Math.round( km / 100 ) * 100 + ' km'; - } else if( km > 10 ) { - return Math.round( km / 10 ) * 10 + ' km'; - } else if( km > 1 ) { - return Math.round( km ) + ' km'; - } - - var m = km * 1000; - - if( m > 100 ) { - return Math.round( m / 100 ) * 100 + ' m'; - } else if( m > 10 ) { - return Math.round( m / 10 ) * 10 + ' m'; - } else if( m > 1 ) { - return Math.round( m ) + ' m'; - } - - var cm = m * 100; - - if( cm > 10 ) { - return Math.round( cm / 10 ) * 10 + ' cm'; - } else if( cm > 1 ) { - return Math.round( cm ) + ' cm'; - } - - var mm = cm * 10; - - if( mm > 1 ) { - return Math.round( mm ) + ' mm'; - } - - return '1 mm'; - }, - - /** - * Applies a precision to a decimal value. + * Return a given decimal value applying a precision. * * @param {number} value * @param {number} precision @@ -153,26 +31,17 @@ }, /** - * Returns a given coordinate as a string according to the decimal system. - * - * @param {number} latitude - * @param {number} longitude - * @param {number} precision - * @return {string} - */ - decimalText: function( latitude, longitude, precision ) { - return '' - + this.toDecimal( latitude, precision ) - + this.settings.latLongCombinator - + this.toDecimal( longitude, precision ); - }, - - /** - * Returns a given value converted to degree. + * Returns a given decimal value converted to degree taking a precision into account. * * @param {number} value * @param {number} precision - * @return {Object} + * @return {Object} Returned object has the following structure: + * { + * degree: {number}, + * minute: {number|undefined}, + * second: {number|undefined} + * } + * "minute" and/or "second" are undefined if not covered by the precision. */ toDegree: function( value, precision ) { var result = {}; @@ -203,11 +72,23 @@ } } + // TODO: precision might be a floating point number and might cause minutes/seconds + // to be "generated". if( precision > 1 ) { - var index = this.getPrecisionIndex( precision ); - if( index !== -1 ) { - var level = this.settings.precisions[index].level; - result.degree = Math.round( result.degree / level ) * level; + result.degree = Math.round( result.degree / precision ) * precision; + + // JavaScript may cause some disturbance regarding rounding and precision. The + // result should not have a higher floating point number precision than the + // applied precision. + var degreeFloat = ( '' + result.degree ).split( '.' ), + precisionFloat = ( '' + precision ).split( '.' ); + + if( + degreeFloat[1] && precisionFloat[1] + && degreeFloat[1].length > precisionFloat[1].length + ) { + var trimmedPrecision = degreeFloat[1].substr( 0, precisionFloat[1].length ); + result.degree = parseFloat( degreeFloat[0] + '.' + trimmedPrecision ); } } @@ -215,34 +96,73 @@ }, /** - * Returns a given coordinate as a string using degree. + * Returns a coordinate's ISO 6709 string representation. * - * @param {number} latitude - * @param {number} longitude - * @param {number} precision + * @param {Object} decimalCoordinateDefinition + * Object with the following structure: + * { + * latitude: {number}, + * longitude: {number}, + * precision: {number} + * } * @return {string} */ - degreeText: function( latitude, longitude, precision ) { - var text = function( number, sign ) { - if( number === undefined ) { - return ''; + iso6709: function( decimalCoordinateDefinition ) { + var latitude = decimalCoordinateDefinition.latitude, + longitude = decimalCoordinateDefinition.longitude, + precision = decimalCoordinateDefinition.precision, + lat = globeCoordinate.toDegree( latitude, precision ), + lon = globeCoordinate.toDegree( longitude, precision ), + latISO, + lonISO; + + /** + * Strips a number's sign and fills the number's integer part with zeroes according to a + * given string length. + * + * @param {number} number + * @param {string} length + */ + function pad( number, length ) { + var absolute = Math.abs( number || 0 ), + string = String( absolute ), + exploded = string.split( '.' ); + + if( exploded[0].length === length ) { + return string; } - return number + sign; - }; - var latDeg = this.toDegree( latitude, precision ), - longDeg = this.toDegree( longitude, precision ); + return '' + + new Array( length - exploded[0].length + 1 ).join( '0' ) + + exploded[0] + + ( ( exploded[1] ) ? '.' + exploded[1] : '' ); + } - return '' - + text( Math.abs( latDeg.degree ), this.settings.degree ) - + text( latDeg.minute, this.settings.minute ) - + text( latDeg.second, this.settings.second ) - + ( ( latitude < 0 ) ? this.settings.south : this.settings.north ) - + this.settings.latLongCombinator - + text( Math.abs( longDeg.degree ), this.settings.degree ) - + text( longDeg.minute, this.settings.minute ) - + text( longDeg.second, this.settings.second ) - + ( ( longitude < 0 ) ? this.settings.west : this.settings.east ); + latISO = '' + + ( ( ( latitude < 0 ) ? '-' : '+' ) + pad( lat.degree, 2 ) ) + + ( ( precision < 1 ) ? pad( lat.minute, 2 ) : '' ) + + ( ( precision < 1 / 60 ) ? pad( lat.second, 2 ) : '' ); + + lonISO = '' + + ( ( ( longitude < 0 ) ? '-' : '+' ) + pad( lon.degree, 3 ) ) + + ( ( precision < 1 ) ? pad( lon.minute, 2 ) : '' ) + + ( ( precision < 1 / 60 ) ? pad( lon.second, 2 ) : '' ); + + // Synchronize precision (longitude degree needs to be 1 digit longer): + if( lonISO.indexOf( '.' ) !== -1 && latISO.indexOf( '.' ) === -1 ) { + latISO += '.'; + } + while( latISO.length < lonISO.length - 1 ) { + latISO += '0'; + } + if( latISO.indexOf( '.' ) !== -1 && lonISO.indexOf( '.' ) === -1 ) { + lonISO += '.'; + } + while( lonISO.length < latISO.length + 1 ) { + lonISO += '0'; + } + + return latISO + lonISO + '/'; } }; diff --git a/DataValues/resources/globeCoordinate.js/tests/globeCoordinate.GlobeCoordinate.tests.js b/DataValues/resources/globeCoordinate.js/tests/globeCoordinate.GlobeCoordinate.tests.js index 1fdef91..3ab889d 100644 --- a/DataValues/resources/globeCoordinate.js/tests/globeCoordinate.GlobeCoordinate.tests.js +++ b/DataValues/resources/globeCoordinate.js/tests/globeCoordinate.GlobeCoordinate.tests.js @@ -9,23 +9,6 @@ ( function( QUnit, $, globeCoordinate ) { 'use strict'; - /** - * ISO 6709 representations keyed by the input string used to generate a GlobeCoordinate object. - * @type {Object} - */ - var iso6709representations = { - '+00+000/': { latitude: 0, longitude: 0, precision: 1 }, - '-03+002/': { latitude: -3, longitude: 2, precision: 1 }, - '+0106+00200/': { latitude: 1.1, longitude: 2, precision: 0.1 }, - '+900000+0300600/': { latitude: 90, longitude: 30.1, precision: 0.01 }, - '+000600+0000027/': { latitude: 0.1, longitude: 0.0075, precision: 1 / 3600 }, - '-0006+00000/': { latitude: -0.1, longitude: 0, precision: 1 / 60 }, - '+010001+0000000/': { latitude: 1.00028, longitude: 0, precision: 1 / 3600 }, - '+010001.8+0000000.0/': { latitude: 1.0005, longitude: 0, precision: 1 / 36000 }, - '+895400.000-0000001.116/': { latitude: 89.9, longitude: -0.00031, precision: 1 / 3600000 }, - '+050000.0-0000010.5/': { latitude: 5, longitude: -0.00292, precision: 1 / 36000 } - }; - QUnit.module( 'globeCoordinate.GlobeCoordinate.js' ); QUnit.test( 'Basic checks', function( assert ) { @@ -73,40 +56,10 @@ 'Verified getPrecision()' ); - assert.equal( - typeof c.getPrecisionText(), - 'string', - 'Verified getPrecisionText()' - ); - - assert.equal( - typeof c.getPrecisionTextEarth(), - 'string', - 'Verified getPrecisionTextEarth()' - ); - - assert.equal( - c.latitudeDecimal(), - 1.5, - 'Verified latitudeDecimal()' - ); - - assert.equal( - c.longitudeDecimal(), - 1.5, - 'Verified longitudeDecimal()' - ); - assert.deepEqual( - c.latitudeDegree(), - { degree: 1, minute: 30, second: undefined }, - 'Verified latitudeDegree()' - ); - - assert.deepEqual( - c.longitudeDegree(), - { degree: 1, minute: 30, second: undefined }, - 'Verified longitudeDegree()' + c.getDecimal(), + { latitude: 1.5, longitude: 1.5, precision: 0.1 }, + 'Verified getDecimal()' ); assert.equal( @@ -121,34 +74,126 @@ 'Verified degreeText()' ); + assert.equal( + typeof c.precisionText(), + 'string', + 'Verified precisionText()' + ); + + assert.equal( + typeof c.iso6709(), + 'string', + 'Verified iso6709()' + ); + } ); - QUnit.test( 'iso6709()', function( assert ) { - var c; + QUnit.test( 'precisionText()', function( assert ) { + var c, + precisions = { + 1: 1, + 0.016666666666666666: 1 / 60, + 2.7777777777777776e-7: 1 / 3600000, + 10: '±10°' + }; - $.each( iso6709representations, function( iso6709string, gcDef ) { - c = new globeCoordinate.GlobeCoordinate( gcDef ); - - assert.equal( - c.iso6709(), - iso6709string, - 'Validated ISO 6709 string for \'' + c.decimalText() + '\': \'' + iso6709string + '\'.' + $.each( precisions, function( testPrecision, expected ) { + c = new globeCoordinate.GlobeCoordinate( + { latitude: 1, longitude: 1, precision: testPrecision } ); + + var precisionText = globeCoordinate.GlobeCoordinate.PRECISIONTEXT( testPrecision ); + + // Look up precision text: + if( typeof expected === 'number' ) { + + $.each( globeCoordinate.GlobeCoordinate.PRECISIONS, function( i, precision ) { + if( '' + precision === testPrecision ) { + + assert.strictEqual( + precisionText, + c.precisionText(), + 'Precision text for \'' + precision + '\' results in text \'' + + precisionText + '\'.' + ); + + return false; + } + } ); + + } else { + + assert.strictEqual( + precisionText, + expected, + 'Precision text for \'' + testPrecision + '\' results in text \'' + expected + '\'.' + ); + + } } ); } ); - QUnit.test( 'equals()', function( assert ) { - var c1, c2; + QUnit.test( 'Text output', function( assert ) { + var GC= globeCoordinate.GlobeCoordinate, + decimalTexts = { + '1, 1': new GC( { latitude: 1, longitude: 1, precision: 1 } ), + '-10, -1.5': new GC( { latitude: -10, longitude: -1.5, precision: 0.1 } ), + '20, 0': new GC( { latitude: 24, longitude: -1.5, precision: 10 } ) + }, + degreeTexts= { + '1°N, 1°E': new GC( { latitude: 1, longitude: 1, precision: 1 } ), + '10°0\'S, 2°30\'W': new GC( { latitude: -10, longitude: -2.5, precision: 0.1 } ), + '20°N, 0°W': new GC( { latitude: 24, longitude: -1.5, precision: 10 } ) + }; - $.each( iso6709representations, function( iso6709string1, gcDef1 ) { + // Just some output sanity checking: + + $.each( decimalTexts, function( expected, gc ) { + assert.equal( + gc.decimalText(), + expected, + 'Verified decimalText() output: ' + expected + ); + } ); + + $.each( degreeTexts, function( expected, gc ) { + assert.equal( + gc.degreeText(), + expected, + 'Verified degreeText() output: ' + expected + ); + } ); + + } ); + + QUnit.test( 'equals()', function( assert ) { + var gcDefs = [ + { latitude: 0, longitude: 0, precision: 1 }, + { latitude: -3, longitude: 2, precision: 1 }, + { latitude: 1.1, longitude: 2, precision: 0.1 }, + { latitude: 90, longitude: 30.1, precision: 0.01 }, + { latitude: 0.1, longitude: 0.0075, precision: 1 / 3600 }, + { latitude: -0.1, longitude: 0, precision: 1 / 60 }, + { latitude: 1.00028, longitude: 0, precision: 1 / 3600 }, + { latitude: 1.0005, longitude: 0, precision: 1 / 36000 }, + { latitude: 89.9, longitude: -0.00031, precision: 1 / 3600000 }, + { latitude: 5, longitude: -0.00292, precision: 1 / 36000 } + ], + c1, c2; + + $.each( gcDefs, function( i1, gcDef1 ) { c1 = new globeCoordinate.GlobeCoordinate( gcDef1 ); - $.each( iso6709representations, function( iso6709string2, gcDef ) { - c2 = new globeCoordinate.GlobeCoordinate( gcDef ); + $.each( gcDefs, function( i2, gcDef2 ) { + c2 = new globeCoordinate.GlobeCoordinate( gcDef2 ); - if( iso6709string1 === iso6709string2 ) { + if( + gcDef1.latitude === gcDef2.latitude + && gcDef1.longitude === gcDef2.longitude + && gcDef1.precision === gcDef2.precision + ) { assert.ok( c1.equals( c2 ), @@ -159,7 +204,8 @@ assert.ok( !c1.equals( c2 ), - 'Validated inequality of \'' + c1.decimalText() + '\' and \'' + c2.decimalText() + '\'.' + 'Validated inequality of \'' + c1.decimalText() + + '\' and \'' + c2.decimalText() + '\'.' ); } diff --git a/DataValues/resources/globeCoordinate.js/tests/globeCoordinate.tests.js b/DataValues/resources/globeCoordinate.js/tests/globeCoordinate.tests.js index e541d43..00ab0b5 100644 --- a/DataValues/resources/globeCoordinate.js/tests/globeCoordinate.tests.js +++ b/DataValues/resources/globeCoordinate.js/tests/globeCoordinate.tests.js @@ -9,12 +9,19 @@ ( function( QUnit, $, globeCoordinate ) { 'use strict'; + /** + * Values that are used in combination with the "precisions" object. + * @type {number[]} + */ var values = [0, 0.06, 0.4, 0.5, 1, 10, 17]; + /** + * Keyed by the precision to apply, this object contains the results for the values specified in + * the "values" array. + * @type {Object} + */ var precisions = { 0: { - tech: '±0°', - earth: '1 mm', toDecimal: [0, 0.06, 0.4, 0.5, 1, 10, 17], toDegree: [ { degree: 0, minute: 0, second: 0 }, @@ -27,8 +34,6 @@ ] }, 1: { - tech: 1, - earth: '100 km', toDecimal: [0, 0, 0, 1, 1, 10, 17], toDegree: [ { degree: 0, minute: undefined, second: undefined }, @@ -41,36 +46,30 @@ ] }, 2: { - tech: '±2°', - earth: '200 km', toDecimal: [0, 0, 0, 1, 1, 10, 17], toDegree: [ { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, - { degree: 1, minute: undefined, second: undefined }, + { degree: 2, minute: undefined, second: undefined }, { degree: 10, minute: undefined, second: undefined }, - { degree: 17, minute: undefined, second: undefined } + { degree: 18, minute: undefined, second: undefined } ] }, 1.00000001: { - tech: 1, - earth: '100 km', toDecimal: [0, 0, 0, 1, 1, 10, 17], toDegree: [ { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, - { degree: 1, minute: undefined, second: undefined }, - { degree: 10, minute: undefined, second: undefined }, - { degree: 17, minute: undefined, second: undefined } + { degree: 1.00000001, minute: undefined, second: undefined }, + { degree: 10.0000001, minute: undefined, second: undefined }, + { degree: 17.00000017, minute: undefined, second: undefined } ] }, 0.016666666666666666: { - tech: 1 / 60, - earth: '2 km', toDecimal: [0, 0.06, 0.4, 0.5, 1, 10, 17], toDegree: [ { degree: 0, minute: 0, second: undefined }, @@ -83,8 +82,6 @@ ] }, 2.7777777777777776e-7: { - tech: 1 / 3600000, - earth: '3 cm', toDecimal: [0, 0.06, 0.4, 0.5, 1, 10, 17], toDegree: [ { degree: 0, minute: 0, second: 0 }, @@ -97,8 +94,6 @@ ] }, 1.0000000001e-10: { - tech: '±1.0000000001e-10°', - earth: '1 mm', toDecimal: [0, 0.06, 0.4, 0.5, 1, 10, 17], toDegree: [ { degree: 0, minute: 0, second: 0 }, @@ -111,36 +106,30 @@ ] }, 1.0000001: { - tech: '±1.0000001°', - earth: '100 km', toDecimal: [0, 0, 0, 1, 1, 10, 17], toDegree: [ { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, - { degree: 1, minute: undefined, second: undefined }, - { degree: 10, minute: undefined, second: undefined }, - { degree: 17, minute: undefined, second: undefined } + { degree: 1.0000001, minute: undefined, second: undefined }, + { degree: 10.000001, minute: undefined, second: undefined }, + { degree: 17.0000017, minute: undefined, second: undefined } ] }, 1.1: { - tech: '±1.1°', - earth: '100 km', toDecimal: [0, 0, 0, 1, 1, 10, 17], toDegree: [ { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, { degree: 0, minute: undefined, second: undefined }, - { degree: 1, minute: undefined, second: undefined }, - { degree: 10, minute: undefined, second: undefined }, - { degree: 17, minute: undefined, second: undefined } + { degree: 1.1, minute: undefined, second: undefined }, + { degree: 9.9, minute: undefined, second: undefined }, + { degree: 16.5, minute: undefined, second: undefined } ] }, 10: { - tech: '±10°', - earth: '1100 km', toDecimal: [0, 0, 0, 0, 0, 10, 20], toDegree: [ { degree: 0, minute: undefined, second: undefined }, @@ -154,57 +143,24 @@ } }; + /** + * ISO 6709 representations keyed by the input string used to generate a GlobeCoordinate object. + * @type {Object} + */ + var iso6709representations = { + '+00+000/': { latitude: 0, longitude: 0, precision: 1 }, + '-03+002/': { latitude: -3, longitude: 2, precision: 1 }, + '+0106+00200/': { latitude: 1.1, longitude: 2, precision: 0.1 }, + '+900000+0300600/': { latitude: 90, longitude: 30.1, precision: 0.01 }, + '+000600+0000027/': { latitude: 0.1, longitude: 0.0075, precision: 1 / 3600 }, + '-0006+00000/': { latitude: -0.1, longitude: 0, precision: 1 / 60 }, + '+010001+0000000/': { latitude: 1.00028, longitude: 0, precision: 1 / 3600 }, + '+010001.8+0000000.0/': { latitude: 1.0005, longitude: 0, precision: 1 / 36000 }, + '+895400.000-0000001.116/': { latitude: 89.9, longitude: -0.00031, precision: 1 / 3600000 }, + '+050000.0-0000010.5/': { latitude: 5, longitude: -0.00292, precision: 1 / 36000 } + }; + QUnit.module( 'globeCoordinate.js' ); - - QUnit.test( 'precisionText()', function( assert ) { - - $.each( precisions, function( precision, expected ) { - var precisionText = globeCoordinate.precisionText( precision ); - - // Look up precision text: - if( typeof expected.tech === 'number' ) { - - $.each( globeCoordinate.settings.precisions, function( i, precisionDefinition ) { - if( precisionDefinition.level === expected.tech ) { - - assert.strictEqual( - precisionText, - precisionDefinition.text, - 'Precision text for \'' + precision + '\' results in text \'' - + precisionDefinition.text + '\'.' - ); - - return false; - } - } ); - - } else { - - assert.strictEqual( - precisionText, - expected.tech, - 'Precision text for \'' + precision + '\' results in text \'' + expected.tech + '\'.' - ); - - } - - } ); - - } ); - - QUnit.test( 'precisionTextEarth()', function( assert ) { - - $.each( precisions, function( precision, expected ) { - - assert.strictEqual( - globeCoordinate.precisionTextEarth( precision ), - expected.earth, - 'Precision text for \'' + precision + '\' results in text \'' + expected.earth + '\'.' - ); - - } ); - - } ); QUnit.test( 'Applying precision', function( assert ) { @@ -242,61 +198,15 @@ } ); - QUnit.test( 'Text output', function( assert ) { + QUnit.test( 'iso6709()', function( assert ) { - // Just some output sanity checking: - - // decimalText(): - - assert.equal( - globeCoordinate.decimalText( 0, 0, 0 ), - '0, 0', - 'Verified output: 0, 0' - ); - - assert.equal( - globeCoordinate.decimalText( 1, 1, 1 ), - '1, 1', - 'Verified output: 1, 1' - ); - - assert.equal( - globeCoordinate.decimalText( -10, -1.5, 0.1 ), - '-10, -1.5', - 'Verified output: -10, -1.5' - ); - - assert.equal( - globeCoordinate.decimalText( 24, -1.5, 10 ), - '20, 0', - 'Verified output: 20, 0' - ); - - // degreeText(): - - assert.equal( - globeCoordinate.degreeText( 0, 0, 0 ), - '0°0\'0"N, 0°0\'0"E', - 'Verified output: 0°0\'0"N, 0°0\'0"E' - ); - - assert.equal( - globeCoordinate.degreeText( 1, 1, 1 ), - '1°N, 1°E', - 'Verified output: 1°N, 1°E' - ); - - assert.equal( - globeCoordinate.degreeText( -10, -2.5, 0.1 ), - '10°0\'S, 2°30\'W', - 'Verified output: 10°0\'S, 2°30\'W' - ); - - assert.equal( - globeCoordinate.degreeText( 24, -1.5, 10 ), - '20°N, 0°W', - 'Verified output: 20°N, 0°W' - ); + $.each( iso6709representations, function( iso6709string, gcDef ) { + assert.equal( + globeCoordinate.iso6709( gcDef ), + iso6709string, + 'Generated ISO 6709 string: \'' + iso6709string + '\'.' + ); + } ); } ); diff --git a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js index 4bca991..43bd1ca 100644 --- a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js +++ b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js @@ -6,11 +6,8 @@ * @author H. Snater < mediaw...@snater.com > * @author Daniel Werner < daniel.wer...@wikimedia.de > */ -( function( dv, vp, $, vv, globeCoordinate ) { +( function( dv, vp, $, vv, GlobeCoordinate ) { 'use strict'; - - var GlobeCoordinate = globeCoordinate.GlobeCoordinate, - globeCoordinateSettings = globeCoordinate.settings; var PARENT = vv.Expert; @@ -82,10 +79,10 @@ .addClass( this.uiBaseClass + '-precisioncontainer' ) .append( $( '<div/>' ).text( this._messageProvider.getMessage( precisionMsgKey ) ) ); - $.each( globeCoordinateSettings.precisions, function( i, precisionDefinition ) { - var label = globeCoordinate.precisionText( precisionDefinition.level ); + $.each( GlobeCoordinate.PRECISIONS, function( i, precision ) { + var label = GlobeCoordinate.PRECISIONTEXT( precision ); precisionValues.push( { - value: roundPrecision( precisionDefinition.level ), + value: roundPrecision( precision ), label: label } ); } ); @@ -297,9 +294,9 @@ /** * 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. + * TODO: Calculated numbers used for the precision (e.g. 1/60) may result in different values + * in front- and back-end. Either use dedicated float numbers in front- and back-end or + * integrate the rounding in GlobeCoordinate. * * @since 0.1 * @@ -307,8 +304,8 @@ * @return {number} */ function roundPrecision( precision ) { - var precisions = globeCoordinateSettings.precisions, - highestPrecision = precisions[precisions.length - 1].level, + var precisions = GlobeCoordinate.PRECISIONS, + highestPrecision = precisions[precisions.length - 1], multiplier = 1; // To make sure that not too much digits are cut off for the "constant" precisions to be @@ -331,17 +328,17 @@ */ function getPrecisionSetting( roundedPrecision ) { var rounded, - precision = null; + actualPrecision = null; - $.each( globeCoordinateSettings.precisions, function( i, precisionDefinition ) { - rounded = roundPrecision( precisionDefinition.level ); + $.each( GlobeCoordinate.PRECISIONS, function( i, precision ) { + rounded = roundPrecision( precision ); if( rounded === roundedPrecision ) { - precision = precisionDefinition.level; + actualPrecision = precision; return false; } } ); - return precision; + return actualPrecision; } -}( dataValues, valueParsers, jQuery, jQuery.valueview, globeCoordinate ) ); +}( dataValues, valueParsers, jQuery, jQuery.valueview, globeCoordinate.GlobeCoordinate ) ); -- To view, visit https://gerrit.wikimedia.org/r/70810 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ib35451626c094624603497a0f62943134802333c Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/DataValues Gerrit-Branch: master Gerrit-Owner: Henning Snater <henning.sna...@wikimedia.de> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits