mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-17 14:23:38 +02:00
Add uiSection class as standard component for pane sections
Move validation rules and privacy preferences to their own section objects
This commit is contained in:
+15
-2
@@ -15,6 +15,7 @@ export function uiPane(id, context) {
|
||||
var _title = '';
|
||||
var _description = '';
|
||||
var _iconName = '';
|
||||
var _sections; // array of uiSection objects
|
||||
|
||||
var _paneSelection = d3_select(null);
|
||||
|
||||
@@ -48,6 +49,12 @@ export function uiPane(id, context) {
|
||||
return pane;
|
||||
};
|
||||
|
||||
pane.sections = function(val) {
|
||||
if (!arguments.length) return _sections;
|
||||
_sections = val;
|
||||
return pane;
|
||||
};
|
||||
|
||||
pane.selection = function() {
|
||||
return _paneSelection;
|
||||
};
|
||||
@@ -78,8 +85,14 @@ export function uiPane(id, context) {
|
||||
.call(_paneTooltip);
|
||||
};
|
||||
|
||||
pane.renderContent = function() {
|
||||
// override
|
||||
pane.renderContent = function(selection) {
|
||||
// override to fully customize content
|
||||
|
||||
if (_sections) {
|
||||
_sections.forEach(function(section) {
|
||||
selection.call(section.render);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pane.renderPane = function(selection) {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import _debounce from 'lodash-es/debounce';
|
||||
|
||||
import { event as d3_event, select as d3_select } from 'd3-selection';
|
||||
import { event as d3_event } from 'd3-selection';
|
||||
|
||||
import { t } from '../../util/locale';
|
||||
import { uiCmd } from '../cmd';
|
||||
@@ -13,31 +11,8 @@ import { uiOverlayList } from '../sections/overlay_list';
|
||||
|
||||
export function uiPaneBackground(context) {
|
||||
|
||||
var _key = t('background.key');
|
||||
|
||||
var _backgroundListContainer = d3_select(null);
|
||||
var _overlayListContainer = d3_select(null);
|
||||
var _displayOptionsContainer = d3_select(null);
|
||||
var _offsetContainer = d3_select(null);
|
||||
|
||||
var backgroundList = uiBackgroundList(context);
|
||||
var backgroundDisplayOptions = uiBackgroundDisplayOptions(context);
|
||||
var backgroundOffset = uiBackgroundOffset(context);
|
||||
var overlayList = uiOverlayList(context);
|
||||
|
||||
function update() {
|
||||
_backgroundListContainer
|
||||
.call(backgroundList);
|
||||
|
||||
_overlayListContainer
|
||||
.call(overlayList);
|
||||
|
||||
_displayOptionsContainer
|
||||
.call(backgroundDisplayOptions);
|
||||
|
||||
_offsetContainer
|
||||
.call(backgroundOffset);
|
||||
}
|
||||
context.keybinding()
|
||||
.on(uiCmd('⌘' + t('background.key')), quickSwitch);
|
||||
|
||||
function quickSwitch() {
|
||||
if (d3_event) {
|
||||
@@ -46,57 +21,24 @@ export function uiPaneBackground(context) {
|
||||
}
|
||||
var previousBackground = context.background().findSource(context.storage('background-last-used-toggle'));
|
||||
if (previousBackground) {
|
||||
var newPreviousBackground = context.background().baseLayerSource();
|
||||
context.storage('background-last-used-toggle', newPreviousBackground.id);
|
||||
var currentBackground = context.background().baseLayerSource();
|
||||
context.storage('background-last-used-toggle', currentBackground.id);
|
||||
context.storage('background-last-used', previousBackground.id);
|
||||
context.background().baseLayerSource(previousBackground);
|
||||
document.activeElement.blur();
|
||||
}
|
||||
}
|
||||
|
||||
var backgroundPane = uiPane('background', context)
|
||||
.key(_key)
|
||||
.key(t('background.key'))
|
||||
.title(t('background.title'))
|
||||
.description(t('background.description'))
|
||||
.iconName('iD-icon-layers');
|
||||
|
||||
backgroundPane.renderContent = function(content) {
|
||||
|
||||
// background list
|
||||
_backgroundListContainer = content
|
||||
.append('div')
|
||||
.attr('class', 'background-background-list-container');
|
||||
|
||||
// overlay list
|
||||
_overlayListContainer = content
|
||||
.append('div')
|
||||
.attr('class', 'background-overlay-list-container');
|
||||
|
||||
// display options
|
||||
_displayOptionsContainer = content
|
||||
.append('div')
|
||||
.attr('class', 'background-display-options');
|
||||
|
||||
// offset controls
|
||||
_offsetContainer = content
|
||||
.append('div')
|
||||
.attr('class', 'background-offset');
|
||||
|
||||
update();
|
||||
|
||||
|
||||
// add listeners
|
||||
context.map()
|
||||
.on('move.background-update',
|
||||
_debounce(function() { window.requestIdleCallback(update); }, 1000)
|
||||
);
|
||||
|
||||
context.background()
|
||||
.on('change.background-update', update);
|
||||
|
||||
context.keybinding()
|
||||
.on(uiCmd('⌘' + _key), quickSwitch);
|
||||
};
|
||||
.iconName('iD-icon-layers')
|
||||
.sections([
|
||||
uiBackgroundList(context),
|
||||
uiOverlayList(context),
|
||||
uiBackgroundDisplayOptions(context),
|
||||
uiBackgroundOffset(context)
|
||||
]);
|
||||
|
||||
return backgroundPane;
|
||||
}
|
||||
|
||||
+12
-192
@@ -3,25 +3,24 @@ import _debounce from 'lodash-es/debounce';
|
||||
import { event as d3_event, select as d3_select } from 'd3-selection';
|
||||
|
||||
import { t } from '../../util/locale';
|
||||
import { tooltip } from '../../util/tooltip';
|
||||
|
||||
//import { actionNoop } from '../actions/noop';
|
||||
import { geoSphericalDistance } from '../../geo';
|
||||
import { svgIcon } from '../../svg/icon';
|
||||
import { uiDisclosure } from '../disclosure';
|
||||
import { utilGetSetValue, utilHighlightEntities, utilNoAuto } from '../../util';
|
||||
import { utilHighlightEntities } from '../../util';
|
||||
import { uiPane } from '../pane';
|
||||
import { uiValidationRules } from '../sections/validation_rules';
|
||||
|
||||
|
||||
export function uiPaneIssues(context) {
|
||||
|
||||
var MINSQUARE = 0;
|
||||
var MAXSQUARE = 20;
|
||||
var DEFAULTSQUARE = 5; // see also unsquare_way.js
|
||||
|
||||
var _errorsSelection = d3_select(null);
|
||||
var _warningsSelection = d3_select(null);
|
||||
var _rulesList = d3_select(null);
|
||||
|
||||
var _rulesListContainer = d3_select(null);
|
||||
|
||||
var _validationRules = uiValidationRules(context);
|
||||
|
||||
var _errors = [];
|
||||
var _warnings = [];
|
||||
@@ -313,69 +312,6 @@ export function uiPaneIssues(context) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function renderRulesList(selection) {
|
||||
var container = selection.selectAll('.issues-rulelist-container')
|
||||
.data([0]);
|
||||
|
||||
var containerEnter = container.enter()
|
||||
.append('div')
|
||||
.attr('class', 'issues-rulelist-container');
|
||||
|
||||
containerEnter
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list issue-rules-list');
|
||||
|
||||
var ruleLinks = containerEnter
|
||||
.append('div')
|
||||
.attr('class', 'issue-rules-links section-footer');
|
||||
|
||||
ruleLinks
|
||||
.append('a')
|
||||
.attr('class', 'issue-rules-link')
|
||||
.attr('href', '#')
|
||||
.text(t('issues.enable_all'))
|
||||
.on('click', function() {
|
||||
context.validator().disableRules([]);
|
||||
});
|
||||
|
||||
ruleLinks
|
||||
.append('a')
|
||||
.attr('class', 'issue-rules-link')
|
||||
.attr('href', '#')
|
||||
.text(t('issues.disable_all'))
|
||||
.on('click', function() {
|
||||
var keys = context.validator().getRuleKeys();
|
||||
context.validator().disableRules(keys);
|
||||
});
|
||||
|
||||
|
||||
// Update
|
||||
container = container
|
||||
.merge(containerEnter);
|
||||
|
||||
_rulesList = container.selectAll('.issue-rules-list');
|
||||
|
||||
updateRulesList();
|
||||
}
|
||||
|
||||
|
||||
function updateRulesList() {
|
||||
var ruleKeys = context.validator().getRuleKeys();
|
||||
_rulesList
|
||||
.call(drawListItems, ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
|
||||
}
|
||||
|
||||
|
||||
function isRuleEnabled(d) {
|
||||
return context.validator().isRuleEnabled(d);
|
||||
}
|
||||
|
||||
|
||||
function toggleRule(d) {
|
||||
context.validator().toggleRule(d);
|
||||
}
|
||||
|
||||
function setNoIssuesText() {
|
||||
|
||||
function checkForHiddenIssues(cases) {
|
||||
@@ -502,10 +438,8 @@ export function uiPaneIssues(context) {
|
||||
setNoIssuesText();
|
||||
}
|
||||
|
||||
if (!issuesPane.selection().select('.disclosure-wrap-issues_rules').classed('hide')) {
|
||||
updateRulesList();
|
||||
}
|
||||
|
||||
_rulesListContainer
|
||||
.call(_validationRules.render);
|
||||
|
||||
function byDistance(a, b) {
|
||||
return a.dist - b.dist;
|
||||
@@ -519,116 +453,6 @@ export function uiPaneIssues(context) {
|
||||
}
|
||||
|
||||
|
||||
function drawListItems(selection, data, type, name, change, active) {
|
||||
var items = selection.selectAll('li')
|
||||
.data(data);
|
||||
|
||||
// Exit
|
||||
items.exit()
|
||||
.remove();
|
||||
|
||||
// Enter
|
||||
var enter = items.enter()
|
||||
.append('li');
|
||||
|
||||
if (name === 'rule') {
|
||||
enter
|
||||
.call(tooltip()
|
||||
.title(function(d) { return t('issues.' + d + '.tip'); })
|
||||
.placement('top')
|
||||
);
|
||||
}
|
||||
|
||||
var label = enter
|
||||
.append('label');
|
||||
|
||||
label
|
||||
.append('input')
|
||||
.attr('type', type)
|
||||
.attr('name', name)
|
||||
.on('change', change);
|
||||
|
||||
label
|
||||
.append('span')
|
||||
.html(function(d) {
|
||||
var params = {};
|
||||
if (d === 'unsquare_way') {
|
||||
params.val = '<span class="square-degrees"></span>';
|
||||
}
|
||||
return t('issues.' + d + '.title', params);
|
||||
});
|
||||
|
||||
// Update
|
||||
items = items
|
||||
.merge(enter);
|
||||
|
||||
items
|
||||
.classed('active', active)
|
||||
.selectAll('input')
|
||||
.property('checked', active)
|
||||
.property('indeterminate', false);
|
||||
|
||||
|
||||
// user-configurable square threshold
|
||||
var degStr = context.storage('validate-square-degrees');
|
||||
if (degStr === null) {
|
||||
degStr = '' + DEFAULTSQUARE;
|
||||
}
|
||||
|
||||
var span = items.selectAll('.square-degrees');
|
||||
var input = span.selectAll('.square-degrees-input')
|
||||
.data([0]);
|
||||
|
||||
// enter / update
|
||||
input.enter()
|
||||
.append('input')
|
||||
.attr('type', 'number')
|
||||
.attr('min', '' + MINSQUARE)
|
||||
.attr('max', '' + MAXSQUARE)
|
||||
.attr('step', '0.5')
|
||||
.attr('class', 'square-degrees-input')
|
||||
.call(utilNoAuto)
|
||||
.on('click', function () {
|
||||
d3_event.preventDefault();
|
||||
d3_event.stopPropagation();
|
||||
this.select();
|
||||
})
|
||||
.on('keyup', function () {
|
||||
if (d3_event.keyCode === 13) { // enter
|
||||
this.blur();
|
||||
this.select();
|
||||
}
|
||||
})
|
||||
.on('blur', changeSquare)
|
||||
.merge(input)
|
||||
.property('value', degStr);
|
||||
}
|
||||
|
||||
|
||||
function changeSquare() {
|
||||
var input = d3_select(this);
|
||||
var degStr = utilGetSetValue(input).trim();
|
||||
var degNum = parseFloat(degStr, 10);
|
||||
|
||||
if (!isFinite(degNum)) {
|
||||
degNum = DEFAULTSQUARE;
|
||||
} else if (degNum > MAXSQUARE) {
|
||||
degNum = MAXSQUARE;
|
||||
} else if (degNum < MINSQUARE) {
|
||||
degNum = MINSQUARE;
|
||||
}
|
||||
|
||||
degNum = Math.round(degNum * 10 ) / 10; // round to 1 decimal
|
||||
degStr = '' + degNum;
|
||||
|
||||
input
|
||||
.property('value', degStr);
|
||||
|
||||
context.storage('validate-square-degrees', degStr);
|
||||
context.validator().reloadUnsquareIssues();
|
||||
}
|
||||
|
||||
|
||||
var issuesPane = uiPane('issues', context)
|
||||
.key(t('issues.key'))
|
||||
.title(t('issues.title'))
|
||||
@@ -664,16 +488,12 @@ export function uiPaneIssues(context) {
|
||||
.content(renderWarningsList)
|
||||
);
|
||||
|
||||
// rules
|
||||
content
|
||||
// rules list
|
||||
_rulesListContainer = content
|
||||
.append('div')
|
||||
.attr('class', 'issues-rules')
|
||||
.call(uiDisclosure(context, 'issues_rules', false)
|
||||
.title(t('issues.rules.title'))
|
||||
.content(renderRulesList)
|
||||
);
|
||||
.attr('class', 'issues-rules');
|
||||
|
||||
// update();
|
||||
update();
|
||||
};
|
||||
|
||||
return issuesPane;
|
||||
|
||||
@@ -1,87 +1,18 @@
|
||||
import { event as d3_event } from 'd3-selection';
|
||||
|
||||
import { svgIcon } from '../../svg/icon';
|
||||
import { t } from '../../util/locale';
|
||||
import { tooltip } from '../../util/tooltip';
|
||||
import { uiDisclosure } from '../disclosure';
|
||||
import { uiPane } from '../pane';
|
||||
|
||||
import { uiSectionPrivacy } from '../sections/privacy';
|
||||
|
||||
export function uiPanePreferences(context) {
|
||||
let _showThirdPartyIcons = context.storage('preferences.privacy.thirdpartyicons') || 'true';
|
||||
|
||||
function renderPrivacyOptions(selection) {
|
||||
// enter
|
||||
let privacyOptionsListEnter = selection.selectAll('.privacy-options-list')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list privacy-options-list');
|
||||
|
||||
let thirdPartyIconsEnter = privacyOptionsListEnter
|
||||
.append('li')
|
||||
.attr('class', 'privacy-third-party-icons-item')
|
||||
.append('label')
|
||||
.call(tooltip()
|
||||
.title(t('preferences.privacy.third_party_icons.tooltip'))
|
||||
.placement('bottom')
|
||||
);
|
||||
|
||||
thirdPartyIconsEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', () => {
|
||||
d3_event.preventDefault();
|
||||
_showThirdPartyIcons = (_showThirdPartyIcons === 'true') ? 'false' : 'true';
|
||||
context.storage('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
|
||||
update();
|
||||
});
|
||||
|
||||
thirdPartyIconsEnter
|
||||
.append('span')
|
||||
.text(t('preferences.privacy.third_party_icons.description'));
|
||||
|
||||
|
||||
// Privacy Policy link
|
||||
selection.selectAll('.privacy-link')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'privacy-link')
|
||||
.append('a')
|
||||
.attr('target', '_blank')
|
||||
.call(svgIcon('#iD-icon-out-link', 'inline'))
|
||||
.attr('href', 'https://github.com/openstreetmap/iD/blob/master/PRIVACY.md')
|
||||
.append('span')
|
||||
.text(t('preferences.privacy.privacy_link'));
|
||||
|
||||
update();
|
||||
|
||||
|
||||
function update() {
|
||||
selection.selectAll('.privacy-third-party-icons-item')
|
||||
.classed('active', (_showThirdPartyIcons === 'true'))
|
||||
.select('input')
|
||||
.property('checked', (_showThirdPartyIcons === 'true'));
|
||||
}
|
||||
}
|
||||
|
||||
let preferencesPane = uiPane('preferences', context)
|
||||
.key(t('preferences.key'))
|
||||
.title(t('preferences.title'))
|
||||
.description(t('preferences.description'))
|
||||
.iconName('fas-user-cog');
|
||||
|
||||
preferencesPane.renderContent = (content) => {
|
||||
|
||||
content
|
||||
.append('div')
|
||||
.attr('class', 'preferences-privacy')
|
||||
.call(uiDisclosure(context, 'preferences_third_party', true)
|
||||
.title(t('preferences.privacy.title'))
|
||||
.content(renderPrivacyOptions)
|
||||
);
|
||||
};
|
||||
.iconName('fas-user-cog')
|
||||
.sections([
|
||||
uiSectionPrivacy(context)
|
||||
]);
|
||||
|
||||
return preferencesPane;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import {
|
||||
select as d3_select
|
||||
} from 'd3-selection';
|
||||
|
||||
import { uiDisclosure } from './disclosure';
|
||||
|
||||
// A unit of controls or info to be used in a layout, such as within a pane.
|
||||
// Can be labeled and collapsible.
|
||||
export function uiSection(id, context) {
|
||||
|
||||
var _disclosure;
|
||||
var _title;
|
||||
var _expandedByDefault = true;
|
||||
|
||||
var _containerSelection = d3_select(null);
|
||||
|
||||
var section = {
|
||||
id: id
|
||||
};
|
||||
|
||||
section.title = function(val) {
|
||||
if (!arguments.length) return _title;
|
||||
_title = val;
|
||||
return section;
|
||||
};
|
||||
|
||||
section.expandedByDefault = function(val) {
|
||||
if (!arguments.length) return _expandedByDefault;
|
||||
_expandedByDefault = val;
|
||||
return section;
|
||||
};
|
||||
|
||||
// may be called multiple times
|
||||
section.render = function(selection) {
|
||||
|
||||
_containerSelection = selection
|
||||
.selectAll('.section-' + id)
|
||||
.data([0]);
|
||||
|
||||
var sectionEnter = _containerSelection
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'section section-' + id);
|
||||
|
||||
_containerSelection = sectionEnter
|
||||
.merge(_containerSelection);
|
||||
|
||||
_containerSelection
|
||||
.call(section.renderContent);
|
||||
};
|
||||
|
||||
// may be called multiple times
|
||||
section.renderContent = function(containerSelection) {
|
||||
|
||||
if (section.renderDisclosureContent && _title) {
|
||||
if (!_disclosure) {
|
||||
_disclosure = uiDisclosure(context, id.replace(/-/g, '_'), _expandedByDefault)
|
||||
.title(_title)
|
||||
.content(section.renderDisclosureContent);
|
||||
}
|
||||
containerSelection
|
||||
.call(_disclosure);
|
||||
}
|
||||
};
|
||||
|
||||
// override to enable disclosure
|
||||
section.renderDisclosureContent = undefined;
|
||||
|
||||
section.rerenderContent = function() {
|
||||
_containerSelection
|
||||
.call(section.renderContent);
|
||||
};
|
||||
|
||||
return section;
|
||||
}
|
||||
@@ -5,29 +5,31 @@ import {
|
||||
|
||||
import { t, textDirection } from '../../util/locale';
|
||||
import { svgIcon } from '../../svg/icon';
|
||||
import { uiDisclosure } from '../disclosure';
|
||||
import { uiSection } from '../section';
|
||||
import { utilDetect } from '../../util/detect';
|
||||
|
||||
|
||||
export function uiBackgroundDisplayOptions(context) {
|
||||
var detected = utilDetect();
|
||||
var storedOpacity = context.storage('background-opacity');
|
||||
var minVal = 0.25;
|
||||
var maxVal = detected.cssfilters ? 2 : 1;
|
||||
|
||||
var sliders = detected.cssfilters
|
||||
var section = uiSection('background-display-options', context)
|
||||
.title(t('background.display_options'));
|
||||
|
||||
var _detected = utilDetect();
|
||||
var _storedOpacity = context.storage('background-opacity');
|
||||
var _minVal = 0.25;
|
||||
var _maxVal = _detected.cssfilters ? 2 : 1;
|
||||
|
||||
var _sliders = _detected.cssfilters
|
||||
? ['brightness', 'contrast', 'saturation', 'sharpness']
|
||||
: ['brightness'];
|
||||
|
||||
var _options = {
|
||||
brightness: (storedOpacity !== null ? (+storedOpacity) : 1),
|
||||
brightness: (_storedOpacity !== null ? (+_storedOpacity) : 1),
|
||||
contrast: 1,
|
||||
saturation: 1,
|
||||
sharpness: 1
|
||||
};
|
||||
|
||||
var _selection = d3_select(null);
|
||||
|
||||
|
||||
function clamp(x, min, max) {
|
||||
return Math.max(min, Math.min(x, max));
|
||||
@@ -39,7 +41,7 @@ export function uiBackgroundDisplayOptions(context) {
|
||||
val = d3_event.target.value;
|
||||
}
|
||||
|
||||
val = clamp(val, minVal, maxVal);
|
||||
val = clamp(val, _minVal, _maxVal);
|
||||
|
||||
_options[d] = val;
|
||||
context.background()[d](val);
|
||||
@@ -48,12 +50,11 @@ export function uiBackgroundDisplayOptions(context) {
|
||||
context.storage('background-opacity', val);
|
||||
}
|
||||
|
||||
_selection
|
||||
.call(render);
|
||||
section.rerenderContent();
|
||||
}
|
||||
|
||||
|
||||
function render(selection) {
|
||||
section.renderDisclosureContent = function(selection) {
|
||||
var container = selection.selectAll('.display-options-container')
|
||||
.data([0]);
|
||||
|
||||
@@ -63,7 +64,7 @@ export function uiBackgroundDisplayOptions(context) {
|
||||
|
||||
// add slider controls
|
||||
var slidersEnter = containerEnter.selectAll('.display-control')
|
||||
.data(sliders)
|
||||
.data(_sliders)
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', function(d) { return 'display-control display-control-' + d; });
|
||||
@@ -78,8 +79,8 @@ export function uiBackgroundDisplayOptions(context) {
|
||||
.append('input')
|
||||
.attr('class', function(d) { return 'display-option-input display-option-input-' + d; })
|
||||
.attr('type', 'range')
|
||||
.attr('min', minVal)
|
||||
.attr('max', maxVal)
|
||||
.attr('min', _minVal)
|
||||
.attr('max', _maxVal)
|
||||
.attr('step', '0.05')
|
||||
.on('input', function(d) {
|
||||
var val = d3_select(this).property('value');
|
||||
@@ -103,8 +104,8 @@ export function uiBackgroundDisplayOptions(context) {
|
||||
.attr('href', '#')
|
||||
.text(t('background.reset_all'))
|
||||
.on('click', function() {
|
||||
for (var i = 0; i < sliders.length; i++) {
|
||||
updateValue(sliders[i],1);
|
||||
for (var i = 0; i < _sliders.length; i++) {
|
||||
updateValue(_sliders[i],1);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -125,19 +126,8 @@ export function uiBackgroundDisplayOptions(context) {
|
||||
if (containerEnter.size() && _options.brightness !== 1) {
|
||||
context.background().brightness(_options.brightness);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function backgroundDisplayOptions(selection) {
|
||||
_selection = selection;
|
||||
|
||||
selection
|
||||
.call(uiDisclosure(context, 'background_display_options', true)
|
||||
.title(t('background.display_options'))
|
||||
.content(render)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return backgroundDisplayOptions;
|
||||
return section;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import _debounce from 'lodash-es/debounce';
|
||||
import { descending as d3_descending, ascending as d3_ascending } from 'd3-array';
|
||||
import {
|
||||
event as d3_event,
|
||||
@@ -8,9 +9,9 @@ import { t, textDirection } from '../../util/locale';
|
||||
import { tooltip } from '../../util/tooltip';
|
||||
import { svgIcon } from '../../svg/icon';
|
||||
import { uiCmd } from '../cmd';
|
||||
import { uiDisclosure } from '../disclosure';
|
||||
import { uiSettingsCustomBackground } from '../settings/custom_background';
|
||||
import { uiMapInMap } from '../map_in_map';
|
||||
import { uiSection } from '../section';
|
||||
import { uiTooltipHtml } from '../tooltipHtml';
|
||||
|
||||
export function uiBackgroundList(context) {
|
||||
@@ -19,14 +20,17 @@ export function uiBackgroundList(context) {
|
||||
|
||||
var _customSource = context.background().findSource('custom');
|
||||
|
||||
var settingsCustomBackground = uiSettingsCustomBackground(context)
|
||||
var _settingsCustomBackground = uiSettingsCustomBackground(context)
|
||||
.on('change', customChanged);
|
||||
|
||||
var section = uiSection('background-list', context)
|
||||
.title(t('background.backgrounds'));
|
||||
|
||||
function previousBackgroundID() {
|
||||
return context.storage('background-last-used-toggle');
|
||||
}
|
||||
|
||||
function render(selection) {
|
||||
section.renderDisclosureContent = function(selection) {
|
||||
|
||||
// the background list
|
||||
var container = selection.selectAll('.layer-background-list')
|
||||
@@ -105,8 +109,9 @@ export function uiBackgroundList(context) {
|
||||
.append('span')
|
||||
.text(t('background.imagery_problem_faq'));
|
||||
|
||||
updateBackgroundList();
|
||||
}
|
||||
_backgroundList
|
||||
.call(drawListItems, 'radio', chooseBackground, function(d) { return !d.isHidden() && !d.overlay; });
|
||||
};
|
||||
|
||||
function setTooltips(selection) {
|
||||
selection.each(function(d, i, nodes) {
|
||||
@@ -136,11 +141,6 @@ export function uiBackgroundList(context) {
|
||||
});
|
||||
}
|
||||
|
||||
function updateBackgroundList() {
|
||||
_backgroundList
|
||||
.call(drawListItems, 'radio', chooseBackground, function(d) { return !d.isHidden() && !d.overlay; });
|
||||
}
|
||||
|
||||
function drawListItems(layerList, type, change, filter) {
|
||||
var sources = context.background()
|
||||
.sources(context.map().extent(), context.map().zoom(), true)
|
||||
@@ -247,22 +247,22 @@ export function uiBackgroundList(context) {
|
||||
function editCustom() {
|
||||
d3_event.preventDefault();
|
||||
context.container()
|
||||
.call(settingsCustomBackground);
|
||||
.call(_settingsCustomBackground);
|
||||
}
|
||||
|
||||
|
||||
function backgroundList(selection) {
|
||||
selection
|
||||
.call(uiDisclosure(context, 'background_list', true)
|
||||
.title(t('background.backgrounds'))
|
||||
.content(render)
|
||||
);
|
||||
}
|
||||
|
||||
context.background()
|
||||
.on('change.background_list', function() {
|
||||
_backgroundList.call(updateLayerSelections);
|
||||
});
|
||||
|
||||
return backgroundList;
|
||||
context.map()
|
||||
.on('move.background_list',
|
||||
_debounce(function() {
|
||||
// layers in-view may have changed due to map move
|
||||
window.requestIdleCallback(section.rerenderContent);
|
||||
}, 1000)
|
||||
);
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,16 @@ import {
|
||||
import { t, textDirection } from '../../util/locale';
|
||||
import { geoMetersToOffset, geoOffsetToMeters } from '../../geo';
|
||||
import { svgIcon } from '../../svg/icon';
|
||||
import { uiDisclosure } from '../disclosure';
|
||||
import { uiSection } from '../section';
|
||||
|
||||
|
||||
export function uiBackgroundOffset(context) {
|
||||
var directions = [
|
||||
|
||||
var section = uiSection('background-offset', context)
|
||||
.title(t('background.fix_misalignment'))
|
||||
.expandedByDefault(false);
|
||||
|
||||
var _directions = [
|
||||
['right', [0.5, 0]],
|
||||
['top', [0, -0.5]],
|
||||
['left', [-0.5, 0]],
|
||||
@@ -129,7 +134,7 @@ export function uiBackgroundOffset(context) {
|
||||
}
|
||||
|
||||
|
||||
function render(selection) {
|
||||
section.renderDisclosureContent = function(selection) {
|
||||
var container = selection.selectAll('.nudge-container')
|
||||
.data([0]);
|
||||
|
||||
@@ -156,7 +161,7 @@ export function uiBackgroundOffset(context) {
|
||||
containerEnter
|
||||
.append('div')
|
||||
.selectAll('button')
|
||||
.data(directions).enter()
|
||||
.data(_directions).enter()
|
||||
.append('button')
|
||||
.attr('class', function(d) { return d[0] + ' nudge'; })
|
||||
.on('contextmenu', d3_eventCancel)
|
||||
@@ -177,20 +182,10 @@ export function uiBackgroundOffset(context) {
|
||||
.call(svgIcon('#iD-icon-' + (textDirection === 'rtl' ? 'redo' : 'undo')));
|
||||
|
||||
updateValue();
|
||||
}
|
||||
|
||||
|
||||
function backgroundOffset(selection) {
|
||||
selection
|
||||
.call(uiDisclosure(context, 'background_offset', false)
|
||||
.title(t('background.fix_misalignment'))
|
||||
.content(render)
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
context.background()
|
||||
.on('change.backgroundOffset-update', updateValue);
|
||||
|
||||
return backgroundOffset;
|
||||
return section;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import _debounce from 'lodash-es/debounce';
|
||||
import { descending as d3_descending, ascending as d3_ascending } from 'd3-array';
|
||||
import {
|
||||
event as d3_event,
|
||||
@@ -6,26 +7,15 @@ import {
|
||||
|
||||
import { t } from '../../util/locale';
|
||||
import { tooltip } from '../../util/tooltip';
|
||||
import { uiDisclosure } from '../disclosure';
|
||||
import { uiSection } from '../section';
|
||||
|
||||
export function uiOverlayList(context) {
|
||||
|
||||
var section = uiSection('overlay-list', context)
|
||||
.title(t('background.overlays'));
|
||||
|
||||
var _overlayList = d3_select(null);
|
||||
|
||||
function render(selection) {
|
||||
|
||||
var container = selection.selectAll('.layer-overlay-list')
|
||||
.data([0]);
|
||||
|
||||
_overlayList = container.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-overlay-list')
|
||||
.attr('dir', 'auto')
|
||||
.merge(container);
|
||||
|
||||
updateOverlayList();
|
||||
}
|
||||
|
||||
function setTooltips(selection) {
|
||||
selection.each(function(d, i, nodes) {
|
||||
var item = d3_select(this).select('label');
|
||||
@@ -107,18 +97,28 @@ export function uiOverlayList(context) {
|
||||
}
|
||||
}
|
||||
|
||||
function updateOverlayList() {
|
||||
section.renderDisclosureContent = function(selection) {
|
||||
|
||||
var container = selection.selectAll('.layer-overlay-list')
|
||||
.data([0]);
|
||||
|
||||
_overlayList = container.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-overlay-list')
|
||||
.attr('dir', 'auto')
|
||||
.merge(container);
|
||||
|
||||
_overlayList
|
||||
.call(drawListItems, 'checkbox', chooseOverlay, function(d) { return !d.isHidden() && d.overlay; });
|
||||
}
|
||||
};
|
||||
|
||||
function overlayList(selection) {
|
||||
selection
|
||||
.call(uiDisclosure(context, 'overlay_list', true)
|
||||
.title(t('background.overlays'))
|
||||
.content(render)
|
||||
);
|
||||
}
|
||||
context.map()
|
||||
.on('move.overlay_list',
|
||||
_debounce(function() {
|
||||
// layers in-view may have changed due to map move
|
||||
window.requestIdleCallback(section.rerenderContent);
|
||||
}, 1000)
|
||||
);
|
||||
|
||||
return overlayList;
|
||||
return section;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
event as d3_event
|
||||
} from 'd3-selection';
|
||||
|
||||
import { t } from '../../util/locale';
|
||||
import { tooltip } from '../../util/tooltip';
|
||||
import { svgIcon } from '../../svg/icon';
|
||||
import { uiSection } from '../section';
|
||||
|
||||
export function uiSectionPrivacy(context) {
|
||||
|
||||
let section = uiSection('preferences-third-party', context)
|
||||
.title(t('preferences.privacy.title'));
|
||||
|
||||
let _showThirdPartyIcons = context.storage('preferences.privacy.thirdpartyicons') || 'true';
|
||||
|
||||
section.renderDisclosureContent = function(selection) {
|
||||
// enter
|
||||
let privacyOptionsListEnter = selection.selectAll('.privacy-options-list')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list privacy-options-list');
|
||||
|
||||
let thirdPartyIconsEnter = privacyOptionsListEnter
|
||||
.append('li')
|
||||
.attr('class', 'privacy-third-party-icons-item')
|
||||
.append('label')
|
||||
.call(tooltip()
|
||||
.title(t('preferences.privacy.third_party_icons.tooltip'))
|
||||
.placement('bottom')
|
||||
);
|
||||
|
||||
thirdPartyIconsEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', () => {
|
||||
d3_event.preventDefault();
|
||||
_showThirdPartyIcons = (_showThirdPartyIcons === 'true') ? 'false' : 'true';
|
||||
context.storage('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
|
||||
update();
|
||||
});
|
||||
|
||||
thirdPartyIconsEnter
|
||||
.append('span')
|
||||
.text(t('preferences.privacy.third_party_icons.description'));
|
||||
|
||||
|
||||
// Privacy Policy link
|
||||
selection.selectAll('.privacy-link')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'privacy-link')
|
||||
.append('a')
|
||||
.attr('target', '_blank')
|
||||
.call(svgIcon('#iD-icon-out-link', 'inline'))
|
||||
.attr('href', 'https://github.com/openstreetmap/iD/blob/master/PRIVACY.md')
|
||||
.append('span')
|
||||
.text(t('preferences.privacy.privacy_link'));
|
||||
|
||||
update();
|
||||
|
||||
|
||||
function update() {
|
||||
selection.selectAll('.privacy-third-party-icons-item')
|
||||
.classed('active', (_showThirdPartyIcons === 'true'))
|
||||
.select('input')
|
||||
.property('checked', (_showThirdPartyIcons === 'true'));
|
||||
}
|
||||
};
|
||||
|
||||
return section;
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
import {
|
||||
event as d3_event,
|
||||
select as d3_select
|
||||
} from 'd3-selection';
|
||||
|
||||
import { t } from '../../util/locale';
|
||||
import { utilGetSetValue, utilNoAuto } from '../../util';
|
||||
import { tooltip } from '../../util/tooltip';
|
||||
import { uiSection } from '../section';
|
||||
|
||||
export function uiValidationRules(context) {
|
||||
|
||||
var MINSQUARE = 0;
|
||||
var MAXSQUARE = 20;
|
||||
var DEFAULTSQUARE = 5; // see also unsquare_way.js
|
||||
|
||||
var section = uiSection('issues-rules', context)
|
||||
.title(t('issues.rules.title'));
|
||||
|
||||
section.renderDisclosureContent = function(selection) {
|
||||
var container = selection.selectAll('.issues-rulelist-container')
|
||||
.data([0]);
|
||||
|
||||
var containerEnter = container.enter()
|
||||
.append('div')
|
||||
.attr('class', 'issues-rulelist-container');
|
||||
|
||||
containerEnter
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list issue-rules-list');
|
||||
|
||||
var ruleLinks = containerEnter
|
||||
.append('div')
|
||||
.attr('class', 'issue-rules-links section-footer');
|
||||
|
||||
ruleLinks
|
||||
.append('a')
|
||||
.attr('class', 'issue-rules-link')
|
||||
.attr('href', '#')
|
||||
.text(t('issues.enable_all'))
|
||||
.on('click', function() {
|
||||
context.validator().disableRules([]);
|
||||
});
|
||||
|
||||
ruleLinks
|
||||
.append('a')
|
||||
.attr('class', 'issue-rules-link')
|
||||
.attr('href', '#')
|
||||
.text(t('issues.disable_all'))
|
||||
.on('click', function() {
|
||||
var keys = context.validator().getRuleKeys();
|
||||
context.validator().disableRules(keys);
|
||||
});
|
||||
|
||||
|
||||
// Update
|
||||
container = container
|
||||
.merge(containerEnter);
|
||||
|
||||
var ruleKeys = context.validator().getRuleKeys();
|
||||
|
||||
container.selectAll('.issue-rules-list')
|
||||
.call(drawListItems, ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
|
||||
};
|
||||
|
||||
function drawListItems(selection, data, type, name, change, active) {
|
||||
var items = selection.selectAll('li')
|
||||
.data(data);
|
||||
|
||||
// Exit
|
||||
items.exit()
|
||||
.remove();
|
||||
|
||||
// Enter
|
||||
var enter = items.enter()
|
||||
.append('li');
|
||||
|
||||
if (name === 'rule') {
|
||||
enter
|
||||
.call(tooltip()
|
||||
.title(function(d) { return t('issues.' + d + '.tip'); })
|
||||
.placement('top')
|
||||
);
|
||||
}
|
||||
|
||||
var label = enter
|
||||
.append('label');
|
||||
|
||||
label
|
||||
.append('input')
|
||||
.attr('type', type)
|
||||
.attr('name', name)
|
||||
.on('change', change);
|
||||
|
||||
label
|
||||
.append('span')
|
||||
.html(function(d) {
|
||||
var params = {};
|
||||
if (d === 'unsquare_way') {
|
||||
params.val = '<span class="square-degrees"></span>';
|
||||
}
|
||||
return t('issues.' + d + '.title', params);
|
||||
});
|
||||
|
||||
// Update
|
||||
items = items
|
||||
.merge(enter);
|
||||
|
||||
items
|
||||
.classed('active', active)
|
||||
.selectAll('input')
|
||||
.property('checked', active)
|
||||
.property('indeterminate', false);
|
||||
|
||||
|
||||
// user-configurable square threshold
|
||||
var degStr = context.storage('validate-square-degrees');
|
||||
if (degStr === null) {
|
||||
degStr = '' + DEFAULTSQUARE;
|
||||
}
|
||||
|
||||
var span = items.selectAll('.square-degrees');
|
||||
var input = span.selectAll('.square-degrees-input')
|
||||
.data([0]);
|
||||
|
||||
// enter / update
|
||||
input.enter()
|
||||
.append('input')
|
||||
.attr('type', 'number')
|
||||
.attr('min', '' + MINSQUARE)
|
||||
.attr('max', '' + MAXSQUARE)
|
||||
.attr('step', '0.5')
|
||||
.attr('class', 'square-degrees-input')
|
||||
.call(utilNoAuto)
|
||||
.on('click', function () {
|
||||
d3_event.preventDefault();
|
||||
d3_event.stopPropagation();
|
||||
this.select();
|
||||
})
|
||||
.on('keyup', function () {
|
||||
if (d3_event.keyCode === 13) { // enter
|
||||
this.blur();
|
||||
this.select();
|
||||
}
|
||||
})
|
||||
.on('blur', changeSquare)
|
||||
.merge(input)
|
||||
.property('value', degStr);
|
||||
}
|
||||
|
||||
function changeSquare() {
|
||||
var input = d3_select(this);
|
||||
var degStr = utilGetSetValue(input).trim();
|
||||
var degNum = parseFloat(degStr, 10);
|
||||
|
||||
if (!isFinite(degNum)) {
|
||||
degNum = DEFAULTSQUARE;
|
||||
} else if (degNum > MAXSQUARE) {
|
||||
degNum = MAXSQUARE;
|
||||
} else if (degNum < MINSQUARE) {
|
||||
degNum = MINSQUARE;
|
||||
}
|
||||
|
||||
degNum = Math.round(degNum * 10 ) / 10; // round to 1 decimal
|
||||
degStr = '' + degNum;
|
||||
|
||||
input
|
||||
.property('value', degStr);
|
||||
|
||||
context.storage('validate-square-degrees', degStr);
|
||||
context.validator().reloadUnsquareIssues();
|
||||
}
|
||||
|
||||
function isRuleEnabled(d) {
|
||||
return context.validator().isRuleEnabled(d);
|
||||
}
|
||||
|
||||
function toggleRule(d) {
|
||||
context.validator().toggleRule(d);
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
Reference in New Issue
Block a user