From cb71e90384fe134fe1f13a84ac50785e239fc3bc Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 13 Jul 2016 09:15:47 -0400 Subject: [PATCH] Module for iD.Detect() (#3243) * convert iD.Detect() iife to a module * iD.Detect() should return loaded locale (except for 'en') (The previous code was a hack to replace the detected locale with the loaded locale. Now that Detect is a module, we can not replace the detected locale from external code, but we can have Detect() return the locale we really want) --- .eslintignore | 2 - Makefile | 2 - dist/index.html | 2 +- index.html | 5 +- js/id/end.js | 1 - js/id/id.js | 93 ++-------------------------------- js/id/start.js | 1 - modules/core/connection.js | 3 +- modules/index.js | 3 ++ modules/services/mapillary.js | 3 +- modules/svg/gpx.js | 3 +- modules/svg/lines.js | 3 +- modules/ui/background.js | 3 +- modules/ui/cmd.js | 8 ++- modules/ui/fields/check.js | 3 +- modules/ui/fields/combo.js | 5 +- modules/ui/fields/localized.js | 4 +- modules/ui/fields/maxspeed.js | 1 + modules/ui/fields/wikipedia.js | 3 +- modules/ui/info.js | 3 +- modules/ui/init.js | 3 +- modules/ui/scale.js | 4 +- modules/ui/tag_reference.js | 4 +- modules/util/detect.js | 89 ++++++++++++++++++++++++++++++++ modules/util/util.js | 5 +- test/spec/ui/cmd.js | 22 ++++---- 26 files changed, 151 insertions(+), 127 deletions(-) delete mode 100644 .eslintignore delete mode 100644 js/id/end.js delete mode 100644 js/id/start.js create mode 100644 modules/util/detect.js diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index cd9ae3522..000000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -js/id/start.js -js/id/end.js diff --git a/Makefile b/Makefile index 7b9199fbc..95e83cb49 100644 --- a/Makefile +++ b/Makefile @@ -62,10 +62,8 @@ dist/iD.js: \ js/lib/d3.curtain.js \ js/lib/d3.value.js \ js/lib/lodash.js \ - js/id/start.js \ js/id/id.js \ $(MODULE_TARGETS) \ - js/id/end.js \ js/lib/locale.js \ data/introGraph.js diff --git a/dist/index.html b/dist/index.html index 620494c13..d3fb15a1f 100644 --- a/dist/index.html +++ b/dist/index.html @@ -35,7 +35,7 @@ a.src=document.location.protocol+'//dnn506yrbagrg.cloudfront.net/pages/scripts/0013/6714.js?'+Math.floor(new Date().getTime()/3600000); a.async=true;a.type='text/javascript';b.parentNode.insertBefore(a,b)}, 1); - if (typeof iD == 'undefined' || !iD.detect().support) { + if (typeof iD == 'undefined' || !iD.Detect().support) { document.getElementById('id-container').innerHTML = 'Sorry, your browser is not currently supported. Please use Potlatch 2 to edit the map.'; document.getElementById('id-container').className = 'unsupported'; } else { diff --git a/index.html b/index.html index d60e8ea26..959f46be4 100644 --- a/index.html +++ b/index.html @@ -27,13 +27,10 @@ - - - - + diff --git a/js/id/end.js b/js/id/end.js deleted file mode 100644 index 0319a0fe5..000000000 --- a/js/id/end.js +++ /dev/null @@ -1 +0,0 @@ -})(); diff --git a/js/id/id.js b/js/id/id.js index 63f643f71..098fb3e79 100644 --- a/js/id/id.js +++ b/js/id/id.js @@ -1,3 +1,5 @@ +(function () { + /*global iD*/ window.iD = function () { window.locale.en = iD.data.en; @@ -305,14 +307,9 @@ window.iD = function () { var locale, localePath; context.locale = function(loc, path) { + if (!arguments.length) return locale; locale = loc; localePath = path; - - // Also set iD.detect().locale (unless we detected 'en-us' and openstreetmap wants 'en').. - if (!(loc.toLowerCase() === 'en' && iD.detect().locale.toLowerCase() === 'en-us')) { - iD.detect().locale = loc; - } - return context; }; @@ -334,7 +331,7 @@ window.iD = function () { context.projection = iD.geo.RawMercator(); - locale = iD.detect().locale; + locale = iD.Detect().locale; if (locale && iD.data.locales.indexOf(locale) === -1) { locale = locale.split('-')[0]; } @@ -385,88 +382,6 @@ window.iD = function () { return d3.rebind(context, dispatch, 'on'); }; - iD.version = '1.9.6'; -(function() { - var detected = {}; - - var ua = navigator.userAgent, - m = null; - - m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge - if (m !== null) { - detected.browser = m[1]; - detected.version = m[2]; - } - if (!detected.browser) { - m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11 - if (m !== null) { - detected.browser = 'msie'; - detected.version = m[1]; - } - } - if (!detected.browser) { - m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+ - if (m !== null) { - detected.browser = 'Opera'; - detected.version = m[2]; - } - } - if (!detected.browser) { - m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i); - if (m !== null) { - detected.browser = m[1]; - detected.version = m[2]; - m = ua.match(/version\/([\.\d]+)/i); - if (m !== null) detected.version = m[1]; - } - } - if (!detected.browser) { - detected.browser = navigator.appName; - detected.version = navigator.appVersion; - } - - // keep major.minor version only.. - detected.version = detected.version.split(/\W/).slice(0,2).join('.'); - - if (detected.browser.toLowerCase() === 'msie') { - detected.ie = true; - detected.browser = 'Internet Explorer'; - detected.support = parseFloat(detected.version) >= 11; - } else { - detected.ie = false; - detected.support = true; - } - - // Added due to incomplete svg style support. See #715 - detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 ); - - detected.locale = (navigator.languages && navigator.languages.length) - ? navigator.languages[0] : (navigator.language || navigator.userLanguage || 'en-US'); - - detected.filedrop = (window.FileReader && 'ondrop' in window); - - function nav(x) { - return navigator.userAgent.indexOf(x) !== -1; - } - - if (nav('Win')) { - detected.os = 'win'; - detected.platform = 'Windows'; - } - else if (nav('Mac')) { - detected.os = 'mac'; - detected.platform = 'Macintosh'; - } - else if (nav('X11') || nav('Linux')) { - detected.os = 'linux'; - detected.platform = 'Linux'; - } - else { - detected.os = 'win'; - detected.platform = 'Unknown'; - } - - iD.detect = function() { return detected; }; })(); diff --git a/js/id/start.js b/js/id/start.js deleted file mode 100644 index 5d11b9790..000000000 --- a/js/id/start.js +++ /dev/null @@ -1 +0,0 @@ -(function () { diff --git a/modules/core/connection.js b/modules/core/connection.js index 66ac6ee3c..ee06e0a69 100644 --- a/modules/core/connection.js +++ b/modules/core/connection.js @@ -1,3 +1,4 @@ +import { Detect } from '../util/detect'; import { Entity } from './entity'; import { Extent } from '../geo/index'; import { JXON } from '../util/jxon'; @@ -258,7 +259,7 @@ export function Connection(useHttps) { }; connection.changesetTags = function(comment, imageryUsed) { - var detected = iD.detect(), + var detected = Detect(), tags = { created_by: 'iD ' + iD.version, imagery_used: imageryUsed.join(';').substr(0, 255), diff --git a/modules/index.js b/modules/index.js index 033619a45..82f2e4571 100644 --- a/modules/index.js +++ b/modules/index.js @@ -10,6 +10,9 @@ import * as ui from './ui/index'; import * as util from './util/index'; import * as validations from './validations/index'; +// detect +export { Detect } from './util/detect'; + // core export { Connection } from './core/connection'; export { Difference } from './core/difference'; diff --git a/modules/services/mapillary.js b/modules/services/mapillary.js index 521e3e24f..1bce9abce 100644 --- a/modules/services/mapillary.js +++ b/modules/services/mapillary.js @@ -1,3 +1,4 @@ +import { Detect } from '../util/detect'; import { Extent } from '../geo/index'; import { Icon } from '../svg/index'; import { qsString } from '../util/index'; @@ -279,7 +280,7 @@ export function init() { }; mapillary.signsSupported = function() { - var detected = iD.detect(); + var detected = Detect(); return (!(detected.ie || detected.browser.toLowerCase() === 'safari')); }; diff --git a/modules/svg/gpx.js b/modules/svg/gpx.js index d425ee9b1..51749682d 100644 --- a/modules/svg/gpx.js +++ b/modules/svg/gpx.js @@ -1,4 +1,5 @@ import { Extent, polygonIntersectsPolygon } from '../geo/index'; +import { Detect } from '../util/detect'; import toGeoJSON from 'togeojson'; export function Gpx(projection, context, dispatch) { @@ -22,7 +23,7 @@ export function Gpx(projection, context, dispatch) { .on('drop.localgpx', function() { d3.event.stopPropagation(); d3.event.preventDefault(); - if (!iD.detect().filedrop) return; + if (!Detect().filedrop) return; drawGpx.files(d3.event.dataTransfer.files); }) .on('dragenter.localgpx', over) diff --git a/modules/svg/lines.js b/modules/svg/lines.js index 2909dacbd..623f00394 100644 --- a/modules/svg/lines.js +++ b/modules/svg/lines.js @@ -1,4 +1,5 @@ import { OneWaySegments, Path, RelationMemberTags, TagClasses } from './index'; +import { Detect } from '../util/detect'; import { Entity } from '../core/index'; import { simpleMultipolygonOuterMember } from '../geo/index'; @@ -121,7 +122,7 @@ export function Lines(projection) { oneways .attr('d', function(d) { return d.d; }); - if (iD.detect().ie) { + if (Detect().ie) { oneways.each(function() { this.parentNode.insertBefore(this, this); }); } diff --git a/modules/ui/background.js b/modules/ui/background.js index 1472521d4..7bb2cb90e 100644 --- a/modules/ui/background.js +++ b/modules/ui/background.js @@ -1,5 +1,6 @@ import { metersToOffset, offsetToMeters } from '../geo/index'; import { BackgroundSource } from '../renderer/index'; +import { Detect } from '../util/detect'; import { Icon } from '../svg/index'; import { MapInMap } from './map_in_map'; import { cmd } from './cmd'; @@ -37,7 +38,7 @@ export function Background(context) { .style('opacity', d) .attr('data-opacity', d); - if (!iD.detect().opera) { + if (!Detect().opera) { setTransform(bg, 0, 0); } diff --git a/modules/ui/cmd.js b/modules/ui/cmd.js index 2a2761f8f..21e717633 100644 --- a/modules/ui/cmd.js +++ b/modules/ui/cmd.js @@ -1,11 +1,15 @@ +import { Detect } from '../util/detect'; + // Translate a MacOS key command into the appropriate Windows/Linux equivalent. // For example, ⌘Z -> Ctrl+Z export function cmd(code) { - if (iD.detect().os === 'mac') { + var detected = Detect(); + + if (detected.os === 'mac') { return code; } - if (iD.detect().os === 'win') { + if (detected.os === 'win') { if (code === '⌘⇧Z') return 'Ctrl+Y'; } diff --git a/modules/ui/fields/check.js b/modules/ui/fields/check.js index 6aaef959a..3a2af2860 100644 --- a/modules/ui/fields/check.js +++ b/modules/ui/fields/check.js @@ -1,5 +1,6 @@ -export { check as defaultcheck }; import { oneWayTags } from '../../core/index'; + +export { check as defaultcheck }; export function check(field) { var dispatch = d3.dispatch('change'), options = field.strings && field.strings.options, diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index cebe8741d..fd3a7df5d 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -1,4 +1,7 @@ -export { combo as typeCombo, combo as multiCombo }; +export { + combo as typeCombo, + combo as multiCombo +}; export function combo(field, context) { var dispatch = d3.dispatch('change'), isMulti = (field.type === 'multiCombo'), diff --git a/modules/ui/fields/localized.js b/modules/ui/fields/localized.js index 822ad532c..5404d8543 100644 --- a/modules/ui/fields/localized.js +++ b/modules/ui/fields/localized.js @@ -1,5 +1,7 @@ +import { Detect } from '../../util/detect'; import { Icon } from '../../svg/index'; import { SuggestNames } from '../../util/index'; + export function localized(field, context) { var dispatch = d3.dispatch('change', 'input'), wikipedia = iD.services.wikipedia.init(), @@ -53,7 +55,7 @@ export function localized(field, context) { function addNew() { d3.event.preventDefault(); var data = localizedInputs.selectAll('div.entry').data(); - var defaultLang = iD.detect().locale.toLowerCase().split('-')[0]; + var defaultLang = Detect().locale.toLowerCase().split('-')[0]; var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;}); var isLangEn = defaultLang.indexOf('en') > -1; if (isLangEn || langExists) { diff --git a/modules/ui/fields/maxspeed.js b/modules/ui/fields/maxspeed.js index 496bfb678..15abad7e8 100644 --- a/modules/ui/fields/maxspeed.js +++ b/modules/ui/fields/maxspeed.js @@ -1,4 +1,5 @@ import { pointInPolygon } from '../../geo/index'; + export function maxspeed(field, context) { var dispatch = d3.dispatch('change'), entity, diff --git a/modules/ui/fields/wikipedia.js b/modules/ui/fields/wikipedia.js index 943bd633e..d564c8a2e 100644 --- a/modules/ui/fields/wikipedia.js +++ b/modules/ui/fields/wikipedia.js @@ -1,4 +1,5 @@ import { ChangeTags } from '../../actions/index'; +import { Detect } from '../../util/detect'; import { Icon } from '../../svg/index'; export function wikipedia(field, context) { @@ -73,7 +74,7 @@ export function wikipedia(field, context) { function language() { var value = lang.value().toLowerCase(); - var locale = iD.detect().locale.toLowerCase(); + var locale = Detect().locale.toLowerCase(); var localeLanguage; return _.find(iD.data.wikipedia, function(d) { if (d[2] === locale) localeLanguage = d; diff --git a/modules/ui/info.js b/modules/ui/info.js index 11e19864f..dff8f2691 100644 --- a/modules/ui/info.js +++ b/modules/ui/info.js @@ -1,9 +1,10 @@ +import { Detect } from '../util/detect'; import { Extent } from '../geo/index'; import { cmd } from './cmd'; export function Info(context) { var key = cmd('⌘I'), - imperial = (iD.detect().locale.toLowerCase() === 'en-us'), + imperial = (Detect().locale.toLowerCase() === 'en-us'), hidden = true; function info(selection) { diff --git a/modules/ui/init.js b/modules/ui/init.js index b254e5095..33f2eaba0 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -4,6 +4,7 @@ import { Attribution } from './attribution'; import { Background } from './background'; import { Browse } from '../modes/index'; import { Contributors } from './contributors'; +import { Detect } from '../util/detect'; import { FeatureInfo } from './feature_info'; import { FullScreen } from './full_screen'; import { Geolocate } from './geolocate'; @@ -29,7 +30,7 @@ export function init(context) { function render(container) { var map = context.map(); - if (iD.detect().opera) container.classed('opera', true); + if (Detect().opera) container.classed('opera', true); var hash = Hash(context); diff --git a/modules/ui/scale.js b/modules/ui/scale.js index 8e2c592e0..179a4f4f8 100644 --- a/modules/ui/scale.js +++ b/modules/ui/scale.js @@ -1,7 +1,9 @@ import { lonToMeters, metersToLon } from '../geo/index'; +import { Detect } from '../util/detect'; + export function Scale(context) { var projection = context.projection, - imperial = (iD.detect().locale.toLowerCase() === 'en-us'), + imperial = (Detect().locale.toLowerCase() === 'en-us'), maxLength = 180, tickHeight = 8; diff --git a/modules/ui/tag_reference.js b/modules/ui/tag_reference.js index 4e34613b4..028291b81 100644 --- a/modules/ui/tag_reference.js +++ b/modules/ui/tag_reference.js @@ -1,4 +1,6 @@ +import { Detect } from '../util/detect'; import { Icon } from '../svg/index'; + export function TagReference(tag, context) { var tagReference = {}, button, @@ -7,7 +9,7 @@ export function TagReference(tag, context) { showing; function findLocal(data) { - var locale = iD.detect().locale.toLowerCase(), + var locale = Detect().locale.toLowerCase(), localized; localized = _.find(data, function(d) { diff --git a/modules/util/detect.js b/modules/util/detect.js new file mode 100644 index 000000000..9ac36d2b9 --- /dev/null +++ b/modules/util/detect.js @@ -0,0 +1,89 @@ +export function Detect() { + var detected = {}; + + var ua = navigator.userAgent, + m = null; + + m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge + if (m !== null) { + detected.browser = m[1]; + detected.version = m[2]; + } + if (!detected.browser) { + m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11 + if (m !== null) { + detected.browser = 'msie'; + detected.version = m[1]; + } + } + if (!detected.browser) { + m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+ + if (m !== null) { + detected.browser = 'Opera'; + detected.version = m[2]; + } + } + if (!detected.browser) { + m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i); + if (m !== null) { + detected.browser = m[1]; + detected.version = m[2]; + m = ua.match(/version\/([\.\d]+)/i); + if (m !== null) detected.version = m[1]; + } + } + if (!detected.browser) { + detected.browser = navigator.appName; + detected.version = navigator.appVersion; + } + + // keep major.minor version only.. + detected.version = detected.version.split(/\W/).slice(0,2).join('.'); + + if (detected.browser.toLowerCase() === 'msie') { + detected.ie = true; + detected.browser = 'Internet Explorer'; + detected.support = parseFloat(detected.version) >= 11; + } else { + detected.ie = false; + detected.support = true; + } + + // Added due to incomplete svg style support. See #715 + detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 ); + + detected.locale = (navigator.languages && navigator.languages.length) + ? navigator.languages[0] : (navigator.language || navigator.userLanguage || 'en-US'); + + // Loaded locale is stored in window.locale.current() + // return that instead (except in the situation where 'en' might override 'en-US') + var loadedLocale = (window.locale && window.locale.current()) || 'en'; + if (loadedLocale !== 'en') { + detected.locale = loadedLocale; + } + + detected.filedrop = (window.FileReader && 'ondrop' in window); + + function nav(x) { + return navigator.userAgent.indexOf(x) !== -1; + } + + if (nav('Win')) { + detected.os = 'win'; + detected.platform = 'Windows'; + } + else if (nav('Mac')) { + detected.os = 'mac'; + detected.platform = 'Macintosh'; + } + else if (nav('X11') || nav('Linux')) { + detected.os = 'linux'; + detected.platform = 'Linux'; + } + else { + detected.os = 'win'; + detected.platform = 'Unknown'; + } + + return detected; +} diff --git a/modules/util/util.js b/modules/util/util.js index d3cc57791..103d72538 100644 --- a/modules/util/util.js +++ b/modules/util/util.js @@ -1,3 +1,4 @@ +import { Detect } from './detect'; import { remove as removeDiacritics } from 'diacritics'; export function tagText(entity) { @@ -26,7 +27,7 @@ export function entityOrMemberSelector(ids, graph) { } export function displayName(entity) { - var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0]; + var localeName = 'name:' + Detect().locale.toLowerCase().split('-')[0]; return entity.tags[localeName] || entity.tags.name || entity.tags.ref; } @@ -98,7 +99,7 @@ export function prefixCSSProperty(property) { var transformProperty; export function setTransform(el, x, y, scale) { var prop = transformProperty = transformProperty || prefixCSSProperty('Transform'), - translate = iD.detect().opera ? + translate = Detect().opera ? 'translate(' + x + 'px,' + y + 'px)' : 'translate3d(' + x + 'px,' + y + 'px,0)'; return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : '')); diff --git a/test/spec/ui/cmd.js b/test/spec/ui/cmd.js index f7f960d8d..ee637b540 100644 --- a/test/spec/ui/cmd.js +++ b/test/spec/ui/cmd.js @@ -1,24 +1,26 @@ describe('iD.ui.cmd', function () { - var detect, os; + var origNavigator, ua; beforeEach(function() { - detect = iD.detect; - iD.detect = function() { - return { os: os }; - }; + /* eslint-disable no-native-reassign */ + origNavigator = navigator; + navigator = Object.create(origNavigator, { + userAgent: { get: function() { return ua; } } + }); }); afterEach(function() { - iD.detect = detect; + navigator = origNavigator; + /* eslint-enable no-native-reassign */ }); it('does not overwrite mac keybindings', function () { - os = 'mac'; + ua = 'Mac'; expect(iD.ui.cmd('⌘A')).to.eql('⌘A'); }); it('changes keys to linux versions', function () { - os = 'linux'; + ua = 'Linux'; expect(iD.ui.cmd('⌘A')).to.eql('Ctrl+A'); expect(iD.ui.cmd('⇧A')).to.eql('Shift+A'); expect(iD.ui.cmd('⌘⇧A')).to.eql('Ctrl+Shift+A'); @@ -26,7 +28,7 @@ describe('iD.ui.cmd', function () { }); it('changes keys to win versions', function () { - os = 'win'; + ua = 'Win'; expect(iD.ui.cmd('⌘A')).to.eql('Ctrl+A'); expect(iD.ui.cmd('⇧A')).to.eql('Shift+A'); expect(iD.ui.cmd('⌘⇧A')).to.eql('Ctrl+Shift+A'); @@ -34,7 +36,7 @@ describe('iD.ui.cmd', function () { }); it('handles multi-character keys', function () { - os = 'win'; + ua = 'Win'; expect(iD.ui.cmd('f11')).to.eql('f11'); expect(iD.ui.cmd('⌘plus')).to.eql('Ctrl+plus'); });