mapshaper 0.7.10 → 0.7.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5472,7 +5472,7 @@
5472
5472
 
5473
5473
  function getUndoStorageLimit(name, defaultValue) {
5474
5474
  var opt = gui.options && gui.options[name],
5475
- query = getQueryValue$4(name);
5475
+ query = getQueryValue$2(name);
5476
5476
  if (query !== null && +query >= 0) return +query;
5477
5477
  return opt >= 0 ? opt : defaultValue;
5478
5478
  }
@@ -5540,10 +5540,10 @@
5540
5540
 
5541
5541
  function getUndoStorageLimitLabel(store) {
5542
5542
  var stats = store && store.getStats ? store.getStats() : null;
5543
- return formatBytes$2(stats && stats.maxBytes || 1024 * 1024 * 1024);
5543
+ return formatBytes$1(stats && stats.maxBytes || 1024 * 1024 * 1024);
5544
5544
  }
5545
5545
 
5546
- function formatBytes$2(bytes) {
5546
+ function formatBytes$1(bytes) {
5547
5547
  var units = ['B', 'KB', 'MB', 'GB'];
5548
5548
  var value = bytes;
5549
5549
  var i = 0;
@@ -5554,7 +5554,97 @@
5554
5554
  return (i === 0 ? String(value) : value.toFixed(value < 10 ? 1 : 0)) + ' ' + units[i];
5555
5555
  }
5556
5556
 
5557
- function getQueryValue$4(key) {
5557
+ function getQueryValue$2(key) {
5558
+ var rxp, match;
5559
+ if (typeof window == 'undefined' || !window.location) return null;
5560
+ rxp = new RegExp('[?&]' + key + '=([^&]+)');
5561
+ match = rxp.exec(window.location.search);
5562
+ return match ? decodeURIComponent(match[1]) : null;
5563
+ }
5564
+
5565
+ // Shared helpers for GUI controls that need to create app-level undo entries
5566
+ // (the storage-backed undo flow used by console commands and a few GUI actions).
5567
+ //
5568
+ // The five GUI controls that grew their own copies of these helpers in the
5569
+ // initial undo/redo commit (gui-add-layer-popup, gui-import-control,
5570
+ // gui-layer-control, gui-simplify-control, gui-undo) should import from here
5571
+ // instead.
5572
+
5573
+
5574
+ var DEFAULT_HISTORY_LIMIT = 10;
5575
+
5576
+ // Returns true if the manifest, URL query, gui-installed checker, or
5577
+ // localStorage indicates that app-level undo should be active.
5578
+ function appUndoIsEnabled(gui) {
5579
+ var opt = gui && gui.options && (gui.options.undoCommands || gui.options.appUndo);
5580
+ var query = getUndoQueryValue();
5581
+ if (opt === true || query == 'on' || query == 'commands') return true;
5582
+ if (gui && gui.appUndoIsEnabled) return gui.appUndoIsEnabled();
5583
+ return appUndoSettingIsOn();
5584
+ }
5585
+
5586
+ // True when the undo URL flag forces app undo on regardless of UI settings.
5587
+ // Mirrors the toggle-disable behavior in HistoryMenu.
5588
+ function appUndoForcedByUrl() {
5589
+ var query = getUndoQueryValue();
5590
+ return query == 'on' || query == 'commands';
5591
+ }
5592
+
5593
+ // Read the persisted localStorage opt-in. Returns false in non-browser
5594
+ // environments or when storage is blocked.
5595
+ function appUndoSettingIsOn() {
5596
+ try {
5597
+ return !!(typeof window != 'undefined' && window.localStorage &&
5598
+ window.localStorage.getItem('mapshaper.undo') == 'on');
5599
+ } catch(e) {
5600
+ return false;
5601
+ }
5602
+ }
5603
+
5604
+ // Returns the per-gui-instance stored undo history, creating it on first use.
5605
+ // Memoizing on `gui` avoids constructing parallel histories from different
5606
+ // callers (the original code created multiple instances depending on which
5607
+ // control ran first).
5608
+ function getStoredUndoHistory(gui) {
5609
+ if (!gui.storedUndoHistory) {
5610
+ gui.storedUndoHistory = createStoredUndoHistory(gui);
5611
+ }
5612
+ return gui.storedUndoHistory;
5613
+ }
5614
+
5615
+ function getUndoHistoryLimit(gui) {
5616
+ var opt = gui && gui.options && gui.options.undoHistoryLimit;
5617
+ return opt > 0 ? opt : DEFAULT_HISTORY_LIMIT;
5618
+ }
5619
+
5620
+ // Construct an UndoTransaction if and only if app undo is enabled and the
5621
+ // transaction can plausibly be added to history. Returns null when undo is
5622
+ // off, when the gui's undo manager is missing, or when the UndoTransaction
5623
+ // constructor cannot be located on the internal namespace.
5624
+ function createUndoTransaction(gui, label) {
5625
+ var Transaction;
5626
+ if (!appUndoIsEnabled(gui)) return null;
5627
+ if (!gui || !gui.undo || typeof gui.undo.addHistoryState != 'function') return null;
5628
+ Transaction = internal.UndoTransaction &&
5629
+ (internal.UndoTransaction.UndoTransaction || internal.UndoTransaction);
5630
+ return Transaction ? new Transaction(label || '') : null;
5631
+ }
5632
+
5633
+ // Add a captured transaction to gui-level history. Pass options through to
5634
+ // stored-undo-history.addTransaction(); fills in maxStates when not provided.
5635
+ function addUndoTransactionToHistory(gui, tx, opts) {
5636
+ if (!tx) return Promise.resolve(null);
5637
+ var fullOpts = Object.assign({maxStates: getUndoHistoryLimit(gui)}, opts || {});
5638
+ return getStoredUndoHistory(gui).addTransaction(tx, fullOpts).catch(function(e) {
5639
+ console.error(e);
5640
+ });
5641
+ }
5642
+
5643
+ function getUndoQueryValue() {
5644
+ return getQueryValue$1('undo');
5645
+ }
5646
+
5647
+ function getQueryValue$1(key) {
5558
5648
  var rxp, match;
5559
5649
  if (typeof window == 'undefined' || !window.location) return null;
5560
5650
  rxp = new RegExp('[?&]' + key + '=([^&]+)');
@@ -5588,7 +5678,7 @@
5588
5678
  function addEmptyLayer(gui, name, type) {
5589
5679
  var targ = gui.model.getActiveLayer();
5590
5680
  var crsInfo = targ && internal.getDatasetCrsInfo(targ.dataset);
5591
- var undoTransaction = createAddLayerUndoTransaction(gui);
5681
+ var undoTransaction = createUndoTransaction(gui, 'add empty layer');
5592
5682
  var dataset = {
5593
5683
  layers: [{
5594
5684
  name: name || undefined,
@@ -5608,60 +5698,12 @@
5608
5698
  }
5609
5699
  gui.model.addDataset(dataset);
5610
5700
  gui.model.updated({select: true});
5611
- addEmptyLayerUndoHistory(gui, undoTransaction);
5612
- }
5613
-
5614
- function createAddLayerUndoTransaction(gui) {
5615
- var Transaction;
5616
- if (!appUndoIsEnabled(gui)) return null;
5617
- if (!gui.undo || typeof gui.undo.addHistoryState != 'function') return null;
5618
- Transaction = internal.UndoTransaction && (internal.UndoTransaction.UndoTransaction || internal.UndoTransaction);
5619
- return Transaction ? new Transaction('add empty layer') : null;
5620
- }
5621
-
5622
- function addEmptyLayerUndoHistory(gui, tx) {
5623
- if (!tx) return;
5624
- getStoredUndoHistory(gui).addTransaction(tx, {
5701
+ addUndoTransactionToHistory(gui, undoTransaction, {
5625
5702
  flags: {select: true},
5626
- entryPrefix: 'add-layer',
5627
- maxStates: getUndoHistoryLimit(gui)
5628
- }).catch(function(e) {
5629
- console.error(e);
5703
+ entryPrefix: 'add-layer'
5630
5704
  });
5631
5705
  }
5632
5706
 
5633
- function getStoredUndoHistory(gui) {
5634
- if (!gui.storedUndoHistory) {
5635
- gui.storedUndoHistory = createStoredUndoHistory(gui);
5636
- }
5637
- return gui.storedUndoHistory;
5638
- }
5639
-
5640
- function getUndoHistoryLimit(gui) {
5641
- var opt = gui.options && gui.options.undoHistoryLimit;
5642
- return opt > 0 ? opt : 10;
5643
- }
5644
-
5645
- function appUndoIsEnabled(gui) {
5646
- var opt = gui.options && (gui.options.undoCommands || gui.options.appUndo);
5647
- var query = getQueryValue$3('undo');
5648
- if (opt === true || query == 'on' || query == 'commands') return true;
5649
- if (gui.appUndoIsEnabled) return gui.appUndoIsEnabled();
5650
- try {
5651
- return window.localStorage && window.localStorage.getItem('mapshaper.undo') == 'on';
5652
- } catch(e) {
5653
- return false;
5654
- }
5655
- }
5656
-
5657
- function getQueryValue$3(key) {
5658
- var rxp, match;
5659
- if (typeof window == 'undefined' || !window.location) return null;
5660
- rxp = new RegExp('[?&]' + key + '=([^&]+)');
5661
- match = rxp.exec(window.location.search);
5662
- return match ? decodeURIComponent(match[1]) : null;
5663
- }
5664
-
5665
5707
  async function considerReprojecting(gui, dataset, opts) {
5666
5708
  var mapCRS = gui.map.getActiveLayerCRS();
5667
5709
  var dataCRS = internal.getDatasetCRS(dataset);
@@ -5709,7 +5751,7 @@
5709
5751
  }
5710
5752
 
5711
5753
  async function loadGeoParquetLib() {
5712
- if (!window.modules || !window.modules.hyparquet || !window.modules['hyparquet-compressors'] || !window.modules['hyparquet-writer'] || !window.modules['zstd-codec']) {
5754
+ if (!window.modules || !window.modules.hyparquet || !window.modules['hyparquet-compressors'] || !window.modules['hyparquet-writer'] || !window.modules['@bokuweb/zstd-wasm']) {
5713
5755
  if (!geoParquetPromise) {
5714
5756
  geoParquetPromise = loadScript('geoparquet.js');
5715
5757
  }
@@ -5921,7 +5963,7 @@
5921
5963
  // gui.container.removeClass('queued-files');
5922
5964
  hideImportMenu();
5923
5965
  var files = queuedFiles;
5924
- var undoTransaction = createImportUndoTransaction();
5966
+ var undoTransaction = model.isEmpty() ? null : createUndoTransaction(gui, 'import files');
5925
5967
  var imported = false;
5926
5968
  try {
5927
5969
  if (files.length > 0) {
@@ -5941,7 +5983,10 @@
5941
5983
  gui.clearMode();
5942
5984
  }
5943
5985
  if (undoTransaction && imported) {
5944
- addImportUndoHistory(undoTransaction);
5986
+ addUndoTransactionToHistory(gui, undoTransaction, {
5987
+ flags: {select: true, arc_count: true},
5988
+ entryPrefix: 'import'
5989
+ });
5945
5990
  }
5946
5991
  }
5947
5992
 
@@ -6174,56 +6219,6 @@
6174
6219
  return imported;
6175
6220
  }
6176
6221
 
6177
- function createImportUndoTransaction() {
6178
- var Transaction;
6179
- if (model.isEmpty() || !appUndoIsEnabled()) return null;
6180
- if (!gui.undo || typeof gui.undo.addHistoryState != 'function') return null;
6181
- Transaction = internal.UndoTransaction && (internal.UndoTransaction.UndoTransaction || internal.UndoTransaction);
6182
- return Transaction ? new Transaction('import files') : null;
6183
- }
6184
-
6185
- function addImportUndoHistory(tx) {
6186
- getStoredUndoHistory().addTransaction(tx, {
6187
- flags: {select: true, arc_count: true},
6188
- entryPrefix: 'import',
6189
- maxStates: getUndoHistoryLimit()
6190
- }).catch(function(e) {
6191
- console.error(e);
6192
- });
6193
- }
6194
-
6195
- function getStoredUndoHistory() {
6196
- if (!gui.storedUndoHistory) {
6197
- gui.storedUndoHistory = createStoredUndoHistory(gui);
6198
- }
6199
- return gui.storedUndoHistory;
6200
- }
6201
-
6202
- function getUndoHistoryLimit() {
6203
- var opt = gui.options && gui.options.undoHistoryLimit;
6204
- return opt > 0 ? opt : 10;
6205
- }
6206
-
6207
- function appUndoIsEnabled() {
6208
- var opt = gui.options && (gui.options.undoCommands || gui.options.appUndo);
6209
- var query = getQueryValue('undo');
6210
- if (opt === true || query == 'on' || query == 'commands') return true;
6211
- if (gui.appUndoIsEnabled) return gui.appUndoIsEnabled();
6212
- try {
6213
- return window.localStorage && window.localStorage.getItem('mapshaper.undo') == 'on';
6214
- } catch(e) {
6215
- return false;
6216
- }
6217
- }
6218
-
6219
- function getQueryValue(key) {
6220
- var rxp, match;
6221
- if (typeof window == 'undefined' || !window.location) return null;
6222
- rxp = new RegExp('[?&]' + key + '=([^&]+)');
6223
- match = rxp.exec(window.location.search);
6224
- return match ? decodeURIComponent(match[1]) : null;
6225
- }
6226
-
6227
6222
 
6228
6223
 
6229
6224
  function filesMayContainPaths(files) {
@@ -7789,8 +7784,8 @@
7789
7784
 
7790
7785
  function startSimplifyUndoSession(dataset) {
7791
7786
  var tx;
7792
- if (!dataset || !dataset.arcs || !appUndoIsEnabled()) return;
7793
- tx = createSimplifyUndoTransaction();
7787
+ if (!dataset || !dataset.arcs || !appUndoIsEnabled(gui)) return;
7788
+ tx = createUndoTransaction(gui, 'simplify');
7794
7789
  if (!tx) return;
7795
7790
  tx.captureArcsSimplificationBefore(dataset.arcs, {operation: 'simplifyTool'});
7796
7791
  tx.captureDatasetInfoBefore(dataset, {operation: 'simplifyTool'});
@@ -7808,54 +7803,12 @@
7808
7803
  var session = undoSession;
7809
7804
  undoSession = null;
7810
7805
  if (!session || !session.changed) return;
7811
- getStoredUndoHistory().addTransaction(session.tx, {
7806
+ addUndoTransactionToHistory(gui, session.tx, {
7812
7807
  flags: {simplify: true, info: true},
7813
- entryPrefix: 'simplify-tool',
7814
- maxStates: getUndoHistoryLimit()
7815
- }).catch(function(e) {
7816
- console.error(e);
7808
+ entryPrefix: 'simplify-tool'
7817
7809
  });
7818
7810
  }
7819
7811
 
7820
- function createSimplifyUndoTransaction() {
7821
- var Transaction;
7822
- if (!gui.undo || typeof gui.undo.addHistoryState != 'function') return null;
7823
- Transaction = internal.UndoTransaction && (internal.UndoTransaction.UndoTransaction || internal.UndoTransaction);
7824
- return Transaction ? new Transaction('simplify') : null;
7825
- }
7826
-
7827
- function getStoredUndoHistory() {
7828
- if (!gui.storedUndoHistory) {
7829
- gui.storedUndoHistory = createStoredUndoHistory(gui);
7830
- }
7831
- return gui.storedUndoHistory;
7832
- }
7833
-
7834
- function getUndoHistoryLimit() {
7835
- var opt = gui.options && gui.options.undoHistoryLimit;
7836
- return opt > 0 ? opt : 10;
7837
- }
7838
-
7839
- function appUndoIsEnabled() {
7840
- var opt = gui.options && (gui.options.undoCommands || gui.options.appUndo);
7841
- var query = getQueryValue('undo');
7842
- if (opt === true || query == 'on' || query == 'commands') return true;
7843
- if (gui.appUndoIsEnabled) return gui.appUndoIsEnabled();
7844
- try {
7845
- return window.localStorage && window.localStorage.getItem('mapshaper.undo') == 'on';
7846
- } catch(e) {
7847
- return false;
7848
- }
7849
- }
7850
-
7851
- function getQueryValue(key) {
7852
- var rxp, match;
7853
- if (typeof window == 'undefined' || !window.location) return null;
7854
- rxp = new RegExp('[?&]' + key + '=([^&]+)');
7855
- match = rxp.exec(window.location.search);
7856
- return match ? decodeURIComponent(match[1]) : null;
7857
- }
7858
-
7859
7812
  function updateSliderDisplay() {
7860
7813
  // TODO: display resolution and vertex count
7861
7814
  // var dataset = model.getActiveLayer().dataset;
@@ -7973,599 +7926,6 @@
7973
7926
  return internal.formatOptionValue(internal.getLayerTargetId(gui.model, lyr));
7974
7927
  }
7975
7928
 
7976
- // Diagnostic-only scaffolding for app-wide undo/redo R&D.
7977
- // It is intentionally dormant unless explicitly enabled.
7978
-
7979
- var DEFAULT_POLICY = {
7980
- maxStates: 20,
7981
- maxBytes: 256 * 1024 * 1024,
7982
- largeChangeBytes: 64 * 1024 * 1024,
7983
- captureMode: 'diagnostic',
7984
- sessionHistory: 'audit-log'
7985
- };
7986
-
7987
- var EDITOR_UNDO_INVENTORY = [
7988
- {
7989
- name: 'attributes',
7990
- events: ['data_preupdate', 'data_postupdate'],
7991
- capture: 'record copies',
7992
- reusable: true
7993
- },
7994
- {
7995
- name: 'labels',
7996
- events: ['label_dragstart', 'label_dragend'],
7997
- capture: 'record copies',
7998
- reusable: true
7999
- },
8000
- {
8001
- name: 'points and symbols',
8002
- events: ['symbol_dragend', 'point_add', 'feature_delete'],
8003
- capture: 'coordinate and feature inserts/deletes',
8004
- reusable: true
8005
- },
8006
- {
8007
- name: 'vertices and rectangles',
8008
- events: ['vertex_dragend', 'vertex_delete', 'rectangle_dragend'],
8009
- capture: 'coordinate and vertex inserts/deletes',
8010
- reusable: true
8011
- },
8012
- {
8013
- name: 'path drawing',
8014
- events: ['path_add', 'path_extend'],
8015
- capture: 'editor events replayed through drawing mode',
8016
- reusable: false
8017
- }
8018
- ];
8019
-
8020
- function createUndoFeasibilityMonitor(gui, opts) {
8021
- opts = Object.assign({}, DEFAULT_POLICY, opts || {});
8022
- var tracker = createRuntimeIdTracker();
8023
- var enabled = isUndoFeasibilityEnabled(gui);
8024
- var lastReport = null;
8025
-
8026
- return {
8027
- beforeCommand,
8028
- afterCommand,
8029
- isEnabled: function() { return enabled; },
8030
- setEnabled: function(val) { enabled = !!val; },
8031
- getPolicy: function() { return Object.assign({}, opts); },
8032
- getLastReport: function() { return lastReport; },
8033
- getEditorUndoInventory: function() { return EDITOR_UNDO_INVENTORY.slice(); }
8034
- };
8035
-
8036
- function beforeCommand(commands, commandString) {
8037
- var start, before;
8038
- if (!enabled || !gui.model || gui.model.isEmpty()) return null;
8039
- start = Date.now();
8040
- before = captureModelState(gui.model, tracker);
8041
- return {
8042
- commandString: commandString || '',
8043
- commandNames: commands.map(function(cmd) { return cmd.name; }),
8044
- before: before,
8045
- beforeCaptureMillis: Date.now() - start,
8046
- startedAt: start
8047
- };
8048
- }
8049
-
8050
- function afterCommand(token, o) {
8051
- var start, after, report;
8052
- if (!token) return null;
8053
- start = Date.now();
8054
- after = captureModelState(gui.model, tracker);
8055
- report = diffModelStates(token.before, after, {
8056
- commandString: token.commandString,
8057
- commandNames: token.commandNames,
8058
- error: o && o.error,
8059
- flags: o && o.flags,
8060
- policy: opts,
8061
- timings: {
8062
- beforeCaptureMillis: token.beforeCaptureMillis,
8063
- afterCaptureMillis: Date.now() - start,
8064
- elapsedMillis: Date.now() - token.startedAt
8065
- }
8066
- });
8067
- lastReport = report;
8068
- gui.dispatchEvent('undo_feasibility_change', report);
8069
- logUndoFeasibilityReport(report);
8070
- return report;
8071
- }
8072
- }
8073
-
8074
- function captureModelState(model, tracker) {
8075
- tracker = tracker || createRuntimeIdTracker();
8076
- var datasets = model.getDatasets();
8077
- var active = model.getActiveLayer && model.getActiveLayer();
8078
- var targets = model.getDefaultTargets ? model.getDefaultTargets() : [];
8079
- var state = {
8080
- datasets: [],
8081
- datasetsById: {},
8082
- layersById: {},
8083
- activeLayerId: active && active.layer ? tracker.layerId(active.layer) : null,
8084
- activeDatasetId: active && active.dataset ? tracker.datasetId(active.dataset) : null,
8085
- targetHash: hashStableValue(targets.map(function(target) {
8086
- return {
8087
- dataset: tracker.datasetId(target.dataset),
8088
- layers: target.layers.map(function(lyr) {
8089
- return tracker.layerId(lyr);
8090
- })
8091
- };
8092
- })),
8093
- editorUndo: EDITOR_UNDO_INVENTORY.slice(),
8094
- policy: Object.assign({}, DEFAULT_POLICY)
8095
- };
8096
-
8097
- datasets.forEach(function(dataset, i) {
8098
- var datasetState = captureDatasetState(dataset, i, tracker);
8099
- state.datasets.push(datasetState);
8100
- state.datasetsById[datasetState.id] = datasetState;
8101
- datasetState.layers.forEach(function(layerState) {
8102
- state.layersById[layerState.id] = layerState;
8103
- });
8104
- });
8105
- state.catalogHash = hashStableValue({
8106
- datasets: state.datasets.map(function(dataset) {
8107
- return {
8108
- id: dataset.id,
8109
- index: dataset.index,
8110
- layers: dataset.layerIds
8111
- };
8112
- }),
8113
- activeLayerId: state.activeLayerId,
8114
- activeDatasetId: state.activeDatasetId,
8115
- targetHash: state.targetHash
8116
- });
8117
- state.bytes = estimateStateBytes(state);
8118
- return state;
8119
- }
8120
-
8121
- function diffModelStates(before, after, opts) {
8122
- opts = opts || {};
8123
- var changes = {
8124
- catalog: before.catalogHash != after.catalogHash,
8125
- selection: before.activeLayerId != after.activeLayerId ||
8126
- before.activeDatasetId != after.activeDatasetId ||
8127
- before.targetHash != after.targetHash,
8128
- datasets: [],
8129
- layers: []
8130
- };
8131
- var ids = mergeKeys(before.datasetsById, after.datasetsById);
8132
- var layerIds = mergeKeys(before.layersById, after.layersById);
8133
-
8134
- ids.forEach(function(id) {
8135
- var a = before.datasetsById[id];
8136
- var b = after.datasetsById[id];
8137
- var change = diffDatasetState(a, b);
8138
- if (change) changes.datasets.push(change);
8139
- });
8140
-
8141
- layerIds.forEach(function(id) {
8142
- var a = before.layersById[id];
8143
- var b = after.layersById[id];
8144
- var change = diffLayerState(a, b);
8145
- if (change) changes.layers.push(change);
8146
- });
8147
-
8148
- return {
8149
- type: 'undo-feasibility',
8150
- command: opts.commandString || '',
8151
- commandNames: opts.commandNames || [],
8152
- failed: !!(opts.error),
8153
- error: opts.error ? String(opts.error.message || opts.error) : null,
8154
- changes: changes,
8155
- storage: estimateUndoStorage(before, after, changes, opts.policy || DEFAULT_POLICY),
8156
- timings: opts.timings || null,
8157
- restore: getRestoreContract(changes),
8158
- policy: getUndoPolicy(opts.policy || DEFAULT_POLICY)
8159
- };
8160
- }
8161
-
8162
- function getUndoPolicy(policy) {
8163
- policy = Object.assign({}, DEFAULT_POLICY, policy || {});
8164
- return {
8165
- optIn: true,
8166
- enableWith: ['gui option undoFeasibility', 'URL parameter undo=diagnostic', 'localStorage mapshaper.undo=diagnostic'],
8167
- stackLimits: {
8168
- maxStates: policy.maxStates,
8169
- maxBytes: policy.maxBytes,
8170
- largeChangeBytes: policy.largeChangeBytes
8171
- },
8172
- coexistence: 'Existing editor undo remains event-based; app-wide command undo should use the same UI state events after it graduates from diagnostics.',
8173
- sessionHistory: 'Session history remains an audit log and is not rewound by undo/redo.'
8174
- };
8175
- }
8176
-
8177
- function getRestoreContract(changes) {
8178
- var flags = {
8179
- select: changes.selection || changes.catalog,
8180
- arc_count: false
8181
- };
8182
- var levels = [];
8183
-
8184
- changes.datasets.forEach(function(change) {
8185
- if (change.status != 'changed') {
8186
- levels.push('catalog');
8187
- } else {
8188
- if (change.arcs) {
8189
- levels.push('dataset');
8190
- flags.arc_count = true;
8191
- }
8192
- if (change.info) levels.push('dataset-info');
8193
- if (change.layerOrder) levels.push('layer-order');
8194
- }
8195
- });
8196
- changes.layers.forEach(function(change) {
8197
- if (change.status != 'changed') {
8198
- levels.push('catalog');
8199
- } else {
8200
- if (change.shapes) levels.push('layer-shapes');
8201
- if (change.data) levels.push('layer-data');
8202
- if (change.meta) levels.push('layer-meta');
8203
- }
8204
- });
8205
-
8206
- return {
8207
- levels: unique(levels),
8208
- updateFlags: flags,
8209
- redoInvalidation: 'Discard redo entries when a new command report contains data, catalog, or selection changes.',
8210
- failureHandling: 'Capture starts before command execution, so partial success after an error can still be rolled back.'
8211
- };
8212
- }
8213
-
8214
- function createRuntimeIdTracker() {
8215
- var datasetIds = new WeakMap();
8216
- var layerIds = new WeakMap();
8217
- var datasetId = 0;
8218
- var layerId = 0;
8219
- return {
8220
- datasetId: function(dataset) {
8221
- if (!datasetIds.has(dataset)) datasetIds.set(dataset, 'd' + (++datasetId));
8222
- return datasetIds.get(dataset);
8223
- },
8224
- layerId: function(layer) {
8225
- if (!layerIds.has(layer)) layerIds.set(layer, 'l' + (++layerId));
8226
- return layerIds.get(layer);
8227
- }
8228
- };
8229
- }
8230
-
8231
- function captureDatasetState(dataset, i, tracker) {
8232
- var layers = dataset.layers.map(function(lyr, j) {
8233
- return captureLayerState(lyr, j, tracker, dataset);
8234
- });
8235
- var arcs = captureArcsState(dataset.arcs);
8236
- var info = captureValueState(dataset.info || null);
8237
- var state = {
8238
- id: tracker.datasetId(dataset),
8239
- index: i,
8240
- layerIds: layers.map(function(lyr) { return lyr.id; }),
8241
- layerOrderHash: hashStableValue(layers.map(function(lyr) { return lyr.id; })),
8242
- arcs: arcs,
8243
- info: info,
8244
- layers: layers
8245
- };
8246
- state.bytes = arcs.bytes + info.bytes + layers.reduce(function(memo, lyr) {
8247
- return memo + lyr.bytes;
8248
- }, 0);
8249
- return state;
8250
- }
8251
-
8252
- function captureLayerState(lyr, i, tracker, dataset) {
8253
- var data = captureDataState(lyr.data);
8254
- var shapes = captureValueState(lyr.shapes || null);
8255
- var meta = captureValueState(getLayerMeta(lyr));
8256
- return {
8257
- id: tracker.layerId(lyr),
8258
- datasetId: tracker.datasetId(dataset),
8259
- index: i,
8260
- name: lyr.name || '',
8261
- geometry_type: lyr.geometry_type || null,
8262
- data: data,
8263
- shapes: shapes,
8264
- meta: meta,
8265
- bytes: data.bytes + shapes.bytes + meta.bytes
8266
- };
8267
- }
8268
-
8269
- function captureDataState(data) {
8270
- var records = data ? data.getRecords() : null;
8271
- var state = captureValueState(records);
8272
- state.recordCount = data ? data.size() : 0;
8273
- state.fields = data ? data.getFields() : [];
8274
- return state;
8275
- }
8276
-
8277
- function captureArcsState(arcs) {
8278
- var data, bytes;
8279
- if (!arcs) {
8280
- return {
8281
- exists: false,
8282
- arcCount: 0,
8283
- pointCount: 0,
8284
- retainedInterval: 0,
8285
- hash: 'null',
8286
- bytes: 0
8287
- };
8288
- }
8289
- data = arcs.getVertexData();
8290
- bytes = typedBytes(data.nn) + typedBytes(data.xx) + typedBytes(data.yy) + typedBytes(data.zz);
8291
- return {
8292
- exists: true,
8293
- arcCount: arcs.size(),
8294
- pointCount: arcs.getPointCount(),
8295
- retainedInterval: arcs.getRetainedInterval(),
8296
- hash: hashStableValue({
8297
- nn: hashTypedArray(data.nn),
8298
- xx: hashTypedArray(data.xx),
8299
- yy: hashTypedArray(data.yy),
8300
- zz: data.zz ? hashTypedArray(data.zz) : null,
8301
- zlimit: arcs.getRetainedInterval()
8302
- }),
8303
- bytes: bytes
8304
- };
8305
- }
8306
-
8307
- function captureValueState(obj) {
8308
- var str = stableStringify$1(obj);
8309
- return {
8310
- hash: hashString$1(str),
8311
- bytes: estimateStringBytes(str)
8312
- };
8313
- }
8314
-
8315
- function diffDatasetState(a, b) {
8316
- if (!a) return {id: b.id, status: 'added', bytes: b.bytes};
8317
- if (!b) return {id: a.id, status: 'removed', bytes: a.bytes};
8318
- var change = {
8319
- id: a.id,
8320
- status: 'changed',
8321
- index: a.index != b.index,
8322
- layerOrder: a.layerOrderHash != b.layerOrderHash,
8323
- arcs: a.arcs.hash != b.arcs.hash,
8324
- info: a.info.hash != b.info.hash,
8325
- beforeBytes: a.bytes,
8326
- afterBytes: b.bytes
8327
- };
8328
- return change.index || change.layerOrder || change.arcs || change.info ? change : null;
8329
- }
8330
-
8331
- function diffLayerState(a, b) {
8332
- if (!a) return {id: b.id, datasetId: b.datasetId, status: 'added', bytes: b.bytes};
8333
- if (!b) return {id: a.id, datasetId: a.datasetId, status: 'removed', bytes: a.bytes};
8334
- var change = {
8335
- id: a.id,
8336
- datasetId: b.datasetId,
8337
- status: 'changed',
8338
- index: a.index != b.index,
8339
- data: a.data.hash != b.data.hash,
8340
- shapes: a.shapes.hash != b.shapes.hash,
8341
- meta: a.meta.hash != b.meta.hash,
8342
- beforeBytes: a.bytes,
8343
- afterBytes: b.bytes,
8344
- recordCount: b.data.recordCount,
8345
- fields: b.data.fields
8346
- };
8347
- return change.index || change.data || change.shapes || change.meta ? change : null;
8348
- }
8349
-
8350
- function estimateUndoStorage(before, after, changes, policy) {
8351
- var bytes = 0;
8352
- var strategy = 'none';
8353
- var changedDatasets = {};
8354
- var changedLayers = {};
8355
- var alternatives = estimateStorageAlternatives(before, after, changes);
8356
-
8357
- changes.datasets.forEach(function(change) {
8358
- var beforeState = before.datasetsById[change.id];
8359
- var afterState = after.datasetsById[change.id];
8360
- if (change.status != 'changed' || change.arcs || change.layerOrder) {
8361
- bytes += (beforeState ? beforeState.bytes : 0) + (afterState ? afterState.bytes : 0);
8362
- changedDatasets[change.id] = true;
8363
- } else if (change.info) {
8364
- bytes += (beforeState ? beforeState.info.bytes : 0) + (afterState ? afterState.info.bytes : 0);
8365
- strategy = strategy == 'none' ? 'dataset-info' : strategy;
8366
- }
8367
- });
8368
- changes.layers.forEach(function(change) {
8369
- var beforeState = before.layersById[change.id];
8370
- var afterState = after.layersById[change.id];
8371
- if (changedDatasets[change.datasetId]) return;
8372
- if (change.data && !change.shapes && !change.meta) {
8373
- bytes += (beforeState ? beforeState.data.bytes : 0) + (afterState ? afterState.data.bytes : 0);
8374
- strategy = strategy == 'none' ? 'table' : strategy;
8375
- } else {
8376
- bytes += (beforeState ? beforeState.bytes : 0) + (afterState ? afterState.bytes : 0);
8377
- changedLayers[change.id] = true;
8378
- }
8379
- });
8380
-
8381
- if (Object.keys(changedDatasets).length > 0) {
8382
- strategy = 'dataset';
8383
- } else if (Object.keys(changedLayers).length > 0) {
8384
- strategy = strategy == 'none' ? 'layer' : 'mixed';
8385
- }
8386
-
8387
- return {
8388
- strategy: strategy,
8389
- estimatedBytes: bytes,
8390
- displaySize: formatBytes$1(bytes),
8391
- alternatives: alternatives,
8392
- exceedsLargeChangeLimit: bytes > policy.largeChangeBytes,
8393
- exceedsStackLimit: bytes > policy.maxBytes
8394
- };
8395
- }
8396
-
8397
- function estimateStorageAlternatives(before, after, changes) {
8398
- var alternatives = {
8399
- fullSession: before.bytes + after.bytes,
8400
- changedDatasets: 0,
8401
- changedLayers: 0,
8402
- changedTables: 0,
8403
- changedArcs: 0
8404
- };
8405
- var datasetIds = {};
8406
-
8407
- changes.datasets.forEach(function(change) {
8408
- var beforeState = before.datasetsById[change.id];
8409
- var afterState = after.datasetsById[change.id];
8410
- var datasetBytes = (beforeState ? beforeState.bytes : 0) + (afterState ? afterState.bytes : 0);
8411
- alternatives.changedDatasets += datasetBytes;
8412
- datasetIds[change.id] = true;
8413
- if (change.arcs) {
8414
- alternatives.changedArcs += (beforeState ? beforeState.arcs.bytes : 0) +
8415
- (afterState ? afterState.arcs.bytes : 0);
8416
- }
8417
- });
8418
- changes.layers.forEach(function(change) {
8419
- var beforeState = before.layersById[change.id];
8420
- var afterState = after.layersById[change.id];
8421
- if (datasetIds[change.datasetId]) return;
8422
- alternatives.changedLayers += (beforeState ? beforeState.bytes : 0) +
8423
- (afterState ? afterState.bytes : 0);
8424
- if (change.data) {
8425
- alternatives.changedTables += (beforeState ? beforeState.data.bytes : 0) +
8426
- (afterState ? afterState.data.bytes : 0);
8427
- }
8428
- });
8429
- Object.keys(alternatives).forEach(function(key) {
8430
- alternatives[key] = {
8431
- estimatedBytes: alternatives[key],
8432
- displaySize: formatBytes$1(alternatives[key])
8433
- };
8434
- });
8435
- return alternatives;
8436
- }
8437
-
8438
- function estimateStateBytes(state) {
8439
- return state.datasets.reduce(function(memo, dataset) {
8440
- return memo + dataset.bytes;
8441
- }, 0);
8442
- }
8443
-
8444
- function getLayerMeta(lyr) {
8445
- var meta = {};
8446
- Object.keys(lyr).sort().forEach(function(key) {
8447
- if (key == 'data' || key == 'shapes') return;
8448
- meta[key] = lyr[key];
8449
- });
8450
- return meta;
8451
- }
8452
-
8453
- function isUndoFeasibilityEnabled(gui) {
8454
- var opt = gui.options && gui.options.undoFeasibility;
8455
- var query = getQueryValue$2('undo');
8456
- if (opt === true || opt == 'diagnostic') return true;
8457
- if (query == 'diagnostic' || query == 'debug') return true;
8458
- try {
8459
- return window.localStorage && window.localStorage.getItem('mapshaper.undo') == 'diagnostic';
8460
- } catch(e) {
8461
- return false;
8462
- }
8463
- }
8464
-
8465
- function getQueryValue$2(key) {
8466
- var rxp, match;
8467
- if (typeof window == 'undefined' || !window.location) return null;
8468
- rxp = new RegExp('[?&]' + key + '=([^&]+)');
8469
- match = rxp.exec(window.location.search);
8470
- return match ? decodeURIComponent(match[1]) : null;
8471
- }
8472
-
8473
- function logUndoFeasibilityReport(report) {
8474
- if (typeof console == 'undefined' || !console.log) return;
8475
- console.log('[mapshaper undo feasibility]', {
8476
- command: report.command,
8477
- failed: report.failed,
8478
- changes: report.changes,
8479
- storage: report.storage,
8480
- restore: report.restore
8481
- });
8482
- }
8483
-
8484
- function mergeKeys(a, b) {
8485
- var index = {};
8486
- Object.keys(a).forEach(function(key) { index[key] = true; });
8487
- Object.keys(b).forEach(function(key) { index[key] = true; });
8488
- return Object.keys(index);
8489
- }
8490
-
8491
- function unique(arr) {
8492
- var index = {};
8493
- arr.forEach(function(item) { index[item] = true; });
8494
- return Object.keys(index);
8495
- }
8496
-
8497
- function hashStableValue(obj) {
8498
- return hashString$1(stableStringify$1(obj));
8499
- }
8500
-
8501
- function stableStringify$1(obj) {
8502
- var seen = [];
8503
- return stringify(obj, 0);
8504
-
8505
- function stringify(val, depth) {
8506
- var keys;
8507
- if (val === null) return 'null';
8508
- if (val === undefined) return 'undefined';
8509
- if (typeof val == 'number') return Number.isNaN(val) ? 'NaN' : String(val);
8510
- if (typeof val == 'string') return JSON.stringify(val);
8511
- if (typeof val == 'boolean') return String(val);
8512
- if (typeof val == 'function') return '[Function]';
8513
- if (ArrayBuffer.isView(val)) return hashTypedArray(val);
8514
- if (seen.indexOf(val) > -1) return '[Circular]';
8515
- if (depth > 8) return '[MaxDepth]';
8516
- seen.push(val);
8517
- if (Array.isArray(val)) {
8518
- return '[' + val.map(function(item) {
8519
- return stringify(item, depth + 1);
8520
- }).join(',') + ']';
8521
- }
8522
- keys = Object.keys(val).sort();
8523
- return '{' + keys.map(function(key) {
8524
- return JSON.stringify(key) + ':' + stringify(val[key], depth + 1);
8525
- }).join(',') + '}';
8526
- }
8527
- }
8528
-
8529
- function hashTypedArray(arr) {
8530
- var hash, view;
8531
- if (!arr) return 'null';
8532
- view = new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
8533
- hash = hashBytes(view);
8534
- return arr.constructor.name + ':' + arr.length + ':' + hash;
8535
- }
8536
-
8537
- function hashBytes(bytes) {
8538
- var hash = 2166136261;
8539
- for (var i=0, n=bytes.length; i<n; i++) {
8540
- hash ^= bytes[i];
8541
- hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
8542
- }
8543
- return (hash >>> 0).toString(16);
8544
- }
8545
-
8546
- function hashString$1(str) {
8547
- var hash = 2166136261;
8548
- for (var i=0, n=str.length; i<n; i++) {
8549
- hash ^= str.charCodeAt(i);
8550
- hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
8551
- }
8552
- return (hash >>> 0).toString(16);
8553
- }
8554
-
8555
- function typedBytes(arr) {
8556
- return arr ? arr.byteLength : 0;
8557
- }
8558
-
8559
- function estimateStringBytes(str) {
8560
- return str.length * 2;
8561
- }
8562
-
8563
- function formatBytes$1(bytes) {
8564
- if (bytes > 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + 'MB';
8565
- if (bytes > 1024) return Math.round(bytes / 1024) + 'KB';
8566
- return bytes + 'B';
8567
- }
8568
-
8569
7929
  function Console(gui) {
8570
7930
  var model = gui.model;
8571
7931
  var CURSOR = '$ ';
@@ -8595,9 +7955,6 @@
8595
7955
  });
8596
7956
  var globals = {}; // share user-defined globals (job.defs) between runs
8597
7957
  var sharedVars = {}; // share -vars / -defaults templating scope between runs
8598
- var undoFeasibility = createUndoFeasibilityMonitor(gui);
8599
- var storedUndoHistory = createStoredUndoHistory(gui);
8600
- gui.undoFeasibility = undoFeasibility;
8601
7958
 
8602
7959
  // expose this function, so other components can run commands (e.g. box tool)
8603
7960
  this.runMapshaperCommands = runMapshaperCommands;
@@ -8999,7 +8356,6 @@
8999
8356
  prevTable = active?.layer.data,
9000
8357
  prevTableSize = prevTable ? prevTable.size() : 0,
9001
8358
  prevArcCount = prevArcs ? prevArcs.size() : 0,
9002
- undoCapture = undoFeasibility.beforeCommand(commands, commandString),
9003
8359
  undoTransaction = createCommandUndoTransaction(commandString),
9004
8360
  job = new internal.Job(model),
9005
8361
  commandStart = Date.now();
@@ -9048,7 +8404,6 @@
9048
8404
  // signal the map to update even if an error has occured, because the
9049
8405
  // commands may have partially succeeded and changes may have occured to
9050
8406
  // the data.
9051
- undoFeasibility.afterCommand(undoCapture, {error: err, flags: flags});
9052
8407
  if (!err) {
9053
8408
  commandString = internal.standardizeConsoleCommands(commandString);
9054
8409
  historyIds.push(gui.session.consoleCommands(commandString));
@@ -9074,7 +8429,7 @@
9074
8429
  function createCommandUndoTransaction(commandString) {
9075
8430
  var Transaction;
9076
8431
  if (!isCommandUndoEnabled()) return null;
9077
- storedUndoHistory.getPayloadStore();
8432
+ getStoredUndoHistory(gui).getPayloadStore();
9078
8433
  Transaction = internal.UndoTransaction.UndoTransaction || internal.UndoTransaction;
9079
8434
  return new Transaction(commandString);
9080
8435
  }
@@ -9098,7 +8453,7 @@
9098
8453
  }
9099
8454
 
9100
8455
  async function addCommandUndoHistory(tx, err, flags, historyIds) {
9101
- return storedUndoHistory.addTransaction(tx, {
8456
+ return getStoredUndoHistory(gui).addTransaction(tx, {
9102
8457
  error: err,
9103
8458
  flags: flags,
9104
8459
  entryPrefix: 'command',
@@ -9113,15 +8468,8 @@
9113
8468
  }
9114
8469
 
9115
8470
  function isCommandUndoEnabled() {
9116
- var opt = gui.options && (gui.options.undoCommands || gui.options.appUndo);
9117
- var query = getQueryValue('undo');
9118
8471
  if (!gui.undo || typeof gui.undo.addHistoryState != 'function') return false;
9119
- if (opt === true || query == 'on' || query == 'commands') return true;
9120
- try {
9121
- return window.localStorage && window.localStorage.getItem('mapshaper.undo') == 'on';
9122
- } catch(e) {
9123
- return false;
9124
- }
8472
+ return appUndoIsEnabled(gui);
9125
8473
  }
9126
8474
 
9127
8475
  function getCommandUndoHistoryLimit() {
@@ -9130,8 +8478,8 @@
9130
8478
  }
9131
8479
 
9132
8480
  function logCommandTiming(commandString, commands, err, totalMillis, undoTiming) {
9133
- var enabled = getQueryValue('command-timing') == 'on' ||
9134
- getQueryValue('undo-timing') == 'on';
8481
+ var enabled = getQueryFlag('command-timing') == 'on' ||
8482
+ getQueryFlag('undo-timing') == 'on';
9135
8483
  var undoMillis = undoTiming && undoTiming.undoMillis || 0;
9136
8484
  if (!enabled || typeof console == 'undefined' || !console.log) return;
9137
8485
  console.log('[mapshaper command timing]', {
@@ -9147,7 +8495,7 @@
9147
8495
  });
9148
8496
  }
9149
8497
 
9150
- function getQueryValue(key) {
8498
+ function getQueryFlag(key) {
9151
8499
  var rxp, match;
9152
8500
  if (typeof window == 'undefined' || !window.location) return null;
9153
8501
  rxp = new RegExp('[?&]' + key + '=([^&]+)');
@@ -10264,8 +9612,9 @@
10264
9612
 
10265
9613
  function deleteLayer() {
10266
9614
  var target = findLayerById(id);
10267
- var undoTransaction = createDeleteLayerUndoTransaction(target);
9615
+ var undoTransaction;
10268
9616
  if (!target) return;
9617
+ undoTransaction = createUndoTransaction(gui, 'delete layer');
10269
9618
  if (map.isVisibleLayer(target.layer)) {
10270
9619
  // TODO: check for double map refresh after model.deleteLayer() below
10271
9620
  setLayerPinning(target.layer, false);
@@ -10274,7 +9623,10 @@
10274
9623
  undoTransaction.run(function() {
10275
9624
  model.deleteLayer(target.layer, target.dataset);
10276
9625
  });
10277
- addDeleteLayerUndoHistory(undoTransaction);
9626
+ addUndoTransactionToHistory(gui, undoTransaction, {
9627
+ flags: {select: true, arc_count: true},
9628
+ entryPrefix: 'delete-layer'
9629
+ });
10278
9630
  } else {
10279
9631
  model.deleteLayer(target.layer, target.dataset);
10280
9632
  }
@@ -10375,41 +9727,18 @@
10375
9727
  return str;
10376
9728
  }
10377
9729
 
10378
- function createDeleteLayerUndoTransaction(target) {
10379
- return createLayerMenuUndoTransaction(target, 'delete layer');
10380
- }
10381
-
10382
- function createLayerRenameUndoTransaction(target) {
10383
- return createLayerMenuUndoTransaction(target, 'rename layer');
10384
- }
10385
-
10386
- function createLayerMenuUndoTransaction(target, label) {
10387
- var Transaction;
10388
- if (!target || !appUndoIsEnabled()) return null;
10389
- if (!gui.undo || typeof gui.undo.addHistoryState != 'function') return null;
10390
- Transaction = internal.UndoTransaction && (internal.UndoTransaction.UndoTransaction || internal.UndoTransaction);
10391
- return Transaction ? new Transaction(label) : null;
10392
- }
10393
-
10394
- function addDeleteLayerUndoHistory(tx) {
10395
- getStoredUndoHistory().addTransaction(tx, {
10396
- flags: {select: true, arc_count: true},
10397
- entryPrefix: 'delete-layer',
10398
- maxStates: getUndoHistoryLimit()
10399
- }).catch(function(e) {
10400
- console.error(e);
10401
- });
10402
- }
10403
-
10404
9730
  function renameLayer(target, name) {
10405
9731
  var undoTransaction;
10406
9732
  if (!target || target.layer.name == name) return;
10407
- undoTransaction = createLayerRenameUndoTransaction(target);
9733
+ undoTransaction = createUndoTransaction(gui, 'rename layer');
10408
9734
  if (undoTransaction) {
10409
9735
  undoTransaction.captureLayerMetadataBefore(target.layer, {operation: 'renameLayer', unit: 'name'});
10410
9736
  target.layer.name = name;
10411
9737
  markLayerChanged(target.layer, {operation: 'renameLayer', unit: 'name'});
10412
- addLayerRenameUndoHistory(undoTransaction);
9738
+ addUndoTransactionToHistory(gui, undoTransaction, {
9739
+ flags: {select: true},
9740
+ entryPrefix: 'rename-layer'
9741
+ });
10413
9742
  } else {
10414
9743
  target.layer.name = name;
10415
9744
  }
@@ -10417,54 +9746,12 @@
10417
9746
  updateMenuBtn();
10418
9747
  }
10419
9748
 
10420
- function addLayerRenameUndoHistory(tx) {
10421
- getStoredUndoHistory().addTransaction(tx, {
10422
- flags: {select: true},
10423
- entryPrefix: 'rename-layer',
10424
- maxStates: getUndoHistoryLimit()
10425
- }).catch(function(e) {
10426
- console.error(e);
10427
- });
10428
- }
10429
-
10430
9749
  function markLayerChanged(layer, detail) {
10431
9750
  if (internal.UndoTracking && internal.UndoTracking.markLayerChanged) {
10432
9751
  internal.UndoTracking.markLayerChanged(layer, detail);
10433
9752
  }
10434
9753
  }
10435
9754
 
10436
- function getStoredUndoHistory() {
10437
- if (!gui.storedUndoHistory) {
10438
- gui.storedUndoHistory = createStoredUndoHistory(gui);
10439
- }
10440
- return gui.storedUndoHistory;
10441
- }
10442
-
10443
- function getUndoHistoryLimit() {
10444
- var opt = gui.options && gui.options.undoHistoryLimit;
10445
- return opt > 0 ? opt : 10;
10446
- }
10447
-
10448
- function appUndoIsEnabled() {
10449
- var opt = gui.options && (gui.options.undoCommands || gui.options.appUndo);
10450
- var query = getQueryValue('undo');
10451
- if (opt === true || query == 'on' || query == 'commands') return true;
10452
- if (gui.appUndoIsEnabled) return gui.appUndoIsEnabled();
10453
- try {
10454
- return window.localStorage && window.localStorage.getItem('mapshaper.undo') == 'on';
10455
- } catch(e) {
10456
- return false;
10457
- }
10458
- }
10459
-
10460
- function getQueryValue(key) {
10461
- var rxp, match;
10462
- if (typeof window == 'undefined' || !window.location) return null;
10463
- rxp = new RegExp('[?&]' + key + '=([^&]+)');
10464
- match = rxp.exec(window.location.search);
10465
- return match ? decodeURIComponent(match[1]) : null;
10466
- }
10467
-
10468
9755
  function getWarnings(lyr, dataset) {
10469
9756
  var file = internal.getLayerSourceFile(lyr, dataset);
10470
9757
  var missing = [];
@@ -10674,19 +9961,6 @@
10674
9961
  el.attr('aria-disabled', enabled ? 'false' : 'true');
10675
9962
  }
10676
9963
 
10677
- function appUndoForcedByUrl() {
10678
- var query = getQueryValue$1('undo');
10679
- return query == 'on' || query == 'commands';
10680
- }
10681
-
10682
- function appUndoSettingIsOn() {
10683
- try {
10684
- return window.localStorage && window.localStorage.getItem(APP_UNDO_KEY) == 'on';
10685
- } catch(e) {
10686
- return false;
10687
- }
10688
- }
10689
-
10690
9964
  function setAppUndoEnabled(enabled) {
10691
9965
  try {
10692
9966
  if (window.localStorage) {
@@ -10698,9 +9972,6 @@
10698
9972
  function getRestoreDataNote(gui) {
10699
9973
  var stats = getUndoPayloadStats(gui);
10700
9974
  var bytes = stats ? stats.ownBytes || 0 : 0;
10701
- if (bytes === 0) {
10702
- return 'estimated on-disk restore data: none';
10703
- }
10704
9975
  return 'estimated on-disk restore data: ' + formatBytes(bytes);
10705
9976
  }
10706
9977
 
@@ -10710,22 +9981,14 @@
10710
9981
  }
10711
9982
 
10712
9983
  function formatBytes(bytes) {
10713
- var units = ['B', 'KB', 'MB', 'GB'];
10714
- var value = bytes;
9984
+ var units = ['KB', 'MB', 'GB'];
9985
+ var value = bytes / 1000;
10715
9986
  var i = 0;
10716
9987
  while (value >= 1000 && i < units.length - 1) {
10717
9988
  value /= 1000;
10718
9989
  i++;
10719
9990
  }
10720
- return (i === 0 ? String(value) : value.toFixed(value < 10 ? 1 : 0)) + ' ' + units[i];
10721
- }
10722
-
10723
- function getQueryValue$1(key) {
10724
- var rxp, match;
10725
- if (typeof window == 'undefined' || !window.location) return null;
10726
- rxp = new RegExp('[?&]' + key + '=([^&]+)');
10727
- match = rxp.exec(window.location.search);
10728
- return match ? decodeURIComponent(match[1]) : null;
9991
+ return value.toFixed(value < 10 && value >= 0.5 ? 1 : 0) + ' ' + units[i];
10729
9992
  }
10730
9993
 
10731
9994
  function SessionHistory(gui) {
@@ -10955,8 +10218,7 @@
10955
10218
  }
10956
10219
 
10957
10220
  function Undo(gui) {
10958
- var history, offset, stashedUndo, storedUndoHistory, editSession;
10959
- storedUndoHistory = createStoredUndoHistory(gui);
10221
+ var history, offset, stashedUndo, editSession;
10960
10222
  editSession = createEditSessionUndo();
10961
10223
  reset();
10962
10224
 
@@ -11318,7 +10580,7 @@
11318
10580
  function start(nextMode) {
11319
10581
  var target, Transaction;
11320
10582
  if (!isEditSessionMode(nextMode)) return;
11321
- if (!appUndoIsEnabled()) return;
10583
+ if (!appUndoIsEnabled(gui)) return;
11322
10584
  target = gui.model.getActiveLayer();
11323
10585
  if (!target || !target.layer) return;
11324
10586
  Transaction = getUndoTransactionConstructor();
@@ -11337,7 +10599,7 @@
11337
10599
  }
11338
10600
  resetSession();
11339
10601
  if (!wasChanged) return;
11340
- storedUndoHistory.addTransaction(finishedTx, {
10602
+ getStoredUndoHistory(gui).addTransaction(finishedTx, {
11341
10603
  flags: {select: true},
11342
10604
  entryPrefix: 'edit-session',
11343
10605
  maxStates: getEditSessionUndoHistoryLimit()
@@ -11392,26 +10654,6 @@
11392
10654
  return opt > 0 ? opt : 10;
11393
10655
  }
11394
10656
 
11395
- function appUndoIsEnabled() {
11396
- var opt = gui.options && (gui.options.undoCommands || gui.options.appUndo);
11397
- var query = getQueryValue('undo');
11398
- if (opt === true || query == 'on' || query == 'commands') return true;
11399
- if (gui.appUndoIsEnabled) return gui.appUndoIsEnabled();
11400
- try {
11401
- return window.localStorage && window.localStorage.getItem('mapshaper.undo') == 'on';
11402
- } catch(e) {
11403
- return false;
11404
- }
11405
- }
11406
-
11407
- function getQueryValue(key) {
11408
- var rxp, match;
11409
- if (typeof window == 'undefined' || !window.location) return null;
11410
- rxp = new RegExp('[?&]' + key + '=([^&]+)');
11411
- match = rxp.exec(window.location.search);
11412
- return match ? decodeURIComponent(match[1]) : null;
11413
- }
11414
-
11415
10657
  }
11416
10658
 
11417
10659
  function SidebarButtons(gui) {