* fromJSONAsync * Restore the edit history from a JSON string. * Because the restore process can involve fetching additional information from the OSM API, * this function needs to be async, and should be chained after a `context.resetAsync()` to ensure * that we are starting with a cle
(json)
| 1005 | * @return {Promise} Promise resolved when the restore process is complete |
| 1006 | */ |
| 1007 | fromJSONAsync(json) { |
| 1008 | const context = this.context; |
| 1009 | const gfx = context.systems.gfx; |
| 1010 | const osm = context.services.osm; |
| 1011 | |
| 1012 | const backup = JSON.parse(json); |
| 1013 | |
| 1014 | if (backup.version !== 3) { |
| 1015 | throw new Error(`Backup version ${backup.version} not supported.`); |
| 1016 | } |
| 1017 | |
| 1018 | // should we assert that the history has been reset? |
| 1019 | // we expect to chain after context.resetAsync() ? we could just call this._reset() ? |
| 1020 | |
| 1021 | gfx.pause(); // block rendering |
| 1022 | |
| 1023 | let loading; |
| 1024 | if (!window.mocha) { |
| 1025 | loading = uiLoading(context).blocking(true); |
| 1026 | context.container().call(loading); // block ui |
| 1027 | } |
| 1028 | |
| 1029 | const __baseEntities = new Map(); // Map(entityID -> Entity) |
| 1030 | const __modifiedEntities = new Map(); // Map(Entity.key -> Entity) (watch out: entity.key - e.g. 'n1v1') |
| 1031 | const __missingEntityIDs = new Set(); // Set(entityID) |
| 1032 | |
| 1033 | osmEntity.id.next = backup.nextIDs; |
| 1034 | |
| 1035 | // Reconstruct base entities.. |
| 1036 | for (const e of backup.baseEntities) { |
| 1037 | const entity = osmEntity(e); |
| 1038 | __baseEntities.set(entity.id, entity); |
| 1039 | } |
| 1040 | |
| 1041 | // Determine if any nodes are missing and need to be loaded separately.. |
| 1042 | for (const entity of __baseEntities.values()) { |
| 1043 | if (!Array.isArray(entity.nodes)) continue; // consider ways only |
| 1044 | for (const nodeID of entity.nodes) { |
| 1045 | if (!__baseEntities.has(nodeID)) { |
| 1046 | __missingEntityIDs.add(nodeID); |
| 1047 | } |
| 1048 | } |
| 1049 | } |
| 1050 | |
| 1051 | // Reconstruct modified entities.. |
| 1052 | for (const e of backup.entities) { |
| 1053 | __modifiedEntities.set(osmEntity.key(e), osmEntity(e)); |
| 1054 | } |
| 1055 | |
| 1056 | // Load missing entities from the OSM API |
| 1057 | // When we restore ways, we also need to fetch any missing childNodes |
| 1058 | // that would normally have been downloaded with those ways.. see iD#2142 |
| 1059 | // As added challenges: |
| 1060 | // - We have to keep the UI blocked while this is happening, because it's destructive to the graphs/edits. |
| 1061 | // - Callback can be called multiple times, so we have to keep track of how many of the missing nodes we got. |
| 1062 | // - The child nodes may have been deleted, so we may have to fetch older non-deleted copies |
| 1063 | // |
| 1064 | // A thought I'm having is - if we need to do all this anyway, it might make more sense to just store the |