@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.157",
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.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(() => {
@@ -154625,13 +154634,27 @@ class IframePanel {
154625
154634
  }
154626
154635
 
154627
154636
  setScreenMode(screenMode) {
154628
- // this.builder.doc.querySelectorAll('.is-block').forEach(block=>{
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
- old2.call(this);
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
- // let html = this.html();
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);