From 9576e95d83b6a974b755160fc292ea7a806f1e92 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Thu, 23 Jun 2022 10:29:22 +0200 Subject: [PATCH 1/9] change label of ui fields from raw html to a callback function fixes #9159 --- modules/presets/field.js | 4 +++- modules/ui/field.js | 2 +- modules/ui/intro/area.js | 8 ++++---- modules/ui/intro/navigation.js | 8 ++++---- modules/ui/sections/preset_fields.js | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/modules/presets/field.js b/modules/presets/field.js index ee81d38a3..5e7a60a73 100644 --- a/modules/presets/field.js +++ b/modules/presets/field.js @@ -26,7 +26,9 @@ export function presetField(fieldID, field) { _this.hasTextForStringId = (scope) => localizer.hasTextForStringId(`_tagging.presets.fields.${fieldID}.${scope}`); _this.title = () => _this.overrideLabel || _this.t('label', { 'default': fieldID }); - _this.label = () => _this.overrideLabel || _this.t.html('label', { 'default': fieldID }); + _this.label = () => _this.overrideLabel ? + selection => selection.text(_this.overrideLabel) : + _this.t.append('label', { 'default': fieldID }); const _placeholder = _this.placeholder; _this.placeholder = () => _this.t('placeholder', { 'default': _placeholder }); diff --git a/modules/ui/field.js b/modules/ui/field.js index 43aac7591..973f69728 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -140,7 +140,7 @@ export function uiField(context, presetField, entityIDs, options) { textEnter .append('span') .attr('class', 'label-textvalue') - .html(function(d) { return d.label(); }); + .each(function(d) { d.label()(d3_select(this)); }); textEnter .append('span') diff --git a/modules/ui/intro/area.js b/modules/ui/intro/area.js index 370f75a25..1ac4dec21 100644 --- a/modules/ui/intro/area.js +++ b/modules/ui/intro/area.js @@ -328,8 +328,8 @@ export function uiIntroArea(context, reveal) { timeout(function() { reveal('.more-fields .combobox-input', helpHtml('intro.areas.add_field', { - name: { html: nameField.label() }, - description: { html: descriptionField.label() } + name: nameField.title(), + description: descriptionField.title() }), { duration: 300 } ); @@ -395,7 +395,7 @@ export function uiIntroArea(context, reveal) { }, 300); reveal('div.combobox', - helpHtml('intro.areas.choose_field', { field: { html: descriptionField.label() } }), + helpHtml('intro.areas.choose_field', { field: descriptionField.title() }), { duration: 300 } ); @@ -456,7 +456,7 @@ export function uiIntroArea(context, reveal) { context.container().select('.inspector-wrap .panewrap').style('right', '0%'); reveal('.entity-editor-pane', - helpHtml('intro.areas.retry_add_field', { field: { html: descriptionField.label() } }), { + helpHtml('intro.areas.retry_add_field', { field: descriptionField.title() }), { buttonText: t.html('intro.ok'), buttonCallback: function() { continueTo(clickAddField); } }); diff --git a/modules/ui/intro/navigation.js b/modules/ui/intro/navigation.js index 8e5acad56..65c4c6710 100644 --- a/modules/ui/intro/navigation.js +++ b/modules/ui/intro/navigation.js @@ -493,8 +493,8 @@ export function uiIntroNavigation(context, reveal) { reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', { button: { html: icon(href, 'inline') }, - field1: { html: onewayField.label() }, - field2: { html: maxspeedField.label() } + field1: onewayField.title(), + field2: maxspeedField.title() })); context.on('exit.intro', function() { @@ -509,8 +509,8 @@ export function uiIntroNavigation(context, reveal) { reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', { button: { html: icon(href, 'inline') }, - field1: { html: onewayField.label() }, - field2: { html: maxspeedField.label() } + field1: onewayField.title(), + field2: maxspeedField.title() }), { duration: 0 } ); }); diff --git a/modules/ui/sections/preset_fields.js b/modules/ui/sections/preset_fields.js index ecb571eb5..6cafc4e6a 100644 --- a/modules/ui/sections/preset_fields.js +++ b/modules/ui/sections/preset_fields.js @@ -81,7 +81,7 @@ export function uiSectionPresetFields(context) { var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal()); additionalFields.sort(function(field1, field2) { - return field1.label().localeCompare(field2.label(), localizer.localeCode()); + return field1.title().localeCompare(field2.title(), localizer.localeCode()); }); additionalFields.forEach(function(field) { From 422861dbc786565de99dc6cfe3ac755b92038e77 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Thu, 23 Jun 2022 10:52:13 +0200 Subject: [PATCH 2/9] render background source labels as text, not html --- modules/ui/panels/background.js | 2 +- modules/ui/sections/background_list.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ui/panels/background.js b/modules/ui/panels/background.js index 80cba011c..cd167db30 100644 --- a/modules/ui/panels/background.js +++ b/modules/ui/panels/background.js @@ -33,7 +33,7 @@ export function uiPanelBackground(context) { list .append('li') - .html(_currSourceName); + .text(_currSourceName); _metadataKeys.forEach(function(k) { // DigitalGlobe vintage is available in raster layers for now. diff --git a/modules/ui/sections/background_list.js b/modules/ui/sections/background_list.js index 49966801c..1fba2a690 100644 --- a/modules/ui/sections/background_list.js +++ b/modules/ui/sections/background_list.js @@ -202,7 +202,7 @@ export function uiSectionBackgroundList(context) { label .append('span') - .html(function(d) { return d.label(); }); + .text(function(d) { return d.label(); }); enter.filter(function(d) { return d.id === 'custom'; }) .append('button') @@ -225,7 +225,7 @@ export function uiSectionBackgroundList(context) { .placement((localizer.textDirection() === 'rtl') ? 'right' : 'left') ) .append('span') - .html('★'); + .text('★'); layerList .call(updateLayerSelections); From ac77289b4db4dca729b0b7f1c290bf1096056ceb Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Thu, 23 Jun 2022 18:24:48 +0200 Subject: [PATCH 3/9] refactor localized text rendering in tooltips, flash messages --- modules/behavior/draw_way.js | 8 ++++---- modules/behavior/operation.js | 2 +- modules/modes/add_note.js | 2 +- modules/modes/browse.js | 4 ++-- modules/modes/drag_node.js | 6 +++--- modules/modes/draw_area.js | 2 +- modules/modes/draw_line.js | 2 +- modules/modes/select.js | 2 +- modules/renderer/background_source.js | 8 ++++---- modules/ui/commit.js | 13 ++++++++----- modules/ui/edit_menu.js | 2 +- modules/ui/feature_info.js | 13 ++++++++++--- modules/ui/field.js | 2 +- modules/ui/fields/localized.js | 2 +- modules/ui/flash.js | 10 +++++++--- modules/ui/geolocate.js | 4 ++-- modules/ui/init.js | 10 +++++++--- modules/ui/issues_info.js | 2 +- modules/ui/pane.js | 5 +++-- modules/ui/panels/background.js | 4 ++-- modules/ui/panes/background.js | 4 ++-- modules/ui/panes/help.js | 6 +++--- modules/ui/panes/issues.js | 4 ++-- modules/ui/panes/map_data.js | 4 ++-- modules/ui/panes/preferences.js | 4 ++-- modules/ui/preset_list.js | 4 ++-- modules/ui/sections/background_list.js | 20 +++++++++----------- modules/ui/sections/data_layers.js | 18 +++++++++--------- modules/ui/sections/feature_type.js | 2 +- modules/ui/sections/map_features.js | 9 ++++++--- modules/ui/sections/map_style_options.js | 2 +- modules/ui/sections/overlay_list.js | 4 ++-- modules/ui/sections/photo_overlays.js | 12 ++++++------ modules/ui/sections/privacy.js | 2 +- modules/ui/sections/raw_membership_editor.js | 4 +++- modules/ui/sections/raw_tag_editor.js | 4 +++- modules/ui/sections/validation_rules.js | 2 +- modules/ui/tools/modes.js | 17 +++++++++-------- modules/ui/tools/notes.js | 2 +- modules/ui/tools/save.js | 8 ++++---- modules/ui/tools/sidebar_toggle.js | 4 ++-- modules/ui/tools/undo_redo.js | 14 +++++++------- modules/ui/tooltip.js | 11 ++++++++--- modules/ui/top_toolbar.js | 4 +--- modules/ui/version.js | 2 +- modules/ui/zoom.js | 8 ++++---- modules/ui/zoom_to_selection.js | 6 +++--- 47 files changed, 156 insertions(+), 128 deletions(-) diff --git a/modules/behavior/draw_way.js b/modules/behavior/draw_way.js index 44e61f1bc..29fa0aa1f 100644 --- a/modules/behavior/draw_way.js +++ b/modules/behavior/draw_way.js @@ -447,7 +447,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) { context.ui().flash .duration(4000) .iconName('#iD-icon-no') - .label(t.html('operations.follow.error.needs_more_initial_nodes'))(); + .label(t.append('operations.follow.error.needs_more_initial_nodes'))(); return; } @@ -461,7 +461,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) { context.ui().flash .duration(4000) .iconName('#iD-icon-no') - .label(t.html(`operations.follow.error.intersection_of_multiple_ways.${featureType}`))(); + .label(t.append(`operations.follow.error.intersection_of_multiple_ways.${featureType}`))(); return; } @@ -472,7 +472,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) { context.ui().flash .duration(4000) .iconName('#iD-icon-no') - .label(t.html(`operations.follow.error.intersection_of_different_ways.${featureType}`))(); + .label(t.append(`operations.follow.error.intersection_of_different_ways.${featureType}`))(); return; } @@ -501,7 +501,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) { context.ui().flash .duration(4000) .iconName('#iD-icon-no') - .label(t.html('operations.follow.error.unknown'))(); + .label(t.append('operations.follow.error.unknown'))(); } } diff --git a/modules/behavior/operation.js b/modules/behavior/operation.js index 724e18f9c..b10fcd3cb 100644 --- a/modules/behavior/operation.js +++ b/modules/behavior/operation.js @@ -19,7 +19,7 @@ export function behaviorOperation(context) { .duration(4000) .iconName('#iD-operation-' + _operation.id) .iconClass('operation disabled') - .label(_operation.tooltip)(); + .label(_operation.tooltip())(); } else { context.ui().flash diff --git a/modules/modes/add_note.js b/modules/modes/add_note.js index 430c70a26..71f9887cc 100644 --- a/modules/modes/add_note.js +++ b/modules/modes/add_note.js @@ -10,7 +10,7 @@ export function modeAddNote(context) { var mode = { id: 'add-note', button: 'note', - description: t.html('modes.add_note.description'), + description: t.append('modes.add_note.description'), key: t('modes.add_note.key') }; diff --git a/modules/modes/browse.js b/modules/modes/browse.js index b268b76c6..c12a17526 100644 --- a/modules/modes/browse.js +++ b/modules/modes/browse.js @@ -14,8 +14,8 @@ export function modeBrowse(context) { var mode = { button: 'browse', id: 'browse', - title: t('modes.browse.title'), - description: t('modes.browse.description') + title: t.append('modes.browse.title'), + description: t.append('modes.browse.description') }; var sidebar; diff --git a/modules/modes/drag_node.js b/modules/modes/drag_node.js index 0e531df9c..b229868ce 100644 --- a/modules/modes/drag_node.js +++ b/modules/modes/drag_node.js @@ -138,7 +138,7 @@ export function modeDragNode(context) { context.ui().flash .duration(4000) .iconName('#iD-icon-no') - .label(t('modes.drag_node.connected_to_hidden'))(); + .label(t.append('modes.drag_node.connected_to_hidden'))(); } return drag.cancel(); } @@ -239,7 +239,7 @@ export function modeDragNode(context) { context.ui().flash .duration(4000) .iconName('#iD-icon-no') - .label(t.html('operations.connect.' + isInvalid, + .label(t.append('operations.connect.' + isInvalid, { relation: presetManager.item('type/restriction').name() } ))(); } @@ -248,7 +248,7 @@ export function modeDragNode(context) { context.ui().flash .duration(3000) .iconName('#iD-icon-no') - .label(t.html('self_intersection.error.' + errorID))(); + .label(t.append('self_intersection.error.' + errorID))(); } else { if (nope) { // about to un-nope, remove hint context.ui().flash diff --git a/modules/modes/draw_area.js b/modules/modes/draw_area.js index 213fa127b..8014569b0 100644 --- a/modules/modes/draw_area.js +++ b/modules/modes/draw_area.js @@ -12,7 +12,7 @@ export function modeDrawArea(context, wayID, startGraph, button) { .on('rejectedSelfIntersection.modeDrawArea', function() { context.ui().flash .iconName('#iD-icon-no') - .label(t.html('self_intersection.error.areas'))(); + .label(t.append('self_intersection.error.areas'))(); }); mode.wayID = wayID; diff --git a/modules/modes/draw_line.js b/modules/modes/draw_line.js index b5dd99429..caa78f060 100644 --- a/modules/modes/draw_line.js +++ b/modules/modes/draw_line.js @@ -12,7 +12,7 @@ export function modeDrawLine(context, wayID, startGraph, button, affix, continui .on('rejectedSelfIntersection.modeDrawLine', function() { context.ui().flash .iconName('#iD-icon-no') - .label(t.html('self_intersection.error.lines'))(); + .label(t.append('self_intersection.error.lines'))(); }); mode.wayID = wayID; diff --git a/modules/modes/select.js b/modules/modes/select.js index d66d6e599..6af3acd4d 100644 --- a/modules/modes/select.js +++ b/modules/modes/select.js @@ -400,7 +400,7 @@ export function modeSelect(context, selectedIDs) { .duration(4000) .iconName('#iD-icon-no') .iconClass('operation disabled') - .label(t.html('operations.scale.' + disabled + '.' + multi))(); + .label(t.append('operations.scale.' + disabled + '.' + multi))(); } else { const pivot = context.projection(extent.center()); const annotation = t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', { n: selectedIDs.length }); diff --git a/modules/renderer/background_source.js b/modules/renderer/background_source.js index 8d406b262..e543f5004 100644 --- a/modules/renderer/background_source.js +++ b/modules/renderer/background_source.js @@ -75,13 +75,13 @@ export function rendererBackgroundSource(data) { source.label = function() { var id_safe = source.id.replace(/\./g, ''); - return t.html('imagery.' + id_safe + '.name', { default: escape(_name) }); + return t.append('imagery.' + id_safe + '.name', { default: escape(_name) }); }; source.description = function() { var id_safe = source.id.replace(/\./g, ''); - return t.html('imagery.' + id_safe + '.description', { default: escape(_description) }); + return t.append('imagery.' + id_safe + '.description', { default: escape(_description) }); }; @@ -536,7 +536,7 @@ rendererBackgroundSource.None = function() { source.label = function() { - return t.html('background.none'); + return t.append('background.none'); }; @@ -563,7 +563,7 @@ rendererBackgroundSource.Custom = function(template) { }; source.label = function() { - return t.html('background.custom'); + return t.append('background.custom'); }; diff --git a/modules/ui/commit.js b/modules/ui/commit.js index cba8e94b7..326b8202a 100644 --- a/modules/ui/commit.js +++ b/modules/ui/commit.js @@ -329,7 +329,9 @@ export function uiCommit(context) { if (!labelEnter.empty()) { labelEnter - .call(uiTooltip().title(t.html('commit.request_review_info')).placement('top')); + .call(uiTooltip() + .title(() => t.append('commit.request_review_info')) + .placement('top')); } labelEnter @@ -405,7 +407,9 @@ export function uiCommit(context) { if (uploadBlockerTooltipText) { buttonSection.selectAll('.save-button') - .call(uiTooltip().title(uploadBlockerTooltipText).placement('top')); + .call(uiTooltip() + .title(() => uploadBlockerTooltipText) + .placement('top')); } // Raw Tag Editor @@ -453,12 +457,11 @@ export function uiCommit(context) { .getIssuesBySeverity({ what: 'edited', where: 'all' }).error; if (errors.length) { - return t('commit.outstanding_errors_message', { count: errors.length }); - + return t.append('commit.outstanding_errors_message', { count: errors.length }); } else { var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length; if (!hasChangesetComment) { - return t('commit.comment_needed_message'); + return t.append('commit.comment_needed_message'); } } return null; diff --git a/modules/ui/edit_menu.js b/modules/ui/edit_menu.js index de483b423..4b199e98a 100644 --- a/modules/ui/edit_menu.js +++ b/modules/ui/edit_menu.js @@ -105,7 +105,7 @@ export function uiEditMenu(context) { buttonsEnter.each(function(d) { var tooltip = uiTooltip() .heading(d.title) - .title(d.tooltip()) + .title(d.tooltip) .keys([d.keys[0]]); _tooltips.push(tooltip); diff --git a/modules/ui/feature_info.js b/modules/ui/feature_info.js index 522fdd67d..84f146d7c 100644 --- a/modules/ui/feature_info.js +++ b/modules/ui/feature_info.js @@ -9,18 +9,25 @@ export function uiFeatureInfo(context) { var hiddenList = features.hidden().map(function(k) { if (stats[k]) { count += stats[k]; - return t.html('inspector.title_count', { title: { html: t.html('feature.' + k + '.description') }, count: stats[k] }); + return t.append('inspector.title_count', { + title: t('feature.' + k + '.description'), + count: stats[k] + }); } return null; }).filter(Boolean); - selection.html(''); + selection.text(''); if (hiddenList.length) { var tooltipBehavior = uiTooltip() .placement('top') .title(function() { - return hiddenList.join('
'); + return selection => { + hiddenList.forEach(hiddenFeature => { + selection.append('div').call(hiddenFeature); + }) + }; }); selection.append('a') diff --git a/modules/ui/field.js b/modules/ui/field.js index 973f69728..11cff9813 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -38,7 +38,7 @@ export function uiField(context, presetField, entityIDs, options) { var _locked = false; var _lockedTip = uiTooltip() - .title(t.html('inspector.lock.suggestion', { label: field.label })) + .title(() => t.append('inspector.lock.suggestion', { label: field.label })) .placement('bottom'); diff --git a/modules/ui/fields/localized.js b/modules/ui/fields/localized.js index b59a55aa0..d86fc79c6 100644 --- a/modules/ui/fields/localized.js +++ b/modules/ui/fields/localized.js @@ -43,7 +43,7 @@ export function uiFieldLocalized(field, context) { var _selection = d3_select(null); var _multilingual = []; var _buttonTip = uiTooltip() - .title(t.html('translate.translate')) + .title(() => t.append('translate.translate')) .placement('left'); var _wikiTitles; var _entityIDs = []; diff --git a/modules/ui/flash.js b/modules/ui/flash.js index 39b04a35c..82062025c 100644 --- a/modules/ui/flash.js +++ b/modules/ui/flash.js @@ -6,7 +6,7 @@ export function uiFlash(context) { var _duration = 2000; var _iconName = '#iD-icon-no'; var _iconClass = 'disabled'; - var _label = ''; + var _label = s => s.text(''); function flash() { if (_flashTimer) { @@ -64,7 +64,7 @@ export function uiFlash(context) { content .selectAll('.flash-text') .attr('class', 'flash-text') - .html(_label); + .call(_label); _flashTimer = d3_timeout(function() { @@ -89,7 +89,11 @@ export function uiFlash(context) { flash.label = function(_) { if (!arguments.length) return _label; - _label = _; + if (typeof _ !== 'function') { + _label = selection => selection.text(_); + } else { + _label = _; + } return flash; }; diff --git a/modules/ui/geolocate.js b/modules/ui/geolocate.js index 21e4c201a..67c359592 100644 --- a/modules/ui/geolocate.js +++ b/modules/ui/geolocate.js @@ -62,7 +62,7 @@ export function uiGeolocate(context) { zoomTo(); } else { context.ui().flash - .label(t.html('geolocate.location_unavailable')) + .label(t.append('geolocate.location_unavailable')) .iconName('#iD-icon-geolocate')(); } @@ -90,7 +90,7 @@ export function uiGeolocate(context) { .call(svgIcon('#iD-icon-geolocate', 'light')) .call(uiTooltip() .placement((localizer.textDirection() === 'rtl') ? 'right' : 'left') - .title(t.html('geolocate.title')) + .title(() => t.append('geolocate.title')) .keys([t('geolocate.key')]) ); diff --git a/modules/ui/init.js b/modules/ui/init.js index 3235364a5..b857719d7 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -128,7 +128,7 @@ export function uiInit(context) { .on('hitMinZoom.ui', function() { ui.flash .iconName('#iD-icon-no') - .label(t.html('cannot_zoom'))(); + .label(t.append('cannot_zoom'))(); }); container @@ -322,7 +322,9 @@ export function uiInit(context) { .attr('href', 'https://github.com/openstreetmap/iD/issues') .attr('aria-label', t('report_a_bug')) .call(svgIcon('#iD-icon-bug', 'light')) - .call(uiTooltip().title(t.html('report_a_bug')).placement('top')); + .call(uiTooltip() + .title(() => t.append('report_a_bug')) + .placement('top')); issueLinks .append('a') @@ -330,7 +332,9 @@ export function uiInit(context) { .attr('href', 'https://github.com/openstreetmap/iD/blob/develop/CONTRIBUTING.md#translating') .attr('aria-label', t('help_translate')) .call(svgIcon('#iD-icon-translate', 'light')) - .call(uiTooltip().title(t.html('help_translate')).placement('top')); + .call(uiTooltip() + .title(() => t.append('help_translate')) + .placement('top')); aboutList .append('li') diff --git a/modules/ui/issues_info.js b/modules/ui/issues_info.js index 04f70348e..b161e7f09 100644 --- a/modules/ui/issues_info.js +++ b/modules/ui/issues_info.js @@ -62,7 +62,7 @@ export function uiIssuesInfo(context) { var tooltipBehavior = uiTooltip() .placement('top') - .title(t.html(d.descriptionID)); + .title(() => t.append(d.descriptionID)); chipSelection .call(tooltipBehavior) diff --git a/modules/ui/pane.js b/modules/ui/pane.js index 6b41fd8a8..5625835b5 100644 --- a/modules/ui/pane.js +++ b/modules/ui/pane.js @@ -72,7 +72,7 @@ export function uiPane(id, context) { if (!_paneTooltip) { _paneTooltip = uiTooltip() .placement((localizer.textDirection() === 'rtl') ? 'right' : 'left') - .title(_description) + .title(() => _description) .keys([_key]); } @@ -106,7 +106,8 @@ export function uiPane(id, context) { heading .append('h2') - .html(_label); + .text('') + .call(_label); heading .append('button') diff --git a/modules/ui/panels/background.js b/modules/ui/panels/background.js index cd167db30..6668d83a8 100644 --- a/modules/ui/panels/background.js +++ b/modules/ui/panels/background.js @@ -25,7 +25,7 @@ export function uiPanelBackground(context) { _metadata = {}; } - selection.html(''); + selection.text(''); var list = selection .append('ul') @@ -33,7 +33,7 @@ export function uiPanelBackground(context) { list .append('li') - .text(_currSourceName); + .call(_currSourceName); _metadataKeys.forEach(function(k) { // DigitalGlobe vintage is available in raster layers for now. diff --git a/modules/ui/panes/background.js b/modules/ui/panes/background.js index 9d2e65505..b041668e9 100644 --- a/modules/ui/panes/background.js +++ b/modules/ui/panes/background.js @@ -11,8 +11,8 @@ export function uiPaneBackground(context) { var backgroundPane = uiPane('background', context) .key(t('background.key')) - .label(t.html('background.title')) - .description(t.html('background.description')) + .label(t.append('background.title')) + .description(t.append('background.description')) .iconName('iD-icon-layers') .sections([ uiSectionBackgroundList(context), diff --git a/modules/ui/panes/help.js b/modules/ui/panes/help.js index 0cd0b107a..7fe8cfd4e 100644 --- a/modules/ui/panes/help.js +++ b/modules/ui/panes/help.js @@ -273,8 +273,8 @@ export function uiPaneHelp(context) { var helpPane = uiPane('help', context) .key(t('help.key')) - .label(t.html('help.title')) - .description(t.html('help.title')) + .label(t.append('help.title')) + .description(t.append('help.title')) .iconName('iD-icon-help'); helpPane.renderContent = function(content) { @@ -373,7 +373,7 @@ export function uiPaneHelp(context) { .append('li') .attr('class', 'shortcuts') .call(uiTooltip() - .title(t.html('shortcuts.tooltip')) + .title(() => t.append('shortcuts.tooltip')) .keys(['?']) .placement('top') ) diff --git a/modules/ui/panes/issues.js b/modules/ui/panes/issues.js index b2e5a1acf..3313ecf09 100644 --- a/modules/ui/panes/issues.js +++ b/modules/ui/panes/issues.js @@ -11,8 +11,8 @@ export function uiPaneIssues(context) { var issuesPane = uiPane('issues', context) .key(t('issues.key')) - .label(t.html('issues.title')) - .description(t.html('issues.title')) + .label(t.append('issues.title')) + .description(t.append('issues.title')) .iconName('iD-icon-alert') .sections([ uiSectionValidationOptions(context), diff --git a/modules/ui/panes/map_data.js b/modules/ui/panes/map_data.js index d46d8f1df..3708fbd80 100644 --- a/modules/ui/panes/map_data.js +++ b/modules/ui/panes/map_data.js @@ -11,8 +11,8 @@ export function uiPaneMapData(context) { var mapDataPane = uiPane('map-data', context) .key(t('map_data.key')) - .label(t.html('map_data.title')) - .description(t.html('map_data.description')) + .label(t.append('map_data.title')) + .description(t.append('map_data.description')) .iconName('iD-icon-data') .sections([ uiSectionDataLayers(context), diff --git a/modules/ui/panes/preferences.js b/modules/ui/panes/preferences.js index 6d7d84356..94eb5fd83 100644 --- a/modules/ui/panes/preferences.js +++ b/modules/ui/panes/preferences.js @@ -7,8 +7,8 @@ export function uiPanePreferences(context) { let preferencesPane = uiPane('preferences', context) .key(t('preferences.key')) - .label(t.html('preferences.title')) - .description(t.html('preferences.description')) + .label(t.append('preferences.title')) + .description(t.append('preferences.description')) .iconName('fas-user-cog') .sections([ uiSectionPrivacy(context) diff --git a/modules/ui/preset_list.js b/modules/ui/preset_list.js index bf449be47..f2e9100fc 100644 --- a/modules/ui/preset_list.js +++ b/modules/ui/preset_list.js @@ -466,8 +466,8 @@ export function uiPresetList(context) { if (isHiddenPreset) { var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId); d3_select(this).call(uiTooltip() - .title(t.html('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), { - features: { html: t.html('feature.' + hiddenPresetFeaturesId + '.description') } + .title(() => t.append('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), { + features: t('feature.' + hiddenPresetFeaturesId + '.description') })) .placement(index < 2 ? 'bottom' : 'top') ); diff --git a/modules/ui/sections/background_list.js b/modules/ui/sections/background_list.js index 1fba2a690..6d51f2d0b 100644 --- a/modules/ui/sections/background_list.js +++ b/modules/ui/sections/background_list.js @@ -1,8 +1,6 @@ import _debounce from 'lodash-es/debounce'; import { descending as d3_descending, ascending as d3_ascending } from 'd3-array'; -import { - select as d3_select -} from 'd3-selection'; +import { select as d3_select } from 'd3-selection'; import { prefs } from '../../core/preferences'; import { t, localizer } from '../../core/localizer'; @@ -55,7 +53,7 @@ export function uiSectionBackgroundList(context) { .attr('class', 'minimap-toggle-item') .append('label') .call(uiTooltip() - .title(t.html('background.minimap.tooltip')) + .title(() => t.append('background.minimap.tooltip')) .keys([t('background.minimap.key')]) .placement('top') ); @@ -78,7 +76,7 @@ export function uiSectionBackgroundList(context) { .attr('class', 'background-panel-toggle-item') .append('label') .call(uiTooltip() - .title(t.html('background.panel.tooltip')) + .title(() => t.append('background.panel.tooltip')) .keys([uiCmd('⌘⇧' + t('info_panels.background.key'))]) .placement('top') ); @@ -100,7 +98,7 @@ export function uiSectionBackgroundList(context) { .attr('class', 'location-panel-toggle-item') .append('label') .call(uiTooltip() - .title(t.html('background.location_panel.tooltip')) + .title(() => t.append('background.location_panel.tooltip')) .keys([uiCmd('⌘⇧' + t('info_panels.location.key'))]) .placement('top') ); @@ -152,13 +150,13 @@ export function uiSectionBackgroundList(context) { if (d.id === previousBackgroundID()) { item.call(uiTooltip() .placement(placement) - .title('
' + t.html('background.switch') + '
') + .title(() => t.append('background.switch')) .keys([uiCmd('⌘' + t('background.key'))]) ); } else if (description || isOverflowing) { item.call(uiTooltip() .placement(placement) - .title(description || d.label()) + .title(() => description || d.label()) ); } }); @@ -202,13 +200,13 @@ export function uiSectionBackgroundList(context) { label .append('span') - .text(function(d) { return d.label(); }); + .each(function(d) { d.label()(d3_select(this)); }); enter.filter(function(d) { return d.id === 'custom'; }) .append('button') .attr('class', 'layer-browse') .call(uiTooltip() - .title(t.html('settings.custom_background.tooltip')) + .title(() => t.append('settings.custom_background.tooltip')) .placement((localizer.textDirection() === 'rtl') ? 'right' : 'left') ) .on('click', function(d3_event) { @@ -221,7 +219,7 @@ export function uiSectionBackgroundList(context) { .append('div') .attr('class', 'best') .call(uiTooltip() - .title(t.html('background.best_imagery')) + .title(() => t.append('background.best_imagery')) .placement((localizer.textDirection() === 'rtl') ? 'right' : 'left') ) .append('span') diff --git a/modules/ui/sections/data_layers.js b/modules/ui/sections/data_layers.js index da0c1830c..9580aae5a 100644 --- a/modules/ui/sections/data_layers.js +++ b/modules/ui/sections/data_layers.js @@ -95,14 +95,14 @@ export function uiSectionDataLayers(context) { if (d.id === 'osm') { d3_select(this) .call(uiTooltip() - .title(t.html('map_data.layers.' + d.id + '.tooltip')) + .title(() => t.append('map_data.layers.' + d.id + '.tooltip')) .keys([uiCmd('⌥' + t('area_fill.wireframe.key'))]) .placement('bottom') ); } else { d3_select(this) .call(uiTooltip() - .title(t.html('map_data.layers.' + d.id + '.tooltip')) + .title(() => t.append('map_data.layers.' + d.id + '.tooltip')) .placement('bottom') ); } @@ -154,7 +154,7 @@ export function uiSectionDataLayers(context) { .each(function(d) { d3_select(this) .call(uiTooltip() - .title(t.html('map_data.layers.' + d.id + '.tooltip')) + .title(() => t.append('map_data.layers.' + d.id + '.tooltip')) .placement('bottom') ); }); @@ -166,7 +166,7 @@ export function uiSectionDataLayers(context) { labelEnter .append('span') - .html(function(d) { return t.html('map_data.layers.' + d.id + '.title'); }); + .each(function(d) { t.append('map_data.layers.' + d.id + '.title')(d3_select(this)); }); // Update @@ -313,7 +313,7 @@ export function uiSectionDataLayers(context) { var labelEnter = liEnter .append('label') .call(uiTooltip() - .title(t.html('map_data.layers.custom.tooltip')) + .title(() => t.append('map_data.layers.custom.tooltip')) .placement('top') ); @@ -330,7 +330,7 @@ export function uiSectionDataLayers(context) { .append('button') .attr('class', 'open-data-options') .call(uiTooltip() - .title(t.html('settings.custom_data.tooltip')) + .title(() => t.append('settings.custom_data.tooltip')) .placement((localizer.textDirection() === 'rtl') ? 'right' : 'left') ) .on('click', function(d3_event) { @@ -343,7 +343,7 @@ export function uiSectionDataLayers(context) { .append('button') .attr('class', 'zoom-to-data') .call(uiTooltip() - .title(t.html('map_data.layers.custom.zoom')) + .title(() => t.append('map_data.layers.custom.zoom')) .placement((localizer.textDirection() === 'rtl') ? 'right' : 'left') ) .on('click', function(d3_event) { @@ -400,7 +400,7 @@ export function uiSectionDataLayers(context) { .attr('class', 'history-panel-toggle-item') .append('label') .call(uiTooltip() - .title(t.html('map_data.history_panel.tooltip')) + .title(() => t.append('map_data.history_panel.tooltip')) .keys([uiCmd('⌘⇧' + t('info_panels.history.key'))]) .placement('top') ); @@ -422,7 +422,7 @@ export function uiSectionDataLayers(context) { .attr('class', 'measurement-panel-toggle-item') .append('label') .call(uiTooltip() - .title(t.html('map_data.measurement_panel.tooltip')) + .title(() => t.append('map_data.measurement_panel.tooltip')) .keys([uiCmd('⌘⇧' + t('info_panels.measurement.key'))]) .placement('top') ); diff --git a/modules/ui/sections/feature_type.js b/modules/ui/sections/feature_type.js index 9c0c0ac6a..e4877484c 100644 --- a/modules/ui/sections/feature_type.js +++ b/modules/ui/sections/feature_type.js @@ -39,7 +39,7 @@ export function uiSectionFeatureType(context) { .append('button') .attr('class', 'preset-list-button preset-reset') .call(uiTooltip() - .title(t.html('inspector.back_tooltip')) + .title(() => t.append('inspector.back_tooltip')) .placement('bottom') ); diff --git a/modules/ui/sections/map_features.js b/modules/ui/sections/map_features.js index 5922dcbb8..ad12ec4f5 100644 --- a/modules/ui/sections/map_features.js +++ b/modules/ui/sections/map_features.js @@ -71,10 +71,13 @@ export function uiSectionMapFeatures(context) { .append('li') .call(uiTooltip() .title(function(d) { - var tip = t.html(name + '.' + d + '.tooltip'); + var tip = t.append(name + '.' + d + '.tooltip'); if (autoHiddenFeature(d)) { - var msg = showsLayer('osm') ? t.html('map_data.autohidden') : t.html('map_data.osmhidden'); - tip += '
' + msg + '
'; + var msg = showsLayer('osm') ? t.append('map_data.autohidden') : t.append('map_data.osmhidden'); + return selection => { + selection.call(tip); + selection.append('div').call(msg); + }; } return tip; }) diff --git a/modules/ui/sections/map_style_options.js b/modules/ui/sections/map_style_options.js index 8cd2d636e..eac759aa9 100644 --- a/modules/ui/sections/map_style_options.js +++ b/modules/ui/sections/map_style_options.js @@ -44,7 +44,7 @@ export function uiSectionMapStyleOptions(context) { .append('li') .call(uiTooltip() .title(function(d) { - return t.html(name + '.' + d + '.tooltip'); + return t.append(name + '.' + d + '.tooltip'); }) .keys(function(d) { var key = (d === 'wireframe' ? t('area_fill.wireframe.key') : null); diff --git a/modules/ui/sections/overlay_list.js b/modules/ui/sections/overlay_list.js index 97eb0f9d8..14640ebdc 100644 --- a/modules/ui/sections/overlay_list.js +++ b/modules/ui/sections/overlay_list.js @@ -29,7 +29,7 @@ export function uiSectionOverlayList(context) { if (description || isOverflowing) { item.call(uiTooltip() .placement(placement) - .title(description || d.name()) + .title(() => description || d.name()) ); } }); @@ -80,7 +80,7 @@ export function uiSectionOverlayList(context) { label .append('span') - .html(function(d) { return d.label(); }); + .each(function(d) { d.label()(d3_select(this)); }); layerList.selectAll('li') diff --git a/modules/ui/sections/photo_overlays.js b/modules/ui/sections/photo_overlays.js index a96233608..79930ea5a 100644 --- a/modules/ui/sections/photo_overlays.js +++ b/modules/ui/sections/photo_overlays.js @@ -77,7 +77,7 @@ export function uiSectionPhotoOverlays(context) { else titleID = d.id.replace(/-/g, '_') + '.tooltip'; d3_select(this) .call(uiTooltip() - .title(t.html(titleID)) + .title(() => t.append(titleID)) .placement('top') ); }); @@ -139,7 +139,7 @@ export function uiSectionPhotoOverlays(context) { .each(function(d) { d3_select(this) .call(uiTooltip() - .title(t.html('photo_overlays.photo_type.' + d + '.tooltip')) + .title(() => t.append('photo_overlays.photo_type.' + d + '.tooltip')) .placement('top') ); }); @@ -200,15 +200,15 @@ export function uiSectionPhotoOverlays(context) { .each(function(d) { d3_select(this) .call(uiTooltip() - .title(t.html('photo_overlays.date_filter.' + d + '.tooltip')) + .title(() => t.append('photo_overlays.date_filter.' + d + '.tooltip')) .placement('top') ); }); labelEnter .append('span') - .html(function(d) { - return t.html('photo_overlays.date_filter.' + d + '.title'); + .each(function(d) { + t.append('photo_overlays.date_filter.' + d + '.title')(d3_select(this)); }); labelEnter @@ -266,7 +266,7 @@ export function uiSectionPhotoOverlays(context) { .each(function() { d3_select(this) .call(uiTooltip() - .title(t.html('photo_overlays.username_filter.tooltip')) + .title(() => t.append('photo_overlays.username_filter.tooltip')) .placement('top') ); }); diff --git a/modules/ui/sections/privacy.js b/modules/ui/sections/privacy.js index 15780a8bb..12547555d 100644 --- a/modules/ui/sections/privacy.js +++ b/modules/ui/sections/privacy.js @@ -25,7 +25,7 @@ export function uiSectionPrivacy(context) { .attr('class', 'privacy-third-party-icons-item') .append('label') .call(uiTooltip() - .title(t.html('preferences.privacy.third_party_icons.tooltip')) + .title(() => t.append('preferences.privacy.third_party_icons.tooltip')) .placement('bottom') ); diff --git a/modules/ui/sections/raw_membership_editor.js b/modules/ui/sections/raw_membership_editor.js index 824d9a091..9f44d8d99 100644 --- a/modules/ui/sections/raw_membership_editor.js +++ b/modules/ui/sections/raw_membership_editor.js @@ -469,7 +469,9 @@ export function uiSectionRawMembershipEditor(context) { addRelationButton .call(svgIcon('#iD-icon-plus', 'light')); addRelationButton - .call(uiTooltip().title(t.html('inspector.add_to_relation')).placement(localizer.textDirection() === 'ltr' ? 'right' : 'left')); + .call(uiTooltip() + .title(() => t.append('inspector.add_to_relation')) + .placement(localizer.textDirection() === 'ltr' ? 'right' : 'left')); addRowEnter .append('div') diff --git a/modules/ui/sections/raw_tag_editor.js b/modules/ui/sections/raw_tag_editor.js index be6da5c23..6a7caba6a 100644 --- a/modules/ui/sections/raw_tag_editor.js +++ b/modules/ui/sections/raw_tag_editor.js @@ -165,7 +165,9 @@ export function uiSectionRawTagEditor(id, context) { .attr('class', 'add-tag') .attr('aria-label', t('inspector.add_to_tag')) .call(svgIcon('#iD-icon-plus', 'light')) - .call(uiTooltip().title(t.html('inspector.add_to_tag')).placement(localizer.textDirection() === 'ltr' ? 'right' : 'left')) + .call(uiTooltip() + .title(() => t.append('inspector.add_to_tag')) + .placement(localizer.textDirection() === 'ltr' ? 'right' : 'left')) .on('click', addTag); addRowEnter diff --git a/modules/ui/sections/validation_rules.js b/modules/ui/sections/validation_rules.js index 977b53a7f..6fe7f5931 100644 --- a/modules/ui/sections/validation_rules.js +++ b/modules/ui/sections/validation_rules.js @@ -87,7 +87,7 @@ export function uiSectionValidationRules(context) { if (name === 'rule') { enter .call(uiTooltip() - .title(function(d) { return t.html('issues.' + d + '.tip'); }) + .title(function(d) { return t.append('issues.' + d + '.tip'); }) .placement('top') ); } diff --git a/modules/ui/tools/modes.js b/modules/ui/tools/modes.js index 325b92aea..edaa8a7f3 100644 --- a/modules/ui/tools/modes.js +++ b/modules/ui/tools/modes.js @@ -18,28 +18,28 @@ export function uiToolDrawModes(context) { var tool = { id: 'old_modes', - label: t.html('toolbar.add_feature') + label: t.append('toolbar.add_feature') }; var modes = [ modeAddPoint(context, { - title: t.html('modes.add_point.title'), + title: t.append('modes.add_point.title'), button: 'point', - description: t.html('modes.add_point.description'), + description: t.append('modes.add_point.description'), preset: presetManager.item('point'), key: '1' }), modeAddLine(context, { - title: t.html('modes.add_line.title'), + title: t.append('modes.add_line.title'), button: 'line', - description: t.html('modes.add_line.description'), + description: t.append('modes.add_line.description'), preset: presetManager.item('line'), key: '2' }), modeAddArea(context, { - title: t.html('modes.add_area.title'), + title: t.append('modes.add_area.title'), button: 'area', - description: t.html('modes.add_area.description'), + description: t.append('modes.add_area.description'), preset: presetManager.item('area'), key: '3' }) @@ -130,7 +130,8 @@ export function uiToolDrawModes(context) { buttonsEnter .append('span') .attr('class', 'label') - .html(function(mode) { return mode.title; }); + .text('') + .each(function(mode) { mode.title(d3_select(this)); }); // if we are adding/removing the buttons, check if toolbar has overflowed if (buttons.enter().size() || buttons.exit().size()) { diff --git a/modules/ui/tools/notes.js b/modules/ui/tools/notes.js index bbb4cc325..fe5703f79 100644 --- a/modules/ui/tools/notes.js +++ b/modules/ui/tools/notes.js @@ -15,7 +15,7 @@ export function uiToolNotes(context) { var tool = { id: 'notes', - label: t.html('modes.add_note.label') + label: t.append('modes.add_note.label') }; var mode = modeAddNote(context); diff --git a/modules/ui/tools/save.js b/modules/ui/tools/save.js index 494cb9d93..5b86eab63 100644 --- a/modules/ui/tools/save.js +++ b/modules/ui/tools/save.js @@ -11,7 +11,7 @@ export function uiToolSave(context) { var tool = { id: 'save', - label: t.html('save.title') + label: t.append('save.title') }; var button = null; @@ -57,7 +57,7 @@ export function uiToolSave(context) { if (tooltipBehavior) { tooltipBehavior - .title(t.html(_numChanges > 0 ? 'save.help' : 'save.no_changes')) + .title(() => t.append(_numChanges > 0 ? 'save.help' : 'save.no_changes')) .keys([key]); } @@ -75,7 +75,7 @@ export function uiToolSave(context) { tool.render = function(selection) { tooltipBehavior = uiTooltip() .placement('bottom') - .title(t.html('save.no_changes')) + .title(() => t.append('save.no_changes')) .keys([key]) .scrollContainer(context.container().select('.top-toolbar')); @@ -99,7 +99,7 @@ export function uiToolSave(context) { .duration(2000) .iconName('#iD-icon-save') .iconClass('disabled') - .label(t.html('save.no_changes'))(); + .label(t.append('save.no_changes'))(); } lastPointerUpType = null; }) diff --git a/modules/ui/tools/sidebar_toggle.js b/modules/ui/tools/sidebar_toggle.js index d99051a91..2a1f3cde2 100644 --- a/modules/ui/tools/sidebar_toggle.js +++ b/modules/ui/tools/sidebar_toggle.js @@ -6,7 +6,7 @@ export function uiToolSidebarToggle(context) { var tool = { id: 'sidebar_toggle', - label: t.html('toolbar.inspect') + label: t.append('toolbar.inspect') }; tool.render = function(selection) { @@ -19,7 +19,7 @@ export function uiToolSidebarToggle(context) { }) .call(uiTooltip() .placement('bottom') - .title(t.html('sidebar.tooltip')) + .title(() => t.append('sidebar.tooltip')) .keys([t('sidebar.key')]) .scrollContainer(context.container().select('.top-toolbar')) ) diff --git a/modules/ui/tools/undo_redo.js b/modules/ui/tools/undo_redo.js index d8b7b4e5d..626729bbe 100644 --- a/modules/ui/tools/undo_redo.js +++ b/modules/ui/tools/undo_redo.js @@ -14,7 +14,7 @@ export function uiToolUndoRedo(context) { var tool = { id: 'undo_redo', - label: t.html('toolbar.undo_redo') + label: t.append('toolbar.undo_redo') }; var commands = [{ @@ -50,8 +50,8 @@ export function uiToolUndoRedo(context) { .placement('bottom') .title(function (d) { return d.annotation() ? - t.html(d.id + '.tooltip', { action: d.annotation() }) : - t.html(d.id + '.nothing'); + t.append(d.id + '.tooltip', { action: d.annotation() }) : + t.append(d.id + '.nothing'); }) .keys(function(d) { return [d.cmd]; @@ -84,14 +84,14 @@ export function uiToolUndoRedo(context) { ) { // there are no tooltips for touch interactions so flash feedback instead - var text = annotation ? - t.html(d.id + '.tooltip', { action: annotation }) : - t.html(d.id + '.nothing'); + var label = annotation ? + t.append(d.id + '.tooltip', { action: annotation }) : + t.append(d.id + '.nothing'); context.ui().flash .duration(2000) .iconName('#' + d.icon) .iconClass(annotation ? '' : 'disabled') - .label(text)(); + .label(label)(); } lastPointerUpType = null; }) diff --git a/modules/ui/tooltip.js b/modules/ui/tooltip.js index d5f040331..e54b508fb 100644 --- a/modules/ui/tooltip.js +++ b/modules/ui/tooltip.js @@ -45,6 +45,9 @@ export function uiTooltip(klass) { var text = _title.apply(this, arguments); var keys = _keys.apply(this, arguments); + var headingCallback = typeof heading === 'function' ? heading : s => s.text(heading); + var textCallback = typeof text === 'function' ? text : s => s.text(text); + return function(selection) { var headingSelect = selection @@ -58,7 +61,8 @@ export function uiTooltip(klass) { .append('div') .attr('class', 'tooltip-heading') .merge(headingSelect) - .html(heading); + .text('') + .call(headingCallback); var textSelect = selection .selectAll('.tooltip-text') @@ -71,7 +75,8 @@ export function uiTooltip(klass) { .append('div') .attr('class', 'tooltip-text') .merge(textSelect) - .html(text); + .text('') + .call(textCallback); var keyhintWrap = selection .selectAll('.keyhint-wrap') @@ -95,7 +100,7 @@ export function uiTooltip(klass) { .enter() .append('kbd') .attr('class', 'shortcut') - .html(function(d) { + .text(function(d) { return d; }); }; diff --git a/modules/ui/top_toolbar.js b/modules/ui/top_toolbar.js index ec66b090e..2fcaa408c 100644 --- a/modules/ui/top_toolbar.js +++ b/modules/ui/top_toolbar.js @@ -85,9 +85,7 @@ export function uiTopToolbar(context) { actionableItems .append('div') .attr('class', 'item-label') - .html(function(d) { - return d.label; - }); + .each(function(d) { d.label(d3_select(this)); }); } } diff --git a/modules/ui/version.js b/modules/ui/version.js index 1c178294c..9c26b1bd5 100644 --- a/modules/ui/version.js +++ b/modules/ui/version.js @@ -43,7 +43,7 @@ export function uiVersion(context) { .attr('href', 'https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new') .call(svgIcon('#maki-gift')) .call(uiTooltip() - .title(t.html('version.whats_new', { version: currVersion })) + .title(() => t.append('version.whats_new', { version: currVersion })) .placement('top') .scrollContainer(context.container().select('.main-footer-wrap')) ); diff --git a/modules/ui/zoom.js b/modules/ui/zoom.js index 9a4eea629..f707e850c 100644 --- a/modules/ui/zoom.js +++ b/modules/ui/zoom.js @@ -14,22 +14,22 @@ export function uiZoom(context) { var zooms = [{ id: 'zoom-in', icon: 'iD-icon-plus', - title: t.html('zoom.in'), + title: t.append('zoom.in'), action: zoomIn, disabled: function() { return !context.map().canZoomIn(); }, - disabledTitle: t.html('zoom.disabled.in'), + disabledTitle: t.append('zoom.disabled.in'), key: '+' }, { id: 'zoom-out', icon: 'iD-icon-minus', - title: t.html('zoom.out'), + title: t.append('zoom.out'), action: zoomOut, disabled: function() { return !context.map().canZoomOut(); }, - disabledTitle: t.html('zoom.disabled.out'), + disabledTitle: t.append('zoom.disabled.out'), key: '-' }]; diff --git a/modules/ui/zoom_to_selection.js b/modules/ui/zoom_to_selection.js index 5913295a2..39f26584c 100644 --- a/modules/ui/zoom_to_selection.js +++ b/modules/ui/zoom_to_selection.js @@ -24,7 +24,7 @@ export function uiZoomToSelection(context) { .duration(2000) .iconName('#iD-icon-framed-dot') .iconClass('disabled') - .label(t.html('inspector.zoom_to.no_selection'))(); + .label(t.append('inspector.zoom_to.no_selection'))(); } } else { var mode = context.mode(); @@ -42,9 +42,9 @@ export function uiZoomToSelection(context) { .placement((localizer.textDirection() === 'rtl') ? 'right' : 'left') .title(function() { if (isDisabled()) { - return t.html('inspector.zoom_to.no_selection'); + return t.append('inspector.zoom_to.no_selection'); } - return t.html('inspector.zoom_to.title'); + return t.append('inspector.zoom_to.title'); }) .keys([t('inspector.zoom_to.key')]); From 85022dcc6c9421e9f6c87068d8bfeec01a90aafd Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Thu, 23 Jun 2022 19:09:10 +0200 Subject: [PATCH 4/9] render operations texts with lang attribute --- modules/modes/select.js | 2 +- modules/operations/circularize.js | 6 +++--- modules/operations/continue.js | 6 +++--- modules/operations/copy.js | 6 +++--- modules/operations/delete.js | 6 +++--- modules/operations/disconnect.js | 9 ++++----- modules/operations/downgrade.js | 6 +++--- modules/operations/extract.js | 6 +++--- modules/operations/merge.js | 10 +++++----- modules/operations/move.js | 6 +++--- modules/operations/orthogonalize.js | 6 +++--- modules/operations/paste.js | 6 +++--- modules/operations/reflect.js | 6 +++--- modules/operations/reverse.js | 4 ++-- modules/operations/rotate.js | 6 +++--- modules/operations/split.js | 7 ++++--- modules/operations/straighten.js | 6 +++--- modules/ui/edit_menu.js | 4 ++-- modules/ui/flash.js | 2 +- 19 files changed, 55 insertions(+), 55 deletions(-) diff --git a/modules/modes/select.js b/modules/modes/select.js index 6af3acd4d..d8c75802a 100644 --- a/modules/modes/select.js +++ b/modules/modes/select.js @@ -327,7 +327,7 @@ export function modeSelect(context, selectedIDs) { .duration(4000) .iconName('#iD-operation-' + moveOp.id) .iconClass('operation disabled') - .label(moveOp.tooltip)(); + .label(moveOp.tooltip())(); } else { context.perform(actionMove(selectedIDs, delta, context.projection), moveOp.annotation()); context.validator().validate(); diff --git a/modules/operations/circularize.js b/modules/operations/circularize.js index b7497c045..184c85dbb 100644 --- a/modules/operations/circularize.js +++ b/modules/operations/circularize.js @@ -96,8 +96,8 @@ export function operationCircularize(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.circularize.' + disable + '.' + _amount) : - t('operations.circularize.description.' + _amount); + t.append('operations.circularize.' + disable + '.' + _amount) : + t.append('operations.circularize.description.' + _amount); }; @@ -108,7 +108,7 @@ export function operationCircularize(context, selectedIDs) { operation.id = 'circularize'; operation.keys = [t('operations.circularize.key')]; - operation.title = t('operations.circularize.title'); + operation.title = t.append('operations.circularize.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/continue.js b/modules/operations/continue.js index 0f5a52941..e6d79fb39 100644 --- a/modules/operations/continue.js +++ b/modules/operations/continue.js @@ -60,8 +60,8 @@ export function operationContinue(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.continue.' + disable) : - t('operations.continue.description'); + t.append('operations.continue.' + disable) : + t.append('operations.continue.description'); }; @@ -72,7 +72,7 @@ export function operationContinue(context, selectedIDs) { operation.id = 'continue'; operation.keys = [t('operations.continue.key')]; - operation.title = t('operations.continue.title'); + operation.title = t.append('operations.continue.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/copy.js b/modules/operations/copy.js index 13c456b83..7bd1f86f0 100644 --- a/modules/operations/copy.js +++ b/modules/operations/copy.js @@ -113,8 +113,8 @@ export function operationCopy(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.copy.' + disable, { n: selectedIDs.length }) : - t('operations.copy.description', { n: selectedIDs.length }); + t.append('operations.copy.' + disable, { n: selectedIDs.length }) : + t.append('operations.copy.description', { n: selectedIDs.length }); }; @@ -132,7 +132,7 @@ export function operationCopy(context, selectedIDs) { operation.id = 'copy'; operation.keys = [uiCmd('⌘C')]; - operation.title = t('operations.copy.title'); + operation.title = t.append('operations.copy.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/delete.js b/modules/operations/delete.js index 9a7bd8ce6..3f365be48 100644 --- a/modules/operations/delete.js +++ b/modules/operations/delete.js @@ -131,8 +131,8 @@ export function operationDelete(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.delete.' + disable + '.' + multi) : - t('operations.delete.description.' + multi); + t.append('operations.delete.' + disable + '.' + multi) : + t.append('operations.delete.description.' + multi); }; @@ -145,7 +145,7 @@ export function operationDelete(context, selectedIDs) { operation.id = 'delete'; operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')]; - operation.title = t('operations.delete.title'); + operation.title = t.append('operations.delete.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/disconnect.js b/modules/operations/disconnect.js index 691f8fa00..ccd476e40 100644 --- a/modules/operations/disconnect.js +++ b/modules/operations/disconnect.js @@ -189,10 +189,9 @@ export function operationDisconnect(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); - if (disable) { - return t('operations.disconnect.' + disable); - } - return t('operations.disconnect.description.' + _descriptionID); + return disable ? + t.append('operations.disconnect.' + disable) : + t.append('operations.disconnect.description.' + _descriptionID); }; @@ -203,7 +202,7 @@ export function operationDisconnect(context, selectedIDs) { operation.id = 'disconnect'; operation.keys = [t('operations.disconnect.key')]; - operation.title = t('operations.disconnect.title'); + operation.title = t.append('operations.disconnect.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/downgrade.js b/modules/operations/downgrade.js index 7177cf9af..8c5f7c326 100644 --- a/modules/operations/downgrade.js +++ b/modules/operations/downgrade.js @@ -120,8 +120,8 @@ export function operationDowngrade(context, selectedIDs) { operation.tooltip = function () { var disable = operation.disabled(); return disable ? - t('operations.downgrade.' + disable + '.' + _multi) : - t('operations.downgrade.description.' + _downgradeType); + t.append('operations.downgrade.' + disable + '.' + _multi) : + t.append('operations.downgrade.description.' + _downgradeType); }; @@ -138,7 +138,7 @@ export function operationDowngrade(context, selectedIDs) { operation.id = 'downgrade'; operation.keys = [uiCmd('⌫')]; - operation.title = t('operations.downgrade.title'); + operation.title = t.append('operations.downgrade.title'); operation.behavior = behaviorOperation(context).which(operation); diff --git a/modules/operations/extract.js b/modules/operations/extract.js index a6ea27f5f..43ddfde7a 100644 --- a/modules/operations/extract.js +++ b/modules/operations/extract.js @@ -71,9 +71,9 @@ export function operationExtract(context, selectedIDs) { operation.tooltip = function () { var disableReason = operation.disabled(); if (disableReason) { - return t('operations.extract.' + disableReason + '.' + _amount); + return t.append('operations.extract.' + disableReason + '.' + _amount); } else { - return t('operations.extract.description.' + _geometryID + '.' + _amount); + return t.append('operations.extract.description.' + _geometryID + '.' + _amount); } }; @@ -85,7 +85,7 @@ export function operationExtract(context, selectedIDs) { operation.id = 'extract'; operation.keys = [t('operations.extract.key')]; - operation.title = t('operations.extract.title'); + operation.title = t.append('operations.extract.title'); operation.behavior = behaviorOperation(context).which(operation); diff --git a/modules/operations/merge.js b/modules/operations/merge.js index f61a016cf..60b4baed1 100644 --- a/modules/operations/merge.js +++ b/modules/operations/merge.js @@ -75,15 +75,15 @@ export function operationMerge(context, selectedIDs) { var disabled = operation.disabled(); if (disabled) { if (disabled === 'conflicting_relations') { - return t('operations.merge.conflicting_relations'); + return t.append('operations.merge.conflicting_relations'); } if (disabled === 'restriction' || disabled === 'connectivity') { - return t('operations.merge.damage_relation', + return t.append('operations.merge.damage_relation', { relation: presetManager.item('type/' + disabled).name() }); } - return t('operations.merge.' + disabled); + return t.append('operations.merge.' + disabled); } - return t('operations.merge.description'); + return t.append('operations.merge.description'); }; operation.annotation = function() { @@ -92,7 +92,7 @@ export function operationMerge(context, selectedIDs) { operation.id = 'merge'; operation.keys = [t('operations.merge.key')]; - operation.title = t('operations.merge.title'); + operation.title = t.append('operations.merge.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/move.js b/modules/operations/move.js index 677709d92..298acb18b 100644 --- a/modules/operations/move.js +++ b/modules/operations/move.js @@ -58,8 +58,8 @@ export function operationMove(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.move.' + disable + '.' + multi) : - t('operations.move.description.' + multi); + t.append('operations.move.' + disable + '.' + multi) : + t.append('operations.move.description.' + multi); }; @@ -72,7 +72,7 @@ export function operationMove(context, selectedIDs) { operation.id = 'move'; operation.keys = [t('operations.move.key')]; - operation.title = t('operations.move.title'); + operation.title = t.append('operations.move.title'); operation.behavior = behaviorOperation(context).which(operation); operation.mouseOnly = true; diff --git a/modules/operations/orthogonalize.js b/modules/operations/orthogonalize.js index c8b89445d..a62dd6aa2 100644 --- a/modules/operations/orthogonalize.js +++ b/modules/operations/orthogonalize.js @@ -119,8 +119,8 @@ export function operationOrthogonalize(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.orthogonalize.' + disable + '.' + _amount) : - t('operations.orthogonalize.description.' + _type + '.' + _amount); + t.append('operations.orthogonalize.' + disable + '.' + _amount) : + t.append('operations.orthogonalize.description.' + _type + '.' + _amount); }; @@ -131,7 +131,7 @@ export function operationOrthogonalize(context, selectedIDs) { operation.id = 'orthogonalize'; operation.keys = [t('operations.orthogonalize.key')]; - operation.title = t('operations.orthogonalize.title'); + operation.title = t.append('operations.orthogonalize.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/paste.js b/modules/operations/paste.js index 30e61d222..6c17d4f3d 100644 --- a/modules/operations/paste.js +++ b/modules/operations/paste.js @@ -76,9 +76,9 @@ export function operationPaste(context) { var oldGraph = context.copyGraph(); var ids = context.copyIDs(); if (!ids.length) { - return t('operations.paste.nothing_copied'); + return t.append('operations.paste.nothing_copied'); } - return t('operations.paste.description', { feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph), n: ids.length }); + return t.append('operations.paste.description', { feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph), n: ids.length }); }; operation.annotation = function() { @@ -88,7 +88,7 @@ export function operationPaste(context) { operation.id = 'paste'; operation.keys = [uiCmd('⌘V')]; - operation.title = t('operations.paste.title'); + operation.title = t.append('operations.paste.title'); return operation; } diff --git a/modules/operations/reflect.js b/modules/operations/reflect.js index 2a0e17271..51872b306 100644 --- a/modules/operations/reflect.js +++ b/modules/operations/reflect.js @@ -77,8 +77,8 @@ export function operationReflect(context, selectedIDs, axis) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.reflect.' + disable + '.' + multi) : - t('operations.reflect.description.' + axis + '.' + multi); + t.append('operations.reflect.' + disable + '.' + multi) : + t.append('operations.reflect.description.' + axis + '.' + multi); }; @@ -89,7 +89,7 @@ export function operationReflect(context, selectedIDs, axis) { operation.id = 'reflect-' + axis; operation.keys = [t('operations.reflect.key.' + axis)]; - operation.title = t('operations.reflect.title.' + axis); + operation.title = t.append('operations.reflect.title.' + axis); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/reverse.js b/modules/operations/reverse.js index c4a01d36d..b2b3274b3 100644 --- a/modules/operations/reverse.js +++ b/modules/operations/reverse.js @@ -58,7 +58,7 @@ export function operationReverse(context, selectedIDs) { operation.tooltip = function() { - return t('operations.reverse.description.' + reverseTypeID()); + return t.append('operations.reverse.description.' + reverseTypeID()); }; @@ -70,7 +70,7 @@ export function operationReverse(context, selectedIDs) { operation.id = 'reverse'; operation.keys = [t('operations.reverse.key')]; - operation.title = t('operations.reverse.title'); + operation.title = t.append('operations.reverse.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/rotate.js b/modules/operations/rotate.js index b8a4c5ea6..c9d13d7a6 100644 --- a/modules/operations/rotate.js +++ b/modules/operations/rotate.js @@ -59,8 +59,8 @@ export function operationRotate(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.rotate.' + disable + '.' + multi) : - t('operations.rotate.description.' + multi); + t.append('operations.rotate.' + disable + '.' + multi) : + t.append('operations.rotate.description.' + multi); }; @@ -73,7 +73,7 @@ export function operationRotate(context, selectedIDs) { operation.id = 'rotate'; operation.keys = [t('operations.rotate.key')]; - operation.title = t('operations.rotate.title'); + operation.title = t.append('operations.rotate.title'); operation.behavior = behaviorOperation(context).which(operation); operation.mouseOnly = true; diff --git a/modules/operations/split.js b/modules/operations/split.js index 583f2db47..771511428 100644 --- a/modules/operations/split.js +++ b/modules/operations/split.js @@ -68,8 +68,9 @@ export function operationSplit(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); - if (disable) return t('operations.split.' + disable); - return t('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node'); + return disable ? + t.append('operations.split.' + disable) : + t.append('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node'); }; @@ -89,7 +90,7 @@ export function operationSplit(context, selectedIDs) { operation.id = 'split'; operation.keys = [t('operations.split.key')]; - operation.title = t('operations.split.title'); + operation.title = t.append('operations.split.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/operations/straighten.js b/modules/operations/straighten.js index 56b5b4050..33c275700 100644 --- a/modules/operations/straighten.js +++ b/modules/operations/straighten.js @@ -124,8 +124,8 @@ export function operationStraighten(context, selectedIDs) { operation.tooltip = function() { var disable = operation.disabled(); return disable ? - t('operations.straighten.' + disable + '.' + _amount) : - t('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's')); + t.append('operations.straighten.' + disable + '.' + _amount) : + t.append('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's')); }; @@ -136,7 +136,7 @@ export function operationStraighten(context, selectedIDs) { operation.id = 'straighten'; operation.keys = [t('operations.straighten.key')]; - operation.title = t('operations.straighten.title'); + operation.title = t.append('operations.straighten.title'); operation.behavior = behaviorOperation(context).which(operation); return operation; diff --git a/modules/ui/edit_menu.js b/modules/ui/edit_menu.js index 4b199e98a..173e1144b 100644 --- a/modules/ui/edit_menu.js +++ b/modules/ui/edit_menu.js @@ -104,7 +104,7 @@ export function uiEditMenu(context) { buttonsEnter.each(function(d) { var tooltip = uiTooltip() - .heading(d.title) + .heading(() => d.title) .title(d.tooltip) .keys([d.keys[0]]); @@ -164,7 +164,7 @@ export function uiEditMenu(context) { .duration(4000) .iconName('#iD-operation-' + operation.id) .iconClass('operation disabled') - .label(operation.tooltip)(); + .label(operation.tooltip())(); } } else { if (lastPointerUpType === 'touch' || diff --git a/modules/ui/flash.js b/modules/ui/flash.js index 82062025c..592f0ecb2 100644 --- a/modules/ui/flash.js +++ b/modules/ui/flash.js @@ -92,7 +92,7 @@ export function uiFlash(context) { if (typeof _ !== 'function') { _label = selection => selection.text(_); } else { - _label = _; + _label = selection => s_; } return flash; }; From 28eae9ed878ae2a8ebd806708acb8ce120924f74 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 24 Jun 2022 11:45:54 +0200 Subject: [PATCH 5/9] refactor uiSections to not inject html --- modules/ui/disclosure.js | 9 +++++++-- modules/ui/sections/background_display_options.js | 2 +- modules/ui/sections/background_list.js | 2 +- modules/ui/sections/background_offset.js | 2 +- modules/ui/sections/changes.js | 2 +- modules/ui/sections/data_layers.js | 2 +- modules/ui/sections/entity_issues.js | 2 +- modules/ui/sections/feature_type.js | 2 +- modules/ui/sections/map_features.js | 2 +- modules/ui/sections/map_style_options.js | 2 +- modules/ui/sections/overlay_list.js | 2 +- modules/ui/sections/photo_overlays.js | 2 +- modules/ui/sections/preset_fields.js | 2 +- modules/ui/sections/privacy.js | 2 +- modules/ui/sections/raw_member_editor.js | 2 +- modules/ui/sections/raw_membership_editor.js | 2 +- modules/ui/sections/raw_tag_editor.js | 2 +- modules/ui/sections/selection_list.js | 2 +- modules/ui/sections/validation_issues.js | 2 +- modules/ui/sections/validation_rules.js | 2 +- modules/ui/splash.js | 2 +- 21 files changed, 27 insertions(+), 22 deletions(-) diff --git a/modules/ui/disclosure.js b/modules/ui/disclosure.js index 474155a3b..d12c19bf9 100644 --- a/modules/ui/disclosure.js +++ b/modules/ui/disclosure.js @@ -51,8 +51,13 @@ export function uiDisclosure(context, key, expandedDefault) { .attr('aria-expanded', _expanded) .classed('expanded', _expanded); - hideToggle.selectAll('.hide-toggle-text') - .html(_label()); + const label = _label(); + const labelSelection = hideToggle.selectAll('.hide-toggle-text'); + if (typeof label !== 'function') { + labelSelection.text(_label()); + } else { + labelSelection.text('').call(label); + } hideToggle.selectAll('.hide-toggle-icon') .attr('xlink:href', _expanded ? '#iD-icon-down' diff --git a/modules/ui/sections/background_display_options.js b/modules/ui/sections/background_display_options.js index 1d4a49f5f..f852c853d 100644 --- a/modules/ui/sections/background_display_options.js +++ b/modules/ui/sections/background_display_options.js @@ -11,7 +11,7 @@ import { uiSection } from '../section'; export function uiSectionBackgroundDisplayOptions(context) { var section = uiSection('background-display-options', context) - .label(t.html('background.display_options')) + .label(() => t.append('background.display_options')) .disclosureContent(renderDisclosureContent); var _storedOpacity = prefs('background-opacity'); diff --git a/modules/ui/sections/background_list.js b/modules/ui/sections/background_list.js index 6d51f2d0b..39c6c7a71 100644 --- a/modules/ui/sections/background_list.js +++ b/modules/ui/sections/background_list.js @@ -21,7 +21,7 @@ export function uiSectionBackgroundList(context) { .on('change', customChanged); var section = uiSection('background-list', context) - .label(t.html('background.backgrounds')) + .label(() => t.append('background.backgrounds')) .disclosureContent(renderDisclosureContent); function previousBackgroundID() { diff --git a/modules/ui/sections/background_offset.js b/modules/ui/sections/background_offset.js index 13cef389c..d7db05862 100644 --- a/modules/ui/sections/background_offset.js +++ b/modules/ui/sections/background_offset.js @@ -11,7 +11,7 @@ import { uiSection } from '../section'; export function uiSectionBackgroundOffset(context) { var section = uiSection('background-offset', context) - .label(t.html('background.fix_misalignment')) + .label(() => t.append('background.fix_misalignment')) .disclosureContent(renderDisclosureContent) .expandedByDefault(false); diff --git a/modules/ui/sections/changes.js b/modules/ui/sections/changes.js index 77d3b37ed..32abc0211 100644 --- a/modules/ui/sections/changes.js +++ b/modules/ui/sections/changes.js @@ -26,7 +26,7 @@ export function uiSectionChanges(context) { .label(function() { var history = context.history(); var summary = history.difference().summary(); - return t.html('inspector.title_count', { title: { html: t.html('commit.changes') }, count: summary.length }); + return t.append('inspector.title_count', { title: t('commit.changes'), count: summary.length }); }) .disclosureContent(renderDisclosureContent); diff --git a/modules/ui/sections/data_layers.js b/modules/ui/sections/data_layers.js index 9580aae5a..c8f469d29 100644 --- a/modules/ui/sections/data_layers.js +++ b/modules/ui/sections/data_layers.js @@ -21,7 +21,7 @@ export function uiSectionDataLayers(context) { var layers = context.layers(); var section = uiSection('data-layers', context) - .label(t.html('map_data.data_layers')) + .label(() => t.append('map_data.data_layers')) .disclosureContent(renderDisclosureContent); function renderDisclosureContent(selection) { diff --git a/modules/ui/sections/entity_issues.js b/modules/ui/sections/entity_issues.js index f0ae094f7..be528ae80 100644 --- a/modules/ui/sections/entity_issues.js +++ b/modules/ui/sections/entity_issues.js @@ -24,7 +24,7 @@ export function uiSectionEntityIssues(context) { return _issues.length > 0; }) .label(function() { - return t.html('inspector.title_count', { title: { html: t.html('issues.list_title') }, count: _issues.length }); + return t.append('inspector.title_count', { title: t('issues.list_title'), count: _issues.length }); }) .disclosureContent(renderDisclosureContent); diff --git a/modules/ui/sections/feature_type.js b/modules/ui/sections/feature_type.js index e4877484c..403591cdd 100644 --- a/modules/ui/sections/feature_type.js +++ b/modules/ui/sections/feature_type.js @@ -20,7 +20,7 @@ export function uiSectionFeatureType(context) { var _tagReference; var section = uiSection('feature-type', context) - .label(t.html('inspector.feature_type')) + .label(() => t.append('inspector.feature_type')) .disclosureContent(renderDisclosureContent); function renderDisclosureContent(selection) { diff --git a/modules/ui/sections/map_features.js b/modules/ui/sections/map_features.js index ad12ec4f5..040a729c4 100644 --- a/modules/ui/sections/map_features.js +++ b/modules/ui/sections/map_features.js @@ -7,7 +7,7 @@ export function uiSectionMapFeatures(context) { var _features = context.features().keys(); var section = uiSection('map-features', context) - .label(t.html('map_data.map_features')) + .label(() => t.append('map_data.map_features')) .disclosureContent(renderDisclosureContent) .expandedByDefault(false); diff --git a/modules/ui/sections/map_style_options.js b/modules/ui/sections/map_style_options.js index eac759aa9..ed6a620e1 100644 --- a/modules/ui/sections/map_style_options.js +++ b/modules/ui/sections/map_style_options.js @@ -5,7 +5,7 @@ import { uiSection } from '../section'; export function uiSectionMapStyleOptions(context) { var section = uiSection('fill-area', context) - .label(t.html('map_data.style_options')) + .label(() => t.append('map_data.style_options')) .disclosureContent(renderDisclosureContent) .expandedByDefault(false); diff --git a/modules/ui/sections/overlay_list.js b/modules/ui/sections/overlay_list.js index 14640ebdc..6252be198 100644 --- a/modules/ui/sections/overlay_list.js +++ b/modules/ui/sections/overlay_list.js @@ -11,7 +11,7 @@ import { uiSection } from '../section'; export function uiSectionOverlayList(context) { var section = uiSection('overlay-list', context) - .label(t.html('background.overlays')) + .label(() => t.append('background.overlays')) .disclosureContent(renderDisclosureContent); var _overlayList = d3_select(null); diff --git a/modules/ui/sections/photo_overlays.js b/modules/ui/sections/photo_overlays.js index 79930ea5a..7d5c76fe6 100644 --- a/modules/ui/sections/photo_overlays.js +++ b/modules/ui/sections/photo_overlays.js @@ -12,7 +12,7 @@ export function uiSectionPhotoOverlays(context) { var layers = context.layers(); var section = uiSection('photo-overlays', context) - .label(t.html('photo_overlays.title')) + .label(() => t.append('photo_overlays.title')) .disclosureContent(renderDisclosureContent) .expandedByDefault(false); diff --git a/modules/ui/sections/preset_fields.js b/modules/ui/sections/preset_fields.js index 6cafc4e6a..34a1b9b1a 100644 --- a/modules/ui/sections/preset_fields.js +++ b/modules/ui/sections/preset_fields.js @@ -12,7 +12,7 @@ import { uiSection } from '../section'; export function uiSectionPresetFields(context) { var section = uiSection('preset-fields', context) - .label(t.html('inspector.fields')) + .label(() => t.append('inspector.fields')) .disclosureContent(renderDisclosureContent); var dispatch = d3_dispatch('change', 'revert'); diff --git a/modules/ui/sections/privacy.js b/modules/ui/sections/privacy.js index 12547555d..bd11c0259 100644 --- a/modules/ui/sections/privacy.js +++ b/modules/ui/sections/privacy.js @@ -6,7 +6,7 @@ import { uiSection } from '../section'; export function uiSectionPrivacy(context) { let section = uiSection('preferences-third-party', context) - .label(t.html('preferences.privacy.title')) + .label(() => t.append('preferences.privacy.title')) .disclosureContent(renderDisclosureContent); function renderDisclosureContent(selection) { diff --git a/modules/ui/sections/raw_member_editor.js b/modules/ui/sections/raw_member_editor.js index f33f28907..ab5942785 100644 --- a/modules/ui/sections/raw_member_editor.js +++ b/modules/ui/sections/raw_member_editor.js @@ -33,7 +33,7 @@ export function uiSectionRawMemberEditor(context) { var gt = entity.members.length > _maxMembers ? '>' : ''; var count = gt + entity.members.slice(0, _maxMembers).length; - return t.html('inspector.title_count', { title: { html: t.html('inspector.members') }, count: count }); + return t.append('inspector.title_count', { title: t('inspector.members'), count: count }); }) .disclosureContent(renderDisclosureContent); diff --git a/modules/ui/sections/raw_membership_editor.js b/modules/ui/sections/raw_membership_editor.js index 9f44d8d99..093df5d4b 100644 --- a/modules/ui/sections/raw_membership_editor.js +++ b/modules/ui/sections/raw_membership_editor.js @@ -31,7 +31,7 @@ export function uiSectionRawMembershipEditor(context) { var parents = getSharedParentRelations(); var gt = parents.length > _maxMemberships ? '>' : ''; var count = gt + parents.slice(0, _maxMemberships).length; - return t.html('inspector.title_count', { title: { html: t.html('inspector.relations') }, count: count }); + return t.append('inspector.title_count', { title: t('inspector.relations'), count: count }); }) .disclosureContent(renderDisclosureContent); diff --git a/modules/ui/sections/raw_tag_editor.js b/modules/ui/sections/raw_tag_editor.js index 6a7caba6a..7d669ed62 100644 --- a/modules/ui/sections/raw_tag_editor.js +++ b/modules/ui/sections/raw_tag_editor.js @@ -19,7 +19,7 @@ export function uiSectionRawTagEditor(id, context) { .classes('raw-tag-editor') .label(function() { var count = Object.keys(_tags).filter(function(d) { return d; }).length; - return t.html('inspector.title_count', { title: { html: t.html('inspector.tags') }, count: count }); + return t.append('inspector.title_count', { title: t('inspector.tags'), count: count }); }) .expandedByDefault(false) .disclosureContent(renderDisclosureContent); diff --git a/modules/ui/sections/selection_list.js b/modules/ui/sections/selection_list.js index ad6830863..bb0ba46c9 100644 --- a/modules/ui/sections/selection_list.js +++ b/modules/ui/sections/selection_list.js @@ -17,7 +17,7 @@ export function uiSectionSelectionList(context) { return _selectedIDs.length > 1; }) .label(function() { - return t.html('inspector.title_count', { title: { html: t.html('inspector.features') }, count: _selectedIDs.length }); + return t.append('inspector.title_count', { title: t('inspector.features'), count: _selectedIDs.length }); }) .disclosureContent(renderDisclosureContent); diff --git a/modules/ui/sections/validation_issues.js b/modules/ui/sections/validation_issues.js index 540ef8f55..321379264 100644 --- a/modules/ui/sections/validation_issues.js +++ b/modules/ui/sections/validation_issues.js @@ -19,7 +19,7 @@ export function uiSectionValidationIssues(id, severity, context) { .label(function() { if (!_issues) return ''; var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length); - return t.html('inspector.title_count', { title: { html: t.html('issues.' + severity + 's.list_title') }, count: issueCountText }); + return t.append('inspector.title_count', { title: t('issues.' + severity + 's.list_title'), count: issueCountText }); }) .disclosureContent(renderDisclosureContent) .shouldDisplay(function() { diff --git a/modules/ui/sections/validation_rules.js b/modules/ui/sections/validation_rules.js index 6fe7f5931..de2b895ef 100644 --- a/modules/ui/sections/validation_rules.js +++ b/modules/ui/sections/validation_rules.js @@ -16,7 +16,7 @@ export function uiSectionValidationRules(context) { var section = uiSection('issues-rules', context) .disclosureContent(renderDisclosureContent) - .label(t.html('issues.rules.title')); + .label(() => t.append('issues.rules.title')); var _ruleKeys = context.validator().getRuleKeys() .filter(function(key) { return key !== 'maprules'; }) diff --git a/modules/ui/splash.js b/modules/ui/splash.js index 992585e69..e0d8f7989 100644 --- a/modules/ui/splash.js +++ b/modules/ui/splash.js @@ -66,7 +66,7 @@ export function uiSplash(context) { })); uiSectionPrivacy(context) - .label(t.html('splash.privacy_settings')) + .label(() => t.append('splash.privacy_settings')) .render(modalSection); let buttonWrap = introModal From 6626ea0682aca372145c24be39aee991882ee12e Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 24 Jun 2022 12:19:17 +0200 Subject: [PATCH 6/9] refactor panels to not inject html --- modules/ui/info.js | 2 +- modules/ui/panels/background.js | 2 +- modules/ui/panels/history.js | 2 +- modules/ui/panels/location.js | 2 +- modules/ui/panels/measurement.js | 2 +- modules/ui/success.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/ui/info.js b/modules/ui/info.js index f06f9dd8d..5baac3c90 100644 --- a/modules/ui/info.js +++ b/modules/ui/info.js @@ -58,7 +58,7 @@ export function uiInfo(context) { title .append('h3') - .html(function(d) { return panels[d].label; }); + .each(function(d) { return panels[d].label(d3_select(this)); }); title .append('button') diff --git a/modules/ui/panels/background.js b/modules/ui/panels/background.js index 6668d83a8..18b045b98 100644 --- a/modules/ui/panels/background.js +++ b/modules/ui/panels/background.js @@ -159,7 +159,7 @@ export function uiPanelBackground(context) { }; panel.id = 'background'; - panel.label = t.html('info_panels.background.title'); + panel.label = t.append('info_panels.background.title'); panel.key = t('info_panels.background.key'); diff --git a/modules/ui/panels/history.js b/modules/ui/panels/history.js index 614b5f709..8f8841b30 100644 --- a/modules/ui/panels/history.js +++ b/modules/ui/panels/history.js @@ -254,7 +254,7 @@ export function uiPanelHistory(context) { }; panel.id = 'history'; - panel.label = t.html('info_panels.history.title'); + panel.label = t.append('info_panels.history.title'); panel.key = t('info_panels.history.key'); diff --git a/modules/ui/panels/location.js b/modules/ui/panels/location.js index f2b3548d5..a761fc3f0 100644 --- a/modules/ui/panels/location.js +++ b/modules/ui/panels/location.js @@ -68,7 +68,7 @@ export function uiPanelLocation(context) { }; panel.id = 'location'; - panel.label = t.html('info_panels.location.title'); + panel.label = t.append('info_panels.location.title'); panel.key = t('info_panels.location.key'); diff --git a/modules/ui/panels/measurement.js b/modules/ui/panels/measurement.js index e3f7d9dec..b7b154560 100644 --- a/modules/ui/panels/measurement.js +++ b/modules/ui/panels/measurement.js @@ -234,7 +234,7 @@ export function uiPanelMeasurement(context) { }; panel.id = 'measurement'; - panel.label = t.html('info_panels.measurement.title'); + panel.label = t.append('info_panels.measurement.title'); panel.key = t('info_panels.measurement.key'); diff --git a/modules/ui/success.js b/modules/ui/success.js index 3e5ce044b..42d4836e8 100644 --- a/modules/ui/success.js +++ b/modules/ui/success.js @@ -261,7 +261,7 @@ export function uiSuccess(context) { .call(uiDisclosure(context, `community-more-${d.id}`, false) .expanded(false) .updatePreference(false) - .label(t.html('success.more')) + .label(() => t.append('success.more')) .content(showMore) ); } From 8bb1d39431f2f8a076c56e6686d45f32b31506fb Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 24 Jun 2022 12:48:46 +0200 Subject: [PATCH 7/9] refactor validation modules to not inject html --- modules/core/validation/models.js | 2 +- modules/ui/commit_warnings.js | 7 +++++-- modules/ui/conflicts.js | 4 ++-- modules/ui/sections/entity_issues.js | 7 ++++--- modules/ui/sections/validation_issues.js | 5 +++-- modules/validations/almost_junction.js | 6 +++--- modules/validations/close_nodes.js | 12 ++++++------ modules/validations/crossing_ways.js | 12 ++++++------ modules/validations/disconnected_way.js | 10 +++++----- modules/validations/help_request.js | 4 ++-- modules/validations/impossible_oneway.js | 6 +++--- modules/validations/incompatible_source.js | 4 ++-- modules/validations/invalid_format.js | 4 ++-- modules/validations/mismatched_geometry.js | 18 +++++++++--------- modules/validations/missing_role.js | 6 +++--- modules/validations/missing_tag.js | 6 +++--- modules/validations/outdated_tags.js | 10 +++++----- modules/validations/private_data.js | 4 ++-- modules/validations/suspicious_name.js | 8 ++++---- modules/validations/unsquare_way.js | 6 +++--- 20 files changed, 73 insertions(+), 68 deletions(-) diff --git a/modules/core/validation/models.js b/modules/core/validation/models.js index d6215ba6d..770de3398 100644 --- a/modules/core/validation/models.js +++ b/modules/core/validation/models.js @@ -66,7 +66,7 @@ export function validationIssue(attrs) { if (issue.severity === 'warning') { // allow ignoring any issue that's not an error fixes.push(new validationIssueFix({ - title: t.html('issues.fix.ignore_issue.title'), + title: t.append('issues.fix.ignore_issue.title'), icon: 'iD-icon-close', onClick: function() { context.validator().ignoreIssue(this.issue.id); diff --git a/modules/ui/commit_warnings.js b/modules/ui/commit_warnings.js index b83f528fc..d919f6aeb 100644 --- a/modules/ui/commit_warnings.js +++ b/modules/ui/commit_warnings.js @@ -1,3 +1,5 @@ +import { select as d3_select } from 'd3-selection'; + import { t } from '../core/localizer'; import { svgIcon } from '../svg/icon'; import { uiTooltip } from './tooltip'; @@ -89,8 +91,9 @@ export function uiCommitWarnings(context) { .merge(items); items.selectAll('.issue-message') - .html(function(d) { - return d.message(context); + .text('') + .each(function(d) { + return d.message(context)(d3_select(this)); }); } } diff --git a/modules/ui/conflicts.js b/modules/ui/conflicts.js index 7ae7b4c52..bd6400e6d 100644 --- a/modules/ui/conflicts.js +++ b/modules/ui/conflicts.js @@ -205,7 +205,6 @@ export function uiConflicts(context) { .data(['previous', 'next']) .enter() .append('button') - .html(function(d) { return t.html('save.conflict.' + d); }) .attr('class', 'conflict-nav-button action col6') .attr('disabled', function(d, i) { return (i === 0 && index === 0) || @@ -223,7 +222,8 @@ export function uiConflicts(context) { container .call(showConflict, index + sign); - }); + }) + .call(function(d) { t.append('save.conflict.' + d)(d3_select(this)); }); } diff --git a/modules/ui/sections/entity_issues.js b/modules/ui/sections/entity_issues.js index be528ae80..4624bcb8b 100644 --- a/modules/ui/sections/entity_issues.js +++ b/modules/ui/sections/entity_issues.js @@ -180,8 +180,9 @@ export function uiSectionEntityIssues(context) { .classed('active', function(d) { return d.id === _activeIssueID; }); containers.selectAll('.issue-message') - .html(function(d) { - return d.message(context); + .text('') + .each(function(d) { + return d.message(context)(d3_select(this)); }); // fixes @@ -242,7 +243,7 @@ export function uiSectionEntityIssues(context) { buttons .append('span') .attr('class', 'fix-message') - .html(function(d) { return d.title; }); + .each(function(d) { return d.title(d3_select(this)); }); fixesEnter.merge(fixes) .selectAll('button') diff --git a/modules/ui/sections/validation_issues.js b/modules/ui/sections/validation_issues.js index 321379264..5bba750aa 100644 --- a/modules/ui/sections/validation_issues.js +++ b/modules/ui/sections/validation_issues.js @@ -146,8 +146,9 @@ export function uiSectionValidationIssues(id, severity, context) { .order(); items.selectAll('.issue-message') - .html(function(d) { - return d.message(context); + .text('') + .each(function(d) { + return d.message(context)(d3_select(this)); }); /* diff --git a/modules/validations/almost_junction.js b/modules/validations/almost_junction.js index 41daf4759..1f3cf1f2a 100644 --- a/modules/validations/almost_junction.js +++ b/modules/validations/almost_junction.js @@ -55,12 +55,12 @@ export function validationAlmostJunction(context) { message: function(context) { const entity1 = context.hasEntity(this.entityIds[0]); if (this.entityIds[0] === this.entityIds[2]) { - return entity1 ? t.html('issues.almost_junction.self.message', { + return entity1 ? t.append('issues.almost_junction.self.message', { feature: utilDisplayLabel(entity1, context.graph()) }) : ''; } else { const entity2 = context.hasEntity(this.entityIds[2]); - return (entity1 && entity2) ? t.html('issues.almost_junction.message', { + return (entity1 && entity2) ? t.append('issues.almost_junction.message', { feature: utilDisplayLabel(entity1, context.graph()), feature2: utilDisplayLabel(entity2, context.graph()) }) : ''; @@ -88,7 +88,7 @@ export function validationAlmostJunction(context) { function makeFixes(context) { let fixes = [new validationIssueFix({ icon: 'iD-icon-abutment', - title: t.html('issues.fix.connect_features.title'), + title: t.append('issues.fix.connect_features.title'), onClick: function(context) { const annotation = t('issues.fix.connect_almost_junction.annotation'); const [, endNodeId, crossWayId] = this.issue.entityIds; diff --git a/modules/validations/close_nodes.js b/modules/validations/close_nodes.js index a7891081a..c08ac7c30 100644 --- a/modules/validations/close_nodes.js +++ b/modules/validations/close_nodes.js @@ -172,7 +172,7 @@ export function validationCloseNodes(context) { message: function(context) { var entity = context.hasEntity(this.entityIds[0]), entity2 = context.hasEntity(this.entityIds[1]); - return (entity && entity2) ? t.html('issues.close_nodes.detached.message', { + return (entity && entity2) ? t.append('issues.close_nodes.detached.message', { feature: utilDisplayLabel(entity, context.graph()), feature2: utilDisplayLabel(entity2, context.graph()) }) : ''; @@ -183,11 +183,11 @@ export function validationCloseNodes(context) { return [ new validationIssueFix({ icon: 'iD-operation-disconnect', - title: t.html('issues.fix.move_points_apart.title') + title: t.append('issues.fix.move_points_apart.title') }), new validationIssueFix({ icon: 'iD-icon-layers', - title: t.html('issues.fix.use_different_layers_or_levels.title') + title: t.append('issues.fix.use_different_layers_or_levels.title') }) ]; } @@ -237,7 +237,7 @@ export function validationCloseNodes(context) { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.close_nodes.message', { way: utilDisplayLabel(entity, context.graph()) }) : ''; + return entity ? t.append('issues.close_nodes.message', { way: utilDisplayLabel(entity, context.graph()) }) : ''; }, reference: showReference, entityIds: [way.id, node1.id, node2.id], @@ -246,7 +246,7 @@ export function validationCloseNodes(context) { return [ new validationIssueFix({ icon: 'iD-icon-plus', - title: t.html('issues.fix.merge_points.title'), + title: t.append('issues.fix.merge_points.title'), onClick: function(context) { var entityIds = this.issue.entityIds; var action = actionMergeNodes([entityIds[1], entityIds[2]]); @@ -255,7 +255,7 @@ export function validationCloseNodes(context) { }), new validationIssueFix({ icon: 'iD-operation-disconnect', - title: t.html('issues.fix.move_points_apart.title') + title: t.append('issues.fix.move_points_apart.title') }) ]; } diff --git a/modules/validations/crossing_ways.js b/modules/validations/crossing_ways.js index aec7b4094..7c5ad2019 100644 --- a/modules/validations/crossing_ways.js +++ b/modules/validations/crossing_ways.js @@ -407,7 +407,7 @@ export function validationCrossingWays(context) { var graph = context.graph(); var entity1 = graph.hasEntity(this.entityIds[0]), entity2 = graph.hasEntity(this.entityIds[1]); - return (entity1 && entity2) ? t.html('issues.crossing_ways.message', { + return (entity1 && entity2) ? t.append('issues.crossing_ways.message', { feature: utilDisplayLabel(entity1, graph), feature2: utilDisplayLabel(entity2, graph) }) : ''; @@ -440,7 +440,7 @@ export function validationCrossingWays(context) { if (isCrossingIndoors) { fixes.push(new validationIssueFix({ icon: 'iD-icon-layers', - title: t.html('issues.fix.use_different_levels.title') + title: t.append('issues.fix.use_different_levels.title') })); } else if (isCrossingTunnels || isCrossingBridges || @@ -469,7 +469,7 @@ export function validationCrossingWays(context) { // repositioning the features is always an option fixes.push(new validationIssueFix({ icon: 'iD-operation-move', - title: t.html('issues.fix.reposition_features.title') + title: t.append('issues.fix.reposition_features.title') })); return fixes; @@ -489,7 +489,7 @@ export function validationCrossingWays(context) { function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel){ return new validationIssueFix({ icon: iconName, - title: t.html('issues.fix.' + fixTitleID + '.title'), + title: t.append('issues.fix.' + fixTitleID + '.title'), onClick: function(context) { var mode = context.mode(); if (!mode || mode.id !== 'select') return; @@ -698,7 +698,7 @@ export function validationCrossingWays(context) { return new validationIssueFix({ icon: 'iD-icon-crossing', - title: t.html('issues.fix.' + fixTitleID + '.title'), + title: t.append('issues.fix.' + fixTitleID + '.title'), onClick: function(context) { var loc = this.issue.loc; var connectionTags = this.issue.data.connectionTags; @@ -742,7 +742,7 @@ export function validationCrossingWays(context) { function makeChangeLayerFix(higherOrLower) { return new validationIssueFix({ icon: 'iD-icon-' + (higherOrLower === 'higher' ? 'up' : 'down'), - title: t.html('issues.fix.tag_this_as_' + higherOrLower + '.title'), + title: t.append('issues.fix.tag_this_as_' + higherOrLower + '.title'), onClick: function(context) { var mode = context.mode(); diff --git a/modules/validations/disconnected_way.js b/modules/validations/disconnected_way.js index 2d7564d58..66504f65f 100644 --- a/modules/validations/disconnected_way.js +++ b/modules/validations/disconnected_way.js @@ -25,7 +25,7 @@ export function validationDisconnectedWay() { message: function(context) { var entity = this.entityIds.length && context.hasEntity(this.entityIds[0]); var label = entity && utilDisplayLabel(entity, context.graph()); - return t.html('issues.disconnected_way.routable.message', { count: this.entityIds.length, highway: label }); + return t.append('issues.disconnected_way.routable.message', { count: this.entityIds.length, highway: label }); }, reference: showReference, entityIds: Array.from(routingIslandWays).map(function(way) { return way.id; }), @@ -53,13 +53,13 @@ export function validationDisconnectedWay() { } if (!fixes.length) { fixes.push(new validationIssueFix({ - title: t.html('issues.fix.connect_feature.title') + title: t.append('issues.fix.connect_feature.title') })); } fixes.push(new validationIssueFix({ icon: 'iD-operation-delete', - title: t.html('issues.fix.delete_feature.title'), + title: t.append('issues.fix.delete_feature.title'), entityIds: [singleEntity.id], onClick: function(context) { var id = this.issue.entityIds[0]; @@ -71,7 +71,7 @@ export function validationDisconnectedWay() { })); } else { fixes.push(new validationIssueFix({ - title: t.html('issues.fix.connect_features.title') + title: t.append('issues.fix.connect_features.title') })); } @@ -184,7 +184,7 @@ export function validationDisconnectedWay() { return new validationIssueFix({ icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''), - title: t.html('issues.fix.continue_from_' + whichEnd + '.title'), + title: t.append('issues.fix.continue_from_' + whichEnd + '.title'), entityIds: [vertexID], onClick: function(context) { var wayId = this.issue.entityIds[0]; diff --git a/modules/validations/help_request.js b/modules/validations/help_request.js index 514ec61e4..830d7c3e1 100644 --- a/modules/validations/help_request.js +++ b/modules/validations/help_request.js @@ -25,14 +25,14 @@ export function validationHelpRequest(context) { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.fixme_tag.message', { + return entity ? t.append('issues.fixme_tag.message', { feature: utilDisplayLabel(entity, context.graph(), true /* verbose */) }) : ''; }, dynamicFixes: function() { return [ new validationIssueFix({ - title: t.html('issues.fix.address_the_concern.title') + title: t.append('issues.fix.address_the_concern.title') }) ]; }, diff --git a/modules/validations/impossible_oneway.js b/modules/validations/impossible_oneway.js index 4b8666df6..23b7d0afe 100644 --- a/modules/validations/impossible_oneway.js +++ b/modules/validations/impossible_oneway.js @@ -162,7 +162,7 @@ export function validationImpossibleOneway() { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.impossible_oneway.' + messageID + '.message', { + return entity ? t.append('issues.impossible_oneway.' + messageID + '.message', { feature: utilDisplayLabel(entity, context.graph()) }) : ''; }, @@ -175,7 +175,7 @@ export function validationImpossibleOneway() { if (attachedOneways.length) { fixes.push(new validationIssueFix({ icon: 'iD-operation-reverse', - title: t.html('issues.fix.reverse_feature.title'), + title: t.append('issues.fix.reverse_feature.title'), entityIds: [way.id], onClick: function(context) { var id = this.issue.entityIds[0]; @@ -189,7 +189,7 @@ export function validationImpossibleOneway() { (!isFirst && textDirection === 'rtl'); fixes.push(new validationIssueFix({ icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''), - title: t.html('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'), + title: t.append('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'), onClick: function(context) { var entityID = this.issue.entityIds[0]; var vertexID = this.issue.entityIds[1]; diff --git a/modules/validations/incompatible_source.js b/modules/validations/incompatible_source.js index cfc93c504..e8367ffd5 100644 --- a/modules/validations/incompatible_source.js +++ b/modules/validations/incompatible_source.js @@ -43,7 +43,7 @@ export function validationIncompatibleSource() { severity: 'warning', message: (context) => { const entity = context.hasEntity(entityID); - return entity ? t.html('issues.incompatible_source.feature.message', { + return entity ? t.append('issues.incompatible_source.feature.message', { feature: utilDisplayLabel(entity, context.graph(), true /* verbose */), value: source }) : ''; @@ -53,7 +53,7 @@ export function validationIncompatibleSource() { hash: source, dynamicFixes: () => { return [ - new validationIssueFix({ title: t.html('issues.fix.remove_proprietary_data.title') }) + new validationIssueFix({ title: t.append('issues.fix.remove_proprietary_data.title') }) ]; } }); diff --git a/modules/validations/invalid_format.js b/modules/validations/invalid_format.js index 1779224b2..069196b9d 100644 --- a/modules/validations/invalid_format.js +++ b/modules/validations/invalid_format.js @@ -55,7 +55,7 @@ export function validationFormatting() { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.invalid_format.website.message' + this.data, + return entity ? t.append('issues.invalid_format.website.message' + this.data, { feature: utilDisplayLabel(entity, context.graph()), site: websites.join(', ') }) : ''; }, reference: showReferenceWebsite, @@ -80,7 +80,7 @@ export function validationFormatting() { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.invalid_format.email.message' + this.data, + return entity ? t.append('issues.invalid_format.email.message' + this.data, { feature: utilDisplayLabel(entity, context.graph()), email: emails.join(', ') }) : ''; }, reference: showReferenceEmail, diff --git a/modules/validations/mismatched_geometry.js b/modules/validations/mismatched_geometry.js index f1eea0646..2eec02ff2 100644 --- a/modules/validations/mismatched_geometry.js +++ b/modules/validations/mismatched_geometry.js @@ -88,7 +88,7 @@ export function validationMismatchedGeometry() { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.tag_suggests_area.message', { + return entity ? t.append('issues.tag_suggests_area.message', { feature: utilDisplayLabel(entity, 'area', true /* verbose */), tag: utilTagText({ tags: tagSuggestingArea }) }) : ''; @@ -104,13 +104,13 @@ export function validationMismatchedGeometry() { var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity, context.graph()); fixes.push(new validationIssueFix({ - title: t.html('issues.fix.connect_endpoints.title'), + title: t.append('issues.fix.connect_endpoints.title'), onClick: connectEndsOnClick })); fixes.push(new validationIssueFix({ icon: 'iD-operation-delete', - title: t.html('issues.fix.remove_tag.title'), + title: t.append('issues.fix.remove_tag.title'), onClick: function(context) { var entityId = this.issue.entityIds[0]; var entity = context.entity(entityId); @@ -161,7 +161,7 @@ export function validationMismatchedGeometry() { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.vertex_as_point.message', { + return entity ? t.append('issues.vertex_as_point.message', { feature: utilDisplayLabel(entity, 'vertex', true /* verbose */) }) : ''; }, @@ -184,7 +184,7 @@ export function validationMismatchedGeometry() { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.point_as_vertex.message', { + return entity ? t.append('issues.point_as_vertex.message', { feature: utilDisplayLabel(entity, 'point', true /* verbose */) }) : ''; }, @@ -264,7 +264,7 @@ export function validationMismatchedGeometry() { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.' + referenceId + '.message', { + return entity ? t.append('issues.' + referenceId + '.message', { feature: utilDisplayLabel(entity, targetGeom, true /* verbose */) }) : ''; }, @@ -308,7 +308,7 @@ export function validationMismatchedGeometry() { return [ new validationIssueFix({ icon: 'iD-icon-line', - title: t.html('issues.fix.convert_to_line.title'), + title: t.append('issues.fix.convert_to_line.title'), onClick: convertOnClick }) ]; @@ -336,7 +336,7 @@ export function validationMismatchedGeometry() { return [ new validationIssueFix({ icon: 'iD-operation-extract', - title: t.html('issues.fix.extract_point.title'), + title: t.append('issues.fix.extract_point.title'), onClick: extractOnClick }) ]; @@ -371,7 +371,7 @@ export function validationMismatchedGeometry() { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.unclosed_multipolygon_part.message', { + return entity ? t.append('issues.unclosed_multipolygon_part.message', { feature: utilDisplayLabel(entity, context.graph(), true /* verbose */) }) : ''; }, diff --git a/modules/validations/missing_role.js b/modules/validations/missing_role.js index 953fd682c..a1325d6ed 100644 --- a/modules/validations/missing_role.js +++ b/modules/validations/missing_role.js @@ -44,7 +44,7 @@ export function validationMissingRole() { message: function(context) { var member = context.hasEntity(this.entityIds[1]), relation = context.hasEntity(this.entityIds[0]); - return (member && relation) ? t.html('issues.missing_role.message', { + return (member && relation) ? t.append('issues.missing_role.message', { member: utilDisplayLabel(member, context.graph()), relation: utilDisplayLabel(relation, context.graph()) }) : ''; @@ -61,7 +61,7 @@ export function validationMissingRole() { makeAddRoleFix('outer'), new validationIssueFix({ icon: 'iD-operation-delete', - title: t.html('issues.fix.remove_from_relation.title'), + title: t.append('issues.fix.remove_from_relation.title'), onClick: function(context) { context.perform( actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index), @@ -89,7 +89,7 @@ export function validationMissingRole() { function makeAddRoleFix(role) { return new validationIssueFix({ - title: t.html('issues.fix.set_as_' + role + '.title'), + title: t.append('issues.fix.set_as_' + role + '.title'), onClick: function(context) { var oldMember = this.issue.data.member; var member = { id: this.issue.entityIds[1], type: oldMember.type, role: role }; diff --git a/modules/validations/missing_tag.js b/modules/validations/missing_tag.js index bcdaf4110..0c091855a 100644 --- a/modules/validations/missing_tag.js +++ b/modules/validations/missing_tag.js @@ -85,7 +85,7 @@ export function validationMissingTag(context) { severity: severity, message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.' + messageID + '.message', { + return entity ? t.append('issues.' + messageID + '.message', { feature: utilDisplayLabel(entity, context.graph()) }) : ''; }, @@ -99,7 +99,7 @@ export function validationMissingTag(context) { fixes.push(new validationIssueFix({ icon: 'iD-icon-search', - title: t.html('issues.fix.' + selectFixType + '.title'), + title: t.append('issues.fix.' + selectFixType + '.title'), onClick: function(context) { context.ui().sidebar.showPresetList(); } @@ -123,7 +123,7 @@ export function validationMissingTag(context) { fixes.push( new validationIssueFix({ icon: 'iD-operation-delete', - title: t.html('issues.fix.delete_feature.title'), + title: t.append('issues.fix.delete_feature.title'), disabledReason: disabledReasonID ? t('operations.delete.' + disabledReasonID + '.single') : undefined, onClick: deleteOnClick }) diff --git a/modules/validations/outdated_tags.js b/modules/validations/outdated_tags.js index d0073e4bc..5c8b5a929 100644 --- a/modules/validations/outdated_tags.js +++ b/modules/validations/outdated_tags.js @@ -111,7 +111,7 @@ export function validationOutdatedTags() { let fixes = [ new validationIssueFix({ autoArgs: autoArgs, - title: t.html('issues.fix.upgrade_tags.title'), + title: t.append('issues.fix.upgrade_tags.title'), onClick: (context) => { context.perform(doUpgrade, t('issues.fix.upgrade_tags.annotation')); } @@ -122,7 +122,7 @@ export function validationOutdatedTags() { if (item) { fixes.push( new validationIssueFix({ - title: t.html('issues.fix.tag_as_not.title', { name: item.displayName }), + title: t.append('issues.fix.tag_as_not.title', { name: item.displayName }), onClick: (context) => { context.perform(addNotTag, t('issues.fix.tag_as_not.annotation')); } @@ -184,7 +184,7 @@ export function validationOutdatedTags() { if (subtype === 'noncanonical_brand' && isOnlyAddingTags) { messageID += '_incomplete'; } - return t.html(messageID, { + return t.append(messageID, { feature: utilDisplayLabel(currEntity, context.graph(), true /* verbose */) }); } @@ -247,7 +247,7 @@ export function validationOutdatedTags() { return [ new validationIssueFix({ autoArgs: [doUpgrade, t('issues.fix.move_tags.annotation')], - title: t.html('issues.fix.move_tags.title'), + title: t.append('issues.fix.move_tags.title'), onClick: (context) => { context.perform(doUpgrade, t('issues.fix.move_tags.annotation')); } @@ -272,7 +272,7 @@ export function validationOutdatedTags() { let currMultipolygon = context.hasEntity(multipolygon.id); if (!currMultipolygon) return ''; - return t.html('issues.old_multipolygon.message', + return t.append('issues.old_multipolygon.message', { multipolygon: utilDisplayLabel(currMultipolygon, context.graph(), true /* verbose */) } ); } diff --git a/modules/validations/private_data.js b/modules/validations/private_data.js index 62d3214f1..f767c273e 100644 --- a/modules/validations/private_data.js +++ b/modules/validations/private_data.js @@ -67,7 +67,7 @@ export function validationPrivateData() { return [ new validationIssueFix({ icon: 'iD-operation-delete', - title: t.html('issues.fix.' + fixID + '.title'), + title: t.append('issues.fix.' + fixID + '.title'), onClick: function(context) { context.perform(doUpgrade, t('issues.fix.upgrade_tags.annotation')); } @@ -98,7 +98,7 @@ export function validationPrivateData() { var currEntity = context.hasEntity(this.entityIds[0]); if (!currEntity) return ''; - return t.html('issues.private_data.contact.message', + return t.append('issues.private_data.contact.message', { feature: utilDisplayLabel(currEntity, context.graph()) } ); } diff --git a/modules/validations/suspicious_name.js b/modules/validations/suspicious_name.js index 720e30925..77aea8236 100644 --- a/modules/validations/suspicious_name.js +++ b/modules/validations/suspicious_name.js @@ -60,7 +60,7 @@ export function validationSuspiciousName() { if (!entity) return ''; let preset = presetManager.match(entity, context.graph()); let langName = langCode && localizer.languageName(langCode); - return t.html('issues.generic_name.message' + (langName ? '_language' : ''), + return t.append('issues.generic_name.message' + (langName ? '_language' : ''), { feature: preset.name(), name: genericName, language: langName } ); }, @@ -71,7 +71,7 @@ export function validationSuspiciousName() { return [ new validationIssueFix({ icon: 'iD-operation-delete', - title: t.html('issues.fix.remove_the_name.title'), + title: t.append('issues.fix.remove_the_name.title'), onClick: function(context) { let entityId = this.issue.entityIds[0]; let entity = context.entity(entityId); @@ -106,7 +106,7 @@ export function validationSuspiciousName() { if (!entity) return ''; const preset = presetManager.match(entity, context.graph()); const langName = langCode && localizer.languageName(langCode); - return t.html('issues.incorrect_name.message' + (langName ? '_language' : ''), + return t.append('issues.incorrect_name.message' + (langName ? '_language' : ''), { feature: preset.name(), name: incorrectName, language: langName } ); }, @@ -117,7 +117,7 @@ export function validationSuspiciousName() { return [ new validationIssueFix({ icon: 'iD-operation-delete', - title: t.html('issues.fix.remove_the_name.title'), + title: t.append('issues.fix.remove_the_name.title'), onClick: function(context) { const entityId = this.issue.entityIds[0]; const entity = context.entity(entityId); diff --git a/modules/validations/unsquare_way.js b/modules/validations/unsquare_way.js index 338118bb3..ca0cfb8f1 100644 --- a/modules/validations/unsquare_way.js +++ b/modules/validations/unsquare_way.js @@ -76,7 +76,7 @@ export function validationUnsquareWay(context) { severity: 'warning', message: function(context) { var entity = context.hasEntity(this.entityIds[0]); - return entity ? t.html('issues.unsquare_way.message', { + return entity ? t.append('issues.unsquare_way.message', { feature: utilDisplayLabel(entity, context.graph()) }) : ''; }, @@ -87,7 +87,7 @@ export function validationUnsquareWay(context) { return [ new validationIssueFix({ icon: 'iD-operation-orthogonalize', - title: t.html('issues.fix.square_feature.title'), + title: t.append('issues.fix.square_feature.title'), autoArgs: autoArgs, onClick: function(context, completionHandler) { var entityId = this.issue.entityIds[0]; @@ -102,7 +102,7 @@ export function validationUnsquareWay(context) { }), /* new validationIssueFix({ - title: t.html('issues.fix.tag_as_unsquare.title'), + title: t.append('issues.fix.tag_as_unsquare.title'), onClick: function(context) { var entityId = this.issue.entityIds[0]; var entity = context.entity(entityId); From 209cc23d928b283dd4ff7b5d8ea1092ea869fa23 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 24 Jun 2022 19:11:00 +0200 Subject: [PATCH 8/9] don't inject html code in preset names --- modules/presets/category.js | 2 +- modules/presets/preset.js | 10 ++++------ modules/ui/preset_list.js | 5 +++-- modules/ui/sections/feature_type.js | 3 ++- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/presets/category.js b/modules/presets/category.js index aadecbbd4..c97f52063 100644 --- a/modules/presets/category.js +++ b/modules/presets/category.js @@ -36,7 +36,7 @@ export function presetCategory(categoryID, category, allPresets) { _this.matchScore = () => -1; _this.name = () => t(`_tagging.presets.categories.${categoryID}.name`, { 'default': categoryID }); - _this.nameLabel = () => t.html(`_tagging.presets.categories.${categoryID}.name`, { 'default': categoryID }); + _this.nameLabel = () => t.append(`_tagging.presets.categories.${categoryID}.name`, { 'default': categoryID }); _this.terms = () => []; diff --git a/modules/presets/preset.js b/modules/presets/preset.js index 65f983780..4cb5c9f62 100644 --- a/modules/presets/preset.js +++ b/modules/presets/preset.js @@ -94,9 +94,9 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) { return t(textID, options); }; - _this.t.html = (scope, options) => { + _this.t.append = (scope, options) => { const textID = `_tagging.presets.presets.${presetID}.${scope}`; - return t.html(textID, options); + return t.append(textID, options); }; @@ -104,9 +104,7 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) { return _this.t('name', { 'default': _this.originalName }); }; - _this.nameLabel = () => { - return _this.t.html('name', { 'default': _this.originalName }); - }; + _this.nameLabel = () => _this.t.append('name', { 'default': _this.originalName }); _this.subtitle = () => { if (_this.suggestion) { @@ -121,7 +119,7 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) { if (_this.suggestion) { let path = presetID.split('/'); path.pop(); // remove brand name - return t.html('_tagging.presets.presets.' + path.join('/') + '.name'); + return t.append('_tagging.presets.presets.' + path.join('/') + '.name'); } return null; }; diff --git a/modules/ui/preset_list.js b/modules/ui/preset_list.js index f2e9100fc..ba9b0bf4f 100644 --- a/modules/ui/preset_list.js +++ b/modules/ui/preset_list.js @@ -329,7 +329,8 @@ export function uiPresetList(context) { .attr('class', 'namepart') .call(svgIcon((localizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'), 'inline')) .append('span') - .html(function() { return preset.nameLabel() + '…'; }); + .call(preset.nameLabel()) + .append('span').text('…'); box = selection.append('div') .attr('class', 'subgrid') @@ -402,7 +403,7 @@ export function uiPresetList(context) { .enter() .append('div') .attr('class', 'namepart') - .html(function(d) { return d; }); + .each(function(d) { d(d3_select(this)); }); wrap.call(item.reference.button); selection.call(item.reference.body); diff --git a/modules/ui/sections/feature_type.js b/modules/ui/sections/feature_type.js index 403591cdd..7939a7605 100644 --- a/modules/ui/sections/feature_type.js +++ b/modules/ui/sections/feature_type.js @@ -1,4 +1,5 @@ import { dispatch as d3_dispatch } from 'd3-dispatch'; +import { select as d3_select } from 'd3-selection'; import { presetManager } from '../../presets'; import { utilArrayIdentical } from '../../util/array'; @@ -108,7 +109,7 @@ export function uiSectionFeatureType(context) { .enter() .append('div') .attr('class', 'namepart') - .html(function(d) { return d; }); + .each(function(d) { return d(d3_select(this)); }); } section.entityIDs = function(val) { From 7d546a8f608c03ae32939c8fb32ce2cfe4b4750f Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 24 Jun 2022 19:31:41 +0200 Subject: [PATCH 9/9] refactor further modules to not rely on html injection --- modules/core/localizer.js | 4 +++- modules/renderer/tile_layer.js | 4 +++- modules/ui/commit_warnings.js | 2 +- modules/ui/entity_editor.js | 3 ++- modules/ui/preset_list.js | 3 ++- modules/ui/sections/feature_type.js | 7 ++++--- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/modules/core/localizer.js b/modules/core/localizer.js index 15f185844..375d359ea 100644 --- a/modules/core/localizer.js +++ b/modules/core/localizer.js @@ -376,7 +376,7 @@ export function coreLocalizer() { // Adds localized text wrapped as an HTML span element with locale info to the DOM localizer.t.append = function(stringId, replacements, locale) { - return function(selection) { + const ret = function(selection) { const info = localizer.tInfo(stringId, replacements, locale); return selection.append('span') .attr('class', 'localized-text') @@ -385,6 +385,8 @@ export function coreLocalizer() { + info.text + (replacements &&replacements.suffix || '')); }; + ret.stringId = stringId; + return ret; }; localizer.languageName = (code, options) => { diff --git a/modules/renderer/tile_layer.js b/modules/renderer/tile_layer.js index bd9c719f1..1ab3d398e 100644 --- a/modules/renderer/tile_layer.js +++ b/modules/renderer/tile_layer.js @@ -250,7 +250,9 @@ export function rendererTileLayer(context) { if (result && result.vintage && result.vintage.range) { span.text(result.vintage.range); } else { - span.html(t.html('info_panels.background.vintage') + ': ' + t.html('info_panels.background.unknown')); + span.call(t.append('info_panels.background.vintage')); + span.append('span').text(': '); + span.call(t.append('info_panels.background.unknown')); } }); }); diff --git a/modules/ui/commit_warnings.js b/modules/ui/commit_warnings.js index d919f6aeb..71c9f8a4e 100644 --- a/modules/ui/commit_warnings.js +++ b/modules/ui/commit_warnings.js @@ -34,7 +34,7 @@ export function uiCommitWarnings(context) { containerEnter .append('h3') - .html(severity === 'warning' ? t.html('commit.warnings') : t.html('commit.errors')); + .call(severity === 'warning' ? t.append('commit.warnings') : t.append('commit.errors')); containerEnter .append('ul') diff --git a/modules/ui/entity_editor.js b/modules/ui/entity_editor.js index f94641fdf..316e9bd26 100644 --- a/modules/ui/entity_editor.js +++ b/modules/ui/entity_editor.js @@ -65,7 +65,8 @@ export function uiEntityEditor(context) { .merge(headerEnter); header.selectAll('h2') - .html(_entityIDs.length === 1 ? t.html('inspector.edit') : t.html('inspector.edit_features')); + .text('') + .call(_entityIDs.length === 1 ? t.append('inspector.edit') : t.append('inspector.edit_features')); header.selectAll('.preset-reset') .on('click', function() { diff --git a/modules/ui/preset_list.js b/modules/ui/preset_list.js index ba9b0bf4f..c06275dd5 100644 --- a/modules/ui/preset_list.js +++ b/modules/ui/preset_list.js @@ -399,10 +399,11 @@ export function uiPresetList(context) { ].filter(Boolean); label.selectAll('.namepart') - .data(nameparts) + .data(nameparts, d => d.stringId) .enter() .append('div') .attr('class', 'namepart') + .text('') .each(function(d) { d(d3_select(this)); }); wrap.call(item.reference.button); diff --git a/modules/ui/sections/feature_type.js b/modules/ui/sections/feature_type.js index 7939a7605..d93c4f020 100644 --- a/modules/ui/sections/feature_type.js +++ b/modules/ui/sections/feature_type.js @@ -96,11 +96,11 @@ export function uiSectionFeatureType(context) { var names = _presets.length === 1 ? [ _presets[0].nameLabel(), _presets[0].subtitleLabel() - ].filter(Boolean) : [t('inspector.multiple_types')]; + ].filter(Boolean) : [ t.append('inspector.multiple_types') ]; var label = selection.select('.label-inner'); var nameparts = label.selectAll('.namepart') - .data(names, function(d) { return d; }); + .data(names, d => d.stringId); nameparts.exit() .remove(); @@ -109,7 +109,8 @@ export function uiSectionFeatureType(context) { .enter() .append('div') .attr('class', 'namepart') - .each(function(d) { return d(d3_select(this)); }); + .text('') + .each(function(d) { d(d3_select(this)); }); } section.entityIDs = function(val) {