From da502df9e3aee414667d21394e72d7886bd201fc Mon Sep 17 00:00:00 2001 From: pedromml Date: Thu, 22 Aug 2024 16:41:37 -0300 Subject: [PATCH 1/4] Add multiple source fields --- data/core.yaml | 6 ++++++ modules/presets/index.js | 17 +++++++++++++++++ modules/ui/field.js | 8 ++++++++ modules/ui/fields/sources.js | 7 ++++++- modules/ui/sections/preset_fields.js | 12 +++++++++++- 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index ce0ab7d32d..356dce8b00 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -2542,6 +2542,12 @@ en: terms: copyleft, copyright source: label: Source + source:2: + label: Source 2 + source:3: + label: Source 3 + source:4: + label: Source 4 presets: type/chronology: name: Chronology diff --git a/modules/presets/index.js b/modules/presets/index.js index 6462a591b2..88d9b40a32 100644 --- a/modules/presets/index.js +++ b/modules/presets/index.js @@ -60,6 +60,23 @@ function addHistoricalFields(fields) { fields.source.type = 'source'; fields.source.source = false; fields.source.keys = ['source', 'source:url', 'source:name', 'source:date']; + + const multipleSourceIds = ['', ':2', ':3', ':4']; + + for (var i = 1; i < multipleSourceIds.length; i++){ + var id = multipleSourceIds[i]; + var previousId = multipleSourceIds[i-1]; + fields['source' + id] = { + ...fields.source, + key: 'source' + id, + keys: ['source' + id, 'source' + id + ':url', 'source' + id + ':name', 'source' + id + ':date'], + prerequisiteTag: { + keys: [ + 'source' + previousId, + 'source' + previousId + ':url', + 'source' + previousId + ':name', + 'source' + previousId + ':date']}}; + } } fields.license = { diff --git a/modules/ui/field.js b/modules/ui/field.js index be11fba3c2..c068f12117 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -350,6 +350,14 @@ export function uiField(context, presetField, entityIDs, options) { if (!entityIDs.every(function(entityID) { var entity = context.graph().entity(entityID); + if (prerequisiteTag.keys) { + // Return true if any key in prerequisiteTag.keys is present, return false otherwise + // If prerequisiteTag.keys is present, prerequisiteTag.key will be ignored + for (var i = 0; i < prerequisiteTag.keys.length; i++){ + if (entity.tags[prerequisiteTag.keys[i]]) return true; + } + return false; + } if (prerequisiteTag.key) { var value = entity.tags[prerequisiteTag.key]; if (!value) return false; diff --git a/modules/ui/fields/sources.js b/modules/ui/fields/sources.js index f7e4a77074..0b0988975b 100644 --- a/modules/ui/fields/sources.js +++ b/modules/ui/fields/sources.js @@ -11,7 +11,7 @@ export function uiFieldSources(field, context) { let _selection = d3_select(null); let _pendingChange; - const mainKey = 'source'; + const mainKey = field.key; const sourceHeader = mainKey + ':'; // Pre-selected subkeys to show @@ -130,5 +130,10 @@ export function uiFieldSources(field, context) { _selection.call(sources); }; + sources.focus = function() { + var node = _selection.selectAll('input').node(); + if (node) node.focus(); + }; + return utilRebind(sources, dispatch, 'on'); } diff --git a/modules/ui/sections/preset_fields.js b/modules/ui/sections/preset_fields.js index e39dd8e07c..8805e55827 100644 --- a/modules/ui/sections/preset_fields.js +++ b/modules/ui/sections/preset_fields.js @@ -78,8 +78,17 @@ export function uiSectionPresetFields(context) { } }); + let optionalCoreKeys = ['source:2', 'source:3', 'source:4']; + optionalCoreKeys.forEach(key => { + let field = presetsManager.field(key); + if (field && _fieldsArr.indexOf(field) === -1) { + _fieldsArr.push(uiField(context, field, _entityIDs, { show: false })); + } + }); + + sharedFields.forEach(function(field) { - if (!coreKeys.includes(field.id) && field.matchAllGeometry(geometries)) { + if (!coreKeys.includes(field.id) && !optionalCoreKeys.includes(field.id) && field.matchAllGeometry(geometries)) { _fieldsArr.push( uiField(context, field, _entityIDs) ); @@ -101,6 +110,7 @@ export function uiSectionPresetFields(context) { additionalFields.forEach(function(field) { if (sharedFields.indexOf(field) === -1 && !coreKeys.includes(field.id) && + !optionalCoreKeys.includes(field.id) && field.matchAllGeometry(geometries)) { _fieldsArr.push( uiField(context, field, _entityIDs, { show: false }) From 60c767b42986fd70d15f48b22eafb7231891eaf7 Mon Sep 17 00:00:00 2001 From: pedromml Date: Sun, 25 Aug 2024 04:02:54 -0300 Subject: [PATCH 2/4] Fix PR comments: Clean code, remove hardcoded ids --- data/core.yaml | 6 ------ modules/presets/index.js | 23 +++++++++++------------ modules/ui/field.js | 6 ++---- modules/ui/sections/preset_fields.js | 4 ++-- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index 356dce8b00..ce0ab7d32d 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -2542,12 +2542,6 @@ en: terms: copyleft, copyright source: label: Source - source:2: - label: Source 2 - source:3: - label: Source 3 - source:4: - label: Source 4 presets: type/chronology: name: Chronology diff --git a/modules/presets/index.js b/modules/presets/index.js index 88d9b40a32..4fa8c3b81b 100644 --- a/modules/presets/index.js +++ b/modules/presets/index.js @@ -61,21 +61,20 @@ function addHistoricalFields(fields) { fields.source.source = false; fields.source.keys = ['source', 'source:url', 'source:name', 'source:date']; - const multipleSourceIds = ['', ':2', ':3', ':4']; - - for (var i = 1; i < multipleSourceIds.length; i++){ - var id = multipleSourceIds[i]; - var previousId = multipleSourceIds[i-1]; - fields['source' + id] = { + for (let i = 1; i < 4; i++){ + let id = 'source' + (i > 0 ? ':' + i.toString() : ''); + let previousId = 'source' + ((i-1) > 0 ? ':' + (i-1).toString() : ''); + fields[id] = { ...fields.source, - key: 'source' + id, - keys: ['source' + id, 'source' + id + ':url', 'source' + id + ':name', 'source' + id + ':date'], + key: id, + keys: [id, id + ':url', id + ':name', id + ':date'], + overrideLabel: 'Source ' + i, prerequisiteTag: { keys: [ - 'source' + previousId, - 'source' + previousId + ':url', - 'source' + previousId + ':name', - 'source' + previousId + ':date']}}; + previousId, + previousId + ':url', + previousId + ':name', + previousId + ':date']}}; } } diff --git a/modules/ui/field.js b/modules/ui/field.js index c068f12117..15009f6119 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -353,10 +353,8 @@ export function uiField(context, presetField, entityIDs, options) { if (prerequisiteTag.keys) { // Return true if any key in prerequisiteTag.keys is present, return false otherwise // If prerequisiteTag.keys is present, prerequisiteTag.key will be ignored - for (var i = 0; i < prerequisiteTag.keys.length; i++){ - if (entity.tags[prerequisiteTag.keys[i]]) return true; - } - return false; + const inEntityTags = (e) => e in entity.tags; + return prerequisiteTag.keys.some(inEntityTags); } if (prerequisiteTag.key) { var value = entity.tags[prerequisiteTag.key]; diff --git a/modules/ui/sections/preset_fields.js b/modules/ui/sections/preset_fields.js index 8805e55827..4cce6cbb77 100644 --- a/modules/ui/sections/preset_fields.js +++ b/modules/ui/sections/preset_fields.js @@ -78,10 +78,10 @@ export function uiSectionPresetFields(context) { } }); - let optionalCoreKeys = ['source:2', 'source:3', 'source:4']; + let optionalCoreKeys = ['source:1', 'source:2', 'source:3']; optionalCoreKeys.forEach(key => { let field = presetsManager.field(key); - if (field && _fieldsArr.indexOf(field) === -1) { + if (field && !_fieldsArr.includes(field)) { _fieldsArr.push(uiField(context, field, _entityIDs, { show: false })); } }); From 6fbf70edbe76a29b5a4e2f55b17f14387e707e98 Mon Sep 17 00:00:00 2001 From: pedromml Date: Thu, 29 Aug 2024 21:23:27 -0300 Subject: [PATCH 3/4] Fix localization of multiple source field labels --- data/core.yaml | 2 ++ modules/presets/field.js | 25 +++++++++++++++---------- modules/presets/index.js | 1 - modules/ui/field.js | 4 ++++ 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index ce0ab7d32d..92dc7fd9db 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -2542,6 +2542,8 @@ en: terms: copyleft, copyright source: label: Source + source_multiple: + label: Source {localizerOption} presets: type/chronology: name: Chronology diff --git a/modules/presets/field.js b/modules/presets/field.js index 7f9215a15d..4eabfd6b05 100644 --- a/modules/presets/field.js +++ b/modules/presets/field.js @@ -10,6 +10,11 @@ export function presetField(fieldID, field, allFields) { allFields = allFields || {}; let _this = Object.assign({}, field); // shallow copy + // This handles fieldIDs that contain ':', like 'source:1' + let localizerFieldID = fieldID.includes(':') ? fieldID.split(':')[0] + '_multiple': fieldID; + // This is what comes after the ':' in the fieldID. + let localizerOption = fieldID.includes(':') ? fieldID.split(':')[1]: 0; + _this.id = fieldID; // for use in classes, element ids, css selectors @@ -21,14 +26,14 @@ export function presetField(fieldID, field, allFields) { return !_this.geometry || geometries.every(geom => _this.geometry.indexOf(geom) !== -1); }; - _this.t = (scope, options) => t(localizer.coalesceStringIds([`custom_presets.fields.${fieldID}.${scope}`, - `_tagging.presets.fields.${fieldID}.${scope}`]), options); - _this.t.html = (scope, options) => t.html(localizer.coalesceStringIds([`custom_presets.fields.${fieldID}.${scope}`, - `_tagging.presets.fields.${fieldID}.${scope}`]), options); - _this.t.append = (scope, options) => t.append(localizer.coalesceStringIds([`custom_presets.fields.${fieldID}.${scope}`, - `_tagging.presets.fields.${fieldID}.${scope}`]), options); - _this.hasTextForStringId = (scope) => localizer.hasTextForStringId(`custom_presets.fields.${fieldID}.${scope}`) || - localizer.hasTextForStringId(`_tagging.presets.fields.${fieldID}.${scope}`); + _this.t = (scope, options) => t(localizer.coalesceStringIds([`custom_presets.fields.${localizerFieldID}.${scope}`, + `_tagging.presets.fields.${localizerFieldID}.${scope}`]), options); + _this.t.html = (scope, options) => t.html(localizer.coalesceStringIds([`custom_presets.fields.${localizerFieldID}.${scope}`, + `_tagging.presets.fields.${localizerFieldID}.${scope}`]), options); + _this.t.append = (scope, options) => t.append(localizer.coalesceStringIds([`custom_presets.fields.${localizerFieldID}.${scope}`, + `_tagging.presets.fields.${localizerFieldID}.${scope}`]), options); + _this.hasTextForStringId = (scope) => localizer.hasTextForStringId(`custom_presets.fields.${localizerFieldID}.${scope}`) || + localizer.hasTextForStringId(`_tagging.presets.fields.${localizerFieldID}.${scope}`); _this.resolveReference = which => { const referenceRegex = /^\{(.*)\}$/; @@ -43,10 +48,10 @@ export function presetField(fieldID, field, allFields) { return _this; }; - _this.title = () => _this.overrideLabel || _this.resolveReference('label').t('label', { 'default': fieldID }); + _this.title = () => _this.overrideLabel || _this.resolveReference('label').t('label', { 'default': fieldID, 'localizerOption': localizerOption }); _this.label = () => _this.overrideLabel ? selection => selection.text(_this.overrideLabel) : - _this.resolveReference('label').t.append('label', { 'default': fieldID }); + _this.resolveReference('label').t.append('label', { 'default': fieldID, 'localizerOption': localizerOption }); _this.placeholder = () => _this.resolveReference('placeholder').t('placeholder', { 'default': '' }); diff --git a/modules/presets/index.js b/modules/presets/index.js index 4fa8c3b81b..8491102e11 100644 --- a/modules/presets/index.js +++ b/modules/presets/index.js @@ -68,7 +68,6 @@ function addHistoricalFields(fields) { ...fields.source, key: id, keys: [id, id + ':url', id + ':name', id + ':date'], - overrideLabel: 'Source ' + i, prerequisiteTag: { keys: [ previousId, diff --git a/modules/ui/field.js b/modules/ui/field.js index 15009f6119..c8e821a45f 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -216,6 +216,10 @@ export function uiField(context, presetField, entityIDs, options) { referenceKey = referenceKey.replace(/:$/, ''); } + if (d.type === 'source') { // lookup key without the trailing ':' + referenceKey = referenceKey.split(':')[0]; + } + var referenceOptions = d.reference || { key: referenceKey, value: _tags[referenceKey] From 577fb55af6139c44349be1de57bfc7776374cca6 Mon Sep 17 00:00:00 2001 From: pedromml Date: Fri, 30 Aug 2024 17:37:59 -0300 Subject: [PATCH 4/4] Use field.baseKey and field.index to generate localizedFieldID --- data/core.yaml | 2 +- modules/presets/field.js | 13 +++++++------ modules/presets/index.js | 5 ++++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index 92dc7fd9db..bce4b03c3f 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -2543,7 +2543,7 @@ en: source: label: Source source_multiple: - label: Source {localizerOption} + label: Source {index} presets: type/chronology: name: Chronology diff --git a/modules/presets/field.js b/modules/presets/field.js index 4eabfd6b05..02a1ae0d60 100644 --- a/modules/presets/field.js +++ b/modules/presets/field.js @@ -10,10 +10,11 @@ export function presetField(fieldID, field, allFields) { allFields = allFields || {}; let _this = Object.assign({}, field); // shallow copy - // This handles fieldIDs that contain ':', like 'source:1' - let localizerFieldID = fieldID.includes(':') ? fieldID.split(':')[0] + '_multiple': fieldID; - // This is what comes after the ':' in the fieldID. - let localizerOption = fieldID.includes(':') ? fieldID.split(':')[1]: 0; + // This handles fields that are composed of a base key and an index, like 'source:1' + let localizerFieldID = fieldID; + if (field.baseKey && field.index){ + localizerFieldID = field.baseKey + '_multiple'; + } _this.id = fieldID; @@ -48,10 +49,10 @@ export function presetField(fieldID, field, allFields) { return _this; }; - _this.title = () => _this.overrideLabel || _this.resolveReference('label').t('label', { 'default': fieldID, 'localizerOption': localizerOption }); + _this.title = () => _this.overrideLabel || _this.resolveReference('label').t('label', { 'default': fieldID, 'index': field.index }); _this.label = () => _this.overrideLabel ? selection => selection.text(_this.overrideLabel) : - _this.resolveReference('label').t.append('label', { 'default': fieldID, 'localizerOption': localizerOption }); + _this.resolveReference('label').t.append('label', { 'default': fieldID, 'index': field.index }); _this.placeholder = () => _this.resolveReference('placeholder').t('placeholder', { 'default': '' }); diff --git a/modules/presets/index.js b/modules/presets/index.js index 8491102e11..7c4689faa9 100644 --- a/modules/presets/index.js +++ b/modules/presets/index.js @@ -62,12 +62,15 @@ function addHistoricalFields(fields) { fields.source.keys = ['source', 'source:url', 'source:name', 'source:date']; for (let i = 1; i < 4; i++){ - let id = 'source' + (i > 0 ? ':' + i.toString() : ''); + let id = 'source:' + i.toString(); let previousId = 'source' + ((i-1) > 0 ? ':' + (i-1).toString() : ''); fields[id] = { ...fields.source, key: id, keys: [id, id + ':url', id + ':name', id + ':date'], + // baseKey and index will be used to create a localized label for this field + baseKey: 'source', + index: i, prerequisiteTag: { keys: [ previousId,