mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-24 09:04:02 +02:00
Enforce max unicode charachter length of keys, values, and relation roles through truncation upon input rather than HTML maxlength attribute (close #6817)
Normalize unicode when changing keys, values, and relation roles
This commit is contained in:
+22
-1
@@ -18,7 +18,7 @@ import { presetManager } from '../presets';
|
||||
import { rendererBackground, rendererFeatures, rendererMap, rendererPhotos } from '../renderer';
|
||||
import { services } from '../services';
|
||||
import { uiInit } from '../ui/init';
|
||||
import { utilKeybinding, utilRebind, utilStringQs } from '../util';
|
||||
import { utilKeybinding, utilRebind, utilStringQs, utilUnicodeCharsTruncated } from '../util';
|
||||
|
||||
|
||||
export function coreContext() {
|
||||
@@ -196,6 +196,27 @@ export function coreContext() {
|
||||
context.maxCharsForTagValue = () => 255;
|
||||
context.maxCharsForRelationRole = () => 255;
|
||||
|
||||
function cleanOsmString(val, maxChars) {
|
||||
// be lenient with input
|
||||
if (val === undefined || val === null) {
|
||||
val = '';
|
||||
} else {
|
||||
val = val.toString();
|
||||
}
|
||||
|
||||
// remove whitespace
|
||||
val = val.trim();
|
||||
|
||||
// use the canonical form of the string
|
||||
if (val.normalize) val = val.normalize('NFC');
|
||||
|
||||
// trim to the number of allowed characters
|
||||
return utilUnicodeCharsTruncated(val, maxChars);
|
||||
}
|
||||
context.cleanTagKey = (val) => cleanOsmString(val, context.maxCharsForTagKey());
|
||||
context.cleanTagValue = (val) => cleanOsmString(val, context.maxCharsForTagValue());
|
||||
context.cleanRelationRole = (val) => cleanOsmString(val, context.maxCharsForRelationRole());
|
||||
|
||||
|
||||
/* History */
|
||||
let _inIntro = false;
|
||||
|
||||
+15
-21
@@ -12,7 +12,7 @@ import { uiChangesetEditor } from './changeset_editor';
|
||||
import { uiSectionChanges } from './sections/changes';
|
||||
import { uiCommitWarnings } from './commit_warnings';
|
||||
import { uiSectionRawTagEditor } from './sections/raw_tag_editor';
|
||||
import { utilArrayGroupBy, utilRebind, utilUnicodeCharsTruncated, utilUniqueDomId } from '../util';
|
||||
import { utilArrayGroupBy, utilRebind, utilUniqueDomId } from '../util';
|
||||
import { utilDetect } from '../util/detect';
|
||||
|
||||
|
||||
@@ -63,8 +63,6 @@ export function uiCommit(context) {
|
||||
|
||||
function initChangeset() {
|
||||
|
||||
var tagCharLimit = context.maxCharsForTagValue();
|
||||
|
||||
// expire stored comment, hashtags, source after cutoff datetime - #3947 #4899
|
||||
var commentDate = +prefs('commentDate') || 0;
|
||||
var currDate = Date.now();
|
||||
@@ -92,9 +90,9 @@ export function uiCommit(context) {
|
||||
var detected = utilDetect();
|
||||
var tags = {
|
||||
comment: prefs('comment') || '',
|
||||
created_by: utilUnicodeCharsTruncated('iD ' + context.version, tagCharLimit),
|
||||
host: utilUnicodeCharsTruncated(detected.host, tagCharLimit),
|
||||
locale: utilUnicodeCharsTruncated(localizer.localeCode(), tagCharLimit)
|
||||
created_by: context.cleanTagValue('iD ' + context.version),
|
||||
host: context.cleanTagValue(detected.host),
|
||||
locale: context.cleanTagValue(localizer.localeCode())
|
||||
};
|
||||
|
||||
// call findHashtags initially - this will remove stored
|
||||
@@ -126,7 +124,7 @@ export function uiCommit(context) {
|
||||
}
|
||||
});
|
||||
|
||||
tags.source = utilUnicodeCharsTruncated(sources.join(';'), tagCharLimit);
|
||||
tags.source = context.cleanTagValue(sources.join(';'));
|
||||
}
|
||||
|
||||
context.changeset = new osmChangeset({ tags: tags });
|
||||
@@ -139,36 +137,34 @@ export function uiCommit(context) {
|
||||
var osm = context.connection();
|
||||
if (!osm) return;
|
||||
|
||||
var tagCharLimit = context.maxCharsForTagValue();
|
||||
|
||||
var tags = Object.assign({}, context.changeset.tags); // shallow copy
|
||||
|
||||
// assign tags for imagery used
|
||||
var imageryUsed = utilUnicodeCharsTruncated(context.history().imageryUsed().join(';'), tagCharLimit);
|
||||
var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(';'));
|
||||
tags.imagery_used = imageryUsed || 'None';
|
||||
|
||||
// assign tags for closed issues and notes
|
||||
var osmClosed = osm.getClosedIDs();
|
||||
var itemType;
|
||||
if (osmClosed.length) {
|
||||
tags['closed:note'] = utilUnicodeCharsTruncated(osmClosed.join(';'), tagCharLimit);
|
||||
tags['closed:note'] = context.cleanTagValue(osmClosed.join(';'));
|
||||
}
|
||||
if (services.keepRight) {
|
||||
var krClosed = services.keepRight.getClosedIDs();
|
||||
if (krClosed.length) {
|
||||
tags['closed:keepright'] = utilUnicodeCharsTruncated(krClosed.join(';'), tagCharLimit);
|
||||
tags['closed:keepright'] = context.cleanTagValue(krClosed.join(';'));
|
||||
}
|
||||
}
|
||||
if (services.improveOSM) {
|
||||
var iOsmClosed = services.improveOSM.getClosedCounts();
|
||||
for (itemType in iOsmClosed) {
|
||||
tags['closed:improveosm:' + itemType] = utilUnicodeCharsTruncated(iOsmClosed[itemType].toString(), tagCharLimit);
|
||||
tags['closed:improveosm:' + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
|
||||
}
|
||||
}
|
||||
if (services.osmose) {
|
||||
var osmoseClosed = services.osmose.getClosedCounts();
|
||||
for (itemType in osmoseClosed) {
|
||||
tags['closed:osmose:' + itemType] = utilUnicodeCharsTruncated(osmoseClosed[itemType].toString(), tagCharLimit);
|
||||
tags['closed:osmose:' + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,10 +183,10 @@ export function uiCommit(context) {
|
||||
var issuesBySubtype = utilArrayGroupBy(issuesOfType, 'subtype');
|
||||
for (var issueSubtype in issuesBySubtype) {
|
||||
var issuesOfSubtype = issuesBySubtype[issueSubtype];
|
||||
tags[prefix + ':' + issueType + ':' + issueSubtype] = utilUnicodeCharsTruncated(issuesOfSubtype.length.toString(), tagCharLimit);
|
||||
tags[prefix + ':' + issueType + ':' + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
|
||||
}
|
||||
} else {
|
||||
tags[prefix + ':' + issueType] = utilUnicodeCharsTruncated(issuesOfType.length.toString(), tagCharLimit);
|
||||
tags[prefix + ':' + issueType] = context.cleanTagValue(issuesOfType.length.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,18 +542,16 @@ export function uiCommit(context) {
|
||||
function updateChangeset(changed, onInput) {
|
||||
var tags = Object.assign({}, context.changeset.tags); // shallow copy
|
||||
|
||||
var tagCharLimit = context.maxCharsForTagValue();
|
||||
|
||||
Object.keys(changed).forEach(function(k) {
|
||||
var v = changed[k];
|
||||
k = utilUnicodeCharsTruncated(k.trim(), tagCharLimit);
|
||||
k = context.cleanTagKey(k);
|
||||
if (readOnlyTags.indexOf(k) !== -1) return;
|
||||
|
||||
if (k !== '' && v !== undefined) {
|
||||
if (onInput) {
|
||||
tags[k] = v;
|
||||
} else {
|
||||
tags[k] = utilUnicodeCharsTruncated(v.trim(), tagCharLimit);
|
||||
tags[k] = context.cleanTagValue(v);
|
||||
}
|
||||
} else {
|
||||
delete tags[k];
|
||||
@@ -569,7 +563,7 @@ export function uiCommit(context) {
|
||||
var commentOnly = changed.hasOwnProperty('comment') && (changed.comment !== '');
|
||||
var arr = findHashtags(tags, commentOnly);
|
||||
if (arr.length) {
|
||||
tags.hashtags = utilUnicodeCharsTruncated(arr.join(';'), tagCharLimit);
|
||||
tags.hashtags = context.cleanTagValue(arr.join(';'));
|
||||
prefs('hashtags', tags.hashtags);
|
||||
} else {
|
||||
delete tags.hashtags;
|
||||
|
||||
@@ -47,7 +47,6 @@ export function uiFieldAccess(field, context) {
|
||||
.attr('class', 'preset-input-access-wrap')
|
||||
.append('input')
|
||||
.attr('type', 'text')
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.attr('class', function(d) { return 'preset-input-access preset-input-access-' + d; })
|
||||
.call(utilNoAuto)
|
||||
.each(function(d) {
|
||||
@@ -69,7 +68,7 @@ export function uiFieldAccess(field, context) {
|
||||
|
||||
function change(d) {
|
||||
var tag = {};
|
||||
var value = utilGetSetValue(d3_select(this));
|
||||
var value = context.cleanTagValue(utilGetSetValue(d3_select(this)));
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!value && typeof _tags[d] !== 'string') return;
|
||||
|
||||
@@ -186,7 +186,6 @@ export function uiFieldAddress(field, context) {
|
||||
.append('input')
|
||||
.property('type', 'text')
|
||||
.call(updatePlaceholder)
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.attr('class', function (d) { return 'addr-' + d.id; })
|
||||
.call(utilNoAuto)
|
||||
.each(addDropdown)
|
||||
@@ -259,10 +258,12 @@ export function uiFieldAddress(field, context) {
|
||||
.each(function (subfield) {
|
||||
var key = field.key + ':' + subfield.id;
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (Array.isArray(_tags[key]) && !this.value) return;
|
||||
var value = context.cleanTagValue(this.value);
|
||||
|
||||
tags[key] = this.value || undefined;
|
||||
// don't override multiple values with blank string
|
||||
if (Array.isArray(_tags[key]) && !value) return;
|
||||
|
||||
tags[key] = value || undefined;
|
||||
});
|
||||
|
||||
dispatch.call('change', this, tags, onInput);
|
||||
|
||||
@@ -290,6 +290,7 @@ export function uiFieldCombo(field, context) {
|
||||
var old = _tags[key];
|
||||
if (typeof old === 'string' && old.toLowerCase() !== 'no') return;
|
||||
}
|
||||
key = context.cleanTagKey(key);
|
||||
field.keys.push(key);
|
||||
t[key] = 'yes';
|
||||
});
|
||||
@@ -297,7 +298,7 @@ export function uiFieldCombo(field, context) {
|
||||
} else if (isSemi) {
|
||||
var arr = _multiData.map(function(d) { return d.key; });
|
||||
arr = arr.concat(vals);
|
||||
t[field.key] = utilArrayUniq(arr).filter(Boolean).join(';');
|
||||
t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
|
||||
}
|
||||
|
||||
window.setTimeout(function() { input.node().focus(); }, 10);
|
||||
@@ -308,7 +309,7 @@ export function uiFieldCombo(field, context) {
|
||||
// don't override multiple values with blank string
|
||||
if (!rawValue && Array.isArray(_tags[field.key])) return;
|
||||
|
||||
val = tagValue(rawValue);
|
||||
val = context.cleanTagValue(tagValue(rawValue));
|
||||
t[field.key] = val;
|
||||
}
|
||||
|
||||
@@ -383,7 +384,6 @@ export function uiFieldCombo(field, context) {
|
||||
.append('input')
|
||||
.attr('type', 'text')
|
||||
.attr('id', field.domId)
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.call(utilNoAuto)
|
||||
.call(initCombo, selection)
|
||||
.merge(input);
|
||||
@@ -456,8 +456,8 @@ export function uiFieldCombo(field, context) {
|
||||
var commonValues;
|
||||
if (Array.isArray(tags[field.key])) {
|
||||
|
||||
tags[field.key].forEach(function(tagValue) {
|
||||
var thisVals = utilArrayUniq((tagValue || '').split(';')).filter(Boolean);
|
||||
tags[field.key].forEach(function(tagVal) {
|
||||
var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
|
||||
allValues = allValues.concat(thisVals);
|
||||
if (!commonValues) {
|
||||
commonValues = thisVals;
|
||||
@@ -544,9 +544,6 @@ export function uiFieldCombo(field, context) {
|
||||
.attr('class', 'remove')
|
||||
.text('×');
|
||||
|
||||
container.selectAll('input[type="text"]')
|
||||
.attr('maxlength', maxLength);
|
||||
|
||||
} else {
|
||||
var isMixed = Array.isArray(tags[field.key]);
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@ export function uiFieldCycleway(field, context) {
|
||||
.attr('class', 'preset-input-cycleway-wrap')
|
||||
.append('input')
|
||||
.attr('type', 'text')
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.attr('class', function(d) { return 'preset-input-cycleway preset-input-' + stripcolon(d); })
|
||||
.call(utilNoAuto)
|
||||
.each(function(d) {
|
||||
@@ -77,7 +76,7 @@ export function uiFieldCycleway(field, context) {
|
||||
|
||||
function change(key) {
|
||||
|
||||
var newValue = utilGetSetValue(d3_select(this));
|
||||
var newValue = context.cleanTagValue(utilGetSetValue(d3_select(this)));
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
|
||||
|
||||
@@ -56,7 +56,6 @@ export function uiFieldText(field, context) {
|
||||
.append('input')
|
||||
.attr('type', field.type === 'identifier' ? 'text' : field.type)
|
||||
.attr('id', field.domId)
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.classed(field.type, true)
|
||||
.call(utilNoAuto)
|
||||
.merge(input);
|
||||
@@ -167,13 +166,13 @@ export function uiFieldText(field, context) {
|
||||
function change(onInput) {
|
||||
return function() {
|
||||
var t = {};
|
||||
var val = utilGetSetValue(input).trim() || undefined;
|
||||
var val = context.cleanTagValue(utilGetSetValue(input));
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!val && Array.isArray(_tags[field.key])) return;
|
||||
|
||||
if (!onInput) {
|
||||
if (field.type === 'number' && val !== undefined) {
|
||||
if (field.type === 'number' && val) {
|
||||
var vals = val.split(';');
|
||||
vals = vals.map(function(v) {
|
||||
var num = parseFloat(v.trim(), 10);
|
||||
@@ -181,9 +180,9 @@ export function uiFieldText(field, context) {
|
||||
});
|
||||
val = vals.join(';');
|
||||
}
|
||||
utilGetSetValue(input, val || '');
|
||||
utilGetSetValue(input, val);
|
||||
}
|
||||
t[field.key] = val;
|
||||
t[field.key] = val || undefined;
|
||||
dispatch.call('change', this, t, onInput);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -170,7 +170,6 @@ export function uiFieldLocalized(field, context) {
|
||||
.attr('type', 'text')
|
||||
.attr('id', field.domId)
|
||||
.attr('class', 'localized-main')
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.call(utilNoAuto)
|
||||
.merge(input);
|
||||
|
||||
@@ -385,13 +384,15 @@ export function uiFieldLocalized(field, context) {
|
||||
d3_event.preventDefault();
|
||||
return;
|
||||
}
|
||||
var t = {};
|
||||
var val = utilGetSetValue(d3_select(this)) || undefined;
|
||||
|
||||
var val = context.cleanTagValue(utilGetSetValue(d3_select(this)));
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!val && Array.isArray(_tags[field.key])) return;
|
||||
|
||||
t[field.key] = val;
|
||||
var t = {};
|
||||
|
||||
t[field.key] = val || undefined;
|
||||
dispatch.call('change', this, t, onInput);
|
||||
};
|
||||
}
|
||||
@@ -420,12 +421,14 @@ export function uiFieldLocalized(field, context) {
|
||||
tags[key(d.lang)] = undefined;
|
||||
}
|
||||
|
||||
var newKey = lang && context.cleanTagKey(key(lang));
|
||||
|
||||
var value = utilGetSetValue(d3_select(this.parentNode).selectAll('.localized-value'));
|
||||
|
||||
if (lang && value) {
|
||||
tags[key(lang)] = value;
|
||||
} else if (lang && _wikiTitles && _wikiTitles[d.lang]) {
|
||||
tags[key(lang)] = _wikiTitles[d.lang];
|
||||
if (newKey && value) {
|
||||
tags[newKey] = value;
|
||||
} else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
|
||||
tags[newKey] = _wikiTitles[d.lang];
|
||||
}
|
||||
|
||||
d.lang = lang;
|
||||
@@ -435,7 +438,7 @@ export function uiFieldLocalized(field, context) {
|
||||
|
||||
function changeValue(d) {
|
||||
if (!d.lang) return;
|
||||
var value = utilGetSetValue(d3_select(this)) || undefined;
|
||||
var value = context.cleanTagValue(utilGetSetValue(d3_select(this))) || undefined;
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!value && Array.isArray(d.value)) return;
|
||||
@@ -549,7 +552,6 @@ export function uiFieldLocalized(field, context) {
|
||||
wrap
|
||||
.append('input')
|
||||
.attr('type', 'text')
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.attr('class', 'localized-value')
|
||||
.on('blur', changeValue)
|
||||
.on('change', changeValue);
|
||||
|
||||
@@ -43,7 +43,6 @@ export function uiFieldMaxspeed(field, context) {
|
||||
.attr('type', 'text')
|
||||
.attr('class', 'maxspeed-number')
|
||||
.attr('id', field.domId)
|
||||
.attr('maxlength', context.maxCharsForTagValue() - 4)
|
||||
.call(utilNoAuto)
|
||||
.call(speedCombo)
|
||||
.merge(input);
|
||||
@@ -95,7 +94,7 @@ export function uiFieldMaxspeed(field, context) {
|
||||
|
||||
function change() {
|
||||
var tag = {};
|
||||
var value = utilGetSetValue(input);
|
||||
var value = utilGetSetValue(input).trim();
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!value && Array.isArray(_tags[field.key])) return;
|
||||
@@ -103,9 +102,9 @@ export function uiFieldMaxspeed(field, context) {
|
||||
if (!value) {
|
||||
tag[field.key] = undefined;
|
||||
} else if (isNaN(value) || !_isImperial) {
|
||||
tag[field.key] = value;
|
||||
tag[field.key] = context.cleanTagValue(value);
|
||||
} else {
|
||||
tag[field.key] = value + ' mph';
|
||||
tag[field.key] = context.cleanTagValue(value + ' mph');
|
||||
}
|
||||
|
||||
dispatch.call('change', this, tag);
|
||||
|
||||
@@ -30,7 +30,6 @@ export function uiFieldTextarea(field, context) {
|
||||
input = input.enter()
|
||||
.append('textarea')
|
||||
.attr('id', field.domId)
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.call(utilNoAuto)
|
||||
.on('input', change(true))
|
||||
.on('blur', change())
|
||||
@@ -42,13 +41,13 @@ export function uiFieldTextarea(field, context) {
|
||||
function change(onInput) {
|
||||
return function() {
|
||||
|
||||
var val = utilGetSetValue(input) || undefined;
|
||||
var val = context.cleanTagValue(utilGetSetValue(input));
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!val && Array.isArray(_tags[field.key])) return;
|
||||
|
||||
var t = {};
|
||||
t[field.key] = val;
|
||||
t[field.key] = val || undefined;
|
||||
dispatch.call('change', this, t, onInput);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@ import { svgIcon } from '../../svg/icon';
|
||||
import {
|
||||
utilGetSetValue,
|
||||
utilNoAuto,
|
||||
utilRebind,
|
||||
utilUnicodeCharsTruncated
|
||||
utilRebind
|
||||
} from '../../util';
|
||||
|
||||
import { t } from '../../core/localizer';
|
||||
@@ -237,7 +236,7 @@ export function uiFieldWikidata(field, context) {
|
||||
}
|
||||
|
||||
if (newWikipediaValue) {
|
||||
newWikipediaValue = utilUnicodeCharsTruncated(newWikipediaValue, context.maxCharsForTagValue());
|
||||
newWikipediaValue = context.cleanTagValue(newWikipediaValue);
|
||||
}
|
||||
|
||||
if (typeof newWikipediaValue === 'undefined') return;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { actionChangeTags } from '../../actions/change_tags';
|
||||
import { services } from '../../services/index';
|
||||
import { svgIcon } from '../../svg/icon';
|
||||
import { uiCombobox } from '../combobox';
|
||||
import { utilGetSetValue, utilNoAuto, utilRebind, utilUnicodeCharsTruncated } from '../../util';
|
||||
import { utilGetSetValue, utilNoAuto, utilRebind } from '../../util';
|
||||
|
||||
|
||||
export function uiFieldWikipedia(field, context) {
|
||||
@@ -115,7 +115,6 @@ export function uiFieldWikipedia(field, context) {
|
||||
.attr('type', 'text')
|
||||
.attr('class', 'wiki-title')
|
||||
.attr('id', field.domId)
|
||||
.attr('maxlength', context.maxCharsForTagValue() - 4)
|
||||
.call(utilNoAuto)
|
||||
.call(titleCombo)
|
||||
.merge(_titleInput);
|
||||
@@ -192,7 +191,7 @@ export function uiFieldWikipedia(field, context) {
|
||||
}
|
||||
|
||||
if (value) {
|
||||
syncTags.wikipedia = utilUnicodeCharsTruncated(language()[2] + ':' + value, context.maxCharsForTagValue());
|
||||
syncTags.wikipedia = context.cleanTagValue(language()[2] + ':' + value);
|
||||
} else {
|
||||
syncTags.wikipedia = undefined;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export function uiSectionRawMemberEditor(context) {
|
||||
|
||||
function changeRole(d) {
|
||||
var oldRole = d.role;
|
||||
var newRole = d3_select(this).property('value');
|
||||
var newRole = context.cleanRelationRole(d3_select(this).property('value'));
|
||||
|
||||
if (oldRole !== newRole) {
|
||||
var member = { id: d.id, type: d.type, role: newRole };
|
||||
@@ -232,7 +232,6 @@ export function uiSectionRawMemberEditor(context) {
|
||||
return d.domId;
|
||||
})
|
||||
.property('type', 'text')
|
||||
.attr('maxlength', context.maxCharsForRelationRole())
|
||||
.attr('placeholder', t('inspector.role'))
|
||||
.call(utilNoAuto);
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ export function uiSectionRawMembershipEditor(context) {
|
||||
if (_inChange) return; // avoid accidental recursive call #5731
|
||||
|
||||
var oldRole = d.member.role;
|
||||
var newRole = d3_select(this).property('value');
|
||||
var newRole = context.cleanRelationRole(d3_select(this).property('value'));
|
||||
|
||||
if (oldRole !== newRole) {
|
||||
_inChange = true;
|
||||
@@ -267,7 +267,6 @@ export function uiSectionRawMembershipEditor(context) {
|
||||
return d.domId;
|
||||
})
|
||||
.property('type', 'text')
|
||||
.attr('maxlength', context.maxCharsForRelationRole())
|
||||
.attr('placeholder', t('inspector.role'))
|
||||
.call(utilNoAuto)
|
||||
.property('value', function(d) { return d.member.role; })
|
||||
@@ -315,7 +314,6 @@ export function uiSectionRawMembershipEditor(context) {
|
||||
.append('input')
|
||||
.attr('class', 'member-role')
|
||||
.property('type', 'text')
|
||||
.attr('maxlength', context.maxCharsForRelationRole())
|
||||
.attr('placeholder', t('inspector.role'))
|
||||
.call(utilNoAuto);
|
||||
|
||||
@@ -387,7 +385,7 @@ export function uiSectionRawMembershipEditor(context) {
|
||||
// remove hover-higlighting
|
||||
if (d.relation) utilHighlightEntities([d.relation.id], false, context);
|
||||
|
||||
var role = list.selectAll('.member-row-new .member-role').property('value');
|
||||
var role = context.cleanRelationRole(list.selectAll('.member-row-new .member-role').property('value'));
|
||||
addMembership(d, role);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { uiTagReference } from '../tag_reference';
|
||||
import { prefs } from '../../core/preferences';
|
||||
import { t } from '../../core/localizer';
|
||||
import { utilArrayDifference, utilArrayIdentical } from '../../util/array';
|
||||
import { utilGetSetValue, utilNoAuto, utilRebind, utilTagDiff, utilUnicodeCharsTruncated } from '../../util';
|
||||
import { utilGetSetValue, utilNoAuto, utilRebind, utilTagDiff } from '../../util';
|
||||
|
||||
export function uiSectionRawTagEditor(id, context) {
|
||||
|
||||
@@ -187,7 +187,6 @@ export function uiSectionRawTagEditor(id, context) {
|
||||
.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('class', 'key')
|
||||
.attr('maxlength', context.maxCharsForTagKey())
|
||||
.call(utilNoAuto)
|
||||
.on('blur', keyChange)
|
||||
.on('change', keyChange);
|
||||
@@ -198,7 +197,6 @@ export function uiSectionRawTagEditor(id, context) {
|
||||
.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('class', 'value')
|
||||
.attr('maxlength', context.maxCharsForTagValue())
|
||||
.call(utilNoAuto)
|
||||
.on('blur', valueChange)
|
||||
.on('change', valueChange)
|
||||
@@ -338,13 +336,11 @@ export function uiSectionRawTagEditor(id, context) {
|
||||
function textChanged() {
|
||||
var newText = this.value.trim();
|
||||
var newTags = {};
|
||||
var maxKeyLength = context.maxCharsForTagKey();
|
||||
var maxValueLength = context.maxCharsForTagValue();
|
||||
newText.split('\n').forEach(function(row) {
|
||||
var m = row.match(/^\s*([^=]+)=(.*)$/);
|
||||
if (m !== null) {
|
||||
var k = utilUnicodeCharsTruncated(unstringify(m[1].trim()), maxKeyLength);
|
||||
var v = utilUnicodeCharsTruncated(unstringify(m[2].trim()), maxValueLength);
|
||||
var k = context.cleanTagKey(unstringify(m[1].trim()));
|
||||
var v = context.cleanTagValue(unstringify(m[2].trim()));
|
||||
newTags[k] = v;
|
||||
}
|
||||
});
|
||||
@@ -461,10 +457,11 @@ export function uiSectionRawTagEditor(id, context) {
|
||||
if (d3_select(this).attr('readonly')) return;
|
||||
|
||||
var kOld = d.key;
|
||||
var kNew = this.value.trim();
|
||||
var row = this.parentNode.parentNode;
|
||||
var inputVal = d3_select(row).selectAll('input.value');
|
||||
var vNew = utilGetSetValue(inputVal);
|
||||
|
||||
// exit if we are currently about to delete this row anyway - #6366
|
||||
if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === undefined) return;
|
||||
|
||||
var kNew = context.cleanTagKey(this.value.trim());
|
||||
|
||||
// allow no change if the key should be readonly
|
||||
if (isReadOnly({ key: kNew })) {
|
||||
@@ -472,26 +469,29 @@ export function uiSectionRawTagEditor(id, context) {
|
||||
return;
|
||||
}
|
||||
|
||||
// switch focus if key is already in use
|
||||
if (kNew && kNew !== kOld) {
|
||||
if (_tags[kNew] !== undefined) { // new key is already in use
|
||||
this.value = kOld; // reset the key
|
||||
section.selection().selectAll('.tag-list input.value')
|
||||
.each(function(d) {
|
||||
if (d.key === kNew) { // send focus to that other value combo instead
|
||||
var input = d3_select(this).node();
|
||||
input.focus();
|
||||
input.select();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (kNew &&
|
||||
kNew !== kOld &&
|
||||
_tags[kNew] !== undefined) {
|
||||
// new key is already in use, switch focus to the existing row
|
||||
|
||||
this.value = kOld; // reset the key
|
||||
section.selection().selectAll('.tag-list input.value')
|
||||
.each(function(d) {
|
||||
if (d.key === kNew) { // send focus to that other value combo instead
|
||||
var input = d3_select(this).node();
|
||||
input.focus();
|
||||
input.select();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
_pendingChange = _pendingChange || {};
|
||||
|
||||
// exit if we are currently about to delete this row anyway - #6366
|
||||
if (_pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
|
||||
var row = this.parentNode.parentNode;
|
||||
var inputVal = d3_select(row).selectAll('input.value');
|
||||
var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
|
||||
|
||||
_pendingChange = _pendingChange || {};
|
||||
|
||||
if (kOld) {
|
||||
_pendingChange[kOld] = undefined;
|
||||
@@ -517,12 +517,12 @@ export function uiSectionRawTagEditor(id, context) {
|
||||
// exit if this is a multiselection and no value was entered
|
||||
if (typeof d.value !== 'string' && !this.value) return;
|
||||
|
||||
_pendingChange = _pendingChange || {};
|
||||
|
||||
// exit if we are currently about to delete this row anyway - #6366
|
||||
if (_pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
|
||||
if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
|
||||
|
||||
_pendingChange[d.key] = this.value;
|
||||
_pendingChange = _pendingChange || {};
|
||||
|
||||
_pendingChange[d.key] = context.cleanTagValue(this.value);
|
||||
scheduleChange();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user