@innovastudio/contentbuilder 1.5.106 → 1.5.107

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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@innovastudio/contentbuilder",
3
3
  "type": "module",
4
- "version": "1.5.106",
4
+ "version": "1.5.107",
5
5
  "description": "",
6
6
  "main": "public/contentbuilder/contentbuilder.esm.js",
7
7
  "types": "index.d.ts",
@@ -8352,3 +8352,7 @@ iframe.wait-autoplay {
8352
8352
  .hide-drag-class {
8353
8353
  opacity: 0;
8354
8354
  }
8355
+
8356
+ .drag-over-image {
8357
+ outline: #a2f0ce 3px solid;
8358
+ }
@@ -850,6 +850,14 @@ class Snippets {
850
850
  // }
851
851
 
852
852
  }
853
+
854
+
855
+ if(!(parent._cb.win.FormViewer)){
856
+ const result = snippets.filter((item)=>{
857
+ return !(item.type === 'form');
858
+ });
859
+ snippets = [...result];
860
+ }
853
861
 
854
862
 
855
863
  for (let i = 0; i <snippets.length; i++) {
@@ -18015,6 +18023,15 @@ const renderSnippetPanel = (builder, snippetOpen) => {
18015
18023
 
18016
18024
  builder.opts.snippetJSON.snippets = [...snippets];
18017
18025
  }
18026
+
18027
+ // Exclude form snippet if FormViewer not found.
18028
+ if (!builder.win.FormViewer) {
18029
+ const result = snippets.filter(item => {
18030
+ return !(item.type === 'form');
18031
+ });
18032
+ snippets = [...result];
18033
+ }
18034
+ builder.opts.snippetJSON.snippets = [...snippets];
18018
18035
  let index = 1;
18019
18036
  if (builder.opts.emailMode) {
18020
18037
  builder.opts.snippetJSON.snippets.forEach(item => {
@@ -45473,6 +45490,106 @@ var loadImageOrientation = {exports: {}};
45473
45490
 
45474
45491
  var js = loadImage.exports;
45475
45492
 
45493
+ class DragDropImageUploader {
45494
+ constructor(element, builder) {
45495
+ this.element = element;
45496
+ this.builder = builder;
45497
+ this.targetImage = null;
45498
+ this.isAttached = false;
45499
+ this._onDragOver = this._onDragOver.bind(this);
45500
+ this._onDragLeave = this._onDragLeave.bind(this);
45501
+ this._onDrop = this._onDrop.bind(this);
45502
+ }
45503
+ attach() {
45504
+ if (this.isAttached) return; // Prevent duplicate attachment
45505
+
45506
+ this.element.addEventListener('dragover', this._onDragOver);
45507
+ this.element.addEventListener('dragleave', this._onDragLeave);
45508
+ this.element.addEventListener('drop', this._onDrop);
45509
+ this.isAttached = true;
45510
+ }
45511
+ detach() {
45512
+ if (!this.isAttached) return;
45513
+ this.element.removeEventListener('dragover', this._onDragOver);
45514
+ this.element.removeEventListener('dragleave', this._onDragLeave);
45515
+ this.element.removeEventListener('drop', this._onDrop);
45516
+ this.isAttached = false;
45517
+ }
45518
+ _getImageUnderCursor(e) {
45519
+ const doc = this.element.ownerDocument || document;
45520
+ const range = doc.caretRangeFromPoint ? doc.caretRangeFromPoint(e.clientX, e.clientY) : doc.caretPositionFromPoint(e.clientX, e.clientY);
45521
+ if (!range) return null;
45522
+ const node = range.startContainer.nodeType === 1 ? range.startContainer : range.startContainer.parentElement;
45523
+ if (this.element.getAttribute('id') === 'divImageResizer') {
45524
+ return this.builder.activeImage;
45525
+ }
45526
+ return node.tagName === 'IMG' ? node : node.querySelector && node.querySelector('img');
45527
+ }
45528
+ async _onDrop(e) {
45529
+ e.preventDefault();
45530
+ if (this.targetImage) {
45531
+ this.targetImage.classList.remove('drag-over-image');
45532
+ }
45533
+ const files = e.dataTransfer.files;
45534
+ if (files && files.length > 0 && files[0].type.startsWith('image/')) {
45535
+ const file = files[0];
45536
+ const result = await this._onUpload(file);
45537
+ if (result && this.targetImage) {
45538
+ this.targetImage.setAttribute('src', result.url);
45539
+
45540
+ // finished steps:
45541
+
45542
+ // let imageProgress = document.querySelector('#divImageProgress');
45543
+ // if(imageProgress) imageProgress.style.display = 'none';
45544
+
45545
+ //Check if image is part of module snippet. If so, refresh the (active) module (hide imageTool). If not, refresh imageTool position
45546
+ this.builder.element.image.refreshIfIsModule(this.targetImage);
45547
+ this.builder.element.image.startImageMonitor(this.targetImage);
45548
+
45549
+ //Trigger Change event
45550
+ this.builder.opts.onChange();
45551
+ this.builder.elmTool.refresh();
45552
+ if (this.builder.onImageChange) this.builder.onImageChange();
45553
+ }
45554
+ }
45555
+ this.targetImage = null;
45556
+ }
45557
+ _onDragOver(e) {
45558
+ e.preventDefault();
45559
+ const img = this._getImageUnderCursor(e);
45560
+ if (img) {
45561
+ if (this.targetImage && this.targetImage !== img) {
45562
+ this.targetImage.classList.remove('drag-over-image');
45563
+ }
45564
+ this.targetImage = img;
45565
+ this.targetImage.classList.add('drag-over-image');
45566
+ }
45567
+ }
45568
+ _onDragLeave() {
45569
+ if (this.targetImage) {
45570
+ this.targetImage.classList.remove('drag-over-image');
45571
+ this.targetImage = null;
45572
+ }
45573
+ }
45574
+ _onUpload(file) {
45575
+ return new Promise(resolve => {
45576
+ this.builder.opts.onAssetUpload = url => {
45577
+ resolve({
45578
+ url: url,
45579
+ name: file.name,
45580
+ size: file.size
45581
+ });
45582
+ };
45583
+ const fakeEvent = {
45584
+ target: {
45585
+ files: [file]
45586
+ }
45587
+ };
45588
+ this.builder.opts.onImageUpload(fakeEvent);
45589
+ });
45590
+ }
45591
+ }
45592
+
45476
45593
  class Image$1 {
45477
45594
  constructor(builder) {
45478
45595
  this.builder = builder;
@@ -45514,6 +45631,15 @@ class Image$1 {
45514
45631
  this.imageTool = imageTool;
45515
45632
  imageResizer = document.querySelector('#divImageResizer');
45516
45633
  this.imageResizer = imageResizer;
45634
+
45635
+ // upload
45636
+ if (this.builder.opts.onImageUpload) {
45637
+ if (!imageResizer._dragDropUploaderAttached) {
45638
+ imageResizer._dragDropUploaderAttached = true;
45639
+ const uploader = new DragDropImageUploader(imageResizer, this.builder);
45640
+ uploader.attach();
45641
+ }
45642
+ }
45517
45643
  imageResizer.addEventListener('wheel', () => {
45518
45644
  this.hideImageResizer();
45519
45645
  }, {
@@ -45657,20 +45783,70 @@ class Image$1 {
45657
45783
 
45658
45784
  // Browse local image
45659
45785
  let elm = imageTool.querySelector('#fileEmbedImage');
45660
- dom.addEventListener(elm, 'change', e => {
45786
+ dom.addEventListener(elm, 'change', async e => {
45661
45787
  this.builder.uo.saveForUndo();
45662
45788
  var input = e.target;
45663
45789
  let img = this.builder.activeImage;
45790
+
45791
+ // content scaling
45792
+ let scale = 1;
45793
+ const contentView = document.querySelector('.is-content-view');
45794
+ if (contentView) {
45795
+ const style = window.getComputedStyle(contentView);
45796
+ const transform = style.transform;
45797
+ if (transform.startsWith('matrix(')) {
45798
+ const matrix = new DOMMatrix(transform);
45799
+ if (matrix.b === 0 && matrix.c === 0 && matrix.a === matrix.d) {
45800
+ scale = matrix.a; // only if pure scale()
45801
+ }
45802
+ }
45803
+ }
45804
+
45664
45805
  let imageProgress = builderStuff.querySelector('#divImageProgress');
45665
45806
  imageProgress.style.display = 'table';
45666
- imageProgress.style.width = img.offsetWidth * this.builder.opts.zoom + 'px';
45667
- imageProgress.style.height = img.offsetHeight * this.builder.opts.zoom + 'px';
45807
+ imageProgress.style.width = img.offsetWidth * this.builder.opts.zoom * scale + 'px';
45808
+ imageProgress.style.height = img.offsetHeight * this.builder.opts.zoom * scale + 'px';
45668
45809
  const newPos = this.builder.util.getElementPosition(img);
45669
45810
  let top = newPos.top + window.pageYOffset;
45670
45811
  let left = newPos.left + window.pageXOffset;
45671
45812
  imageProgress.style.top = top + 'px';
45672
45813
  imageProgress.style.left = left + 'px';
45673
45814
 
45815
+ // upload
45816
+ const onUpload = async e => {
45817
+ let file = e.target.files[0];
45818
+ return new Promise(resolve => {
45819
+ this.builder.opts.onAssetUpload = url => {
45820
+ resolve({
45821
+ url: url,
45822
+ name: file.name,
45823
+ size: file.size
45824
+ });
45825
+ };
45826
+ this.builder.opts.onImageUpload(e);
45827
+ });
45828
+ };
45829
+ if (this.builder.opts.onImageUpload) {
45830
+ const result = await onUpload(e);
45831
+ img.setAttribute('src', result.url);
45832
+
45833
+ // finished steps:
45834
+
45835
+ imageProgress.style.display = 'none';
45836
+ elm = imageTool.querySelector('#fileEmbedImage');
45837
+ elm.value = ''; //clear input
45838
+
45839
+ //Check if image is part of module snippet. If so, refresh the (active) module (hide imageTool). If not, refresh imageTool position
45840
+ this.refreshIfIsModule(img);
45841
+ this.startImageMonitor(img);
45842
+
45843
+ //Trigger Change event
45844
+ this.builder.opts.onChange();
45845
+ this.builder.elmTool.refresh();
45846
+ if (this.builder.onImageChange) this.builder.onImageChange();
45847
+ return;
45848
+ }
45849
+
45674
45850
  //The #fileEmbedImage triggered 2 times in IE (because of clearInputs below). This makes input.files[0].name returns error on 2nd trigger. Just add try{}!
45675
45851
  try {
45676
45852
  img.setAttribute('data-filename', input.files[0].name); //needed for saveimage.js |
@@ -46192,9 +46368,113 @@ class Image$1 {
46192
46368
 
46193
46369
  // Apply (crop) image
46194
46370
  elm = modalImageEdit.querySelector('.input-ok');
46195
- dom.addEventListener(elm, 'click', () => {
46371
+ dom.addEventListener(elm, 'click', async () => {
46196
46372
  this.builder.uo.saveForUndo();
46197
46373
  let img = this.builder.activeImage;
46374
+ if (this.builder.opts.onImageUpload) {
46375
+ let basename, extension, newname, newfilename;
46376
+ let src = img.getAttribute('src');
46377
+ if (src.indexOf('base64') === -1) {
46378
+ let filename = src.substring(src.lastIndexOf('/') + 1);
46379
+ basename = dom.baseName(filename);
46380
+ extension = filename.substr(filename.lastIndexOf('.') + 1).toLowerCase();
46381
+ } else if (img.getAttribute('data-filename')) {
46382
+ let attr = img.getAttribute('data-filename');
46383
+ basename = dom.baseName(attr);
46384
+ extension = attr.substr(attr.lastIndexOf('.') + 1).toLowerCase();
46385
+ } else {
46386
+ basename = util.makeId();
46387
+ extension = 'png';
46388
+ const match = src.match(/^data:image\/(.*?);base64,/);
46389
+ if (match) {
46390
+ extension = match[1]; // e.g., "png", "jpeg", "gif"
46391
+ }
46392
+ }
46393
+
46394
+ if (basename.indexOf('-edit') !== -1) {
46395
+ basename = basename.substr(0, basename.indexOf('-edit'));
46396
+ }
46397
+ newname = basename + '-edit' + util.makeId();
46398
+ newname = newname.replaceAll('%20', '-'); // fix 404 error after file upload
46399
+
46400
+ newfilename = newname + '.' + extension;
46401
+ let base64;
46402
+ if (extension === 'jpg' || extension === 'jpeg' || extension === 'webm' || extension === 'webp') {
46403
+ base64 = this.cropper.getCroppedCanvas({
46404
+ fillColor: '#fff',
46405
+ imageSmoothingEnabled: true,
46406
+ imageSmoothingQuality: 'high'
46407
+ }).toDataURL('image/jpeg');
46408
+ } else {
46409
+ base64 = this.cropper.getCroppedCanvas({}).toDataURL();
46410
+ }
46411
+
46412
+ // await this.builder.opts.onBase64Upload(img, base64, newfilename);
46413
+ const getMimeTypeFromFilename = filename => {
46414
+ const ext = filename.split('.').pop().toLowerCase();
46415
+ const mimeTypes = {
46416
+ jpg: 'image/jpeg',
46417
+ jpeg: 'image/jpeg',
46418
+ png: 'image/png',
46419
+ gif: 'image/gif',
46420
+ webp: 'image/webp',
46421
+ svg: 'image/svg+xml',
46422
+ pdf: 'application/pdf',
46423
+ txt: 'text/plain',
46424
+ mp3: 'audio/mpeg',
46425
+ mp4: 'video/mp4',
46426
+ mov: 'video/quicktime',
46427
+ wav: 'audio/wav',
46428
+ json: 'application/json'
46429
+ // add more as needed
46430
+ };
46431
+
46432
+ return mimeTypes[ext] || 'application/octet-stream';
46433
+ };
46434
+ const base64ToFile = (base64, filename) => {
46435
+ const mimeType = getMimeTypeFromFilename(filename);
46436
+ const byteString = atob(base64.split(',')[1]);
46437
+ const byteArray = new Uint8Array(byteString.length);
46438
+ for (let i = 0; i < byteString.length; i++) {
46439
+ byteArray[i] = byteString.charCodeAt(i);
46440
+ }
46441
+ return new File([byteArray], filename, {
46442
+ type: mimeType
46443
+ });
46444
+ };
46445
+ const onUpload = file => {
46446
+ return new Promise(resolve => {
46447
+ this.builder.opts.onAssetUpload = url => {
46448
+ resolve({
46449
+ url: url,
46450
+ name: file.name,
46451
+ size: file.size
46452
+ });
46453
+ };
46454
+ const fakeEvent = {
46455
+ target: {
46456
+ files: [file]
46457
+ }
46458
+ };
46459
+ this.builder.opts.onImageUpload(fakeEvent);
46460
+ });
46461
+ };
46462
+ const file = base64ToFile(base64, newfilename);
46463
+ const result = await onUpload(file);
46464
+ img.setAttribute('src', result.url);
46465
+
46466
+ // finished steps:
46467
+
46468
+ //Check if image is part of module snippet. If so, refresh the (active) module (hide imageTool). If not, refresh imageTool position
46469
+ this.refreshIfIsModule(img);
46470
+
46471
+ //Trigger Change event
46472
+ this.builder.opts.onChange();
46473
+ util.hideModal(modalImageEdit);
46474
+ this.builder.elmTool.refresh();
46475
+ if (this.builder.onImageChange) this.builder.onImageChange();
46476
+ return;
46477
+ }
46198
46478
  let attr = img.getAttribute('data-filename');
46199
46479
  let extension = 'jpg';
46200
46480
  if (attr) {
@@ -49942,6 +50222,9 @@ class Module {
49942
50222
  let result = await fetch(this.builder.opts.modulePath + modulename + '.html');
49943
50223
  result = await result.text();
49944
50224
  result = result.replace(/<script>/g, `${this.builder.nonce ? `<script nonce="${this.builder.nonce}">` : '<script>'}`);
50225
+
50226
+ // Replace assets path
50227
+ result = result.replace(/="assets\//g, '="' + this.builder.settings.assetPath);
49945
50228
  iframe.srcdoc = result;
49946
50229
  setTimeout(() => {
49947
50230
  iframe.style.opacity = '';
@@ -67965,7 +68248,7 @@ class Rte {
67965
68248
  });
67966
68249
 
67967
68250
  const btnInsertImageOk = modalInsertImage.querySelector('.input-ok');
67968
- dom.addEventListener(btnInsertImageOk, 'click', () => {
68251
+ dom.addEventListener(btnInsertImageOk, 'click', async () => {
67969
68252
  if (!this.builder.activeCol) {
67970
68253
  util.hideModal(modalInsertImage);
67971
68254
  return;
@@ -67981,7 +68264,76 @@ class Rte {
67981
68264
  }
67982
68265
  if (val === '') return;
67983
68266
  let fileToInsert = modalInsertImage.querySelector('#imgInsertImagePreview').getAttribute('data-filename');
67984
- util.pasteHtmlAtCaret('<img data-filename="' + fileToInsert + '" src="' + val + '" alt="" />', false);
68267
+ if (this.builder.opts.onImageUpload && val.indexOf('base64') !== -1) {
68268
+ let basename, extension, newname, newfilename;
68269
+ basename = dom.baseName(fileToInsert);
68270
+ extension = fileToInsert.substr(fileToInsert.lastIndexOf('.') + 1).toLowerCase();
68271
+ if (basename.indexOf('-edit') !== -1) {
68272
+ basename = basename.substr(0, basename.indexOf('-edit'));
68273
+ }
68274
+ newname = basename + '-edit' + util.makeId();
68275
+ newname = newname.replaceAll('%20', '-'); // fix 404 error after file upload
68276
+
68277
+ newfilename = newname + '.' + extension;
68278
+ let base64 = val;
68279
+
68280
+ // await this.builder.opts.onBase64Upload(img, base64, newfilename);
68281
+ const getMimeTypeFromFilename = filename => {
68282
+ const ext = filename.split('.').pop().toLowerCase();
68283
+ const mimeTypes = {
68284
+ jpg: 'image/jpeg',
68285
+ jpeg: 'image/jpeg',
68286
+ png: 'image/png',
68287
+ gif: 'image/gif',
68288
+ webp: 'image/webp',
68289
+ svg: 'image/svg+xml',
68290
+ pdf: 'application/pdf',
68291
+ txt: 'text/plain',
68292
+ mp3: 'audio/mpeg',
68293
+ mp4: 'video/mp4',
68294
+ mov: 'video/quicktime',
68295
+ wav: 'audio/wav',
68296
+ json: 'application/json'
68297
+ // add more as needed
68298
+ };
68299
+
68300
+ return mimeTypes[ext] || 'application/octet-stream';
68301
+ };
68302
+ const base64ToFile = (base64, filename) => {
68303
+ const mimeType = getMimeTypeFromFilename(filename);
68304
+ const byteString = atob(base64.split(',')[1]);
68305
+ const byteArray = new Uint8Array(byteString.length);
68306
+ for (let i = 0; i < byteString.length; i++) {
68307
+ byteArray[i] = byteString.charCodeAt(i);
68308
+ }
68309
+ return new File([byteArray], filename, {
68310
+ type: mimeType
68311
+ });
68312
+ };
68313
+ const onUpload = file => {
68314
+ return new Promise(resolve => {
68315
+ this.builder.opts.onAssetUpload = url => {
68316
+ resolve({
68317
+ url: url,
68318
+ name: file.name,
68319
+ size: file.size
68320
+ });
68321
+ };
68322
+ const fakeEvent = {
68323
+ target: {
68324
+ files: [file]
68325
+ }
68326
+ };
68327
+ this.builder.opts.onImageUpload(fakeEvent);
68328
+ });
68329
+ };
68330
+ const file = base64ToFile(base64, newfilename);
68331
+ const result = await onUpload(file);
68332
+ val = result.url;
68333
+ }
68334
+
68335
+ // util.pasteHtmlAtCaret('<img data-filename="' + fileToInsert + '" src="' + val + '" alt="" />', false);
68336
+ util.pasteHtmlAtCaret('<img src="' + val + '" alt="" />', false);
67985
68337
  util.hideModal(modalInsertImage);
67986
68338
  let builderActive = this.builder.doc.querySelector('.builder-active');
67987
68339
  if (builderActive) this.builder.applyBehaviorOn(builderActive);
@@ -83053,6 +83405,9 @@ class Dictation {
83053
83405
  this.modalConfig = modalConfig;
83054
83406
  const btnConfig = builderStuff.querySelector('.cmd-command-config');
83055
83407
  const btnDictation = builderStuff.querySelector('.cmd-enable-dictation');
83408
+ if (!this.builder.settings.enableDictation) {
83409
+ btnDictation.style.display = 'none';
83410
+ }
83056
83411
  const btnClear = builderStuff.querySelector('.cmd-clear-command');
83057
83412
  const chkAutoSend = builderStuff.querySelector('#chkAutoSendCommand');
83058
83413
  const btnCommandList = builderStuff.querySelector('.cmd-command-list');
@@ -92062,7 +92417,7 @@ class ContentBuilder {
92062
92417
  // Option for self-hosted fonts:
92063
92418
  // fontPath: 'assets/cssfonts/', // If set, will be used
92064
92419
 
92065
- snippetModal: false,
92420
+ snippetModal: true,
92066
92421
  snippetModalLeft: false,
92067
92422
  snippetData: 'assets/minimalist-blocks/snippetlist.html',
92068
92423
  // Deprecated
@@ -92342,7 +92697,7 @@ class ContentBuilder {
92342
92697
  maxEmbedImageWidth: 1600,
92343
92698
  //set -1 for no max (use original image width)
92344
92699
  zoom: 1,
92345
- useLightbox: false,
92700
+ useLightbox: true,
92346
92701
  lightboxArrow: true,
92347
92702
  imageRenameOnEdit: true,
92348
92703
  disableAutoEmbedVideo: false,
@@ -92731,6 +93086,7 @@ class ContentBuilder {
92731
93086
  sendCommandUrl: '',
92732
93087
  // http://localhost:8081/answer
92733
93088
  // speechTranscribeUrl: 'http://192.168.1.7:8081',
93089
+ enableDictation: false,
92734
93090
  onlineDemo: false,
92735
93091
  autoSendDelay: 4000,
92736
93092
  autoEditBlock: false,
@@ -94868,6 +95224,15 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
94868
95224
  applyBehaviorOn(builder) {
94869
95225
  const util = this.util;
94870
95226
 
95227
+ // upload
95228
+ if (this.opts.onImageUpload) {
95229
+ if (!builder._dragDropUploaderAttached) {
95230
+ builder._dragDropUploaderAttached = true;
95231
+ const uploader = new DragDropImageUploader(builder, this);
95232
+ uploader.attach();
95233
+ }
95234
+ }
95235
+
94871
95236
  //Make absolute
94872
95237
  if (this.opts.absolutePath) {
94873
95238
  let links = builder.querySelectorAll('a');