@innovastudio/contentbox 1.6.201 → 1.6.202

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@innovastudio/contentbox",
4
- "version": "1.6.201",
4
+ "version": "1.6.202",
5
5
  "description": "",
6
6
  "main": "public/contentbox/contentbox.esm.js",
7
7
  "types": "index.d.ts",
@@ -72,7 +72,7 @@
72
72
  "@gltf-transform/core": "^4.5.0",
73
73
  "@gltf-transform/extensions": "^4.5.0",
74
74
  "@gltf-transform/functions": "^4.5.0",
75
- "@innovastudio/contentbuilder": "^1.5.219",
75
+ "@innovastudio/contentbuilder": "^1.5.220",
76
76
  "js-beautify": "^1.14.0",
77
77
  "marked": "^17.0.0",
78
78
  "meshoptimizer": "^1.2.0",
@@ -15507,10 +15507,12 @@ class PanelButton {
15507
15507
  const inpHref = panel.querySelector('.inp-href');
15508
15508
  inpHref.addEventListener('input', () => {
15509
15509
  this.edit(btn => setHref$1(btn, inpHref.value), false);
15510
+ this.syncLinkDialog();
15510
15511
  });
15511
15512
  const chkNewTab = panel.querySelector('.chk-newtab');
15512
15513
  chkNewTab.addEventListener('change', () => {
15513
15514
  this.edit(btn => setNewTab$1(btn, chkNewTab.checked), false);
15515
+ this.syncLinkDialog();
15514
15516
  }); // --- Colours ---
15515
15517
 
15516
15518
  panel.querySelectorAll('[data-colorstate]').forEach(btn => {
@@ -15580,6 +15582,20 @@ class PanelButton {
15580
15582
  this.getState();
15581
15583
  this.repositionTools();
15582
15584
  }
15585
+ } // ContentBuilder's link dialog edits the same href/target and can be open
15586
+ // alongside this panel. It reads its fields when it opens, so without this
15587
+ // its Ok would write back the link as it was before the panel touched it.
15588
+ // (The other direction is the editor's own: see elementhyperlink.js.)
15589
+
15590
+
15591
+ syncLinkDialog() {
15592
+ const btn = this.target();
15593
+ const modal = this.builder.editor.builderStuff.querySelector('.is-modal.createlink');
15594
+ if (!btn || !modal || !modal.classList.contains('active')) return;
15595
+ const url = modal.querySelector('.input-url');
15596
+ if (url && document.activeElement !== url) url.value = btn.getAttribute('href') || '';
15597
+ const newwindow = modal.querySelector('.input-newwindow');
15598
+ if (newwindow) newwindow.checked = btn.getAttribute('target') === '_blank';
15583
15599
  } // Size and padding change the button's box, which leaves the floating
15584
15600
  // tools pointing at where it used to be.
15585
15601
 
@@ -18790,7 +18806,7 @@ class PanelOverlay {
18790
18806
 
18791
18807
  <label class="label checkbox mt-3">
18792
18808
  <input type="checkbox" class="chk-newwindow" id="_chk_ovl_newwindow_${this.random()}">
18793
- <span>${out('Open new window')}</span>
18809
+ <span>${out('Open in new tab')}</span>
18794
18810
  </label>
18795
18811
 
18796
18812
  </div>
@@ -74561,10 +74577,10 @@ class Image$1 {
74561
74577
 
74562
74578
  <div class="cb-field">
74563
74579
  <label class="label-checkbox">
74564
- <input class="input-newwindow" id="__input_newwindow2" type="checkbox" /> ${util.out('Open new window')}
74580
+ <input class="input-newwindow" id="__input_newwindow2" type="checkbox" /> ${util.out('Open in new tab')}
74565
74581
  </label>
74566
74582
  <label class="label-checkbox mt-1" id="lblImageLinkOpenLightbox" style="${this.builder.useLightbox ? '' : 'display:none'}">
74567
- <input class="input-openlightbox" id="__input_openlightbox2" type="checkbox" /> ${util.out('Open in a lightbox (for image, video or Youtube)')}
74583
+ <input class="input-openlightbox" id="__input_openlightbox2" type="checkbox" /> ${util.out('Open in a lightbox')}
74568
74584
  </label>
74569
74585
  </div>
74570
74586
 
@@ -75644,9 +75660,22 @@ class ButtonEditor {
75644
75660
  if (cmd === 'href') setHref(el, value);else if (cmd === 'newtab') setNewTab(el, value);else if (cmd === 'fontsize') setFontSize(el, value === '' ? '' : parseInt(value, 10));else if (cmd === 'tracking') {
75645
75661
  if (value !== '') setTracking(el, parseInt(value, 10));
75646
75662
  } else if (cmd === 'margin') setMargin(el, side, value === '' ? 0 : parseInt(value, 10));
75663
+ if (cmd === 'href' || cmd === 'newtab') this.syncLinkDialog(el);
75647
75664
  this.builder.opts.onChange();
75648
75665
  this.realtime();
75649
75666
  }
75667
+
75668
+ // The link dialog edits the same href/target and can be open alongside this
75669
+ // panel. Its fields are read when it opens, so without this its Ok would
75670
+ // write back the link as it was before the panel touched it.
75671
+ syncLinkDialog(el) {
75672
+ const modal = this.builderStuff.querySelector('.is-modal.createlink');
75673
+ if (!modal || !this.dom.hasClass(modal, 'active')) return;
75674
+ const url = modal.querySelector('.input-url');
75675
+ if (url && document.activeElement !== url) url.value = el.getAttribute('href') || '';
75676
+ const newwindow = modal.querySelector('.input-newwindow');
75677
+ if (newwindow) newwindow.checked = el.getAttribute('target') === '_blank';
75678
+ }
75650
75679
  openColor(cmd, btn) {
75651
75680
  const el = this.getButton();
75652
75681
  if (!el) return;
@@ -75965,6 +75994,23 @@ class Hyperlink {
75965
75994
  this.buttonEditor = new ButtonEditor(this.builder);
75966
75995
  }
75967
75996
  }
75997
+
75998
+ // The link dialog and a button UI can be open at the same time and both
75999
+ // show the link's href and target. After the dialog writes to the link,
76000
+ // the button UI has to re-read it, or it keeps showing (and writing back)
76001
+ // the old values. The host can own that UI instead (onButtonEdit).
76002
+ syncButtonUI(link) {
76003
+ if (!link || !link.isConnected) return;
76004
+ if (this.builder.opts.onButtonEdit) {
76005
+ if (link === this.builder.activeLinkButton) this.builder.opts.onButtonEdit(link);
76006
+ return;
76007
+ }
76008
+ const dom = this.builder.dom;
76009
+ const buttonModal = this.builder.builderStuff.querySelector('.is-modal.buttoneditor');
76010
+ if (!buttonModal || !dom.hasClass(buttonModal, 'active')) return;
76011
+ if (!this.buttonEditor) this.buttonEditor = new ButtonEditor(this.builder);
76012
+ this.buttonEditor.realtime();
76013
+ }
75968
76014
  renderPanel() {
75969
76015
  const builderStuff = this.builder.builderStuff;
75970
76016
  const util = this.builder.util;
@@ -75996,10 +76042,10 @@ class Hyperlink {
75996
76042
  </div>
75997
76043
  <div class="cb-field">
75998
76044
  <label class="label-checkbox">
75999
- <input class="input-newwindow" id="__input_newwindow" type="checkbox" /> ${util.out('Open new window')}
76045
+ <input class="input-newwindow" id="__input_newwindow" type="checkbox" /> ${util.out('Open in new tab')}
76000
76046
  </label>
76001
- <label class="label-checkbox" id="lblOpenLightbox" style="${this.builder.useLightbox ? '' : 'display:none'}">
76002
- <input class="input-openlightbox" id="__input_openlightbox" type="checkbox" /> ${util.out('Open in a lightbox (for image, video or Youtube)')}
76047
+ <label class="label-checkbox mt-1" id="lblOpenLightbox" style="${this.builder.useLightbox ? '' : 'display:none'}">
76048
+ <input class="input-openlightbox" id="__input_openlightbox" type="checkbox" /> ${util.out('Open in a lightbox')}
76003
76049
  </label>
76004
76050
  </div>
76005
76051
  <div class="cb-field">
@@ -76042,6 +76088,7 @@ class Hyperlink {
76042
76088
  let inputOk = modal.querySelector('.input-ok');
76043
76089
  dom.addEventListener(inputOk, 'click', () => {
76044
76090
  this.builder.uo.saveForUndo();
76091
+ let editedLink = null;
76045
76092
  let link = this.builder.activeLink;
76046
76093
  if (link) {
76047
76094
  // Edit Existing Link
@@ -76051,35 +76098,19 @@ class Hyperlink {
76051
76098
  let linktext = modal.querySelector('.input-text').value;
76052
76099
  if (linktext === '') linktext = url;
76053
76100
 
76054
- // Engine seam: edit / unlink an existing link via Inscribe.
76055
- // A cleared URL means UNLINK. Icon links stay legacy.
76056
- if (this.builder.opts.engine === 'inscribe' && !this.builder.activeIcon) {
76101
+ // Engine seam: only UNLINK (a cleared URL) goes through
76102
+ // Inscribe. An edit is applied in place below: region.link()
76103
+ // re-wraps the selection in a NEW plain <a>, which dropped
76104
+ // the link's classes and inline styles, so changing a
76105
+ // button's URL stripped the button. Icon links stay legacy.
76106
+ if (url === '' && this.builder.opts.engine === 'inscribe' && !this.builder.activeIcon) {
76057
76107
  const region = this.builder.editingEngine.active;
76058
76108
  if (region && link.isConnected) {
76059
76109
  dom.selectElementContents(link); // target the link
76060
- if (url !== '') {
76061
- const attrs = {
76062
- target: modal.querySelector('.input-newwindow').checked ? '_blank' : '',
76063
- title: title || '',
76064
- class: modal.querySelector('.input-openlightbox').checked ? 'is-lightbox' : ''
76065
- };
76066
- const created = region.link(url, attrs); // re-wraps, returns <a>
76067
- if (created && linktext && created.textContent !== linktext) {
76068
- created.textContent = linktext;
76069
- }
76070
- this.builder.opts.onChange();
76071
- util.hideModal(modal);
76072
- if (created && created.isConnected) {
76073
- region.focus();
76074
- dom.selectElementContents(created);
76075
- util.saveSelection();
76076
- }
76077
- } else {
76078
- region.unlink();
76079
- this.hideTool();
76080
- this.builder.opts.onChange();
76081
- util.hideModal(modal);
76082
- }
76110
+ region.unlink();
76111
+ this.hideTool();
76112
+ this.builder.opts.onChange();
76113
+ util.hideModal(modal);
76083
76114
  return;
76084
76115
  }
76085
76116
  }
@@ -76087,6 +76118,7 @@ class Hyperlink {
76087
76118
  link.setAttribute('href', url);
76088
76119
  if (modal.querySelector('.input-newwindow').checked) {
76089
76120
  link.setAttribute('target', '_blank');
76121
+ if (!link.getAttribute('rel')) link.setAttribute('rel', 'noopener noreferrer');
76090
76122
  } else {
76091
76123
  link.removeAttribute('target');
76092
76124
  }
@@ -76098,7 +76130,14 @@ class Hyperlink {
76098
76130
  if (this.builder.activeIcon) ; else {
76099
76131
  link.innerHTML = linktext;
76100
76132
  }
76101
- link.setAttribute('title', title);
76133
+ if (title) link.setAttribute('title', title);else link.removeAttribute('title');
76134
+
76135
+ // A button UI (this editor's Button panel, or the
76136
+ // host's own) shows the same link and can be open at
76137
+ // the same time as this dialog, so it has to re-read
76138
+ // what was just written.
76139
+ this.syncButtonUI(link);
76140
+ editedLink = link;
76102
76141
  } else {
76103
76142
  // link.outerHTML = link.innerHTML;
76104
76143
  this.hideTool();
@@ -76256,6 +76295,17 @@ class Hyperlink {
76256
76295
  this.builder.opts.onRender();
76257
76296
  }
76258
76297
  util.hideModal(modal);
76298
+
76299
+ // hideModal() blurs, so the caret goes back on the edited link
76300
+ // afterwards: the dialog can be reopened straight away.
76301
+ if (editedLink && editedLink.isConnected && !this.builder.activeIcon) {
76302
+ const region = this.builder.editingEngine.active;
76303
+ if (region) {
76304
+ region.focus();
76305
+ dom.selectElementContents(editedLink);
76306
+ util.saveSelection();
76307
+ }
76308
+ }
76259
76309
  });
76260
76310
  let inputCancel = modal.querySelector('.input-cancel');
76261
76311
  dom.addEventListener(inputCancel, 'click', () => {
@@ -76401,7 +76451,10 @@ class Hyperlink {
76401
76451
  }
76402
76452
 
76403
76453
  // Button Stuff
76404
- if (this.builder.useButtonPlugin) {
76454
+ // A host with its own button UI (onButtonEdit) already opens it by
76455
+ // selecting the button, so the pencil is a second route to the same
76456
+ // panel and is left out.
76457
+ if (this.builder.useButtonPlugin || this.builder.opts.onButtonEdit) {
76405
76458
  linkTool.querySelector('.link-button-edit').style.display = 'none';
76406
76459
  } else {
76407
76460
  if (link && this.builder.activeLinkButton) linkTool.querySelector('.link-button-edit').style.display = 'block';else linkTool.querySelector('.link-button-edit').style.display = 'none';
@@ -76705,6 +76758,11 @@ class Button {
76705
76758
  this.buttonEditor.realtime();
76706
76759
  }
76707
76760
  const buttonTool = this.buttonTool;
76761
+
76762
+ // A host with its own button UI (onButtonEdit) already opens it by
76763
+ // selecting the button, so the pencil is a second route to the same
76764
+ // panel and is left out.
76765
+ buttonTool.querySelector('.button-edit').style.display = this.builder.opts.onButtonEdit ? 'none' : '';
76708
76766
  let top = activeButton.getBoundingClientRect().top + this.builder.win.pageYOffset;
76709
76767
  let left = activeButton.getBoundingClientRect().left;
76710
76768
  buttonTool.style.display = 'flex';