mirror of
https://github.com/FoggedLens/iD.git
synced 2026-03-28 23:10:40 +01:00
Merge pull request #6302 from openstreetmap/text-raw-tag-editor
Text raw tag editor / Copy-paste tags
This commit is contained in:
@@ -55,9 +55,12 @@ module.exports = function buildData() {
|
||||
|
||||
// Font Awesome icons used
|
||||
var faIcons = {
|
||||
'fas-long-arrow-alt-right': {}
|
||||
'fas-i-cursor': {},
|
||||
'fas-long-arrow-alt-right': {},
|
||||
'fas-th-list': {}
|
||||
};
|
||||
|
||||
// The Noun Project icons used
|
||||
var tnpIcons = {};
|
||||
|
||||
// Start clean
|
||||
|
||||
@@ -259,10 +259,12 @@ table.tags, table.tags td, table.tags th {
|
||||
.ar { right: 0; }
|
||||
|
||||
input.hide,
|
||||
textarea.hide,
|
||||
div.hide,
|
||||
form.hide,
|
||||
button.hide,
|
||||
a.hide,
|
||||
ul.hide,
|
||||
li.hide {
|
||||
display: none;
|
||||
}
|
||||
@@ -2401,8 +2403,56 @@ div.combobox {
|
||||
|
||||
/* Raw Tag Editor
|
||||
------------------------------------------------------- */
|
||||
.raw-tag-options {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
flex-direction: row-reverse;
|
||||
margin-top: -25px;
|
||||
padding: 0 3px;
|
||||
}
|
||||
button.raw-tag-option {
|
||||
flex: 0 0 20px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: #aaa;
|
||||
color: #eee;
|
||||
margin: 0 3px;
|
||||
}
|
||||
button.raw-tag-option:focus,
|
||||
button.raw-tag-option:hover,
|
||||
button.raw-tag-option.active {
|
||||
color: #fff;
|
||||
background: #597be7;
|
||||
}
|
||||
button.raw-tag-option.selected {
|
||||
color: #fff;
|
||||
background: #7092ff;
|
||||
}
|
||||
button.raw-tag-option svg.icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
[dir='ltr'] button.raw-tag-option-list {
|
||||
-moz-transform: scaleX(-1);
|
||||
-o-transform: scaleX(-1);
|
||||
-webkit-transform: scaleX(-1);
|
||||
transform: scaleX(-1);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
|
||||
|
||||
.tag-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.tag-text,
|
||||
.tag-list {
|
||||
padding-top: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.tag-row {
|
||||
width: 100%;
|
||||
|
||||
@@ -17,7 +17,7 @@ import { uiTagReference } from './tag_reference';
|
||||
import { uiPresetEditor } from './preset_editor';
|
||||
import { uiEntityIssues } from './entity_issues';
|
||||
import { uiTooltipHtml } from './tooltipHtml';
|
||||
import { utilCleanTags, utilRebind } from '../util';
|
||||
import { utilCallWhenIdle, utilCleanTags, utilRebind } from '../util';
|
||||
|
||||
|
||||
export function uiEntityEditor(context) {
|
||||
@@ -25,6 +25,7 @@ export function uiEntityEditor(context) {
|
||||
var _state = 'select';
|
||||
var _coalesceChanges = false;
|
||||
var _modified = false;
|
||||
var _scrolled = false;
|
||||
var _base;
|
||||
var _entityID;
|
||||
var _activePreset;
|
||||
@@ -83,7 +84,8 @@ export function uiEntityEditor(context) {
|
||||
// Enter
|
||||
var bodyEnter = body.enter()
|
||||
.append('div')
|
||||
.attr('class', 'inspector-body');
|
||||
.attr('class', 'inspector-body')
|
||||
.on('scroll.entity-editor', function() { _scrolled = true; });
|
||||
|
||||
bodyEnter
|
||||
.append('div')
|
||||
@@ -327,9 +329,14 @@ export function uiEntityEditor(context) {
|
||||
_coalesceChanges = false;
|
||||
|
||||
// reset the scroll to the top of the inspector (warning: triggers reflow)
|
||||
var body = d3_selectAll('.entity-editor-pane .inspector-body');
|
||||
if (!body.empty()) {
|
||||
body.node().scrollTop = 0;
|
||||
if (_scrolled) {
|
||||
utilCallWhenIdle(function() {
|
||||
var body = d3_selectAll('.entity-editor-pane .inspector-body');
|
||||
if (!body.empty()) {
|
||||
_scrolled = false;
|
||||
body.node().scrollTop = 0;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
var presetMatch = context.presets().match(context.entity(_entityID), _base);
|
||||
|
||||
@@ -7,12 +7,18 @@ import { svgIcon } from '../svg/icon';
|
||||
import { uiCombobox } from './combobox';
|
||||
import { uiDisclosure } from './disclosure';
|
||||
import { uiTagReference } from './tag_reference';
|
||||
import { utilArrayDifference, utilGetSetValue, utilNoAuto, utilRebind } from '../util';
|
||||
import { utilArrayDifference, utilGetSetValue, utilNoAuto, utilRebind, utilTagDiff } from '../util';
|
||||
|
||||
|
||||
export function uiRawTagEditor(context) {
|
||||
var taginfo = services.taginfo;
|
||||
var dispatch = d3_dispatch('change');
|
||||
var availableViews = [
|
||||
{ id: 'text', icon: '#fas-i-cursor' },
|
||||
{ id: 'list', icon: '#fas-th-list' }
|
||||
];
|
||||
|
||||
var _tagView = (context.storage('raw-tag-editor-view') || 'list'); // 'list, 'text'
|
||||
var _readOnlyTags = [];
|
||||
var _indexedKeys = [];
|
||||
var _showBlank = false;
|
||||
@@ -75,13 +81,80 @@ export function uiRawTagEditor(context) {
|
||||
rowData.push({ index: _indexedKeys.length, key: '', value: '' });
|
||||
}
|
||||
|
||||
// List of tags
|
||||
|
||||
// View Options
|
||||
var options = wrap.selectAll('.raw-tag-options')
|
||||
.data([0]);
|
||||
|
||||
var optionsEnter = options.enter()
|
||||
.append('div')
|
||||
.attr('class', 'raw-tag-options');
|
||||
|
||||
var optionEnter = optionsEnter.selectAll('.raw-tag-option')
|
||||
.data(availableViews, function(d) { return d.id; })
|
||||
.enter();
|
||||
|
||||
optionEnter
|
||||
.append('button')
|
||||
.attr('class', function(d) {
|
||||
return 'raw-tag-option raw-tag-option-' + d.id + (_tagView === d.id ? ' selected' : '');
|
||||
})
|
||||
.attr('title', function(d) { return d.id; })
|
||||
.on('click', function(d) {
|
||||
_tagView = d.id;
|
||||
context.storage('raw-tag-editor-view', d.id);
|
||||
|
||||
wrap.selectAll('.raw-tag-option')
|
||||
.classed('selected', function(datum) { return datum === d; });
|
||||
|
||||
wrap.selectAll('.tag-text')
|
||||
.classed('hide', (d.id !== 'text'))
|
||||
.each(setTextareaHeight);
|
||||
|
||||
wrap.selectAll('.tag-list, .add-row')
|
||||
.classed('hide', (d.id !== 'list'));
|
||||
})
|
||||
.each(function(d) {
|
||||
d3_select(this)
|
||||
.call(svgIcon(d.icon));
|
||||
});
|
||||
|
||||
|
||||
// View as Text
|
||||
var textData = rowsToText(rowData);
|
||||
var textarea = wrap.selectAll('.tag-text')
|
||||
.data([0]);
|
||||
|
||||
textarea = textarea.enter()
|
||||
.append('textarea')
|
||||
.attr('class', 'tag-text' + (_tagView !== 'text' ? ' hide' : ''))
|
||||
.call(utilNoAuto)
|
||||
.attr('spellcheck', 'false')
|
||||
.merge(textarea);
|
||||
|
||||
textarea
|
||||
.call(utilGetSetValue, textData)
|
||||
.each(setTextareaHeight)
|
||||
.on('input', setTextareaHeight)
|
||||
.on('blur', textChanged)
|
||||
.on('change', textChanged);
|
||||
|
||||
// If All Fields section is hidden, focus textarea and put cursor at end..
|
||||
var fieldsExpanded = d3_select('.hide-toggle-preset_fields.expanded').size();
|
||||
if (_state !== 'hover' && _tagView === 'text' && !fieldsExpanded) {
|
||||
var element = textarea.node();
|
||||
element.focus();
|
||||
element.setSelectionRange(textData.length, textData.length);
|
||||
}
|
||||
|
||||
|
||||
// View as List
|
||||
var list = wrap.selectAll('.tag-list')
|
||||
.data([0]);
|
||||
|
||||
list = list.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'tag-list')
|
||||
.attr('class', 'tag-list' + (_tagView !== 'list' ? ' hide' : ''))
|
||||
.merge(list);
|
||||
|
||||
|
||||
@@ -90,7 +163,7 @@ export function uiRawTagEditor(context) {
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'add-row');
|
||||
.attr('class', 'add-row' + (_tagView !== 'list' ? ' hide' : ''));
|
||||
|
||||
addRowEnter
|
||||
.append('button')
|
||||
@@ -217,6 +290,75 @@ export function uiRawTagEditor(context) {
|
||||
}
|
||||
|
||||
|
||||
function setTextareaHeight() {
|
||||
if (_tagView !== 'text') return;
|
||||
|
||||
var selection = d3_select(this);
|
||||
selection.style('height', null);
|
||||
selection.style('height', selection.node().scrollHeight + 5 + 'px');
|
||||
}
|
||||
|
||||
|
||||
function stringify(s) {
|
||||
return JSON.stringify(s).slice(1, -1); // without leading/trailing "
|
||||
}
|
||||
|
||||
function unstringify(s) {
|
||||
var leading = '';
|
||||
var trailing = '';
|
||||
if (s.length < 1 || s.charAt(0) !== '"') {
|
||||
leading = '"';
|
||||
}
|
||||
if (s.length < 2 || s.charAt(s.length - 1) !== '"' ||
|
||||
(s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === '\\')
|
||||
) {
|
||||
trailing = '"';
|
||||
}
|
||||
return JSON.parse(leading + s + trailing);
|
||||
}
|
||||
|
||||
|
||||
function rowsToText(rows) {
|
||||
var str = rows
|
||||
.filter(function(row) { return row.key && row.key.trim() !== ''; })
|
||||
.map(function(row) { return stringify(row.key) + '=' + stringify(row.value); })
|
||||
.join('\n');
|
||||
|
||||
return _state === 'hover' ? str : str + '\n';
|
||||
}
|
||||
|
||||
|
||||
function textChanged() {
|
||||
var newText = this.value.trim();
|
||||
var newTags = {};
|
||||
newText.split('\n').forEach(function(row) {
|
||||
var m = row.match(/^\s*([^=]+)=(.*)$/);
|
||||
if (m !== null) {
|
||||
var k = unstringify(m[1].trim());
|
||||
var v = unstringify(m[2].trim());
|
||||
newTags[k] = v;
|
||||
}
|
||||
});
|
||||
|
||||
var tagDiff = utilTagDiff(_tags, newTags);
|
||||
if (!tagDiff.length) return;
|
||||
|
||||
_pendingChange = _pendingChange || {};
|
||||
|
||||
tagDiff.forEach(function(change) {
|
||||
if (isReadOnly({ key: change.key })) return;
|
||||
|
||||
if (change.type === '-') {
|
||||
_pendingChange[change.key] = undefined;
|
||||
} else if (change.type === '+') {
|
||||
_pendingChange[change.key] = change.newVal || '';
|
||||
}
|
||||
});
|
||||
|
||||
scheduleChange();
|
||||
}
|
||||
|
||||
|
||||
function pushMore() {
|
||||
if (d3_event.keyCode === 9 && !d3_event.shiftKey &&
|
||||
list.selectAll('li:last-child input.value').node() === this) {
|
||||
@@ -317,25 +459,7 @@ export function uiRawTagEditor(context) {
|
||||
_pendingChange[kOld] = undefined;
|
||||
}
|
||||
|
||||
// if the key looks like "key=value key2=value2", split them up - #5024
|
||||
var keys = (kNew.match(/[\w_]+=/g) || []).map(function (key) { return key.slice(0, -1); });
|
||||
var vals = keys.length === 0
|
||||
? []
|
||||
: kNew
|
||||
.split(new RegExp(keys.map(function (key) { return key.replace('_', '\\_'); }).join('|')))
|
||||
.splice(1)
|
||||
.map(function (val) { return val.slice(1).trim(); });
|
||||
|
||||
if (keys.length > 0) {
|
||||
kNew = keys[0];
|
||||
vNew = vals[0];
|
||||
|
||||
keys.forEach(function (key, i) {
|
||||
_pendingChange[key] = vals[i];
|
||||
});
|
||||
} else {
|
||||
_pendingChange[kNew] = vNew;
|
||||
}
|
||||
_pendingChange[kNew] = vNew;
|
||||
|
||||
d.key = kNew; // update datum to avoid exit/enter on tag update
|
||||
d.value = vNew;
|
||||
|
||||
@@ -38,6 +38,7 @@ export { utilRebind } from './rebind';
|
||||
export { utilSetTransform } from './util';
|
||||
export { utilSessionMutex } from './session_mutex';
|
||||
export { utilStringQs } from './util';
|
||||
export { utilTagDiff } from './util';
|
||||
export { utilTagText } from './util';
|
||||
export { utilTiler } from './tiler';
|
||||
export { utilTriggerEvent } from './trigger_event';
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { t, textDirection } from './locale';
|
||||
import { utilDetect } from './detect';
|
||||
import { remove as removeDiacritics } from 'diacritics';
|
||||
import { fixRTLTextForSvg, rtlRegex } from './svg_paths_rtl_fix';
|
||||
|
||||
import { t, textDirection } from './locale';
|
||||
import { utilArrayUnion } from './array';
|
||||
import { utilDetect } from './detect';
|
||||
|
||||
|
||||
export function utilTagText(entity) {
|
||||
var obj = (entity && entity.tags) || {};
|
||||
@@ -12,6 +14,36 @@ export function utilTagText(entity) {
|
||||
}
|
||||
|
||||
|
||||
export function utilTagDiff(oldTags, newTags) {
|
||||
var tagDiff = [];
|
||||
var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
|
||||
keys.forEach(function(k) {
|
||||
var oldVal = oldTags[k];
|
||||
var newVal = newTags[k];
|
||||
|
||||
if (oldVal && (!newVal || newVal !== oldVal)) {
|
||||
tagDiff.push({
|
||||
type: '-',
|
||||
key: k,
|
||||
oldVal: oldVal,
|
||||
newVal: newVal,
|
||||
display: '- ' + k + '=' + oldVal
|
||||
});
|
||||
}
|
||||
if (newVal && (!oldVal || newVal !== oldVal)) {
|
||||
tagDiff.push({
|
||||
type: '+',
|
||||
key: k,
|
||||
oldVal: oldVal,
|
||||
newVal: newVal,
|
||||
display: '+ ' + k + '=' + newVal
|
||||
});
|
||||
}
|
||||
});
|
||||
return tagDiff;
|
||||
}
|
||||
|
||||
|
||||
export function utilEntitySelector(ids) {
|
||||
return ids.length ? '.' + ids.join(',.') : 'nothing';
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { actionChangePreset } from '../actions/change_preset';
|
||||
import { actionChangeTags } from '../actions/change_tags';
|
||||
import { actionUpgradeTags } from '../actions/upgrade_tags';
|
||||
import { osmIsOldMultipolygonOuterMember, osmOldMultipolygonOuterMemberOfRelation } from '../osm/multipolygon';
|
||||
import { utilArrayUnion, utilDisplayLabel } from '../util';
|
||||
import { utilDisplayLabel, utilTagDiff } from '../util';
|
||||
import { validationIssue, validationIssueFix } from '../core/validation';
|
||||
|
||||
|
||||
@@ -48,20 +48,7 @@ export function validationOutdatedTags() {
|
||||
}
|
||||
|
||||
// determine diff
|
||||
var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
|
||||
var tagDiff = [];
|
||||
keys.forEach(function(k) {
|
||||
var oldVal = oldTags[k];
|
||||
var newVal = newTags[k];
|
||||
|
||||
if (oldVal && (!newVal || newVal !== oldVal)) {
|
||||
tagDiff.push('- ' + k + '=' + oldVal);
|
||||
}
|
||||
if (newVal && (!oldVal || newVal !== oldVal)) {
|
||||
tagDiff.push('+ ' + k + '=' + newVal);
|
||||
}
|
||||
});
|
||||
|
||||
var tagDiff = utilTagDiff(oldTags, newTags);
|
||||
if (!tagDiff.length) return [];
|
||||
|
||||
return [new validationIssue({
|
||||
@@ -113,10 +100,10 @@ export function validationOutdatedTags() {
|
||||
.attr('class', 'tagDiff-row')
|
||||
.append('td')
|
||||
.attr('class', function(d) {
|
||||
var klass = d.charAt(0) === '+' ? 'add' : 'remove';
|
||||
var klass = d.type === '+' ? 'add' : 'remove';
|
||||
return 'tagDiff-cell tagDiff-cell-' + klass;
|
||||
})
|
||||
.text(function(d) { return d; });
|
||||
.text(function(d) { return d.display; });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { actionChangeTags } from '../actions/change_tags';
|
||||
import { t } from '../util/locale';
|
||||
import { utilDisplayLabel } from '../util';
|
||||
import { utilDisplayLabel, utilTagDiff } from '../util';
|
||||
import { validationIssue, validationIssueFix } from '../core/validation';
|
||||
|
||||
|
||||
@@ -40,20 +40,17 @@ export function validationPrivateData() {
|
||||
|
||||
var validation = function checkPrivateData(entity, context) {
|
||||
var tags = entity.tags;
|
||||
var keepTags = {};
|
||||
var tagDiff = [];
|
||||
if (!tags.building || !privateBuildingValues[tags.building]) return [];
|
||||
|
||||
var keepTags = {};
|
||||
for (var k in tags) {
|
||||
if (publicKeys[k]) return []; // probably a public feature
|
||||
|
||||
if (personalTags[k]) {
|
||||
tagDiff.push('- ' + k + '=' + tags[k]);
|
||||
} else {
|
||||
if (!personalTags[k]) {
|
||||
keepTags[k] = tags[k];
|
||||
}
|
||||
}
|
||||
|
||||
var tagDiff = utilTagDiff(tags, keepTags);
|
||||
if (!tagDiff.length) return [];
|
||||
|
||||
var fixID = tagDiff.length === 1 ? 'remove_tag' : 'remove_tags';
|
||||
@@ -110,10 +107,10 @@ export function validationPrivateData() {
|
||||
.attr('class', 'tagDiff-row')
|
||||
.append('td')
|
||||
.attr('class', function(d) {
|
||||
var klass = d.charAt(0) === '+' ? 'add' : 'remove';
|
||||
var klass = d.type === '+' ? 'add' : 'remove';
|
||||
return 'tagDiff-cell tagDiff-cell-' + klass;
|
||||
})
|
||||
.text(function(d) { return d; });
|
||||
.text(function(d) { return d.display; });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
1
svg/fontawesome/fas-i-cursor.svg
Normal file
1
svg/fontawesome/fas-i-cursor.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="i-cursor" class="svg-inline--fa fa-i-cursor fa-w-8" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 512"><path fill="currentColor" d="M256 52.048V12.065C256 5.496 250.726.148 244.158.066 211.621-.344 166.469.011 128 37.959 90.266.736 46.979-.114 11.913.114 5.318.157 0 5.519 0 12.114v39.645c0 6.687 5.458 12.078 12.145 11.998C38.111 63.447 96 67.243 96 112.182V224H60c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h36v112c0 44.932-56.075 48.031-83.95 47.959C5.404 447.942 0 453.306 0 459.952v39.983c0 6.569 5.274 11.917 11.842 11.999 32.537.409 77.689.054 116.158-37.894 37.734 37.223 81.021 38.073 116.087 37.845 6.595-.043 11.913-5.405 11.913-12V460.24c0-6.687-5.458-12.078-12.145-11.998C217.889 448.553 160 444.939 160 400V288h36c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-36V112.182c0-44.932 56.075-48.213 83.95-48.142 6.646.018 12.05-5.346 12.05-11.992z"></path></svg>
|
||||
|
After Width: | Height: | Size: 970 B |
1
svg/fontawesome/fas-th-list.svg
Normal file
1
svg/fontawesome/fas-th-list.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="th-list" class="svg-inline--fa fa-th-list fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M149.333 216v80c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-80c0-13.255 10.745-24 24-24h101.333c13.255 0 24 10.745 24 24zM0 376v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zM125.333 32H24C10.745 32 0 42.745 0 56v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24zm80 448H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24zm-24-424v80c0 13.255 10.745 24 24 24H488c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24zm24 264H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1004 B |
@@ -2,57 +2,76 @@ describe('iD.util', function() {
|
||||
|
||||
describe('utilGetAllNodes', function() {
|
||||
it('gets all descendant nodes of a way', function() {
|
||||
var a = iD.osmNode({ id: 'a' }),
|
||||
b = iD.osmNode({ id: 'b' }),
|
||||
w = iD.osmWay({ id: 'w', nodes: ['a','b','a'] }),
|
||||
graph = iD.coreGraph([a, b, w]),
|
||||
result = iD.utilGetAllNodes(['w'], graph);
|
||||
var a = iD.osmNode({ id: 'a' });
|
||||
var b = iD.osmNode({ id: 'b' });
|
||||
var w = iD.osmWay({ id: 'w', nodes: ['a','b','a'] });
|
||||
var graph = iD.coreGraph([a, b, w]);
|
||||
var result = iD.utilGetAllNodes(['w'], graph);
|
||||
|
||||
expect(result).to.have.members([a, b]);
|
||||
expect(result).to.have.lengthOf(2);
|
||||
});
|
||||
|
||||
it('gets all descendant nodes of a relation', function() {
|
||||
var a = iD.osmNode({ id: 'a' }),
|
||||
b = iD.osmNode({ id: 'b' }),
|
||||
c = iD.osmNode({ id: 'c' }),
|
||||
w = iD.osmWay({ id: 'w', nodes: ['a','b','a'] }),
|
||||
r = iD.osmRelation({ id: 'r', members: [{id: 'w'}, {id: 'c'}] }),
|
||||
graph = iD.coreGraph([a, b, c, w, r]),
|
||||
result = iD.utilGetAllNodes(['r'], graph);
|
||||
var a = iD.osmNode({ id: 'a' });
|
||||
var b = iD.osmNode({ id: 'b' });
|
||||
var c = iD.osmNode({ id: 'c' });
|
||||
var w = iD.osmWay({ id: 'w', nodes: ['a','b','a'] });
|
||||
var r = iD.osmRelation({ id: 'r', members: [{id: 'w'}, {id: 'c'}] });
|
||||
var graph = iD.coreGraph([a, b, c, w, r]);
|
||||
var result = iD.utilGetAllNodes(['r'], graph);
|
||||
|
||||
expect(result).to.have.members([a, b, c]);
|
||||
expect(result).to.have.lengthOf(3);
|
||||
});
|
||||
|
||||
it('gets all descendant nodes of multiple ids', function() {
|
||||
var a = iD.osmNode({ id: 'a' }),
|
||||
b = iD.osmNode({ id: 'b' }),
|
||||
c = iD.osmNode({ id: 'c' }),
|
||||
d = iD.osmNode({ id: 'd' }),
|
||||
e = iD.osmNode({ id: 'e' }),
|
||||
w1 = iD.osmWay({ id: 'w1', nodes: ['a','b','a'] }),
|
||||
w2 = iD.osmWay({ id: 'w2', nodes: ['c','b','a','c'] }),
|
||||
r = iD.osmRelation({ id: 'r', members: [{id: 'w1'}, {id: 'd'}] }),
|
||||
graph = iD.coreGraph([a, b, c, d, e, w1, w2, r]),
|
||||
result = iD.utilGetAllNodes(['r', 'w2', 'e'], graph);
|
||||
var a = iD.osmNode({ id: 'a' });
|
||||
var b = iD.osmNode({ id: 'b' });
|
||||
var c = iD.osmNode({ id: 'c' });
|
||||
var d = iD.osmNode({ id: 'd' });
|
||||
var e = iD.osmNode({ id: 'e' });
|
||||
var w1 = iD.osmWay({ id: 'w1', nodes: ['a','b','a'] });
|
||||
var w2 = iD.osmWay({ id: 'w2', nodes: ['c','b','a','c'] });
|
||||
var r = iD.osmRelation({ id: 'r', members: [{id: 'w1'}, {id: 'd'}] });
|
||||
var graph = iD.coreGraph([a, b, c, d, e, w1, w2, r]);
|
||||
var result = iD.utilGetAllNodes(['r', 'w2', 'e'], graph);
|
||||
|
||||
expect(result).to.have.members([a, b, c, d, e]);
|
||||
expect(result).to.have.lengthOf(5);
|
||||
});
|
||||
|
||||
it('handles recursive relations', function() {
|
||||
var a = iD.osmNode({ id: 'a' }),
|
||||
r1 = iD.osmRelation({ id: 'r1', members: [{id: 'r2'}] }),
|
||||
r2 = iD.osmRelation({ id: 'r2', members: [{id: 'r1'}, {id: 'a'}] }),
|
||||
graph = iD.coreGraph([a, r1, r2]),
|
||||
result = iD.utilGetAllNodes(['r1'], graph);
|
||||
var a = iD.osmNode({ id: 'a' });
|
||||
var r1 = iD.osmRelation({ id: 'r1', members: [{id: 'r2'}] });
|
||||
var r2 = iD.osmRelation({ id: 'r2', members: [{id: 'r1'}, {id: 'a'}] });
|
||||
var graph = iD.coreGraph([a, r1, r2]);
|
||||
var result = iD.utilGetAllNodes(['r1'], graph);
|
||||
|
||||
expect(result).to.have.members([a]);
|
||||
expect(result).to.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('utilTagDiff', function() {
|
||||
var oldTags = { a: 'one', b: 'two', c: 'three' };
|
||||
var newTags = { a: 'one', b: 'three', d: 'four' };
|
||||
var diff = iD.utilTagDiff(oldTags, newTags);
|
||||
expect(diff).to.have.length(4);
|
||||
expect(diff[0]).to.eql({
|
||||
type: '-', key: 'b', oldVal: 'two', newVal: 'three', display: '- b=two' // delete-modify
|
||||
});
|
||||
expect(diff[1]).to.eql({
|
||||
type: '+', key: 'b', oldVal: 'two', newVal: 'three', display: '+ b=three' // insert-modify
|
||||
});
|
||||
expect(diff[2]).to.eql({
|
||||
type: '-', key: 'c', oldVal: 'three', newVal: undefined, display: '- c=three' // delete
|
||||
});
|
||||
expect(diff[3]).to.eql({
|
||||
type: '+', key: 'd', oldVal: undefined, newVal: 'four', display: '+ d=four' // insert
|
||||
});
|
||||
});
|
||||
|
||||
it('utilTagText', function() {
|
||||
expect(iD.utilTagText({})).to.eql('');
|
||||
expect(iD.utilTagText({tags:{foo:'bar'}})).to.eql('foo=bar');
|
||||
|
||||
Reference in New Issue
Block a user