simplify raw tag editor ui and logic (#10889)

* always show empty line at bottom of the tag list to allow adding more tags (replaces `+` button and tab logic)
* disable delete and info buttons on empty tag
* replace deferring of tag change events and re-rendering with a simpler logic (to fix issues like #10871):
  only set input field values if the rendering event was triggered by an external event, or by a change of the respective field in the raw tag editor itself
* skip delete and tag info buttons while navigating using tab: makes it more quick to get to where one typically needs to, deleting a key using the keyboard only is possible by emptying the tag's key, and advanced users are not typically using the `i` button anyway
This commit is contained in:
Martin Raifer
2025-05-12 18:21:55 +02:00
committed by GitHub
parent 7f8e676af3
commit ac59197632
5 changed files with 55 additions and 115 deletions

View File

@@ -1,5 +1,3 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.uiSectionRawTagEditor', function() {
var taglist, element, entity, context;
@@ -37,40 +35,22 @@ describe('iD.uiSectionRawTagEditor', function() {
it('creates a pair of empty input elements if the entity has no tags', function () {
element.remove();
render({});
expect(element.selectAll('.tag-list li').nodes().length).to.eql(1);
expect(element.select('.tag-list').selectAll('input.value').property('value')).to.be.empty;
expect(element.select('.tag-list').selectAll('input.key').property('value')).to.be.empty;
});
it('adds tags when clicking the add button', async () => {
happen.click(element.selectAll('button.add-tag').node());
await setTimeout(20);
expect(element.select('.tag-list').selectAll('input').nodes()[2].value).to.be.empty;
expect(element.select('.tag-list').selectAll('input').nodes()[3].value).to.be.empty;
});
it('removes tags when clicking the remove button', async () => {
iD.utilTriggerEvent(element.selectAll('button.remove'), 'mousedown', { button: 0 });
const tags = await new Promise(cb => {
taglist.on('change', (_, tags) => cb(tags));
});
expect(tags).to.eql({highway: undefined});
});
it('adds tags when pressing the TAB key on last input.value', async () => {
expect(element.selectAll('.tag-list li').nodes().length).to.eql(1);
var input = d3.select('.tag-list li:last-child input.value').nodes()[0];
happen.keydown(d3.select(input).node(), {keyCode: 9});
await setTimeout(20);
it('adds pair of empty input elements at end of list', () => {
expect(element.selectAll('.tag-list li').nodes().length).to.eql(2);
expect(element.select('.tag-list').selectAll('input').nodes()[2].value).to.be.empty;
expect(element.select('.tag-list').selectAll('input').nodes()[3].value).to.be.empty;
});
it('does not add a tag when pressing TAB while shift is pressed', async () => {
expect(element.selectAll('.tag-list li').nodes().length).to.eql(1);
var input = d3.select('.tag-list li:last-child input.value').nodes()[0];
happen.keydown(d3.select(input).node(), {keyCode: 9, shiftKey: true});
await setTimeout(20);
expect(element.selectAll('.tag-list li').nodes().length).to.eql(1);
it('removes tags when clicking the remove button', async () => {
const tags = new Promise(cb => {
taglist.on('change', (_, tags) => cb(tags));
});
iD.utilTriggerEvent(element.selectAll('button.remove'), 'mousedown', { button: 0 });
expect(await tags).to.eql({highway: undefined});
});
});