@innovastudio/contentbuilder 1.5.47 → 1.5.49

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
@@ -1,28 +1,233 @@
1
1
  interface ContentBuilderOptions {
2
+ page?: string;
2
3
  container?: string;
4
+ row?: string;
5
+ cols?: any[];
6
+ colequal?: any[];
7
+ colsizes?: any[];
8
+ imageQuality?: number;
9
+ elementSelection?: boolean;
10
+ paste?: string;
11
+ snippetJSON?: object;
12
+ screenMode?: string;
13
+ onPreviewOpen?: () => void;
14
+ previewURL?: string;
15
+ onPreviewClose?: () => void;
16
+ previewStyle?: string;
17
+ livePreviewOpen?: boolean;
18
+ livePreviewAlwaysReload?: boolean;
19
+ livePreviewReloadEvery?: number;
20
+ scriptPath?: string;
21
+ plugins?: any[];
22
+ pluginPath?: string;
23
+ disableConfig?: boolean;
24
+ modulePath?: string;
25
+ assetPath?: string;
26
+ fontAssetPath?: string;
27
+ fontPath?: string;
3
28
  snippetModal?: boolean;
4
29
  snippetModalLeft?: boolean;
30
+ snippetData?: string;
31
+ snippetUrl?: string;
32
+ snippetPath?: string;
33
+ snippetPathReplace?: any[];
34
+ snippetCategories?: any[];
35
+ defaultSnippetCategory?: number;
36
+ snippetHandle?: boolean;
37
+ sidePanel?: string;
38
+ snippetList?: string;
39
+ onRender?: () => void;
40
+ onContentClick?: () => void;
41
+ onChange?: () => void;
42
+ onAdd?: () => void;
43
+ largerImageHandler?: string;
44
+ onLargerImageUpload?: () => void;
45
+ imageHandler?: string;
46
+ onImageUpload?: () => void;
47
+ fileHandler?: string;
48
+ onFileUpload?: () => void;
49
+ mediaHandler?: string;
50
+ onMediaUpload?: () => void;
51
+ videoHandler?: string;
52
+ onVideoUpload?: () => void;
53
+ audioHandler?: string;
54
+ onAudioUpload?: () => void;
55
+ colors?: any[];
56
+ builderMode?: string;
57
+ rowTool?: string;
58
+ rowcolOutline?: boolean;
59
+ columnTool?: boolean;
60
+ outlineMode?: string;
61
+ toolStyle?: string;
62
+ outlineStyle?: string;
63
+ snippetAddTool?: boolean;
64
+ elementTool?: boolean;
65
+ elementHighlight?: boolean;
66
+ columnHtmlEditor?: boolean;
67
+ rowHtmlEditor?: boolean;
68
+ htmlSyntaxHighlighting?: boolean;
69
+ snippetOpen?: boolean;
70
+ toolbar?: string;
71
+ toolbarDisplay?: string;
72
+ shortenHTML?: boolean;
73
+ imageResizeOnBlock?: boolean;
74
+ simpleEditingBreakpoint?: string;
75
+ resizeHeight?: boolean;
76
+ snippetsSidebarDisplay?: string;
77
+ snippetDisplay?: string;
78
+ onImageSelectClick?: () => void;
79
+ onFileSelectClick?: () => void;
80
+ onVideoSelectClick?: () => void;
81
+ onAudioSelectClick?: () => void;
82
+ onMediaSelectClick?: () => void;
83
+ onPluginsLoaded?: () => void;
84
+ onImageBrowseClick?: () => void;
85
+ onImageSettingClick?: () => void;
86
+ onImageEditClick?: () => void;
87
+ setCropperConfig?: () => void;
88
+ imageEmbed?: boolean;
89
+ imageselect?: string;
90
+ fileselect?: string;
91
+ videoselect?: string;
92
+ imageSelect?: string;
93
+ fileSelect?: string;
94
+ videoSelect?: string;
95
+ audioSelect?: string;
96
+ mediaSelect?: string;
97
+ selectIcon?: string;
98
+ otherSelect?: string;
99
+ otherSelectCaption?: string;
100
+ otherSelectIcon?: string;
101
+ imageSelectWidth?: string;
102
+ imageSelectHeight?: string;
103
+ fileSelectWidth?: string;
104
+ fileSelectHeight?: string;
105
+ videoSelectWidth?: string;
106
+ videoSelectHeight?: string;
107
+ audioSelectWidth?: string;
108
+ audioSelectHeight?: string;
109
+ mediaSelectWidth?: string;
110
+ mediaSelectHeight?: string;
111
+ otherSelectWidth?: string;
112
+ otherSelectHeight?: string;
113
+ imageSelectMaxWidth?: string;
114
+ fileSelectMaxWidth?: string;
115
+ videoSelectMaxWidth?: string;
116
+ audioSelectMaxWidth?: string;
117
+ mediaSelectMaxWidth?: string;
118
+ otherSelectMaxWidth?: string;
119
+ assetPanelFullScreen?: boolean;
120
+ codeEditorWidth?: string;
121
+ codeEditorHeight?: string;
122
+ codeEditorMaxWidth?: string;
123
+ blockCodeEditorWidth?: string;
124
+ blockCodeEditorHeight?: string;
125
+ blockCodeEditorMaxWidth?: string;
126
+ assetRefresh?: boolean;
127
+ customTags?: any[];
128
+ buttons?: any[];
129
+ buttonsMore?: any[];
130
+ elementButtons?: any[];
131
+ elementButtonsMore?: any[];
132
+ iconButtons?: any[];
133
+ iconButtonsMore?: any[];
134
+ lang?: any[];
135
+ checkLang?: boolean;
136
+ clearPreferences?: boolean;
137
+ toolbarAddSnippetButton?: boolean;
138
+ animateModal?: boolean;
139
+ defaultFontSizes?: any[];
140
+ fontSizeClassValues?: any[];
141
+ gradientcolors?: any[];
142
+ elementEditor?: boolean;
143
+ customval?: string;
144
+ moduleConfig?: any[];
145
+ elementAnimate?: boolean;
146
+ cleanAOS?: boolean;
147
+ framework?: string;
148
+ cellFormat?: string;
149
+ rowFormat?: string;
150
+ emailMode?: boolean;
151
+ absolutePath?: boolean;
152
+ emailSnippetCategories?: any[];
153
+ defaultEmailSnippetCategory?: number;
154
+ undoRedoStyles?: boolean;
155
+ specialElementClasses?: any[];
156
+ onUndo?: () => void;
157
+ onRedo?: () => void;
158
+ onBlockCanvasAdd?: () => void;
159
+ docContainer?: string;
160
+ blockContainer?: string;
161
+ pageSize?: string;
162
+ pageSizes?: any[];
163
+ maxEmbedImageWidth?: number;
164
+ zoom?: number;
165
+ useLightbox?: boolean;
166
+ lightboxArrow?: boolean;
167
+ imageRenameOnEdit?: boolean;
168
+ disableAutoEmbedVideo?: boolean;
169
+ deleteConfirm?: boolean;
170
+ disableBootstrapIcons?: boolean;
171
+ sectionTemplate?: string;
172
+ onZoomStart?: () => void;
173
+ onZoom?: () => void;
174
+ onZoomEnd?: () => void;
175
+ themes?: any[];
176
+ colHeight?: any[];
177
+ maxColumns?: number;
178
+ leadingPreset?: any[];
179
+ cssClasses?: object;
180
+ useCssClasses?: boolean;
181
+ useButtonPlugin?: boolean;
182
+ enableDragResize?: boolean;
183
+ simpleTextSettings?: boolean;
184
+ enableColumnsPerLine?: boolean;
185
+ startAIAssistant?: boolean;
186
+ isContentBox?: boolean;
187
+ sendCommandUrl?: string;
188
+ speechTranscribeUrl?: string;
189
+ onlineDemo?: boolean;
190
+ autoSendDelay?: number;
191
+ autoEditBlock?: boolean;
192
+ disclaimerAI?: string;
193
+ showDisclaimer?: boolean;
194
+ AIModalStyle?: string;
195
+ enableShortCommands?: boolean;
196
+ speechRecognitionLang?: string;
197
+ assistantMode?: string;
198
+ triggerWords?: object;
199
+ temperature?: number;
200
+ topP?: number;
201
+ useMediaRecorder?: boolean;
202
+ encoderPath?: string;
203
+ imageAutoUpscale?: boolean;
204
+ headlineList?: any[];
205
+ mediaPath?: string;
206
+ media?: object;
207
+ shortCommandList?: object;
208
+ similarityThreshold?: number;
209
+ commandList?: object;
5
210
  }
6
211
 
7
212
  declare class ContentBuilder {
8
213
  constructor(options?: ContentBuilderOptions);
9
214
 
10
- html(element: HTMLElement): void;
11
- loadSnippets(snippetFile: string, snippetOpen: boolean): void;
215
+ html(element?: HTMLElement): void;
216
+ loadSnippets(snippetFile: string, snippetOpen?: boolean): void;
12
217
  viewSnippets(): void;
13
- saveImages(handler: string, onComplete: () => void, onBase64Upload: () => void): void;
218
+ saveImages(handler?: string, onComplete?: () => void, onBase64Upload?: () => void): void;
14
219
  applyBehavior(): void;
15
220
  applyBehaviorOn(element: HTMLElement): void;
16
221
  viewConfig(): void;
17
- setUIColor(mode: string, csslink: string): void;
222
+ setUIColor(mode: string, csslink?: string): void;
18
223
  viewHtml(): void;
19
- loadHtml(html: string, area: HTMLElement): void;
20
- pasteHtmlAtCaret(html: string, selectPastedContent: boolean): void;
21
- addSnippetl(html: string, bSnippet: boolean, noedit: boolean): void;
224
+ loadHtml(html: string, area?: HTMLElement): void;
225
+ pasteHtmlAtCaret(html: string, selectPastedContent?: boolean): void;
226
+ addSnippet(html: string, bSnippet?: boolean, noedit?: boolean): void;
22
227
  undo(): void;
23
228
  redo(): void;
24
229
  destroy(): void;
25
- returnUrl(mode: string): void;
230
+ returnUrl(s: string): void;
26
231
  toggleSnippetModal(): void;
27
232
  openSnippetModal(): void;
28
233
  closeSnippetModal(): void;
@@ -30,10 +235,10 @@ declare class ContentBuilder {
30
235
  openAIAssistant(): void;
31
236
  closeAIAssistant(): void;
32
237
  saveForUndo(): void;
33
- selectAsset(s: string, f: boolean)
34
- addBlock(html: string, blockContainer: HTMLElement)
35
- addPage(box: HTMLElement)
36
- setPageSize(s: string)
238
+ selectAsset(s: string, f?: boolean)
239
+ addBlock(html: string, blockContainer?: HTMLElement)
240
+ addPage(box?: HTMLElement)
241
+ setPageSize(s?: string)
37
242
  openPageOptions(): void;
38
243
  print(): void;
39
244
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@innovastudio/contentbuilder",
3
3
  "type": "module",
4
- "version": "1.5.47",
4
+ "version": "1.5.49",
5
5
  "description": "",
6
6
  "main": "public/contentbuilder/contentbuilder.esm.js",
7
7
  "types": "index.d.ts",
@@ -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,19 @@ const renderSnippetPanel = (builder, snippetOpen) => {
17223
17241
 
17224
17242
  let activeBuilderArea;
17225
17243
  let itemHeight;
17226
- new Sortable(snippetlist, {
17244
+ const isMobile = dom.detectMobileOrTablet();
17245
+ let useClick = false;
17246
+ if (isMobile && builder.isContentBox) {
17247
+ const items = snippetlist.querySelectorAll('.snippet-item');
17248
+ items.forEach(item => {
17249
+ item.addEventListener('click', () => {
17250
+ const snippetid = item.getAttribute('data-id');
17251
+ builder.dropSnippet(snippetid);
17252
+ });
17253
+ });
17254
+ useClick = true;
17255
+ }
17256
+ if (!useClick) new Sortable(snippetlist, {
17227
17257
  // forceFallback: safariAgent,
17228
17258
  group: {
17229
17259
  name: 'shared',
@@ -66679,6 +66709,7 @@ class Rte {
66679
66709
  btnFront.forEach(btn => {
66680
66710
  btn.addEventListener('click', () => {
66681
66711
  let activeBlock = this.builder.doc.querySelector('.is-block.cloned');
66712
+ if (!activeBlock) activeBlock = this.builder.doc.querySelector('.is-block.active');
66682
66713
  if (!activeBlock) return;
66683
66714
  this.builder.forward(activeBlock);
66684
66715
  });
@@ -66687,6 +66718,7 @@ class Rte {
66687
66718
  btnBackward.forEach(btn => {
66688
66719
  btn.addEventListener('click', () => {
66689
66720
  let activeBlock = this.builder.doc.querySelector('.is-block.cloned');
66721
+ if (!activeBlock) activeBlock = this.builder.doc.querySelector('.is-block.active');
66690
66722
  if (!activeBlock) return;
66691
66723
  if (activeBlock.style.zIndex === '0') {
66692
66724
  this.builder.moveUp(activeBlock);
@@ -66714,6 +66746,7 @@ class Rte {
66714
66746
  btnDuplicate.forEach(btn => {
66715
66747
  btn.addEventListener('click', () => {
66716
66748
  let activeBlock = this.builder.doc.querySelector('.is-block.cloned');
66749
+ if (!activeBlock) activeBlock = this.builder.doc.querySelector('.is-block.active');
66717
66750
  if (!activeBlock) return;
66718
66751
  this.builder.duplicate(activeBlock);
66719
66752
  });
@@ -83995,7 +84028,8 @@ class EditableBlocks {
83995
84028
  }
83996
84029
  if (block.classList.contains('is-group')) return; // do not clone if block is shape
83997
84030
 
83998
- if (!block.classList.contains('clone')) {
84031
+ const isMobileOrTablet = this.detectMobileOrTablet();
84032
+ if (!block.classList.contains('clone') & !isMobileOrTablet) {
83999
84033
  let clonedDiv = block.cloneNode(true);
84000
84034
  clonedDiv.classList.add('clone');
84001
84035
  block.parentNode.appendChild(clonedDiv);
@@ -84003,6 +84037,24 @@ class EditableBlocks {
84003
84037
  this.refresh();
84004
84038
  }
84005
84039
  }
84040
+ detectMobileOrTablet() {
84041
+ const userAgent = navigator.userAgent.toLowerCase();
84042
+ const isIOS = /ipad|iphone|ipod/.test(userAgent) && !window.MSStream;
84043
+ const isAndroid = /android/.test(userAgent);
84044
+ const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
84045
+ const screenWidth = window.innerWidth <= 1600;
84046
+ if (isIOS || isAndroid) {
84047
+ return true; // Definitely a mobile or tablet
84048
+ }
84049
+
84050
+ // Additional check for other touch devices with screen width under 1600px
84051
+ if (isTouchDevice && screenWidth) {
84052
+ return true; // Likely a mobile or tablet
84053
+ }
84054
+
84055
+ return false; // Likely not a mobile or tablet
84056
+ }
84057
+
84006
84058
  selectClear() {
84007
84059
  this.doc.querySelectorAll('.clone').forEach(elm => elm.parentNode.removeChild(elm));
84008
84060
  this.doc.querySelectorAll('.cloned').forEach(elm => elm.classList.remove('cloned'));
@@ -92316,6 +92368,203 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
92316
92368
  // return currentScript.replace(currentScriptFile, '');
92317
92369
  }
92318
92370
 
92371
+ dropSnippet(snippetid) {
92372
+ // snippetJSON is snippet's JSON (from assets/minimalist-blocks/content.js) that store all snippets' html
92373
+ const result = this.opts.snippetJSON.snippets.filter(item => {
92374
+ if (item.id + '' === snippetid) return item;else return false;
92375
+ });
92376
+ let html = result[0].html;
92377
+ let noedit = result[0].noedit;
92378
+ let bSnippet;
92379
+ if (html.indexOf('"row') === -1) {
92380
+ bSnippet = true; // Just snippet (without row/column grid)
92381
+ } else {
92382
+ bSnippet = false; // Snippet is wrapped in row/colum
92383
+ }
92384
+
92385
+ if (this.opts.emailMode) bSnippet = false;
92386
+
92387
+ // check if is block
92388
+ let isBlock = false;
92389
+ if (html.includes('"is-block')) {
92390
+ isBlock = true;
92391
+ bSnippet = false;
92392
+ }
92393
+
92394
+ // Convert snippet into your defined 12 columns grid
92395
+ let rowClass = this.opts.row; //row
92396
+ 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']
92397
+ if (rowClass !== '' && colClass.length === 12) {
92398
+ // html = html.replace(new RegExp('row clearfix', 'g'), rowClass);
92399
+ html = html.replace(new RegExp('row clearfix', 'g'), 'row'); // backward
92400
+ html = html.replace(new RegExp('"row', 'g'), '"' + rowClass);
92401
+ html = html.replace(new RegExp('column full', 'g'), colClass[11]);
92402
+ html = html.replace(new RegExp('column half', 'g'), colClass[5]);
92403
+ html = html.replace(new RegExp('column third', 'g'), colClass[3]);
92404
+ html = html.replace(new RegExp('column fourth', 'g'), colClass[2]);
92405
+ html = html.replace(new RegExp('column fifth', 'g'), colClass[1]);
92406
+ html = html.replace(new RegExp('column sixth', 'g'), colClass[1]);
92407
+ html = html.replace(new RegExp('column two-third', 'g'), colClass[7]);
92408
+ html = html.replace(new RegExp('column two-fourth', 'g'), colClass[8]);
92409
+ html = html.replace(new RegExp('column two-fifth', 'g'), colClass[9]);
92410
+ html = html.replace(new RegExp('column two-sixth', 'g'), colClass[9]);
92411
+ }
92412
+ html = html.replace(/{id}/g, this.util.makeId());
92413
+ if (this.opts.onAdd) {
92414
+ html = this.opts.onAdd(html);
92415
+ }
92416
+ if (this.opts.snippetPathReplace.length > 0) {
92417
+ // try {
92418
+ if (this.opts.snippetPathReplace[0] !== '') {
92419
+ let regex = new RegExp(this.opts.snippetPathReplace[0], 'g');
92420
+ html = html.replace(regex, this.opts.snippetPathReplace[1]);
92421
+ let string1 = this.opts.snippetPathReplace[0].replace(/\//g, '%2F');
92422
+ let string2 = this.opts.snippetPathReplace[1].replace(/\//g, '%2F');
92423
+ let regex2 = new RegExp(string1, 'g');
92424
+ html = html.replace(regex2, string2);
92425
+ }
92426
+ // } catch (e) { 1; }
92427
+ }
92428
+
92429
+ // this.addSnippet(html, bSnippet, noedit);
92430
+
92431
+ if (bSnippet) {
92432
+ // Just snippet (without row/column grid), ex. buttons, line, social, video, map.
92433
+ // Can be inserted after current row, column (cell), element, or last row.
92434
+
92435
+ html = `<div class="${this.opts.row}"><div class="${this.opts.cols[this.opts.cols.length - 1]}"${noedit ? ' data-noedit' : ''}>${html}</div></div>`;
92436
+ } else if (isBlock) ; else {
92437
+ // Snippet is wrapped in row/colum (may contain custom code or has [data-html] attribute)
92438
+ // Can only be inserted after current row or last row (not on column or element).
92439
+
92440
+ let snippet = this.dom.createElement('div');
92441
+ snippet.innerHTML = html;
92442
+ let blocks = snippet.querySelectorAll('[data-html]');
92443
+ Array.prototype.forEach.call(blocks, block => {
92444
+ // Render custom code block
92445
+ html = decodeURIComponent(block.getAttribute('data-html'));
92446
+ html = html.replace(/{id}/g, this.util.makeId());
92447
+ html = html.replace(/<script>/g, `${this.nonce ? `<script nonce="${this.nonce}">` : '<script>'}`);
92448
+ for (var i = 1; i <= 20; i++) {
92449
+ html = html.replace('[%HTML' + i + '%]', block.getAttribute('data-html-' + i) === undefined ? '' : decodeURIComponent(block.getAttribute('data-html-' + i))); //render editable area
92450
+ }
92451
+
92452
+ block.innerHTML = html;
92453
+ });
92454
+ html = snippet.innerHTML;
92455
+ }
92456
+ const activeBox = this.doc.querySelector('.box-select');
92457
+ const activeRow = this.doc.querySelector('.row-active');
92458
+ if (activeRow) {
92459
+ this.addRow(html, activeBox);
92460
+ } else {
92461
+ if (activeBox) {
92462
+ if (activeBox.classList.contains('box-canvas')) {
92463
+ // Canvas Mode
92464
+
92465
+ let snippet = this.dom.createElement('div');
92466
+ snippet.innerHTML = html;
92467
+ let blocks = snippet.querySelectorAll('[data-html]');
92468
+ Array.prototype.forEach.call(blocks, block => {
92469
+ // Render custom code block
92470
+ html = decodeURIComponent(block.getAttribute('data-html'));
92471
+ html = html.replace(/{id}/g, this.util.makeId());
92472
+ html = html.replace(/<script>/g, `${this.nonce ? `<script nonce="${this.nonce}">` : '<script>'}`);
92473
+ for (var i = 1; i <= 20; i++) {
92474
+ html = html.replace('[%HTML' + i + '%]', block.getAttribute('data-html-' + i) === undefined ? '' : decodeURIComponent(block.getAttribute('data-html-' + i))); //render editable area
92475
+ }
92476
+
92477
+ block.innerHTML = html;
92478
+ });
92479
+ html = snippet.innerHTML;
92480
+ const blockTemplate = `
92481
+ <div class="is-block block-steady height-auto" data-new-dummy="1" style="top: 20%; left: 20%; width: 760px;">
92482
+ <div class="is-container container-new size-18 leading-14">
92483
+ [%CONTENT%]
92484
+ </div>
92485
+ </div>
92486
+ `; // data-new-dummy will be used by onSort to apply top/left position (snippetpanel.js)
92487
+ // html = blockTemplate.replace('[%CONTENT%]', html);
92488
+
92489
+ this.uo.saveForUndo();
92490
+ this.eb.addBlock(blockTemplate, activeBox);
92491
+ const builders = activeBox.querySelectorAll('.is-container.container-new');
92492
+ builders.forEach(builder => {
92493
+ // After snippet has been added, re-apply behavior on builder areas
92494
+
92495
+ var range = document.createRange();
92496
+ range.setStart(builder, 0);
92497
+ builder.appendChild(range.createContextualFragment(html));
92498
+ this.applyBehaviorOn(builder);
92499
+ builder.classList.remove('container-new');
92500
+ });
92501
+ this.opts.onChange();
92502
+ this.opts.onRender();
92503
+ if (this.opts.onBlockCanvasAdd) this.opts.onBlockCanvasAdd();
92504
+ } else {
92505
+ let container = activeBox.querySelector('.builder-active');
92506
+ if (container) {
92507
+ this.addRow(html, activeBox);
92508
+ } else {
92509
+ container = activeBox.querySelector('.is-container');
92510
+ if (container) {
92511
+ this.addRow(html, activeBox);
92512
+ }
92513
+ }
92514
+ }
92515
+ }
92516
+ }
92517
+ this.activeCol = null;
92518
+ }
92519
+ addRow(html, box) {
92520
+ this.uo.saveForUndo();
92521
+ let rowElement;
92522
+ let bAddLast = false;
92523
+
92524
+ // Add after selected row
92525
+ let cell = this.activeCol;
92526
+ let row;
92527
+ if (cell) {
92528
+ 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!)
92529
+ } else {
92530
+ // If no active cell, check if it is from .row-add-initial (empty info)
92531
+ row = this.doc.querySelector('.row-active');
92532
+ if (!row) {
92533
+ bAddLast = true;
92534
+ }
92535
+ }
92536
+ // Add after last row
92537
+ if (bAddLast) {
92538
+ const container = box.querySelector('.is-builder');
92539
+ const rows = this.dom.elementChildren(container);
92540
+ const lastrow = rows[rows.length - 1];
92541
+ row = lastrow;
92542
+ }
92543
+
92544
+ // Use createContextualFragment() to make embedded script executable
92545
+ let range = document.createRange();
92546
+ row.parentNode.insertBefore(range.createContextualFragment(html), row.nextSibling);
92547
+ // rowElement = snippet.childNodes[0];
92548
+
92549
+ rowElement = row.nextElementSibling; // a must. Must be before applyBehavior to prevent element delete during fixLayout
92550
+
92551
+ // checkEmpty & onRender called here
92552
+ let builderActive = box.querySelector('.builder-active');
92553
+ if (builderActive) this.applyBehaviorOn(builderActive);else {
92554
+ builderActive = box.querySelector('.is-builder');
92555
+ this.applyBehaviorOn(builderActive);
92556
+ }
92557
+ let cellElement = rowElement.querySelector('div');
92558
+ if (cellElement) cellElement.click(); //change active block to the newly created
92559
+
92560
+ // Change to row selection
92561
+ rowElement.className = rowElement.className.replace('row-outline', '');
92562
+
92563
+ //Hide Column tool (new!)
92564
+ this.util.hideColumnTool();
92565
+ this.opts.onChange();
92566
+ this.opts.onRender();
92567
+ }
92319
92568
  sectionDropSetup() {
92320
92569
  if (this.blockContainer) {
92321
92570
  this.sortableOnCanvas = [];