Skip to content

Commit

Permalink
Merge branch 'editsystem-modern' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
bhousel committed Oct 21, 2023
2 parents 374debc + a8b3e24 commit 35a5957
Show file tree
Hide file tree
Showing 233 changed files with 7,602 additions and 5,857 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"no-unreachable": "warn",
"no-unreachable-loop": "warn",
"no-unused-expressions": "error",
"no-unused-vars": "warn",
"no-unused-vars": ["warn", { "vars": "all", "args": "none", "caughtErrors": "none" }],
"no-use-before-define": ["off", "nofunc"],
"no-useless-backreference": "warn",
"no-useless-call": "warn",
Expand Down
88 changes: 8 additions & 80 deletions modules/Context.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { EventEmitter } from '@pixi/utils';
import { select as d3_select } from 'd3-selection';
import { Projection, geoScaleToZoom } from '@rapid-sdk/math';
import { utilUnicodeCharsTruncated } from '@rapid-sdk/util';
import debounce from 'lodash-es/debounce';

import { behaviors } from './behaviors';
import { modes } from './modes';
Expand Down Expand Up @@ -92,13 +91,6 @@ export class Context extends EventEmitter {

// true/false whether we are in the intro walkthrough
this.inIntro = false;

// Ensure methods used as callbacks always have `this` bound correctly.
this.save = this.save.bind(this);

// Debounce save, since it's a synchronous localStorage write,
// and history changes can happen frequently (e.g. when dragging).
this.debouncedSave = debounce(this.save, 350);
}


Expand All @@ -115,43 +107,19 @@ export class Context extends EventEmitter {
this.systems[id] = new System(this);
}

// EditSystem
const editSystem = this.systems.edits;
const withDebouncedSave = (fn) => {
return (...args) => {
const result = fn.apply(editSystem, args);
this.debouncedSave();
return result;
};
};

this.graph = editSystem.graph;
this.hasEntity = (id) => editSystem.graph().hasEntity(id);
this.entity = (id) => editSystem.graph().entity(id);
this.pauseChangeDispatch = editSystem.pauseChangeDispatch;
this.resumeChangeDispatch = editSystem.resumeChangeDispatch;
this.perform = withDebouncedSave(editSystem.perform);
this.replace = withDebouncedSave(editSystem.replace);
this.pop = withDebouncedSave(editSystem.pop);
this.overwrite = withDebouncedSave(editSystem.overwrite);
this.undo = withDebouncedSave(editSystem.undo);
this.redo = withDebouncedSave(editSystem.redo);

// LocalizationSystem
const l10n = this.systems.l10n;
this.t = l10n.t;
this.tHtml = l10n.tHtml;
this.tAppend = l10n.tAppend;
if (this._prelocale) { // set preferred locale codes, if we have them
this.systems.l10n.preferredLocaleCodes = this._prelocale;
l10n.preferredLocaleCodes = this._prelocale;
}

// FilterSystem
const filterSystem = this.systems.filters;
const filters = this.systems.filters;
this.hasHiddenConnections = (entityID) => {
const graph = editSystem.graph();
const editor = this.systems.editor;
const graph = editor.staging.graph;
const entity = graph.entity(entityID);
return filterSystem.hasHiddenConnections(entity, graph);
return filters.hasHiddenConnections(entity, graph);
};

// MapSystem
Expand Down Expand Up @@ -208,8 +176,6 @@ export class Context extends EventEmitter {
* @return {Promise} Promise resolved when Rapid is finished resetting
*/
resetAsync() {
this.debouncedSave.cancel();

const allSystems = Object.values(this.systems);
const allServices = Object.values(this.services);

Expand Down Expand Up @@ -263,7 +229,7 @@ export class Context extends EventEmitter {
return;

} else {
this.systems.edits.merge(result.data, result.seenIDs);
this.systems.editor.merge(result.data, result.seenIDs);
if (typeof callback === 'function') {
callback(err, result);
}
Expand Down Expand Up @@ -333,42 +299,6 @@ export class Context extends EventEmitter {
cleanRelationRole(val) { return this._cleanOsmString(val, this.maxCharsForRelationRole); }


// Immediately save the user's history to localstorage, if possible
// This is called sometimes, but also on the `window.onbeforeunload` handler
save() {
const edits = this.systems.edits;
const l10n = this.systems.l10n;

// no history save, no message onbeforeunload
if (this.inIntro || this._container.select('.modal').size()) return;

let canSave;
if (this._currMode?.id === 'save') {
canSave = false;

// Attempt to prevent user from creating duplicate changes - see iD#5200
const osm = this.services.osm;
if (osm && osm.isChangesetInflight()) {
edits.clearSaved();
return;
}

} else {
canSave = this.selectedIDs().every(id => {
const entity = this.hasEntity(id);
return entity && !entity.isDegenerate();
});
}

if (canSave) {
edits.save();
}
if (edits.hasChanges()) {
return l10n.t('save.unsaved_changes');
}
}


/**
* mode
* Gets the current mode (`null` until UiSystem.render initializes the map and enters browse mode)
Expand Down Expand Up @@ -484,7 +414,7 @@ export class Context extends EventEmitter {
get copyIDs() { return this._copyIDs; }
set copyIDs(val) {
this._copyIDs = val;
this._copyGraph = this.systems.edits.graph();
this._copyGraph = this.systems.editor.staging.graph;
}

get copyLoc() { return this._copyLoc; }
Expand All @@ -500,9 +430,7 @@ export class Context extends EventEmitter {
}
setDebug(flag, val = true) {
this._debugFlags[flag] = val;
if (this.systems.map?.renderer) {
this.systems.map.immediateRedraw();
}
this.systems.map?.immediateRedraw();
}


Expand Down
3 changes: 2 additions & 1 deletion modules/behaviors/AbstractBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ export class AbstractBehavior extends EventEmitter {
/**
* _getEventData
* Returns an object containing the important details about this Pixi event.
* @param `e` A Pixi FederatedEvent (or something that looks like one)
* @param {Object} e - A Pixi FederatedEvent (or something that looks like one)
* @return {Object} Object containing data about the event and what was targeted
*/
_getEventData(e) {
// const result = {
Expand Down
36 changes: 32 additions & 4 deletions modules/behaviors/DragBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,10 @@ export class DragBehavior extends AbstractBehavior {
* @param `e` A Pixi FederatedPointerEvent
*/
_pointermove(e) {
const map = this.context.systems.map;
const context = this.context;
const editor = context.systems.editor;
const graph = editor.staging.graph;
const map = context.systems.map;

// If we detect the edit (right-click) menu, we should cease any dragging behavior.
const hasEditmenu = map.supersurface.select('.edit-menu').size();
Expand Down Expand Up @@ -156,17 +159,42 @@ export class DragBehavior extends AbstractBehavior {
} else if (down.target) { // start dragging if we've moved enough
const dist = vecLength(down.coord, move.coord);
const tolerance = (e.pointerType === 'pen') ? FAR_TOLERANCE : NEAR_TOLERANCE;

if (dist >= tolerance) {
// Save the target, *and set it to be non-interactive*.
// This lets us catch events for what other objects it passes over as the user drags it.
const target = Object.assign({}, down.target); // shallow copy
this.dragTarget = target;
target.feature.active = true;

const data = target.data;
const isMidpoint = (data.type === 'midpoint');

// If the current selection includes a parent of the dragged item,
// reselect those same feature(s) after the drag completes.
// (The user is reshaping a line or area by dragging vertices or midpoints.)
const parentWays = (isMidpoint ? [data.way] : graph.parentWays(data));

// Gather all parentIDs - include both ways and relations (such as multipolygons)
const parentIDs = new Set();
for (const way of parentWays) {
parentIDs.add(way.id);
for (const relation of graph.parentRelations(way)) {
parentIDs.add(relation.id);
}
}

const selectedIDs = context.selectedIDs();
const selectionIncludesParent = selectedIDs.some(selectedID => parentIDs.has(selectedID));
const reselectIDs = selectionIncludesParent ? selectedIDs.slice() : [];

// Enter Drag Node mode
const selection = new Map().set(target.data.id, target.data);
const reselectIDs = this.context.selectedIDs();
this.context.enter('drag-node', { selection: selection, reselectIDs: reselectIDs });
if (isMidpoint) {
const midpoint = { loc: data.loc, edge: [ data.a.id, data.b.id ] };
context.enter('drag-node', { midpoint: midpoint, reselectIDs: reselectIDs });
} else {
context.enter('drag-node', { nodeID: data.id, reselectIDs: reselectIDs });
}

this.emit('start', down);
}
Expand Down
4 changes: 2 additions & 2 deletions modules/behaviors/DrawBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ export class DrawBehavior extends AbstractBehavior {
// const activeIndex = target.nodes.indexOf(activeID);
// if (activeIndex !== -1) {
// isActiveTarget = true;
// const graph = context.graph();
// const graph = context.systems.editor.staging.graph;
// const projection = context.projection;
// const choice = geoChooseEdge(graph.childNodes(target), eventData.coord, projection, activeID);
//
Expand Down Expand Up @@ -341,7 +341,7 @@ export class DrawBehavior extends AbstractBehavior {
// const activeIndex = target.nodes.indexOf(activeID);
// if (activeIndex !== -1) {
// isActiveTarget = true;
// const graph = context.graph();
// const graph = context.systems.editor.staging.graph;
// const projection = context.projection;
// const choice = geoChooseEdge(graph.childNodes(target), eventData.coord, projection, activeID);
//
Expand Down
2 changes: 1 addition & 1 deletion modules/behaviors/HoverBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class HoverBehavior extends AbstractBehavior {
// const activeIndex = target.nodes.indexOf(activeID);
// if (activeIndex !== -1) {
// isActiveTarget = true;
// const graph = context.graph();
// const graph = context.systems.editor.staging.graph;
// const projection = context.projection;
// const choice = geoChooseEdge(graph.childNodes(target), eventData.coord, projection, activeID);
//
Expand Down
61 changes: 34 additions & 27 deletions modules/behaviors/LassoBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export class LassoBehavior extends AbstractBehavior {
this._lassoing = false;
this._extent = null;

const eventManager = this.context.systems.map.renderer.events;
const map = this.context.systems.map;
const eventManager = map.renderer.events;
eventManager.on('pointerdown', this._pointerdown);
eventManager.on('pointermove', this._pointermove);
eventManager.on('pointerup', this._pointerup);
Expand All @@ -60,7 +61,8 @@ export class LassoBehavior extends AbstractBehavior {
this._lassoing = false;
this._extent = null;

const eventManager = this.context.systems.map.renderer.events;
const map = this.context.systems.map;
const eventManager = map.renderer.events;
eventManager.off('pointerdown', this._pointerdown);
eventManager.off('pointermove', this._pointermove);
eventManager.off('pointerup', this._pointerup);
Expand All @@ -72,21 +74,22 @@ export class LassoBehavior extends AbstractBehavior {
* Handler for pointerdown events.
* @param `e` A Pixi FederatedPointerEvent
*/
_pointerdown() {
_pointerdown() {
// Ignore it if we are not over the canvas
// (e.g. sidebar, out of browser window, over a button, toolbar, modal)
const eventManager = this.context.systems.map.renderer.events;
if (!eventManager.pointerOverRenderer) return;

const modifiers = eventManager.modifierKeys;
const drawLasso = modifiers.has('Shift');

if (drawLasso) {
this._lassoing = true;
const coord = this.context.systems.map.mouseLoc();
this._extent = new Extent(coord);
this._coords.push(coord);
}
const map = this.context.systems.map;
const eventManager = map.renderer.events;
if (!eventManager.pointerOverRenderer) return;

const modifiers = eventManager.modifierKeys;
const drawLasso = modifiers.has('Shift');

if (drawLasso) {
this._lassoing = true;
const coord = map.mouseLoc();
this._extent = new Extent(coord);
this._coords.push(coord);
}
}


Expand All @@ -98,19 +101,20 @@ export class LassoBehavior extends AbstractBehavior {
_pointermove() {
if (!this._lassoing) return;

const eventManager = this.context.systems.map.renderer.events;
const map = this.context.systems.map;
const eventManager = map.renderer.events;
if (!eventManager.pointerOverRenderer) return;

const coord = this.context.systems.map.mouseLoc();
const coord = map.mouseLoc();

// Update geometry and extent
this._extent = this._extent.extend(new Extent(coord));
this._coords.push(coord);

// Push the polygon data to the map UI for rendering.
const mapUILayer = this.context.scene().layers.get('map-ui');
const mapUILayer = map.scene.layers.get('map-ui');
mapUILayer.lassoPolygonData = this._coords;
this.context.systems.map.immediateRedraw();
map.immediateRedraw();
}


Expand All @@ -123,7 +127,8 @@ export class LassoBehavior extends AbstractBehavior {
if (!this._lassoing) return;

this._lassoing = false;
const mapUILayer = this.context.scene().layers.get('map-ui');
const map = this.context.systems.map;
const mapUILayer = map.scene.layers.get('map-ui');

const ids = this._lassoed();
this._coords = [];
Expand All @@ -132,7 +137,7 @@ export class LassoBehavior extends AbstractBehavior {
this._extent = null;

if (ids.length) {
this.context.enter('select-osm', { selectedIDs: ids });
this.context.enter('select-osm', { selection: { osm: ids }} );
}
}

Expand All @@ -148,21 +153,23 @@ export class LassoBehavior extends AbstractBehavior {


_lassoed() {
const graph = this.context.graph();
const context = this.context;
const polygonLocs = this._coords;
const locationSystem = context.systems.locations;
const editor = context.systems.editor;
const locations = context.systems.locations;
const filters = context.systems.filters;
const graph = editor.staging.graph;

if (!this.context.editable()) return [];

let intersects = this.context.systems.edits
const polygonLocs = this._coords;
let intersects = editor
.intersects(this._extent)
.filter(entity => {
return (
entity.type === 'node' &&
geomPointInPolygon(entity.loc, polygonLocs) &&
!context.systems.filters.isHidden(entity, graph, entity.geometry(graph)) &&
!locationSystem.blocksAt(entity.loc).length
!filters.isHidden(entity, graph, entity.geometry(graph)) &&
!locations.blocksAt(entity.loc).length
);
});

Expand Down
Loading

0 comments on commit 35a5957

Please sign in to comment.