@innovastudio/contentbuilder 1.4.145 → 1.4.147

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10355,6 +10355,14 @@ class HtmlUtil {
10355
10355
  this.builder.opts.onRender();
10356
10356
  }
10357
10357
  if (mode === 'full') {
10358
+ // freeform
10359
+ if (this.builder.docContainer) {
10360
+ this.builder.loadHTML(html);
10361
+ util.clearControls();
10362
+ this.builder.hideModal(modal);
10363
+ return;
10364
+ }
10365
+
10358
10366
  // area.innerHTML = html;
10359
10367
  area.innerHTML = '';
10360
10368
  // Use createContextualFragment() to make embedded script executable
@@ -10879,10 +10887,12 @@ class HtmlUtil {
10879
10887
  dom$k.removeElements(tmp.querySelectorAll('.row-add-initial'));
10880
10888
 
10881
10889
  //Extra cleaning
10882
- elms = tmp.querySelectorAll('.aos-init');
10883
- dom$k.removeClasses(elms, 'aos-init');
10884
- elms = tmp.querySelectorAll('.aos-animate');
10885
- dom$k.removeClasses(elms, 'aos-animate');
10890
+ if (this.builder.cleanAOS) {
10891
+ elms = tmp.querySelectorAll('.aos-init');
10892
+ dom$k.removeClasses(elms, 'aos-init');
10893
+ elms = tmp.querySelectorAll('.aos-animate');
10894
+ dom$k.removeClasses(elms, 'aos-animate');
10895
+ }
10886
10896
  elms = tmp.querySelectorAll('.skrollable');
10887
10897
  dom$k.removeClasses(elms, 'skrollable');
10888
10898
  elms = tmp.querySelectorAll('.skrollable-after');
@@ -11202,6 +11212,23 @@ class HtmlUtil {
11202
11212
  elms = tmp.querySelectorAll('[data-html-25]');
11203
11213
  dom$k.removeAttributes(elms, 'data-html-25');
11204
11214
  }
11215
+
11216
+ // freeform
11217
+ elms = tmp.querySelectorAll('.is-block .handle, .is-block .rotate-handle');
11218
+ dom$k.removeElements(elms);
11219
+ elms = tmp.querySelectorAll('.is-block');
11220
+ Array.prototype.forEach.call(elms, elm => {
11221
+ dom$k.removeClass(elm, 'active');
11222
+ dom$k.removeClass(elm, 'multi');
11223
+ dom$k.removeClass(elm, 'editable');
11224
+ dom$k.removeClass(elm, 'fluid');
11225
+ dom$k.removeClass(elm, 'cloned');
11226
+ elm.removeAttribute('data-fluid-val');
11227
+ elm.removeAttribute('data-fluid');
11228
+ });
11229
+ tmp.querySelectorAll('.is-block.clone').forEach(elm => elm.parentNode.removeChild(elm));
11230
+ // tmp.querySelectorAll('.is-block.cloned').forEach(elm=>elm.classList.remove('cloned'));
11231
+
11205
11232
  html = tmp.innerHTML.trim();
11206
11233
  html = html.replace(/<font/g, '<span').replace(/<\/font/g, '</span');
11207
11234
  }
@@ -14528,7 +14555,7 @@ Insipred by: https://www.kirupa.com/html5/drag.htm
14528
14555
  */
14529
14556
 
14530
14557
  let initialX, initialY, currentX, currentY, xOffset, yOffset, dragActive, activeDraggableBox;
14531
- class Draggable$1 {
14558
+ class Draggable$2 {
14532
14559
  constructor(opts = {}) {
14533
14560
  this.opts = opts;
14534
14561
  const elms = document.querySelectorAll(this.opts.selector);
@@ -14692,7 +14719,7 @@ const renderGridEditor = builder => {
14692
14719
  //<button title="${util.out('Element Tool')}" class="cell-elmtool"><svg class="is-icon-flex" style="width:12px;height:12px;"><use xlink:href="#ion-ios-gear"></use></svg></button>
14693
14720
 
14694
14721
  dom.appendHtml(builderStuff, html);
14695
- new Draggable$1({
14722
+ new Draggable$2({
14696
14723
  selector: '.is-draggable'
14697
14724
  });
14698
14725
  const grideditor = document.querySelector('.grideditor');
@@ -28673,7 +28700,7 @@ function dragControlCondition(moveable, e) {
28673
28700
  return false;
28674
28701
  }
28675
28702
 
28676
- var Rotatable = {
28703
+ var Rotatable$1 = {
28677
28704
  name: "rotatable",
28678
28705
  canPinch: true,
28679
28706
  props: {
@@ -28812,7 +28839,7 @@ var Rotatable = {
28812
28839
  datas.startValue = rotatation * Math.PI / 180;
28813
28840
  }
28814
28841
  }, fillTransformStartEvent(e)), {
28815
- dragStart: Draggable.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
28842
+ dragStart: Draggable$1.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
28816
28843
  }));
28817
28844
  var result = triggerEvent(moveable, "onRotateStart", params);
28818
28845
  datas.isRotate = result !== false;
@@ -32513,7 +32540,7 @@ var Snappable = {
32513
32540
  * @description Draggable refers to the ability to drag and move targets.
32514
32541
  */
32515
32542
 
32516
- var Draggable = {
32543
+ var Draggable$1 = {
32517
32544
  name: "draggable",
32518
32545
  props: {
32519
32546
  draggable: Boolean,
@@ -33401,7 +33428,7 @@ function fillTransformEvent(moveable, nextTransform, delta, isPinch, e) {
33401
33428
  fillOriginalTransform(e, nextTransform);
33402
33429
  return {
33403
33430
  transform: nextTransform,
33404
- drag: Draggable.drag(moveable, setCustomDrag(e, moveable.state, delta, isPinch, false))
33431
+ drag: Draggable$1.drag(moveable, setCustomDrag(e, moveable.state, delta, isPinch, false))
33405
33432
  };
33406
33433
  }
33407
33434
 
@@ -35298,7 +35325,7 @@ var Pinchable = makeAble("pinchable", {
35298
35325
  * @description Resizable indicates whether the target's width and height can be increased or decreased.
35299
35326
  */
35300
35327
 
35301
- var Resizable = {
35328
+ var Resizable$1 = {
35302
35329
  name: "resizable",
35303
35330
  ableGroup: "size",
35304
35331
  canPinch: true,
@@ -35443,7 +35470,7 @@ var Resizable = {
35443
35470
  setOrigin: function (origin) {
35444
35471
  datas.transformOrigin = origin;
35445
35472
  },
35446
- dragStart: Draggable.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
35473
+ dragStart: Draggable$1.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
35447
35474
  });
35448
35475
  var result = triggerEvent(moveable, "onResizeStart", params);
35449
35476
 
@@ -35628,7 +35655,7 @@ var Resizable = {
35628
35655
  dist: [distWidth, distHeight],
35629
35656
  delta: delta,
35630
35657
  isPinch: !!isPinch,
35631
- drag: Draggable.drag(moveable, setCustomDrag(e, moveable.state, inverseDelta, !!isPinch, false))
35658
+ drag: Draggable$1.drag(moveable, setCustomDrag(e, moveable.state, inverseDelta, !!isPinch, false))
35632
35659
  });
35633
35660
  triggerEvent(moveable, "onResize", params);
35634
35661
  return params;
@@ -36220,7 +36247,7 @@ var Scalable = {
36220
36247
  setRatio: setRatio,
36221
36248
  setFixedDirection: setFixedDirection
36222
36249
  }, fillTransformStartEvent(e)), {
36223
- dragStart: Draggable.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
36250
+ dragStart: Draggable$1.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
36224
36251
  }));
36225
36252
  var result = triggerEvent(moveable, "onScaleStart", params);
36226
36253
 
@@ -39363,7 +39390,7 @@ var OriginDraggable = {
39363
39390
  var datas = e.datas;
39364
39391
  setDragStart(moveable, e);
39365
39392
  var params = fillParams(moveable, e, {
39366
- dragStart: Draggable.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
39393
+ dragStart: Draggable$1.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
39367
39394
  });
39368
39395
  var result = triggerEvent(moveable, "onDragOriginStart", params);
39369
39396
  datas.startOrigin = moveable.state.transformOrigin;
@@ -39426,7 +39453,7 @@ var OriginDraggable = {
39426
39453
  dist: dist,
39427
39454
  delta: delta,
39428
39455
  transformOrigin: transformOrigin,
39429
- drag: Draggable.drag(moveable, setCustomDrag(e, moveable.state, dragDelta, !!isPinch, false))
39456
+ drag: Draggable$1.drag(moveable, setCustomDrag(e, moveable.state, dragDelta, !!isPinch, false))
39430
39457
  });
39431
39458
  triggerEvent(moveable, "onDragOrigin", params);
39432
39459
  return params;
@@ -41838,13 +41865,13 @@ var edgeDraggable = makeAble("edgeDraggable", {
41838
41865
  return hasClass(target, prefix("direction")) && hasClass(target, prefix("line"));
41839
41866
  },
41840
41867
  dragControlStart: function (moveable, e) {
41841
- return Draggable.dragStart(moveable, getDraggableEvent(e));
41868
+ return Draggable$1.dragStart(moveable, getDraggableEvent(e));
41842
41869
  },
41843
41870
  dragControl: function (moveable, e) {
41844
- return Draggable.drag(moveable, getDraggableEvent(e));
41871
+ return Draggable$1.drag(moveable, getDraggableEvent(e));
41845
41872
  },
41846
41873
  dragControlEnd: function (moveable, e) {
41847
- return Draggable.dragEnd(moveable, getDraggableEvent(e));
41874
+ return Draggable$1.dragEnd(moveable, getDraggableEvent(e));
41848
41875
  },
41849
41876
  dragGroupControlCondition: function (moveable, e) {
41850
41877
  if (!moveable.props.edgeDraggable || !e.inputEvent) {
@@ -41855,16 +41882,16 @@ var edgeDraggable = makeAble("edgeDraggable", {
41855
41882
  return hasClass(target, prefix("direction")) && hasClass(target, prefix("line"));
41856
41883
  },
41857
41884
  dragGroupControlStart: function (moveable, e) {
41858
- return Draggable.dragGroupStart(moveable, getDraggableEvent(e));
41885
+ return Draggable$1.dragGroupStart(moveable, getDraggableEvent(e));
41859
41886
  },
41860
41887
  dragGroupControl: function (moveable, e) {
41861
- return Draggable.dragGroup(moveable, getDraggableEvent(e));
41888
+ return Draggable$1.dragGroup(moveable, getDraggableEvent(e));
41862
41889
  },
41863
41890
  dragGroupControlEnd: function (moveable, e) {
41864
- return Draggable.dragGroupEnd(moveable, getDraggableEvent(e));
41891
+ return Draggable$1.dragGroupEnd(moveable, getDraggableEvent(e));
41865
41892
  },
41866
41893
  unset: function (moveable) {
41867
- return Draggable.unset(moveable);
41894
+ return Draggable$1.unset(moveable);
41868
41895
  }
41869
41896
  });
41870
41897
  /**
@@ -41888,7 +41915,7 @@ var IndividualGroupable = {
41888
41915
  },
41889
41916
  events: {}
41890
41917
  };
41891
- var MOVEABLE_ABLES = [BeforeRenderable, Default, Snappable, Pinchable, Draggable, edgeDraggable, Rotatable, Resizable, Scalable, Warpable, Scrollable, Padding, Origin, OriginDraggable, Clippable, Roundable, Groupable, IndividualGroupable, Clickable, DragArea, Renderable];
41918
+ var MOVEABLE_ABLES = [BeforeRenderable, Default, Snappable, Pinchable, Draggable$1, edgeDraggable, Rotatable$1, Resizable$1, Scalable, Warpable, Scrollable, Padding, Origin, OriginDraggable, Clippable, Roundable, Groupable, IndividualGroupable, Clickable, DragArea, Renderable];
41892
41919
  var MOVEABLE_EVENTS_PROPS_MAP = /*#__PURE__*/MOVEABLE_ABLES.reduce(function (current, able) {
41893
41920
  return __assign$2(__assign$2({}, current), "events" in able ? able.events : {});
41894
41921
  }, {});
@@ -52085,7 +52112,7 @@ class ColorPicker {
52085
52112
  });
52086
52113
  };
52087
52114
  setupTabKeys(pickcolor);
52088
- new Draggable$1({
52115
+ new Draggable$2({
52089
52116
  selector: '#' + this.id + ' .is-draggable'
52090
52117
  });
52091
52118
  let tmp = document.createElement('div');
@@ -52950,7 +52977,7 @@ class GradientPicker {
52950
52977
  });
52951
52978
  };
52952
52979
  setupTabKeys(pickGradient);
52953
- new Draggable$1({
52980
+ new Draggable$2({
52954
52981
  selector: '#' + this.id + ' .is-draggable'
52955
52982
  });
52956
52983
  const colorPicker = new ColorPicker({
@@ -75401,7 +75428,2106 @@ class Similarity {
75401
75428
  }
75402
75429
  }
75403
75430
 
75404
- // import ControlPanel from './controlpanel.js';
75431
+ class Common {
75432
+ constructor(options) {
75433
+ this.selector = options && options.selector || '.is-block';
75434
+ this.doc = options && options.doc || document;
75435
+ this.win = options && options.win || window;
75436
+ this.onDuplicate = options && options.onDuplicate || null;
75437
+ }
75438
+ transform2d(block, x1, y1, x2, y2, x3, y3, x4, y4) {
75439
+ this.matrix3d = new Matrix3D();
75440
+ return this.matrix3d.transform2d(block, x1, y1, x2, y2, x3, y3, x4, y4);
75441
+ }
75442
+ applyPercentage(block) {
75443
+ const rect = this.getRect(block);
75444
+ const container = block.parentNode;
75445
+ let isChildBlock = false;
75446
+ if (block.parentNode.matches(this.selector)) {
75447
+ // child block
75448
+ isChildBlock = true;
75449
+ }
75450
+
75451
+ // const containerRect = container.getBoundingClientRect(); // if container has top/left
75452
+ const containerRect = this.getRect(container); // if container has top/left
75453
+ const left = (rect.left - containerRect.left) / container.offsetWidth * 100;
75454
+ const top = (rect.top - containerRect.top) / container.offsetHeight * 100;
75455
+ let isBlockFixed = block.classList.contains('block-steady');
75456
+ if (isBlockFixed) {
75457
+ let dividerTop = (container.offsetHeight - block.offsetHeight) / (rect.top - containerRect.top);
75458
+ if (isNaN(dividerTop)) {
75459
+ // there is possibility of 0/0
75460
+ dividerTop = 1;
75461
+ }
75462
+ block.style.top = `calc((100% - ${block.offsetHeight}px)/${dividerTop})`;
75463
+ if (isChildBlock) {
75464
+ block.style.top = top + '%';
75465
+ }
75466
+ let dividerLeft = (container.offsetWidth - block.offsetWidth) / (rect.left - containerRect.left);
75467
+ if (isNaN(dividerLeft)) {
75468
+ // there is possibility of 0/0
75469
+ dividerLeft = 1;
75470
+ }
75471
+ // if(rect.left-containerRect.left===0) { // dividerLeft = Infinity
75472
+ // dividerLeft=1;
75473
+ // }
75474
+ block.style.left = `calc((100% - ${block.offsetWidth}px)/${dividerLeft})`;
75475
+ if (isChildBlock) {
75476
+ block.style.left = left + '%';
75477
+ }
75478
+ } else {
75479
+ const width = block.offsetWidth / container.offsetWidth * 100;
75480
+ const height = block.offsetHeight / container.offsetHeight * 100;
75481
+ block.style.width = width + '%';
75482
+ block.style.height = height + '%';
75483
+ block.style.top = top + '%';
75484
+ block.style.left = left + '%';
75485
+ }
75486
+ }
75487
+ applyPixels(block) {
75488
+ const rect = this.getRect(block);
75489
+ const containerRect = this.getRect(block.parentNode); // if container has top/left
75490
+ block.style.left = rect.left - containerRect.left + 'px';
75491
+ block.style.top = rect.top - containerRect.top + 'px';
75492
+ block.style.width = block.offsetWidth + 'px';
75493
+ }
75494
+ updateHeight(block) {
75495
+ if (!block.parentNode) return;
75496
+ let clonedDiv = block.cloneNode(true);
75497
+ clonedDiv.style.position = 'absolute';
75498
+ clonedDiv.style.top = '-9999px';
75499
+ clonedDiv.style.left = '-9999px';
75500
+ block.parentNode.appendChild(clonedDiv);
75501
+ clonedDiv.style.height = '';
75502
+ setTimeout(() => {
75503
+ let clonedDivHeight = clonedDiv.offsetHeight;
75504
+ if (block.offsetHeight <= clonedDivHeight) {
75505
+ block.style.height = clonedDivHeight + 'px';
75506
+ setTimeout(() => {
75507
+ block.parentNode.removeChild(clonedDiv);
75508
+ }, 10);
75509
+ } else {
75510
+ block.parentNode.removeChild(clonedDiv);
75511
+ }
75512
+ }, 10);
75513
+ }
75514
+ duplicate() {
75515
+ const block = this.doc.querySelector(this.selector + '.active');
75516
+ if (!block) return;
75517
+ if (this.onDuplicate) this.onDuplicate(block);
75518
+ }
75519
+ getRect(element) {
75520
+ let group = element.parentNode.closest(this.selector);
75521
+ if (element.closest(this.selector) && group) {
75522
+ let transform = group.style.transform;
75523
+ if (transform.includes('rotate')) {
75524
+ // Create a temporary element with the same dimensions and position
75525
+ const tempGroup = this.doc.createElement('div');
75526
+ tempGroup.style.position = 'absolute';
75527
+ tempGroup.style.width = group.offsetWidth + 'px';
75528
+ tempGroup.style.height = group.offsetHeight + 'px';
75529
+ tempGroup.style.left = group.style.left;
75530
+ tempGroup.style.top = group.style.top;
75531
+ // tempGroup.style.border ='red 1px solid';
75532
+ group.parentNode.appendChild(tempGroup);
75533
+ // const wrapperRect = tempGroup.getBoundingClientRect(); // Get the unrotated position
75534
+
75535
+ // Create a temporary element with the same dimensions and position
75536
+ const tempElement = this.doc.createElement('div');
75537
+ tempElement.style.position = 'absolute';
75538
+ tempElement.style.width = element.offsetWidth + 'px';
75539
+ tempElement.style.height = element.offsetHeight + 'px';
75540
+ tempElement.style.left = element.style.left;
75541
+ tempElement.style.top = element.style.top;
75542
+ // tempElement.style.border ='green 1px solid';
75543
+ tempGroup.appendChild(tempElement);
75544
+ const tempRect = tempElement.getBoundingClientRect(); // Get the unrotated position
75545
+
75546
+ // let top = tempRect.top - wrapperRect.top;
75547
+ // let left = tempRect.left - wrapperRect.left;
75548
+
75549
+ setTimeout(() => {
75550
+ tempElement.parentNode.removeChild(tempElement);
75551
+ tempGroup.parentNode.removeChild(tempGroup);
75552
+ }, 0);
75553
+ return tempRect;
75554
+ }
75555
+ }
75556
+ const rect = element.getBoundingClientRect();
75557
+ const transform = this.win.getComputedStyle(element).getPropertyValue('transform');
75558
+ if (transform !== 'none') {
75559
+ // Create a temporary element with the same dimensions and position
75560
+ const tempElement = this.doc.createElement('div');
75561
+ tempElement.style.position = 'absolute';
75562
+ tempElement.style.width = element.offsetWidth + 'px';
75563
+ tempElement.style.height = element.offsetHeight + 'px';
75564
+ tempElement.style.left = element.style.left;
75565
+ tempElement.style.top = element.style.top;
75566
+ // tempElement.style.border ='green 1px solid';
75567
+ element.parentNode.appendChild(tempElement);
75568
+
75569
+ // Get the unrotated position of the temporary element
75570
+ const tempRect = tempElement.getBoundingClientRect();
75571
+ setTimeout(() => {
75572
+ tempElement.parentNode.removeChild(tempElement);
75573
+ }, 1);
75574
+ return tempRect;
75575
+ } else {
75576
+ return rect;
75577
+ }
75578
+ }
75579
+ getTranslateValues(transformString) {
75580
+ // Regular expression to match the translate values in the transform string
75581
+ const regex = /translate\((-?\d+\.?\d*)px, (-?\d+\.?\d*)px\)/;
75582
+
75583
+ // Use the regular expression to extract x and y values
75584
+ const match = transformString.match(regex);
75585
+
75586
+ // If there's a match, return an object with x and y values
75587
+ if (match) {
75588
+ const [, x, y] = match.map(parseFloat);
75589
+ return {
75590
+ x,
75591
+ y
75592
+ };
75593
+ }
75594
+
75595
+ // If no match, return null or handle it as needed
75596
+ return null;
75597
+ }
75598
+ group(className = 'is-block', groupClassName = 'is-group') {
75599
+ let top = Infinity;
75600
+ let left = Infinity;
75601
+ let bottom = -Infinity;
75602
+ let right = -Infinity;
75603
+
75604
+ // Check group
75605
+ let blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active'));
75606
+ if (blocks.length <= 1) return;
75607
+
75608
+ // Check if there is selected block that is part of other group
75609
+ let ok = true;
75610
+ blocks.forEach(block => {
75611
+ if (block.parentNode.matches(this.selector)) {
75612
+ // TODO: detach block
75613
+ alert('One or more blocks belong to another group.');
75614
+ ok = false;
75615
+ }
75616
+ });
75617
+ if (!ok) return;
75618
+ blocks.forEach(block => {
75619
+ let elms = block.querySelectorAll(this.selector);
75620
+ if (elms.length > 0) {
75621
+ elms.forEach(elm => elm.classList.add('active'));
75622
+ this.unGroup(block);
75623
+ }
75624
+ });
75625
+ blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active'));
75626
+ blocks.forEach(block => {
75627
+ if (!block.parentNode.matches(this.selector)) {
75628
+ const rect = this.getRect(block);
75629
+ let blockTop = rect.top;
75630
+ let blockLeft = rect.left;
75631
+ let blockWidth = block.offsetWidth;
75632
+ let blockHeight = block.offsetHeight;
75633
+ top = Math.min(top, blockTop);
75634
+ left = Math.min(left, blockLeft);
75635
+ bottom = Math.max(bottom, blockTop + blockHeight);
75636
+ right = Math.max(right, blockLeft + blockWidth);
75637
+ }
75638
+ });
75639
+ const group = this.doc.createElement('div');
75640
+ group.classList.add(className);
75641
+ group.classList.add(groupClassName);
75642
+ group.classList.add('block-steady');
75643
+ group.style.top = top + 'px';
75644
+ group.style.left = left + 'px';
75645
+ group.style.width = right + 1 - left + 'px';
75646
+ group.style.height = bottom + 1 - top + 'px';
75647
+ const container = blocks[0].parentNode;
75648
+ container.appendChild(group);
75649
+ blocks.forEach(block => {
75650
+ if (!block.parentNode.matches(this.selector)) {
75651
+ this.applyPixels(block);
75652
+ let blockTop = parseFloat(block.style.top) || 0;
75653
+ let blockLeft = parseFloat(block.style.left) || 0;
75654
+
75655
+ // Adjust position relative to the group div
75656
+ block.style.top = blockTop - top + 'px';
75657
+ block.style.left = blockLeft - left + 'px';
75658
+ group.appendChild(block);
75659
+ this.applyPercentage(block);
75660
+ }
75661
+ });
75662
+ this.applyPercentage(group);
75663
+ blocks.forEach(block => {
75664
+ block.classList.remove('active');
75665
+ });
75666
+ group.classList.add('active');
75667
+ blocks = group.querySelectorAll(this.selector);
75668
+ blocks.forEach(target => {
75669
+ // Remove all breakpoints
75670
+ let attributesToRemove = [];
75671
+ const attributes = target.attributes;
75672
+ for (let i = 0; i < attributes.length; i++) {
75673
+ const attributeName = attributes[i].name;
75674
+ if (attributeName.includes('data--y-') || attributeName.includes('data--x-') || attributeName.includes('data--w-') || attributeName.includes('data--h-')) {
75675
+ attributesToRemove.push(attributeName);
75676
+ }
75677
+ }
75678
+ attributesToRemove.forEach(attr => {
75679
+ target.removeAttribute(attr);
75680
+ });
75681
+
75682
+ // Make/save current inline style as default
75683
+ target.removeAttribute('data-breakpoint');
75684
+ target.setAttribute('data--y', target.style.top);
75685
+ target.setAttribute('data--x', target.style.left);
75686
+ target.setAttribute('data--w', target.style.width);
75687
+ target.setAttribute('data--h', target.style.height);
75688
+ });
75689
+ return group;
75690
+ }
75691
+ unGroup(element) {
75692
+ let group;
75693
+ if (element) group = element;else {
75694
+ let blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active'));
75695
+ blocks.forEach(block => {
75696
+ if (block.querySelector(this.selector)) {
75697
+ // this block is a group
75698
+ this.unGroup(block);
75699
+ }
75700
+ });
75701
+ return;
75702
+ }
75703
+ if (!group) return;
75704
+ if (!group.querySelector(this.selector)) return;
75705
+ this.applyPixels(group);
75706
+ const rect = this.getRect(group);
75707
+ const top = rect.top;
75708
+ const left = rect.left;
75709
+ const container = group.parentNode;
75710
+ group.querySelectorAll(this.selector).forEach(block => {
75711
+ this.applyPixels(block);
75712
+ let blockTop = parseFloat(block.style.top) || 0;
75713
+ let blockLeft = parseFloat(block.style.left) || 0;
75714
+
75715
+ // Adjust position relative to the group div
75716
+ block.style.top = blockTop + top + 'px';
75717
+ block.style.left = blockLeft + left + 'px';
75718
+ container.appendChild(block);
75719
+
75720
+ // Remove all breakpoints
75721
+ let attributesToRemove = [];
75722
+ const attributes = block.attributes;
75723
+ for (let i = 0; i < attributes.length; i++) {
75724
+ const attributeName = attributes[i].name;
75725
+ if (attributeName.includes('data--y-') || attributeName.includes('data--x-') || attributeName.includes('data--w-') || attributeName.includes('data--h-')) {
75726
+ attributesToRemove.push(attributeName);
75727
+ }
75728
+ }
75729
+ attributesToRemove.forEach(attr => {
75730
+ block.removeAttribute(attr);
75731
+ });
75732
+ // Make/save current inline style as default
75733
+ block.removeAttribute('data-breakpoint');
75734
+ block.setAttribute('data--y', block.style.top);
75735
+ block.setAttribute('data--x', block.style.left);
75736
+ block.setAttribute('data--w', block.style.width);
75737
+ block.setAttribute('data--h', block.style.height);
75738
+ this.applyPercentage(block);
75739
+ });
75740
+ group.parentElement.removeChild(group);
75741
+ }
75742
+ addBreakpoint() {
75743
+ const viewportWidth = this.win.innerWidth;
75744
+ this.doc.body.setAttribute('data-breakpoint', viewportWidth);
75745
+ }
75746
+
75747
+ /*
75748
+ clearBreakpoint(target) {
75749
+ let breakpoint = target.getAttribute('data-breakpoint');
75750
+ if(!breakpoint) return;
75751
+ if(target.hasAttribute('data--y-'+breakpoint)) {
75752
+ target.removeAttribute('data--y-'+breakpoint);
75753
+ let top = target.getAttribute('data--y');
75754
+ if(top) target.style.top = top;
75755
+ }
75756
+ if(target.hasAttribute('data--x-'+breakpoint)) {
75757
+ target.removeAttribute('data--x-'+breakpoint);
75758
+ let left = target.getAttribute('data--x');
75759
+ if(left) target.style.left = left;
75760
+ }
75761
+ if(target.hasAttribute('data--w-'+breakpoint)) {
75762
+ target.removeAttribute('data--w-'+breakpoint);
75763
+ let width = target.getAttribute('data--w');
75764
+ if(width) target.style.width = width;
75765
+ }
75766
+ if(target.hasAttribute('data--h-'+breakpoint)) {
75767
+ target.removeAttribute('data--h-'+breakpoint);
75768
+ let height = target.getAttribute('data--h');
75769
+ if(height) target.style.height = height;
75770
+ }
75771
+ target.removeAttribute('data-breakpoint');
75772
+ // reset
75773
+ let top = target.getAttribute('data--y');
75774
+ if(top)target.style.top = top;
75775
+ let left = target.getAttribute('data--x');
75776
+ if(left) target.style.left = left;
75777
+ let width = target.getAttribute('data--w');
75778
+ if(width) target.style.width = width;
75779
+ let height = target.getAttribute('data--h');
75780
+ if(height) target.style.height = height;
75781
+ }
75782
+ */
75783
+
75784
+ clearBreakpoint(target) {
75785
+ let attributesToRemove = [];
75786
+ const attributes = target.attributes;
75787
+ for (let i = 0; i < attributes.length; i++) {
75788
+ const attributeName = attributes[i].name;
75789
+ if (attributeName.includes('data--y-') || attributeName.includes('data--x-') || attributeName.includes('data--w-') || attributeName.includes('data--h-') || attributeName.includes('data--transform-') || attributeName.includes('data--matrix-')) {
75790
+ attributesToRemove.push(attributeName);
75791
+ }
75792
+ }
75793
+ attributesToRemove.forEach(attr => {
75794
+ target.removeAttribute(attr);
75795
+ });
75796
+ target.removeAttribute('data-breakpoint');
75797
+
75798
+ // reset
75799
+ let top = target.getAttribute('data--y');
75800
+ if (top) target.style.top = top;
75801
+ let left = target.getAttribute('data--x');
75802
+ if (left) target.style.left = left;
75803
+ let width = target.getAttribute('data--w');
75804
+ if (width) target.style.width = width;
75805
+ let height = target.getAttribute('data--h');
75806
+ if (height) target.style.height = height;
75807
+ }
75808
+ clearAllBreakpoints(container) {
75809
+ // REVIEW (Currently not used)
75810
+ const elements = container.querySelectorAll(this.selector);
75811
+ elements.forEach(target => {
75812
+ let attributesToRemove = [];
75813
+ const attributes = target.attributes;
75814
+ for (let i = 0; i < attributes.length; i++) {
75815
+ const attributeName = attributes[i].name;
75816
+ if (attributeName.includes('data--y-') || attributeName.includes('data--x-') || attributeName.includes('data--w-') || attributeName.includes('data--h-') || attributeName.includes('data--transform-') || attributeName.includes('data--matrix-')) {
75817
+ attributesToRemove.push(attributeName);
75818
+ }
75819
+ }
75820
+ attributesToRemove.forEach(attr => {
75821
+ target.removeAttribute(attr);
75822
+ });
75823
+ });
75824
+ elements.forEach(target => {
75825
+ let y = target.getAttribute('data--y');
75826
+ let x = target.getAttribute('data--x');
75827
+ let w = target.getAttribute('data--w');
75828
+ let h = target.getAttribute('data--h');
75829
+ if (y) target.style.top = y;
75830
+ if (x) target.style.left = x;
75831
+ if (w) target.style.width = w;
75832
+ if (h) target.style.height = h;
75833
+ });
75834
+ }
75835
+ getBreakpoints(target) {
75836
+ let breakpoints = [];
75837
+ const attributes = target.attributes;
75838
+ for (let i = 0; i < attributes.length; i++) {
75839
+ const attributeName = attributes[i].name;
75840
+ if (attributeName.includes('data--y-') || attributeName.includes('data--x-') || attributeName.includes('data--w-') || attributeName.includes('data--h-')) {
75841
+ let val = attributeName.replace('data--y-', '');
75842
+ val = val.replace('data--x-', '');
75843
+ val = val.replace('data--w-', '');
75844
+ val = val.replace('data--h-', '');
75845
+ if (!breakpoints.includes(val)) breakpoints.push(val);
75846
+ }
75847
+ }
75848
+ return breakpoints;
75849
+ }
75850
+ getSelectedBlock() {
75851
+ const blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active') && !elm.classList.contains('cloned'));
75852
+ if (blocks.length === 1) {
75853
+ const block = blocks[0];
75854
+ return block;
75855
+ }
75856
+ return false;
75857
+ }
75858
+ checkOverlap(target) {
75859
+ const targetRect = target.getBoundingClientRect();
75860
+ const blocks = Array.from(target.parentNode.querySelectorAll(this.selector)).filter(elm => !elm.classList.contains('cloned'));
75861
+ let overlappedBlocks = [];
75862
+ for (const block of blocks) {
75863
+ if (block !== target) {
75864
+ const blockRect = block.getBoundingClientRect();
75865
+ if (targetRect.top < blockRect.bottom && targetRect.bottom > blockRect.top && targetRect.left < blockRect.right && targetRect.right > blockRect.left) {
75866
+ overlappedBlocks.push(block);
75867
+ }
75868
+ }
75869
+ }
75870
+ return overlappedBlocks;
75871
+ }
75872
+ }
75873
+ class Matrix3D {
75874
+ adj(m) {
75875
+ return [m[4] * m[8] - m[5] * m[7], m[2] * m[7] - m[1] * m[8], m[1] * m[5] - m[2] * m[4], m[5] * m[6] - m[3] * m[8], m[0] * m[8] - m[2] * m[6], m[2] * m[3] - m[0] * m[5], m[3] * m[7] - m[4] * m[6], m[1] * m[6] - m[0] * m[7], m[0] * m[4] - m[1] * m[3]];
75876
+ }
75877
+ multmm(a, b) {
75878
+ const c = Array(9);
75879
+ for (var i = 0; i != 3; ++i) {
75880
+ for (var j = 0; j != 3; ++j) {
75881
+ var cij = 0;
75882
+ for (var k = 0; k != 3; ++k) {
75883
+ cij += a[3 * i + k] * b[3 * k + j];
75884
+ }
75885
+ c[3 * i + j] = cij;
75886
+ }
75887
+ }
75888
+ return c;
75889
+ }
75890
+ multmv(m, v) {
75891
+ return [m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[3] * v[0] + m[4] * v[1] + m[5] * v[2], m[6] * v[0] + m[7] * v[1] + m[8] * v[2]];
75892
+ }
75893
+ pdbg(m, v) {
75894
+ const r = this.multmv(m, v);
75895
+ return r + ' (' + r[0] / r[2] + ', ' + r[1] / r[2] + ')';
75896
+ }
75897
+ basisToPoints(x1, y1, x2, y2, x3, y3, x4, y4) {
75898
+ const m = [x1, x2, x3, y1, y2, y3, 1, 1, 1];
75899
+ const v = this.multmv(this.adj(m), [x4, y4, 1]);
75900
+ return this.multmm(m, [v[0], 0, 0, 0, v[1], 0, 0, 0, v[2]]);
75901
+ }
75902
+ general2DProjection(x1s, y1s, x1d, y1d, x2s, y2s, x2d, y2d, x3s, y3s, x3d, y3d, x4s, y4s, x4d, y4d) {
75903
+ const s = this.basisToPoints(x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s);
75904
+ const d = this.basisToPoints(x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d);
75905
+ return this.multmm(d, this.adj(s));
75906
+ }
75907
+ project(m, x, y) {
75908
+ const v = this.multmv(m, [x, y, 1]);
75909
+ return [v[0] / v[2], v[1] / v[2]];
75910
+ }
75911
+ transform2d(element, x1, y1, x2, y2, x3, y3, x4, y4) {
75912
+ const w = element.offsetWidth,
75913
+ h = element.offsetHeight;
75914
+ let t = this.general2DProjection(0, 0, x1, y1, w, 0, x2, y2, 0, h, x3, y3, w, h, x4, y4);
75915
+ for (let i = 0; i != 9; ++i) t[i] = t[i] / t[8];
75916
+ t = [t[0], t[3], 0, t[6], t[1], t[4], 0, t[7], 0, 0, 1, 0, t[2], t[5], 0, t[8]];
75917
+ t = 'matrix3d(' + t.join(', ') + ')';
75918
+ return t;
75919
+ }
75920
+ }
75921
+ class Ruler {
75922
+ constructor(options) {
75923
+ this.selector = options && options.selector || '.is-block';
75924
+ this.doc = options && options.doc || document;
75925
+ this.win = options && options.win || window;
75926
+ const rulerHTML = `
75927
+ <div class="ruler horizontal-ruler" id="horizontal-ruler-top"></div>
75928
+ <div class="ruler horizontal-ruler" id="horizontal-ruler-bottom"></div>
75929
+ <div class="ruler horizontal-ruler" id="horizontal-ruler-middle"></div>
75930
+ <div class="ruler vertical-ruler" id="vertical-ruler-left"></div>
75931
+ <div class="ruler vertical-ruler" id="vertical-ruler-right"></div>
75932
+ <div class="ruler vertical-ruler" id="vertical-ruler-center"></div>
75933
+ `;
75934
+ if (!this.doc.getElementById('horizontal-ruler-top')) this.doc.body.insertAdjacentHTML('beforeend', rulerHTML);
75935
+ this.horizontalRulerTop = this.doc.getElementById('horizontal-ruler-top');
75936
+ this.horizontalRulerBottom = this.doc.getElementById('horizontal-ruler-bottom');
75937
+ this.horizontalRulerMiddle = this.doc.getElementById('horizontal-ruler-middle');
75938
+ this.verticalRulerLeft = this.doc.getElementById('vertical-ruler-left');
75939
+ this.verticalRulerRight = this.doc.getElementById('vertical-ruler-right');
75940
+ this.verticalRulerCenter = this.doc.getElementById('vertical-ruler-center');
75941
+ this.setup();
75942
+ }
75943
+ setup() {
75944
+ this.elements = this.doc.querySelectorAll(this.selector);
75945
+ }
75946
+ refresh() {
75947
+ this.elements = this.doc.querySelectorAll(this.selector);
75948
+ }
75949
+ destroy() {
75950
+ [this.horizontalRulerTop, this.horizontalRulerBottom, this.verticalRulerLeft, this.verticalRulerRight].forEach(elm => {
75951
+ if (elm.parentNode) elm.parentNode.removeChild(elm);
75952
+ });
75953
+ }
75954
+ hideRulers() {
75955
+ this.horizontalRulerTop.style.top = '-1000px';
75956
+ this.horizontalRulerBottom.style.top = '-1000px';
75957
+ this.horizontalRulerMiddle.style.top = '-1000px';
75958
+ this.verticalRulerLeft.style.left = '-1000px';
75959
+ this.verticalRulerRight.style.left = '-1000px';
75960
+ this.verticalRulerCenter.style.left = '-1000px';
75961
+ this.rulerTop = null;
75962
+ this.rulerLeft = null;
75963
+ this.rulerRight = null;
75964
+ }
75965
+ updateRulers(block) {
75966
+ // if(block.querySelector(this.selector)) return; // group (because updateRules also calls parent group if child block is dragged)
75967
+
75968
+ let transform = block.style.transform;
75969
+ if (transform.includes('rotate') || transform.includes('matrix3d')) return;
75970
+ let parentTransform = block.parentNode.style.transform;
75971
+ if (parentTransform.includes('rotate')) return;
75972
+ this.hideRulers();
75973
+ const rect = block.getBoundingClientRect();
75974
+ const top = rect.top;
75975
+ const bottom = top + block.offsetHeight;
75976
+ const left = rect.left;
75977
+ const right = left + block.offsetWidth;
75978
+ const center = left + block.offsetWidth / 2;
75979
+ const middle = top + block.offsetHeight / 2;
75980
+ this.rulerTop = null;
75981
+ this.rulerLeft = null;
75982
+ this.rulerRight = null;
75983
+ let containerTop = 0;
75984
+ const container = block.parentNode;
75985
+ if (container) {
75986
+ this.elements = container.querySelectorAll(this.selector);
75987
+ containerTop = this.win.scrollY;
75988
+ }
75989
+ this.elements.forEach(element => {
75990
+ if (!this.doc.body.contains(element)) return; // in case element removed (eg. unGroup, block deleted)
75991
+
75992
+ if (block.contains(element)) return; // In case of group moving
75993
+
75994
+ let transform = element.style.transform;
75995
+ let parentTransform = element.parentNode.style.transform;
75996
+ if (!transform.includes('rotate') && !parentTransform.includes('rotate') && !transform.includes('matrix3d') && !parentTransform.includes('matrix3d') && element !== block && !element.classList.contains('cloned')) {
75997
+ const rect = element.getBoundingClientRect();
75998
+ const otherTop = rect.top;
75999
+ const otherBottom = rect.top + element.offsetHeight;
76000
+ const otherLeft = rect.left;
76001
+ const otherRight = rect.left + element.offsetWidth;
76002
+ const otherMiddle = rect.top + element.offsetHeight / 2;
76003
+ const otherCenter = rect.left + element.offsetWidth / 2;
76004
+ if (otherMiddle - 4 <= middle && middle <= otherMiddle + 4) {
76005
+ this.horizontalRulerMiddle.style.top = containerTop + otherTop + (element.offsetHeight - block.offsetHeight) / 2 + block.offsetHeight / 2 + 'px';
76006
+ let val = otherTop + (element.offsetHeight - block.offsetHeight) / 2;
76007
+ if (this.rulerTop === null) this.rulerTop = val;
76008
+ }
76009
+ if (otherCenter - 4 <= center && center <= otherCenter + 4) {
76010
+ this.verticalRulerCenter.style.left = otherLeft + (element.offsetWidth - block.offsetWidth) / 2 + block.offsetWidth / 2 + 'px';
76011
+ this.verticalRulerCenter.style.top = containerTop + 'px'; // adj
76012
+
76013
+ let val = otherLeft + (element.offsetWidth - block.offsetWidth) / 2;
76014
+ if (this.rulerLeft === null) this.rulerLeft = val;
76015
+ }
76016
+
76017
+ // block top
76018
+ if (otherTop - 4 <= top && top <= otherTop + 4) {
76019
+ this.horizontalRulerTop.style.top = containerTop + otherTop + 'px';
76020
+ let val = otherTop;
76021
+ if (this.rulerTop === null) this.rulerTop = val;
76022
+ }
76023
+ if (otherBottom - 4 <= top && top <= otherBottom + 4) {
76024
+ this.horizontalRulerTop.style.top = containerTop + otherBottom + 'px';
76025
+ let val = otherBottom;
76026
+ if (this.rulerTop === null) this.rulerTop = val;
76027
+ }
76028
+
76029
+ // block bottom
76030
+ if (otherTop - 4 <= bottom && bottom <= otherTop + 4) {
76031
+ this.horizontalRulerBottom.style.top = containerTop + otherTop + 'px';
76032
+ let val = otherTop - block.offsetHeight;
76033
+ if (this.rulerTop === null) this.rulerTop = val;
76034
+ }
76035
+ if (otherBottom - 4 <= bottom && bottom <= otherBottom + 4) {
76036
+ this.horizontalRulerBottom.style.top = containerTop + otherBottom + 'px';
76037
+ let val = otherBottom - block.offsetHeight;
76038
+ if (this.rulerTop === null) this.rulerTop = val;
76039
+ }
76040
+
76041
+ // block left
76042
+ if (otherLeft - 4 <= left && left <= otherLeft + 4) {
76043
+ this.verticalRulerLeft.style.left = otherLeft + 'px';
76044
+ this.verticalRulerLeft.style.top = containerTop + 'px'; // adj
76045
+
76046
+ let val = otherLeft;
76047
+ if (this.rulerLeft === null) this.rulerLeft = val;
76048
+ }
76049
+ if (otherRight - 4 <= left && left <= otherRight + 4) {
76050
+ this.verticalRulerLeft.style.left = otherRight + 'px';
76051
+ this.verticalRulerLeft.style.top = containerTop + 'px'; // adj
76052
+
76053
+ let val = otherRight;
76054
+ if (this.rulerLeft === null) this.rulerLeft = val;
76055
+ }
76056
+
76057
+ // block right
76058
+ if (otherLeft - 4 <= right && right <= otherLeft + 4) {
76059
+ this.verticalRulerRight.style.left = otherLeft + 'px';
76060
+ this.verticalRulerRight.style.top = containerTop + 'px'; // adj
76061
+
76062
+ let val = otherLeft;
76063
+ if (this.rulerRight === null) this.rulerRight = val;
76064
+ }
76065
+ if (otherRight - 4 <= right && right <= otherRight + 4) {
76066
+ this.verticalRulerRight.style.left = otherRight + 'px';
76067
+ this.verticalRulerRight.style.top = containerTop + 'px'; // adj
76068
+
76069
+ let val = otherRight;
76070
+ if (this.rulerRight === null) this.rulerRight = val;
76071
+ }
76072
+ }
76073
+ });
76074
+
76075
+ // Edges
76076
+ const conRect = block.parentNode.getBoundingClientRect();
76077
+ const conTop = conRect.top;
76078
+ const conBottom = conRect.top + block.parentNode.offsetHeight;
76079
+ const conLeft = conRect.left;
76080
+ const conRight = conRect.left + block.parentNode.offsetWidth;
76081
+ const conCenter = conRect.left + block.parentNode.offsetWidth / 2;
76082
+ const conMiddle = conRect.top + block.parentNode.offsetHeight / 2;
76083
+ if (conMiddle - 4 <= middle && middle <= conMiddle + 4) {
76084
+ this.horizontalRulerMiddle.style.top = containerTop + conTop + (block.parentNode.offsetHeight - block.offsetHeight) / 2 + block.offsetHeight / 2 + 'px';
76085
+ let val = conTop + (block.parentNode.offsetHeight - block.offsetHeight) / 2;
76086
+ if (this.rulerTop === null) this.rulerTop = val;
76087
+ }
76088
+ if (conCenter - 4 <= center && center <= conCenter + 4) {
76089
+ this.verticalRulerCenter.style.left = conLeft + (block.parentNode.offsetWidth - block.offsetWidth) / 2 + block.offsetWidth / 2 + 'px';
76090
+ this.verticalRulerCenter.style.top = containerTop + 'px';
76091
+ let val = conLeft + (block.parentNode.offsetWidth - block.offsetWidth) / 2;
76092
+ if (this.rulerLeft === null) this.rulerLeft = val;
76093
+ }
76094
+
76095
+ // block top
76096
+ if (conTop - 4 <= top && top <= conTop + 4) {
76097
+ this.horizontalRulerTop.style.top = containerTop + conTop + 'px';
76098
+ let val = conTop;
76099
+ if (this.rulerTop === null) this.rulerTop = val;
76100
+ }
76101
+ // block bottom
76102
+ if (conBottom - 4 <= bottom && bottom <= conBottom + 4) {
76103
+ this.horizontalRulerBottom.style.top = containerTop + conBottom - 3 + 'px'; // -3 is an adjustment to make the line visible
76104
+
76105
+ let val = conBottom - block.offsetHeight;
76106
+ if (this.rulerTop === null) this.rulerTop = val;
76107
+ }
76108
+ // block left
76109
+ if (conLeft - 4 <= left && left <= conLeft + 4) {
76110
+ this.verticalRulerLeft.style.left = conLeft + 2 + 'px'; // +3 is an adjustment
76111
+ this.verticalRulerLeft.style.top = containerTop + 'px';
76112
+ let val = conLeft;
76113
+ if (this.rulerLeft === null) this.rulerLeft = val;
76114
+ }
76115
+ // block right
76116
+ if (conRight - 4 <= right && right <= conRight + 4) {
76117
+ this.verticalRulerRight.style.left = conRight - 2 + 'px'; // -2 is an adjustment
76118
+ this.verticalRulerRight.style.top = containerTop + 'px';
76119
+ let val = conRight;
76120
+ if (this.rulerRight === null) this.rulerRight = val;
76121
+ }
76122
+ }
76123
+ }
76124
+ class Rotatable {
76125
+ constructor(options) {
76126
+ this.selector = options && options.selector || '.is-block';
76127
+ this.doc = options && options.doc || document;
76128
+ this.win = options && options.win || window;
76129
+ this.onBeforeChange = options && options.onBeforeChange || null;
76130
+ this.onChange = options && options.onChange || null;
76131
+ this.disableOnMobile = options && options.disableOnMobile || 0;
76132
+ this.centerX = 0;
76133
+ this.centerY = 0;
76134
+ this.initialRotation = 0;
76135
+ this.handleRotateStart = this.handleRotateStart.bind(this);
76136
+ this.handleDblClick = this.handleDblClick.bind(this);
76137
+ this.handleRotateMove = this.handleRotateMove.bind(this);
76138
+ this.handleRotateEnd = this.handleRotateEnd.bind(this);
76139
+ this.setup();
76140
+ this.common = new Common({
76141
+ selector: this.selector
76142
+ });
76143
+ }
76144
+ setup() {
76145
+ this.elements = this.doc.querySelectorAll(this.selector);
76146
+ this.elements.forEach(element => {
76147
+ element.querySelectorAll('.rotate-handle').forEach(elm => elm.parentNode.removeChild(elm));
76148
+ const handleHTML = '<div class="rotate-handle" contentEditable="false"><div></div></div>';
76149
+ element.insertAdjacentHTML('afterbegin', handleHTML);
76150
+ const handles = Array.from(element.querySelectorAll('.rotate-handle')).filter(handle => handle.parentElement === element);
76151
+ handles.forEach(handle => {
76152
+ handle.addEventListener('mousedown', this.handleRotateStart);
76153
+ handle.addEventListener('touchstart', this.handleRotateStart, {
76154
+ passive: false
76155
+ });
76156
+ handle.addEventListener('dblclick', this.handleDblClick);
76157
+ });
76158
+ });
76159
+ }
76160
+ refresh() {
76161
+ this.elements = this.doc.querySelectorAll(this.selector);
76162
+ this.elements.forEach(element => {
76163
+ let handles = Array.from(element.querySelectorAll('.rotate-handle')).filter(handle => handle.parentElement === element); // only one handle
76164
+ handles.forEach(handle => {
76165
+ handle.removeEventListener('mousedown', this.handleRotateStart);
76166
+ handle.removeEventListener('touchstart', this.handleRotateStart);
76167
+ handle.removeEventListener('dblclick', this.handleDblClick);
76168
+ handle.parentNode.removeChild(handle);
76169
+ });
76170
+ const handleHTML = '<div class="rotate-handle" contentEditable="false"><div></div></div>';
76171
+ element.insertAdjacentHTML('afterbegin', handleHTML);
76172
+ handles = Array.from(element.querySelectorAll('.rotate-handle')).filter(handle => handle.parentElement === element); // only one handle
76173
+ handles.forEach(handle => {
76174
+ handle.addEventListener('mousedown', this.handleRotateStart);
76175
+ handle.addEventListener('touchstart', this.handleRotateStart, {
76176
+ passive: false
76177
+ });
76178
+ handle.addEventListener('dblclick', this.handleDblClick);
76179
+ });
76180
+ });
76181
+ }
76182
+ destroy(block) {
76183
+ if (block) {
76184
+ this.elements = this.doc.querySelectorAll(this.selector);
76185
+ this.elements.forEach(element => {
76186
+ if (element === block) {
76187
+ const handles = Array.from(element.querySelectorAll('.rotate-handle')).filter(handle => handle.parentElement === element);
76188
+ handles.forEach(handle => {
76189
+ handle.removeEventListener('mousedown', this.handleRotateStart);
76190
+ handle.removeEventListener('touchstart', this.handleRotateStart);
76191
+ handle.removeEventListener('dblclick', this.handleDblClick);
76192
+ handle.parentNode.removeChild(handle);
76193
+ });
76194
+ }
76195
+ });
76196
+ } else {
76197
+ this.elements = this.doc.querySelectorAll(this.selector);
76198
+ this.elements.forEach(element => {
76199
+ const handles = Array.from(element.querySelectorAll('.rotate-handle')).filter(handle => handle.parentElement === element);
76200
+ handles.forEach(handle => {
76201
+ handle.removeEventListener('mousedown', this.handleRotateStart);
76202
+ handle.removeEventListener('touchstart', this.handleRotateStart);
76203
+ handle.removeEventListener('dblclick', this.handleDblClick);
76204
+ handle.parentNode.removeChild(handle);
76205
+ });
76206
+ });
76207
+ }
76208
+ }
76209
+ handleDblClick(event) {
76210
+ if (this.onBeforeChange) this.onBeforeChange();
76211
+ event.preventDefault();
76212
+ event.stopImmediatePropagation();
76213
+ const block = event.target.parentNode;
76214
+ const transform = block.style.transform;
76215
+ if (transform.includes('rotate')) block.style.transform = '';
76216
+ this.clonedTarget = this.doc.querySelector(this.selector + '.cloned');
76217
+ if (this.clonedTarget) this.clonedTarget.style.transform = '';
76218
+ if (this.onChange) this.onChange();
76219
+ }
76220
+ handleRotateStart(event) {
76221
+ const viewportWidth = this.win.innerWidth;
76222
+ if (viewportWidth <= this.disableOnMobile) return;
76223
+ if (event.type === 'touchstart' && event.touches.length !== 1) {
76224
+ return; // Do nothing if more than one touch point is detected
76225
+ }
76226
+
76227
+ if (event.type === 'mousedown' && event.button !== 0) {
76228
+ return; // Do nothing if the right mouse button is clicked
76229
+ }
76230
+
76231
+ event.preventDefault();
76232
+ this.target = event.target.parentNode; // block
76233
+
76234
+ this.clonedTarget = this.doc.querySelector(this.selector + '.cloned');
76235
+ this.dragStartTimeout = setTimeout(() => {
76236
+ // Set a timeout before starting the drag (to differentiate from click)
76237
+
76238
+ if (event.type === 'mousedown') {
76239
+ this.startRotation(event.clientX, event.clientY);
76240
+ } else if (event.type === 'touchstart') {
76241
+ const touch = event.touches[0];
76242
+ this.startRotation(touch.clientX, touch.clientY);
76243
+ }
76244
+ this.doc.addEventListener('mousemove', this.handleRotateMove);
76245
+ this.doc.addEventListener('touchmove', this.handleRotateMove);
76246
+ }, 120);
76247
+ this.doc.addEventListener('mouseup', this.handleRotateEnd);
76248
+ this.doc.addEventListener('touchend', this.handleRotateEnd);
76249
+ }
76250
+ handleRotateMove() {
76251
+ let clientX, clientY;
76252
+ if (event.type === 'mousemove') {
76253
+ clientX = event.clientX;
76254
+ clientY = event.clientY;
76255
+ } else if (event.type === 'touchmove') {
76256
+ const touch = event.touches[0];
76257
+ clientX = touch.clientX;
76258
+ clientY = touch.clientY;
76259
+ }
76260
+ this.updateRotation(clientX, clientY);
76261
+ }
76262
+ handleRotateEnd() {
76263
+ clearTimeout(this.dragStartTimeout);
76264
+ this.doc.removeEventListener('mousemove', this.handleRotateMove);
76265
+ this.doc.removeEventListener('touchmove', this.handleRotateMove);
76266
+ this.doc.removeEventListener('mouseup', this.handleRotateEnd);
76267
+ this.doc.removeEventListener('touchend', this.handleRotateEnd);
76268
+ if (this.onChange) this.onChange();
76269
+ }
76270
+ getCurrentRotation(transform) {
76271
+ const match = transform.match(/rotate\(([-+]?\d*\.?\d*)deg\)/);
76272
+ return match ? parseFloat(match[1]) : 0;
76273
+ }
76274
+ startRotation() {
76275
+ if (this.onBeforeChange) this.onBeforeChange();
76276
+ const target = this.target;
76277
+ const rect = target.getBoundingClientRect();
76278
+ this.centerX = rect.left + rect.width / 2;
76279
+ this.centerY = rect.top + rect.height / 2;
76280
+
76281
+ // Store the initial rotation
76282
+ if (target.parentNode.matches(this.selector)) {
76283
+ const currentTransform = target.style.transform;
76284
+ let currentRotation = this.getCurrentRotation(currentTransform);
76285
+ this.initialRotation = currentRotation;
76286
+ const parentTransform = target.parentNode.style.transform;
76287
+ let parentRotation = this.getCurrentRotation(parentTransform);
76288
+ if (parentRotation) {
76289
+ this.initialRotation = parentRotation;
76290
+ }
76291
+ } else {
76292
+ this.initialRotation = 0; // If no child blocks
76293
+ }
76294
+ }
76295
+
76296
+ updateRotation(x, y) {
76297
+ const target = this.target;
76298
+ const angle = Math.atan2(y - this.centerY, x - this.centerX);
76299
+ const degrees = angle * (180 / Math.PI);
76300
+ const initialRotation = this.initialRotation || 0;
76301
+ target.style.transform = `rotate(${degrees - initialRotation}deg)`;
76302
+ if (this.clonedTarget) this.clonedTarget.style.transform = `rotate(${degrees - initialRotation}deg)`;
76303
+ }
76304
+ }
76305
+ class Resizable {
76306
+ constructor(options) {
76307
+ this.selector = options && options.selector || '.is-block';
76308
+ this.doc = options && options.doc || document;
76309
+ this.win = options && options.win || window;
76310
+ this.onBeforeChange = options && options.onBeforeChange || null;
76311
+ this.onChange = options && options.onChange || null;
76312
+ this.disableOnMobile = options && options.disableOnMobile || 0;
76313
+ this.isResizing = false;
76314
+ this.resizeHandle = null;
76315
+ this.startX = 0;
76316
+ this.startY = 0;
76317
+ this.elements = this.doc.querySelectorAll(this.selector);
76318
+ this.startResizing = this.startResizing.bind(this);
76319
+ this.handleResizeMove = this.handleResizeMove.bind(this);
76320
+ this.handleResizeEnd = this.handleResizeEnd.bind(this);
76321
+ this.setup();
76322
+ this.ruler = new Ruler({
76323
+ selector: this.selector,
76324
+ doc: this.doc,
76325
+ win: this.win
76326
+ });
76327
+ this.common = new Common({
76328
+ selector: this.selector,
76329
+ doc: this.doc,
76330
+ win: this.win
76331
+ });
76332
+ }
76333
+ setup() {
76334
+ this.elements.forEach(element => {
76335
+ element.querySelectorAll('.handle').forEach(elm => elm.parentNode.removeChild(elm));
76336
+ const handleHTML = `
76337
+ <div class="handle top-left"></div>
76338
+ <div class="handle top-right"></div>
76339
+ <div class="handle bottom-left"></div>
76340
+ <div class="handle bottom-right"></div>
76341
+
76342
+ <div class="handle top"></div>
76343
+ <div class="handle bottom"></div>
76344
+ <div class="handle left"></div>
76345
+ <div class="handle right"></div>`;
76346
+ element.insertAdjacentHTML('afterbegin', handleHTML);
76347
+ const handles = Array.from(element.querySelectorAll('.handle')).filter(handle => handle.parentElement === element);
76348
+ handles.forEach(handle => {
76349
+ handle.addEventListener('mousedown', this.startResizing);
76350
+ handle.addEventListener('touchstart', this.startResizing, {
76351
+ passive: false
76352
+ });
76353
+ });
76354
+ });
76355
+ }
76356
+ refresh() {
76357
+ this.elements = this.doc.querySelectorAll(this.selector);
76358
+ this.elements.forEach(element => {
76359
+ let handles = Array.from(element.querySelectorAll('.handle')).filter(handle => handle.parentElement === element);
76360
+ handles.forEach(handle => {
76361
+ handle.removeEventListener('mousedown', this.startResizing);
76362
+ handle.removeEventListener('touchstart', this.startResizing);
76363
+ handle.parentNode.removeChild(handle);
76364
+ });
76365
+ const handleHTML = `
76366
+ <div class="handle top-left"></div>
76367
+ <div class="handle top-right"></div>
76368
+ <div class="handle bottom-left"></div>
76369
+ <div class="handle bottom-right"></div>
76370
+
76371
+ <div class="handle top"></div>
76372
+ <div class="handle bottom"></div>
76373
+ <div class="handle left"></div>
76374
+ <div class="handle right"></div>`;
76375
+ element.insertAdjacentHTML('afterbegin', handleHTML);
76376
+ handles = Array.from(element.querySelectorAll('.handle')).filter(handle => handle.parentElement === element);
76377
+ handles.forEach(handle => {
76378
+ handle.addEventListener('mousedown', this.startResizing);
76379
+ handle.addEventListener('touchstart', this.startResizing, {
76380
+ passive: false
76381
+ });
76382
+ });
76383
+ });
76384
+ this.ruler.refresh();
76385
+ }
76386
+ destroy(block) {
76387
+ if (block) {
76388
+ const handles = Array.from(block.querySelectorAll('.handle')).filter(handle => handle.parentElement === block);
76389
+ handles.forEach(handle => {
76390
+ handle.removeEventListener('mousedown', this.startResizing);
76391
+ handle.removeEventListener('touchstart', this.startResizing);
76392
+ handle.parentNode.removeChild(handle);
76393
+ });
76394
+ } else {
76395
+ const handles = this.doc.querySelectorAll('.handle');
76396
+ handles.forEach(handle => {
76397
+ handle.removeEventListener('mousedown', this.startResizing);
76398
+ handle.removeEventListener('touchstart', this.startResizing);
76399
+ handle.parentNode.removeChild(handle);
76400
+ });
76401
+ this.ruler.destroy();
76402
+ }
76403
+ }
76404
+ startResizing(event) {
76405
+ const viewportWidth = this.win.innerWidth;
76406
+ if (viewportWidth <= this.disableOnMobile) return;
76407
+ if (event.type === 'touchstart' && event.touches.length !== 1) {
76408
+ return; // Do nothing if more than one touch point is detected
76409
+ }
76410
+
76411
+ if (event.type === 'mousedown' && event.button !== 0) {
76412
+ return; // Do nothing if the right mouse button is clicked
76413
+ }
76414
+
76415
+ this.target = event.target.parentNode; // block
76416
+
76417
+ this.clonedTarget = this.doc.querySelector(this.selector + '.cloned');
76418
+ event.preventDefault();
76419
+ event.stopPropagation();
76420
+ this.dragStartTimeout = setTimeout(() => {
76421
+ // Set a timeout before starting the drag (to differentiate from click)
76422
+
76423
+ if (this.onBeforeChange) this.onBeforeChange();
76424
+ const handle = event.target.closest('.handle');
76425
+ this.isResizing = true;
76426
+ this.resizeHandle = handle.classList[1];
76427
+ if (event.type === 'mousedown') {
76428
+ this.startX = event.clientX;
76429
+ this.startY = event.clientY;
76430
+ } else if (event.type === 'touchstart') {
76431
+ const touch = event.touches[0];
76432
+ this.startX = touch.clientX;
76433
+ this.startY = touch.clientY;
76434
+ }
76435
+
76436
+ //Initial
76437
+ this.initialWidth = parseFloat(getComputedStyle(this.target).width);
76438
+ this.initialHeight = parseFloat(getComputedStyle(this.target).height);
76439
+ const containerRect = this.common.getRect(this.target.parentNode);
76440
+ const rect = this.common.getRect(this.target);
76441
+ this.initialLeft = rect.left - containerRect.left;
76442
+ this.initialTop = rect.top - containerRect.top;
76443
+ this.common.applyPixels(this.target);
76444
+ }, 120);
76445
+ this.doc.addEventListener('mousemove', this.handleResizeMove);
76446
+ this.doc.addEventListener('mouseup', this.handleResizeEnd);
76447
+ this.doc.addEventListener('touchmove', this.handleResizeMove);
76448
+ this.doc.addEventListener('touchend', this.handleResizeEnd);
76449
+ }
76450
+ handleResizeMove(event) {
76451
+ if (this.isResizing) {
76452
+ let deltaX, deltaY;
76453
+ if (event.type === 'mousemove') {
76454
+ deltaX = event.clientX - this.startX;
76455
+ deltaY = event.clientY - this.startY;
76456
+ } else if (event.type === 'touchmove') {
76457
+ const touch = event.touches[0];
76458
+ deltaX = touch.clientX - this.startX;
76459
+ deltaY = touch.clientY - this.startY;
76460
+ }
76461
+ this.target.style.minWidth = ''; // to ensure no resize limit
76462
+ if (this.clonedTarget) this.clonedTarget.style.minWidth = '';
76463
+ switch (this.resizeHandle) {
76464
+ case 'top-left':
76465
+ this.resizeTopLeft(deltaX, deltaY);
76466
+ break;
76467
+ case 'top-right':
76468
+ this.resizeTopRight(deltaX, deltaY);
76469
+ break;
76470
+ case 'bottom-left':
76471
+ this.resizeBottomLeft(deltaX, deltaY);
76472
+ break;
76473
+ case 'bottom-right':
76474
+ this.resizeBottomRight(deltaX, deltaY);
76475
+ break;
76476
+ case 'top':
76477
+ this.resizeTop(deltaY);
76478
+ break;
76479
+ case 'left':
76480
+ this.resizeLeft(deltaX);
76481
+ break;
76482
+ case 'bottom':
76483
+ this.resizeBottom(deltaY);
76484
+ break;
76485
+ case 'right':
76486
+ this.resizeRight(deltaX);
76487
+ break;
76488
+ }
76489
+ this.ruler.updateRulers(this.target);
76490
+ }
76491
+ }
76492
+ handleResizeEnd() {
76493
+ clearTimeout(this.dragStartTimeout);
76494
+ this.stopResizing();
76495
+ this.doc.removeEventListener('mousemove', this.handleResizeMove);
76496
+ this.doc.removeEventListener('mouseup', this.handleResizeEnd);
76497
+ this.doc.removeEventListener('touchmove', this.handleResizeMove);
76498
+ this.doc.removeEventListener('touchend', this.handleResizeEnd);
76499
+ this.ruler.hideRulers();
76500
+ }
76501
+ resizeTopLeft(deltaX, deltaY) {
76502
+ this.target.style.left = this.initialLeft + deltaX + 'px';
76503
+ this.target.style.top = this.initialTop + deltaY + 'px';
76504
+ this.target.style.width = this.initialWidth - deltaX + 'px';
76505
+ this.target.style.height = this.initialHeight - deltaY + 'px';
76506
+ if (this.clonedTarget) {
76507
+ this.clonedTarget.style.left = this.initialLeft + deltaX + 'px';
76508
+ this.clonedTarget.style.top = this.initialTop + deltaY + 'px';
76509
+ this.clonedTarget.style.width = this.initialWidth - deltaX + 'px';
76510
+ this.clonedTarget.style.height = this.initialHeight - deltaY + 'px';
76511
+ }
76512
+ }
76513
+ resizeTopRight(deltaX, deltaY) {
76514
+ this.target.style.width = this.initialWidth + deltaX + 'px';
76515
+ this.target.style.top = this.initialTop + deltaY + 'px';
76516
+ this.target.style.height = this.initialHeight - deltaY + 'px';
76517
+ if (this.clonedTarget) {
76518
+ this.clonedTarget.style.width = this.initialWidth + deltaX + 'px';
76519
+ this.clonedTarget.style.top = this.initialTop + deltaY + 'px';
76520
+ this.clonedTarget.style.height = this.initialHeight - deltaY + 'px';
76521
+ }
76522
+ }
76523
+ resizeBottomLeft(deltaX, deltaY) {
76524
+ this.target.style.width = this.initialWidth - deltaX + 'px';
76525
+ this.target.style.height = this.initialHeight + deltaY + 'px';
76526
+ this.target.style.left = this.initialLeft + deltaX + 'px';
76527
+ if (this.clonedTarget) {
76528
+ this.clonedTarget.style.width = this.initialWidth - deltaX + 'px';
76529
+ this.clonedTarget.style.height = this.initialHeight + deltaY + 'px';
76530
+ this.clonedTarget.style.left = this.initialLeft + deltaX + 'px';
76531
+ }
76532
+ }
76533
+ resizeBottomRight(deltaX, deltaY) {
76534
+ this.target.style.width = this.initialWidth + deltaX + 'px';
76535
+ this.target.style.height = this.initialHeight + deltaY + 'px';
76536
+ if (this.clonedTarget) {
76537
+ this.clonedTarget.style.width = this.initialWidth + deltaX + 'px';
76538
+ this.clonedTarget.style.height = this.initialHeight + deltaY + 'px';
76539
+ }
76540
+ }
76541
+ resizeTop(deltaY) {
76542
+ this.target.style.top = this.initialTop + deltaY + 'px';
76543
+ this.target.style.height = this.initialHeight - deltaY + 'px';
76544
+ if (this.clonedTarget) {
76545
+ this.clonedTarget.style.top = this.initialTop + deltaY + 'px';
76546
+ this.clonedTarget.style.height = this.initialHeight - deltaY + 'px';
76547
+ }
76548
+ }
76549
+ resizeBottom(deltaY) {
76550
+ this.target.style.height = this.initialHeight + deltaY + 'px';
76551
+ if (this.clonedTarget) {
76552
+ this.clonedTarget.style.height = this.initialHeight + deltaY + 'px';
76553
+ }
76554
+ }
76555
+ resizeLeft(deltaX) {
76556
+ this.target.style.width = this.initialWidth - deltaX + 'px';
76557
+ this.target.style.left = this.initialLeft + deltaX + 'px';
76558
+ if (this.clonedTarget) {
76559
+ this.clonedTarget.style.width = this.initialWidth - deltaX + 'px';
76560
+ this.clonedTarget.style.left = this.initialLeft + deltaX + 'px';
76561
+ }
76562
+ }
76563
+ resizeRight(deltaX) {
76564
+ this.target.style.width = this.initialWidth + deltaX + 'px';
76565
+ if (this.clonedTarget) {
76566
+ this.clonedTarget.style.width = this.initialWidth + deltaX + 'px';
76567
+ }
76568
+ }
76569
+ stopResizing() {
76570
+ if (this.isResizing) {
76571
+ if (this.target) {
76572
+ this.updateBlockStyle(this.target);
76573
+ if (this.clonedTarget) this.updateBlockStyle(this.clonedTarget);
76574
+ }
76575
+ this.isResizing = false;
76576
+ }
76577
+ }
76578
+ updateBlockStyle(target) {
76579
+ if (target.querySelector(this.selector)) ; else {
76580
+ // this.common.updateHeight(target);
76581
+ if (target.classList.contains('height-auto')) target.style.height = '';
76582
+ }
76583
+
76584
+ // Replace with ruler's alignment
76585
+ if (this.ruler.rulerTop !== null) {
76586
+ target.style.top = this.ruler.rulerTop + 'px';
76587
+ // if container has top/left
76588
+ if (target.parentNode.matches(this.selector)) {
76589
+ const containerRect = target.parentNode.getBoundingClientRect();
76590
+ target.style.top = this.ruler.rulerTop - containerRect.top + 'px';
76591
+ }
76592
+ }
76593
+
76594
+ // If resizing by dragging the right corners (top or bottom)
76595
+ if (this.resizeHandle === 'top-right' || this.resizeHandle === 'bottom-right' || this.resizeHandle === 'right') {
76596
+ // Check if vertical right ruler visible (has value)
76597
+ if (this.ruler.rulerRight !== null) {
76598
+ // If so, keep the left position
76599
+ // target.style.left = newLeft + 'px';
76600
+
76601
+ // And update the width to align with vertical right ruler
76602
+ const rect = target.getBoundingClientRect();
76603
+ target.style.width = this.ruler.rulerRight - rect.left + 'px';
76604
+ }
76605
+ } else if (this.resizeHandle === 'top-left' || this.resizeHandle === 'bottom-left' || this.resizeHandle === 'left') {
76606
+ if (this.ruler.rulerLeft !== null) {
76607
+ const currentRight = this.initialLeft + this.initialWidth;
76608
+
76609
+ // if container has top/left
76610
+ const containerRect = target.parentNode.getBoundingClientRect();
76611
+ this.ruler.rulerLeft = this.ruler.rulerLeft - containerRect.left;
76612
+
76613
+ // And update the width to align with vertical left ruler
76614
+ target.style.left = this.ruler.rulerLeft + 'px';
76615
+ let newWidth = currentRight - this.ruler.rulerLeft;
76616
+ target.style.width = newWidth + 'px';
76617
+ }
76618
+ }
76619
+
76620
+ // Convert px to %
76621
+ this.common.applyPercentage(target);
76622
+ setTimeout(() => {
76623
+ const breakpoint = this.doc.body.getAttribute('data-breakpoint');
76624
+
76625
+ // const screenWidth = window.innerWidth;
76626
+ // let defaultPoint;
76627
+ // if(screenWidth<=1920) {
76628
+ // defaultPoint = 1366;
76629
+ // } else {
76630
+ // defaultPoint = 1900;
76631
+ // }
76632
+
76633
+ if (breakpoint && breakpoint < 1920) {
76634
+ target.setAttribute('data--y-' + breakpoint, target.style.top);
76635
+ target.setAttribute('data--x-' + breakpoint, target.style.left);
76636
+ target.setAttribute('data--w-' + breakpoint, target.style.width);
76637
+ target.setAttribute('data--h-' + breakpoint, target.style.height);
76638
+ } else {
76639
+ target.setAttribute('data--y', target.style.top);
76640
+ target.setAttribute('data--x', target.style.left);
76641
+ target.setAttribute('data--w', target.style.width);
76642
+ target.setAttribute('data--h', target.style.height);
76643
+ }
76644
+ target.removeAttribute('data-prev'); // reset
76645
+ target.removeAttribute('data-fluid');
76646
+ }, 30); // delay needed since we use updateHeight() previously that has 20ms process
76647
+
76648
+ if (this.onChange) this.onChange();
76649
+ }
76650
+ }
76651
+ class Draggable {
76652
+ constructor(options) {
76653
+ this.selector = options && options.selector || '.is-block';
76654
+ this.doc = options && options.doc || document;
76655
+ this.win = options && options.win || window;
76656
+ this.onDelete = options && options.onDelete || null;
76657
+ this.onBeforeChange = options && options.onBeforeChange || null;
76658
+ this.onChange = options && options.onChange || null;
76659
+ this.onSelectStart = options && options.onSelectStart || null;
76660
+ this.onSelectClear = options && options.onSelectClear || null;
76661
+ this.disableOnMobile = options && options.disableOnMobile || 0;
76662
+ this.onMultipleSelect = options && options.onMultipleSelect || null;
76663
+ this.onSelectBlock = options && options.onSelectBlock || null;
76664
+ this.isDragging = false;
76665
+ this.startX = 0;
76666
+ this.startY = 0;
76667
+ this.handleDragStart = this.handleDragStart.bind(this);
76668
+ this.handleDragMove = this.handleDragMove.bind(this);
76669
+ this.handleDragEnd = this.handleDragEnd.bind(this);
76670
+ this.handleSelect = this.handleSelect.bind(this);
76671
+ this.handleKeyDown = this.handleKeyDown.bind(this);
76672
+ this.setup();
76673
+ this.ruler = new Ruler({
76674
+ selector: this.selector,
76675
+ doc: this.doc,
76676
+ win: this.win
76677
+ });
76678
+ this.common = new Common({
76679
+ selector: this.selector,
76680
+ doc: this.doc,
76681
+ win: this.win
76682
+ });
76683
+ }
76684
+ setup() {
76685
+ this.elements = this.doc.querySelectorAll(this.selector);
76686
+ this.elements.forEach(element => {
76687
+ element.addEventListener('mousedown', this.handleDragStart);
76688
+ element.addEventListener('touchstart', this.handleDragStart, {
76689
+ passive: false
76690
+ });
76691
+ });
76692
+ this.doc.addEventListener('mousedown', this.handleSelect);
76693
+ this.doc.addEventListener('touchstart', this.handleSelect, {
76694
+ passive: false
76695
+ });
76696
+ this.doc.addEventListener('keydown', this.handleKeyDown);
76697
+ }
76698
+ refresh() {
76699
+ this.elements = this.doc.querySelectorAll(this.selector);
76700
+ this.elements.forEach(element => {
76701
+ element.removeEventListener('mousedown', this.handleDragStart);
76702
+ element.removeEventListener('touchstart', this.handleDragStart);
76703
+ });
76704
+ this.elements.forEach(element => {
76705
+ element.addEventListener('mousedown', this.handleDragStart);
76706
+ element.addEventListener('touchstart', this.handleDragStart, {
76707
+ passive: false
76708
+ });
76709
+ });
76710
+ this.ruler.refresh();
76711
+ }
76712
+ destroy() {
76713
+ this.ruler.destroy();
76714
+ this.elements.forEach(element => {
76715
+ element.removeEventListener('mousedown', this.handleDragStart);
76716
+ element.removeEventListener('touchstart', this.handleDragStart);
76717
+ });
76718
+ this.doc.removeEventListener('mousedown', this.handleSelect);
76719
+ this.doc.removeEventListener('touchstart', this.handleSelect);
76720
+ this.doc.removeEventListener('keydown', this.handleKeyDown);
76721
+ const blocks = this.doc.querySelectorAll(this.selector);
76722
+ blocks.forEach(elm => elm.classList.remove('active'));
76723
+ }
76724
+ disableDrag(block) {
76725
+ this.elements.forEach(element => {
76726
+ if (block === element) {
76727
+ element.removeEventListener('mousedown', this.handleDragStart);
76728
+ element.removeEventListener('touchstart', this.handleDragStart);
76729
+ }
76730
+ });
76731
+ }
76732
+ enableDrag(block) {
76733
+ this.elements.forEach(element => {
76734
+ if (block === element) {
76735
+ element.addEventListener('mousedown', this.handleDragStart);
76736
+ element.addEventListener('touchstart', this.handleDragStart, {
76737
+ passive: false
76738
+ });
76739
+ }
76740
+ });
76741
+ }
76742
+ handleDragStart(event) {
76743
+ const viewportWidth = this.win.innerWidth;
76744
+ if (viewportWidth <= this.disableOnMobile) return;
76745
+ if (event.target.classList.contains('rotate-handle')) return;
76746
+ if (event.type === 'touchstart' && event.touches.length !== 1) {
76747
+ return; // Do nothing if more than one touch point is detected
76748
+ }
76749
+
76750
+ if (event.type === 'mousedown' && event.button !== 0) {
76751
+ return; // Do nothing if the right mouse button is clicked
76752
+ }
76753
+
76754
+ const currentTarget = event.currentTarget;
76755
+ const clickedBlock = event.target.closest(this.selector);
76756
+ if (currentTarget !== clickedBlock) {
76757
+ // Triggered Group click by child block click
76758
+ return; // Return here, so that when block events are working, group events won't
76759
+ }
76760
+
76761
+ this.clickedBlock = clickedBlock;
76762
+ this.dragStartTimeout = setTimeout(() => {
76763
+ // Set a timeout before starting the drag (to differentiate from click)
76764
+
76765
+ if (event.type === 'mousedown') {
76766
+ this.startDragging(event.clientX, event.clientY, currentTarget);
76767
+ } else if (event.type === 'touchstart') {
76768
+ const touch = event.touches[0];
76769
+ this.startDragging(touch.clientX, touch.clientY, currentTarget);
76770
+ }
76771
+ this.doc.addEventListener('mousemove', this.handleDragMove);
76772
+ this.doc.addEventListener('touchmove', this.handleDragMove);
76773
+ }, 120);
76774
+ this.doc.addEventListener('mouseup', this.handleDragEnd);
76775
+ this.doc.addEventListener('touchend', this.handleDragEnd);
76776
+ }
76777
+ startDragging(startX, startY) {
76778
+ if (this.onBeforeChange) this.onBeforeChange();
76779
+ this.isDragging = true;
76780
+ const blocks = this.doc.querySelectorAll(this.selector + '.active');
76781
+ blocks.forEach(target => {
76782
+ // const containerRect = target.parentNode.getBoundingClientRect(); // if container has top/left
76783
+ const containerRect = this.common.getRect(target.parentNode); // if container has top/left
76784
+ const rect = this.common.getRect(target);
76785
+ const x = startX - rect.left + containerRect.left;
76786
+ const y = startY - rect.top + containerRect.top;
76787
+ target.setAttribute('data-startx', x);
76788
+ target.setAttribute('data-starty', y);
76789
+ this.common.applyPixels(target);
76790
+ });
76791
+ this.clickedBlock = this.common.getSelectedBlock();
76792
+ }
76793
+ handleDragMove(event) {
76794
+ let clientX, clientY;
76795
+ if (event.type === 'mousemove') {
76796
+ clientX = event.clientX;
76797
+ clientY = event.clientY;
76798
+ } else if (event.type === 'touchmove') {
76799
+ const touch = event.touches[0];
76800
+ clientX = touch.clientX;
76801
+ clientY = touch.clientY;
76802
+ }
76803
+ if (this.isDragging) {
76804
+ // Allows dragging multiple selected blocks
76805
+
76806
+ let blocks = this.doc.querySelectorAll(this.selector + '.active');
76807
+ blocks.forEach(target => {
76808
+ this.updatePosition(clientX, clientY, target);
76809
+ });
76810
+
76811
+ // Ruler works for single block selection only
76812
+ if (this.clickedBlock) this.ruler.updateRulers(this.clickedBlock);
76813
+ }
76814
+ event.preventDefault();
76815
+ event.stopImmediatePropagation();
76816
+ }
76817
+ updatePosition(x, y, target) {
76818
+ if (this.isDragging) {
76819
+ const startX = target.getAttribute('data-startx');
76820
+ const startY = target.getAttribute('data-starty');
76821
+ const newX = x - startX;
76822
+ const newY = y - startY;
76823
+ target.style.left = newX + 'px';
76824
+ target.style.top = newY + 'px';
76825
+ }
76826
+ }
76827
+ handleDragEnd() {
76828
+ clearTimeout(this.dragStartTimeout);
76829
+ if (this.isDragging) {
76830
+ this.doc.removeEventListener('mousemove', this.handleDragMove);
76831
+ this.doc.removeEventListener('touchmove', this.handleDragMove);
76832
+ }
76833
+ this.doc.removeEventListener('mouseup', this.handleDragEnd);
76834
+ this.doc.removeEventListener('touchend', this.handleDragEnd);
76835
+ this.stopDragging();
76836
+ this.ruler.hideRulers();
76837
+ let blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active') && !elm.classList.contains('multi'));
76838
+ if (blocks.length === 1) {
76839
+ const block = blocks[0];
76840
+ if (this.onSelectStart) this.onSelectStart(block); // on first block select (before clone)
76841
+ }
76842
+ }
76843
+
76844
+ stopDragging() {
76845
+ if (this.isDragging) {
76846
+ const blocks = this.doc.querySelectorAll(this.selector + '.active');
76847
+ blocks.forEach(target => {
76848
+ this.updateBlockStyle(target);
76849
+ });
76850
+ this.isDragging = false;
76851
+ }
76852
+ }
76853
+ updateBlockStyle(target) {
76854
+ // Replace with ruler's alignment
76855
+ const containerRect = this.common.getRect(target.parentNode); // if container has top/left
76856
+ const initialWidth = parseFloat(getComputedStyle(target).width);
76857
+ if (this.ruler.rulerTop !== null) target.style.top = this.ruler.rulerTop - containerRect.top + 'px';
76858
+ 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';
76859
+ this.doc.querySelectorAll('[data-startx]').forEach(elm => elm.removeAttribute('data-startx'));
76860
+ this.doc.querySelectorAll('[data-starty]').forEach(elm => elm.removeAttribute('data-starty'));
76861
+ this.common.applyPercentage(target);
76862
+ const breakpoint = this.doc.body.getAttribute('data-breakpoint');
76863
+
76864
+ // const screenWidth = window.innerWidth;
76865
+ // let defaultPoint;
76866
+ // if(screenWidth<=1920) {
76867
+ // defaultPoint = 1366;
76868
+ // } else {
76869
+ // defaultPoint = 1900;
76870
+ // }
76871
+
76872
+ if (breakpoint && breakpoint < 1920) {
76873
+ target.setAttribute('data--y-' + breakpoint, target.style.top);
76874
+ target.setAttribute('data--x-' + breakpoint, target.style.left);
76875
+ target.setAttribute('data--w-' + breakpoint, target.style.width);
76876
+ target.setAttribute('data--h-' + breakpoint, target.style.height);
76877
+ } else {
76878
+ target.setAttribute('data--y', target.style.top);
76879
+ target.setAttribute('data--x', target.style.left);
76880
+ target.setAttribute('data--w', target.style.width);
76881
+ target.setAttribute('data--h', target.style.height);
76882
+ }
76883
+ target.removeAttribute('data-prev'); // reset
76884
+ target.removeAttribute('data-fluid');
76885
+ if (this.onChange) this.onChange();
76886
+ }
76887
+ handleSelect(event) {
76888
+ const element = event.target;
76889
+ if (element.classList.contains('rotate-handle')) return;
76890
+ const block = element.closest(this.selector);
76891
+ if (block) {
76892
+ if (block.classList.contains('active')) {
76893
+ let actualBlock = block.classList.contains('clone') ? this.doc.querySelector(this.selector + '.cloned') : null;
76894
+ if (!actualBlock) actualBlock = block;
76895
+ if (this.onSelectBlock) this.onSelectBlock(actualBlock);
76896
+ return; // if clicked block is active
76897
+ }
76898
+ // if(block.parentNode.classList.contains('active')) return; // if group is active
76899
+
76900
+ if (block.matches(this.selector) && block.querySelector(this.selector)) {
76901
+ // if group is clicked, remove active childe's blocks
76902
+ block.querySelectorAll(this.selector).forEach(elm => elm.classList.remove('active'));
76903
+ }
76904
+ if (event.shiftKey || this.doc.body.classList.contains('multi-select')) {
76905
+ // multi select
76906
+ block.classList.add('active');
76907
+ if (this.onMultipleSelect) this.onMultipleSelect();
76908
+ } else {
76909
+ if (this.onSelectClear) this.onSelectClear();
76910
+ this.doc.querySelectorAll(this.selector + '.active').forEach(elm => elm.classList.remove('active'));
76911
+ block.classList.add('active');
76912
+ let actualBlock = block.classList.contains('clone') ? this.doc.querySelector(this.selector + '.cloned') : null;
76913
+ if (!actualBlock) actualBlock = block;
76914
+ if (this.onSelectBlock) this.onSelectBlock(actualBlock);
76915
+ }
76916
+ if (!block.parentNode) return; // just in case
76917
+
76918
+ // Higlight parent group if current child block is clicked
76919
+ if (block.parentNode.matches(this.selector)) {
76920
+ block.parentNode.classList.add('block-active');
76921
+ } else {
76922
+ this.doc.querySelectorAll('.block-active').forEach(elm => elm.classList.remove('block-active'));
76923
+ }
76924
+ } else {
76925
+ if (event.target.closest('.keep-selection')) return;
76926
+
76927
+ // // Make empty height set with value
76928
+ // // if(this.clickedBlock) this.common.updateHeight(this.clickedBlock);
76929
+ // // Check
76930
+ // if(this.clickedBlock && !this.clickedBlock.classList.contains('clone')) {
76931
+ // this.common.updateHeight(this.clickedBlock);
76932
+ // }
76933
+
76934
+ this.doc.querySelectorAll(this.selector + '.active').forEach(elm => elm.classList.remove('active'));
76935
+ this.doc.querySelectorAll('.block-active').forEach(elm => elm.classList.remove('block-active'));
76936
+ if (this.onSelectClear) this.onSelectClear();
76937
+ }
76938
+
76939
+ // Check if multiple selection occurs. If so, add 'multi' class to hide all the handles
76940
+ let blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active') && !elm.classList.contains('clone'));
76941
+ if (blocks.length > 1) {
76942
+ blocks.forEach(block => {
76943
+ block.classList.add('multi');
76944
+ });
76945
+ } else {
76946
+ const elms = this.doc.querySelectorAll('.multi');
76947
+ elms.forEach(elm => elm.classList.remove('multi'));
76948
+ }
76949
+ }
76950
+ delete() {
76951
+ let blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active') && elm.classList.contains('editable'));
76952
+ if (blocks.length > 0) return;
76953
+ if (this.onBeforeChange) this.onBeforeChange();
76954
+ blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active'));
76955
+ blocks.forEach(element => {
76956
+ element.removeEventListener('mousedown', this.handleDragStart);
76957
+ element.removeEventListener('touchstart', this.handleDragStart);
76958
+ if (this.onDelete) this.onDelete(element);
76959
+ element.parentNode.removeChild(element);
76960
+ });
76961
+ if (this.onChange) this.onChange();
76962
+ }
76963
+ handleKeyDown(event) {
76964
+ if (event.key === 'Delete' || event.key === 'Backspace' || event.keyCode === 46) {
76965
+ this.delete();
76966
+ }
76967
+ }
76968
+ }
76969
+ class Editable {
76970
+ constructor(options) {
76971
+ this.selector = options && options.selector || '.is-block';
76972
+ this.controlSelector = options && options.controlSelector || null;
76973
+ this.onEditStart = options && options.onEditStart || null;
76974
+ this.onEditEnd = options && options.onEditEnd || null;
76975
+ this.doc = options && options.doc || document;
76976
+ this.win = options && options.win || window;
76977
+ this.onContentClick = options && options.onContentClick || null;
76978
+ this.elements = this.doc.querySelectorAll(this.selector);
76979
+ this.handleEditStart = this.handleEditStart.bind(this);
76980
+ this.handleMouseClick = this.handleMouseClick.bind(this);
76981
+ this.handleTouchStart = this.handleTouchStart.bind(this);
76982
+ this.setup();
76983
+ }
76984
+ setup() {
76985
+ this.elements.forEach(element => {
76986
+ element.addEventListener('dblclick', this.handleEditStart);
76987
+ element.addEventListener('touchstart', this.handleTouchStart, {
76988
+ passive: false
76989
+ });
76990
+ });
76991
+ }
76992
+ refresh() {
76993
+ this.elements = this.doc.querySelectorAll(this.selector);
76994
+ this.elements.forEach(element => {
76995
+ element.removeEventListener('dblclick', this.handleEditStart);
76996
+ element.removeEventListener('touchstart', this.handleTouchStart);
76997
+ });
76998
+ this.elements.forEach(element => {
76999
+ element.addEventListener('dblclick', this.handleEditStart);
77000
+ element.addEventListener('touchstart', this.handleTouchStart, {
77001
+ passive: false
77002
+ });
77003
+ });
77004
+ }
77005
+ destroy(element) {
77006
+ if (element) {
77007
+ element.removeEventListener('dblclick', this.handleEditStart);
77008
+ element.removeEventListener('touchstart', this.handleTouchStart);
77009
+ } else {
77010
+ this.elements = this.doc.querySelectorAll(this.selector);
77011
+ this.elements.forEach(element => {
77012
+ element.removeEventListener('dblclick', this.handleEditStart);
77013
+ element.removeEventListener('touchstart', this.handleTouchStart);
77014
+ });
77015
+ }
77016
+ }
77017
+ handleEditStart(event) {
77018
+ const currentTarget = event.currentTarget;
77019
+ if (currentTarget.querySelector(this.selector)) {
77020
+ // if group, no edit needed
77021
+ return;
77022
+ }
77023
+ const block = event.target.closest(this.selector);
77024
+ if (currentTarget !== block) {
77025
+ // Triggered Group click by child block click
77026
+ return; // Return here, so that when block events are working, group events won't
77027
+ }
77028
+
77029
+ if (block.parentNode.matches(this.selector) && block.parentNode.classList.contains('active')) {
77030
+ // if group is active, no edit needed
77031
+ return;
77032
+ }
77033
+ this.clickedBlock = currentTarget;
77034
+
77035
+ // currentTarget.classList.add('editable');
77036
+ // currentTarget.setAttribute('contentEditable', true);
77037
+ // currentTarget.style.cursor = 'auto'; // Change cursor to normal
77038
+ // currentTarget.focus();
77039
+ // this.placeCursorAtEnd(currentTarget);
77040
+
77041
+ this.elements.forEach(element => {
77042
+ if (currentTarget === element) {
77043
+ element.removeEventListener('dblclick', this.handleEditStart);
77044
+ element.removeEventListener('touchstart', this.handleTouchStart);
77045
+ const clonedTarget = this.doc.querySelector(this.selector + '.cloned');
77046
+ if (clonedTarget) {
77047
+ clonedTarget.removeEventListener('dblclick', this.handleEditStart);
77048
+ clonedTarget.removeEventListener('touchstart', this.handleTouchStart);
77049
+ this.clickedBlock = clonedTarget;
77050
+ }
77051
+ }
77052
+ });
77053
+ this.doc.addEventListener('mousedown', this.handleMouseClick);
77054
+ this.doc.addEventListener('touchstart', this.handleMouseClick, {
77055
+ passive: false
77056
+ });
77057
+ if (this.onEditStart) this.onEditStart(currentTarget);
77058
+ }
77059
+ handleTouchStart(event) {
77060
+ // Handle Double Tab
77061
+ if (event.touches.length === 1) {
77062
+ const now = new Date().getTime();
77063
+ const lastTouchTime = this.lastTouchTime || now;
77064
+ const timeDiff = now - lastTouchTime;
77065
+ if (timeDiff < 300 && timeDiff > 0) {
77066
+ // Less than 300ms since the last touch, consider it a double-tap
77067
+ this.handleDoubleTap(event);
77068
+ }
77069
+ this.lastTouchTime = now;
77070
+ }
77071
+ }
77072
+ handleDoubleTap(event) {
77073
+ this.handleEditStart(event);
77074
+ }
77075
+ handleMouseClick(event) {
77076
+ const element = event.target;
77077
+ if (element.closest(this.selector) === this.clickedBlock || this.controlSelector && element.closest(this.controlSelector)) {
77078
+ // Do Nothing
77079
+ // Continue editing
77080
+ if (element.parentNode.matches(this.selector)) {
77081
+ if (this.onContentClick) this.onContentClick(event);
77082
+ // this.doc.querySelectorAll('.elm-active').forEach(elm=>elm.classList.remove('elm-active'));
77083
+ // element.classList.add('elm-active');
77084
+ }
77085
+ } else {
77086
+ let clickedBlock = this.clickedBlock;
77087
+
77088
+ // currentTarget.classList.remove('editable');
77089
+ // clickedBlock.removeAttribute('contentEditable');
77090
+ // clickedBlock.style.cursor = '';
77091
+
77092
+ if (this.onEditEnd) this.onEditEnd(this.clickedBlock);
77093
+ this.elements.forEach(element => {
77094
+ if (clickedBlock === element) {
77095
+ element.addEventListener('dblclick', this.handleEditStart);
77096
+ element.addEventListener('touchstart', this.handleTouchStart, {
77097
+ passive: false
77098
+ });
77099
+ }
77100
+ });
77101
+ this.doc.removeEventListener('mousedown', this.handleMouseClick);
77102
+ this.doc.removeEventListener('touchstart', this.handleMouseClick);
77103
+
77104
+ // this.doc.querySelectorAll('.elm-active').forEach(elm=>elm.classList.remove('elm-active'));
77105
+ }
77106
+ }
77107
+
77108
+ quitEditable(block) {
77109
+ if (this.onEditEnd) this.onEditEnd(block);
77110
+ block.addEventListener('dblclick', this.handleEditStart);
77111
+ block.addEventListener('touchstart', this.handleTouchStart, {
77112
+ passive: false
77113
+ });
77114
+ this.doc.removeEventListener('mousedown', this.handleMouseClick);
77115
+ this.doc.removeEventListener('touchstart', this.handleMouseClick);
77116
+ }
77117
+ placeCursorAtEnd(element) {
77118
+ const range = this.doc.createRange();
77119
+ const sel = this.win.getSelection();
77120
+ range.setStart(element, element.childNodes.length);
77121
+ range.collapse(true);
77122
+ sel.removeAllRanges();
77123
+ sel.addRange(range);
77124
+ }
77125
+ }
77126
+ class BlockSelector {
77127
+ constructor(options) {
77128
+ this.selector = options && options.selector || '.is-block';
77129
+ this.parentSelector = options && options.parentSelector || 'body';
77130
+ this.doc = options && options.doc || document;
77131
+ this.win = options && options.win || window;
77132
+ this.disableOnMobile = options && options.disableOnMobile || 0;
77133
+ this.onMultipleSelect = options && options.onMultipleSelect || null;
77134
+ this.isDragging = false;
77135
+ this.startCoords = {
77136
+ x: 0,
77137
+ y: 0
77138
+ };
77139
+ const handleHTML = `
77140
+ <div class="selection-rectangle"></div>`;
77141
+ this.doc.body.insertAdjacentHTML('afterbegin', handleHTML);
77142
+ this.selectionRect = this.doc.querySelector('.selection-rectangle');
77143
+ const styleHTML = `
77144
+ <style id="styleSelector">
77145
+ .selection-rectangle {
77146
+ position: absolute;
77147
+ border: 1px solid #c2e2ff;
77148
+ pointer-events: none;
77149
+ display: none;
77150
+ background-color: #a9c4e442;
77151
+ z-index:1
77152
+ }
77153
+ <style>
77154
+ `;
77155
+ const elmStyle = this.doc.querySelector('#styleSelector');
77156
+ if (!elmStyle) this.doc.head.insertAdjacentHTML('beforeend', styleHTML);
77157
+ this.handleDragStart = this.handleDragStart.bind(this);
77158
+ this.handleDragMove = this.handleDragMove.bind(this);
77159
+ this.handleDragEnd = this.handleDragEnd.bind(this);
77160
+ this.doc.addEventListener('mousedown', this.handleDragStart);
77161
+ this.doc.addEventListener('touchstart', this.handleDragStart, {
77162
+ passive: false
77163
+ });
77164
+ }
77165
+ destroy() {
77166
+ const elmStyle = this.doc.querySelector('#styleSelector');
77167
+ if (elmStyle) elmStyle.parentNode.removeChild(elmStyle);
77168
+ const selectionRect = this.doc.querySelector('.selection-rectangle');
77169
+ if (selectionRect) selectionRect.parentNode.removeChild(selectionRect);
77170
+ this.doc.removeEventListener('mousedown', this.handleDragStart);
77171
+ this.doc.removeEventListener('touchstart', this.handleDragStart);
77172
+ }
77173
+ handleDragStart(event) {
77174
+ const viewportWidth = this.win.innerWidth;
77175
+ if (viewportWidth <= this.disableOnMobile) return;
77176
+ if (event.type === 'touchstart' && event.touches.length !== 1) {
77177
+ return; // Do nothing if more than one touch point is detected
77178
+ }
77179
+
77180
+ if (event.type === 'mousedown' && event.button !== 0) {
77181
+ return; // Do nothing if the right mouse button is clicked
77182
+ }
77183
+
77184
+ if (event.target.closest(this.selector)) return;
77185
+ if (!event.target.closest(this.parentSelector)) return;
77186
+ if (event.target.closest('.keep-selection')) return;
77187
+ this.dragStartTimeout = setTimeout(() => {
77188
+ // Set a timeout before starting the drag (to differentiate from click)
77189
+
77190
+ this.isDragging = true;
77191
+ let clientX, clientY;
77192
+ if (event.type === 'mousedown') {
77193
+ clientX = event.clientX;
77194
+ clientY = event.clientY;
77195
+ } else if (event.type === 'touchstart') {
77196
+ const touch = event.touches[0];
77197
+ clientX = touch.clientX;
77198
+ clientY = touch.clientY;
77199
+ }
77200
+ this.startCoords = {
77201
+ x: clientX,
77202
+ y: clientY
77203
+ };
77204
+ this.updateSelectionRect(this.startCoords, this.startCoords);
77205
+ this.doc.addEventListener('mousemove', this.handleDragMove);
77206
+ this.doc.addEventListener('touchmove', this.handleDragMove);
77207
+ this.doc.body.style.userSelect = 'none';
77208
+ }, 100);
77209
+ this.doc.addEventListener('mouseup', this.handleDragEnd);
77210
+ this.doc.addEventListener('touchend', this.handleDragEnd);
77211
+ }
77212
+ handleDragMove(event) {
77213
+ if (!this.isDragging) return;
77214
+ if (event.target.closest('.keep-selection')) return;
77215
+ let clientX, clientY;
77216
+ if (event.type === 'mousemove') {
77217
+ clientX = event.clientX;
77218
+ clientY = event.clientY;
77219
+ } else if (event.type === 'touchmove') {
77220
+ const touch = event.touches[0];
77221
+ clientX = touch.clientX;
77222
+ clientY = touch.clientY;
77223
+ }
77224
+ this.updateSelectionRect(this.startCoords, {
77225
+ x: clientX,
77226
+ y: clientY
77227
+ });
77228
+ this.selectBlocksInArea(this.startCoords, {
77229
+ x: clientX,
77230
+ y: clientY
77231
+ });
77232
+ }
77233
+ handleDragEnd() {
77234
+ clearTimeout(this.dragStartTimeout);
77235
+ this.isDragging = false;
77236
+ this.selectionRect.style.display = 'none';
77237
+ this.doc.removeEventListener('mousemove', this.handleDragMove);
77238
+ this.doc.removeEventListener('touchmove', this.handleDragMove);
77239
+ this.doc.removeEventListener('mouseup', this.handleDragEnd);
77240
+ this.doc.removeEventListener('touchend', this.handleDragEnd);
77241
+ this.doc.body.style.userSelect = '';
77242
+ const elms = this.doc.querySelectorAll(this.selector + '.active');
77243
+ if (elms.length > 1) this.onMultipleSelect();
77244
+ }
77245
+ updateSelectionRect(start, end) {
77246
+ const minX = Math.min(start.x, end.x);
77247
+ const minY = Math.min(start.y, end.y) + this.win.scrollY;
77248
+ const width = Math.abs(start.x - end.x);
77249
+ const height = Math.abs(start.y - end.y);
77250
+ this.selectionRect.style.left = `${minX}px`;
77251
+ this.selectionRect.style.top = `${minY}px`;
77252
+ this.selectionRect.style.width = `${width}px`;
77253
+ this.selectionRect.style.height = `${height}px`;
77254
+ this.selectionRect.style.display = 'block';
77255
+ }
77256
+ selectBlocksInArea(start, end) {
77257
+ const blocks = this.doc.querySelectorAll(this.selector);
77258
+ blocks.forEach(block => {
77259
+ const rect = block.getBoundingClientRect();
77260
+ if (rect.left < Math.max(start.x, end.x) && rect.right > Math.min(start.x, end.x) && rect.top < Math.max(start.y, end.y) && rect.bottom > Math.min(start.y, end.y)) {
77261
+ if (block.parentNode.matches(this.selector)) ; else {
77262
+ block.classList.add('active');
77263
+ let elms = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active') && !elm.classList.contains('clone'));
77264
+ if (elms.length > 1) block.classList.add('multi');
77265
+ }
77266
+ } else {
77267
+ block.classList.remove('active');
77268
+ block.classList.remove('multi');
77269
+ }
77270
+ });
77271
+ }
77272
+ unSelect() {
77273
+ const blocks = this.doc.querySelectorAll(this.selector);
77274
+ blocks.forEach(elm => elm.classList.remove('active'));
77275
+ }
77276
+ }
77277
+ class EditableBlocks {
77278
+ constructor(options = {}) {
77279
+ const defaults = {
77280
+ selector: '.is-block',
77281
+ parentSelector: 'body',
77282
+ // controlSelector: '.is-tool',
77283
+ doc: document,
77284
+ win: window,
77285
+ // onBeforeChange: () => {},
77286
+ // onChange: () => {},
77287
+ // onContentClick: () => {},
77288
+ // onEditStart: () => {},
77289
+ // onEditEnd: () => {},
77290
+ // onDuplicate: () => {},
77291
+ // onSelectBlock: (block) => {},
77292
+ // onUnSelectBlock: () => {},
77293
+ // onMultipleSelect: () => {},
77294
+ disableOnMobile: 0,
77295
+ rotate: true,
77296
+ clone: true
77297
+ // onDelete: () = {}
77298
+ };
77299
+
77300
+ Object.assign(this, defaults, options);
77301
+ this.init();
77302
+ }
77303
+ checkOverlap(target) {
77304
+ return this.common.checkOverlap(target);
77305
+ }
77306
+ forward(target) {
77307
+ let newZIndex;
77308
+ if (!target.style.zIndex) {
77309
+ newZIndex = 1;
77310
+ } else {
77311
+ newZIndex = parseInt(target.style.zIndex) + 1;
77312
+ }
77313
+ target.style.zIndex = newZIndex;
77314
+ }
77315
+ backward(target) {
77316
+ let newZIndex;
77317
+ if (!target.style.zIndex) {
77318
+ newZIndex = 0;
77319
+ } else {
77320
+ if (parseInt(target.style.zIndex) - 1 < 0) newZIndex = 0;else newZIndex = parseInt(target.style.zIndex) - 1;
77321
+ }
77322
+ target.style.zIndex = newZIndex;
77323
+ }
77324
+ selectStart(block) {
77325
+ if (block.classList.contains('is-shape')) return; // do not clone if block is shape
77326
+
77327
+ if (!this.clone) return;
77328
+ const viewportWidth = this.win.innerWidth;
77329
+ if (block.closest('.autolayout') && viewportWidth <= 760) {
77330
+ return;
77331
+ }
77332
+ if (block.classList.contains('is-group')) return; // do not clone if block is shape
77333
+
77334
+ if (!block.classList.contains('clone')) {
77335
+ let clonedDiv = block.cloneNode(true);
77336
+ clonedDiv.classList.add('clone');
77337
+ block.parentNode.appendChild(clonedDiv);
77338
+ block.classList.add('cloned');
77339
+ this.refresh();
77340
+ }
77341
+ }
77342
+ selectClear() {
77343
+ this.doc.querySelectorAll('.clone').forEach(elm => elm.parentNode.removeChild(elm));
77344
+ this.doc.querySelectorAll('.cloned').forEach(elm => elm.classList.remove('cloned'));
77345
+ }
77346
+ setMultiSelect(multiSelect) {
77347
+ if (multiSelect) this.doc.body.classList.add('multi-select');else this.doc.body.classList.remove('multi-select');
77348
+ }
77349
+ init() {
77350
+ this.doc.body.classList.add('editableblocks');
77351
+ this.draggable = new Draggable({
77352
+ selector: this.selector,
77353
+ disableOnMobile: this.disableOnMobile,
77354
+ doc: this.doc,
77355
+ win: this.win,
77356
+ onDelete: element => {
77357
+ if (this.rotatable) this.rotatable.destroy(element);
77358
+ this.resizable.destroy(element);
77359
+ this.editable.destroy(element);
77360
+ if (this.onDelete) this.onDelete();
77361
+ },
77362
+ onBeforeChange: () => {
77363
+ if (this.onBeforeChange) this.onBeforeChange();
77364
+ },
77365
+ onChange: () => {
77366
+ if (this.onChange) this.onChange();
77367
+ },
77368
+ onMultipleSelect: this.onMultipleSelect,
77369
+ onSelectStart: block => {
77370
+ // for cloning
77371
+ this.selectStart(block);
77372
+ },
77373
+ onSelectClear: () => {
77374
+ // for removing clones
77375
+ this.selectClear();
77376
+ if (this.onUnselectBlock) this.onUnselectBlock();
77377
+ },
77378
+ onSelectBlock: this.onSelectBlock
77379
+ });
77380
+ this.resizable = new Resizable({
77381
+ selector: this.selector,
77382
+ disableOnMobile: this.disableOnMobile,
77383
+ doc: this.doc,
77384
+ win: this.win,
77385
+ onBeforeChange: () => {
77386
+ if (this.onBeforeChange) this.onBeforeChange();
77387
+ },
77388
+ onChange: () => {
77389
+ if (this.onChange) this.onChange();
77390
+ }
77391
+ });
77392
+ if (this.rotate) {
77393
+ this.rotatable = new Rotatable({
77394
+ selector: this.selector,
77395
+ disableOnMobile: this.disableOnMobile,
77396
+ doc: this.doc,
77397
+ win: this.win,
77398
+ onBeforeChange: () => {
77399
+ if (this.onBeforeChange) this.onBeforeChange();
77400
+ },
77401
+ onChange: () => {
77402
+ if (this.onChange) this.onChange();
77403
+ }
77404
+ });
77405
+ }
77406
+ this.editable = new Editable({
77407
+ selector: this.selector,
77408
+ controlSelector: this.controlSelector,
77409
+ doc: this.doc,
77410
+ win: this.win,
77411
+ onContentClick: this.onContentClick,
77412
+ onEditStart: block => {
77413
+ if (block.classList.contains('clone')) {
77414
+ const clonedTarget = this.doc.querySelector(this.selector + '.cloned');
77415
+ this.onEditStart(clonedTarget);
77416
+ this.selectClear();
77417
+
77418
+ // Disable drag during editing
77419
+ if (!this.draggable) return;
77420
+ this.draggable.disableDrag(clonedTarget);
77421
+ return;
77422
+ }
77423
+ this.onEditStart(block);
77424
+
77425
+ // Disable drag during editing
77426
+ if (!this.draggable) return;
77427
+ this.draggable.disableDrag(block);
77428
+ },
77429
+ onEditEnd: block => {
77430
+ this.onEditEnd(block);
77431
+
77432
+ // Enable drag
77433
+ if (!this.draggable) return;
77434
+ this.draggable.enableDrag(block);
77435
+ }
77436
+ });
77437
+ this.blockSelector = new BlockSelector({
77438
+ selector: this.selector,
77439
+ parentSelector: this.parentSelector,
77440
+ disableOnMobile: this.disableOnMobile,
77441
+ onMultipleSelect: this.onMultipleSelect,
77442
+ doc: this.doc,
77443
+ win: this.win
77444
+ });
77445
+ this.common = new Common({
77446
+ selector: this.selector,
77447
+ doc: this.doc,
77448
+ win: this.win,
77449
+ onDuplicate: this.onDuplicate
77450
+ });
77451
+ }
77452
+ duplicate() {
77453
+ this.common.duplicate();
77454
+ this.refresh();
77455
+ }
77456
+ delete() {
77457
+ this.draggable.delete();
77458
+ }
77459
+ getBreakpoints(block) {
77460
+ return this.common.getBreakpoints(block);
77461
+ }
77462
+ placeCursorAtEnd(block) {
77463
+ this.editable.placeCursorAtEnd(block);
77464
+ }
77465
+ quitEditable(block) {
77466
+ this.editable.quitEditable(block);
77467
+ }
77468
+ destroy() {
77469
+ if (!this.draggable) return;
77470
+ this.draggable.destroy();
77471
+ this.resizable.destroy();
77472
+ if (this.rotatable) this.rotatable.destroy();
77473
+ this.editable.destroy();
77474
+ this.blockSelector.destroy();
77475
+ this.draggable = null;
77476
+ this.doc.body.classList.remove('editableblocks');
77477
+ }
77478
+ refresh() {
77479
+ // Call refresh() whenever blocks are added
77480
+ this.draggable.refresh();
77481
+ this.resizable.refresh();
77482
+ if (this.rotatable) this.rotatable.refresh();
77483
+ this.editable.refresh();
77484
+ }
77485
+ addBlock(html, container) {
77486
+ this.selectClear(); // clear clones
77487
+ this.blockSelector.unSelect(); // clear active
77488
+
77489
+ const parser = new DOMParser();
77490
+ let doc = parser.parseFromString(html, 'text/html');
77491
+ const block = doc.querySelector('.is-block');
77492
+ block.classList.add('block-dummy');
77493
+ html = doc.body.innerHTML;
77494
+ container.insertAdjacentHTML('beforeend', html);
77495
+ const newBlock = document.querySelector('.block-dummy');
77496
+ if (newBlock) {
77497
+ newBlock.classList.remove('block-dummy');
77498
+ if (this.onAddBlock) this.onAddBlock(newBlock);
77499
+ newBlock.classList.add('active');
77500
+ }
77501
+ this.refresh();
77502
+ }
77503
+ group() {
77504
+ const group = this.common.group('is-block', 'is-group');
77505
+ this.refresh();
77506
+ return group;
77507
+ }
77508
+ unGroup() {
77509
+ this.common.unGroup();
77510
+ }
77511
+ addBreakpoint() {
77512
+ this.common.addBreakpoint();
77513
+ }
77514
+ clearBreakpoint(target) {
77515
+ this.common.clearBreakpoint(target);
77516
+ if (target.classList.contains('cloned')) {
77517
+ const cloneTarget = this.doc.querySelector(this.selector + '.clone');
77518
+ this.common.clearBreakpoint(cloneTarget);
77519
+ }
77520
+ }
77521
+ clearAllBreakpoints(container) {
77522
+ this.common.clearAllBreakpoints(container);
77523
+ }
77524
+ isMultiSelect() {
77525
+ // Check if multiple selection occurs. If so, add 'multi' class to hide all the handles
77526
+ let blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active') && !elm.classList.contains('clone'));
77527
+ if (blocks.length > 1) return true;
77528
+ return false;
77529
+ }
77530
+ }
75405
77531
 
75406
77532
  class ContentBuilder {
75407
77533
  constructor(opts = {}) {
@@ -75630,6 +77756,7 @@ class ContentBuilder {
75630
77756
  customval: '',
75631
77757
  moduleConfig: [],
75632
77758
  elementAnimate: false,
77759
+ cleanAOS: false,
75633
77760
  framework: '',
75634
77761
  cellFormat: '',
75635
77762
  rowFormat: '',
@@ -75641,9 +77768,11 @@ class ContentBuilder {
75641
77768
  defaultEmailSnippetCategory: 14,
75642
77769
  undoRedoStyles: false,
75643
77770
  // specialElementClasses: ['sl-wrapper', 'sl-overlay'] // specify elements that when clicked will not affect the builder interface (active selection). Usefull for external code, ex lightbox, etc.
75644
- // onUndo: function () { },
75645
- // onRedo: function () { }
75646
77771
 
77772
+ // freeform
77773
+ onUndo: function () {},
77774
+ onRedo: function () {},
77775
+ onBlockCanvasAdd: function () {},
75647
77776
  /*
75648
77777
  Deprecated:
75649
77778
  snippetSampleImage: '',
@@ -76525,6 +78654,26 @@ class ContentBuilder {
76525
78654
  this.colTool.lockIndicator.style.display = '';
76526
78655
  return ret;
76527
78656
  };
78657
+
78658
+ // freeform
78659
+ let oldOnBlockCanvasAdd = this.opts.onBlockCanvasAdd;
78660
+ this.opts.onBlockCanvasAdd = () => {
78661
+ let ret = oldOnBlockCanvasAdd.apply(this, arguments);
78662
+ if (this.eb) this.eb.refresh();
78663
+ return ret;
78664
+ };
78665
+ let oldOnUndo = this.opts.onUndo;
78666
+ this.opts.onUndo = () => {
78667
+ let ret = oldOnUndo.apply(this, arguments);
78668
+ if (this.eb) this.eb.refresh();
78669
+ return ret;
78670
+ };
78671
+ let oldOnRedo = this.opts.onRedo;
78672
+ this.opts.onRedo = () => {
78673
+ let ret = oldOnRedo.apply(this, arguments);
78674
+ if (this.eb) this.eb.refresh();
78675
+ return ret;
78676
+ };
76528
78677
  this.elmTool = new ElementTool(this); // Render Element Tool
76529
78678
 
76530
78679
  // Render controls or behavior for handling element editing
@@ -76592,6 +78741,68 @@ class ContentBuilder {
76592
78741
  }
76593
78742
  */
76594
78743
 
78744
+ // freeform
78745
+ if (this.canvas) this.eb = new EditableBlocks({
78746
+ doc: this.doc,
78747
+ win: this.win,
78748
+ selector: '.is-block',
78749
+ controlSelector: '.is-tool,.is-pop,.is-modal,#divImageResizer,.is-rte-tool,is-elementrte-tool,.is-rte-pop,.keep-selection',
78750
+ parentSelector: '.box-canvas',
78751
+ rotate: true,
78752
+ // disableOnMobile: 760,
78753
+ onBeforeChange: () => {
78754
+ this.uo.saveForUndo();
78755
+ },
78756
+ onChange: () => {
78757
+ this.opts.onChange();
78758
+ },
78759
+ onEditStart: block => {
78760
+ block.classList.add('editable');
78761
+ const cols = block.querySelectorAll('[data-click="true"]'); // or [contentEditable="true"]
78762
+ if (cols.length > 0) {
78763
+ let col = cols[cols.length - 1];
78764
+ if (col.lastElementChild) col.lastElementChild.click();
78765
+ }
78766
+ },
78767
+ onEditEnd: block => {
78768
+ block.classList.remove('editable');
78769
+ this.util.clearActiveCell();
78770
+ this.util.clearPops();
78771
+ this.hideElementTools();
78772
+ },
78773
+ onDuplicate: block => {
78774
+ const builder = block.querySelector(this.container);
78775
+ let html = '';
78776
+ if (builder) {
78777
+ html = this.readHtml(builder);
78778
+ }
78779
+ let clonedDiv = block.cloneNode(true);
78780
+ clonedDiv.style.top = '20%';
78781
+ clonedDiv.style.left = '20%';
78782
+ if (builder) {
78783
+ const cloneBuilder = clonedDiv.querySelector(this.container);
78784
+ cloneBuilder.innerHTML = '';
78785
+ block.parentNode.appendChild(clonedDiv);
78786
+ const range = document.createRange();
78787
+ cloneBuilder.appendChild(range.createContextualFragment(html));
78788
+ this.applyBehaviorOn(cloneBuilder);
78789
+ cloneBuilder.click();
78790
+ } else {
78791
+ block.parentNode.appendChild(clonedDiv);
78792
+ }
78793
+ block.classList.remove('active');
78794
+ this.doc.querySelectorAll('.clone').forEach(elm => elm.parentNode.removeChild(elm));
78795
+ this.doc.querySelectorAll('.cloned').forEach(elm => elm.classList.remove('cloned'));
78796
+ },
78797
+ onAddBlock: block => {
78798
+ const builder = block.querySelector(this.container);
78799
+ this.applyBehaviorOn(builder);
78800
+ },
78801
+ onMultipleSelect: this.onMultipleSelect,
78802
+ onDelete: this.onDelete,
78803
+ onSelectBlock: this.onSelectBlock,
78804
+ onUnselectBlock: this.onUnselectBlock
78805
+ });
76595
78806
  if (this.iframe) {
76596
78807
  this.win.addEventListener('scroll', this.doWindowScroll = () => {
76597
78808
  this.util.hidePops();
@@ -77412,6 +79623,13 @@ class ContentBuilder {
77412
79623
  this.setZoomOnControl(builder);
77413
79624
  }
77414
79625
  html(area) {
79626
+ if (this.docContainer) {
79627
+ // freeform
79628
+
79629
+ const docContainer = this.doc.querySelector(this.docContainer);
79630
+ const html = this.readHtml(docContainer, false, true);
79631
+ return html;
79632
+ }
77415
79633
  const util = this.util;
77416
79634
  const htmlutil = new HtmlUtil(this);
77417
79635
  if (area) ; else {
@@ -77478,7 +79696,87 @@ class ContentBuilder {
77478
79696
  simpleColorPicker(onPick, mode) {
77479
79697
  return this.colorClassPicker.open(onPick, mode);
77480
79698
  }
79699
+
79700
+ // freeform
79701
+ refresh() {
79702
+ if (this.eb) this.eb.refresh();
79703
+ }
79704
+ group() {
79705
+ if (!this.eb) return;
79706
+ this.uo.saveForUndo();
79707
+ this.eb.group();
79708
+ this.opts.onChange();
79709
+ }
79710
+ unGroup() {
79711
+ if (!this.eb) return;
79712
+ this.uo.saveForUndo();
79713
+ this.eb.unGroup();
79714
+ this.opts.onChange();
79715
+ }
79716
+ delete() {
79717
+ if (!this.eb) return;
79718
+ this.uo.saveForUndo();
79719
+ this.eb.delete();
79720
+ this.opts.onChange();
79721
+ }
79722
+ forward(target) {
79723
+ if (!this.eb) return;
79724
+ this.uo.saveForUndo();
79725
+ this.eb.forward(target);
79726
+ this.opts.onChange();
79727
+ }
79728
+ backward(target) {
79729
+ if (!this.eb) return;
79730
+ this.uo.saveForUndo();
79731
+ this.eb.backward(target);
79732
+ this.opts.onChange();
79733
+ }
79734
+ enableShape() {
79735
+ if (!this.eb) return;
79736
+ this.uo.saveForUndo();
79737
+ this.eb.enableShape();
79738
+ this.opts.onChange();
79739
+ }
79740
+ removeShape() {
79741
+ if (!this.eb) return;
79742
+ this.uo.saveForUndo();
79743
+ this.eb.removeShape();
79744
+ this.opts.onChange();
79745
+ }
79746
+ addBlock(html, blockContainer) {
79747
+ if (!this.eb) return;
79748
+ this.uo.saveForUndo();
79749
+ this.eb.addBlock(html, blockContainer);
79750
+ this.opts.onChange();
79751
+ this.opts.onRender();
79752
+ }
79753
+ duplicate() {
79754
+ if (!this.eb) return;
79755
+ this.uo.saveForUndo();
79756
+ this.eb.duplicate();
79757
+ this.opts.onChange();
79758
+ this.opts.onRender();
79759
+ }
79760
+ addBreakpoint() {
79761
+ if (!this.eb) return;
79762
+ this.eb.addBreakpoint();
79763
+ }
79764
+ getBreakpoints(target) {
79765
+ if (!this.eb) return;
79766
+ return this.eb.getBreakpoints(target);
79767
+ }
79768
+ clearBreakpoint(target) {
79769
+ if (!this.eb) return;
79770
+ this.uo.saveForUndo();
79771
+ this.eb.clearBreakpoint(target);
79772
+ this.opts.onChange();
79773
+ }
79774
+ quitEditable(target) {
79775
+ if (!this.eb) return;
79776
+ this.eb.quitEditable(target);
79777
+ }
77481
79778
  destroy() {
79779
+ if (this.eb) this.eb.destroy();
77482
79780
  this.doc.body.classList.remove('data-editor');
77483
79781
  document.removeEventListener('click', this.doDocumentClick, false);
77484
79782
  document.removeEventListener('keydown', this.doDocumentKeydown, false);
@@ -78100,7 +80398,7 @@ class ContentBuilder {
78100
80398
  this.opts.onPluginsLoaded();
78101
80399
  }
78102
80400
  this.tooltip.setAll();
78103
- new Draggable$1({
80401
+ new Draggable$2({
78104
80402
  selector: '.is-draggable'
78105
80403
  }); //draggable for plugins
78106
80404
 
@@ -78161,7 +80459,7 @@ class ContentBuilder {
78161
80459
  this.opts.onPluginsLoaded();
78162
80460
  }
78163
80461
  this.tooltip.setAll();
78164
- new Draggable$1({
80462
+ new Draggable$2({
78165
80463
  selector: '.is-draggable'
78166
80464
  }); //draggable for plugins
78167
80465
 
@@ -78317,7 +80615,7 @@ class ContentBuilder {
78317
80615
  }
78318
80616
 
78319
80617
  draggable(selector) {
78320
- new Draggable$1({
80618
+ new Draggable$2({
78321
80619
  selector: selector
78322
80620
  });
78323
80621
  }
@@ -78328,7 +80626,7 @@ class ContentBuilder {
78328
80626
  embeddedModal = this.builderStuff.querySelector(selector);
78329
80627
  }
78330
80628
  this.showModal(embeddedModal, overlayStay, cancelCallback, animated, overflowHidden);
78331
- new Draggable$1({
80629
+ new Draggable$2({
78332
80630
  selector: '.is-draggable'
78333
80631
  });
78334
80632
  return embeddedModal;
@@ -78454,6 +80752,10 @@ class ContentBuilder {
78454
80752
  // /Plugins related
78455
80753
 
78456
80754
  viewHtml(area) {
80755
+ if (this.docContainer) {
80756
+ // freeform
80757
+ area = this.doc.querySelector(this.docContainer);
80758
+ }
78457
80759
  const htmlutil = new HtmlUtil(this);
78458
80760
  htmlutil.view('full', area);
78459
80761
  }
@@ -78500,6 +80802,20 @@ class ContentBuilder {
78500
80802
  return false;
78501
80803
  }
78502
80804
  loadHtml(html, area) {
80805
+ if (this.docContainer) {
80806
+ // freeform
80807
+ const docContainer = this.doc.querySelector(this.docContainer);
80808
+ let range = this.doc.createRange();
80809
+ docContainer.innerHTML = '';
80810
+ docContainer.appendChild(range.createContextualFragment(html)); // We use createContextualFragment so that embedded javascript code (code block) will be executed
80811
+
80812
+ const builders = docContainer.querySelectorAll(this.container);
80813
+ builders.forEach(builder => {
80814
+ this.applyBehaviorOn(builder);
80815
+ });
80816
+ this.refresh();
80817
+ return;
80818
+ }
78503
80819
  const util = this.util;
78504
80820
  if (area) ; else {
78505
80821
  const builders = this.doc.querySelectorAll(this.opts.container);
@@ -78558,6 +80874,7 @@ class ContentBuilder {
78558
80874
  // }
78559
80875
  loadHTML(html) {
78560
80876
  //backward
80877
+
78561
80878
  this.loadHtml(html);
78562
80879
  }
78563
80880
  async setUIColor(mode, csslink) {