modules/ui/sections/validation_issues.js (170 lines of code) (raw):

import _debounce from 'lodash-es/debounce'; import { select as d3_select } from 'd3-selection'; import { actionNoop } from '../../actions/noop'; import { geoSphericalDistance } from '@id-sdk/geo'; import { svgIcon } from '../../svg/icon'; import { prefs } from '../../core/preferences'; import { t } from '../../core/localizer'; import { utilHighlightEntities } from '../../util'; import { uiSection } from '../section'; export function uiSectionValidationIssues(id, severity, context) { var _issues = []; var section = uiSection(id, context) .label(function() { if (!_issues) return ''; var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length); return t('inspector.title_count', { title: t.html('issues.' + severity + 's.list_title'), count: issueCountText }); }) .disclosureContent(renderDisclosureContent) .shouldDisplay(function() { return _issues && _issues.length; }); function getOptions() { return { what: prefs('validate-what') || 'edited', where: prefs('validate-where') || 'all' }; } // get and cache the issues to display, unordered function reloadIssues() { _issues = context.validator().getIssuesBySeverity(getOptions())[severity]; } function renderDisclosureContent(selection) { var center = context.map().center(); var graph = context.graph(); // sort issues by distance away from the center of the map var issues = _issues.map(function withDistance(issue) { var extent = issue.extent(graph); var dist = extent ? geoSphericalDistance(center, extent.center()) : 0; return Object.assign(issue, { dist: dist }); }) .sort(function byDistance(a, b) { return a.dist - b.dist; }); // cut off at 1000 issues = issues.slice(0, 1000); //renderIgnoredIssuesReset(_warningsSelection); selection .call(drawIssuesList, issues); } function drawIssuesList(selection, issues) { const showAutoFix = prefs('rapid-internal-feature.showAutoFix') === 'true'; var list = selection.selectAll('.issues-list') .data([0]); list = list.enter() .append('ul') .attr('class', 'layer-list issues-list ' + severity + 's-list') .merge(list); var items = list.selectAll('li') .data(issues, function(d) { return d.key; }); // Exit items.exit() .remove(); // Enter var itemsEnter = items.enter() .append('li') .attr('class', function (d) { return 'issue severity-' + d.severity; }); var labelsEnter = itemsEnter .append('button') .attr('class', 'issue-label') .on('click', function(d3_event, d) { context.validator().focusIssue(d); }) .on('mouseover', function(d3_event, d) { utilHighlightEntities(d.entityIds, true, context); }) .on('mouseout', function(d3_event, d) { utilHighlightEntities(d.entityIds, false, context); }); 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'); if (showAutoFix) { labelsEnter .append('span') .attr('class', 'issue-autofix') .each(function(d) { if (!d.autoArgs) return; d3_select(this) .append('button') .attr('title', t('issues.fix_one.title')) .datum(d) // set button datum to the issue .attr('class', 'autofix action') .on('click', function(d3_event, d) { d3_event.preventDefault(); d3_event.stopPropagation(); utilHighlightEntities(d.entityIds, false, context); // unhighlight context.perform.apply(context, d.autoArgs); context.validator().validate(); }) .call(svgIcon('#iD-icon-wrench')); }); } /* show autoFix */ // Update items = items .merge(itemsEnter) .order(); items.selectAll('.issue-message') .html(function(d) { return d.message(context); }); var canAutoFix = issues.filter(function(issue) { return issue.autoArgs; }); var autoFixAll = selection.selectAll('.autofix-all') .data(showAutoFix && canAutoFix.length ? [0] : []); // exit autoFixAll.exit() .remove(); // enter var autoFixAllEnter = autoFixAll.enter() .insert('div', '.issues-list') .attr('class', 'autofix-all'); var linkEnter = autoFixAllEnter .append('a') .attr('class', 'autofix-all-link') .attr('href', '#'); linkEnter .append('span') .attr('class', 'autofix-all-link-text') .html(t.html('issues.fix_all.title')); linkEnter .append('span') .attr('class', 'autofix-all-link-icon') .call(svgIcon('#iD-icon-wrench')); // if (severity === 'warning') { // renderIgnoredIssuesReset(selection); // } // update autoFixAll = autoFixAll .merge(autoFixAllEnter); autoFixAll.selectAll('.autofix-all-link') .on('click', function() { context.pauseChangeDispatch(); context.perform(actionNoop()); canAutoFix.forEach(function(issue) { var args = issue.autoArgs.slice(); // copy if (typeof args[args.length - 1] !== 'function') { args.pop(); } args.push(t('issues.fix_all.annotation')); context.replace.apply(context, args); }); context.resumeChangeDispatch(); context.validator().validate(); }); } context.validator().on('validated.uiSectionValidationIssues' + id, function() { window.requestIdleCallback(function() { reloadIssues(); section.reRender(); }); }); context.map().on('move.uiSectionValidationIssues' + id, _debounce(function() { window.requestIdleCallback(function() { if (getOptions().where === 'visible') { // must refetch issues if they are viewport-dependent reloadIssues(); } // always reload list to re-sort-by-distance section.reRender(); }); }, 1000) ); return section; }