@innovastudio/contentbuilder 1.5.48 → 1.5.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -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 = [];
|