@innovastudio/contentbuilder 1.5.15 → 1.5.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -11527,7 +11527,7 @@ class HtmlUtil {
11527
11527
  elm.removeAttribute('grideditor');
11528
11528
  elm.removeAttribute('gridoutline');
11529
11529
  });
11530
- elms = tmp.querySelectorAll('.is-row-tool,.is-col-tool,.is-rowadd-tool,.is-canvas-tool,.is-canvasadd-tool');
11530
+ elms = tmp.querySelectorAll('.is-row-tool,.is-col-tool,.is-rowadd-tool,.is-canvas-tool,.is-canvasadd-tool,.h-ruler,.v-ruler');
11531
11531
  elms.forEach(elm => {
11532
11532
  if (elm.previousSibling && elm.previousSibling.nodeType === Node.TEXT_NODE) {
11533
11533
  elm.previousSibling.remove();
@@ -11904,6 +11904,8 @@ class UndoRedo {
11904
11904
  dom.removeElements(tmp.querySelectorAll('.is-canvasadd-tool'));
11905
11905
  dom.removeElements(tmp.querySelectorAll('.ovl'));
11906
11906
  dom.removeElements(tmp.querySelectorAll('.row-add-initial'));
11907
+ dom.removeElements(tmp.querySelectorAll('.h-ruler'));
11908
+ dom.removeElements(tmp.querySelectorAll('.v-ruler'));
11907
11909
 
11908
11910
  // freeform
11909
11911
  elms = tmp.querySelectorAll('.is-block .handle, .is-block .rotate-handle');
@@ -12562,11 +12564,11 @@ const prepareSvgIcons = builder => {
12562
12564
  <path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 16.572v2.42a2.01 2.01 0 0 1 -2.009 2.008h-7.981a2.01 2.01 0 0 1 -2.01 -2.009v-7.981a2.01 2.01 0 0 1 2.009 -2.01h2.954" /><path d="M9.167 4.511a2.04 2.04 0 0 1 2.496 -1.441l7.826 2.097a2.04 2.04 0 0 1 1.441 2.496l-2.097 7.826a2.04 2.04 0 0 1 -2.496 1.441l-7.827 -2.097a2.04 2.04 0 0 1 -1.441 -2.496l2.098 -7.827z" />
12563
12565
  </symbol>
12564
12566
 
12565
- <symbol id="icon-duplicate" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
12567
+ <symbol id="icon-duplicate2" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
12566
12568
  <path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 16.572v2.42a2.01 2.01 0 0 1 -2.009 2.008h-7.981a2.01 2.01 0 0 1 -2.01 -2.009v-7.981a2.01 2.01 0 0 1 2.009 -2.01h2.954" /><path d="M9.167 4.511a2.04 2.04 0 0 1 2.496 -1.441l7.826 2.097a2.04 2.04 0 0 1 1.441 2.496l-2.097 7.826a2.04 2.04 0 0 1 -2.496 1.441l-7.827 -2.097a2.04 2.04 0 0 1 -1.441 -2.496l2.098 -7.827z" />
12567
12569
  </symbol>
12568
- <symbol id="icon-duplicate2" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
12569
- <path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 3m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z" /><path d="M17 17v2a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2h2" />
12570
+ <symbol id="icon-duplicate" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
12571
+ <path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 7m0 2.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667z" /><path d="M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1" />
12570
12572
  </symbol>
12571
12573
 
12572
12574
  <symbol id="icon-trash" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
@@ -64525,7 +64527,7 @@ class Rte {
64525
64527
  let html_elementrte = '';
64526
64528
  for (j = 0; j < builder.opts.elementButtons.length; j++) {
64527
64529
  btn = builder.opts.elementButtons[j].toLowerCase();
64528
- if (btn === 'left') html_elementrte += `<button tabindex="-1" title="${util.out('Align Left')}" data-align="left"><svg class="is-icon-flex" style="width:14px;height:14px;"><use xlink:href="#icon-align-left"></use></svg></button>`;else if (btn === 'center') html_elementrte += `<button tabindex="-1" title="${util.out('Align Center')}" data-align="center"><svg class="is-icon-flex" style="width:14px;height:14px;"><use xlink:href="#icon-align-center"></use></svg></button>`;else if (btn === 'right') html_elementrte += `<button tabindex="-1" title="${util.out('Align Right')}" data-align="right"><svg class="is-icon-flex" style="width:14px;height:14px;"><use xlink:href="#icon-align-right"></use></svg></button>`;else if (btn === 'full') html_elementrte += `<button tabindex="-1" title="${util.out('Align Full')}" data-align="justify"><svg class="is-icon-flex" style="width:14px;height:14px;"><use xlink:href="#icon-align-full"></use></svg></button>`;else if (btn === 'gridtool') html_elementrte += `<button tabindex="-1" title="${util.out('Grid Tool')}" class="rte-grideditor"><svg class="is-icon-flex" style="margin-right:-3px;width:17px;height:17px;"><use xlink:href="#ion-grid"></use></svg></button>`;else if (btn === 'html') html_elementrte += `<button tabindex="-1" title="${util.out('HTML')}" class="rte-html"><svg class="is-icon-flex" style="margin-right:-3px;width:14px;height:14px;"><use xlink:href="#ion-ios-arrow-left"></use></svg><svg class="is-icon-flex" style="margin-left:-2px;width:14px;height:14px;"><use xlink:href="#ion-ios-arrow-right"></use></svg></button>`;else if (btn === 'preferences') html_elementrte += `<button tabindex="-1" title="${util.out('Preferences')}" class="rte-preferences"><svg class="is-icon-flex" style="width:13px;height:13px;"><use xlink:href="#ion-wrench"></use></svg></button>`;else if (btn === 'addsnippet') html_elementrte += `<button tabindex="-1" title="${util.out('Add Snippet')}" class="rte-addsnippet"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#ion-ios-plus-empty"></use></svg></button>`;else if (btn === 'group') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Group')}" class="rte-group"><svg class="is-icon-flex" style="width:20px;height:20px;margin-top:-1px;"><use xlink:href="#icon-group"></use></svg></button>`;else if (btn === 'ungroup') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Ungroup')}" class="rte-ungroup"><svg class="is-icon-flex" style="width:20px;height:20px;margin-top:-1px;"><use xlink:href="#icon-ungroup"></use></svg></button>`;else if (btn === 'duplicate') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Duplicate')}" class="rte-duplicate"><svg class="is-icon-flex" style="width:20px;height:20px;margin-top:-1px;"><use xlink:href="#icon-duplicate"></use></svg></button>`;else if (btn === 'front') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Bring to Front')}" class="rte-front"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-stack-forward"></use></svg></button>`;else if (btn === 'backward') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Send to Back')}" class="rte-backward"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-stack-backward"></use></svg></button>`;else if (btn === 'moveup') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Move Up')}" class="rte-moveup"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-arrow-up"></use></svg></button>`;else if (btn === 'movedown') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Move Down')}" class="rte-movedown"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-arrow-down"></use></svg></button>`;else if (btn === 'delete') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Delete')}" class="rte-delete"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-trash"></use></svg></button>`;else if (btn === 'blocksettings' && this.builder.canvas) html_elementrte += `<button tabindex="-1" title="${util.out('Block Settings')}" class="rte-blocksettings"><svg class="is-icon-flex"><use xlink:href="#icon-settings"></use></svg></button>`;else if (btn === 'undo') html_elementrte += `<button tabindex="-1" title="${util.out('Undo')}" class="rte-undo"><svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;"><use xlink:href="#ion-ios-undo"></use></svg></button>`;else if (btn === 'redo') html_elementrte += `<button tabindex="-1" title="${util.out('Redo')}" class="rte-redo"><svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;"><use xlink:href="#ion-ios-redo"></use></svg></button>`;else if (btn === 'aiassistant') html_elementrte += `<button tabindex="-1" title="${util.out('AI Assistant')}" class="rte-ai"><svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;"><use xlink:href="#icon-message"></use></svg></button>`;else if (btn === 'snippets') html_elementrte += `<button tabindex="-1" title="${util.out('Snippets')}" class="rte-snippets"><svg class="is-icon-flex" style="width:19px;height:19px;"><use xlink:href="#icon-snippets"></use></svg></button>`;else if (btn === 'more' && html_elementrtemore !== '') html_elementrte += `<button tabindex="-1" title="${util.out('More')}" class="rte-more"><svg class="is-icon-flex" style="width:13px;height:13px;"><use xlink:href="#ion-more"></use></svg></button>`;else if (btn === 'pageoptions') html_elementrte += `<button tabindex="-1" title="${util.out('Page Options')}" class="rte-pageoptions"><svg class="is-icon-flex"><use xlink:href="#icon-pagesize"></use></svg></button>`;else if (btn === 'print') html_elementrte += `<button tabindex="-1" title="${util.out('Print')}" class="rte-print"><svg class="is-icon-flex" style="width:15px;height:15px;"><use xlink:href="#icon-print"></use></svg></button>`;else if (btn === 'zoom') html_elementrte += `<button tabindex="-1" title="${util.out('Zoom')}" class="rte-zoom"><svg class="is-icon-flex" style="margin-top:1px;width:15px;height:15px;"><use xlink:href="#icon-zoom-in"></use></svg></button>`;else if (btn === 'livepreview') html_elementrte += `<button tabindex="-1" title="${util.out('Live Preview')}" class="rte-livepreview"><svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;"><use xlink:href="#icon-device-desktop"></use></svg></button>`;else if (btn === '|') {
64530
+ if (btn === 'left') html_elementrte += `<button tabindex="-1" title="${util.out('Align Left')}" data-align="left"><svg class="is-icon-flex" style="width:14px;height:14px;"><use xlink:href="#icon-align-left"></use></svg></button>`;else if (btn === 'center') html_elementrte += `<button tabindex="-1" title="${util.out('Align Center')}" data-align="center"><svg class="is-icon-flex" style="width:14px;height:14px;"><use xlink:href="#icon-align-center"></use></svg></button>`;else if (btn === 'right') html_elementrte += `<button tabindex="-1" title="${util.out('Align Right')}" data-align="right"><svg class="is-icon-flex" style="width:14px;height:14px;"><use xlink:href="#icon-align-right"></use></svg></button>`;else if (btn === 'full') html_elementrte += `<button tabindex="-1" title="${util.out('Align Full')}" data-align="justify"><svg class="is-icon-flex" style="width:14px;height:14px;"><use xlink:href="#icon-align-full"></use></svg></button>`;else if (btn === 'gridtool') html_elementrte += `<button tabindex="-1" title="${util.out('Grid Tool')}" class="rte-grideditor"><svg class="is-icon-flex" style="margin-right:-3px;width:17px;height:17px;"><use xlink:href="#ion-grid"></use></svg></button>`;else if (btn === 'html') html_elementrte += `<button tabindex="-1" title="${util.out('HTML')}" class="rte-html"><svg class="is-icon-flex" style="margin-right:-3px;width:14px;height:14px;"><use xlink:href="#ion-ios-arrow-left"></use></svg><svg class="is-icon-flex" style="margin-left:-2px;width:14px;height:14px;"><use xlink:href="#ion-ios-arrow-right"></use></svg></button>`;else if (btn === 'preferences') html_elementrte += `<button tabindex="-1" title="${util.out('Preferences')}" class="rte-preferences"><svg class="is-icon-flex" style="width:13px;height:13px;"><use xlink:href="#ion-wrench"></use></svg></button>`;else if (btn === 'addsnippet') html_elementrte += `<button tabindex="-1" title="${util.out('Add Snippet')}" class="rte-addsnippet"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#ion-ios-plus-empty"></use></svg></button>`;else if (btn === 'group') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Group')}" class="rte-group"><svg class="is-icon-flex" style="width:20px;height:20px;margin-top:-1px;"><use xlink:href="#icon-group"></use></svg></button>`;else if (btn === 'ungroup') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Ungroup')}" class="rte-ungroup"><svg class="is-icon-flex" style="width:20px;height:20px;margin-top:-1px;"><use xlink:href="#icon-ungroup"></use></svg></button>`;else if (btn === 'duplicate') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Duplicate')}" class="rte-duplicate"><svg class="is-icon-flex" style="width:16px;height:16px;margin-top:-1px;"><use xlink:href="#icon-duplicate"></use></svg></button>`;else if (btn === 'front') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Bring to Front')}" class="rte-front"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-stack-forward"></use></svg></button>`;else if (btn === 'backward') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Send to Back')}" class="rte-backward"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-stack-backward"></use></svg></button>`;else if (btn === 'moveup') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Move Up')}" class="rte-moveup"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-arrow-up"></use></svg></button>`;else if (btn === 'movedown') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Move Down')}" class="rte-movedown"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-arrow-down"></use></svg></button>`;else if (btn === 'delete') html_elementrte += `<button style="display:none" tabindex="-1" title="${util.out('Delete')}" class="rte-delete"><svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;"><use xlink:href="#icon-trash"></use></svg></button>`;else if (btn === 'blocksettings' && this.builder.canvas) html_elementrte += `<button tabindex="-1" title="${util.out('Block Settings')}" class="rte-blocksettings"><svg class="is-icon-flex"><use xlink:href="#icon-settings"></use></svg></button>`;else if (btn === 'undo') html_elementrte += `<button tabindex="-1" title="${util.out('Undo')}" class="rte-undo"><svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;"><use xlink:href="#ion-ios-undo"></use></svg></button>`;else if (btn === 'redo') html_elementrte += `<button tabindex="-1" title="${util.out('Redo')}" class="rte-redo"><svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;"><use xlink:href="#ion-ios-redo"></use></svg></button>`;else if (btn === 'aiassistant') html_elementrte += `<button tabindex="-1" title="${util.out('AI Assistant')}" class="rte-ai"><svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;"><use xlink:href="#icon-message"></use></svg></button>`;else if (btn === 'snippets') html_elementrte += `<button tabindex="-1" title="${util.out('Snippets')}" class="rte-snippets"><svg class="is-icon-flex" style="width:19px;height:19px;"><use xlink:href="#icon-snippets"></use></svg></button>`;else if (btn === 'more' && html_elementrtemore !== '') html_elementrte += `<button tabindex="-1" title="${util.out('More')}" class="rte-more"><svg class="is-icon-flex" style="width:13px;height:13px;"><use xlink:href="#ion-more"></use></svg></button>`;else if (btn === 'pageoptions') html_elementrte += `<button tabindex="-1" title="${util.out('Page Options')}" class="rte-pageoptions"><svg class="is-icon-flex"><use xlink:href="#icon-pagesize"></use></svg></button>`;else if (btn === 'print') html_elementrte += `<button tabindex="-1" title="${util.out('Print')}" class="rte-print"><svg class="is-icon-flex" style="width:15px;height:15px;"><use xlink:href="#icon-print"></use></svg></button>`;else if (btn === 'zoom') html_elementrte += `<button tabindex="-1" title="${util.out('Zoom')}" class="rte-zoom"><svg class="is-icon-flex" style="margin-top:1px;width:15px;height:15px;"><use xlink:href="#icon-zoom-in"></use></svg></button>`;else if (btn === 'livepreview') html_elementrte += `<button tabindex="-1" title="${util.out('Live Preview')}" class="rte-livepreview"><svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;"><use xlink:href="#icon-device-desktop"></use></svg></button>`;else if (btn === '|') {
64529
64531
  html_elementrte += '<div class="rte-separator"></div>';
64530
64532
  } else {
64531
64533
  html_elementrte += `<button tabindex="-1" title="button not found" data-plugin="${btn}"></button>`; //temporary (later will be replaced with plugin button)
@@ -64701,6 +64703,9 @@ class Rte {
64701
64703
  <div style="padding-top:4px">
64702
64704
  <input type="range" min="50" max="${zoomMax}" value="1" class="rte-zoom-slider is-rangeslider">
64703
64705
  </div>
64706
+ <div style="display:flex;justify-content:flex-end">
64707
+ <button title="${util.out('Reset')}" class="reset-zoom" style="background:transparent;padding:0;height:27px;text-decoration:underline">${util.out('Reset')}</button>
64708
+ </div>
64704
64709
  </div>
64705
64710
  </div>
64706
64711
 
@@ -65879,6 +65884,16 @@ class Rte {
65879
65884
  showTools();
65880
65885
  });
65881
65886
 
65887
+ // Reset Zoom
65888
+ const btnResetZoom = builderStuff.querySelector('.reset-zoom');
65889
+ btnResetZoom.addEventListener('click', () => {
65890
+ this.builder.opts.zoom = 1;
65891
+ localStorage.setItem('_zoom', 1); // Save
65892
+
65893
+ // setZoomOnArea
65894
+ this.builder.setZoomOnArea();
65895
+ });
65896
+
65882
65897
  // Zoom Modal
65883
65898
  this.inpZoomSlider.onfocus = () => {
65884
65899
  if (this.builder.onZoomStart) {
@@ -73397,7 +73412,6 @@ class ContentStuff {
73397
73412
  <button title="${util.out('Settings')}" data-title="${util.out('Settings')}" style="width:37px;height:37px;background:none;"><svg class="is-icon-flex"><use xlink:href="#ion-ios-gear"></use></svg></button>
73398
73413
  </div>
73399
73414
 
73400
-
73401
73415
  <div class="is-locked-indicator">
73402
73416
  <svg class="is-icon-flex"><use xlink:href="#icon-lock"></use></svg>
73403
73417
  </div>
@@ -73891,6 +73905,35 @@ class ContentStuff {
73891
73905
  }
73892
73906
  .is-tool.is-element-tool .elm-settings { display: none; }
73893
73907
 
73908
+ /* is-block-tool
73909
+
73910
+ .is-tool.is-block-tool {
73911
+ background: rgba(243, 243, 243, 0.9);
73912
+ border-radius: 3px;
73913
+ overflow: hidden;
73914
+ top: 3px;
73915
+ right: 3px;
73916
+ left: auto;
73917
+ width: 25px;
73918
+ }
73919
+ .is-tool.is-block-tool button {
73920
+ width: 25px;
73921
+ height: 25px;
73922
+ background: transparent;
73923
+ display: flex;
73924
+ align-items: center;
73925
+ justify-content: center;
73926
+ }
73927
+ .is-tool.is-block-tool svg {
73928
+ width: 14px;
73929
+ height: 14px;
73930
+ fill: #000;
73931
+ }
73932
+ .is-block.active:not(.multi):not(.editable) .is-block-tool {
73933
+ display:flex;
73934
+ }
73935
+ */
73936
+
73894
73937
  /* is-column-tool */
73895
73938
 
73896
73939
  .is-tool.is-column-tool {
@@ -81759,7 +81802,25 @@ class Common {
81759
81802
  applyPercentage(block) {
81760
81803
  const zoom = this.zoom;
81761
81804
  const rect = this.getRect(block);
81762
- const container = block.parentNode;
81805
+ const container = block.closest('.box-canvas');
81806
+ const containerRect = this.getRect(container); // if container has top/left
81807
+
81808
+ this.horizontalRulerTop = container.querySelector('.h-ruler-top');
81809
+ this.horizontalRulerBottom = container.querySelector('.h-ruler-bottom');
81810
+ this.horizontalRulerMiddle = container.querySelector('.h-ruler-middle');
81811
+ this.verticalRulerLeft = container.querySelector('.v-ruler-left');
81812
+ this.verticalRulerRight = container.querySelector('.v-ruler-right');
81813
+ this.verticalRulerCenter = container.querySelector('.v-ruler-center');
81814
+
81815
+ // Check Edges
81816
+ let topTouched = false;
81817
+ let bottomTouched = false;
81818
+ let leftTouched = false;
81819
+ let rightTouched = false;
81820
+ if (this.horizontalRulerTop.hasAttribute('data-topTouched')) topTouched = true;
81821
+ if (this.horizontalRulerBottom.hasAttribute('data-bottomTouched')) bottomTouched = true;
81822
+ if (this.verticalRulerLeft.hasAttribute('data-leftTouched')) leftTouched = true;
81823
+ if (this.verticalRulerRight.hasAttribute('data-rightTouched')) rightTouched = true;
81763
81824
  let isChildBlock = false;
81764
81825
  if (block.parentNode.matches(this.selector)) {
81765
81826
  // child block
@@ -81767,7 +81828,7 @@ class Common {
81767
81828
  }
81768
81829
 
81769
81830
  // const containerRect = container.getBoundingClientRect(); // if container has top/left
81770
- const containerRect = this.getRect(container); // if container has top/left
81831
+ // const containerRect = this.getRect(container); // if container has top/left
81771
81832
  let left = (rect.left - containerRect.left) / container.offsetWidth * 100;
81772
81833
  let top = (rect.top - containerRect.top) / container.offsetHeight * 100;
81773
81834
  let isBlockFixed = block.classList.contains('block-steady');
@@ -81806,6 +81867,35 @@ class Common {
81806
81867
  block.style.left = left / zoom + '%';
81807
81868
  if (block.classList.contains('height-auto')) block.style.height = '';
81808
81869
  }
81870
+
81871
+ // Check
81872
+
81873
+ block.style.right = ''; //reset
81874
+ block.style.bottom = ''; //reset
81875
+
81876
+ if (topTouched) block.style.top = 0;
81877
+ // if(topTouched && bottomTouched) block.style.height = '100%';
81878
+ if (leftTouched) block.style.left = 0;
81879
+ // if(leftTouched && rightTouched) block.style.width = '100%';
81880
+
81881
+ if (topTouched && bottomTouched) {
81882
+ block.style.top = 0;
81883
+ block.style.bottom = 0;
81884
+ block.style.height = '';
81885
+ }
81886
+ if (leftTouched && rightTouched) {
81887
+ block.style.left = 0;
81888
+ block.style.right = 0;
81889
+ block.style.width = '';
81890
+ }
81891
+ if (bottomTouched && !topTouched) {
81892
+ block.style.bottom = 0;
81893
+ block.style.height = '';
81894
+ }
81895
+ if (rightTouched && !leftTouched) {
81896
+ block.style.right = 0;
81897
+ block.style.width = '';
81898
+ }
81809
81899
  }
81810
81900
  applyPixels(block) {
81811
81901
  const zoom = this.zoom;
@@ -81960,15 +82050,16 @@ class Common {
81960
82050
  right = Math.max(right, blockLeft + blockWidth);
81961
82051
  }
81962
82052
  });
82053
+ const container = blocks[0].parentNode;
82054
+ const containerRect = this.getRect(container);
81963
82055
  const group = this.doc.createElement('div');
81964
82056
  group.classList.add(className);
81965
82057
  group.classList.add(groupClassName);
81966
82058
  group.classList.add('block-steady');
81967
- group.style.top = top + 'px';
81968
- group.style.left = left + 'px';
82059
+ group.style.top = top - containerRect.top + 'px';
82060
+ group.style.left = left - containerRect.left + 'px';
81969
82061
  group.style.width = right + 1 - left + 'px';
81970
82062
  group.style.height = bottom + 1 - top + 'px';
81971
- const container = blocks[0].parentNode;
81972
82063
  container.appendChild(group);
81973
82064
  blocks.forEach(block => {
81974
82065
  if (!block.parentNode.matches(this.selector)) {
@@ -81977,8 +82068,8 @@ class Common {
81977
82068
  let blockLeft = parseFloat(block.style.left) || 0;
81978
82069
 
81979
82070
  // Adjust position relative to the group div
81980
- block.style.top = blockTop - top + 'px';
81981
- block.style.left = blockLeft - left + 'px';
82071
+ block.style.top = blockTop - top + containerRect.top + 'px';
82072
+ block.style.left = blockLeft - left + containerRect.left + 'px';
81982
82073
  group.appendChild(block);
81983
82074
  this.applyPercentage(block);
81984
82075
  }
@@ -82033,14 +82124,15 @@ class Common {
82033
82124
  const top = rect.top;
82034
82125
  const left = rect.left;
82035
82126
  const container = group.parentNode;
82127
+ const containerRect = this.getRect(container);
82036
82128
  group.querySelectorAll(this.selector).forEach(block => {
82037
82129
  this.applyPixels(block);
82038
82130
  let blockTop = parseFloat(block.style.top) || 0;
82039
82131
  let blockLeft = parseFloat(block.style.left) || 0;
82040
82132
 
82041
82133
  // Adjust position relative to the group div
82042
- block.style.top = blockTop + top + 'px';
82043
- block.style.left = blockLeft + left + 'px';
82134
+ block.style.top = blockTop + top - containerRect.top + 'px';
82135
+ block.style.left = blockLeft + left - containerRect.left + 'px';
82044
82136
  container.appendChild(block);
82045
82137
 
82046
82138
  // Remove all breakpoints
@@ -82252,10 +82344,23 @@ class Ruler {
82252
82344
  this.zoom = scale;
82253
82345
  }
82254
82346
  setup() {
82255
- this.elements = this.doc.querySelectorAll(this.selector);
82347
+ // this.elements = this.doc.querySelectorAll(this.selector);
82348
+ this.refresh();
82256
82349
  }
82257
82350
  refresh() {
82258
82351
  this.elements = this.doc.querySelectorAll(this.selector);
82352
+ const rulerHTML = `
82353
+ <div class="ruler h-ruler h-ruler-top""></div>
82354
+ <div class="ruler h-ruler h-ruler-bottom"></div>
82355
+ <div class="ruler h-ruler h-ruler-middle"></div>
82356
+ <div class="ruler v-ruler v-ruler-left"></div>
82357
+ <div class="ruler v-ruler v-ruler-right"></div>
82358
+ <div class="ruler v-ruler v-ruler-center"></div>
82359
+ `;
82360
+ const containers = this.doc.querySelectorAll('.box-canvas');
82361
+ containers.forEach(container => {
82362
+ if (!container.querySelector('.h-ruler-top')) container.insertAdjacentHTML('beforeend', rulerHTML);
82363
+ });
82259
82364
  }
82260
82365
  destroy() {
82261
82366
  [this.horizontalRulerTop, this.horizontalRulerBottom, this.verticalRulerLeft, this.verticalRulerRight].forEach(elm => {
@@ -82263,6 +82368,18 @@ class Ruler {
82263
82368
  });
82264
82369
  }
82265
82370
  hideRulers() {
82371
+ this.horizontalRulerTop.classList.remove('active');
82372
+ this.horizontalRulerBottom.classList.remove('active');
82373
+ this.horizontalRulerMiddle.classList.remove('active');
82374
+ this.verticalRulerLeft.classList.remove('active');
82375
+ this.verticalRulerRight.classList.remove('active');
82376
+ this.verticalRulerCenter.classList.remove('active');
82377
+ this.rulerTop = null;
82378
+ this.rulerBottom = null; //new
82379
+ this.rulerLeft = null;
82380
+ this.rulerRight = null;
82381
+ }
82382
+ hideRulers_bak() {
82266
82383
  this.horizontalRulerTop.style.top = '-1000px';
82267
82384
  this.horizontalRulerBottom.style.top = '-1000px';
82268
82385
  this.horizontalRulerMiddle.style.top = '-1000px';
@@ -82270,10 +82387,207 @@ class Ruler {
82270
82387
  this.verticalRulerRight.style.left = '-1000px';
82271
82388
  this.verticalRulerCenter.style.left = '-1000px';
82272
82389
  this.rulerTop = null;
82390
+ this.rulerBottom = null; //new
82273
82391
  this.rulerLeft = null;
82274
82392
  this.rulerRight = null;
82275
82393
  }
82276
82394
  updateRulers(block) {
82395
+ const container = block.closest('.box-canvas');
82396
+ this.horizontalRulerTop = container.querySelector('.h-ruler-top');
82397
+ this.horizontalRulerBottom = container.querySelector('.h-ruler-bottom');
82398
+ this.horizontalRulerMiddle = container.querySelector('.h-ruler-middle');
82399
+ this.verticalRulerLeft = container.querySelector('.v-ruler-left');
82400
+ this.verticalRulerRight = container.querySelector('.v-ruler-right');
82401
+ this.verticalRulerCenter = container.querySelector('.v-ruler-center');
82402
+ let transform = block.style.transform;
82403
+ if (transform.includes('rotate') || transform.includes('matrix3d')) return;
82404
+ let parentTransform = block.parentNode.style.transform;
82405
+ if (parentTransform.includes('rotate')) return;
82406
+ this.hideRulers();
82407
+ const top = block.offsetTop;
82408
+ const bottom = top + block.offsetHeight;
82409
+ const left = block.offsetLeft;
82410
+ const right = left + block.offsetWidth;
82411
+ const center = left + block.offsetWidth / 2;
82412
+ const middle = top + block.offsetHeight / 2;
82413
+ this.rulerTop = null;
82414
+ this.rulerBottom = null; //new
82415
+ this.rulerLeft = null;
82416
+ this.rulerRight = null;
82417
+ this.elements = container.querySelectorAll(this.selector);
82418
+ this.elements.forEach(element => {
82419
+ if (!this.doc.body.contains(element)) return; // in case element removed (eg. unGroup, block deleted)
82420
+
82421
+ if (block.contains(element)) return; // In case of group moving
82422
+
82423
+ let transform = element.style.transform;
82424
+ let parentTransform = element.parentNode.style.transform;
82425
+ if (!transform.includes('rotate') && !parentTransform.includes('rotate') && !transform.includes('matrix3d') && !parentTransform.includes('matrix3d') && element !== block && !element.classList.contains('cloned')) {
82426
+ const otherTop = element.offsetTop;
82427
+ const otherBottom = otherTop + element.offsetHeight;
82428
+ const otherLeft = element.offsetLeft;
82429
+ const otherRight = otherLeft + element.offsetWidth;
82430
+ const otherMiddle = otherTop + element.offsetHeight / 2;
82431
+ const otherCenter = otherLeft + element.offsetWidth / 2;
82432
+
82433
+ // block top
82434
+ if (otherTop - 4 <= top && top <= otherTop + 4) {
82435
+ this.horizontalRulerTop.style.top = otherTop + 'px';
82436
+ this.horizontalRulerTop.classList.add('active');
82437
+ let val = otherTop;
82438
+ if (this.rulerTop === null) this.rulerTop = val;
82439
+ }
82440
+ if (otherBottom - 4 <= top && top <= otherBottom + 4) {
82441
+ this.horizontalRulerTop.style.top = otherBottom + 'px';
82442
+ this.horizontalRulerTop.classList.add('active');
82443
+ let val = otherBottom;
82444
+ if (this.rulerTop === null) this.rulerTop = val;
82445
+ }
82446
+
82447
+ // block bottom
82448
+ if (otherTop - 4 <= bottom && bottom <= otherTop + 4) {
82449
+ /*
82450
+ _____
82451
+ ___________________|__x__|__ rulerBottom
82452
+ | other |
82453
+ */
82454
+ this.horizontalRulerBottom.style.top = otherTop + 'px';
82455
+ this.horizontalRulerBottom.classList.add('active');
82456
+ if (this.rulerBottom === null) this.rulerBottom = element.offsetTop; // new
82457
+ }
82458
+
82459
+ if (otherBottom - 4 <= bottom && bottom <= otherBottom + 4) {
82460
+ /*
82461
+ _____
82462
+ | other |__________|__x__|__ rulerBottom
82463
+
82464
+ */
82465
+ this.horizontalRulerBottom.style.top = otherBottom + 'px';
82466
+ this.horizontalRulerBottom.classList.add('active');
82467
+ if (this.rulerBottom === null) this.rulerBottom = element.offsetTop + element.offsetHeight; // new
82468
+ }
82469
+
82470
+ // block middle
82471
+ if (this.rulerTop === null && this.rulerBottom === null) {
82472
+ if (otherMiddle - 4 <= middle && middle <= otherMiddle + 4) {
82473
+ this.horizontalRulerMiddle.style.top = otherTop + (element.offsetHeight - block.offsetHeight) / 2 + block.offsetHeight / 2 + 'px';
82474
+ this.horizontalRulerMiddle.classList.add('active');
82475
+ let val = otherTop + (element.offsetHeight - block.offsetHeight) / 2;
82476
+ if (this.rulerTop === null) this.rulerTop = val;
82477
+ }
82478
+ }
82479
+
82480
+ // block left
82481
+ if (otherLeft - 4 <= left && left <= otherLeft + 4) {
82482
+ this.verticalRulerLeft.style.left = otherLeft + 'px';
82483
+ this.verticalRulerLeft.classList.add('active');
82484
+ let val = otherLeft;
82485
+ if (this.rulerLeft === null) this.rulerLeft = val;
82486
+ }
82487
+ if (otherRight - 4 <= left && left <= otherRight + 4) {
82488
+ this.verticalRulerLeft.style.left = otherRight + 'px';
82489
+ this.verticalRulerLeft.classList.add('active');
82490
+ let val = otherRight;
82491
+ if (this.rulerLeft === null) this.rulerLeft = val;
82492
+ }
82493
+
82494
+ // block right
82495
+ if (otherLeft - 4 <= right && right <= otherLeft + 4) {
82496
+ this.verticalRulerRight.style.left = otherLeft + 'px';
82497
+ this.verticalRulerRight.classList.add('active');
82498
+ let val = otherLeft;
82499
+ if (this.rulerRight === null) this.rulerRight = val;
82500
+ }
82501
+ if (otherRight - 4 <= right && right <= otherRight + 4) {
82502
+ this.verticalRulerRight.style.left = otherRight + 'px';
82503
+ this.verticalRulerRight.classList.add('active');
82504
+ let val = otherRight;
82505
+ if (this.rulerRight === null) this.rulerRight = val;
82506
+ }
82507
+
82508
+ // block center
82509
+ if (this.rulerLeft === null && this.rulerRight === null) {
82510
+ if (otherCenter - 4 <= center && center <= otherCenter + 4) {
82511
+ this.verticalRulerCenter.style.left = otherLeft + (element.offsetWidth - block.offsetWidth) / 2 + block.offsetWidth / 2 + 'px';
82512
+ this.verticalRulerCenter.classList.add('active');
82513
+ let val = otherLeft + (element.offsetWidth - block.offsetWidth) / 2;
82514
+ if (this.rulerLeft === null) this.rulerLeft = val;
82515
+ }
82516
+ }
82517
+ }
82518
+ });
82519
+
82520
+ // Edges
82521
+ const conTop = 0;
82522
+ const conBottom = container.offsetHeight;
82523
+ const conLeft = 0;
82524
+ const conRight = container.offsetWidth;
82525
+ const conCenter = container.offsetWidth / 2;
82526
+ const conMiddle = container.offsetHeight / 2;
82527
+
82528
+ // block top
82529
+ this.horizontalRulerTop.removeAttribute('data-topTouched');
82530
+ if (conTop - 4 <= top && top <= conTop + 4) {
82531
+ this.horizontalRulerTop.style.top = conTop + 'px';
82532
+ this.horizontalRulerTop.classList.add('active');
82533
+ let val = conTop;
82534
+ if (this.rulerTop === null) this.rulerTop = val;
82535
+ this.topTouched = true;
82536
+ this.horizontalRulerTop.setAttribute('data-topTouched', 1);
82537
+ }
82538
+
82539
+ // block bottom
82540
+ this.horizontalRulerBottom.removeAttribute('data-bottomTouched');
82541
+ if (conBottom - 4 <= bottom && bottom <= conBottom + 4) {
82542
+ this.horizontalRulerBottom.style.top = conBottom - 2 + 'px'; // -2 is an adjustment to make the line visible
82543
+ this.horizontalRulerBottom.classList.add('active');
82544
+ if (this.rulerBottom === null) this.rulerBottom = conBottom; //conRect.height;// or block.parentNode.offsetHeight; // new
82545
+
82546
+ this.bottomTouched = true;
82547
+ this.horizontalRulerBottom.setAttribute('data-bottomTouched', 1);
82548
+ }
82549
+
82550
+ // block middle
82551
+ if (this.rulerTop === null && this.rulerBottom === null) {
82552
+ if (conMiddle - 4 <= middle && middle <= conMiddle + 4) {
82553
+ this.horizontalRulerMiddle.style.top = conTop + (block.parentNode.offsetHeight - block.offsetHeight) / 2 + block.offsetHeight / 2 + 'px';
82554
+ this.horizontalRulerMiddle.classList.add('active');
82555
+ let val = conTop + (block.parentNode.offsetHeight - block.offsetHeight) / 2;
82556
+ if (this.rulerTop === null) this.rulerTop = val;
82557
+ }
82558
+ }
82559
+
82560
+ // block left
82561
+ this.verticalRulerLeft.removeAttribute('data-leftTouched');
82562
+ if (conLeft - 4 <= left && left <= conLeft + 4) {
82563
+ this.verticalRulerLeft.style.left = conLeft + 0 + 'px'; // +0 is an adjustment
82564
+ this.verticalRulerLeft.classList.add('active');
82565
+ let val = conLeft;
82566
+ if (this.rulerLeft === null) this.rulerLeft = val;
82567
+ this.verticalRulerLeft.setAttribute('data-leftTouched', 1);
82568
+ }
82569
+
82570
+ // block right
82571
+ this.verticalRulerRight.removeAttribute('data-rightTouched');
82572
+ if (conRight - 4 <= right && right <= conRight + 4) {
82573
+ this.verticalRulerRight.style.left = conRight - 2 + 'px'; // -2 is an adjustment
82574
+ this.verticalRulerRight.classList.add('active');
82575
+ let val = conRight;
82576
+ if (this.rulerRight === null) this.rulerRight = val;
82577
+ this.verticalRulerRight.setAttribute('data-rightTouched', 1);
82578
+ }
82579
+
82580
+ // block center
82581
+ if (this.rulerLeft === null && this.rulerRight === null) {
82582
+ if (conCenter - 4 <= center && center <= conCenter + 4) {
82583
+ this.verticalRulerCenter.style.left = conLeft + (block.parentNode.offsetWidth - block.offsetWidth) / 2 + block.offsetWidth / 2 + 'px';
82584
+ this.verticalRulerCenter.classList.add('active');
82585
+ let val = conLeft + (block.parentNode.offsetWidth - block.offsetWidth) / 2;
82586
+ if (this.rulerLeft === null) this.rulerLeft = val;
82587
+ }
82588
+ }
82589
+ }
82590
+ updateRulers_bak(block) {
82277
82591
  // if(block.querySelector(this.selector)) return; // group (because updateRules also calls parent group if child block is dragged)
82278
82592
 
82279
82593
  let transform = block.style.transform;
@@ -82291,6 +82605,7 @@ class Ruler {
82291
82605
  const center = left + block.offsetWidth / 2;
82292
82606
  const middle = top + block.offsetHeight / 2;
82293
82607
  this.rulerTop = null;
82608
+ this.rulerBottom = null; //new
82294
82609
  this.rulerLeft = null;
82295
82610
  this.rulerRight = null;
82296
82611
  let containerTop = 0;
@@ -82314,18 +82629,6 @@ class Ruler {
82314
82629
  const otherRight = rect.left + element.offsetWidth;
82315
82630
  const otherMiddle = rect.top + element.offsetHeight / 2;
82316
82631
  const otherCenter = rect.left + element.offsetWidth / 2;
82317
- if (otherMiddle - 4 <= middle && middle <= otherMiddle + 4) {
82318
- this.horizontalRulerMiddle.style.top = containerTop + otherTop + (element.offsetHeight - block.offsetHeight) / 2 + block.offsetHeight / 2 + 'px';
82319
- let val = otherTop + (element.offsetHeight - block.offsetHeight) / 2;
82320
- if (this.rulerTop === null) this.rulerTop = val;
82321
- }
82322
- if (otherCenter - 4 <= center && center <= otherCenter + 4) {
82323
- this.verticalRulerCenter.style.left = otherLeft + (element.offsetWidth - block.offsetWidth) / 2 + block.offsetWidth / 2 + 'px';
82324
- this.verticalRulerCenter.style.top = containerTop + 'px'; // adj
82325
-
82326
- let val = otherLeft + (element.offsetWidth - block.offsetWidth) / 2;
82327
- if (this.rulerLeft === null) this.rulerLeft = val;
82328
- }
82329
82632
 
82330
82633
  // block top
82331
82634
  if (otherTop - 4 <= top && top <= otherTop + 4) {
@@ -82341,14 +82644,38 @@ class Ruler {
82341
82644
 
82342
82645
  // block bottom
82343
82646
  if (otherTop - 4 <= bottom && bottom <= otherTop + 4) {
82647
+ /*
82648
+ _____
82649
+ ___________________|__x__|__ rulerBottom
82650
+ | other |
82651
+ */
82344
82652
  this.horizontalRulerBottom.style.top = containerTop + otherTop + 'px';
82345
- let val = otherTop - block.offsetHeight;
82346
- if (this.rulerTop === null) this.rulerTop = val;
82653
+
82654
+ // let val = otherTop - block.offsetHeight;
82655
+ // if(this.rulerTop===null) this.rulerTop = val;
82656
+ if (this.rulerBottom === null) this.rulerBottom = element.offsetTop; // new
82347
82657
  }
82658
+
82348
82659
  if (otherBottom - 4 <= bottom && bottom <= otherBottom + 4) {
82660
+ /*
82661
+ _____
82662
+ | other |__________|__x__|__ rulerBottom
82663
+
82664
+ */
82349
82665
  this.horizontalRulerBottom.style.top = containerTop + otherBottom + 'px';
82350
- let val = otherBottom - block.offsetHeight;
82351
- if (this.rulerTop === null) this.rulerTop = val;
82666
+
82667
+ // let val = otherBottom - block.offsetHeight;
82668
+ // if(this.rulerTop===null) this.rulerTop = val;
82669
+ if (this.rulerBottom === null) this.rulerBottom = element.offsetTop + element.offsetHeight; // new
82670
+ }
82671
+
82672
+ // block middle
82673
+ if (this.rulerTop === null && this.rulerBottom === null) {
82674
+ if (otherMiddle - 4 <= middle && middle <= otherMiddle + 4) {
82675
+ this.horizontalRulerMiddle.style.top = containerTop + otherTop + (element.offsetHeight - block.offsetHeight) / 2 + block.offsetHeight / 2 + 'px';
82676
+ let val = otherTop + (element.offsetHeight - block.offsetHeight) / 2;
82677
+ if (this.rulerTop === null) this.rulerTop = val;
82678
+ }
82352
82679
  }
82353
82680
 
82354
82681
  // block left
@@ -82382,6 +82709,17 @@ class Ruler {
82382
82709
  let val = otherRight;
82383
82710
  if (this.rulerRight === null) this.rulerRight = val;
82384
82711
  }
82712
+
82713
+ // block center
82714
+ if (this.rulerLeft === null && this.rulerRight === null) {
82715
+ if (otherCenter - 4 <= center && center <= otherCenter + 4) {
82716
+ this.verticalRulerCenter.style.left = otherLeft + (element.offsetWidth - block.offsetWidth) / 2 + block.offsetWidth / 2 + 'px';
82717
+ this.verticalRulerCenter.style.top = containerTop + 'px'; // adj
82718
+
82719
+ let val = otherLeft + (element.offsetWidth - block.offsetWidth) / 2;
82720
+ if (this.rulerLeft === null) this.rulerLeft = val;
82721
+ }
82722
+ }
82385
82723
  }
82386
82724
  });
82387
82725
 
@@ -82393,44 +82731,69 @@ class Ruler {
82393
82731
  const conRight = conRect.left + block.parentNode.offsetWidth;
82394
82732
  const conCenter = conRect.left + block.parentNode.offsetWidth / 2;
82395
82733
  const conMiddle = conRect.top + block.parentNode.offsetHeight / 2;
82396
- if (conMiddle - 4 <= middle && middle <= conMiddle + 4) {
82397
- this.horizontalRulerMiddle.style.top = containerTop + conTop + (block.parentNode.offsetHeight - block.offsetHeight) / 2 + block.offsetHeight / 2 + 'px';
82398
- let val = conTop + (block.parentNode.offsetHeight - block.offsetHeight) / 2;
82399
- if (this.rulerTop === null) this.rulerTop = val;
82400
- }
82401
- if (conCenter - 4 <= center && center <= conCenter + 4) {
82402
- this.verticalRulerCenter.style.left = conLeft + (block.parentNode.offsetWidth - block.offsetWidth) / 2 + block.offsetWidth / 2 + 'px';
82403
- this.verticalRulerCenter.style.top = containerTop + 'px';
82404
- let val = conLeft + (block.parentNode.offsetWidth - block.offsetWidth) / 2;
82405
- if (this.rulerLeft === null) this.rulerLeft = val;
82406
- }
82407
82734
 
82408
82735
  // block top
82736
+ this.horizontalRulerTop.removeAttribute('data-topTouched');
82409
82737
  if (conTop - 4 <= top && top <= conTop + 4) {
82410
82738
  this.horizontalRulerTop.style.top = containerTop + conTop + 'px';
82411
82739
  let val = conTop;
82412
82740
  if (this.rulerTop === null) this.rulerTop = val;
82741
+ this.topTouched = true;
82742
+ this.horizontalRulerTop.setAttribute('data-topTouched', 1);
82413
82743
  }
82744
+
82414
82745
  // block bottom
82746
+ this.horizontalRulerBottom.removeAttribute('data-bottomTouched');
82415
82747
  if (conBottom - 4 <= bottom && bottom <= conBottom + 4) {
82416
- this.horizontalRulerBottom.style.top = containerTop + conBottom - 3 + 'px'; // -3 is an adjustment to make the line visible
82748
+ this.horizontalRulerBottom.style.top = containerTop + conBottom - 2 + 'px'; // -2 is an adjustment to make the line visible
82417
82749
 
82418
- let val = conBottom - block.offsetHeight;
82419
- if (this.rulerTop === null) this.rulerTop = val;
82750
+ // let val = conBottom - block.offsetHeight;
82751
+ // if(this.rulerTop===null) this.rulerTop = val;
82752
+ if (this.rulerBottom === null) this.rulerBottom = conRect.height; // or block.parentNode.offsetHeight; // new
82753
+
82754
+ this.bottomTouched = true;
82755
+ this.horizontalRulerBottom.setAttribute('data-bottomTouched', 1);
82420
82756
  }
82757
+
82758
+ // block middle
82759
+ if (this.rulerTop === null && this.rulerBottom === null) {
82760
+ if (conMiddle - 4 <= middle && middle <= conMiddle + 4) {
82761
+ this.horizontalRulerMiddle.style.top = containerTop + conTop + (block.parentNode.offsetHeight - block.offsetHeight) / 2 + block.offsetHeight / 2 + 'px';
82762
+ let val = conTop + (block.parentNode.offsetHeight - block.offsetHeight) / 2;
82763
+ if (this.rulerTop === null) this.rulerTop = val;
82764
+ }
82765
+ }
82766
+
82421
82767
  // block left
82768
+ this.verticalRulerLeft.removeAttribute('data-leftTouched');
82422
82769
  if (conLeft - 4 <= left && left <= conLeft + 4) {
82423
- this.verticalRulerLeft.style.left = conLeft + 2 + 'px'; // +3 is an adjustment
82424
- this.verticalRulerLeft.style.top = containerTop + 'px';
82770
+ this.verticalRulerLeft.style.left = conLeft + 0 + 'px'; // +0 is an adjustment
82771
+ this.verticalRulerLeft.style.top = containerTop + 'px'; // adj
82772
+
82425
82773
  let val = conLeft;
82426
82774
  if (this.rulerLeft === null) this.rulerLeft = val;
82775
+ this.verticalRulerLeft.setAttribute('data-leftTouched', 1);
82427
82776
  }
82777
+
82428
82778
  // block right
82779
+ this.verticalRulerRight.removeAttribute('data-rightTouched');
82429
82780
  if (conRight - 4 <= right && right <= conRight + 4) {
82430
82781
  this.verticalRulerRight.style.left = conRight - 2 + 'px'; // -2 is an adjustment
82431
- this.verticalRulerRight.style.top = containerTop + 'px';
82782
+ this.verticalRulerRight.style.top = containerTop + 'px'; // adj
82783
+
82432
82784
  let val = conRight;
82433
82785
  if (this.rulerRight === null) this.rulerRight = val;
82786
+ this.verticalRulerRight.setAttribute('data-rightTouched', 1);
82787
+ }
82788
+
82789
+ // block center
82790
+ if (this.rulerLeft === null && this.rulerRight === null) {
82791
+ if (conCenter - 4 <= center && center <= conCenter + 4) {
82792
+ this.verticalRulerCenter.style.left = conLeft + (block.parentNode.offsetWidth - block.offsetWidth) / 2 + block.offsetWidth / 2 + 'px';
82793
+ this.verticalRulerCenter.style.top = containerTop + 'px';
82794
+ let val = conLeft + (block.parentNode.offsetWidth - block.offsetWidth) / 2;
82795
+ if (this.rulerLeft === null) this.rulerLeft = val;
82796
+ }
82434
82797
  }
82435
82798
  }
82436
82799
  }
@@ -82905,38 +83268,131 @@ class Resizable {
82905
83268
  }
82906
83269
 
82907
83270
  // Replace with ruler's alignment
82908
- if (this.ruler.rulerTop !== null) {
82909
- target.style.top = this.ruler.rulerTop + 'px';
82910
- // if container has top/left
82911
- if (target.parentNode.matches(this.selector)) {
82912
- const containerRect = target.parentNode.getBoundingClientRect();
82913
- target.style.top = this.ruler.rulerTop - containerRect.top + 'px';
83271
+
83272
+ if (this.resizeHandle.includes('top')) {
83273
+ if (this.ruler.rulerTop !== null) {
83274
+ //bottom fixed
83275
+ let targetBottom = target.offsetTop + target.offsetHeight;
83276
+ target.style.top = this.ruler.rulerTop + 'px';
83277
+ target.style.height = targetBottom - this.ruler.rulerTop + 'px';
82914
83278
  }
82915
83279
  }
82916
-
82917
- // If resizing by dragging the right corners (top or bottom)
82918
- if (this.resizeHandle === 'top-right' || this.resizeHandle === 'bottom-right' || this.resizeHandle === 'right') {
82919
- // Check if vertical right ruler visible (has value)
83280
+ if (this.resizeHandle.includes('bottom')) {
83281
+ if (this.ruler.rulerBottom !== null) {
83282
+ // top fixed
83283
+ target.style.height = this.ruler.rulerBottom - target.offsetTop + 'px';
83284
+ }
83285
+ }
83286
+ if (this.resizeHandle.includes('left')) {
83287
+ if (this.ruler.rulerLeft !== null) {
83288
+ //right fixed
83289
+ let targetRight = target.offsetLeft + target.offsetWidth;
83290
+ target.style.left = this.ruler.rulerLeft + 'px';
83291
+ target.style.width = targetRight - this.ruler.rulerLeft + 'px';
83292
+ }
83293
+ }
83294
+ if (this.resizeHandle.includes('right')) {
82920
83295
  if (this.ruler.rulerRight !== null) {
82921
- // If so, keep the left position
82922
- // target.style.left = newLeft + 'px';
83296
+ //left fixed
83297
+ target.style.width = this.ruler.rulerRight - target.offsetLeft + 'px';
83298
+ }
83299
+ }
82923
83300
 
82924
- // And update the width to align with vertical right ruler
82925
- const rect = target.getBoundingClientRect();
82926
- target.style.width = this.ruler.rulerRight - rect.left + 'px';
83301
+ // Convert px to %
83302
+ this.common.applyPercentage(target);
83303
+ setTimeout(() => {
83304
+ const breakpoint = this.doc.body.getAttribute('data-breakpoint');
83305
+
83306
+ // const screenWidth = window.innerWidth;
83307
+ // let defaultPoint;
83308
+ // if(screenWidth<=1920) {
83309
+ // defaultPoint = 1366;
83310
+ // } else {
83311
+ // defaultPoint = 1900;
83312
+ // }
83313
+
83314
+ let largeScreenBreakpoint = 1280; //1920
83315
+ largeScreenBreakpoint = window.innerWidth - 360; //351
83316
+ if (largeScreenBreakpoint < 1280) largeScreenBreakpoint = 1280;
83317
+ let isPrint = false;
83318
+ let elmBox = target.closest('[data-pagesize]');
83319
+ if (elmBox) {
83320
+ if (elmBox.getAttribute('data-pagesize').includes('web')) ; else {
83321
+ isPrint = true;
83322
+ }
82927
83323
  }
82928
- } else if (this.resizeHandle === 'top-left' || this.resizeHandle === 'bottom-left' || this.resizeHandle === 'left') {
82929
- if (this.ruler.rulerLeft !== null) {
82930
- const currentRight = this.initialLeft + this.initialWidth;
83324
+ if (isPrint) {
83325
+ target.setAttribute('data--t', target.style.top);
83326
+ target.setAttribute('data--l', target.style.left);
83327
+ target.setAttribute('data--b', target.style.bottom);
83328
+ target.setAttribute('data--r', target.style.right);
83329
+ target.setAttribute('data--w', target.style.width);
83330
+ target.setAttribute('data--h', target.style.height);
83331
+ } else {
83332
+ if (breakpoint && breakpoint < largeScreenBreakpoint) {
83333
+ target.setAttribute('data--t-' + breakpoint, target.style.top);
83334
+ target.setAttribute('data--l-' + breakpoint, target.style.left);
83335
+ target.setAttribute('data--b-' + breakpoint, target.style.bottom);
83336
+ target.setAttribute('data--r-' + breakpoint, target.style.right);
83337
+ if (!(target.classList.contains('fluid') && target.closest('.autolayout'))) {
83338
+ target.setAttribute('data--w-' + breakpoint, target.style.width);
83339
+ }
83340
+ target.setAttribute('data--h-' + breakpoint, target.style.height);
83341
+ } else {
83342
+ target.setAttribute('data--t', target.style.top);
83343
+ target.setAttribute('data--l', target.style.left);
83344
+ target.setAttribute('data--b', target.style.bottom);
83345
+ target.setAttribute('data--r', target.style.right);
83346
+ target.setAttribute('data--w', target.style.width);
83347
+ target.setAttribute('data--h', target.style.height);
83348
+ }
83349
+ }
83350
+ target.removeAttribute('data-prev'); // reset
83351
+ target.removeAttribute('data-fluid');
83352
+ }, 30); // delay needed since we use updateHeight() previously that has 20ms process
82931
83353
 
82932
- // if container has top/left
82933
- const containerRect = target.parentNode.getBoundingClientRect();
82934
- this.ruler.rulerLeft = this.ruler.rulerLeft - containerRect.left;
83354
+ if (this.onChange) this.onChange();
83355
+ }
83356
+ updateBlockStyle_bak(target) {
83357
+ if (target.querySelector(this.selector)) ; else {
83358
+ // this.common.updateHeight(target);
83359
+ if (target.classList.contains('height-auto')) target.style.height = '';
83360
+ }
82935
83361
 
82936
- // And update the width to align with vertical left ruler
82937
- target.style.left = this.ruler.rulerLeft + 'px';
82938
- let newWidth = currentRight - this.ruler.rulerLeft;
82939
- target.style.width = newWidth + 'px';
83362
+ // Replace with ruler's alignment
83363
+ const containerRect = this.common.getRect(target.parentNode); // if container has top/left
83364
+
83365
+ if (this.resizeHandle.includes('top')) {
83366
+ if (this.ruler.rulerTop !== null) {
83367
+ //bottom fixed
83368
+ const rect = target.getBoundingClientRect();
83369
+ let targetBottom = rect.top + rect.height;
83370
+ target.style.top = this.ruler.rulerTop - containerRect.top + 'px';
83371
+ target.style.height = targetBottom - this.ruler.rulerTop + 'px';
83372
+ }
83373
+ }
83374
+ if (this.resizeHandle.includes('bottom')) {
83375
+ if (this.ruler.rulerBottom !== null) {
83376
+ // top fixed
83377
+ // const rect = target.getBoundingClientRect();
83378
+ // target.style.height = this.ruler.rulerBottom - rect.top + containerRect.top + 'px';
83379
+ target.style.height = this.ruler.rulerBottom - target.offsetTop + 'px';
83380
+ }
83381
+ }
83382
+ if (this.resizeHandle.includes('left')) {
83383
+ if (this.ruler.rulerLeft !== null) {
83384
+ //right fixed
83385
+ const rect = target.getBoundingClientRect();
83386
+ let targetRight = rect.left + rect.width;
83387
+ target.style.left = this.ruler.rulerLeft - containerRect.left + 'px';
83388
+ target.style.width = targetRight - this.ruler.rulerLeft + 'px';
83389
+ }
83390
+ }
83391
+ if (this.resizeHandle.includes('right')) {
83392
+ if (this.ruler.rulerRight !== null) {
83393
+ //left fixed
83394
+ const rect = target.getBoundingClientRect();
83395
+ target.style.width = this.ruler.rulerRight - rect.left + 'px';
82940
83396
  }
82941
83397
  }
82942
83398
 
@@ -83139,6 +83595,10 @@ class Draggable {
83139
83595
  const y = startY - rect.top + containerRect.top;
83140
83596
  target.setAttribute('data-startx', x);
83141
83597
  target.setAttribute('data-starty', y);
83598
+
83599
+ // reset (from applyPercentage bottomTouched)
83600
+ target.style.height = target.offsetHeight + 'px';
83601
+ target.style.bottom = '';
83142
83602
  this.common.applyPixels(target);
83143
83603
  });
83144
83604
  this.clickedBlock = this.common.getSelectedBlock();
@@ -83206,10 +83666,9 @@ class Draggable {
83206
83666
  }
83207
83667
  updateBlockStyle(target) {
83208
83668
  // Replace with ruler's alignment
83209
- const containerRect = this.common.getRect(target.parentNode); // if container has top/left
83210
- const initialWidth = parseFloat(getComputedStyle(target).width);
83211
- if (this.ruler.rulerTop !== null) target.style.top = this.ruler.rulerTop - containerRect.top + 'px';
83212
- if (this.ruler.rulerLeft !== null) target.style.left = this.ruler.rulerLeft - containerRect.left + 'px';else if (this.ruler.rulerRight !== null) target.style.left = this.ruler.rulerRight - initialWidth - containerRect.left + 'px';
83669
+ if (this.ruler.rulerTop !== null) target.style.top = this.ruler.rulerTop + 'px';
83670
+ if (this.ruler.rulerBottom !== null) target.style.top = this.ruler.rulerBottom - target.offsetHeight + 'px'; //new
83671
+ if (this.ruler.rulerLeft !== null) target.style.left = this.ruler.rulerLeft + 'px';else if (this.ruler.rulerRight !== null) target.style.left = this.ruler.rulerRight - target.offsetWidth + 'px';
83213
83672
  this.doc.querySelectorAll('[data-startx]').forEach(elm => elm.removeAttribute('data-startx'));
83214
83673
  this.doc.querySelectorAll('[data-starty]').forEach(elm => elm.removeAttribute('data-starty'));
83215
83674
  this.common.applyPercentage(target);
@@ -83900,6 +84359,9 @@ class EditableBlocks {
83900
84359
  win: this.win,
83901
84360
  onContentClick: this.onContentClick,
83902
84361
  onEditStart: (event, block) => {
84362
+ const container = block.querySelector('.is-container');
84363
+ if (!container) return; // if block is empty, no edit required
84364
+
83903
84365
  if (block.classList.contains('clone')) {
83904
84366
  const clonedTarget = this.doc.querySelector(this.selector + '.cloned');
83905
84367
  this.onEditStart(event, clonedTarget);
@@ -84070,133 +84532,181 @@ class BlockModal {
84070
84532
  </div>
84071
84533
  </div>
84072
84534
 
84535
+ <div class="label-page-grayscale label checkbox grayscale" style="padding:30px 0 10px;">
84536
+ <label class="label-checkbox" for="chkPageGrayscale"><input id="chkPageGrayscale" class="chk-grayscale" type="checkbox" /> ${util.out('Grayscale')}</label>
84537
+ </div>
84538
+
84539
+ <div style="padding-top:30px;padding-bottom:3px;">${util.out('Auto layout on mobile')}:</div>
84540
+
84541
+ <label class="switch"><input id="inpAutoLayout" type="checkbox" checked=""><span class="slider round"></span></label>
84542
+
84073
84543
  </div>
84074
84544
 
84075
- <div class="modal-content">
84545
+ <div class="modal-content" style="padding:0">
84076
84546
 
84077
- <div style="padding-bottom: 3px;">${util.out('Background Color')}:</div>
84078
- <div style="display:flex;">
84079
- <button title="${util.out('Background Color')}" class="input-block-bgcolor is-btn-color" style="margin-right:15px"></button>
84080
- <button title="${util.out('Gradient')}" class="btn-block-gradient classic" data-value="+"> ${util.out('Gradient')} </button>
84547
+ <div class="is-tabs" data-group="blocksettings" style="background-color:transparent">
84548
+ <a title="${util.out('General')}" id="tabBlockGeneral" href="#" data-content="divBlockGeneral" class="active">${util.out('General')}</a>
84549
+ <a title="${util.out('More')}" id="tabBlockMore" href="#" data-content="divBlockMore">${util.out('More')}</a>
84081
84550
  </div>
84082
84551
 
84083
- <div style="padding-top:20px;padding-bottom: 3px;">${util.out('Background Image')}:</div>
84084
- <div>
84085
- <div class="asset-block-preview" style="display:none"></div>
84086
- <div style="display: flex">
84087
- <button title="${util.out('Image')}" class="btn-block-bgimage">
84088
- <svg class="is-icon-flex"><use xlink:href="#ion-image"></use></svg>
84089
- <span>${util.out('Image')}</span>
84552
+ <div id="divBlockMore" class="is-tab-content" data-group="blocksettings" tabindex="-1" style="padding:25px 25px 28px">
84553
+
84554
+ <div class="div-target" style="display: flex;justify-content: flex-end;padding: 5px 0 0;">
84555
+ <button title="${util.out('Desktop')}" class="input-device on" data-value="" style="width:40px;height:25px;">
84556
+ <svg class="is-icon-flex" style="width:16px;height:16px"><use xlink:href="#icon-device-desktop"></use></svg>
84557
+ </button>
84558
+ <button title="${util.out('Laptop/Tablet (Landscape)')}" class="input-device" data-value="md" style="width:40px;height:25px;">
84559
+ <svg class="is-icon-flex" style="width:16px;height:16px;transform:rotate(-90deg)"><use xlink:href="#icon-device-tablet"></use></svg>
84560
+ </button>
84561
+ <button title="${util.out('Tablet (Portrait)')}" class="input-device" data-value="sm" style="width:40px;height:25px;">
84562
+ <svg class="is-icon-flex" style="width:16px;height:16px"><use xlink:href="#icon-device-tablet"></use></svg>
84563
+ </button>
84564
+ <button title="${util.out('Mobile')}" class="input-device" data-value="xs" style="width:40px;height:25px;">
84565
+ <svg class="is-icon-flex" style="width:13px;height:13px"><use xlink:href="#icon-device-mobile"></use></svg>
84090
84566
  </button>
84091
- <button title="${util.out('Select')}" class="btn-block-asset">${this.builder.opts.selectIcon}</button>
84092
- <button title="${util.out('Remove')}" class="btn-block-clear"><svg class="is-icon-flex" style="width:11px;height:11px;"><use xlink:href="#icon-clean"></use></svg></button>
84093
- <button title="${util.out('Adjust')}" class="btn-block-adjust" style="width:40px"><svg class="is-icon-flex"><use xlink:href="#ion-wrench"></use></svg></button>
84094
84567
  </div>
84095
- </div>
84096
84568
 
84097
- <div class="div-content-textcolor flex flex-col">
84098
- <div style="padding-top:20px;padding-bottom:3px;">${util.out('Text Color')}:</div>
84099
- <div class="flex flex-row">
84100
- <button title="0" data-textcolor="dark">${util.out('Dark')}</button>
84101
- <button title="10" data-textcolor="light">${util.out('Light')}</button>
84102
-
84103
- <button title="${util.out('Clear')}" data-textcolor=""><svg class="is-icon-flex" style="flex:none;width:18px;height:18px;margin-top: 2px;"><use xlink:href="#ion-ios-close-empty"></use></svg></button>
84569
+ <div style="padding-top:0;padding-bottom:3px;">${util.out('Visibility')}:</div>
84570
+ <div class="div-visibility" style="display:flex;">
84571
+ <button title="${util.out('Visible')}" class="input-visible on" data-value="sm" style="width:100px;height:34px;">
84572
+ <svg class="is-icon-flex" style="width:16px;height:16px"><use xlink:href="#icon-eye"></use></svg>
84573
+ <span>${util.out('Visible')}</span>
84574
+ </button>
84575
+ <button title="${util.out('Hidden')}" class="input-hidden" data-value="xs" style="width:100px;height:34px;">
84576
+ <svg class="is-icon-flex" style="width:16px;height:16px"><use xlink:href="#icon-eye-off"></use></svg>
84577
+ <span>${util.out('Hidden')}</span>
84578
+ </button>
84104
84579
  </div>
84580
+
84105
84581
  </div>
84106
84582
 
84107
- <div class="label checkbox grayscale" style="padding:30px 0 10px;">
84108
- <label class="label-block-grayscale label-checkbox" for="chkBlockGrayscale"><input id="chkBlockGrayscale" class="chk-grayscale" type="checkbox" /> ${util.out('Grayscale')}</label>
84109
- </div>
84583
+ <div id="divBlockGeneral" class="is-tab-content active" data-group="blocksettings" style="display:flex" tabindex="-1" style="padding:25px 25px 28px">
84110
84584
 
84111
- <button title="${util.out('Remove Content/Text')}" class="btn-clear-text" style="margin-top:20px">
84112
- <svg class="is-icon-flex"><use xlink:href="#icon-trash"></use></svg>
84113
- <span>${util.out('Remove Content/Text')}</span>
84114
- </button>
84585
+ <div style="padding-bottom: 3px;">${util.out('Background Color')}:</div>
84586
+ <div style="display:flex;">
84587
+ <button title="${util.out('Background Color')}" class="input-block-bgcolor is-btn-color" style="margin-right:15px"></button>
84588
+ <button title="${util.out('Gradient')}" class="btn-block-gradient classic" data-value="+"> ${util.out('Gradient')} </button>
84589
+ </div>
84115
84590
 
84116
- <button title="${util.out('Clear Breakpoints')}" class="btn-clear-breakpoint" style="margin-top:20px">
84117
- <svg class="is-icon-flex"><use xlink:href="#icon-trash"></use></svg>
84118
- <span>${util.out('Clear Breakpoints')}</span>
84119
- </button>
84591
+ <div style="padding-top:20px;padding-bottom: 3px;">${util.out('Background Image')}:</div>
84592
+ <div>
84593
+ <div class="asset-block-preview" style="display:none"></div>
84594
+ <div style="display: flex">
84595
+ <button title="${util.out('Image')}" class="btn-block-bgimage">
84596
+ <svg class="is-icon-flex"><use xlink:href="#ion-image"></use></svg>
84597
+ <span>${util.out('Image')}</span>
84598
+ </button>
84599
+ <button title="${util.out('Select')}" class="btn-block-asset">${this.builder.opts.selectIcon}</button>
84600
+ <button title="${util.out('Remove')}" class="btn-block-clear"><svg class="is-icon-flex" style="width:11px;height:11px;"><use xlink:href="#icon-clean"></use></svg></button>
84601
+ <button title="${util.out('Adjust')}" class="btn-block-adjust" style="width:40px"><svg class="is-icon-flex"><use xlink:href="#ion-wrench"></use></svg></button>
84602
+ </div>
84603
+ </div>
84120
84604
 
84121
- <div style="padding-top:23px;padding-bottom:3px;">${util.out('Lock')}:</div>
84605
+ <div class="div-content-textcolor flex flex-col">
84606
+ <div style="padding-top:20px;padding-bottom:3px;">${util.out('Text Color')}:</div>
84607
+ <div class="flex flex-row">
84608
+ <button title="0" data-textcolor="dark">${util.out('Dark')}</button>
84609
+ <button title="10" data-textcolor="light">${util.out('Light')}</button>
84610
+
84611
+ <button title="${util.out('Clear')}" data-textcolor=""><svg class="is-icon-flex" style="flex:none;width:18px;height:18px;margin-top: 2px;"><use xlink:href="#ion-ios-close-empty"></use></svg></button>
84612
+ </div>
84613
+ </div>
84122
84614
 
84123
- <label class="switch"><input id="inpLockBlock" type="checkbox" checked=""><span class="slider round"></span></label>
84615
+ <div class="label-block-grayscale label checkbox grayscale" style="padding:30px 0 10px;">
84616
+ <label class="label-checkbox" for="chkBlockGrayscale"><input id="chkBlockGrayscale" class="chk-grayscale" type="checkbox" /> ${util.out('Grayscale')}</label>
84617
+ </div>
84124
84618
 
84125
- <div id="divBlockPos">
84619
+ <button title="${util.out('Remove Content/Text')}" class="btn-clear-text" style="margin-top:20px">
84620
+ <svg class="is-icon-flex"><use xlink:href="#icon-trash"></use></svg>
84621
+ <span>${util.out('Remove Content/Text')}</span>
84622
+ </button>
84126
84623
 
84127
- <div class="flex" style="gap:10px">
84128
- <div>
84129
- <label for="inpBlockTop" class="flex" style="padding:10px 0 3px;">${util.out('Top')}:</label>
84130
- <div style="display:flex">
84131
- <input id="inpBlockTop" class="inp-block-top" type="text" style="width:74px;height:35px">
84132
- <select id="inpBlockTopUnit">
84133
- <option></option>
84134
- <option>px</option>
84135
- <option>%</option>
84136
- </select>
84624
+ <button title="${util.out('Clear Breakpoints')}" class="btn-clear-breakpoint" style="margin-top:20px">
84625
+ <svg class="is-icon-flex"><use xlink:href="#icon-trash"></use></svg>
84626
+ <span>${util.out('Clear Breakpoints')}</span>
84627
+ </button>
84628
+
84629
+ <div style="padding-top:23px;padding-bottom:3px;">${util.out('Lock')}:</div>
84630
+
84631
+ <label class="switch"><input id="inpLockBlock" type="checkbox" checked=""><span class="slider round"></span></label>
84632
+
84633
+ <div id="divBlockPos">
84634
+
84635
+ <div class="flex" style="gap:10px">
84636
+ <div>
84637
+ <label for="inpBlockTop" class="flex" style="padding:10px 0 3px;">${util.out('Top')}:</label>
84638
+ <div style="display:flex">
84639
+ <input id="inpBlockTop" class="inp-block-top" type="text" style="width:74px;height:35px">
84640
+ <select id="inpBlockTopUnit">
84641
+ <option></option>
84642
+ <option>px</option>
84643
+ <option>%</option>
84644
+ </select>
84645
+ </div>
84137
84646
  </div>
84138
- </div>
84139
- <div>
84140
- <label for="inpBlockBottom" class="flex" style="padding:10px 0 3px;">${util.out('Bottom')}:</label>
84141
- <div style="display:flex">
84142
- <input id="inpBlockBottom" class="inp-block-top" type="text" style="width:74px;height:35px">
84143
- <select id="inpBlockBottomUnit">
84144
- <option></option>
84145
- <option>px</option>
84146
- <option>%</option>
84147
- </select>
84647
+ <div>
84648
+ <label for="inpBlockBottom" class="flex" style="padding:10px 0 3px;">${util.out('Bottom')}:</label>
84649
+ <div style="display:flex">
84650
+ <input id="inpBlockBottom" class="inp-block-top" type="text" style="width:74px;height:35px">
84651
+ <select id="inpBlockBottomUnit">
84652
+ <option></option>
84653
+ <option>px</option>
84654
+ <option>%</option>
84655
+ </select>
84656
+ </div>
84148
84657
  </div>
84149
84658
  </div>
84150
- </div>
84151
84659
 
84152
- <div class="flex" style="gap:10px">
84153
- <div>
84154
- <label for="inpBlockLeft" class="flex" style="padding:10px 0 3px;">${util.out('Left')}:</label>
84155
- <div style="display:flex">
84156
- <input id="inpBlockLeft" class="inp-block-left" type="text" style="width:74px;height:35px">
84157
- <select id="inpBlockLeftUnit">
84158
- <option></option>
84159
- <option>px</option>
84160
- <option>%</option>
84161
- </select>
84660
+ <div class="flex" style="gap:10px">
84661
+ <div>
84662
+ <label for="inpBlockLeft" class="flex" style="padding:10px 0 3px;">${util.out('Left')}:</label>
84663
+ <div style="display:flex">
84664
+ <input id="inpBlockLeft" class="inp-block-left" type="text" style="width:74px;height:35px">
84665
+ <select id="inpBlockLeftUnit">
84666
+ <option></option>
84667
+ <option>px</option>
84668
+ <option>%</option>
84669
+ </select>
84670
+ </div>
84162
84671
  </div>
84163
- </div>
84164
- <div>
84165
- <label for="inpBlockRight" class="flex" style="padding:10px 0 3px;">${util.out('Right')}:</label>
84166
- <div style="display:flex">
84167
- <input id="inpBlockRight" class="inp-block-left" type="text" style="width:74px;height:35px">
84168
- <select id="inpBlockRightUnit">
84169
- <option></option>
84170
- <option>px</option>
84171
- <option>%</option>
84172
- </select>
84672
+ <div>
84673
+ <label for="inpBlockRight" class="flex" style="padding:10px 0 3px;">${util.out('Right')}:</label>
84674
+ <div style="display:flex">
84675
+ <input id="inpBlockRight" class="inp-block-left" type="text" style="width:74px;height:35px">
84676
+ <select id="inpBlockRightUnit">
84677
+ <option></option>
84678
+ <option>px</option>
84679
+ <option>%</option>
84680
+ </select>
84681
+ </div>
84173
84682
  </div>
84174
84683
  </div>
84175
- </div>
84176
84684
 
84177
- <div class="flex" style="gap:10px">
84178
- <div>
84179
- <label for="inpBlockWidth" class="flex" style="padding:10px 0 3px;">${util.out('Width')}:</label>
84180
- <div style="display:flex">
84181
- <input id="inpBlockWidth" class="inp-block-left" type="text" style="width:74px;height:35px">
84182
- <select id="inpBlockWidthUnit">
84183
- <option></option>
84184
- <option>px</option>
84185
- <option>%</option>
84186
- </select>
84685
+ <div class="flex" style="gap:10px">
84686
+ <div>
84687
+ <label for="inpBlockWidth" class="flex" style="padding:10px 0 3px;">${util.out('Width')}:</label>
84688
+ <div style="display:flex">
84689
+ <input id="inpBlockWidth" class="inp-block-left" type="text" style="width:74px;height:35px">
84690
+ <select id="inpBlockWidthUnit">
84691
+ <option></option>
84692
+ <option>px</option>
84693
+ <option>%</option>
84694
+ </select>
84695
+ </div>
84187
84696
  </div>
84188
- </div>
84189
- <div>
84190
- <label for="inpBlockHeight" class="flex" style="padding:10px 0 3px;">${util.out('Height')}:</label>
84191
- <div style="display:flex">
84192
- <input id="inpBlockHeight" class="inp-block-left" type="text" style="width:74px;height:35px">
84193
- <select id="inpBlockHeightUnit">
84194
- <option></option>
84195
- <option>px</option>
84196
- <option>%</option>
84197
- </select>
84697
+ <div>
84698
+ <label for="inpBlockHeight" class="flex" style="padding:10px 0 3px;">${util.out('Height')}:</label>
84699
+ <div style="display:flex">
84700
+ <input id="inpBlockHeight" class="inp-block-left" type="text" style="width:74px;height:35px">
84701
+ <select id="inpBlockHeightUnit">
84702
+ <option></option>
84703
+ <option>px</option>
84704
+ <option>%</option>
84705
+ </select>
84706
+ </div>
84198
84707
  </div>
84199
84708
  </div>
84709
+
84200
84710
  </div>
84201
84711
 
84202
84712
  </div>
@@ -84298,19 +84808,19 @@ class BlockModal {
84298
84808
  const btnPageBgImage = modal.querySelector('.btn-page-bgimage');
84299
84809
  if (btnPageBgImage) dom.addEventListener(btnPageBgImage, 'click', () => {
84300
84810
  // Background image
84301
- const page = this.getPage();
84811
+ let pageOverlay = this.pageOverlay();
84302
84812
  let src = '';
84303
- if (page) if (page.style.backgroundImage) {
84304
- if (page.style.backgroundImage.indexOf('url(') !== -1) {
84305
- src = page.style.backgroundImage.slice(4, -1).replace(/["']/g, '');
84813
+ if (pageOverlay) if (pageOverlay.style.backgroundImage) {
84814
+ if (pageOverlay.style.backgroundImage.indexOf('url(') !== -1) {
84815
+ src = pageOverlay.style.backgroundImage.slice(4, -1).replace(/["']/g, '');
84306
84816
  }
84307
84817
  }
84308
84818
  this.openImagePicker(src, url => {
84309
- const page = this.getPage();
84819
+ let pageOverlay = this.pageOverlay();
84310
84820
  this.builder.uo.saveForUndo();
84311
- page.style.backgroundImage = `url("${url}")`;
84312
- page.style.backgroundSize = 'cover';
84313
- page.style.backgroundRepeat = 'no-repeat';
84821
+ pageOverlay.style.backgroundImage = `url("${url}")`;
84822
+ pageOverlay.style.backgroundSize = 'cover';
84823
+ pageOverlay.style.backgroundRepeat = 'no-repeat';
84314
84824
  const div = this.pageImagePreview;
84315
84825
  const btnPageAdjust = modal.querySelector('.btn-page-adjust');
84316
84826
  const btnPageClear = modal.querySelector('.btn-page-clear');
@@ -84341,9 +84851,43 @@ class BlockModal {
84341
84851
  });
84342
84852
  const btnPageAdjust = modal.querySelector('.btn-page-adjust');
84343
84853
  btnPageAdjust.addEventListener('click', () => {
84344
- let page = this.getPage();
84345
- this.builder.colTool.openImageAdjust(page, btnPageAdjust);
84854
+ let pageOverlay = this.pageOverlay();
84855
+ this.builder.colTool.openImageAdjust(pageOverlay, btnPageAdjust);
84346
84856
  });
84857
+ const chkPageGrayscale = modal.querySelector('#chkPageGrayscale');
84858
+ chkPageGrayscale.addEventListener('click', () => {
84859
+ this.builder.uo.saveForUndo();
84860
+ let pageOverlay = this.pageOverlay();
84861
+ const checked = chkPageGrayscale.checked;
84862
+ if (checked) {
84863
+ pageOverlay.style.filter = 'grayscale(1)';
84864
+ } else {
84865
+ if (pageOverlay.style.filter) pageOverlay.style.filter = pageOverlay.style.filter.replace('grayscale(1)', '');
84866
+ }
84867
+ this.builder.onChange();
84868
+ });
84869
+
84870
+ // Page Auto Layout
84871
+ const chkAutoLayout = modal.querySelector('#inpAutoLayout');
84872
+ chkAutoLayout.addEventListener(this.builder.isTouchSupport ? 'touchstart' : 'click', () => {
84873
+ const page = this.getPage();
84874
+ if (chkAutoLayout.checked) {
84875
+ page.classList.add('autolayout');
84876
+ } else {
84877
+ page.classList.remove('autolayout');
84878
+ }
84879
+ });
84880
+ if (this.builder.isTouchSupport) {
84881
+ let chkAutoLayoutLabel = chkAutoLayout.parentNode;
84882
+ chkAutoLayoutLabel.addEventListener('touchstart', () => {
84883
+ const page = this.getPage();
84884
+ if (chkAutoLayout.checked) {
84885
+ page.classList.add('autolayout');
84886
+ } else {
84887
+ page.classList.remove('autolayout');
84888
+ }
84889
+ });
84890
+ }
84347
84891
 
84348
84892
  // Block Background Image
84349
84893
 
@@ -84397,7 +84941,7 @@ class BlockModal {
84397
84941
  let blockOverlay = this.blockOverlay();
84398
84942
  this.builder.colTool.openImageAdjust(blockOverlay, btnAdjust);
84399
84943
  });
84400
- const chkGrayscale = modal.querySelector('.chk-grayscale');
84944
+ const chkGrayscale = modal.querySelector('#chkBlockGrayscale');
84401
84945
  chkGrayscale.addEventListener('click', () => {
84402
84946
  this.builder.uo.saveForUndo();
84403
84947
  let blockOverlay = this.blockOverlay();
@@ -84624,6 +85168,62 @@ class BlockModal {
84624
85168
  }
84625
85169
  });
84626
85170
  }
85171
+
85172
+ // Responsive Visibility
85173
+
85174
+ let btns = modal.querySelectorAll('.input-device');
85175
+ btns.forEach(btn => {
85176
+ btn.addEventListener('click', () => {
85177
+ const block = this.blockSelected();
85178
+ let elms = modal.querySelectorAll('.input-device');
85179
+ elms.forEach(elm => {
85180
+ elm.classList.remove('on');
85181
+ });
85182
+ btn.classList.add('on');
85183
+ this.realtimeVisibility(block);
85184
+ });
85185
+ });
85186
+ let btnVisible = modal.querySelector('.input-visible');
85187
+ let btnHidden = modal.querySelector('.input-hidden');
85188
+ btnVisible.addEventListener('click', () => {
85189
+ const block = this.blockSelected();
85190
+ this.builder.uo.saveForUndo();
85191
+ let divTarget = modal.querySelector('.div-target');
85192
+ let target = this.builder.responsive.readTarget(divTarget);
85193
+ if (target === 'xs') {
85194
+ block.classList.remove('xs-hidden');
85195
+ } else if (target === 'sm') {
85196
+ block.classList.remove('sm-hidden');
85197
+ } else if (target === 'md') {
85198
+ block.classList.remove('md-hidden');
85199
+ } else if (target === '') {
85200
+ block.classList.remove('desktop-hidden');
85201
+ }
85202
+ btnVisible.classList.add('on');
85203
+ btnHidden.classList.remove('on');
85204
+ this.builder.opts.onChange();
85205
+ });
85206
+ btnHidden.addEventListener('click', () => {
85207
+ const block = this.blockSelected();
85208
+ this.builder.uo.saveForUndo();
85209
+ let divTarget = modal.querySelector('.div-target');
85210
+ let target = this.builder.responsive.readTarget(divTarget);
85211
+ if (target === 'xs') {
85212
+ block.classList.add('xs-hidden');
85213
+ } else if (target === 'sm') {
85214
+ block.classList.add('sm-hidden');
85215
+ } else if (target === 'md') {
85216
+ block.classList.add('md-hidden');
85217
+ } else if (target === '') {
85218
+ block.classList.add('desktop-hidden');
85219
+ }
85220
+ btnVisible.classList.remove('on');
85221
+ btnHidden.classList.add('on');
85222
+ this.builder.opts.onChange();
85223
+ });
85224
+ new Tabs({
85225
+ element: modal
85226
+ });
84627
85227
  } // constructor
84628
85228
 
84629
85229
  getPage() {
@@ -84655,6 +85255,16 @@ class BlockModal {
84655
85255
  // this.builder.eb.common.applyPercentage(target);
84656
85256
  }
84657
85257
 
85258
+ pageOverlay() {
85259
+ const page = this.getPage();
85260
+ if (!page) return false;
85261
+ let pageOverlay = page.querySelector('.is-page-overlay');
85262
+ if (!pageOverlay) {
85263
+ page.insertAdjacentHTML('afterbegin', '<div class="is-page-overlay"></div>');
85264
+ pageOverlay = page.querySelector('.is-page-overlay');
85265
+ }
85266
+ return pageOverlay;
85267
+ }
84658
85268
  blockOverlay() {
84659
85269
  const block = this.builder.doc.querySelector('.is-block.active:not(.multi)');
84660
85270
  if (!block) return false;
@@ -84671,6 +85281,7 @@ class BlockModal {
84671
85281
  }
84672
85282
  realtime() {
84673
85283
  const modal = this.modal;
85284
+ if (!modal.classList.contains('active')) return;
84674
85285
  const page = this.getPage();
84675
85286
  const block = this.blockSelected();
84676
85287
  if (block) {
@@ -84713,7 +85324,7 @@ class BlockModal {
84713
85324
  }
84714
85325
 
84715
85326
  // Grayscale
84716
- const chkGrayscale = modal.querySelector('.chk-grayscale');
85327
+ const chkGrayscale = modal.querySelector('#chkBlockGrayscale');
84717
85328
  chkGrayscale.checked = false;
84718
85329
  if (blockOverlay) {
84719
85330
  if (blockOverlay.style.filter) {
@@ -84864,23 +85475,38 @@ class BlockModal {
84864
85475
  inpHeight.value = '';
84865
85476
  inpHeightUnit.value = '%';
84866
85477
  }
85478
+ this.realtimeVisibility(block);
84867
85479
  } else if (page) {
85480
+ let pageOverlay = this.pageOverlay();
85481
+
84868
85482
  // Background image
84869
85483
  let src = '';
84870
- if (page) if (page.style.backgroundImage) {
84871
- if (page.style.backgroundImage.indexOf('url(') !== -1) {
84872
- src = page.style.backgroundImage.slice(4, -1).replace(/["']/g, '');
85484
+ if (pageOverlay) if (pageOverlay.style.backgroundImage) {
85485
+ if (pageOverlay.style.backgroundImage.indexOf('url(') !== -1) {
85486
+ src = pageOverlay.style.backgroundImage.slice(4, -1).replace(/["']/g, '');
84873
85487
  }
84874
85488
  }
84875
85489
 
84876
85490
  // Update preview
84877
85491
  this.updatePanelPageImage(src);
84878
85492
 
84879
- // Show/hide
85493
+ // Show/hide grayscale
85494
+ const divPageGrayscale = modal.querySelector('.label-page-grayscale');
84880
85495
  if (src === '') {
84881
85496
  this.pageImagePreview.style.display = 'none';
85497
+ divPageGrayscale.style.display = 'none';
84882
85498
  } else {
84883
85499
  this.pageImagePreview.style.display = '';
85500
+ divPageGrayscale.style.display = '';
85501
+ }
85502
+
85503
+ // Grayscale
85504
+ const chkPageGrayscale = modal.querySelector('#chkPageGrayscale');
85505
+ chkPageGrayscale.checked = false;
85506
+ if (pageOverlay.style.filter) {
85507
+ if (pageOverlay.style.filter.indexOf('grayscale') !== -1) {
85508
+ chkPageGrayscale.checked = true;
85509
+ }
84884
85510
  }
84885
85511
 
84886
85512
  // Background color
@@ -84903,6 +85529,58 @@ class BlockModal {
84903
85529
  } else {
84904
85530
  btnPageGradient.style.backgroundImage = '';
84905
85531
  }
85532
+
85533
+ // Page Auto Layout
85534
+ const chkAutoLayout = modal.querySelector('#inpAutoLayout');
85535
+ if (page.classList.contains('autolayout')) {
85536
+ chkAutoLayout.checked = true;
85537
+ } else {
85538
+ chkAutoLayout.checked = false;
85539
+ }
85540
+ }
85541
+ }
85542
+ realtimeVisibility(row, initialOpen) {
85543
+ if (!this.modal) return;
85544
+ if (initialOpen) {
85545
+ const builderStuff = this.builder.builderStuff;
85546
+ const modal = builderStuff.querySelector('.is-modal.content-preview.active');
85547
+ if (modal) {
85548
+ let elms = this.modal.querySelectorAll('.input-device');
85549
+ elms.forEach(elm => {
85550
+ elm.classList.remove('on');
85551
+ });
85552
+ if (modal.classList.contains('is-screen-1920')) {
85553
+ this.modal.querySelector('.input-device[data-value=""]').classList.add('on');
85554
+ } else if (modal.classList.contains('is-screen-1440')) {
85555
+ this.modal.querySelector('.input-device[data-value=""]').classList.add('on');
85556
+ } else if (modal.classList.contains('is-screen-1024')) {
85557
+ this.modal.querySelector('.input-device[data-value="md"]').classList.add('on');
85558
+ } else if (modal.classList.contains('is-screen-768')) {
85559
+ this.modal.querySelector('.input-device[data-value="sm"]').classList.add('on');
85560
+ } else if (modal.classList.contains('is-screen-375')) {
85561
+ this.modal.querySelector('.input-device[data-value="xs"]').classList.add('on');
85562
+ }
85563
+ }
85564
+ }
85565
+ let divTarget = this.modal.querySelector('.div-target');
85566
+ let divVisibility = this.modal.querySelector('.div-visibility');
85567
+ let target = this.builder.responsive.readTarget(divTarget);
85568
+ let valVisibility = this.builder.responsive.getVisibility(row, target);
85569
+ this.builder.responsive.showVisibility(divVisibility, valVisibility);
85570
+
85571
+ // const divColsPerLine = this.modal.querySelector('.div-colsperline');
85572
+ let btns = this.modal.querySelectorAll('.input-colsperline');
85573
+ btns.forEach(btn => {
85574
+ btn.classList.remove('on');
85575
+ });
85576
+ if (target === 'xs') {
85577
+ if (!initialOpen) this.builder.livePreview.resizePreview(375);
85578
+ } else if (target === 'sm') {
85579
+ if (!initialOpen) this.builder.livePreview.resizePreview(768);
85580
+ } else if (target === 'md') {
85581
+ if (!initialOpen) this.builder.livePreview.resizePreview(1024);
85582
+ } else {
85583
+ if (!initialOpen) this.builder.livePreview.resizePreview(1920);
84906
85584
  }
84907
85585
  }
84908
85586
  openImagePicker(currentUrl, callback, btn) {
@@ -84926,17 +85604,17 @@ class BlockModal {
84926
85604
  }
84927
85605
  updatePageImage(src) {
84928
85606
  this.builder.uo.saveForUndo();
84929
- let page = this.getPage();
84930
- page.style.backgroundImage = 'url(\'' + src + '\')';
85607
+ let pageOverlay = this.pageOverlay();
85608
+ pageOverlay.style.backgroundImage = 'url(\'' + src + '\')';
84931
85609
 
84932
85610
  // Reset position & filter (grayscale)
84933
- page.style.filter = '';
84934
- page.style.backgroundSize = '';
84935
- page.style.backgroundPosition = '50% 60%';
84936
- page.removeAttribute('data-bg-xs');
84937
- page.removeAttribute('data-bg-sm');
84938
- page.removeAttribute('data-bg-md');
84939
- page.removeAttribute('data-bg-lg');
85611
+ pageOverlay.style.filter = '';
85612
+ pageOverlay.style.backgroundSize = '';
85613
+ pageOverlay.style.backgroundPosition = '50% 60%';
85614
+ pageOverlay.removeAttribute('data-bg-xs');
85615
+ pageOverlay.removeAttribute('data-bg-sm');
85616
+ pageOverlay.removeAttribute('data-bg-md');
85617
+ pageOverlay.removeAttribute('data-bg-lg');
84940
85618
  this.updatePanelPageImage(src);
84941
85619
  this.builder.onChange();
84942
85620
  }
@@ -84960,6 +85638,16 @@ class BlockModal {
84960
85638
  }
84961
85639
  const btnPageGradient = modal.querySelector('.btn-page-gradient');
84962
85640
  btnPageGradient.style.backgroundImage = '';
85641
+
85642
+ // Show/hide grayscale
85643
+ const divPageGrayscale = modal.querySelector('.label-page-grayscale');
85644
+ if (src === '') {
85645
+ this.pageImagePreview.style.display = 'none';
85646
+ divPageGrayscale.style.display = 'none';
85647
+ } else {
85648
+ this.pageImagePreview.style.display = '';
85649
+ divPageGrayscale.style.display = '';
85650
+ }
84963
85651
  }
84964
85652
  updateImage(src) {
84965
85653
  this.builder.uo.saveForUndo();
@@ -84975,6 +85663,7 @@ class BlockModal {
84975
85663
  blockOverlay.removeAttribute('data-bg-md');
84976
85664
  blockOverlay.removeAttribute('data-bg-lg');
84977
85665
  this.updatePanelImage(src);
85666
+ this.realtime();
84978
85667
  this.builder.onChange();
84979
85668
  }
84980
85669
  updatePanelImage(src) {
@@ -84997,6 +85686,16 @@ class BlockModal {
84997
85686
  }
84998
85687
  const btnGradient = modal.querySelector('.btn-block-gradient');
84999
85688
  btnGradient.style.backgroundImage = '';
85689
+
85690
+ // Show/hide grayscale
85691
+ const divGrayscale = modal.querySelector('.label-block-grayscale');
85692
+ if (src === '') {
85693
+ this.imagePreview.style.display = 'none';
85694
+ divGrayscale.style.display = 'none';
85695
+ } else {
85696
+ this.imagePreview.style.display = '';
85697
+ divGrayscale.style.display = '';
85698
+ }
85000
85699
  }
85001
85700
  show() {
85002
85701
  const modal = this.modal;
@@ -85027,6 +85726,7 @@ class BlockModal {
85027
85726
  }
85028
85727
  showHideControls() {
85029
85728
  const modal = this.modal;
85729
+ if (!modal.classList.contains('active')) return;
85030
85730
  const content1 = modal.querySelector('.modal-none');
85031
85731
  const content2 = modal.querySelector('.modal-content');
85032
85732
  const content3 = modal.querySelector('.modal-page-content');
@@ -85067,6 +85767,60 @@ class BlockModal {
85067
85767
  this.builder.doc.removeEventListener('click', this.handleBlockClick);
85068
85768
  }
85069
85769
  }
85770
+ position() {
85771
+ const dom = this.dom;
85772
+ let elementTool = this.elementTool;
85773
+ let elementMore = this.elementMore;
85774
+ dom.addClass(elementMore, 'transition1');
85775
+ let elmMore = elementTool.querySelector('.elm-more');
85776
+ const viewportHeight = window.innerHeight;
85777
+
85778
+ /*
85779
+ let top, left;
85780
+ if(!this.builder.iframe) {
85781
+ top = elmMore.getBoundingClientRect().top;
85782
+ left = elmMore.getBoundingClientRect().left;
85783
+ } else {
85784
+ let adjY = this.builder.iframe.getBoundingClientRect().top;
85785
+ let adjX = this.builder.iframe.getBoundingClientRect().left;
85786
+ top = elmMore.getBoundingClientRect().top;
85787
+ left = elmMore.getBoundingClientRect().left;
85788
+ top = top + adjY;
85789
+ left = left + adjX;
85790
+ }
85791
+ */
85792
+ const newPos = this.builder.util.getElementPosition(elmMore);
85793
+ let top = newPos.top;
85794
+ let left = newPos.left;
85795
+
85796
+ // elementMore.style.display = 'flex';
85797
+ const btnMore = elementTool.querySelector('.elm-more');
85798
+ this.util.showPop(elementMore, false, btnMore);
85799
+ const w = elementMore.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
85800
+ const h = elementMore.offsetHeight;
85801
+ if (viewportHeight - top > h) {
85802
+ elementMore.style.top = top + window.pageYOffset + 27 + 'px';
85803
+ elementMore.style.left = left - w / 2 + 10 + 'px';
85804
+ dom.removeClass(elementMore, 'arrow-bottom');
85805
+ dom.removeClass(elementMore, 'arrow-right');
85806
+ dom.removeClass(elementMore, 'arrow-left');
85807
+ dom.removeClass(elementMore, 'center');
85808
+ dom.addClass(elementMore, 'arrow-top');
85809
+ dom.addClass(elementMore, 'center');
85810
+ } else {
85811
+ elementMore.style.top = top + window.pageYOffset - h - 8 + 'px';
85812
+ elementMore.style.left = left - w / 2 + 10 + 'px';
85813
+ dom.removeClass(elementMore, 'arrow-top');
85814
+ dom.removeClass(elementMore, 'arrow-right');
85815
+ dom.removeClass(elementMore, 'arrow-left');
85816
+ dom.removeClass(elementMore, 'center');
85817
+ dom.addClass(elementMore, 'arrow-bottom');
85818
+ dom.addClass(elementMore, 'center');
85819
+ }
85820
+ setTimeout(() => {
85821
+ dom.removeClass(elementMore, 'transition1');
85822
+ }, 300);
85823
+ }
85070
85824
  }
85071
85825
 
85072
85826
  class PageSize {
@@ -85199,12 +85953,19 @@ class PageSize {
85199
85953
  // let h = arr[1].trim();
85200
85954
  if (arr.length === 3) {
85201
85955
  // web
85202
- const docWidth = docContainer.offsetWidth;
85203
- const viewportWidth = this.builder.win.innerWidth;
85204
- if (docWidth < viewportWidth - 50) {
85205
- // web (container)
85206
- docContainer.classList.remove('page-web');
85207
- docContainer.classList.add('page-web-container');
85956
+ let box = docContainer.querySelector('.is-box');
85957
+ if (box) {
85958
+ const boxWidth = box.offsetWidth;
85959
+ const viewportWidth = this.builder.win.innerWidth;
85960
+ if (boxWidth < viewportWidth - 50) {
85961
+ // web (container)
85962
+ docContainer.classList.remove('page-web');
85963
+ docContainer.classList.add('page-web-container');
85964
+ } else {
85965
+ // web (full)
85966
+ docContainer.classList.remove('page-web-container');
85967
+ docContainer.classList.add('page-web');
85968
+ }
85208
85969
  } else {
85209
85970
  // web (full)
85210
85971
  docContainer.classList.remove('page-web-container');
@@ -85293,18 +86054,53 @@ class PageSize {
85293
86054
  position: relative;
85294
86055
  flex:none;
85295
86056
  background: #fff;
85296
- overflow: hidden;
86057
+ /* overflow: hidden;*/
85297
86058
  box-shadow: none;
85298
86059
  }
85299
86060
  ${css}
85300
86061
  </style>
86062
+
86063
+ ${html.includes('data-module="codeview"') ? `
86064
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.25.0/themes/prism.min.css" rel="stylesheet">
86065
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.25.0/themes/prism-coy.min.css" rel="stylesheet">
86066
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.25.0/prism.min.js"></script>
86067
+ <style>
86068
+ :not(pre)>code[class*=language-], pre[class*=language-] {
86069
+ background-color: #f4f4f4 !important;
86070
+ padding: 12px 16px !important;
86071
+ }
86072
+ pre[class*=language-]:after, pre[class*=language-]:before {
86073
+ box-shadow: none;
86074
+ }
86075
+ :not(pre)>code[class*=language-], pre[class*=language-] {
86076
+ margin-bottom: 1.2rem;
86077
+ }
86078
+ div[data-html] {
86079
+ min-height: 40px;
86080
+ }
86081
+ code[class*=language-], pre[class*=language-] {
86082
+ text-shadow: none;
86083
+ }
86084
+ </style>
86085
+ ` : ''}
85301
86086
  </head>
85302
86087
  <body class="print">
85303
86088
 
85304
86089
  <div class="is-page">${html}</div>
85305
86090
 
85306
86091
  <script>
85307
- window.print();
86092
+ var docReady = function(fn) {
86093
+ var stateCheck = setInterval(function() {
86094
+ if (document.readyState !== "complete") return;
86095
+ clearInterval(stateCheck);
86096
+ try {
86097
+ fn()
86098
+ } catch (e) {}
86099
+ }, 1);
86100
+ };
86101
+ docReady(function() {
86102
+ window.print();
86103
+ });
85308
86104
  </script>
85309
86105
  </body>
85310
86106
  </html>
@@ -85389,6 +86185,9 @@ class PageSize {
85389
86185
  width: ${docWidth};
85390
86186
  height: ${docHeight};
85391
86187
  }
86188
+ .hide-on-print {
86189
+ display: none !important;
86190
+ }
85392
86191
  }
85393
86192
  @page {
85394
86193
  size:${docWidth} ${docHeight};;
@@ -85409,6 +86208,9 @@ class PageSize {
85409
86208
  width: ${w};
85410
86209
  height: ${h};
85411
86210
  }
86211
+ .hide-on-print {
86212
+ display: none !important;
86213
+ }
85412
86214
  }
85413
86215
  @page {
85414
86216
  size:${w} ${h};
@@ -85678,7 +86480,7 @@ class ContentBuilder {
85678
86480
  style: 'width:180px;height:112.5px'
85679
86481
  }, {
85680
86482
  title: 'Web (container)',
85681
- pagesize: '800px,1000px,web',
86483
+ pagesize: '1000px,1000px,web',
85682
86484
  style: 'width:180px;height:112.5px'
85683
86485
  }, {
85684
86486
  title: '8.27x5.52',
@@ -86519,6 +87321,12 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
86519
87321
  if (window.data_basic) {
86520
87322
  // if snippet file included
86521
87323
  this.opts.snippetJSON = window.data_basic;
87324
+ if (!this.canvas) for (let i = this.opts.snippetJSON.snippets.length - 1; i >= 0; i--) {
87325
+ if (this.opts.snippetJSON.snippets[i].mode === 'canvas') {
87326
+ this.opts.snippetJSON.snippets.splice(i, 1);
87327
+ }
87328
+ }
87329
+
86522
87330
  // if snippetPath is specified (not empty), then use the specified. Otherwise, use the one generated from snippet file (_snippets_path)
86523
87331
  if (this.opts.snippetPath === '') {
86524
87332
  this.opts.snippetPath = window._snippets_path;
@@ -86566,12 +87374,12 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
86566
87374
  // this.iconButtons = ['icon', 'color','textsettings', 'createLink','|', 'undo', 'redo', 'aiassistant', 'snippets', 'pageoptions', 'print', 'zoom', 'html'];
86567
87375
  // this.iconButtonsMore = [];
86568
87376
 
86569
- this.buttons = ['bold', 'italic', 'underline', 'formatting', 'color', 'align', 'textsettings', 'createLink', 'tags', '|', 'undo', 'redo', 'html', 'zoom', 'more'];
86570
- this.buttonsMore = ['icon', 'image', '|', 'list', 'font', 'formatPara', '|', 'aiassistant', 'snippets', 'pageoptions', 'print', 'preferences'];
86571
- this.elementButtons = ['front', 'backward', 'moveup', 'movedown', 'group', 'ungroup', 'duplicate', 'delete', 'left', 'center', 'right', 'full', 'undo', 'redo', 'blocksettings', 'html', 'zoom', 'more'];
86572
- this.elementButtonsMore = ['aiassistant', 'snippets', 'pageoptions', 'print', 'preferences'];
86573
- this.iconButtons = ['icon', 'color', 'textsettings', 'createLink', '|', 'undo', 'redo', 'html', 'zoom', 'more'];
86574
- this.iconButtonsMore = ['aiassistant', 'snippets', 'pageoptions', 'print', 'preferences'];
87377
+ this.buttons = ['bold', 'italic', 'underline', 'formatting', 'color', 'align', 'textsettings', 'createLink', 'tags', '|', 'undo', 'redo', 'zoom', 'pageoptions', 'print', 'html', 'more'];
87378
+ this.buttonsMore = ['icon', 'image', '|', 'list', 'font', 'formatPara', '|', 'aiassistant', 'snippets', 'preferences'];
87379
+ this.elementButtons = ['front', 'backward', 'moveup', 'movedown', 'group', 'ungroup', 'duplicate', 'delete', 'left', 'center', 'right', 'full', 'undo', 'redo', 'blocksettings', 'zoom', 'pageoptions', 'print', 'html', 'more'];
87380
+ this.elementButtonsMore = ['aiassistant', 'snippets', 'preferences'];
87381
+ this.iconButtons = ['icon', 'color', 'textsettings', 'createLink', '|', 'undo', 'redo', 'zoom', 'pageoptions', 'print', 'html', 'more'];
87382
+ this.iconButtonsMore = ['aiassistant', 'snippets', 'preferences'];
86575
87383
  if (!this.docContainer && this.container !== '.is-container') {
86576
87384
  this.docContainer = this.container;
86577
87385
  this.container = '.is-container';
@@ -87083,6 +87891,11 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
87083
87891
  this.rte.hideBlockButtons();
87084
87892
  this.rte.positionToolbar();
87085
87893
  }
87894
+ if (this.blockmodal) {
87895
+ setTimeout(() => {
87896
+ this.blockmodal.showHideControls();
87897
+ }, 30);
87898
+ }
87086
87899
  },
87087
87900
  onSelectBlock: block => {
87088
87901
  if (this.onSelectBlock) this.onSelectBlock(block);
@@ -87238,6 +88051,57 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
87238
88051
  }
87239
88052
  }
87240
88053
  });
88054
+
88055
+ // Copy & Paste Block
88056
+ document.addEventListener('keydown', e => {
88057
+ if ((e.ctrlKey || e.metaKey) && e.which === 67) {
88058
+ //CTRL-C
88059
+ const activeBlock = docContainer.querySelector('.is-block.active'); // always get .cloned
88060
+ if (activeBlock) {
88061
+ this.copyBlock = activeBlock;
88062
+ }
88063
+ }
88064
+ });
88065
+ document.addEventListener('keydown', e => {
88066
+ if ((e.ctrlKey || e.metaKey) && e.which === 86) {
88067
+ //CTRL-V
88068
+
88069
+ const box = docContainer.querySelector('.is-box.box-select'); // always get .cloned
88070
+ let block = this.copyBlock;
88071
+ if (box && block) {
88072
+ if (document.querySelector('.is-modal.active:not(.is-modal-content)')) return;
88073
+ const focusedElement = e.target;
88074
+ const isEditable = focusedElement.tagName === 'INPUT' || focusedElement.tagName === 'TEXTAREA' || focusedElement.hasAttribute('contenteditable');
88075
+ if (isEditable) return;
88076
+ this.uo.saveForUndo();
88077
+ let block = this.copyBlock;
88078
+ const builder = block.querySelector(this.container);
88079
+ let html = '';
88080
+ if (builder) {
88081
+ html = this.readHtml(builder);
88082
+ }
88083
+ let clonedDiv = block.cloneNode(true);
88084
+ clonedDiv.style.top = '20%';
88085
+ clonedDiv.style.left = '20%';
88086
+ if (builder) {
88087
+ const cloneBuilder = clonedDiv.querySelector(this.container);
88088
+ cloneBuilder.innerHTML = '';
88089
+ box.appendChild(clonedDiv);
88090
+ const range = document.createRange();
88091
+ cloneBuilder.appendChild(range.createContextualFragment(html));
88092
+ this.applyBehaviorOn(cloneBuilder);
88093
+ cloneBuilder.click();
88094
+ } else {
88095
+ block.parentNode.appendChild(clonedDiv);
88096
+ }
88097
+ block.classList.remove('active');
88098
+ this.doc.querySelectorAll('.clone').forEach(elm => elm.parentNode.removeChild(elm));
88099
+ this.doc.querySelectorAll('.cloned').forEach(elm => elm.classList.remove('cloned'));
88100
+ this.eb.refresh();
88101
+ this.opts.onChange();
88102
+ }
88103
+ }
88104
+ });
87241
88105
  }
87242
88106
  let previousWidth = this.win.innerWidth;
87243
88107
  let timer;
@@ -87667,6 +88531,22 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
87667
88531
  top: 0;
87668
88532
  left: -1000px;
87669
88533
  }
88534
+ .h-ruler {
88535
+ top:0;
88536
+ left:-100vw;
88537
+ width: 300vw;
88538
+ height:2px;
88539
+ display:none;
88540
+ }
88541
+ .h-ruler.active { display: block }
88542
+ .v-ruler {
88543
+ top:0;
88544
+ left:0;
88545
+ width:2px;
88546
+ height: 100%;
88547
+ display:none;
88548
+ }
88549
+ .v-ruler.active { display: block }
87670
88550
 
87671
88551
  /* Resize Handles */
87672
88552
  .handle {
@@ -87841,16 +88721,19 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
87841
88721
  @media (max-width: 760px) {
87842
88722
  .is-box.autolayout .is-block > .rotate-handle,
87843
88723
  .is-box.autolayout .is-block > .handle {
87844
- display: none;
88724
+ display: none;
87845
88725
  }
87846
88726
 
87847
88727
  /* NEW */
87848
- .is-block.clone {
88728
+ .is-box.autolayout .is-block.clone {
87849
88729
  display:none;
87850
88730
  }
87851
- .is-block.cloned {
88731
+ .is-box.autolayout .is-block.cloned {
87852
88732
  outline: var(--is-outline);
87853
88733
  }
88734
+ .is-box.box-select {
88735
+ outline: none !important;
88736
+ }
87854
88737
  }
87855
88738
 
87856
88739
  .is-block.locked .handle,
@@ -88517,7 +89400,7 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
88517
89400
  this.setZoomOnControl(builder);
88518
89401
  }
88519
89402
  html(area) {
88520
- if (this.docContainer) {
89403
+ if (this.docContainer && !area) {
88521
89404
  // freeform
88522
89405
 
88523
89406
  const docContainer = this.doc.querySelector(this.docContainer);
@@ -88625,7 +89508,33 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
88625
89508
  }
88626
89509
  refresh() {
88627
89510
  if (this.eb) this.eb.refresh();
89511
+
89512
+ /*
89513
+ // Add block tool
89514
+ let html = `
89515
+ <div class="is-tool is-block-tool">
89516
+ <button type="button" tabindex="-1" title="${this.util.out('Settings')}" class="block-settings"><svg class="is-icon-flex"><use xlink:href="#icon-settings"></use></svg></button>
89517
+ </div>
89518
+ `;
89519
+ let blocks = this.doc.querySelectorAll('.is-block');
89520
+ blocks.forEach(block => {
89521
+ let tool = block.querySelector('.is-block-tool');
89522
+ if(tool) tool.remove();
89523
+ block.insertAdjacentHTML('beforeend', html);
89524
+ tool = block.querySelector('.is-block-tool');
89525
+ tool.addEventListener('click',(e)=>{
89526
+ if(document.querySelector('.is-modal.editblock.active')) {
89527
+ this.blockmodal.hide();
89528
+ } else {
89529
+ this.blockmodal.show();
89530
+ }
89531
+ e.preventDefault();
89532
+ e.stopImmediatePropagation();
89533
+ });
89534
+ });
89535
+ */
88628
89536
  }
89537
+
88629
89538
  group() {
88630
89539
  if (!this.eb) return;
88631
89540
  this.uo.saveForUndo();
@@ -88780,6 +89689,7 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
88780
89689
  <!--
88781
89690
  <button type="button" tabindex="-1" class="box-settings" title="${this.util.out('Settings')}"><svg class="is-icon-flex"><use xlink:href="#ion-more"></use></svg></button>
88782
89691
  -->
89692
+ <button type="button" tabindex="-1" class="box-duplicate" title="${this.util.out('Duplicate')}"><svg class="is-icon-flex" style="width:14px;height:14px"><use xlink:href="#icon-duplicate"></use></svg></button>
88783
89693
  <button type="button" tabindex="-1" class="box-remove" title="${this.util.out('Remove')}"><svg class="is-icon-flex"><use xlink:href="#icon-trash"></use></svg></button>
88784
89694
  </div>
88785
89695
  <div class="is-tool is-canvasadd-tool" style="transform: scale(1); transform-origin: center top;">
@@ -88830,6 +89740,57 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
88830
89740
  });
88831
89741
  this.opts.onChange();
88832
89742
  });
89743
+ const btnDuplicate = box.querySelector('.is-canvas-tool .box-duplicate');
89744
+ btnDuplicate.addEventListener('click', e => {
89745
+ this.eb.selectClear(); // clear clone
89746
+
89747
+ // clear active
89748
+ const box = e.target.closest('.is-box');
89749
+ const block = box.querySelector('.is-block.active');
89750
+ if (block) block.classList.remove('active');
89751
+ this.uo.saveForUndo();
89752
+ let copiedBox = box.cloneNode(true);
89753
+ copiedBox.setAttribute('data-box-copied', '1');
89754
+ let parent = box.parentNode;
89755
+ parent.insertBefore(copiedBox, box.nextElementSibling);
89756
+ let newBox = docContainer.querySelector('[data-box-copied]');
89757
+ newBox.removeAttribute('data-box-copied');
89758
+
89759
+ // Code Blocks Handling
89760
+ let codeBlocks = newBox.querySelectorAll('[data-module]');
89761
+ codeBlocks.forEach(element => {
89762
+ let html = decodeURIComponent(element.getAttribute('data-html')); // Original code is stored in data-html attribute
89763
+ html = html.replace(/{id}/g, this.util.makeId());
89764
+ //Fill the block with original code
89765
+ this.html(element, html);
89766
+ });
89767
+ newBox.scrollIntoView({
89768
+ behavior: 'smooth',
89769
+ block: 'center'
89770
+ });
89771
+ this.applyBehaviorCanvas();
89772
+
89773
+ // ContentBuilder Handling
89774
+ let containers = newBox.querySelectorAll('.is-builder');
89775
+ containers.forEach(container => {
89776
+ let containerHtml = this.html(container);
89777
+ let range = document.createRange();
89778
+ container.innerHTML = '';
89779
+ container.appendChild(range.createContextualFragment(containerHtml));
89780
+ container.removeAttribute('data-sort'); //important (ContentBuilder cleanup for the container)
89781
+ this.applyBehaviorOn(container);
89782
+ });
89783
+ this.eb.refresh();
89784
+ this.opts.onChange();
89785
+
89786
+ // Change selection
89787
+ setTimeout(() => {
89788
+ box.classList.remove('box-select');
89789
+ const prevBox = docContainer.querySelector('.box-select');
89790
+ if (prevBox) prevBox.classList.remove('box-select');
89791
+ newBox.classList.add('box-select');
89792
+ }, 30);
89793
+ });
88833
89794
  const btnRemove = box.querySelector('.is-canvas-tool .box-remove');
88834
89795
  btnRemove.addEventListener('click', e => {
88835
89796
  const box = e.target.closest('.is-box');
@@ -89896,6 +90857,12 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
89896
90857
  script.async = true;
89897
90858
  script.onload = () => {
89898
90859
  this.opts.snippetJSON = window.data_basic;
90860
+ if (!this.canvas) for (let i = this.opts.snippetJSON.snippets.length - 1; i >= 0; i--) {
90861
+ if (this.opts.snippetJSON.snippets[i].mode === 'canvas') {
90862
+ this.opts.snippetJSON.snippets.splice(i, 1);
90863
+ }
90864
+ }
90865
+
89899
90866
  // if snippetPath is specified (not empty), then use the specified. Otherwise, use the one generated from snippet file (_snippets_path)
89900
90867
  if (this.opts.snippetPath === '') {
89901
90868
  this.opts.snippetPath = window._snippets_path;
@@ -89922,7 +90889,7 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
89922
90889
  html = `
89923
90890
  <div class="is-box box-canvas autolayout">
89924
90891
  <div class="is-block block-steady height-auto" style="top: calc(50% - 357px); left: calc(50% - 348px); width: 696px;" data--t="calc(50% - 357px)" data--l="calc(50% - 348px)" data--b="" data--r="" data--w="696px" data--h="">
89925
- <div class="is-container leading-12 size-17">
90892
+ <div class="is-container">
89926
90893
  ${html}
89927
90894
  </div>
89928
90895
  <div class="is-block-overlay"></div>
@@ -91494,6 +92461,13 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
91494
92461
 
91495
92462
  if (this.opts.emailMode) bSnippet = false;
91496
92463
 
92464
+ // check if is block
92465
+ let isBlock = false;
92466
+ if (html.includes('"is-block')) {
92467
+ isBlock = true;
92468
+ bSnippet = false;
92469
+ }
92470
+
91497
92471
  // Convert snippet into your defined 12 columns grid
91498
92472
  var rowClass = this.opts.row; //row
91499
92473
  var colClass = this.opts.cols; //['col s1', 'col s2', 'col s3', 'col s4', 'col s5', 'col s6', 'col s7', 'col s8', 'col s9', 'col s10', 'col s11', 'col s12']
@@ -91540,24 +92514,26 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
91540
92514
  this.dom.removeClass(itemEl, 'snippet-item');
91541
92515
  let bw = '';
91542
92516
  if (this.page && this.page === '.is-wrapper') {
91543
- bw = '800px';
92517
+ bw = '760px';
91544
92518
  } else {
91545
92519
  if (occurrences === 2) {
91546
- bw = '800px';
92520
+ bw = '760px';
91547
92521
  } else if (occurrences >= 3) {
91548
- bw = '800px';
92522
+ bw = '760px';
91549
92523
  } else {
91550
92524
  bw = '540px';
91551
92525
  }
91552
92526
  }
91553
92527
  const blockTemplate = `
91554
92528
  <div class="is-block block-steady height-auto" data-new-dummy="1" style="top: 20%; left: 20%; width: ${bw};">
91555
- <div class="is-container container-new leading-12 size-17">
92529
+ <div class="is-container container-new">
91556
92530
  [%CONTENT%]
91557
92531
  </div>
91558
92532
  </div>
91559
92533
  `; // data-new-dummy will be used by onSort to apply top/left position (snippetpanel.js)
91560
92534
  itemEl.outerHTML = blockTemplate.replace('[%CONTENT%]', html);
92535
+ } else if (isBlock) {
92536
+ itemEl.outerHTML = html;
91561
92537
  } else {
91562
92538
  // Snippet is wrapped in row/colum (may contain custom code or has [data-html] attribute)
91563
92539
  // Can only be inserted after current row or last row (not on column or element).
@@ -91590,19 +92566,19 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
91590
92566
  itemEl.appendChild(range.createContextualFragment(html));
91591
92567
  let bw = '';
91592
92568
  if (this.page && this.page === '.is-wrapper') {
91593
- bw = '800px';
92569
+ bw = '760px';
91594
92570
  } else {
91595
92571
  if (occurrences === 2) {
91596
- bw = '800px';
92572
+ bw = '760px';
91597
92573
  } else if (occurrences >= 3) {
91598
- bw = '800px';
92574
+ bw = '760px';
91599
92575
  } else {
91600
92576
  bw = '540px';
91601
92577
  }
91602
92578
  }
91603
92579
  const blockTemplate = `
91604
92580
  <div class="is-block block-steady height-auto" data-new-dummy="1" style="top: 20%; left: 20%; width: ${bw};">
91605
- <div class="is-container container-new leading-12 size-17">
92581
+ <div class="is-container container-new">
91606
92582
  [%CONTENT%]
91607
92583
  </div>
91608
92584
  </div>