diff --git a/modules/ui/fields/wikipedia.js b/modules/ui/fields/wikipedia.js index 832881c77..30f313d2a 100644 --- a/modules/ui/fields/wikipedia.js +++ b/modules/ui/fields/wikipedia.js @@ -11,6 +11,8 @@ import { utilGetSetValue, utilNoAuto, utilRebind } from '../../util'; export function uiFieldWikipedia(field, context) { + const scheme = 'https://'; + const domain = 'wikipedia.org'; const dispatch = d3_dispatch('change'); const wikipedia = services.wikipedia; const wikidata = services.wikidata; @@ -132,7 +134,7 @@ export function uiFieldWikipedia(field, context) { link = link.enter() .append('button') .attr('class', 'form-field-button wiki-link') - .attr('title', t('icons.view_on', { domain: 'wikipedia.org' })) + .attr('title', t('icons.view_on', { domain })) .call(svgIcon('#iD-icon-out-link')) .merge(link); @@ -280,24 +282,13 @@ export function uiFieldWikipedia(field, context) { const nativeLangName = tagLangInfo[1]; utilGetSetValue(_langInput, nativeLangName); utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? ('#' + anchor) : '')); - if (anchor) { - try { - // Best-effort `anchorencode:` implementation - anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.'); - } catch (e) { - anchor = anchor.replace(/ /g, '_'); - } - } - _wikiURL = 'https://' + tagLang + '.wikipedia.org/wiki/' + - tagArticleTitle.replace(/ /g, '_') + (anchor ? ('#' + anchor) : ''); - - // unrecognized value format + _wikiURL = `${scheme}${tagLang}.${domain}/wiki/${wiki.encodePath(tagArticleTitle, anchor)}`; } else { utilGetSetValue(_titleInput, value); if (value && value !== '') { utilGetSetValue(_langInput, ''); const defaultLangInfo = defaultLanguageInfo(); - _wikiURL = `https://${defaultLangInfo[2]}.wikipedia.org/w/index.php?fulltext=1&search=${value}`; + _wikiURL = `${scheme}${defaultLangInfo[2]}.${domain}/w/index.php?fulltext=1&search=${value}`; } else { const shownOrDefaultLangInfo = language(true /* skipEnglishFallback */); utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]); @@ -306,6 +297,18 @@ export function uiFieldWikipedia(field, context) { } } + wiki.encodePath = (tagArticleTitle, anchor) => { + const underscoredTitle = tagArticleTitle.replace(/ /g, '_'); + const uriEncodedUnderscoredTitle = encodeURIComponent(underscoredTitle); + const uriEncodedAnchorFragment = wiki.encodeURIAnchorFragment(anchor); + return `${uriEncodedUnderscoredTitle}${uriEncodedAnchorFragment}`; + }; + + wiki.encodeURIAnchorFragment = (anchor) => { + if (!anchor) return ''; + const underscoredAnchor = anchor.replace(/ /g, '_'); + return '#' + encodeURIComponent(underscoredAnchor); + }; wiki.entityIDs = (val) => { if (!arguments.length) return _entityIDs; diff --git a/test/spec/ui/fields/wikipedia.js b/test/spec/ui/fields/wikipedia.js index 6a6d4a122..dc31d78f9 100644 --- a/test/spec/ui/fields/wikipedia.js +++ b/test/spec/ui/fields/wikipedia.js @@ -113,6 +113,48 @@ describe('iD.uiFieldWikipedia', function() { }, 20); }); + describe('encodePath', function() { + it('returns an encoded URI component that contains the title with spaces replaced by underscores', function(done) { + var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]); + expect(wikipedia.encodePath('? (film)', undefined)).to.equal('%3F_(film)'); + done(); + }); + + it('returns an encoded URI component that includes an anchor fragment', function(done) { + var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]); + // this can be tested manually by entering '? (film)#Themes and style in the search box before focusing out' + expect(wikipedia.encodePath('? (film)', 'Themes and style')).to.equal('%3F_(film)#Themes_and_style'); + done(); + }); + }); + + describe('encodeURIAnchorFragment', function() { + it('returns an encoded URI anchor fragment', function(done) { + var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]); + // this can be similarily tested by entering 'Section#Arts, entertainment and media' in the search box before focusing out' + expect(wikipedia.encodeURIAnchorFragment('Theme?')).to.equal('#Theme%3F'); + done(); + }); + + it('replaces all whitespace characters with underscore', function(done) { + var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]); + expect(wikipedia.encodeURIAnchorFragment('Themes And Styles')).to.equal('#Themes_And_Styles'); + done(); + }); + + it('encodes % characters, does not replace them with a dot', function(done) { + var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]); + expect(wikipedia.encodeURIAnchorFragment('Is%this_100% correct')).to.equal('#Is%25this_100%25_correct'); + done(); + }); + + it('encodes characters that are URI encoded characters', function (done) { + var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]); + expect(wikipedia.encodeURIAnchorFragment('Section %20%25')).to.equal('#Section_%2520%2525'); + done(); + }); + }); + // note - currently skipping the tests that use `options` to delay responses it('preserves existing language', function(done) { var wikipedia1 = iD.uiFieldWikipedia(field, context);