Field: fix wikiURL by URL encoding it - and slight refactors (#10165)

* Field: fix wikiURL by URL encoding it - and slight refactors

* Field: fix wikiURL only encodeURIComponent instead of redundant full URL

* Field: refactors function to generate wikiURL, ensures anchor part is also URI encoded, ensures the anchor ref is not encoded, adds unit tests

* Field: refactors wikipedia URI encoding of the anchor logic, removes legacy anchorencode effort via try-catch that replaced percentage character with dots, adds unit further  tests, reduces exessive inlining
This commit is contained in:
Hirako
2024-03-21 14:42:08 +07:00
committed by GitHub
parent 12b0528175
commit 85278c35e4
2 changed files with 59 additions and 14 deletions
+17 -14
View File
@@ -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;
+42
View File
@@ -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);