mapshaper 0.7.10 → 0.7.12

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) {
@@ -6731,13 +6726,11 @@
6731
6726
 
6732
6727
  function message() {
6733
6728
  var msg = GUI.formatMessageArgs(arguments);
6734
- if (gui.notify) {
6735
- gui.notify({severity: 'info', body: msg});
6736
- } else {
6729
+ if (!gui.notify) {
6737
6730
  // Fallback for early messages before MessageControl is constructed
6738
6731
  gui.message(msg);
6739
- internal.logArgs(arguments);
6740
6732
  }
6733
+ internal.logArgs(arguments);
6741
6734
  }
6742
6735
 
6743
6736
  // CLI warnings used to surface as modal alerts, which interrupt the user
@@ -7789,8 +7782,8 @@
7789
7782
 
7790
7783
  function startSimplifyUndoSession(dataset) {
7791
7784
  var tx;
7792
- if (!dataset || !dataset.arcs || !appUndoIsEnabled()) return;
7793
- tx = createSimplifyUndoTransaction();
7785
+ if (!dataset || !dataset.arcs || !appUndoIsEnabled(gui)) return;
7786
+ tx = createUndoTransaction(gui, 'simplify');
7794
7787
  if (!tx) return;
7795
7788
  tx.captureArcsSimplificationBefore(dataset.arcs, {operation: 'simplifyTool'});
7796
7789
  tx.captureDatasetInfoBefore(dataset, {operation: 'simplifyTool'});
@@ -7808,54 +7801,12 @@
7808
7801
  var session = undoSession;
7809
7802
  undoSession = null;
7810
7803
  if (!session || !session.changed) return;
7811
- getStoredUndoHistory().addTransaction(session.tx, {
7804
+ addUndoTransactionToHistory(gui, session.tx, {
7812
7805
  flags: {simplify: true, info: true},
7813
- entryPrefix: 'simplify-tool',
7814
- maxStates: getUndoHistoryLimit()
7815
- }).catch(function(e) {
7816
- console.error(e);
7806
+ entryPrefix: 'simplify-tool'
7817
7807
  });
7818
7808
  }
7819
7809
 
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
7810
  function updateSliderDisplay() {
7860
7811
  // TODO: display resolution and vertex count
7861
7812
  // var dataset = model.getActiveLayer().dataset;
@@ -7973,599 +7924,6 @@
7973
7924
  return internal.formatOptionValue(internal.getLayerTargetId(gui.model, lyr));
7974
7925
  }
7975
7926
 
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
7927
  function Console(gui) {
8570
7928
  var model = gui.model;
8571
7929
  var CURSOR = '$ ';
@@ -8595,9 +7953,6 @@
8595
7953
  });
8596
7954
  var globals = {}; // share user-defined globals (job.defs) between runs
8597
7955
  var sharedVars = {}; // share -vars / -defaults templating scope between runs
8598
- var undoFeasibility = createUndoFeasibilityMonitor(gui);
8599
- var storedUndoHistory = createStoredUndoHistory(gui);
8600
- gui.undoFeasibility = undoFeasibility;
8601
7956
 
8602
7957
  // expose this function, so other components can run commands (e.g. box tool)
8603
7958
  this.runMapshaperCommands = runMapshaperCommands;
@@ -8999,7 +8354,6 @@
8999
8354
  prevTable = active?.layer.data,
9000
8355
  prevTableSize = prevTable ? prevTable.size() : 0,
9001
8356
  prevArcCount = prevArcs ? prevArcs.size() : 0,
9002
- undoCapture = undoFeasibility.beforeCommand(commands, commandString),
9003
8357
  undoTransaction = createCommandUndoTransaction(commandString),
9004
8358
  job = new internal.Job(model),
9005
8359
  commandStart = Date.now();
@@ -9048,7 +8402,6 @@
9048
8402
  // signal the map to update even if an error has occured, because the
9049
8403
  // commands may have partially succeeded and changes may have occured to
9050
8404
  // the data.
9051
- undoFeasibility.afterCommand(undoCapture, {error: err, flags: flags});
9052
8405
  if (!err) {
9053
8406
  commandString = internal.standardizeConsoleCommands(commandString);
9054
8407
  historyIds.push(gui.session.consoleCommands(commandString));
@@ -9074,7 +8427,7 @@
9074
8427
  function createCommandUndoTransaction(commandString) {
9075
8428
  var Transaction;
9076
8429
  if (!isCommandUndoEnabled()) return null;
9077
- storedUndoHistory.getPayloadStore();
8430
+ getStoredUndoHistory(gui).getPayloadStore();
9078
8431
  Transaction = internal.UndoTransaction.UndoTransaction || internal.UndoTransaction;
9079
8432
  return new Transaction(commandString);
9080
8433
  }
@@ -9098,7 +8451,7 @@
9098
8451
  }
9099
8452
 
9100
8453
  async function addCommandUndoHistory(tx, err, flags, historyIds) {
9101
- return storedUndoHistory.addTransaction(tx, {
8454
+ return getStoredUndoHistory(gui).addTransaction(tx, {
9102
8455
  error: err,
9103
8456
  flags: flags,
9104
8457
  entryPrefix: 'command',
@@ -9113,15 +8466,8 @@
9113
8466
  }
9114
8467
 
9115
8468
  function isCommandUndoEnabled() {
9116
- var opt = gui.options && (gui.options.undoCommands || gui.options.appUndo);
9117
- var query = getQueryValue('undo');
9118
8469
  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
- }
8470
+ return appUndoIsEnabled(gui);
9125
8471
  }
9126
8472
 
9127
8473
  function getCommandUndoHistoryLimit() {
@@ -9130,8 +8476,8 @@
9130
8476
  }
9131
8477
 
9132
8478
  function logCommandTiming(commandString, commands, err, totalMillis, undoTiming) {
9133
- var enabled = getQueryValue('command-timing') == 'on' ||
9134
- getQueryValue('undo-timing') == 'on';
8479
+ var enabled = getQueryFlag('command-timing') == 'on' ||
8480
+ getQueryFlag('undo-timing') == 'on';
9135
8481
  var undoMillis = undoTiming && undoTiming.undoMillis || 0;
9136
8482
  if (!enabled || typeof console == 'undefined' || !console.log) return;
9137
8483
  console.log('[mapshaper command timing]', {
@@ -9147,7 +8493,7 @@
9147
8493
  });
9148
8494
  }
9149
8495
 
9150
- function getQueryValue(key) {
8496
+ function getQueryFlag(key) {
9151
8497
  var rxp, match;
9152
8498
  if (typeof window == 'undefined' || !window.location) return null;
9153
8499
  rxp = new RegExp('[?&]' + key + '=([^&]+)');
@@ -10264,8 +9610,9 @@
10264
9610
 
10265
9611
  function deleteLayer() {
10266
9612
  var target = findLayerById(id);
10267
- var undoTransaction = createDeleteLayerUndoTransaction(target);
9613
+ var undoTransaction;
10268
9614
  if (!target) return;
9615
+ undoTransaction = createUndoTransaction(gui, 'delete layer');
10269
9616
  if (map.isVisibleLayer(target.layer)) {
10270
9617
  // TODO: check for double map refresh after model.deleteLayer() below
10271
9618
  setLayerPinning(target.layer, false);
@@ -10274,7 +9621,10 @@
10274
9621
  undoTransaction.run(function() {
10275
9622
  model.deleteLayer(target.layer, target.dataset);
10276
9623
  });
10277
- addDeleteLayerUndoHistory(undoTransaction);
9624
+ addUndoTransactionToHistory(gui, undoTransaction, {
9625
+ flags: {select: true, arc_count: true},
9626
+ entryPrefix: 'delete-layer'
9627
+ });
10278
9628
  } else {
10279
9629
  model.deleteLayer(target.layer, target.dataset);
10280
9630
  }
@@ -10375,41 +9725,18 @@
10375
9725
  return str;
10376
9726
  }
10377
9727
 
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
9728
  function renameLayer(target, name) {
10405
9729
  var undoTransaction;
10406
9730
  if (!target || target.layer.name == name) return;
10407
- undoTransaction = createLayerRenameUndoTransaction(target);
9731
+ undoTransaction = createUndoTransaction(gui, 'rename layer');
10408
9732
  if (undoTransaction) {
10409
9733
  undoTransaction.captureLayerMetadataBefore(target.layer, {operation: 'renameLayer', unit: 'name'});
10410
9734
  target.layer.name = name;
10411
9735
  markLayerChanged(target.layer, {operation: 'renameLayer', unit: 'name'});
10412
- addLayerRenameUndoHistory(undoTransaction);
9736
+ addUndoTransactionToHistory(gui, undoTransaction, {
9737
+ flags: {select: true},
9738
+ entryPrefix: 'rename-layer'
9739
+ });
10413
9740
  } else {
10414
9741
  target.layer.name = name;
10415
9742
  }
@@ -10417,54 +9744,12 @@
10417
9744
  updateMenuBtn();
10418
9745
  }
10419
9746
 
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
9747
  function markLayerChanged(layer, detail) {
10431
9748
  if (internal.UndoTracking && internal.UndoTracking.markLayerChanged) {
10432
9749
  internal.UndoTracking.markLayerChanged(layer, detail);
10433
9750
  }
10434
9751
  }
10435
9752
 
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
9753
  function getWarnings(lyr, dataset) {
10469
9754
  var file = internal.getLayerSourceFile(lyr, dataset);
10470
9755
  var missing = [];
@@ -10674,19 +9959,6 @@
10674
9959
  el.attr('aria-disabled', enabled ? 'false' : 'true');
10675
9960
  }
10676
9961
 
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
9962
  function setAppUndoEnabled(enabled) {
10691
9963
  try {
10692
9964
  if (window.localStorage) {
@@ -10698,9 +9970,6 @@
10698
9970
  function getRestoreDataNote(gui) {
10699
9971
  var stats = getUndoPayloadStats(gui);
10700
9972
  var bytes = stats ? stats.ownBytes || 0 : 0;
10701
- if (bytes === 0) {
10702
- return 'estimated on-disk restore data: none';
10703
- }
10704
9973
  return 'estimated on-disk restore data: ' + formatBytes(bytes);
10705
9974
  }
10706
9975
 
@@ -10710,22 +9979,14 @@
10710
9979
  }
10711
9980
 
10712
9981
  function formatBytes(bytes) {
10713
- var units = ['B', 'KB', 'MB', 'GB'];
10714
- var value = bytes;
9982
+ var units = ['KB', 'MB', 'GB'];
9983
+ var value = bytes / 1000;
10715
9984
  var i = 0;
10716
9985
  while (value >= 1000 && i < units.length - 1) {
10717
9986
  value /= 1000;
10718
9987
  i++;
10719
9988
  }
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;
9989
+ return value.toFixed(value < 10 && value >= 0.5 ? 1 : 0) + ' ' + units[i];
10729
9990
  }
10730
9991
 
10731
9992
  function SessionHistory(gui) {
@@ -10955,8 +10216,7 @@
10955
10216
  }
10956
10217
 
10957
10218
  function Undo(gui) {
10958
- var history, offset, stashedUndo, storedUndoHistory, editSession;
10959
- storedUndoHistory = createStoredUndoHistory(gui);
10219
+ var history, offset, stashedUndo, editSession;
10960
10220
  editSession = createEditSessionUndo();
10961
10221
  reset();
10962
10222
 
@@ -11318,7 +10578,7 @@
11318
10578
  function start(nextMode) {
11319
10579
  var target, Transaction;
11320
10580
  if (!isEditSessionMode(nextMode)) return;
11321
- if (!appUndoIsEnabled()) return;
10581
+ if (!appUndoIsEnabled(gui)) return;
11322
10582
  target = gui.model.getActiveLayer();
11323
10583
  if (!target || !target.layer) return;
11324
10584
  Transaction = getUndoTransactionConstructor();
@@ -11337,7 +10597,7 @@
11337
10597
  }
11338
10598
  resetSession();
11339
10599
  if (!wasChanged) return;
11340
- storedUndoHistory.addTransaction(finishedTx, {
10600
+ getStoredUndoHistory(gui).addTransaction(finishedTx, {
11341
10601
  flags: {select: true},
11342
10602
  entryPrefix: 'edit-session',
11343
10603
  maxStates: getEditSessionUndoHistoryLimit()
@@ -11392,26 +10652,6 @@
11392
10652
  return opt > 0 ? opt : 10;
11393
10653
  }
11394
10654
 
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
10655
  }
11416
10656
 
11417
10657
  function SidebarButtons(gui) {