@themarioga/grid-editor 8.2.0 → 8.3.0

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.
@@ -2,6 +2,10 @@
2
2
  position: relative;
3
3
  min-height: 22px;
4
4
  margin-bottom: 10px;
5
+ /* toolbar_overflow: 'menu'. The add buttons keep to one line, and the
6
+ ones that don't fit go behind a button at its end. The right-hand
7
+ buttons come before in the markup, so they are ordered back to how
8
+ floating them puts them. */
5
9
  }
6
10
  .ge-mainControls .ge-wrapper {
7
11
  padding-top: 5px;
@@ -45,6 +49,69 @@
45
49
  .ge-mainControls .ge-layout-mode {
46
50
  margin-left: 5px;
47
51
  }
52
+ .ge-mainControls .ge-wrapper.ge-toolbar-menu {
53
+ display: flex;
54
+ align-items: flex-start;
55
+ }
56
+ .ge-mainControls .ge-wrapper.ge-toolbar-menu > .pull-right {
57
+ float: none;
58
+ }
59
+ .ge-mainControls .ge-wrapper.ge-toolbar-menu > .ge-toolbar-end {
60
+ order: 1;
61
+ }
62
+ .ge-mainControls .ge-wrapper.ge-toolbar-menu > .btn-group.pull-right {
63
+ order: 2;
64
+ }
65
+ .ge-mainControls .ge-wrapper.ge-toolbar-menu > .ge-layout-mode {
66
+ order: 3;
67
+ }
68
+ .ge-mainControls .ge-toolbar-start {
69
+ display: flex;
70
+ flex: 1 1 auto;
71
+ min-width: 0;
72
+ overflow: hidden;
73
+ }
74
+ .ge-mainControls .ge-toolbar-more {
75
+ display: none;
76
+ position: relative;
77
+ flex: none;
78
+ margin: 0 5px 0 4px;
79
+ }
80
+ .ge-mainControls .ge-toolbar-more.ge-needed {
81
+ display: block;
82
+ }
83
+ .ge-mainControls .ge-toolbar-overflow {
84
+ display: none;
85
+ position: absolute;
86
+ z-index: 30;
87
+ top: calc(100% + 4px);
88
+ right: 0;
89
+ flex-direction: column;
90
+ gap: 6px;
91
+ width: max-content;
92
+ max-width: min(420px, calc(100vw - 32px));
93
+ padding: 6px;
94
+ background: #fff;
95
+ border: 1px solid rgba(0, 0, 0, 0.15);
96
+ border-radius: 6px;
97
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
98
+ /* Wrapped onto several lines, a group's buttons stand apart */
99
+ }
100
+ .ge-mainControls .ge-toolbar-overflow > .btn-group {
101
+ flex-wrap: wrap;
102
+ gap: 4px;
103
+ margin: 0;
104
+ }
105
+ .ge-mainControls .ge-toolbar-overflow > .btn-group:empty {
106
+ display: none;
107
+ }
108
+ .ge-mainControls .ge-toolbar-overflow > .btn-group > .btn.btn {
109
+ margin-left: 0;
110
+ border-radius: 4px;
111
+ }
112
+ .ge-mainControls .ge-toolbar-more.ge-open > .ge-toolbar-overflow {
113
+ display: flex;
114
+ }
48
115
  .ge-mainControls .ge-toolbar-end {
49
116
  margin-right: 5px;
50
117
  }
@@ -107,6 +107,8 @@ export interface GridEditorOptions {
107
107
  text_tools?: HostTool[];
108
108
  drag_handle?: 'tool' | 'drawer';
109
109
  toolbar_drag?: 'auto' | boolean;
110
+ /** The add buttons that don't fit on the toolbar's line: behind a more button, or onto another line. Default 'menu'. */
111
+ toolbar_overflow?: 'menu' | 'wrap';
110
112
  /** A click in a column or a section makes it where the toolbar's buttons add. Default false. */
111
113
  active_target?: boolean;
112
114
  /** The plugins to use, of any kind; null is every one loaded. */
@@ -570,6 +570,8 @@ function build(instance, baseElem, optionsOrMethod) {
570
570
  // 'tool' for the move tool, 'drawer' for the whole drawer
571
571
  "toolbar_drag": "auto",
572
572
  // Drag the toolbar's buttons onto the canvas. 'auto' follows drag_handle
573
+ "toolbar_overflow": "menu",
574
+ // What doesn't fit on one line: 'menu' behind a button, 'wrap' onto another line
573
575
  "active_target": false,
574
576
  // A click in a column makes it where the toolbar's buttons add
575
577
  "element_tools": [],
@@ -634,6 +636,9 @@ function build(instance, baseElem, optionsOrMethod) {
634
636
  var sourceOpen = false;
635
637
  var dropMarker = null;
636
638
  var activeTarget = null;
639
+ var toolbarLifetime = null;
640
+ var closeOverflowMenu = function() {
641
+ };
637
642
  var warnedHere = {};
638
643
  var sortables = [];
639
644
  var instanceId = ++editorCounter;
@@ -661,7 +666,7 @@ function build(instance, baseElem, optionsOrMethod) {
661
666
  removeConfirmModal();
662
667
  removeSettingsPanels();
663
668
  removeDialog();
664
- mainControls.remove();
669
+ removeMainControls();
665
670
  createMainControls();
666
671
  reset();
667
672
  }
@@ -1078,7 +1083,13 @@ function build(instance, baseElem, optionsOrMethod) {
1078
1083
  mainControls = element("div", { "class": "ge-mainControls" });
1079
1084
  htmlTextArea.parentNode.insertBefore(mainControls, htmlTextArea);
1080
1085
  wrapper = mainControls.appendChild(element("div", { "class": "ge-wrapper ge-top" }));
1081
- addRowGroup = wrapper.appendChild(element("div", { "class": "ge-addRowGroup btn-group" }));
1086
+ var overflowMenu = settings.toolbar_overflow !== "wrap";
1087
+ var start = wrapper;
1088
+ if (overflowMenu) {
1089
+ addClass(wrapper, "ge-toolbar-menu");
1090
+ start = wrapper.appendChild(element("div", { "class": "ge-toolbar-start" }));
1091
+ }
1092
+ addRowGroup = start.appendChild(element("div", { "class": "ge-addRowGroup btn-group" }));
1082
1093
  addContainerGroup = element("div", { "class": "ge-addContainerGroup btn-group ms-1" });
1083
1094
  settings.new_row_layouts.forEach(function(layout) {
1084
1095
  var grouped = !Array.isArray(layout);
@@ -1113,7 +1124,7 @@ function build(instance, baseElem, optionsOrMethod) {
1113
1124
  icon += "</div>";
1114
1125
  btn.appendChild(create(icon));
1115
1126
  });
1116
- wrapper.appendChild(addContainerGroup);
1127
+ start.appendChild(addContainerGroup);
1117
1128
  Object.keys(CONTAINERS).forEach(function(type) {
1118
1129
  var definition = CONTAINERS[type];
1119
1130
  var button = labelButton(
@@ -1197,8 +1208,99 @@ function build(instance, baseElem, optionsOrMethod) {
1197
1208
  end.appendChild(button);
1198
1209
  });
1199
1210
  }
1211
+ if (overflowMenu) {
1212
+ createOverflowMenu(start);
1213
+ }
1200
1214
  makeToolbarDraggable();
1201
1215
  }
1216
+ function removeMainControls() {
1217
+ if (toolbarLifetime) {
1218
+ toolbarLifetime.abort();
1219
+ }
1220
+ toolbarLifetime = null;
1221
+ closeOverflowMenu = function() {
1222
+ };
1223
+ mainControls.remove();
1224
+ }
1225
+ function createOverflowMenu(start) {
1226
+ var more = create('<div class="ge-toolbar-more"><button type="button" class="btn btn-sm btn-primary"><i class="bi bi-three-dots"></i></button><div class="ge-toolbar-overflow"><div class="ge-addRowGroup btn-group"></div><div class="ge-addContainerGroup btn-group"></div></div></div>');
1227
+ start.parentNode.insertBefore(more, start.nextSibling);
1228
+ var toggle2 = one(more, "button");
1229
+ var panel = one(more, ".ge-toolbar-overflow");
1230
+ var spares = all(panel, ".btn-group");
1231
+ var homes = [];
1232
+ [addRowGroup, addContainerGroup].forEach(function(group, index) {
1233
+ Array.prototype.slice.call(group.children).forEach(function(button) {
1234
+ homes.push({ button, home: group, spare: spares[index] });
1235
+ });
1236
+ });
1237
+ toggle2.setAttribute("title", t("tool.more"));
1238
+ toggle2.setAttribute("aria-haspopup", "true");
1239
+ toggle2.setAttribute("aria-expanded", "false");
1240
+ var menuLifetime = toolbarLifetime = new AbortController();
1241
+ var signal = { signal: menuLifetime.signal };
1242
+ toggle2.addEventListener("click", function() {
1243
+ openOverflow(!hasClass(more, "ge-open"));
1244
+ });
1245
+ panel.addEventListener("click", function(e) {
1246
+ if (closest(e.target, "[data-ge-toolbar]")) {
1247
+ openOverflow(false);
1248
+ }
1249
+ });
1250
+ document.addEventListener("pointerdown", function(e) {
1251
+ if (!more.contains(e.target)) {
1252
+ openOverflow(false);
1253
+ }
1254
+ }, signal);
1255
+ document.addEventListener("keydown", function(e) {
1256
+ if (e.key === "Escape") {
1257
+ openOverflow(false);
1258
+ }
1259
+ }, signal);
1260
+ closeOverflowMenu = function() {
1261
+ openOverflow(false);
1262
+ };
1263
+ fit();
1264
+ if (window.ResizeObserver) {
1265
+ var pending = false;
1266
+ var observer = new window.ResizeObserver(function() {
1267
+ if (pending) {
1268
+ return;
1269
+ }
1270
+ pending = true;
1271
+ window.requestAnimationFrame(function() {
1272
+ pending = false;
1273
+ if (!menuLifetime.signal.aborted) {
1274
+ fit();
1275
+ }
1276
+ });
1277
+ });
1278
+ observer.observe(wrapper);
1279
+ observer.observe(start);
1280
+ menuLifetime.signal.addEventListener("abort", function() {
1281
+ observer.disconnect();
1282
+ });
1283
+ }
1284
+ function openOverflow(open) {
1285
+ open = open && hasClass(more, "ge-needed");
1286
+ toggleClass(more, "ge-open", open);
1287
+ toggle2.setAttribute("aria-expanded", open ? "true" : "false");
1288
+ }
1289
+ function fit() {
1290
+ homes.forEach(function(entry) {
1291
+ entry.home.appendChild(entry.button);
1292
+ });
1293
+ removeClass(more, "ge-needed");
1294
+ if (start.scrollWidth <= start.clientWidth) {
1295
+ openOverflow(false);
1296
+ return;
1297
+ }
1298
+ addClass(more, "ge-needed");
1299
+ for (var i = homes.length - 1; i >= 0 && start.scrollWidth > start.clientWidth; i--) {
1300
+ homes[i].spare.insertBefore(homes[i].button, homes[i].spare.firstChild);
1301
+ }
1302
+ }
1303
+ }
1202
1304
  function labelButton(button, label, iconClass) {
1203
1305
  button.setAttribute("title", label);
1204
1306
  if (iconClass) {
@@ -1273,6 +1375,7 @@ function build(instance, baseElem, optionsOrMethod) {
1273
1375
  }
1274
1376
  helper = addClass(button.cloneNode(true), "ge-toolbar-helper");
1275
1377
  document.body.appendChild(helper);
1378
+ closeOverflowMenu();
1276
1379
  addClass(canvas, "ge-dropping");
1277
1380
  }
1278
1381
  css(helper, { left: move.pageX - 14, top: move.pageY - 14 });
@@ -1754,7 +1857,7 @@ function build(instance, baseElem, optionsOrMethod) {
1754
1857
  removeConfirmModal();
1755
1858
  removeSettingsPanels();
1756
1859
  removeDialog();
1757
- mainControls.remove();
1860
+ removeMainControls();
1758
1861
  htmlTextArea.remove();
1759
1862
  lifetime.abort();
1760
1863
  instances.delete(canvas);
@@ -4220,7 +4323,7 @@ GridEditor.t = translate;
4220
4323
  GridEditor._plainHtml = plainHtml;
4221
4324
  GridEditor.Sortable = null;
4222
4325
  GridEditor.bootstrap = null;
4223
- GridEditor.version = false ? "dev" : "8.2.0";
4326
+ GridEditor.version = false ? "dev" : "8.3.0";
4224
4327
  GridEditor.locales = {
4225
4328
  en: {
4226
4329
  "tool.move": "Move",
@@ -4245,6 +4348,7 @@ GridEditor.locales = {
4245
4348
  "tool.indent_increase": "Increase indent\n(hold shift for max)",
4246
4349
  "tool.edit_source": "Edit Source Code",
4247
4350
  "tool.preview": "Preview",
4351
+ "tool.more": "More",
4248
4352
  "panel.title": "{kind} settings",
4249
4353
  "panel.close": "Close",
4250
4354
  "panel.done": "Done",
@@ -571,6 +571,8 @@
571
571
  // 'tool' for the move tool, 'drawer' for the whole drawer
572
572
  "toolbar_drag": "auto",
573
573
  // Drag the toolbar's buttons onto the canvas. 'auto' follows drag_handle
574
+ "toolbar_overflow": "menu",
575
+ // What doesn't fit on one line: 'menu' behind a button, 'wrap' onto another line
574
576
  "active_target": false,
575
577
  // A click in a column makes it where the toolbar's buttons add
576
578
  "element_tools": [],
@@ -635,6 +637,9 @@
635
637
  var sourceOpen = false;
636
638
  var dropMarker = null;
637
639
  var activeTarget = null;
640
+ var toolbarLifetime = null;
641
+ var closeOverflowMenu = function() {
642
+ };
638
643
  var warnedHere = {};
639
644
  var sortables = [];
640
645
  var instanceId = ++editorCounter;
@@ -662,7 +667,7 @@
662
667
  removeConfirmModal();
663
668
  removeSettingsPanels();
664
669
  removeDialog();
665
- mainControls.remove();
670
+ removeMainControls();
666
671
  createMainControls();
667
672
  reset();
668
673
  }
@@ -1079,7 +1084,13 @@
1079
1084
  mainControls = element("div", { "class": "ge-mainControls" });
1080
1085
  htmlTextArea.parentNode.insertBefore(mainControls, htmlTextArea);
1081
1086
  wrapper = mainControls.appendChild(element("div", { "class": "ge-wrapper ge-top" }));
1082
- addRowGroup = wrapper.appendChild(element("div", { "class": "ge-addRowGroup btn-group" }));
1087
+ var overflowMenu = settings.toolbar_overflow !== "wrap";
1088
+ var start = wrapper;
1089
+ if (overflowMenu) {
1090
+ addClass(wrapper, "ge-toolbar-menu");
1091
+ start = wrapper.appendChild(element("div", { "class": "ge-toolbar-start" }));
1092
+ }
1093
+ addRowGroup = start.appendChild(element("div", { "class": "ge-addRowGroup btn-group" }));
1083
1094
  addContainerGroup = element("div", { "class": "ge-addContainerGroup btn-group ms-1" });
1084
1095
  settings.new_row_layouts.forEach(function(layout) {
1085
1096
  var grouped = !Array.isArray(layout);
@@ -1114,7 +1125,7 @@
1114
1125
  icon += "</div>";
1115
1126
  btn.appendChild(create(icon));
1116
1127
  });
1117
- wrapper.appendChild(addContainerGroup);
1128
+ start.appendChild(addContainerGroup);
1118
1129
  Object.keys(CONTAINERS).forEach(function(type) {
1119
1130
  var definition = CONTAINERS[type];
1120
1131
  var button = labelButton(
@@ -1198,8 +1209,99 @@
1198
1209
  end.appendChild(button);
1199
1210
  });
1200
1211
  }
1212
+ if (overflowMenu) {
1213
+ createOverflowMenu(start);
1214
+ }
1201
1215
  makeToolbarDraggable();
1202
1216
  }
1217
+ function removeMainControls() {
1218
+ if (toolbarLifetime) {
1219
+ toolbarLifetime.abort();
1220
+ }
1221
+ toolbarLifetime = null;
1222
+ closeOverflowMenu = function() {
1223
+ };
1224
+ mainControls.remove();
1225
+ }
1226
+ function createOverflowMenu(start) {
1227
+ var more = create('<div class="ge-toolbar-more"><button type="button" class="btn btn-sm btn-primary"><i class="bi bi-three-dots"></i></button><div class="ge-toolbar-overflow"><div class="ge-addRowGroup btn-group"></div><div class="ge-addContainerGroup btn-group"></div></div></div>');
1228
+ start.parentNode.insertBefore(more, start.nextSibling);
1229
+ var toggle2 = one(more, "button");
1230
+ var panel = one(more, ".ge-toolbar-overflow");
1231
+ var spares = all(panel, ".btn-group");
1232
+ var homes = [];
1233
+ [addRowGroup, addContainerGroup].forEach(function(group, index) {
1234
+ Array.prototype.slice.call(group.children).forEach(function(button) {
1235
+ homes.push({ button, home: group, spare: spares[index] });
1236
+ });
1237
+ });
1238
+ toggle2.setAttribute("title", t("tool.more"));
1239
+ toggle2.setAttribute("aria-haspopup", "true");
1240
+ toggle2.setAttribute("aria-expanded", "false");
1241
+ var menuLifetime = toolbarLifetime = new AbortController();
1242
+ var signal = { signal: menuLifetime.signal };
1243
+ toggle2.addEventListener("click", function() {
1244
+ openOverflow(!hasClass(more, "ge-open"));
1245
+ });
1246
+ panel.addEventListener("click", function(e) {
1247
+ if (closest(e.target, "[data-ge-toolbar]")) {
1248
+ openOverflow(false);
1249
+ }
1250
+ });
1251
+ document.addEventListener("pointerdown", function(e) {
1252
+ if (!more.contains(e.target)) {
1253
+ openOverflow(false);
1254
+ }
1255
+ }, signal);
1256
+ document.addEventListener("keydown", function(e) {
1257
+ if (e.key === "Escape") {
1258
+ openOverflow(false);
1259
+ }
1260
+ }, signal);
1261
+ closeOverflowMenu = function() {
1262
+ openOverflow(false);
1263
+ };
1264
+ fit();
1265
+ if (window.ResizeObserver) {
1266
+ var pending = false;
1267
+ var observer = new window.ResizeObserver(function() {
1268
+ if (pending) {
1269
+ return;
1270
+ }
1271
+ pending = true;
1272
+ window.requestAnimationFrame(function() {
1273
+ pending = false;
1274
+ if (!menuLifetime.signal.aborted) {
1275
+ fit();
1276
+ }
1277
+ });
1278
+ });
1279
+ observer.observe(wrapper);
1280
+ observer.observe(start);
1281
+ menuLifetime.signal.addEventListener("abort", function() {
1282
+ observer.disconnect();
1283
+ });
1284
+ }
1285
+ function openOverflow(open) {
1286
+ open = open && hasClass(more, "ge-needed");
1287
+ toggleClass(more, "ge-open", open);
1288
+ toggle2.setAttribute("aria-expanded", open ? "true" : "false");
1289
+ }
1290
+ function fit() {
1291
+ homes.forEach(function(entry) {
1292
+ entry.home.appendChild(entry.button);
1293
+ });
1294
+ removeClass(more, "ge-needed");
1295
+ if (start.scrollWidth <= start.clientWidth) {
1296
+ openOverflow(false);
1297
+ return;
1298
+ }
1299
+ addClass(more, "ge-needed");
1300
+ for (var i = homes.length - 1; i >= 0 && start.scrollWidth > start.clientWidth; i--) {
1301
+ homes[i].spare.insertBefore(homes[i].button, homes[i].spare.firstChild);
1302
+ }
1303
+ }
1304
+ }
1203
1305
  function labelButton(button, label, iconClass) {
1204
1306
  button.setAttribute("title", label);
1205
1307
  if (iconClass) {
@@ -1274,6 +1376,7 @@
1274
1376
  }
1275
1377
  helper = addClass(button.cloneNode(true), "ge-toolbar-helper");
1276
1378
  document.body.appendChild(helper);
1379
+ closeOverflowMenu();
1277
1380
  addClass(canvas, "ge-dropping");
1278
1381
  }
1279
1382
  css(helper, { left: move.pageX - 14, top: move.pageY - 14 });
@@ -1755,7 +1858,7 @@
1755
1858
  removeConfirmModal();
1756
1859
  removeSettingsPanels();
1757
1860
  removeDialog();
1758
- mainControls.remove();
1861
+ removeMainControls();
1759
1862
  htmlTextArea.remove();
1760
1863
  lifetime.abort();
1761
1864
  instances.delete(canvas);
@@ -4221,7 +4324,7 @@
4221
4324
  GridEditor._plainHtml = plainHtml;
4222
4325
  GridEditor.Sortable = null;
4223
4326
  GridEditor.bootstrap = null;
4224
- GridEditor.version = false ? "dev" : "8.2.0";
4327
+ GridEditor.version = false ? "dev" : "8.3.0";
4225
4328
  GridEditor.locales = {
4226
4329
  en: {
4227
4330
  "tool.move": "Move",
@@ -4246,6 +4349,7 @@
4246
4349
  "tool.indent_increase": "Increase indent\n(hold shift for max)",
4247
4350
  "tool.edit_source": "Edit Source Code",
4248
4351
  "tool.preview": "Preview",
4352
+ "tool.more": "More",
4249
4353
  "panel.title": "{kind} settings",
4250
4354
  "panel.close": "Close",
4251
4355
  "panel.done": "Done",