@innovastudio/contentbuilder 1.5.48 → 1.5.50
Sign up to get free protection for your applications and to get access to all the features.
package/package.json
CHANGED
@@ -3711,6 +3711,24 @@ class Dom {
|
|
3711
3711
|
constructor(builder) {
|
3712
3712
|
this.builder = builder;
|
3713
3713
|
}
|
3714
|
+
detectMobileOrTablet() {
|
3715
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
3716
|
+
const isIOS = /ipad|iphone|ipod/.test(userAgent) && !window.MSStream;
|
3717
|
+
const isAndroid = /android/.test(userAgent);
|
3718
|
+
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
|
3719
|
+
const screenWidth = window.innerWidth <= 1600;
|
3720
|
+
if (isIOS || isAndroid) {
|
3721
|
+
return true; // Definitely a mobile or tablet
|
3722
|
+
}
|
3723
|
+
|
3724
|
+
// Additional check for other touch devices with screen width under 1600px
|
3725
|
+
if (isTouchDevice && screenWidth) {
|
3726
|
+
return true; // Likely a mobile or tablet
|
3727
|
+
}
|
3728
|
+
|
3729
|
+
return false; // Likely not a mobile or tablet
|
3730
|
+
}
|
3731
|
+
|
3714
3732
|
getScale(container) {
|
3715
3733
|
let matrix = window.getComputedStyle(container).transform;
|
3716
3734
|
if (matrix === 'none') return 1;
|
@@ -17223,7 +17241,26 @@ const renderSnippetPanel = (builder, snippetOpen) => {
|
|
17223
17241
|
|
17224
17242
|
let activeBuilderArea;
|
17225
17243
|
let itemHeight;
|
17226
|
-
|
17244
|
+
const isMobile = dom.detectMobileOrTablet();
|
17245
|
+
let snippetid;
|
17246
|
+
let useClick = false;
|
17247
|
+
if (isMobile && builder.isContentBox) {
|
17248
|
+
const items = snippetlist.querySelectorAll('.snippet-item');
|
17249
|
+
items.forEach(item => {
|
17250
|
+
item.addEventListener('touchstart', () => {
|
17251
|
+
snippetid = item.getAttribute('data-id');
|
17252
|
+
}, {
|
17253
|
+
passive: false
|
17254
|
+
});
|
17255
|
+
item.addEventListener('touchend', () => {
|
17256
|
+
builder.dropSnippet(snippetid);
|
17257
|
+
}, {
|
17258
|
+
passive: false
|
17259
|
+
});
|
17260
|
+
});
|
17261
|
+
useClick = true;
|
17262
|
+
}
|
17263
|
+
if (!useClick) new Sortable(snippetlist, {
|
17227
17264
|
// forceFallback: safariAgent,
|
17228
17265
|
group: {
|
17229
17266
|
name: 'shared',
|
@@ -66679,6 +66716,7 @@ class Rte {
|
|
66679
66716
|
btnFront.forEach(btn => {
|
66680
66717
|
btn.addEventListener('click', () => {
|
66681
66718
|
let activeBlock = this.builder.doc.querySelector('.is-block.cloned');
|
66719
|
+
if (!activeBlock) activeBlock = this.builder.doc.querySelector('.is-block.active');
|
66682
66720
|
if (!activeBlock) return;
|
66683
66721
|
this.builder.forward(activeBlock);
|
66684
66722
|
});
|
@@ -66687,6 +66725,7 @@ class Rte {
|
|
66687
66725
|
btnBackward.forEach(btn => {
|
66688
66726
|
btn.addEventListener('click', () => {
|
66689
66727
|
let activeBlock = this.builder.doc.querySelector('.is-block.cloned');
|
66728
|
+
if (!activeBlock) activeBlock = this.builder.doc.querySelector('.is-block.active');
|
66690
66729
|
if (!activeBlock) return;
|
66691
66730
|
if (activeBlock.style.zIndex === '0') {
|
66692
66731
|
this.builder.moveUp(activeBlock);
|
@@ -66714,6 +66753,7 @@ class Rte {
|
|
66714
66753
|
btnDuplicate.forEach(btn => {
|
66715
66754
|
btn.addEventListener('click', () => {
|
66716
66755
|
let activeBlock = this.builder.doc.querySelector('.is-block.cloned');
|
66756
|
+
if (!activeBlock) activeBlock = this.builder.doc.querySelector('.is-block.active');
|
66717
66757
|
if (!activeBlock) return;
|
66718
66758
|
this.builder.duplicate(activeBlock);
|
66719
66759
|
});
|
@@ -83277,6 +83317,7 @@ class Draggable {
|
|
83277
83317
|
passive: false
|
83278
83318
|
});
|
83279
83319
|
this.doc.addEventListener('keydown', this.handleKeyDown);
|
83320
|
+
if (this.doc !== document) document.addEventListener('keydown', this.handleKeyDown);
|
83280
83321
|
}
|
83281
83322
|
refresh() {
|
83282
83323
|
this.elements = this.doc.querySelectorAll(this.selector);
|
@@ -83302,6 +83343,7 @@ class Draggable {
|
|
83302
83343
|
this.doc.removeEventListener('mousedown', this.handleSelect);
|
83303
83344
|
this.doc.removeEventListener('touchstart', this.handleSelect);
|
83304
83345
|
this.doc.removeEventListener('keydown', this.handleKeyDown);
|
83346
|
+
if (this.doc !== document) document.removeEventListener('keydown', this.handleKeyDown);
|
83305
83347
|
const blocks = this.doc.querySelectorAll(this.selector);
|
83306
83348
|
blocks.forEach(elm => elm.classList.remove('active'));
|
83307
83349
|
}
|
@@ -83612,14 +83654,18 @@ class Draggable {
|
|
83612
83654
|
let blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active') && elm.classList.contains('editable'));
|
83613
83655
|
if (blocks.length > 0) return;
|
83614
83656
|
if (this.onBeforeChange) this.onBeforeChange();
|
83657
|
+
let isDeleted = false;
|
83615
83658
|
blocks = Array.from(this.doc.querySelectorAll(this.selector)).filter(elm => elm.classList.contains('active'));
|
83616
83659
|
blocks.forEach(element => {
|
83617
83660
|
element.removeEventListener('mousedown', this.handleDragStart);
|
83618
83661
|
element.removeEventListener('touchstart', this.handleDragStart);
|
83619
83662
|
if (this.onDelete) this.onDelete(element);
|
83620
83663
|
element.parentNode.removeChild(element);
|
83664
|
+
isDeleted = true;
|
83621
83665
|
});
|
83622
|
-
if (this.onChange)
|
83666
|
+
if (isDeleted && this.onChange) {
|
83667
|
+
this.onChange();
|
83668
|
+
}
|
83623
83669
|
}
|
83624
83670
|
handleKeyDown(event) {
|
83625
83671
|
if (event.key === 'Delete' || event.key === 'Backspace' || event.keyCode === 46) {
|
@@ -83995,7 +84041,8 @@ class EditableBlocks {
|
|
83995
84041
|
}
|
83996
84042
|
if (block.classList.contains('is-group')) return; // do not clone if block is shape
|
83997
84043
|
|
83998
|
-
|
84044
|
+
const isMobileOrTablet = this.detectMobileOrTablet();
|
84045
|
+
if (!block.classList.contains('clone') & !isMobileOrTablet) {
|
83999
84046
|
let clonedDiv = block.cloneNode(true);
|
84000
84047
|
clonedDiv.classList.add('clone');
|
84001
84048
|
block.parentNode.appendChild(clonedDiv);
|
@@ -84003,6 +84050,24 @@ class EditableBlocks {
|
|
84003
84050
|
this.refresh();
|
84004
84051
|
}
|
84005
84052
|
}
|
84053
|
+
detectMobileOrTablet() {
|
84054
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
84055
|
+
const isIOS = /ipad|iphone|ipod/.test(userAgent) && !window.MSStream;
|
84056
|
+
const isAndroid = /android/.test(userAgent);
|
84057
|
+
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
|
84058
|
+
const screenWidth = window.innerWidth <= 1600;
|
84059
|
+
if (isIOS || isAndroid) {
|
84060
|
+
return true; // Definitely a mobile or tablet
|
84061
|
+
}
|
84062
|
+
|
84063
|
+
// Additional check for other touch devices with screen width under 1600px
|
84064
|
+
if (isTouchDevice && screenWidth) {
|
84065
|
+
return true; // Likely a mobile or tablet
|
84066
|
+
}
|
84067
|
+
|
84068
|
+
return false; // Likely not a mobile or tablet
|
84069
|
+
}
|
84070
|
+
|
84006
84071
|
selectClear() {
|
84007
84072
|
this.doc.querySelectorAll('.clone').forEach(elm => elm.parentNode.removeChild(elm));
|
84008
84073
|
this.doc.querySelectorAll('.cloned').forEach(elm => elm.classList.remove('cloned'));
|
@@ -92316,6 +92381,224 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
|
|
92316
92381
|
// return currentScript.replace(currentScriptFile, '');
|
92317
92382
|
}
|
92318
92383
|
|
92384
|
+
dropSnippet(snippetid) {
|
92385
|
+
// snippetJSON is snippet's JSON (from assets/minimalist-blocks/content.js) that store all snippets' html
|
92386
|
+
const result = this.opts.snippetJSON.snippets.filter(item => {
|
92387
|
+
if (item.id + '' === snippetid) return item;else return false;
|
92388
|
+
});
|
92389
|
+
let html = result[0].html;
|
92390
|
+
let noedit = result[0].noedit;
|
92391
|
+
let html2 = '';
|
92392
|
+
if (result[0].mode === 'canvas') {
|
92393
|
+
html2 = result[0].html2;
|
92394
|
+
if (!html2) {
|
92395
|
+
html2 = `
|
92396
|
+
<div class="row">
|
92397
|
+
<div class="column pt-0 pb-0 pl-0 pr-0 flex flex-col justify-center">
|
92398
|
+
<img src="${this.opts.snippetPath}images/img-2400x1350.png" alt="">
|
92399
|
+
</div>
|
92400
|
+
</div>
|
92401
|
+
`;
|
92402
|
+
}
|
92403
|
+
}
|
92404
|
+
let bSnippet;
|
92405
|
+
if (html.indexOf('"row') === -1) {
|
92406
|
+
bSnippet = true; // Just snippet (without row/column grid)
|
92407
|
+
} else {
|
92408
|
+
bSnippet = false; // Snippet is wrapped in row/colum
|
92409
|
+
}
|
92410
|
+
|
92411
|
+
if (this.opts.emailMode) bSnippet = false;
|
92412
|
+
|
92413
|
+
// check if is block
|
92414
|
+
let isBlock = false;
|
92415
|
+
if (html.includes('"is-block')) {
|
92416
|
+
isBlock = true;
|
92417
|
+
bSnippet = false;
|
92418
|
+
}
|
92419
|
+
|
92420
|
+
// Convert snippet into your defined 12 columns grid
|
92421
|
+
let rowClass = this.opts.row; //row
|
92422
|
+
let colClass = this.opts.cols; //['col s1', 'col s2', 'col s3', 'col s4', 'col s5', 'col s6', 'col s7', 'col s8', 'col s9', 'col s10', 'col s11', 'col s12']
|
92423
|
+
if (rowClass !== '' && colClass.length === 12) {
|
92424
|
+
// html = html.replace(new RegExp('row clearfix', 'g'), rowClass);
|
92425
|
+
html = html.replace(new RegExp('row clearfix', 'g'), 'row'); // backward
|
92426
|
+
html = html.replace(new RegExp('"row', 'g'), '"' + rowClass);
|
92427
|
+
html = html.replace(new RegExp('column full', 'g'), colClass[11]);
|
92428
|
+
html = html.replace(new RegExp('column half', 'g'), colClass[5]);
|
92429
|
+
html = html.replace(new RegExp('column third', 'g'), colClass[3]);
|
92430
|
+
html = html.replace(new RegExp('column fourth', 'g'), colClass[2]);
|
92431
|
+
html = html.replace(new RegExp('column fifth', 'g'), colClass[1]);
|
92432
|
+
html = html.replace(new RegExp('column sixth', 'g'), colClass[1]);
|
92433
|
+
html = html.replace(new RegExp('column two-third', 'g'), colClass[7]);
|
92434
|
+
html = html.replace(new RegExp('column two-fourth', 'g'), colClass[8]);
|
92435
|
+
html = html.replace(new RegExp('column two-fifth', 'g'), colClass[9]);
|
92436
|
+
html = html.replace(new RegExp('column two-sixth', 'g'), colClass[9]);
|
92437
|
+
}
|
92438
|
+
html = html.replace(/{id}/g, this.util.makeId());
|
92439
|
+
if (this.opts.onAdd) {
|
92440
|
+
html = this.opts.onAdd(html);
|
92441
|
+
}
|
92442
|
+
if (this.opts.snippetPathReplace.length > 0) {
|
92443
|
+
// try {
|
92444
|
+
if (this.opts.snippetPathReplace[0] !== '') {
|
92445
|
+
let regex = new RegExp(this.opts.snippetPathReplace[0], 'g');
|
92446
|
+
html = html.replace(regex, this.opts.snippetPathReplace[1]);
|
92447
|
+
let string1 = this.opts.snippetPathReplace[0].replace(/\//g, '%2F');
|
92448
|
+
let string2 = this.opts.snippetPathReplace[1].replace(/\//g, '%2F');
|
92449
|
+
let regex2 = new RegExp(string1, 'g');
|
92450
|
+
html = html.replace(regex2, string2);
|
92451
|
+
}
|
92452
|
+
// } catch (e) { 1; }
|
92453
|
+
}
|
92454
|
+
|
92455
|
+
// this.addSnippet(html, bSnippet, noedit);
|
92456
|
+
|
92457
|
+
if (bSnippet) {
|
92458
|
+
// Just snippet (without row/column grid), ex. buttons, line, social, video, map.
|
92459
|
+
// Can be inserted after current row, column (cell), element, or last row.
|
92460
|
+
|
92461
|
+
html = `<div class="${this.opts.row}"><div class="${this.opts.cols[this.opts.cols.length - 1]}"${noedit ? ' data-noedit' : ''}>${html}</div></div>`;
|
92462
|
+
} else if (isBlock) ; else {
|
92463
|
+
// Snippet is wrapped in row/colum (may contain custom code or has [data-html] attribute)
|
92464
|
+
// Can only be inserted after current row or last row (not on column or element).
|
92465
|
+
|
92466
|
+
let snippet = this.dom.createElement('div');
|
92467
|
+
snippet.innerHTML = html;
|
92468
|
+
let blocks = snippet.querySelectorAll('[data-html]');
|
92469
|
+
Array.prototype.forEach.call(blocks, block => {
|
92470
|
+
// Render custom code block
|
92471
|
+
html = decodeURIComponent(block.getAttribute('data-html'));
|
92472
|
+
html = html.replace(/{id}/g, this.util.makeId());
|
92473
|
+
html = html.replace(/<script>/g, `${this.nonce ? `<script nonce="${this.nonce}">` : '<script>'}`);
|
92474
|
+
for (var i = 1; i <= 20; i++) {
|
92475
|
+
html = html.replace('[%HTML' + i + '%]', block.getAttribute('data-html-' + i) === undefined ? '' : decodeURIComponent(block.getAttribute('data-html-' + i))); //render editable area
|
92476
|
+
}
|
92477
|
+
|
92478
|
+
block.innerHTML = html;
|
92479
|
+
});
|
92480
|
+
html = snippet.innerHTML;
|
92481
|
+
}
|
92482
|
+
let activeBox = this.doc.querySelector('.box-select');
|
92483
|
+
if (!activeBox) activeBox = this.activeBox;
|
92484
|
+
const activeRow = this.doc.querySelector('.row-active');
|
92485
|
+
if (activeRow) {
|
92486
|
+
if (html2) html = html2; // if it is canvas block, change it to normal using html2
|
92487
|
+
this.addRow(html, activeBox);
|
92488
|
+
} else {
|
92489
|
+
if (activeBox) {
|
92490
|
+
if (activeBox.classList.contains('box-canvas')) {
|
92491
|
+
// Canvas Mode
|
92492
|
+
|
92493
|
+
let snippet = this.dom.createElement('div');
|
92494
|
+
snippet.innerHTML = html;
|
92495
|
+
let blocks = snippet.querySelectorAll('[data-html]');
|
92496
|
+
Array.prototype.forEach.call(blocks, block => {
|
92497
|
+
// Render custom code block
|
92498
|
+
html = decodeURIComponent(block.getAttribute('data-html'));
|
92499
|
+
html = html.replace(/{id}/g, this.util.makeId());
|
92500
|
+
html = html.replace(/<script>/g, `${this.nonce ? `<script nonce="${this.nonce}">` : '<script>'}`);
|
92501
|
+
for (var i = 1; i <= 20; i++) {
|
92502
|
+
html = html.replace('[%HTML' + i + '%]', block.getAttribute('data-html-' + i) === undefined ? '' : decodeURIComponent(block.getAttribute('data-html-' + i))); //render editable area
|
92503
|
+
}
|
92504
|
+
|
92505
|
+
block.innerHTML = html;
|
92506
|
+
});
|
92507
|
+
html = snippet.innerHTML;
|
92508
|
+
this.uo.saveForUndo();
|
92509
|
+
if (isBlock) {
|
92510
|
+
this.eb.addBlock(html, activeBox);
|
92511
|
+
} else {
|
92512
|
+
const blockTemplate = `
|
92513
|
+
<div class="is-block block-steady height-auto" data-new-dummy="1" style="top: 20%; left: 20%; width: 760px;">
|
92514
|
+
<div class="is-container container-new size-18 leading-14">
|
92515
|
+
[%CONTENT%]
|
92516
|
+
</div>
|
92517
|
+
</div>
|
92518
|
+
`; // data-new-dummy will be used by onSort to apply top/left position (snippetpanel.js)
|
92519
|
+
// html = blockTemplate.replace('[%CONTENT%]', html);
|
92520
|
+
|
92521
|
+
this.eb.addBlock(blockTemplate, activeBox);
|
92522
|
+
}
|
92523
|
+
const builders = activeBox.querySelectorAll('.is-container.container-new');
|
92524
|
+
builders.forEach(builder => {
|
92525
|
+
// After snippet has been added, re-apply behavior on builder areas
|
92526
|
+
|
92527
|
+
var range = document.createRange();
|
92528
|
+
range.setStart(builder, 0);
|
92529
|
+
builder.appendChild(range.createContextualFragment(html));
|
92530
|
+
this.applyBehaviorOn(builder);
|
92531
|
+
builder.classList.remove('container-new');
|
92532
|
+
});
|
92533
|
+
this.opts.onChange();
|
92534
|
+
this.opts.onRender();
|
92535
|
+
if (this.opts.onBlockCanvasAdd) this.opts.onBlockCanvasAdd();
|
92536
|
+
} else {
|
92537
|
+
let container = activeBox.querySelector('.builder-active');
|
92538
|
+
if (container) {
|
92539
|
+
if (html2) html = html2;
|
92540
|
+
this.addRow(html, activeBox);
|
92541
|
+
} else {
|
92542
|
+
container = activeBox.querySelector('.is-container');
|
92543
|
+
if (container) {
|
92544
|
+
if (html2) html = html2;
|
92545
|
+
this.addRow(html, activeBox);
|
92546
|
+
}
|
92547
|
+
}
|
92548
|
+
}
|
92549
|
+
}
|
92550
|
+
}
|
92551
|
+
this.activeCol = null;
|
92552
|
+
}
|
92553
|
+
addRow(html, box) {
|
92554
|
+
this.uo.saveForUndo();
|
92555
|
+
let rowElement;
|
92556
|
+
let bAddLast = false;
|
92557
|
+
|
92558
|
+
// Add after selected row
|
92559
|
+
let cell = this.activeCol;
|
92560
|
+
let row;
|
92561
|
+
if (cell) {
|
92562
|
+
row = cell.parentNode; // in email mode, cell active is also under row active (incorrect, but cell active is not needed in email mode. So this line works!)
|
92563
|
+
} else {
|
92564
|
+
// If no active cell, check if it is from .row-add-initial (empty info)
|
92565
|
+
row = this.doc.querySelector('.row-active');
|
92566
|
+
if (!row) {
|
92567
|
+
bAddLast = true;
|
92568
|
+
}
|
92569
|
+
}
|
92570
|
+
// Add after last row
|
92571
|
+
if (bAddLast) {
|
92572
|
+
const container = box.querySelector('.is-builder');
|
92573
|
+
const rows = this.dom.elementChildren(container);
|
92574
|
+
const lastrow = rows[rows.length - 1];
|
92575
|
+
row = lastrow;
|
92576
|
+
}
|
92577
|
+
|
92578
|
+
// Use createContextualFragment() to make embedded script executable
|
92579
|
+
let range = document.createRange();
|
92580
|
+
row.parentNode.insertBefore(range.createContextualFragment(html), row.nextSibling);
|
92581
|
+
// rowElement = snippet.childNodes[0];
|
92582
|
+
|
92583
|
+
rowElement = row.nextElementSibling; // a must. Must be before applyBehavior to prevent element delete during fixLayout
|
92584
|
+
|
92585
|
+
// checkEmpty & onRender called here
|
92586
|
+
let builderActive = box.querySelector('.builder-active');
|
92587
|
+
if (builderActive) this.applyBehaviorOn(builderActive);else {
|
92588
|
+
builderActive = box.querySelector('.is-builder');
|
92589
|
+
if (builderActive) this.applyBehaviorOn(builderActive);
|
92590
|
+
}
|
92591
|
+
let cellElement = rowElement.querySelector('div');
|
92592
|
+
if (cellElement) cellElement.click(); //change active block to the newly created
|
92593
|
+
|
92594
|
+
// Change to row selection
|
92595
|
+
rowElement.className = rowElement.className.replace('row-outline', '');
|
92596
|
+
|
92597
|
+
//Hide Column tool (new!)
|
92598
|
+
this.util.hideColumnTool();
|
92599
|
+
this.opts.onChange();
|
92600
|
+
this.opts.onRender();
|
92601
|
+
}
|
92319
92602
|
sectionDropSetup() {
|
92320
92603
|
if (this.blockContainer) {
|
92321
92604
|
this.sortableOnCanvas = [];
|