mapshaper 0.7.12 → 0.7.13

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.
@@ -6097,6 +6097,7 @@
6097
6097
  // gui.container.addClass('queued-files');
6098
6098
  El('#import-options').show();
6099
6099
  gui.container.classed('queued-files', queuedFiles.length > 0);
6100
+ updateSidebarTabZIndex();
6100
6101
  El('#path-import-options').classed('hidden', !filesMayContainPaths(queuedFiles));
6101
6102
  showQueuedFiles();
6102
6103
  updateGeoPackageLayerSelectionMenu();
@@ -6104,9 +6105,15 @@
6104
6105
 
6105
6106
  function hideImportMenu() {
6106
6107
  // gui.container.removeClass('queued-files');
6108
+ gui.container.removeClass('sidebar-tabs-over-popup');
6107
6109
  El('#import-options').hide();
6108
6110
  }
6109
6111
 
6112
+ function updateSidebarTabZIndex() {
6113
+ gui.container.classed('sidebar-tabs-over-popup',
6114
+ queuedFiles.length === 0 && !gui.sidebarPanelIsOpen());
6115
+ }
6116
+
6110
6117
  function getFileNames(files) {
6111
6118
  return Array.from(files).map(function(f) {return f.name;});
6112
6119
  }
@@ -7927,7 +7934,7 @@
7927
7934
  function Console(gui) {
7928
7935
  var model = gui.model;
7929
7936
  var CURSOR = '$ ';
7930
- var PROMPT = 'Enter mapshaper commands or type "tips" for examples and console help';
7937
+ var PROMPT = 'Enter mapshaper commands or type "tips" for console help.';
7931
7938
  var el = gui.container.findChild('.console').hide();
7932
7939
  var content = el.findChild('.console-buffer');
7933
7940
  var log = El('div').appendTo(content);
@@ -7948,6 +7955,7 @@
7948
7955
  .on('keydown', function(e) {
7949
7956
  if (e.key == 'Enter' || e.key == ' ') {
7950
7957
  e.preventDefault();
7958
+ e.stopPropagation();
7951
7959
  toggle();
7952
7960
  }
7953
7961
  });
@@ -7963,7 +7971,7 @@
7963
7971
  this.runCommand = function(str) {
7964
7972
  str = str.trim();
7965
7973
  if (!str) return;
7966
- turnOn();
7974
+ gui.setSidebarPanel('console');
7967
7975
  submit(str);
7968
7976
  };
7969
7977
 
@@ -7981,10 +7989,17 @@
7981
7989
  });
7982
7990
 
7983
7991
  function toggle() {
7984
- if (_isOpen) turnOff();
7985
- else turnOn();
7992
+ gui.toggleSidebarPanel('console');
7986
7993
  }
7987
7994
 
7995
+ gui.on('sidebar', function(e) {
7996
+ if (e.name == 'console') {
7997
+ turnOn();
7998
+ } else if (e.prev == 'console') {
7999
+ turnOff();
8000
+ }
8001
+ });
8002
+
7988
8003
  function getHistory() {
7989
8004
  return GUI.getSavedValue('console_history') || [];
7990
8005
  }
@@ -8004,10 +8019,30 @@
8004
8019
  scrollDown();
8005
8020
  }
8006
8021
 
8022
+ function toLogNode(node, cname) {
8023
+ var msg = El('div').appendTo(log);
8024
+ if (cname) {
8025
+ msg.addClass(cname);
8026
+ }
8027
+ msg.node().appendChild(node);
8028
+ scrollDown();
8029
+ }
8030
+
8031
+ function getStructuredConsoleMessage(args) {
8032
+ var arr = utils$1.toArray(args);
8033
+ var msg;
8034
+ // print() sends its arguments as one array argument.
8035
+ if (arr.length == 1 && Array.isArray(arr[0])) {
8036
+ arr = arr[0];
8037
+ }
8038
+ msg = arr[arr.length - 1];
8039
+ return msg && msg.type && /^mapshaper-console-/.test(msg.type) ? msg : null;
8040
+ }
8041
+
8007
8042
  function turnOn() {
8008
8043
  // if (!_isOpen && !model.isEmpty()) {
8009
8044
  if (!_isOpen) {
8010
- btn.addClass('active');
8045
+ btn.addClass('active').attr('aria-expanded', 'true');
8011
8046
  _isOpen = true;
8012
8047
  // Route logging output to the in-app console while it's open, so a
8013
8048
  // user typing CLI commands here sees the results inline -- the same
@@ -8019,9 +8054,7 @@
8019
8054
  // gui instances with the console open. E.g. console could close
8020
8055
  // when an instance loses focus.
8021
8056
  internal.setLoggingFunctions(consoleMessage, consoleError, consoleStop, consoleWarn);
8022
- gui.container.addClass('console-open');
8023
8057
  el.show();
8024
- gui.dispatchEvent('resize');
8025
8058
  input.node().focus();
8026
8059
  history = getHistory();
8027
8060
  }
@@ -8029,7 +8062,7 @@
8029
8062
 
8030
8063
  function turnOff() {
8031
8064
  if (_isOpen) {
8032
- btn.removeClass('active');
8065
+ btn.removeClass('active').attr('aria-expanded', 'false');
8033
8066
  _isOpen = false;
8034
8067
  if (GUI.isActiveInstance(gui)) {
8035
8068
  setLoggingForGUI(gui); // reset stop, message and error functions
@@ -8037,8 +8070,6 @@
8037
8070
  el.hide();
8038
8071
  input.node().blur();
8039
8072
  saveHistory();
8040
- gui.container.removeClass('console-open');
8041
- gui.dispatchEvent('resize');
8042
8073
  }
8043
8074
  }
8044
8075
 
@@ -8098,7 +8129,7 @@
8098
8129
  if (gui.getMode()) {
8099
8130
  gui.clearMode(); // esc closes any open panels
8100
8131
  } else {
8101
- turnOff();
8132
+ gui.setSidebarPanel(null);
8102
8133
  }
8103
8134
  capture = true;
8104
8135
 
@@ -8134,8 +8165,8 @@
8134
8165
  } else if (kc == 40) {
8135
8166
  forward();
8136
8167
  } else if (kc == 32 && (!typing || (inputText === '' && typingInConsole))) {
8137
- // space bar closes if nothing has been typed
8138
- turnOff();
8168
+ // space bar toggles the sidebar if nothing has been typed
8169
+ gui.toggleSidebar();
8139
8170
  } else if (!typing && e.target != input.node() && !metaKey(e)) {
8140
8171
  // typing returns focus, unless a meta key is down (to allow Cmd-C copy)
8141
8172
  // or user is typing in a different input area somewhere
@@ -8152,9 +8183,9 @@
8152
8183
 
8153
8184
  // various shortcuts (while not typing in an input field or editable el)
8154
8185
  } else if (!typing) {
8155
- if (kc == 32) { // space bar opens console
8186
+ if (kc == 32) { // space bar toggles the sidebar
8156
8187
  capture = true;
8157
- turnOn();
8188
+ gui.toggleSidebar();
8158
8189
  // } else if (kc == 73) { // letter i opens inspector
8159
8190
  // gui.dispatchEvent('interaction_toggle');
8160
8191
  } else if (kc == 72) { // letter h resets map extent
@@ -8535,9 +8566,15 @@
8535
8566
  }
8536
8567
 
8537
8568
  function consoleMessage() {
8538
- var msg = GUI.formatMessageArgs(arguments);
8569
+ var structured = getStructuredConsoleMessage(arguments);
8570
+ var msg;
8539
8571
  if (internal.loggingEnabled()) {
8540
- toLog(msg, 'console-message');
8572
+ if (structured) {
8573
+ toLogNode(renderStructuredConsoleMessage(structured), 'console-message');
8574
+ } else {
8575
+ msg = GUI.formatMessageArgs(arguments);
8576
+ toLog(msg, 'console-message');
8577
+ }
8541
8578
  }
8542
8579
  }
8543
8580
 
@@ -8562,6 +8599,137 @@
8562
8599
  printExample("Clear the console", "$ clear");
8563
8600
  }
8564
8601
 
8602
+ function renderStructuredConsoleMessage(msg) {
8603
+ if (msg.type == 'mapshaper-console-help') {
8604
+ return renderHelpMessage(msg.lines);
8605
+ }
8606
+ if (msg.type == 'mapshaper-console-info') {
8607
+ return renderInfoMessage(msg.layers);
8608
+ }
8609
+ return document.createTextNode('');
8610
+ }
8611
+
8612
+ function renderHelpMessage(lines) {
8613
+ var container = document.createElement('div');
8614
+ var rows = [];
8615
+ container.className = 'console-help';
8616
+ (lines || []).forEach(function(line) {
8617
+ if (Array.isArray(line)) {
8618
+ rows.push(line);
8619
+ } else {
8620
+ flushRows();
8621
+ appendHelpLine(container, line);
8622
+ }
8623
+ });
8624
+ flushRows();
8625
+ return container;
8626
+
8627
+ function flushRows() {
8628
+ if (rows.length > 0) {
8629
+ container.appendChild(renderKeyValueTable(rows, 'console-help-table'));
8630
+ rows = [];
8631
+ }
8632
+ }
8633
+ }
8634
+
8635
+ function appendHelpLine(container, line) {
8636
+ var div = document.createElement('div');
8637
+ div.className = line ? 'console-help-line' : 'console-help-spacer';
8638
+ div.textContent = line || '';
8639
+ container.appendChild(div);
8640
+ }
8641
+
8642
+ function renderInfoMessage(layers) {
8643
+ var container = document.createElement('div');
8644
+ container.className = 'console-info';
8645
+ (layers || []).forEach(function(info) {
8646
+ var section = document.createElement('div');
8647
+ var title = document.createElement('div');
8648
+ section.className = 'console-info-layer';
8649
+ title.className = 'console-info-title';
8650
+ title.textContent = 'Layer: ' + (info.layer_name || '[unnamed layer]');
8651
+ section.appendChild(title);
8652
+ section.appendChild(renderKeyValueTable(getInfoRows(info), 'console-info-table'));
8653
+ section.appendChild(renderAttributeInfoTable(info.attribute_data));
8654
+ container.appendChild(section);
8655
+ });
8656
+ return container;
8657
+ }
8658
+
8659
+ function getInfoRows(info) {
8660
+ var rows = [
8661
+ ['Type', info.geometry_type || 'tabular data'],
8662
+ ['Records', utils$1.format('%,d', info.feature_count)]
8663
+ ];
8664
+ if (info.null_shape_count > 0) {
8665
+ rows.push(['Nulls', utils$1.format("%'d", info.null_shape_count)]);
8666
+ }
8667
+ if (info.geometry_type && info.feature_count > info.null_shape_count) {
8668
+ rows.push(['Bounds', info.bbox.join(',')]);
8669
+ rows.push(['CRS', info.proj4]);
8670
+ }
8671
+ rows.push(['Source', info.source_file || 'n/a']);
8672
+ return rows;
8673
+ }
8674
+
8675
+ function renderAttributeInfoTable(fields) {
8676
+ var wrapper = document.createElement('div');
8677
+ var title = document.createElement('div');
8678
+ wrapper.className = 'console-attribute-info';
8679
+ title.className = 'console-info-subtitle';
8680
+ title.textContent = 'Attribute data';
8681
+ wrapper.appendChild(title);
8682
+ if (!fields) {
8683
+ var none = document.createElement('div');
8684
+ none.className = 'console-info-empty';
8685
+ none.textContent = '[none]';
8686
+ wrapper.appendChild(none);
8687
+ return wrapper;
8688
+ }
8689
+ wrapper.appendChild(renderDataTable(
8690
+ [['Field', 'First value']].concat(fields.map(function(o) {
8691
+ var valKey = 'first_value' in o ? 'first_value' : 'value';
8692
+ return [o.field, formatInfoValue(o[valKey])];
8693
+ })),
8694
+ 'console-attribute-table'
8695
+ ));
8696
+ return wrapper;
8697
+ }
8698
+
8699
+ function renderKeyValueTable(rows, className) {
8700
+ return renderDataTable(rows, className + ' console-key-value-table');
8701
+ }
8702
+
8703
+ function renderDataTable(rows, className) {
8704
+ var table = document.createElement('table');
8705
+ var tbody = document.createElement('tbody');
8706
+ table.className = className;
8707
+ rows.forEach(function(row, i) {
8708
+ var tr = document.createElement('tr');
8709
+ row.forEach(function(val) {
8710
+ var cell = document.createElement(i === 0 && rows.length > 1 && className == 'console-attribute-table' ? 'th' : 'td');
8711
+ cell.textContent = val == null ? '' : String(val);
8712
+ tr.appendChild(cell);
8713
+ });
8714
+ tbody.appendChild(tr);
8715
+ });
8716
+ table.appendChild(tbody);
8717
+ return table;
8718
+ }
8719
+
8720
+ function formatInfoValue(val) {
8721
+ if (val === null || val === undefined) return '';
8722
+ if (utils$1.isString(val)) {
8723
+ return "'" + val.replace(/[\r\t\n]/g, function(c) {
8724
+ return c == '\n' ? '\\n' : c == '\r' ? '\\r' : '\\t';
8725
+ }) + "'";
8726
+ }
8727
+ if (utils$1.isNumber(val) || val === true || val === false) {
8728
+ return String(val);
8729
+ }
8730
+ return JSON.stringify(val);
8731
+ }
8732
+
8565
8733
  function saveRuntimeContext() {
8566
8734
  var json = stringifyRuntimeStateContext(gui);
8567
8735
  saveBlobToLocalFile2('mapshaper-runtime-context.json', new Blob([json], {type: 'application/json'}));
@@ -9148,6 +9316,7 @@
9148
9316
  }
9149
9317
 
9150
9318
  var openMenu;
9319
+ var openMenuId;
9151
9320
 
9152
9321
  document.addEventListener('mousedown', function(e) {
9153
9322
  if (e.target.classList.contains('contextmenu-item')) {
@@ -9156,17 +9325,23 @@
9156
9325
  closeOpenMenu();
9157
9326
  });
9158
9327
 
9159
- function closeOpenMenu() {
9328
+ function closeOpenMenu(immediate) {
9160
9329
  if (openMenu) {
9161
- openMenu.close();
9330
+ openMenu.close(immediate);
9162
9331
  openMenu = null;
9332
+ openMenuId = null;
9163
9333
  }
9164
9334
  }
9165
9335
 
9166
9336
  function openContextMenu(e, lyr, parent) {
9167
9337
  var menu = new ContextMenu(parent);
9168
- closeOpenMenu();
9338
+ if (e.contextMenuId && e.contextMenuId == openMenuId) {
9339
+ closeOpenMenu(true);
9340
+ return;
9341
+ }
9342
+ closeOpenMenu(true);
9169
9343
  menu.open(e, lyr);
9344
+ openMenuId = e.contextMenuId || null;
9170
9345
  }
9171
9346
 
9172
9347
  function ContextMenu(parentArg) {
@@ -9183,9 +9358,14 @@
9183
9358
 
9184
9359
  this.close = close;
9185
9360
 
9186
- function close() {
9361
+ function close(immediate) {
9187
9362
  var count = _openCount;
9188
9363
  if (!_open) return;
9364
+ if (immediate) {
9365
+ menu.hide();
9366
+ _open = false;
9367
+ return;
9368
+ }
9189
9369
  setTimeout(function() {
9190
9370
  if (count == _openCount) {
9191
9371
  menu.hide();
@@ -9346,8 +9526,10 @@
9346
9526
  function LayerControl(gui) {
9347
9527
  var model = gui.model;
9348
9528
  var map = gui.map;
9349
- var el = gui.container.findChild(".layer-control").on('click', GUI.handleDirectEvent(gui.clearMode));
9529
+ var el = gui.container.findChild(".layer-control");
9350
9530
  var btn = gui.container.findChild('.layer-control-btn');
9531
+ var headerBtn = btn.findChild('.active-layer-label');
9532
+ var tab = gui.container.findChild('.layer-tab');
9351
9533
  var isOpen = false;
9352
9534
  var cache = new DomCache();
9353
9535
  var pinAll = el.findChild('.pin-all'); // button for toggling layer visibility
@@ -9357,7 +9539,34 @@
9357
9539
  var dragging = false;
9358
9540
  var layerOrderSlug;
9359
9541
 
9360
- gui.addMode('layer_menu', turnOn, turnOff, btn.findChild('.header-btn'));
9542
+ headerBtn.on('click', function() {
9543
+ toggle();
9544
+ }).on('keydown', function(e) {
9545
+ if (e.key == 'Enter' || e.key == ' ') {
9546
+ e.preventDefault();
9547
+ e.stopPropagation();
9548
+ toggle();
9549
+ }
9550
+ });
9551
+ tab.on('click', toggle).on('keydown', function(e) {
9552
+ if (e.key == 'Enter' || e.key == ' ') {
9553
+ e.preventDefault();
9554
+ e.stopPropagation();
9555
+ toggle();
9556
+ }
9557
+ });
9558
+
9559
+ function toggle() {
9560
+ gui.toggleSidebarPanel('layers');
9561
+ }
9562
+
9563
+ gui.on('sidebar', function(e) {
9564
+ if (e.name == 'layers') {
9565
+ turnOn();
9566
+ } else if (e.prev == 'layers') {
9567
+ turnOff();
9568
+ }
9569
+ });
9361
9570
 
9362
9571
  // kludge to show menu button after initial import dialog is dismissed
9363
9572
  gui.on('mode', function(e) {
@@ -9443,53 +9652,33 @@
9443
9652
  }
9444
9653
 
9445
9654
  function turnOn() {
9655
+ if (isOpen) return;
9446
9656
  isOpen = true;
9447
- el.findChild('div.info-box-scrolled').css('max-height', El('body').height() - 80);
9657
+ tab.addClass('active').attr('aria-expanded', 'true');
9448
9658
  render();
9449
9659
  el.show();
9450
9660
  }
9451
9661
 
9452
9662
  function turnOff() {
9663
+ if (!isOpen) return;
9453
9664
  stopDragging();
9454
9665
  isOpen = false;
9666
+ tab.removeClass('active').attr('aria-expanded', 'false');
9455
9667
  el.hide();
9456
9668
  }
9457
9669
 
9458
9670
  function updateMenuBtn() {
9459
9671
  var lyr = model.getActiveLayer()?.layer;
9460
9672
  var lyrName = lyr?.name || '';
9461
- var menuTitle = lyrName || lyr && '[unnamed layer]' || '[no data]';
9462
9673
  var pageTitle = lyrName || 'mapshaper';
9463
- btn.classed('active', 'true').findChild('.layer-name').html(menuTitle + "  ▼");
9674
+ btn.classed('active', !!lyr);
9675
+ headerBtn.text(lyr ? 'Active: ' + formatLayerNameForDisplay(lyr.name) : '');
9464
9676
  window.document.title = pageTitle;
9465
9677
  }
9466
9678
 
9467
9679
  function render() {
9468
9680
  renderLayerList();
9469
- renderSourceFileList();
9470
- }
9471
-
9472
- function renderSourceFileList() {
9473
9681
  el.findChild('.no-layer-note').classed('hidden', model.getActiveLayer());
9474
- el.findChild('.source-file-section').classed('hidden', !model.getActiveLayer());
9475
- var list = el.findChild('.file-list');
9476
- var files = [];
9477
- list.empty();
9478
- model.forEachLayer(function(lyr, dataset) {
9479
- var file = internal.getLayerSourceFile(lyr, dataset);
9480
- if (!file || files.includes(file)) return;
9481
- files.push(file);
9482
- var warnings = getWarnings(lyr, dataset);
9483
- var html = '<div class="layer-item">';
9484
- html += rowHTML('name', file);
9485
- if (warnings) {
9486
- // html += rowHTML('problems', warnings, 'layer-problems');
9487
- html += rowHTML('', warnings, 'layer-problems');
9488
- }
9489
- html += '</div>';
9490
- list.appendChild(El('div').html(html).firstChild());
9491
- });
9492
-
9493
9682
  }
9494
9683
 
9495
9684
  function renderLayerList() {
@@ -9550,10 +9739,10 @@
9550
9739
  html = '<!-- ' + lyr.menu_id + '--><div class="' + classes + '">';
9551
9740
  html += rowHTML('name', '<span class="layer-name colored-text dot-underline">' + formatLayerNameForDisplay(lyr.name) + '</span>', 'row1');
9552
9741
  html += rowHTML('contents', describeLyr(lyr, dataset));
9553
- // html += '<img class="close-btn" draggable="false" src="images/close.png">';
9742
+ html += '<span class="more-btn layer-btn" role="button" tabindex="0" aria-label="More layer options"></span>';
9554
9743
  if (opts.pinnable) {
9555
- html += '<img class="eye-btn black-eye" draggable="false" src="images/eye.png">';
9556
- html += '<img class="eye-btn green-eye" draggable="false" src="images/eye2.png">';
9744
+ html += '<img class="eye-btn black-eye layer-btn" draggable="false" src="images/eye.png">';
9745
+ html += '<img class="eye-btn green-eye layer-btn" draggable="false" src="images/eye2.png">';
9557
9746
  }
9558
9747
  html += '</div>';
9559
9748
  return html;
@@ -9561,8 +9750,10 @@
9561
9750
 
9562
9751
  function initMouseEvents(entry, id, pinnable) {
9563
9752
  entry.on('mouseover', init);
9753
+ entry.on('focusin', init);
9564
9754
  function init() {
9565
9755
  entry.removeEventListener('mouseover', init);
9756
+ entry.removeEventListener('focusin', init);
9566
9757
  initMouseEvents2(entry, id, pinnable);
9567
9758
  }
9568
9759
  }
@@ -9578,10 +9769,6 @@
9578
9769
  }
9579
9770
  // start dragging when button is first pressed
9580
9771
  if (e.buttons && !dragTargetId) {
9581
- // don't start dragging if pointer is over the close button
9582
- // (before, clicking this button wqs finicky -- the mouse had to remain
9583
- // perfectly still between mousedown and mouseup)
9584
- if (El(e.target).hasClass('close-btn')) return;
9585
9772
  dragTargetId = id;
9586
9773
  entry.addClass('drag-target');
9587
9774
  }
@@ -9606,6 +9793,7 @@
9606
9793
  }
9607
9794
 
9608
9795
  function initMouseEvents2(entry, id, pinnable) {
9796
+ var moreBtn = entry.findChild('.more-btn');
9609
9797
  initLayerDragging(entry, id);
9610
9798
 
9611
9799
  function deleteLayer() {
@@ -9630,7 +9818,7 @@
9630
9818
  }
9631
9819
  }
9632
9820
 
9633
- function selectLayer(closeMenu) {
9821
+ function selectLayer() {
9634
9822
  var target = findLayerById(id);
9635
9823
  // don't select if user is typing or dragging
9636
9824
  if (GUI.textIsSelected() || dragging) return;
@@ -9639,17 +9827,24 @@
9639
9827
  if (!map.isActiveLayer(target.layer)) {
9640
9828
  model.selectLayer(target.layer, target.dataset);
9641
9829
  }
9642
- // close menu after a delay
9643
- if (closeMenu === true) setTimeout(function() {
9644
- gui.clearMode();
9645
- }, 230);
9646
9830
  }
9647
9831
 
9648
- // init delete button
9649
- // GUI.onClick(entry.findChild('img.close-btn'), function(e) {
9650
- // e.stopPropagation();
9651
- // deleteLayer();
9652
- // });
9832
+ function openLayerMenu(e) {
9833
+ var menuEvent = e;
9834
+ e.stopPropagation();
9835
+ if (!isFinite(e.pageX) || !isFinite(e.pageY)) {
9836
+ var rect = moreBtn.node().getBoundingClientRect();
9837
+ menuEvent = {
9838
+ pageX: rect.right,
9839
+ pageY: rect.top + rect.height / 2
9840
+ };
9841
+ }
9842
+ menuEvent.deleteLayer = deleteLayer;
9843
+ menuEvent.selectLayer = selectLayer;
9844
+ menuEvent.contextMenuId = 'layer-' + id;
9845
+ openContextMenu(menuEvent, null, null);
9846
+ }
9847
+
9653
9848
 
9654
9849
  if (pinnable) {
9655
9850
  // init pin button
@@ -9692,18 +9887,22 @@
9692
9887
  renameLayer(target, str);
9693
9888
  });
9694
9889
 
9890
+ moreBtn.on('mousedown', function(e) {
9891
+ e.stopPropagation();
9892
+ });
9893
+ GUI.onClick(moreBtn, openLayerMenu);
9894
+ moreBtn.on('keydown', function(e) {
9895
+ if (e.key == 'Enter' || e.key == ' ') {
9896
+ e.preventDefault();
9897
+ openLayerMenu(e);
9898
+ }
9899
+ });
9900
+
9695
9901
  // init click-to-select
9696
9902
  GUI.onClick(entry, function() {
9697
- selectLayer(true);
9903
+ selectLayer();
9698
9904
  });
9699
9905
 
9700
- GUI.onContextClick(entry, function(e) {
9701
- e.deleteLayer = deleteLayer;
9702
- e.selectLayer = selectLayer;
9703
- // contextMenu.open(e);
9704
- // openContextMenu(e, null, entry.node())
9705
- openContextMenu(e, null, null);
9706
- });
9707
9906
  }
9708
9907
 
9709
9908
  function describeLyr(lyr, dataset) {
@@ -9750,30 +9949,6 @@
9750
9949
  }
9751
9950
  }
9752
9951
 
9753
- function getWarnings(lyr, dataset) {
9754
- var file = internal.getLayerSourceFile(lyr, dataset);
9755
- var missing = [];
9756
- var msg;
9757
- // show missing file warning for first layer in dataset
9758
- // (assuming it represents the content of the original file)
9759
- if (utils$1.endsWith(file, '.shp') && lyr == dataset.layers[0]) {
9760
- if (!lyr.data) {
9761
- missing.push('.dbf');
9762
- }
9763
- if (!dataset.info.wkt1 && !dataset.info.crs) {
9764
- missing.push('.prj');
9765
- }
9766
- }
9767
- if (missing.length) {
9768
- msg = 'missing ' + missing.join(' and ') + ' data';
9769
- }
9770
- return msg;
9771
- }
9772
-
9773
- function describeSrc(lyr, dataset) {
9774
- return internal.getLayerSourceFile(lyr, dataset);
9775
- }
9776
-
9777
9952
  function isPinnable(lyr) {
9778
9953
  return internal.layerIsGeometric(lyr) || internal.layerHasFurniture(lyr);
9779
9954
  }
@@ -9970,7 +10145,7 @@
9970
10145
  function getRestoreDataNote(gui) {
9971
10146
  var stats = getUndoPayloadStats(gui);
9972
10147
  var bytes = stats ? stats.ownBytes || 0 : 0;
9973
- return 'estimated on-disk restore data: ' + formatBytes(bytes);
10148
+ return 'restore data stored on-disk: ' + formatBytes(bytes);
9974
10149
  }
9975
10150
 
9976
10151
  function getUndoPayloadStats(gui) {
@@ -11991,8 +12166,8 @@
11991
12166
  // DELETE key
11992
12167
  // delete pinned feature
11993
12168
  // to help protect against inadvertent deletion, don't delete
11994
- // when console is open or a popup menu is open
11995
- if (!gui.getMode() && !gui.consoleIsOpen()) {
12169
+ // when a sidebar panel or popup menu is open
12170
+ if (!gui.getMode() && !gui.sidebarPanelIsOpen()) {
11996
12171
  internal.deleteFeatureById(targetLayer, pinnedId());
11997
12172
  self.clearSelection();
11998
12173
  gui.model.updated({flags: 'filter'}); // signal map to update
@@ -18326,6 +18501,10 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
18326
18501
 
18327
18502
 
18328
18503
  gui.state = {};
18504
+ var sidebarPanel = null;
18505
+ var lastSidebarPanel = 'console';
18506
+ var sidebarWidth = GUI.getSavedValue('sidebar_width') || 0;
18507
+ var sidebarResizeFrame = null;
18329
18508
 
18330
18509
  var msgCount = 0;
18331
18510
  var clearMsg;
@@ -18366,10 +18545,50 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
18366
18545
  // if (gui.progressMessage) gui.progressMessage.hide();
18367
18546
  };
18368
18547
 
18548
+ if (sidebarWidth) {
18549
+ setSidebarWidth(sidebarWidth);
18550
+ }
18551
+
18552
+ gui.getSidebarPanel = function() {
18553
+ return sidebarPanel;
18554
+ };
18555
+
18556
+ gui.setSidebarPanel = function(name) {
18557
+ var prev = sidebarPanel;
18558
+ sidebarPanel = name || null;
18559
+ if (sidebarPanel && gui.getMode()) {
18560
+ gui.clearMode();
18561
+ }
18562
+ if (sidebarPanel == prev) return;
18563
+ if (sidebarPanel) {
18564
+ lastSidebarPanel = sidebarPanel;
18565
+ }
18566
+ gui.container
18567
+ .classed('sidebar-open', !!sidebarPanel)
18568
+ .classed('layers-open', sidebarPanel == 'layers')
18569
+ .classed('console-open', sidebarPanel == 'console');
18570
+ gui.dispatchEvent('sidebar', {name: sidebarPanel, prev: prev});
18571
+ gui.dispatchEvent('resize');
18572
+ };
18573
+
18574
+ gui.toggleSidebarPanel = function(name) {
18575
+ gui.setSidebarPanel(sidebarPanel == name ? null : name);
18576
+ };
18577
+
18578
+ gui.toggleSidebar = function() {
18579
+ gui.setSidebarPanel(sidebarPanel ? null : lastSidebarPanel);
18580
+ };
18581
+
18582
+ gui.sidebarPanelIsOpen = function() {
18583
+ return !!sidebarPanel;
18584
+ };
18585
+
18369
18586
  gui.consoleIsOpen = function() {
18370
- return gui.container.hasClass('console-open');
18587
+ return sidebarPanel == 'console';
18371
18588
  };
18372
18589
 
18590
+ initSidebarResizing();
18591
+
18373
18592
  gui.getRuntimeStateContext = function() {
18374
18593
  return getRuntimeStateContext(gui);
18375
18594
  };
@@ -18411,6 +18630,50 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
18411
18630
  }
18412
18631
 
18413
18632
  return gui;
18633
+
18634
+ function initSidebarResizing() {
18635
+ var handle = gui.container.findChild('.sidebar-resize-handle');
18636
+ if (!handle) return;
18637
+ handle.on('mousedown', function(e) {
18638
+ if (!gui.sidebarPanelIsOpen()) return;
18639
+ e.preventDefault();
18640
+ e.stopPropagation();
18641
+ gui.container.addClass('sidebar-resizing');
18642
+ window.addEventListener('mousemove', onMove);
18643
+ window.addEventListener('mouseup', onRelease);
18644
+ });
18645
+
18646
+ function onMove(e) {
18647
+ setSidebarWidth(e.pageX);
18648
+ scheduleSidebarResize();
18649
+ }
18650
+
18651
+ function onRelease() {
18652
+ window.removeEventListener('mousemove', onMove);
18653
+ window.removeEventListener('mouseup', onRelease);
18654
+ gui.container.removeClass('sidebar-resizing');
18655
+ GUI.setSavedValue('sidebar_width', sidebarWidth);
18656
+ scheduleSidebarResize();
18657
+ }
18658
+ }
18659
+
18660
+ function setSidebarWidth(width) {
18661
+ sidebarWidth = clampSidebarWidth(width);
18662
+ gui.container.node().style.setProperty('--left-sidebar-width', sidebarWidth + 'px');
18663
+ }
18664
+
18665
+ function clampSidebarWidth(width) {
18666
+ var max = Math.min(720, Math.round(window.innerWidth * 0.6));
18667
+ return Math.max(220, Math.min(max, Math.round(width)));
18668
+ }
18669
+
18670
+ function scheduleSidebarResize() {
18671
+ if (sidebarResizeFrame) return;
18672
+ sidebarResizeFrame = requestAnimationFrame(function() {
18673
+ sidebarResizeFrame = null;
18674
+ gui.dispatchEvent('resize');
18675
+ });
18676
+ }
18414
18677
  }
18415
18678
 
18416
18679
  function createUndoTestApi(gui) {