mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 17:23:02 +00:00
This is cleaner than adding hooks to transitionable actions, or performing validation on every history change. We want validation to run after each operation, but not while the user is drawing lines or typing in fields.
233 lines
7.3 KiB
JavaScript
233 lines
7.3 KiB
JavaScript
import { event as d3_event, select as d3_select } from 'd3-selection';
|
|
|
|
import { svgIcon } from '../svg/icon';
|
|
import { t } from '../util/locale';
|
|
import { uiDisclosure } from './disclosure';
|
|
import { utilHighlightEntities } from '../util';
|
|
|
|
|
|
export function uiEntityIssues(context) {
|
|
var _selection = d3_select(null);
|
|
var _activeIssueID;
|
|
var _entityID;
|
|
|
|
// Refresh on validated events
|
|
context.validator().on('validated.entity_issues', function() {
|
|
_selection.selectAll('.disclosure-wrap-entity_issues')
|
|
.call(render);
|
|
|
|
update();
|
|
});
|
|
|
|
|
|
function entityIssues(selection) {
|
|
_selection = selection;
|
|
|
|
selection
|
|
.call(uiDisclosure(context, 'entity_issues', true)
|
|
.content(render)
|
|
);
|
|
|
|
update();
|
|
}
|
|
|
|
|
|
function update() {
|
|
var issues = context.validator().getEntityIssues(_entityID);
|
|
|
|
_selection
|
|
.classed('hide', issues.length === 0);
|
|
|
|
_selection.selectAll('.hide-toggle-entity_issues span')
|
|
.text(t('issues.list_title', { count: issues.length }));
|
|
}
|
|
|
|
|
|
function render(selection) {
|
|
var issues = context.validator().getEntityIssues(_entityID);
|
|
_activeIssueID = issues.length > 0 ? issues[0].id : null;
|
|
|
|
|
|
var containers = selection.selectAll('.issue-container')
|
|
.data(issues, function(d) { return d.id; });
|
|
|
|
// Exit
|
|
containers.exit()
|
|
.remove();
|
|
|
|
// Enter
|
|
var containersEnter = containers.enter()
|
|
.append('div')
|
|
.attr('class', 'issue-container');
|
|
|
|
|
|
var itemsEnter = containersEnter
|
|
.append('div')
|
|
.attr('class', function(d) { return 'issue severity-' + d.severity; })
|
|
.on('mouseover.highlight', function(d) {
|
|
// don't hover-highlight the selected entity
|
|
var ids = d.entityIds
|
|
.filter(function(e) { return e !== _entityID; });
|
|
|
|
utilHighlightEntities(ids, true, context);
|
|
})
|
|
.on('mouseout.highlight', function(d) {
|
|
var ids = d.entityIds
|
|
.filter(function(e) { return e !== _entityID; });
|
|
|
|
utilHighlightEntities(ids, false, context);
|
|
});
|
|
|
|
var labelsEnter = itemsEnter
|
|
.append('div')
|
|
.attr('class', 'issue-label')
|
|
.on('click', function(d) {
|
|
_activeIssueID = d.id; // expand only the clicked item
|
|
selection.selectAll('.issue-container')
|
|
.classed('active', function(d) { return d.id === _activeIssueID; });
|
|
|
|
var extent = d.extent(context.graph());
|
|
if (extent) {
|
|
var setZoom = Math.max(context.map().zoom(), 19);
|
|
context.map().centerZoomEase(extent.center(), setZoom);
|
|
}
|
|
});
|
|
|
|
var textEnter = labelsEnter
|
|
.append('span')
|
|
.attr('class', 'issue-text');
|
|
|
|
textEnter
|
|
.append('span')
|
|
.attr('class', 'issue-icon')
|
|
.each(function(d) {
|
|
var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
|
|
d3_select(this)
|
|
.call(svgIcon(iconName));
|
|
});
|
|
|
|
textEnter
|
|
.append('span')
|
|
.attr('class', 'issue-message')
|
|
.text(function(d) { return d.message; });
|
|
|
|
|
|
var infoButton = labelsEnter
|
|
.append('button')
|
|
.attr('class', 'issue-info-button')
|
|
.attr('title', t('icons.information'))
|
|
.attr('tabindex', -1)
|
|
.call(svgIcon('#iD-icon-inspect'));
|
|
|
|
infoButton
|
|
.on('click', function () {
|
|
d3_event.stopPropagation();
|
|
d3_event.preventDefault();
|
|
this.blur(); // avoid keeping focus on the button - #4641
|
|
|
|
var container = d3_select(this.parentNode.parentNode.parentNode);
|
|
var info = container.selectAll('.issue-info');
|
|
var isExpanded = info.classed('expanded');
|
|
|
|
if (isExpanded) {
|
|
info
|
|
.transition()
|
|
.duration(200)
|
|
.style('max-height', '0px')
|
|
.style('opacity', '0')
|
|
.on('end', function () {
|
|
info.classed('expanded', false);
|
|
});
|
|
} else {
|
|
info
|
|
.classed('expanded', true)
|
|
.transition()
|
|
.duration(200)
|
|
.style('max-height', '200px')
|
|
.style('opacity', '1');
|
|
}
|
|
});
|
|
|
|
itemsEnter
|
|
.append('ul')
|
|
.attr('class', 'issue-fix-list');
|
|
|
|
containersEnter
|
|
.append('div')
|
|
.attr('class', 'issue-info')
|
|
.style('max-height', '0')
|
|
.style('opacity', '0')
|
|
.each(function(d) {
|
|
if (typeof d.reference === 'function') {
|
|
d3_select(this)
|
|
.call(d.reference);
|
|
} else {
|
|
d3_select(this)
|
|
.text(t('inspector.no_documentation_key'));
|
|
}
|
|
});
|
|
|
|
|
|
// Update
|
|
containers = containers
|
|
.merge(containersEnter)
|
|
.classed('active', function(d) { return d.id === _activeIssueID; });
|
|
|
|
|
|
// fixes
|
|
var fixLists = containers.selectAll('.issue-fix-list');
|
|
|
|
var fixes = fixLists.selectAll('.issue-fix-item')
|
|
.data(function(d) { return d.fixes ? d.fixes : []; });
|
|
|
|
var fixesEnter = fixes.enter()
|
|
.append('li')
|
|
.attr('class', function(d) {
|
|
return 'issue-fix-item ' + (d.onClick ? 'actionable' : '');
|
|
})
|
|
.on('click', function(d) {
|
|
if (d.onClick) {
|
|
var issueEntityIDs = d.issue.entityIds;
|
|
utilHighlightEntities(issueEntityIDs.concat(d.entityIds), false, context);
|
|
d.onClick();
|
|
window.setTimeout(function() { context.validator().validate(); }, 300); // after any transition
|
|
}
|
|
})
|
|
.on('mouseover.highlight', function(d) {
|
|
utilHighlightEntities(d.entityIds, true, context);
|
|
})
|
|
.on('mouseout.highlight', function(d) {
|
|
utilHighlightEntities(d.entityIds, false, context);
|
|
});
|
|
|
|
fixesEnter
|
|
.append('span')
|
|
.attr('class', 'fix-icon')
|
|
.each(function(d) {
|
|
var iconName = d.icon || 'iD-icon-wrench';
|
|
if (iconName.startsWith('maki')) {
|
|
iconName += '-15';
|
|
}
|
|
d3_select(this).call(svgIcon('#' + iconName));
|
|
});
|
|
|
|
fixesEnter
|
|
.append('span')
|
|
.attr('class', 'fix-message')
|
|
.text(function(d) { return d.title; });
|
|
}
|
|
|
|
|
|
entityIssues.entityID = function(val) {
|
|
if (!arguments.length) return _entityID;
|
|
if (_entityID !== val) {
|
|
_entityID = val;
|
|
_activeIssueID = null;
|
|
}
|
|
return entityIssues;
|
|
};
|
|
|
|
|
|
return entityIssues;
|
|
}
|