@innovastudio/contentbuilder 1.4.146 → 1.4.148
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
|
|
@@ -11204,6 +11212,23 @@ class HtmlUtil {
|
|
|
11204
11212
|
elms = tmp.querySelectorAll('[data-html-25]');
|
|
11205
11213
|
dom$k.removeAttributes(elms, 'data-html-25');
|
|
11206
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
|
+
|
|
11207
11232
|
html = tmp.innerHTML.trim();
|
|
11208
11233
|
html = html.replace(/<font/g, '<span').replace(/<\/font/g, '</span');
|
|
11209
11234
|
}
|
|
@@ -13287,26 +13312,26 @@ const renderQuickAdd = builder => {
|
|
|
13287
13312
|
elm = quickadd.querySelector('.add-button');
|
|
13288
13313
|
if (elm) dom.addEventListener(elm, 'click', () => {
|
|
13289
13314
|
const mode = quickadd.getAttribute('data-mode');
|
|
13290
|
-
let html = `<div
|
|
13291
|
-
|
|
13315
|
+
let html = `<div>
|
|
13316
|
+
<a href="#" role="button" class="transition-all inline-block whitespace-nowrap cursor-pointer no-underline border-2 border-solid mr-2 mt-2 mb-1 py-2 size-17 px-6 text-black leading-14 rounded border-transparent hover:border-transparent font-normal tracking-wide" style="background-color: rgb(240, 240, 240);">Read More</a>
|
|
13292
13317
|
</div>`;
|
|
13293
13318
|
if (builder.opts.emailMode) {
|
|
13294
|
-
html = '<div
|
|
13319
|
+
html = '<div><a href="#" role="button" style="margin-top: ;margin-right: ;margin-bottom: ;margin-left: ;display: inline-block; text-decoration: none; transition: all 0.16s ease 0s; border-style: solid; cursor: pointer; background-color: rgb(220, 220, 220); color: rgb(0, 0, 0); border-color: rgb(220, 220, 220); border-width: 2px; border-radius: 0px; padding: 13px 28px; line-height: 21px; text-transform: uppercase; font-weight: 400; font-size: 14px; letter-spacing: 3px;">Read More</a></div>';
|
|
13295
13320
|
}
|
|
13296
13321
|
util.addContent(html, mode);
|
|
13297
13322
|
});
|
|
13298
13323
|
elm = quickadd.querySelector('.add-twobutton');
|
|
13299
13324
|
if (elm) dom.addEventListener(elm, 'click', () => {
|
|
13300
13325
|
const mode = quickadd.getAttribute('data-mode');
|
|
13301
|
-
let html = `<div
|
|
13326
|
+
let html = `<div>
|
|
13302
13327
|
<a href="#" role="button" class="transition-all inline-block whitespace-nowrap cursor-pointer no-underline border-2 border-solid mr-2 mt-2 mb-1 py-2 size-17 px-6 text-black leading-14 rounded border-transparent hover:border-transparent font-normal tracking-wide" style="background-color: rgb(240, 240, 240);">Read More</a>
|
|
13303
13328
|
<a href="#" role="button" class="transition-all inline-block whitespace-nowrap cursor-pointer no-underline border-2 border-solid mr-2 mt-2 mb-1 py-2 size-17 px-6 border-current hover:border-current font-normal leading-14 rounded tracking-wide">Get Started</a>
|
|
13304
13329
|
</div>`;
|
|
13305
13330
|
if (builder.opts.emailMode) {
|
|
13306
|
-
html = `<div
|
|
13307
|
-
|
|
13308
|
-
|
|
13309
|
-
|
|
13331
|
+
html = `<div>
|
|
13332
|
+
<a href="#" role="button" style="margin-top: ;margin-right: ;margin-bottom: ;margin-left: ;display: inline-block; text-decoration: none; transition: all 0.16s ease 0s; border-style: solid; cursor: pointer; background-color: rgb(220, 220, 220); color: rgb(0, 0, 0); border-color: rgb(220, 220, 220); border-width: 2px; border-radius: 0px; padding: 13px 28px; line-height: 21px; text-transform: uppercase; font-weight: 400; font-size: 14px; letter-spacing: 3px;">Read More</a>
|
|
13333
|
+
<a href="#" role="button" style="display: inline-block; text-decoration: none; transition: all 0.16s ease 0s; border-style: solid; cursor: pointer; background-color: rgba(0, 0, 0, 0); border-color: rgb(53, 53, 53); border-width: 2px; border-radius: 0px; padding: 13px 28px; line-height: 21px; text-transform: uppercase; font-weight: 600; font-size: 14px; letter-spacing: 3px; color: rgb(53, 53, 53);">Get Started</a>
|
|
13334
|
+
</div>`;
|
|
13310
13335
|
}
|
|
13311
13336
|
util.addContent(html, mode);
|
|
13312
13337
|
});
|
|
@@ -14530,7 +14555,7 @@ Insipred by: https://www.kirupa.com/html5/drag.htm
|
|
|
14530
14555
|
*/
|
|
14531
14556
|
|
|
14532
14557
|
let initialX, initialY, currentX, currentY, xOffset, yOffset, dragActive, activeDraggableBox;
|
|
14533
|
-
class Draggable$
|
|
14558
|
+
class Draggable$2 {
|
|
14534
14559
|
constructor(opts = {}) {
|
|
14535
14560
|
this.opts = opts;
|
|
14536
14561
|
const elms = document.querySelectorAll(this.opts.selector);
|
|
@@ -14694,7 +14719,7 @@ const renderGridEditor = builder => {
|
|
|
14694
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>
|
|
14695
14720
|
|
|
14696
14721
|
dom.appendHtml(builderStuff, html);
|
|
14697
|
-
new Draggable$
|
|
14722
|
+
new Draggable$2({
|
|
14698
14723
|
selector: '.is-draggable'
|
|
14699
14724
|
});
|
|
14700
14725
|
const grideditor = document.querySelector('.grideditor');
|
|
@@ -28675,7 +28700,7 @@ function dragControlCondition(moveable, e) {
|
|
|
28675
28700
|
return false;
|
|
28676
28701
|
}
|
|
28677
28702
|
|
|
28678
|
-
var Rotatable = {
|
|
28703
|
+
var Rotatable$1 = {
|
|
28679
28704
|
name: "rotatable",
|
|
28680
28705
|
canPinch: true,
|
|
28681
28706
|
props: {
|
|
@@ -28814,7 +28839,7 @@ var Rotatable = {
|
|
|
28814
28839
|
datas.startValue = rotatation * Math.PI / 180;
|
|
28815
28840
|
}
|
|
28816
28841
|
}, fillTransformStartEvent(e)), {
|
|
28817
|
-
dragStart: Draggable.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
|
|
28842
|
+
dragStart: Draggable$1.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
|
|
28818
28843
|
}));
|
|
28819
28844
|
var result = triggerEvent(moveable, "onRotateStart", params);
|
|
28820
28845
|
datas.isRotate = result !== false;
|
|
@@ -32515,7 +32540,7 @@ var Snappable = {
|
|
|
32515
32540
|
* @description Draggable refers to the ability to drag and move targets.
|
|
32516
32541
|
*/
|
|
32517
32542
|
|
|
32518
|
-
var Draggable = {
|
|
32543
|
+
var Draggable$1 = {
|
|
32519
32544
|
name: "draggable",
|
|
32520
32545
|
props: {
|
|
32521
32546
|
draggable: Boolean,
|
|
@@ -33403,7 +33428,7 @@ function fillTransformEvent(moveable, nextTransform, delta, isPinch, e) {
|
|
|
33403
33428
|
fillOriginalTransform(e, nextTransform);
|
|
33404
33429
|
return {
|
|
33405
33430
|
transform: nextTransform,
|
|
33406
|
-
drag: Draggable.drag(moveable, setCustomDrag(e, moveable.state, delta, isPinch, false))
|
|
33431
|
+
drag: Draggable$1.drag(moveable, setCustomDrag(e, moveable.state, delta, isPinch, false))
|
|
33407
33432
|
};
|
|
33408
33433
|
}
|
|
33409
33434
|
|
|
@@ -35300,7 +35325,7 @@ var Pinchable = makeAble("pinchable", {
|
|
|
35300
35325
|
* @description Resizable indicates whether the target's width and height can be increased or decreased.
|
|
35301
35326
|
*/
|
|
35302
35327
|
|
|
35303
|
-
var Resizable = {
|
|
35328
|
+
var Resizable$1 = {
|
|
35304
35329
|
name: "resizable",
|
|
35305
35330
|
ableGroup: "size",
|
|
35306
35331
|
canPinch: true,
|
|
@@ -35445,7 +35470,7 @@ var Resizable = {
|
|
|
35445
35470
|
setOrigin: function (origin) {
|
|
35446
35471
|
datas.transformOrigin = origin;
|
|
35447
35472
|
},
|
|
35448
|
-
dragStart: Draggable.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
|
|
35473
|
+
dragStart: Draggable$1.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
|
|
35449
35474
|
});
|
|
35450
35475
|
var result = triggerEvent(moveable, "onResizeStart", params);
|
|
35451
35476
|
|
|
@@ -35630,7 +35655,7 @@ var Resizable = {
|
|
|
35630
35655
|
dist: [distWidth, distHeight],
|
|
35631
35656
|
delta: delta,
|
|
35632
35657
|
isPinch: !!isPinch,
|
|
35633
|
-
drag: Draggable.drag(moveable, setCustomDrag(e, moveable.state, inverseDelta, !!isPinch, false))
|
|
35658
|
+
drag: Draggable$1.drag(moveable, setCustomDrag(e, moveable.state, inverseDelta, !!isPinch, false))
|
|
35634
35659
|
});
|
|
35635
35660
|
triggerEvent(moveable, "onResize", params);
|
|
35636
35661
|
return params;
|
|
@@ -36222,7 +36247,7 @@ var Scalable = {
|
|
|
36222
36247
|
setRatio: setRatio,
|
|
36223
36248
|
setFixedDirection: setFixedDirection
|
|
36224
36249
|
}, fillTransformStartEvent(e)), {
|
|
36225
|
-
dragStart: Draggable.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
|
|
36250
|
+
dragStart: Draggable$1.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
|
|
36226
36251
|
}));
|
|
36227
36252
|
var result = triggerEvent(moveable, "onScaleStart", params);
|
|
36228
36253
|
|
|
@@ -39365,7 +39390,7 @@ var OriginDraggable = {
|
|
|
39365
39390
|
var datas = e.datas;
|
|
39366
39391
|
setDragStart(moveable, e);
|
|
39367
39392
|
var params = fillParams(moveable, e, {
|
|
39368
|
-
dragStart: Draggable.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
|
|
39393
|
+
dragStart: Draggable$1.dragStart(moveable, new CustomGesto().dragStart([0, 0], e))
|
|
39369
39394
|
});
|
|
39370
39395
|
var result = triggerEvent(moveable, "onDragOriginStart", params);
|
|
39371
39396
|
datas.startOrigin = moveable.state.transformOrigin;
|
|
@@ -39428,7 +39453,7 @@ var OriginDraggable = {
|
|
|
39428
39453
|
dist: dist,
|
|
39429
39454
|
delta: delta,
|
|
39430
39455
|
transformOrigin: transformOrigin,
|
|
39431
|
-
drag: Draggable.drag(moveable, setCustomDrag(e, moveable.state, dragDelta, !!isPinch, false))
|
|
39456
|
+
drag: Draggable$1.drag(moveable, setCustomDrag(e, moveable.state, dragDelta, !!isPinch, false))
|
|
39432
39457
|
});
|
|
39433
39458
|
triggerEvent(moveable, "onDragOrigin", params);
|
|
39434
39459
|
return params;
|
|
@@ -41840,13 +41865,13 @@ var edgeDraggable = makeAble("edgeDraggable", {
|
|
|
41840
41865
|
return hasClass(target, prefix("direction")) && hasClass(target, prefix("line"));
|
|
41841
41866
|
},
|
|
41842
41867
|
dragControlStart: function (moveable, e) {
|
|
41843
|
-
return Draggable.dragStart(moveable, getDraggableEvent(e));
|
|
41868
|
+
return Draggable$1.dragStart(moveable, getDraggableEvent(e));
|
|
41844
41869
|
},
|
|
41845
41870
|
dragControl: function (moveable, e) {
|
|
41846
|
-
return Draggable.drag(moveable, getDraggableEvent(e));
|
|
41871
|
+
return Draggable$1.drag(moveable, getDraggableEvent(e));
|
|
41847
41872
|
},
|
|
41848
41873
|
dragControlEnd: function (moveable, e) {
|
|
41849
|
-
return Draggable.dragEnd(moveable, getDraggableEvent(e));
|
|
41874
|
+
return Draggable$1.dragEnd(moveable, getDraggableEvent(e));
|
|
41850
41875
|
},
|
|
41851
41876
|
dragGroupControlCondition: function (moveable, e) {
|
|
41852
41877
|
if (!moveable.props.edgeDraggable || !e.inputEvent) {
|
|
@@ -41857,16 +41882,16 @@ var edgeDraggable = makeAble("edgeDraggable", {
|
|
|
41857
41882
|
return hasClass(target, prefix("direction")) && hasClass(target, prefix("line"));
|
|
41858
41883
|
},
|
|
41859
41884
|
dragGroupControlStart: function (moveable, e) {
|
|
41860
|
-
return Draggable.dragGroupStart(moveable, getDraggableEvent(e));
|
|
41885
|
+
return Draggable$1.dragGroupStart(moveable, getDraggableEvent(e));
|
|
41861
41886
|
},
|
|
41862
41887
|
dragGroupControl: function (moveable, e) {
|
|
41863
|
-
return Draggable.dragGroup(moveable, getDraggableEvent(e));
|
|
41888
|
+
return Draggable$1.dragGroup(moveable, getDraggableEvent(e));
|
|
41864
41889
|
},
|
|
41865
41890
|
dragGroupControlEnd: function (moveable, e) {
|
|
41866
|
-
return Draggable.dragGroupEnd(moveable, getDraggableEvent(e));
|
|
41891
|
+
return Draggable$1.dragGroupEnd(moveable, getDraggableEvent(e));
|
|
41867
41892
|
},
|
|
41868
41893
|
unset: function (moveable) {
|
|
41869
|
-
return Draggable.unset(moveable);
|
|
41894
|
+
return Draggable$1.unset(moveable);
|
|
41870
41895
|
}
|
|
41871
41896
|
});
|
|
41872
41897
|
/**
|
|
@@ -41890,7 +41915,7 @@ var IndividualGroupable = {
|
|
|
41890
41915
|
},
|
|
41891
41916
|
events: {}
|
|
41892
41917
|
};
|
|
41893
|
-
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];
|
|
41894
41919
|
var MOVEABLE_EVENTS_PROPS_MAP = /*#__PURE__*/MOVEABLE_ABLES.reduce(function (current, able) {
|
|
41895
41920
|
return __assign$2(__assign$2({}, current), "events" in able ? able.events : {});
|
|
41896
41921
|
}, {});
|
|
@@ -52087,7 +52112,7 @@ class ColorPicker {
|
|
|
52087
52112
|
});
|
|
52088
52113
|
};
|
|
52089
52114
|
setupTabKeys(pickcolor);
|
|
52090
|
-
new Draggable$
|
|
52115
|
+
new Draggable$2({
|
|
52091
52116
|
selector: '#' + this.id + ' .is-draggable'
|
|
52092
52117
|
});
|
|
52093
52118
|
let tmp = document.createElement('div');
|
|
@@ -52952,7 +52977,7 @@ class GradientPicker {
|
|
|
52952
52977
|
});
|
|
52953
52978
|
};
|
|
52954
52979
|
setupTabKeys(pickGradient);
|
|
52955
|
-
new Draggable$
|
|
52980
|
+
new Draggable$2({
|
|
52956
52981
|
selector: '#' + this.id + ' .is-draggable'
|
|
52957
52982
|
});
|
|
52958
52983
|
const colorPicker = new ColorPicker({
|
|
@@ -75403,7 +75428,2106 @@ class Similarity {
|
|
|
75403
75428
|
}
|
|
75404
75429
|
}
|
|
75405
75430
|
|
|
75406
|
-
|
|
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
|
+
}
|
|
75407
77531
|
|
|
75408
77532
|
class ContentBuilder {
|
|
75409
77533
|
constructor(opts = {}) {
|
|
@@ -75644,9 +77768,11 @@ class ContentBuilder {
|
|
|
75644
77768
|
defaultEmailSnippetCategory: 14,
|
|
75645
77769
|
undoRedoStyles: false,
|
|
75646
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.
|
|
75647
|
-
// onUndo: function () { },
|
|
75648
|
-
// onRedo: function () { }
|
|
75649
77771
|
|
|
77772
|
+
// freeform
|
|
77773
|
+
onUndo: function () {},
|
|
77774
|
+
onRedo: function () {},
|
|
77775
|
+
onBlockCanvasAdd: function () {},
|
|
75650
77776
|
/*
|
|
75651
77777
|
Deprecated:
|
|
75652
77778
|
snippetSampleImage: '',
|
|
@@ -76528,6 +78654,26 @@ class ContentBuilder {
|
|
|
76528
78654
|
this.colTool.lockIndicator.style.display = '';
|
|
76529
78655
|
return ret;
|
|
76530
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
|
+
};
|
|
76531
78677
|
this.elmTool = new ElementTool(this); // Render Element Tool
|
|
76532
78678
|
|
|
76533
78679
|
// Render controls or behavior for handling element editing
|
|
@@ -76595,6 +78741,68 @@ class ContentBuilder {
|
|
|
76595
78741
|
}
|
|
76596
78742
|
*/
|
|
76597
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
|
+
});
|
|
76598
78806
|
if (this.iframe) {
|
|
76599
78807
|
this.win.addEventListener('scroll', this.doWindowScroll = () => {
|
|
76600
78808
|
this.util.hidePops();
|
|
@@ -77415,6 +79623,13 @@ class ContentBuilder {
|
|
|
77415
79623
|
this.setZoomOnControl(builder);
|
|
77416
79624
|
}
|
|
77417
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
|
+
}
|
|
77418
79633
|
const util = this.util;
|
|
77419
79634
|
const htmlutil = new HtmlUtil(this);
|
|
77420
79635
|
if (area) ; else {
|
|
@@ -77481,7 +79696,87 @@ class ContentBuilder {
|
|
|
77481
79696
|
simpleColorPicker(onPick, mode) {
|
|
77482
79697
|
return this.colorClassPicker.open(onPick, mode);
|
|
77483
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
|
+
}
|
|
77484
79778
|
destroy() {
|
|
79779
|
+
if (this.eb) this.eb.destroy();
|
|
77485
79780
|
this.doc.body.classList.remove('data-editor');
|
|
77486
79781
|
document.removeEventListener('click', this.doDocumentClick, false);
|
|
77487
79782
|
document.removeEventListener('keydown', this.doDocumentKeydown, false);
|
|
@@ -78103,7 +80398,7 @@ class ContentBuilder {
|
|
|
78103
80398
|
this.opts.onPluginsLoaded();
|
|
78104
80399
|
}
|
|
78105
80400
|
this.tooltip.setAll();
|
|
78106
|
-
new Draggable$
|
|
80401
|
+
new Draggable$2({
|
|
78107
80402
|
selector: '.is-draggable'
|
|
78108
80403
|
}); //draggable for plugins
|
|
78109
80404
|
|
|
@@ -78164,7 +80459,7 @@ class ContentBuilder {
|
|
|
78164
80459
|
this.opts.onPluginsLoaded();
|
|
78165
80460
|
}
|
|
78166
80461
|
this.tooltip.setAll();
|
|
78167
|
-
new Draggable$
|
|
80462
|
+
new Draggable$2({
|
|
78168
80463
|
selector: '.is-draggable'
|
|
78169
80464
|
}); //draggable for plugins
|
|
78170
80465
|
|
|
@@ -78320,7 +80615,7 @@ class ContentBuilder {
|
|
|
78320
80615
|
}
|
|
78321
80616
|
|
|
78322
80617
|
draggable(selector) {
|
|
78323
|
-
new Draggable$
|
|
80618
|
+
new Draggable$2({
|
|
78324
80619
|
selector: selector
|
|
78325
80620
|
});
|
|
78326
80621
|
}
|
|
@@ -78331,7 +80626,7 @@ class ContentBuilder {
|
|
|
78331
80626
|
embeddedModal = this.builderStuff.querySelector(selector);
|
|
78332
80627
|
}
|
|
78333
80628
|
this.showModal(embeddedModal, overlayStay, cancelCallback, animated, overflowHidden);
|
|
78334
|
-
new Draggable$
|
|
80629
|
+
new Draggable$2({
|
|
78335
80630
|
selector: '.is-draggable'
|
|
78336
80631
|
});
|
|
78337
80632
|
return embeddedModal;
|
|
@@ -78457,6 +80752,10 @@ class ContentBuilder {
|
|
|
78457
80752
|
// /Plugins related
|
|
78458
80753
|
|
|
78459
80754
|
viewHtml(area) {
|
|
80755
|
+
if (this.docContainer) {
|
|
80756
|
+
// freeform
|
|
80757
|
+
area = this.doc.querySelector(this.docContainer);
|
|
80758
|
+
}
|
|
78460
80759
|
const htmlutil = new HtmlUtil(this);
|
|
78461
80760
|
htmlutil.view('full', area);
|
|
78462
80761
|
}
|
|
@@ -78503,6 +80802,20 @@ class ContentBuilder {
|
|
|
78503
80802
|
return false;
|
|
78504
80803
|
}
|
|
78505
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
|
+
}
|
|
78506
80819
|
const util = this.util;
|
|
78507
80820
|
if (area) ; else {
|
|
78508
80821
|
const builders = this.doc.querySelectorAll(this.opts.container);
|
|
@@ -78561,6 +80874,7 @@ class ContentBuilder {
|
|
|
78561
80874
|
// }
|
|
78562
80875
|
loadHTML(html) {
|
|
78563
80876
|
//backward
|
|
80877
|
+
|
|
78564
80878
|
this.loadHtml(html);
|
|
78565
80879
|
}
|
|
78566
80880
|
async setUIColor(mode, csslink) {
|