@innovastudio/contentbox 1.6.157 → 1.6.158

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.157",
4
+ "version": "1.6.158",
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.152",
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
- elm.setAttribute('aria-hidden', true);
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(() => {
@@ -161180,8 +161189,13 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
161180
161189
 
161181
161190
  let old2 = this.settings.onChange;
161182
161191
 
161183
- this.settings.onChange = () => {
161184
- old2.call(this);
161192
+ this.settings.onChange = (...args) => {
161193
+ // Accept all arguments
161194
+ // Call original onChange with all arguments
161195
+ if (old2) old2.apply(this, args); // Use apply to pass arguments
161196
+ // Trigger auto-save
161197
+
161198
+ this.markContentChanged();
161185
161199
  setTimeout(() => {
161186
161200
  // this.quickPosTool();
161187
161201
  this.editor.livePreview.previewRefresh();
@@ -161411,16 +161425,184 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
161411
161425
  }, this);
161412
161426
  } else {
161413
161427
  initialStart();
161428
+ } // ---- AUTO-SAVE ----
161429
+ // Auto-save timing configuration
161430
+
161431
+
161432
+ this.autoSaveDelay = settings.autoSaveDelay || 3000; // Wait 3s after pause before saving
161433
+
161434
+ this.maxAutoSaveInterval = settings.maxAutoSaveInterval || 30000; // Force save every 30s during continuous editing
161435
+
161436
+ this.minAutoSaveInterval = settings.minAutoSaveInterval || 5000; // Minimum 5s between saves (rate limit)
161437
+ // Auto-save callback function
161438
+
161439
+ this.autoSave = settings.autoSave; // Auto-save state
161440
+
161441
+ this.autoSaveTimeoutId = null; // Debounce timer
161442
+
161443
+ this.maxIntervalCheckerId = null; // Background checker for max interval
161444
+
161445
+ this.previousHash = null; // Last saved content hash
161446
+
161447
+ this.lastSaveTime = 0; // Timestamp of last save
161448
+
161449
+ this.pendingChanges = false; // Flag for unsaved changes
161450
+
161451
+ this.isSaving = false; // Prevent concurrent saves
161452
+ // Start auto-save if configured
161453
+
161454
+ if (this.autoSave && typeof this.autoSave === 'function') {
161455
+ this.initAutoSave();
161414
161456
  }
161415
161457
  } // constructor
161458
+ // ---- AUTO-SAVE ----
161459
+ // Initialize auto-save system
161460
+
161461
+
161462
+ initAutoSave() {
161463
+ this.startMaxIntervalChecker();
161464
+ } // Start background checker to enforce max interval
161465
+
161466
+
161467
+ startMaxIntervalChecker() {
161468
+ this.maxIntervalCheckerId = setInterval(() => {
161469
+ // Only check if there are pending changes and not currently saving
161470
+ if (this.pendingChanges && !this.isSaving) {
161471
+ const now = Date.now();
161472
+ const timeSinceLastSave = now - this.lastSaveTime; // Force save if max interval exceeded
161473
+
161474
+ if (timeSinceLastSave >= this.maxAutoSaveInterval) {
161475
+ // console.log('Max interval reached - forcing save');
161476
+ this.performAutoSave();
161477
+ }
161478
+ }
161479
+ }, 1000); // Check every second
161480
+ } // Mark content as changed and schedule auto-save
161481
+
161482
+
161483
+ markContentChanged() {
161484
+ // Skip if auto-save not configured
161485
+ if (!this.autoSave) return; // Mark that changes exist
161486
+
161487
+ this.pendingChanges = true; // Initialize lastSaveTime on first change
161488
+
161489
+ if (this.lastSaveTime === 0) {
161490
+ this.lastSaveTime = Date.now();
161491
+ }
161492
+
161493
+ const now = Date.now();
161494
+ const timeSinceLastSave = now - this.lastSaveTime; // Clear any pending scheduled save
161495
+
161496
+ if (this.autoSaveTimeoutId) {
161497
+ clearTimeout(this.autoSaveTimeoutId);
161498
+ } // Scenario 1: Max interval reached - save immediately
161499
+
161500
+
161501
+ if (timeSinceLastSave >= this.maxAutoSaveInterval && !this.isSaving) {
161502
+ this.performAutoSave();
161503
+ } // Scenario 2: Min interval passed - schedule debounced save
161504
+ else if (timeSinceLastSave >= this.minAutoSaveInterval) {
161505
+ this.autoSaveTimeoutId = setTimeout(() => {
161506
+ this.performAutoSave();
161507
+ }, this.autoSaveDelay);
161508
+ } // Scenario 3: Too soon - schedule for later
161509
+ else {
161510
+ const delayUntilNextSave = this.minAutoSaveInterval - timeSinceLastSave;
161511
+ this.autoSaveTimeoutId = setTimeout(() => {
161512
+ if (this.pendingChanges) {
161513
+ this.performAutoSave();
161514
+ }
161515
+ }, delayUntilNextSave + this.autoSaveDelay);
161516
+ }
161517
+ } // Execute auto-save with change detection
161518
+
161519
+
161520
+ async performAutoSave() {
161521
+ // Prevent concurrent saves
161522
+ if (this.isSaving) return; // Get current content hash (lightweight check)
161523
+
161524
+ const htmlLight = this.htmlCheck();
161525
+ const currentHash = this.simpleHash(htmlLight); // Only save if content actually changed
161526
+
161527
+ if (this.previousHash !== currentHash) {
161528
+ this.isSaving = true;
161529
+
161530
+ try {
161531
+ // Call the save function
161532
+ await this.autoSave(); // console.log('Content auto-saved successfully.');
161533
+ // Update tracking state
161534
+
161535
+ this.previousHash = currentHash;
161536
+ this.lastSaveTime = Date.now();
161537
+ this.pendingChanges = false;
161538
+ } catch (error) {// console.error('Auto-save failed:', error);
161539
+ // Keep pendingChanges = true to retry later
161540
+ } finally {
161541
+ this.isSaving = false;
161542
+ }
161543
+ } else {
161544
+ // No actual changes detected
161545
+ this.pendingChanges = false;
161546
+ }
161547
+ } // Generate hash for efficient change detection
161548
+
161549
+
161550
+ simpleHash(str) {
161551
+ let hash = 0;
161552
+
161553
+ for (let i = 0; i < str.length; i++) {
161554
+ const char = str.charCodeAt(i);
161555
+ hash = (hash << 5) - hash + char; // hash * 31 + char
161556
+
161557
+ hash = hash & hash; // Convert to 32-bit integer
161558
+ }
161559
+
161560
+ return hash;
161561
+ } // Manually trigger save (useful for "Save" button)
161562
+
161563
+
161564
+ async saveNow() {
161565
+ if (this.pendingChanges && !this.isSaving) {
161566
+ await this.performAutoSave();
161567
+ }
161568
+ } //----
161416
161569
 
161417
161570
 
161418
161571
  isNewV2() {
161419
161572
  return this.wrapperEl.classList.contains('box-v2');
161420
161573
  }
161421
161574
 
161575
+ loadFonts() {
161576
+ let contentStylePath = this.settings.contentStylePath;
161577
+ const wrapper = this.wrapperEl;
161578
+ const sections = wrapper.querySelectorAll('.is-section');
161579
+ sections.forEach(section => {
161580
+ section.classList.forEach(item => {
161581
+ if (item.indexOf('type-') !== -1) {
161582
+ const contentClass = item;
161583
+ const contentCss = item + '.css'; //Add css
161584
+
161585
+ let exist = false;
161586
+ let links = this.doc.getElementsByTagName('link');
161587
+
161588
+ for (let i = 0; i < links.length; i++) {
161589
+ let src = links[i].href.toLowerCase();
161590
+ if (src.indexOf(contentCss.toLowerCase()) !== -1) exist = true;
161591
+ }
161592
+
161593
+ if (!exist) {
161594
+ this.wrapperEl.insertAdjacentHTML('beforeend', '<link data-name="contentstyle" data-class="' + contentClass + '" href="' + contentStylePath + contentCss + '" rel="stylesheet">');
161595
+ }
161596
+ }
161597
+ });
161598
+ });
161599
+ }
161600
+
161422
161601
  editorSetup() {
161423
161602
  this.editor = new ContentBuilder({
161603
+ onType: () => {
161604
+ this.markContentChanged();
161605
+ },
161424
161606
  quickAddButtons: this.settings.quickAddButtons,
161425
161607
  assetManagerBasePath: this.settings.assetManagerBasePath || '',
161426
161608
  assetAbsoluteBasePath: this.settings.assetAbsoluteBasePath || '',
@@ -161545,6 +161727,7 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
161545
161727
  sectionTemplate: this.settings.sectionTemplate,
161546
161728
  formTemplate: this.settings.formTemplate,
161547
161729
  onBlockSectionAdd: () => {
161730
+ this.loadFonts();
161548
161731
  this.pageSetup();
161549
161732
  },
161550
161733
  onBlockCanvasAdd: () => {
@@ -165314,7 +165497,23 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
165314
165497
  }
165315
165498
 
165316
165499
  destroy() {
165317
- // let html = this.html();
165500
+ // Save any pending changes before destroying
165501
+ if (this.pendingChanges && !this.isSaving) {
165502
+ this.performAutoSave();
165503
+ } // Clear debounce timer
165504
+
165505
+
165506
+ if (this.autoSaveTimeoutId) {
165507
+ clearTimeout(this.autoSaveTimeoutId);
165508
+ this.autoSaveTimeoutId = null;
165509
+ } // Clear background checker
165510
+
165511
+
165512
+ if (this.maxIntervalCheckerId) {
165513
+ clearInterval(this.maxIntervalCheckerId);
165514
+ this.maxIntervalCheckerId = null;
165515
+ }
165516
+
165318
165517
  if (this.resizeObserver) this.resizeObserver.disconnect();
165319
165518
  const elmStyleEditPanel = document.querySelector('#_style_editpanel');
165320
165519
  if (elmStyleEditPanel) elmStyleEditPanel.remove(elmStyleEditPanel);