Files
iD/modules/ui/panes/issues.js
T
Quincy Morgan e42bc34e4b Move validation warnings and errors to their own section objects
Allow function parameters for disclosure titles
2020-02-19 17:28:51 -08:00

287 lines
9.2 KiB
JavaScript

import _debounce from 'lodash-es/debounce';
import { event as d3_event } from 'd3-selection';
import { t } from '../../util/locale';
import { svgIcon } from '../../svg/icon';
import { uiPane } from '../pane';
import { uiSectionValidationIssues } from '../sections/validation_issues';
import { uiSectionValidationRules } from '../sections/validation_rules';
export function uiPaneIssues(context) {
var _validationRules = uiSectionValidationRules(context);
var _validationErrors = uiSectionValidationIssues('issues-errors', 'error', context);
var _validationWarnings = uiSectionValidationIssues('issues-warnings', 'warning', context);
function getOptions() {
return {
what: context.storage('validate-what') || 'edited', // 'all', 'edited'
where: context.storage('validate-where') || 'all' // 'all', 'visible'
};
}
// listen for updates that affect the "no issues" box
context.validator().on('validated.uiPaneIssues',
function() { window.requestIdleCallback(update); }
);
context.map().on('move.uiPaneIssues',
_debounce(function() { window.requestIdleCallback(update); }, 1000)
);
function updateOptionValue(d, val) {
if (!val && d3_event && d3_event.target) {
val = d3_event.target.value;
}
context.storage('validate-' + d, val);
context.validator().validate();
}
function renderIssuesOptions(selection) {
var container = selection.selectAll('.issues-options-container')
.data([0]);
container = container.enter()
.append('div')
.attr('class', 'issues-options-container')
.merge(container);
var data = [
{ key: 'what', values: ['edited', 'all'] },
{ key: 'where', values: ['visible', 'all'] }
];
var options = container.selectAll('.issues-option')
.data(data, function(d) { return d.key; });
var optionsEnter = options.enter()
.append('div')
.attr('class', function(d) { return 'issues-option issues-option-' + d.key; });
optionsEnter
.append('div')
.attr('class', 'issues-option-title')
.text(function(d) { return t('issues.options.' + d.key + '.title'); });
var valuesEnter = optionsEnter.selectAll('label')
.data(function(d) {
return d.values.map(function(val) { return { value: val, key: d.key }; });
})
.enter()
.append('label');
valuesEnter
.append('input')
.attr('type', 'radio')
.attr('name', function(d) { return 'issues-option-' + d.key; })
.attr('value', function(d) { return d.value; })
.property('checked', function(d) { return getOptions()[d.key] === d.value; })
.on('change', function(d) { updateOptionValue(d.key, d.value); });
valuesEnter
.append('span')
.text(function(d) { return t('issues.options.' + d.key + '.' + d.value); });
}
function renderNoIssuesBox(selection) {
var box = selection.append('div')
.attr('class', 'box');
box
.append('div')
.call(svgIcon('#iD-icon-apply', 'pre-text'));
var noIssuesMessage = box
.append('span');
noIssuesMessage
.append('strong')
.attr('class', 'message');
noIssuesMessage
.append('br');
noIssuesMessage
.append('span')
.attr('class', 'details');
}
function renderIgnoredIssuesReset(selection) {
var ignoredIssues = context.validator()
.getIssues({ what: 'all', where: 'all', includeDisabledRules: true, includeIgnored: 'only' });
var resetIgnored = selection.selectAll('.reset-ignored')
.data(ignoredIssues.length ? [0] : []);
// exit
resetIgnored.exit()
.remove();
// enter
var resetIgnoredEnter = resetIgnored.enter()
.append('div')
.attr('class', 'reset-ignored section-footer');
resetIgnoredEnter
.append('a')
.attr('href', '#');
// update
resetIgnored = resetIgnored
.merge(resetIgnoredEnter);
resetIgnored.select('a')
.text(t('issues.reset_ignored', { count: ignoredIssues.length.toString() }));
resetIgnored.on('click', function() {
context.validator().resetIgnoredIssues();
});
}
function setNoIssuesText() {
var opts = getOptions();
function checkForHiddenIssues(cases) {
for (var type in cases) {
var hiddenOpts = cases[type];
var hiddenIssues = context.validator().getIssues(hiddenOpts);
if (hiddenIssues.length) {
issuesPane.selection().select('.issues-none .details')
.text(t(
'issues.no_issues.hidden_issues.' + type,
{ count: hiddenIssues.length.toString() }
));
return;
}
}
issuesPane.selection().select('.issues-none .details')
.text(t('issues.no_issues.hidden_issues.none'));
}
var messageType;
if (opts.what === 'edited' && opts.where === 'visible') {
messageType = 'edits_in_view';
checkForHiddenIssues({
elsewhere: { what: 'edited', where: 'all' },
everything_else: { what: 'all', where: 'visible' },
disabled_rules: { what: 'edited', where: 'visible', includeDisabledRules: 'only' },
everything_else_elsewhere: { what: 'all', where: 'all' },
disabled_rules_elsewhere: { what: 'edited', where: 'all', includeDisabledRules: 'only' },
ignored_issues: { what: 'edited', where: 'visible', includeIgnored: 'only' },
ignored_issues_elsewhere: { what: 'edited', where: 'all', includeIgnored: 'only' }
});
} else if (opts.what === 'edited' && opts.where === 'all') {
messageType = 'edits';
checkForHiddenIssues({
everything_else: { what: 'all', where: 'all' },
disabled_rules: { what: 'edited', where: 'all', includeDisabledRules: 'only' },
ignored_issues: { what: 'edited', where: 'all', includeIgnored: 'only' }
});
} else if (opts.what === 'all' && opts.where === 'visible') {
messageType = 'everything_in_view';
checkForHiddenIssues({
elsewhere: { what: 'all', where: 'all' },
disabled_rules: { what: 'all', where: 'visible', includeDisabledRules: 'only' },
disabled_rules_elsewhere: { what: 'all', where: 'all', includeDisabledRules: 'only' },
ignored_issues: { what: 'all', where: 'visible', includeIgnored: 'only' },
ignored_issues_elsewhere: { what: 'all', where: 'all', includeIgnored: 'only' }
});
} else if (opts.what === 'all' && opts.where === 'all') {
messageType = 'everything';
checkForHiddenIssues({
disabled_rules: { what: 'all', where: 'all', includeDisabledRules: 'only' },
ignored_issues: { what: 'all', where: 'all', includeIgnored: 'only' }
});
}
if (opts.what === 'edited' && context.history().difference().summary().length === 0) {
messageType = 'no_edits';
}
issuesPane.selection().select('.issues-none .message')
.text(t('issues.no_issues.message.' + messageType));
}
function update() {
var issues = context.validator().getIssues(getOptions());
var hasIssues = issues.length > 0;
var issuesNone = issuesPane.selection().select('.issues-none');
issuesNone.classed('hide', hasIssues);
if (!hasIssues) {
renderIgnoredIssuesReset(issuesNone);
setNoIssuesText();
}
issuesPane.selection().select('.issues-errors')
.call(_validationErrors.render);
issuesPane.selection().select('.issues-warnings')
.call(_validationWarnings.render);
issuesPane.selection().select('.issues-rules')
.call(_validationRules.render);
}
var issuesPane = uiPane('issues', context)
.key(t('issues.key'))
.title(t('issues.title'))
.description(t('issues.title'))
.iconName('iD-icon-alert');
issuesPane.renderContent = function(content) {
content
.append('div')
.attr('class', 'issues-options')
.call(renderIssuesOptions);
content
.append('div')
.attr('class', 'issues-none')
.call(renderNoIssuesBox);
// errors
content
.append('div')
.attr('class', 'issues-errors');
// warnings
content
.append('div')
.attr('class', 'issues-warnings');
// rules list
content
.append('div')
.attr('class', 'issues-rules');
update();
};
return issuesPane;
}