@innovastudio/contentbox 1.6.157 → 1.6.159
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/index.d.ts
CHANGED
@@ -374,6 +374,11 @@ interface ContentBoxOptions {
|
|
374
374
|
exampleAudioUrl?: string;
|
375
375
|
saveResults?: boolean;
|
376
376
|
//---
|
377
|
+
|
378
|
+
autoSaveDelay?: number;
|
379
|
+
maxAutoSaveInterval?: number;
|
380
|
+
minAutoSaveInterval?: number;
|
381
|
+
autoSave?: () => void | Promise<void>;
|
377
382
|
}
|
378
383
|
|
379
384
|
interface OpenModalOptions {
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@innovastudio/contentbox",
|
3
3
|
"type": "module",
|
4
|
-
"version": "1.6.
|
4
|
+
"version": "1.6.159",
|
5
5
|
"description": "",
|
6
6
|
"main": "public/contentbox/contentbox.esm.js",
|
7
7
|
"types": "index.d.ts",
|
@@ -59,7 +59,7 @@
|
|
59
59
|
"ws": "^8.13.0"
|
60
60
|
},
|
61
61
|
"dependencies": {
|
62
|
-
"@innovastudio/contentbuilder": "^1.5.
|
62
|
+
"@innovastudio/contentbuilder": "^1.5.153",
|
63
63
|
"js-beautify": "^1.14.0",
|
64
64
|
"sortablejs": "^1.15.2"
|
65
65
|
}
|
@@ -1391,10 +1391,14 @@ class SideBar {
|
|
1391
1391
|
dom$l.removeClass(elm, 'active');
|
1392
1392
|
});
|
1393
1393
|
builderStuff.querySelectorAll('.is-sidebar-content.active').forEach(elm => {
|
1394
|
-
dom$l.removeClass(elm, 'active');
|
1395
|
-
|
1394
|
+
dom$l.removeClass(elm, 'active'); // elm.setAttribute('aria-hidden', true);
|
1395
|
+
|
1396
1396
|
setTimeout(() => {
|
1397
1397
|
elm.style.display = ''; //hide
|
1398
|
+
|
1399
|
+
setTimeout(() => {
|
1400
|
+
elm.setAttribute('aria-hidden', true);
|
1401
|
+
}, 50);
|
1398
1402
|
}, 300);
|
1399
1403
|
}); // this.builder.animateScroll.close();
|
1400
1404
|
}
|
@@ -126130,6 +126134,11 @@ Please obtain a license at: https://innovastudio.com/contentbox`);
|
|
126130
126134
|
this.elmTool.hide();
|
126131
126135
|
}
|
126132
126136
|
typing() {
|
126137
|
+
// Lightweight: Just mark content changed for auto-save
|
126138
|
+
if (this.opts.onType) {
|
126139
|
+
this.opts.onType();
|
126140
|
+
}
|
126141
|
+
|
126133
126142
|
// console.log('typing');
|
126134
126143
|
if (this.timeoutId) clearTimeout(this.timeoutId);
|
126135
126144
|
this.timeoutId = setTimeout(() => {
|
@@ -154625,13 +154634,27 @@ class IframePanel {
|
|
154625
154634
|
}
|
154626
154635
|
|
154627
154636
|
setScreenMode(screenMode) {
|
154628
|
-
|
154637
|
+
if (!this.builder.win) {
|
154638
|
+
// If setScreenMode called on first load
|
154639
|
+
const contentView = this.editPanel.querySelector('.is-content-view');
|
154640
|
+
contentView.classList.add(screenMode);
|
154641
|
+
|
154642
|
+
if (screenMode === 'fullview') {
|
154643
|
+
document.body.classList.add('fullview');
|
154644
|
+
} else {
|
154645
|
+
document.body.classList.remove('fullview');
|
154646
|
+
}
|
154647
|
+
|
154648
|
+
return;
|
154649
|
+
} // this.builder.doc.querySelectorAll('.is-block').forEach(block=>{
|
154629
154650
|
// block.removeAttribute('data-prev'); // reset => initial call before resize(). Or just call start();
|
154630
154651
|
// block.removeAttribute('data-fluid');
|
154631
154652
|
// block.removeAttribute('data-fluid-val');
|
154632
154653
|
// block.classList.remove('fluid');
|
154633
154654
|
// block.style.transition = '';
|
154634
154655
|
// });
|
154656
|
+
|
154657
|
+
|
154635
154658
|
if (this.builder.win.Block) {
|
154636
154659
|
this.builder.win.Block.start();
|
154637
154660
|
this.builder.win.Block.resize();
|
@@ -161180,8 +161203,13 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
|
|
161180
161203
|
|
161181
161204
|
let old2 = this.settings.onChange;
|
161182
161205
|
|
161183
|
-
this.settings.onChange = () => {
|
161184
|
-
|
161206
|
+
this.settings.onChange = (...args) => {
|
161207
|
+
// Accept all arguments
|
161208
|
+
// Call original onChange with all arguments
|
161209
|
+
if (old2) old2.apply(this, args); // Use apply to pass arguments
|
161210
|
+
// Trigger auto-save
|
161211
|
+
|
161212
|
+
this.markContentChanged();
|
161185
161213
|
setTimeout(() => {
|
161186
161214
|
// this.quickPosTool();
|
161187
161215
|
this.editor.livePreview.previewRefresh();
|
@@ -161411,16 +161439,184 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
|
|
161411
161439
|
}, this);
|
161412
161440
|
} else {
|
161413
161441
|
initialStart();
|
161442
|
+
} // ---- AUTO-SAVE ----
|
161443
|
+
// Auto-save timing configuration
|
161444
|
+
|
161445
|
+
|
161446
|
+
this.autoSaveDelay = settings.autoSaveDelay || 3000; // Wait 3s after pause before saving
|
161447
|
+
|
161448
|
+
this.maxAutoSaveInterval = settings.maxAutoSaveInterval || 30000; // Force save every 30s during continuous editing
|
161449
|
+
|
161450
|
+
this.minAutoSaveInterval = settings.minAutoSaveInterval || 5000; // Minimum 5s between saves (rate limit)
|
161451
|
+
// Auto-save callback function
|
161452
|
+
|
161453
|
+
this.autoSave = settings.autoSave; // Auto-save state
|
161454
|
+
|
161455
|
+
this.autoSaveTimeoutId = null; // Debounce timer
|
161456
|
+
|
161457
|
+
this.maxIntervalCheckerId = null; // Background checker for max interval
|
161458
|
+
|
161459
|
+
this.previousHash = null; // Last saved content hash
|
161460
|
+
|
161461
|
+
this.lastSaveTime = 0; // Timestamp of last save
|
161462
|
+
|
161463
|
+
this.pendingChanges = false; // Flag for unsaved changes
|
161464
|
+
|
161465
|
+
this.isSaving = false; // Prevent concurrent saves
|
161466
|
+
// Start auto-save if configured
|
161467
|
+
|
161468
|
+
if (this.autoSave && typeof this.autoSave === 'function') {
|
161469
|
+
this.initAutoSave();
|
161414
161470
|
}
|
161415
161471
|
} // constructor
|
161472
|
+
// ---- AUTO-SAVE ----
|
161473
|
+
// Initialize auto-save system
|
161474
|
+
|
161475
|
+
|
161476
|
+
initAutoSave() {
|
161477
|
+
this.startMaxIntervalChecker();
|
161478
|
+
} // Start background checker to enforce max interval
|
161479
|
+
|
161480
|
+
|
161481
|
+
startMaxIntervalChecker() {
|
161482
|
+
this.maxIntervalCheckerId = setInterval(() => {
|
161483
|
+
// Only check if there are pending changes and not currently saving
|
161484
|
+
if (this.pendingChanges && !this.isSaving) {
|
161485
|
+
const now = Date.now();
|
161486
|
+
const timeSinceLastSave = now - this.lastSaveTime; // Force save if max interval exceeded
|
161487
|
+
|
161488
|
+
if (timeSinceLastSave >= this.maxAutoSaveInterval) {
|
161489
|
+
// console.log('Max interval reached - forcing save');
|
161490
|
+
this.performAutoSave();
|
161491
|
+
}
|
161492
|
+
}
|
161493
|
+
}, 1000); // Check every second
|
161494
|
+
} // Mark content as changed and schedule auto-save
|
161495
|
+
|
161496
|
+
|
161497
|
+
markContentChanged() {
|
161498
|
+
// Skip if auto-save not configured
|
161499
|
+
if (!this.autoSave) return; // Mark that changes exist
|
161500
|
+
|
161501
|
+
this.pendingChanges = true; // Initialize lastSaveTime on first change
|
161502
|
+
|
161503
|
+
if (this.lastSaveTime === 0) {
|
161504
|
+
this.lastSaveTime = Date.now();
|
161505
|
+
}
|
161506
|
+
|
161507
|
+
const now = Date.now();
|
161508
|
+
const timeSinceLastSave = now - this.lastSaveTime; // Clear any pending scheduled save
|
161509
|
+
|
161510
|
+
if (this.autoSaveTimeoutId) {
|
161511
|
+
clearTimeout(this.autoSaveTimeoutId);
|
161512
|
+
} // Scenario 1: Max interval reached - save immediately
|
161513
|
+
|
161514
|
+
|
161515
|
+
if (timeSinceLastSave >= this.maxAutoSaveInterval && !this.isSaving) {
|
161516
|
+
this.performAutoSave();
|
161517
|
+
} // Scenario 2: Min interval passed - schedule debounced save
|
161518
|
+
else if (timeSinceLastSave >= this.minAutoSaveInterval) {
|
161519
|
+
this.autoSaveTimeoutId = setTimeout(() => {
|
161520
|
+
this.performAutoSave();
|
161521
|
+
}, this.autoSaveDelay);
|
161522
|
+
} // Scenario 3: Too soon - schedule for later
|
161523
|
+
else {
|
161524
|
+
const delayUntilNextSave = this.minAutoSaveInterval - timeSinceLastSave;
|
161525
|
+
this.autoSaveTimeoutId = setTimeout(() => {
|
161526
|
+
if (this.pendingChanges) {
|
161527
|
+
this.performAutoSave();
|
161528
|
+
}
|
161529
|
+
}, delayUntilNextSave + this.autoSaveDelay);
|
161530
|
+
}
|
161531
|
+
} // Execute auto-save with change detection
|
161532
|
+
|
161533
|
+
|
161534
|
+
async performAutoSave() {
|
161535
|
+
// Prevent concurrent saves
|
161536
|
+
if (this.isSaving) return; // Get current content hash (lightweight check)
|
161537
|
+
|
161538
|
+
const htmlLight = this.htmlCheck();
|
161539
|
+
const currentHash = this.simpleHash(htmlLight); // Only save if content actually changed
|
161540
|
+
|
161541
|
+
if (this.previousHash !== currentHash) {
|
161542
|
+
this.isSaving = true;
|
161543
|
+
|
161544
|
+
try {
|
161545
|
+
// Call the save function
|
161546
|
+
await this.autoSave(); // console.log('Content auto-saved successfully.');
|
161547
|
+
// Update tracking state
|
161548
|
+
|
161549
|
+
this.previousHash = currentHash;
|
161550
|
+
this.lastSaveTime = Date.now();
|
161551
|
+
this.pendingChanges = false;
|
161552
|
+
} catch (error) {// console.error('Auto-save failed:', error);
|
161553
|
+
// Keep pendingChanges = true to retry later
|
161554
|
+
} finally {
|
161555
|
+
this.isSaving = false;
|
161556
|
+
}
|
161557
|
+
} else {
|
161558
|
+
// No actual changes detected
|
161559
|
+
this.pendingChanges = false;
|
161560
|
+
}
|
161561
|
+
} // Generate hash for efficient change detection
|
161562
|
+
|
161563
|
+
|
161564
|
+
simpleHash(str) {
|
161565
|
+
let hash = 0;
|
161566
|
+
|
161567
|
+
for (let i = 0; i < str.length; i++) {
|
161568
|
+
const char = str.charCodeAt(i);
|
161569
|
+
hash = (hash << 5) - hash + char; // hash * 31 + char
|
161570
|
+
|
161571
|
+
hash = hash & hash; // Convert to 32-bit integer
|
161572
|
+
}
|
161573
|
+
|
161574
|
+
return hash;
|
161575
|
+
} // Manually trigger save (useful for "Save" button)
|
161576
|
+
|
161577
|
+
|
161578
|
+
async saveNow() {
|
161579
|
+
if (this.pendingChanges && !this.isSaving) {
|
161580
|
+
await this.performAutoSave();
|
161581
|
+
}
|
161582
|
+
} //----
|
161416
161583
|
|
161417
161584
|
|
161418
161585
|
isNewV2() {
|
161419
161586
|
return this.wrapperEl.classList.contains('box-v2');
|
161420
161587
|
}
|
161421
161588
|
|
161589
|
+
loadFonts() {
|
161590
|
+
let contentStylePath = this.settings.contentStylePath;
|
161591
|
+
const wrapper = this.wrapperEl;
|
161592
|
+
const sections = wrapper.querySelectorAll('.is-section');
|
161593
|
+
sections.forEach(section => {
|
161594
|
+
section.classList.forEach(item => {
|
161595
|
+
if (item.indexOf('type-') !== -1) {
|
161596
|
+
const contentClass = item;
|
161597
|
+
const contentCss = item + '.css'; //Add css
|
161598
|
+
|
161599
|
+
let exist = false;
|
161600
|
+
let links = this.doc.getElementsByTagName('link');
|
161601
|
+
|
161602
|
+
for (let i = 0; i < links.length; i++) {
|
161603
|
+
let src = links[i].href.toLowerCase();
|
161604
|
+
if (src.indexOf(contentCss.toLowerCase()) !== -1) exist = true;
|
161605
|
+
}
|
161606
|
+
|
161607
|
+
if (!exist) {
|
161608
|
+
this.wrapperEl.insertAdjacentHTML('beforeend', '<link data-name="contentstyle" data-class="' + contentClass + '" href="' + contentStylePath + contentCss + '" rel="stylesheet">');
|
161609
|
+
}
|
161610
|
+
}
|
161611
|
+
});
|
161612
|
+
});
|
161613
|
+
}
|
161614
|
+
|
161422
161615
|
editorSetup() {
|
161423
161616
|
this.editor = new ContentBuilder({
|
161617
|
+
onType: () => {
|
161618
|
+
this.markContentChanged();
|
161619
|
+
},
|
161424
161620
|
quickAddButtons: this.settings.quickAddButtons,
|
161425
161621
|
assetManagerBasePath: this.settings.assetManagerBasePath || '',
|
161426
161622
|
assetAbsoluteBasePath: this.settings.assetAbsoluteBasePath || '',
|
@@ -161545,6 +161741,7 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
|
|
161545
161741
|
sectionTemplate: this.settings.sectionTemplate,
|
161546
161742
|
formTemplate: this.settings.formTemplate,
|
161547
161743
|
onBlockSectionAdd: () => {
|
161744
|
+
this.loadFonts();
|
161548
161745
|
this.pageSetup();
|
161549
161746
|
},
|
161550
161747
|
onBlockCanvasAdd: () => {
|
@@ -165314,7 +165511,23 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
|
|
165314
165511
|
}
|
165315
165512
|
|
165316
165513
|
destroy() {
|
165317
|
-
//
|
165514
|
+
// Save any pending changes before destroying
|
165515
|
+
if (this.pendingChanges && !this.isSaving) {
|
165516
|
+
this.performAutoSave();
|
165517
|
+
} // Clear debounce timer
|
165518
|
+
|
165519
|
+
|
165520
|
+
if (this.autoSaveTimeoutId) {
|
165521
|
+
clearTimeout(this.autoSaveTimeoutId);
|
165522
|
+
this.autoSaveTimeoutId = null;
|
165523
|
+
} // Clear background checker
|
165524
|
+
|
165525
|
+
|
165526
|
+
if (this.maxIntervalCheckerId) {
|
165527
|
+
clearInterval(this.maxIntervalCheckerId);
|
165528
|
+
this.maxIntervalCheckerId = null;
|
165529
|
+
}
|
165530
|
+
|
165318
165531
|
if (this.resizeObserver) this.resizeObserver.disconnect();
|
165319
165532
|
const elmStyleEditPanel = document.querySelector('#_style_editpanel');
|
165320
165533
|
if (elmStyleEditPanel) elmStyleEditPanel.remove(elmStyleEditPanel);
|