mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-14 01:33:03 +00:00
What could happen was: - user could right click on a line - this would trigger `disabled()` checks for each operation buttons - the line was not fully downloaded, so would return `disabled()` 'not_downloaded' (and also start download of the missing tiles) - then the tooltip would pop into existence, calling `tooltip()` - which calls `disabled()` again - but this time it's fine and the `disabled()` is false - so you'd see a greyed out button but the tooltip said everyting is ok and you can click the button anyway I fixed this by just caching the disabled test. This is probably ok anyway because these tests can be expensive, and then the user will see a consistent message like "The line is not yet fully downloaded". If the user clicks off the line and back onto it, iD will reenter select mode, rebuild the menu, redo the disabled test, and they will see the button enabled.
184 lines
5.7 KiB
JavaScript
184 lines
5.7 KiB
JavaScript
import { event as d3_event, select as d3_select } from 'd3-selection';
|
|
|
|
import { geoVecAdd, geoVecFloor } from '../geo';
|
|
import { textDirection } from '../util/locale';
|
|
import { uiTooltipHtml } from './tooltipHtml';
|
|
|
|
|
|
export function uiEditMenu(context, operations) {
|
|
var menu;
|
|
var center = [0, 0];
|
|
var offset = [0, 0];
|
|
var tooltip;
|
|
|
|
var p = 8; // top padding
|
|
var m = 4; // top margin
|
|
var h = 15; // height of icon
|
|
var vpBottomMargin = 45; // viewport bottom margin
|
|
var vpSideMargin = 35; // viewport side margin
|
|
var buttonWidth = 44;
|
|
var buttonHeight = (2 * p + h);
|
|
var menuWidth = buttonWidth;
|
|
var menuHeight = (2 * m) + operations.length * buttonHeight;
|
|
var menuSideMargin = 10;
|
|
var tooltipWidth = 200;
|
|
var tooltipHeight = 200; // a reasonable guess, real height depends on tooltip contents
|
|
|
|
|
|
var editMenu = function (selection) {
|
|
if (!operations.length) return;
|
|
|
|
selection.node().parentNode.focus();
|
|
|
|
var isRTL = textDirection === 'rtl';
|
|
var viewport = context.surfaceRect();
|
|
|
|
if (!isRTL && (center[0] + menuSideMargin + menuWidth) > (viewport.width - vpSideMargin)) {
|
|
// menu is going left-to-right and near right viewport edge, go left instead
|
|
isRTL = true;
|
|
} else if (isRTL && (center[0] - menuSideMargin - menuWidth) < vpSideMargin) {
|
|
// menu is going right-to-left and near left viewport edge, go right instead
|
|
isRTL = false;
|
|
}
|
|
|
|
offset[0] = (isRTL ? -1 * (menuSideMargin + menuWidth) : menuSideMargin);
|
|
|
|
if (center[1] + menuHeight > (viewport.height - vpBottomMargin)) {
|
|
// menu is near bottom viewport edge, shift upwards
|
|
offset[1] = -1 * (center[1] + menuHeight - viewport.height + vpBottomMargin);
|
|
}
|
|
|
|
var origin = geoVecAdd(center, offset);
|
|
|
|
menu = selection
|
|
.append('g')
|
|
.attr('class', 'edit-menu')
|
|
.attr('transform', 'translate(' + origin + ')')
|
|
.attr('opacity', 0);
|
|
|
|
menu
|
|
.transition()
|
|
.attr('opacity', 1);
|
|
|
|
menu
|
|
.append('rect')
|
|
.attr('class', 'edit-menu-background')
|
|
.attr('x', 4)
|
|
.attr('rx', 4)
|
|
.attr('ry', 4)
|
|
.attr('width', menuWidth)
|
|
.attr('height', menuHeight)
|
|
.attr('stroke-linecap', 'round');
|
|
|
|
|
|
var button = menu.selectAll('.edit-menu-item')
|
|
.data(operations);
|
|
|
|
// enter
|
|
var buttonEnter = button.enter()
|
|
.append('g')
|
|
.attr('class', function (d) { return 'edit-menu-item edit-menu-item-' + d.id; })
|
|
.attr('transform', function(d, i) {
|
|
return 'translate(' + geoVecFloor([0, m + i * buttonHeight]).join(',') + ')';
|
|
});
|
|
|
|
buttonEnter
|
|
.append('rect')
|
|
.attr('x', 4)
|
|
.attr('width', buttonWidth)
|
|
.attr('height', buttonHeight)
|
|
.on('click', click)
|
|
.on('mousedown', mousedown)
|
|
.on('mouseover', mouseover)
|
|
.on('mouseout', mouseout);
|
|
|
|
buttonEnter
|
|
.append('use')
|
|
.attr('width', '20')
|
|
.attr('height', '20')
|
|
.attr('transform', function () { return 'translate(' + [2 * p, 5] + ')'; })
|
|
.attr('xlink:href', function (d) { return '#iD-operation-' + d.id; });
|
|
|
|
// update
|
|
button = buttonEnter
|
|
.merge(button)
|
|
.classed('disabled', function(d) { return d.disabled(); });
|
|
|
|
|
|
tooltip = d3_select('#id-container')
|
|
.append('div')
|
|
.attr('class', 'tooltip-inner edit-menu-tooltip');
|
|
|
|
|
|
function click(operation) {
|
|
d3_event.stopPropagation();
|
|
if (operation.disabled()) return;
|
|
operation();
|
|
editMenu.close();
|
|
}
|
|
|
|
function mousedown() {
|
|
d3_event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
|
|
}
|
|
|
|
function mouseover(d, i) {
|
|
var tipX, tipY;
|
|
|
|
if (!isRTL) {
|
|
tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
|
|
} else {
|
|
tipX = viewport.left + origin[0] - 4 - tooltipWidth;
|
|
}
|
|
|
|
if (tipX + tooltipWidth > viewport.right) {
|
|
// tip is going left-to-right and near right viewport edge, go left instead
|
|
tipX = viewport.left + origin[0] - 4 - tooltipWidth;
|
|
} else if (tipX < viewport.left) {
|
|
// tip is going right-to-left and near left viewport edge, go right instead
|
|
tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
|
|
}
|
|
|
|
tipY = viewport.top + origin[1] + (i * buttonHeight);
|
|
if (tipY + tooltipHeight > viewport.bottom) {
|
|
// tip is near bottom viewport edge, shift upwards
|
|
tipY -= tipY + tooltipHeight - viewport.bottom;
|
|
}
|
|
|
|
tooltip
|
|
.style('left', tipX + 'px')
|
|
.style('top', tipY + 'px')
|
|
.style('display', 'block')
|
|
.html(uiTooltipHtml(d.tooltip(), d.keys[0], d.title));
|
|
}
|
|
|
|
function mouseout() {
|
|
tooltip.style('display', 'none');
|
|
}
|
|
};
|
|
|
|
|
|
editMenu.close = function () {
|
|
if (menu) {
|
|
menu
|
|
.style('pointer-events', 'none')
|
|
.transition()
|
|
.attr('opacity', 0)
|
|
.remove();
|
|
}
|
|
|
|
if (tooltip) {
|
|
tooltip.remove();
|
|
}
|
|
};
|
|
|
|
|
|
editMenu.center = function(val) {
|
|
if (!arguments.length) return center;
|
|
center = val;
|
|
return editMenu;
|
|
};
|
|
|
|
|
|
return editMenu;
|
|
}
|