@innovastudio/contentbuilder 1.4.124 → 1.4.125

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@innovastudio/contentbuilder",
3
3
  "type": "module",
4
- "version": "1.4.124",
4
+ "version": "1.4.125",
5
5
  "description": "",
6
6
  "main": "public/contentbuilder/contentbuilder.esm.js",
7
7
  "files": [
@@ -3592,7 +3592,7 @@ class Dom {
3592
3592
  }
3593
3593
  }
3594
3594
  let blocks = [];
3595
- const blockElms = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'pre'];
3595
+ const blockElms = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'pre', 'td', 'th'];
3596
3596
  elements.forEach(item => {
3597
3597
  const tagName = item.tagName.toLowerCase();
3598
3598
  if (blockElms.includes(tagName)) {
@@ -76867,8 +76867,10 @@ class ContentBuilder {
76867
76867
  // ON PASTE
76868
76868
  // col.addEventListener('paste', this.handleCellPaste.bind(this));
76869
76869
  col.addEventListener('paste', e => {
76870
- const clipboardData = (e.clipboardData || window.clipboardData).getData('text');
76871
- this.handleCellPaste(clipboardData);
76870
+ e.preventDefault();
76871
+ const clipboardDataText = (e.clipboardData || window.clipboardData).getData('text');
76872
+ const clipboardDataHtml = (e.clipboardData || window.clipboardData).getData('text/html');
76873
+ this.handleCellPaste(clipboardDataText, clipboardDataHtml);
76872
76874
  });
76873
76875
  col.setAttribute('data-click', true);
76874
76876
  }
@@ -79046,6 +79048,7 @@ class ContentBuilder {
79046
79048
  // CMD-B
79047
79049
 
79048
79050
  if (this.opts.useCssClasses) {
79051
+ this.uo.saveForUndo();
79049
79052
  this.dom.execCommandToggle('fontWeight', '', this.opts.cssClasses);
79050
79053
  this.opts.onChange();
79051
79054
  e.preventDefault();
@@ -79056,6 +79059,7 @@ class ContentBuilder {
79056
79059
  // CMD-I
79057
79060
 
79058
79061
  if (this.opts.useCssClasses) {
79062
+ this.uo.saveForUndo();
79059
79063
  this.dom.execCommandToggle('fontStyle', '', this.opts.cssClasses);
79060
79064
  this.opts.onChange();
79061
79065
  e.preventDefault();
@@ -79066,6 +79070,7 @@ class ContentBuilder {
79066
79070
  // CMD-U
79067
79071
 
79068
79072
  if (this.opts.useCssClasses) {
79073
+ this.uo.saveForUndo();
79069
79074
  this.dom.execCommandToggle('textUnderline', '', this.opts.cssClasses);
79070
79075
  this.opts.onChange();
79071
79076
  e.preventDefault();
@@ -79076,6 +79081,7 @@ class ContentBuilder {
79076
79081
  // CMD-S
79077
79082
 
79078
79083
  if (this.opts.useCssClasses) {
79084
+ this.uo.saveForUndo();
79079
79085
  this.dom.execCommandToggle('textLinethrough', '', this.opts.cssClasses);
79080
79086
  this.opts.onChange();
79081
79087
  e.preventDefault();
@@ -79083,6 +79089,8 @@ class ContentBuilder {
79083
79089
  }
79084
79090
  }
79085
79091
  if (isCmd && e.which === 221) {
79092
+ this.uo.saveForUndo();
79093
+
79086
79094
  // CMD-]
79087
79095
  e.preventDefault();
79088
79096
  document.execCommand('indent', false, null);
@@ -79091,6 +79099,8 @@ class ContentBuilder {
79091
79099
  markSpan();
79092
79100
  }
79093
79101
  if (isCmd && e.which === 219) {
79102
+ this.uo.saveForUndo();
79103
+
79094
79104
  // CMD-]
79095
79105
  e.preventDefault();
79096
79106
  document.execCommand('outdent', false, null);
@@ -79322,307 +79332,288 @@ class ContentBuilder {
79322
79332
  this.opts.onChange();
79323
79333
  }, 2000);
79324
79334
  }
79325
- handleCellPaste(clipboardData) {
79335
+ handleCellPaste(clipboardData, clipboardDataHtml) {
79326
79336
  this.uo.saveForUndo();
79327
79337
  const util = this.util;
79328
79338
  util.saveSelection(); //required. Without this, CTRL-A (select element) & CTRL-V won't replace the element, but will paste at the end of the element.
79329
79339
 
79330
- let contentword = this.doc.querySelector('#idContentWord');
79331
- if (contentword) contentword.parentNode.removeChild(contentword);
79332
- var el;
79333
- var curr;
79334
- if (this.win.getSelection) {
79335
- curr = this.win.getSelection().getRangeAt(0).commonAncestorContainer;
79336
- if (curr.nodeType === 3) {
79337
- //ini text node
79338
- el = curr.parentNode;
79339
- } else {
79340
- el = curr;
79341
- }
79342
- } else if (this.doc.selection) {
79343
- curr = this.doc.selection.createRange();
79344
- el = this.doc.selection.createRange().parentElement();
79345
- }
79346
- var tmptop = el.getBoundingClientRect().top + this.win.pageYOffset;
79347
- const html = '<div style="position:absolute;z-index:-1000;top:' + tmptop + 'px;left:-1000px;width:100px;height:100px;overflow:auto;" name="idContentWord" id="idContentWord" contenteditable="true"></div>';
79348
- if (!this.iframe) {
79349
- this.dom.appendHtml(this.builderStuff, html);
79350
- } else {
79351
- this.dom.appendHtml(this.contentStuff, html);
79352
- }
79353
- contentword = this.doc.querySelector('#idContentWord');
79354
- contentword.focus();
79355
- setTimeout(() => {
79356
- try {
79357
- var sPastedText = '';
79358
- let contentword = this.doc.querySelector('#idContentWord');
79359
-
79360
- //Check video embed
79361
- var bPasteObject = false;
79362
- var src = contentword.innerText;
79363
- if (!this.opts.disableAutoEmbedVideo) {
79364
- //var youRegex = /^http[s]?:\/\/(((www.youtube.com\/watch\?(feature=player_detailpage&)?)v=)|(youtu.be\/))([^#\&\?]*)/;
79365
- var youRegex = /^http[s]?:\/\/(((www.youtube.com\/watch\?(feature=player_detailpage&)?)v=)|(youtu.be\/))([^#&?]*)/;
79366
- var vimeoRegex = /^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/)|(video\/))?([0-9]+)\/?/;
79367
- var youRegexMatches = youRegex.exec(src);
79368
- var vimeoRegexMatches = vimeoRegex.exec(src);
79369
- if (youRegexMatches !== null || vimeoRegexMatches !== null) {
79370
- if (youRegexMatches !== null && youRegexMatches.length >= 7) {
79371
- var youMatch = youRegexMatches[6];
79372
- src = 'https://www.youtube.com/embed/' + youMatch + '?rel=0';
79373
- }
79374
- if (vimeoRegexMatches !== null && vimeoRegexMatches.length >= 7) {
79375
- var vimeoMatch = vimeoRegexMatches[6];
79376
- src = 'https://player.vimeo.com/video/' + vimeoMatch;
79377
- }
79378
- sPastedText = '<div class="embed-responsive embed-responsive-16by9"><iframe tabindex="0" width="560" height="315" src="' + src + '" frameborder="0" allowfullscreen=""></iframe></div>';
79379
- bPasteObject = true;
79340
+ // Create a temporary div to hold the pasted HTML
79341
+ let contentword = document.createElement('div');
79342
+ contentword.innerHTML = clipboardDataHtml;
79343
+ try {
79344
+ var sPastedText = '';
79345
+
79346
+ //Check video embed
79347
+ var bPasteObject = false;
79348
+ var src = contentword.innerText;
79349
+ if (!this.opts.disableAutoEmbedVideo) {
79350
+ //var youRegex = /^http[s]?:\/\/(((www.youtube.com\/watch\?(feature=player_detailpage&)?)v=)|(youtu.be\/))([^#\&\?]*)/;
79351
+ var youRegex = /^http[s]?:\/\/(((www.youtube.com\/watch\?(feature=player_detailpage&)?)v=)|(youtu.be\/))([^#&?]*)/;
79352
+ var vimeoRegex = /^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/)|(video\/))?([0-9]+)\/?/;
79353
+ var youRegexMatches = youRegex.exec(src);
79354
+ var vimeoRegexMatches = vimeoRegex.exec(src);
79355
+ if (youRegexMatches !== null || vimeoRegexMatches !== null) {
79356
+ if (youRegexMatches !== null && youRegexMatches.length >= 7) {
79357
+ var youMatch = youRegexMatches[6];
79358
+ src = 'https://www.youtube.com/embed/' + youMatch + '?rel=0';
79359
+ }
79360
+ if (vimeoRegexMatches !== null && vimeoRegexMatches.length >= 7) {
79361
+ var vimeoMatch = vimeoRegexMatches[6];
79362
+ src = 'https://player.vimeo.com/video/' + vimeoMatch;
79380
79363
  }
79364
+ sPastedText = '<div class="embed-responsive embed-responsive-16by9"><iframe tabindex="0" width="560" height="315" src="' + src + '" frameborder="0" allowfullscreen=""></iframe></div>';
79365
+ bPasteObject = true;
79381
79366
  }
79382
- if (!bPasteObject) {
79383
- if (this.opts.paste === 'text') {
79384
- /*
79385
- let elms = contentword.querySelectorAll('p,h1,h2,h3,h4,h5,h6');
79386
- Array.prototype.forEach.call(elms, (elm) => {
79387
- elm.innerHTML = elm.innerHTML + ' '; //add space (&nbsp;)
79388
- });
79389
- // sPastedText = contentword.innerText;
79390
- sPastedText = contentword.innerHTML;
79391
- sPastedText = sPastedText.replace(/(<([^>]+)>)/ig,'<br>');
79392
- sPastedText = sPastedText.replace(/(<br\s*\/?>){3,}/gi, '<br>');
79393
- if(sPastedText.indexOf('<br>')===0) {
79394
- sPastedText = sPastedText.substring(4);
79395
- }
79396
- if(sPastedText.substring(sPastedText.length-4)==='<br>'){
79397
- sPastedText = sPastedText.substring(0, sPastedText.length-4);
79398
- }
79399
- sPastedText = sPastedText.trim();
79400
- */
79367
+ }
79368
+ if (!bPasteObject) {
79369
+ if (this.opts.paste === 'text') {
79370
+ /*
79371
+ let elms = contentword.querySelectorAll('p,h1,h2,h3,h4,h5,h6');
79372
+ Array.prototype.forEach.call(elms, (elm) => {
79373
+ elm.innerHTML = elm.innerHTML + ' '; //add space (&nbsp;)
79374
+ });
79375
+ // sPastedText = contentword.innerText;
79376
+ sPastedText = contentword.innerHTML;
79377
+ sPastedText = sPastedText.replace(/(<([^>]+)>)/ig,'<br>');
79378
+ sPastedText = sPastedText.replace(/(<br\s*\/?>){3,}/gi, '<br>');
79379
+ if(sPastedText.indexOf('<br>')===0) {
79380
+ sPastedText = sPastedText.substring(4);
79381
+ }
79382
+ if(sPastedText.substring(sPastedText.length-4)==='<br>'){
79383
+ sPastedText = sPastedText.substring(0, sPastedText.length-4);
79384
+ }
79385
+ sPastedText = sPastedText.trim();
79386
+ */
79401
79387
 
79402
- sPastedText = clipboardData;
79403
- // sPastedText = sPastedText.replace(/(?:\r\n|\r|\n)/g, '<br>');
79388
+ sPastedText = clipboardData;
79389
+ // sPastedText = sPastedText.replace(/(?:\r\n|\r|\n)/g, '<br>');
79390
+ } else {
79391
+ sPastedText = contentword.innerHTML;
79392
+ if (this.opts.paste === 'html') {
79393
+ //with styles
79394
+ sPastedText = util.cleanHTML(sPastedText, false);
79404
79395
  } else {
79405
- sPastedText = contentword.innerHTML;
79406
- if (this.opts.paste === 'html') {
79407
- //with styles
79408
- sPastedText = util.cleanHTML(sPastedText, false);
79409
- } else {
79410
- //html-without-styles (default)
79411
- sPastedText = util.cleanHTML(sPastedText, true);
79412
- }
79413
- contentword.innerHTML = sPastedText;
79414
-
79415
- /*
79416
- // remove attributes
79417
- if(this.opts.paste === 'html'){//with styles
79418
- let elms = contentword.querySelectorAll('*');
79419
- Array.prototype.forEach.call(elms, (elm) => {
79420
- for(let n = 0;n<elm.attributes.length;n++) {
79421
- if(elm.attributes[n].name!=='style') elm.removeAttribute(elm.attributes[n].name);
79422
- }
79423
- });
79424
- } else { //html-without-styles (default)
79425
-
79426
- const removeAttributes = (element) => {
79427
- while (element.attributes.length > 0) {
79428
- element.removeAttribute(element.attributes[0].name);
79429
- }
79430
- };
79431
- let elms = contentword.querySelectorAll('*');
79432
- Array.prototype.forEach.call(elms, (elm) => {
79433
- removeAttributes(elm);
79434
- });
79435
- }
79436
- */
79437
-
79438
- /*
79439
- Additional Cleanup:
79440
- - Remove p inside li
79441
- - Remove li with white-space: pre
79442
- */
79443
- let elms = contentword.querySelectorAll('li');
79444
- Array.prototype.forEach.call(elms, elm => {
79445
- elm.style.whiteSpace = '';
79446
- const childNodes = elm.childNodes;
79447
- let i = childNodes.length;
79448
- while (i--) {
79449
- if (childNodes[i].tagName === 'P') {
79450
- childNodes[i].outerHTML = childNodes[i].innerHTML;
79451
- }
79452
- }
79453
- });
79454
-
79455
- // NOTE: paste <h1><p> jadi nempel
79456
-
79457
- // // Source: https://gist.github.com/sbrin/6801034
79458
- // jQuery('p', $editor).each(function(){
79459
- // var str = jQuery(this).attr('style');
79460
- // var matches = /mso-list:\w+ \w+([0-9]+)/.exec(str);
79461
- // if (matches) {
79462
- // jQuery(this).data('_listLevel', parseInt(matches[1], 10));
79463
- // }
79464
- // });
79465
- // var last_level=0;
79466
- // var pnt = null;
79467
- // jQuery('p', $editor).each(function(){
79468
- // var cur_level = jQuery(this).data('_listLevel');
79469
- // if(cur_level !== undefined){
79470
- // var txt = jQuery(this).text();
79471
- // var list_tag = '<ul></ul>';
79472
- // if (/^\s*\w+\./.test(txt)) {
79473
- // var matches = /([0-9])\./.exec(txt);
79474
- // if (matches) {
79475
- // var start = parseInt(matches[1], 10);
79476
- // list_tag = start>1 ? '<ol start="' + start + '"></ol>' : '<ol></ol>';
79477
- // }else{
79478
- // list_tag = '<ol></ol>';
79479
- // }
79480
- // }
79481
-
79482
- // if(cur_level>last_level){
79483
- // if(last_level===0){
79484
- // jQuery(this).before(list_tag);
79485
- // pnt = jQuery(this).prev();
79486
- // }else{
79487
- // pnt = jQuery(list_tag).appendTo(pnt);
79488
- // }
79489
- // }
79490
- // if(cur_level<last_level){
79491
- // for(var i=0; i<last_level-cur_level; i++){
79492
- // pnt = pnt.parent();
79493
- // }
79494
- // }
79495
- // jQuery('span:first', this).remove();
79496
- // pnt.append('<li>' + jQuery(this).html() + '</li>');
79497
- // jQuery(this).remove();
79498
- // last_level = cur_level;
79499
- // }else{
79500
- // last_level = 0;
79501
- // }
79502
- // });
79503
- // //jQuery('[style]', $editor).removeAttr('style'); //done (see cleanHTML)
79504
- // jQuery('[align]', $editor).removeAttr('align');
79505
- // //jQuery('span', $editor).replaceWith(function() {return jQuery(this).contents();}); //done (see cleanHTML)
79506
- // jQuery('span:empty', $editor).remove();
79507
- // //jQuery("[class^='Mso']", $editor).removeAttr('class'); //done (see cleanHTML)
79508
- // jQuery('p:empty', $editor).remove();
79509
-
79510
- sPastedText = contentword.innerHTML;
79396
+ //html-without-styles (default)
79397
+ sPastedText = util.cleanHTML(sPastedText, true);
79511
79398
  }
79512
- }
79513
- contentword = this.doc.querySelector('#idContentWord');
79514
- if (contentword) contentword.parentNode.removeChild(contentword);
79515
- util.restoreSelection();
79516
- var oSel = this.win.getSelection();
79517
- var range = oSel.getRangeAt(0);
79518
- range.extractContents();
79519
- range.collapse(true);
79520
- var docFrag = range.createContextualFragment(sPastedText);
79521
- var lastNode = docFrag.lastChild;
79522
- range.insertNode(docFrag);
79523
- if (this.activeCol) {
79399
+ contentword.innerHTML = sPastedText;
79400
+
79524
79401
  /*
79525
- Additional Cleanup:
79526
- - Remove empty elements (empty p, etc)
79402
+ // remove attributes
79403
+ if(this.opts.paste === 'html'){//with styles
79404
+ let elms = contentword.querySelectorAll('*');
79405
+ Array.prototype.forEach.call(elms, (elm) => {
79406
+ for(let n = 0;n<elm.attributes.length;n++) {
79407
+ if(elm.attributes[n].name!=='style') elm.removeAttribute(elm.attributes[n].name);
79408
+ }
79409
+ });
79410
+ } else { //html-without-styles (default)
79411
+
79412
+ const removeAttributes = (element) => {
79413
+ while (element.attributes.length > 0) {
79414
+ element.removeAttribute(element.attributes[0].name);
79415
+ }
79416
+ };
79417
+ let elms = contentword.querySelectorAll('*');
79418
+ Array.prototype.forEach.call(elms, (elm) => {
79419
+ removeAttributes(elm);
79420
+ });
79421
+ }
79527
79422
  */
79528
- // this.activeCol.find('h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty,p:empty').remove();
79529
- // this.activeCol.querySelectorAll('*:empty').forEach((x)=>{x.remove();}); // Makes <img> removed
79530
- this.activeCol.querySelectorAll('h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty,p:empty').forEach(x => {
79531
- x.remove();
79532
- });
79533
79423
 
79534
79424
  /*
79535
79425
  Additional Cleanup:
79536
- Fix HTML structure. The problem:
79537
- <p class="elm-active">
79538
- ...Sometimes h1, h2, p can be pasted here..
79539
- </p>
79426
+ - Remove p inside li
79427
+ - Remove li with white-space: pre
79540
79428
  */
79541
- let elmActive = this.activeCol.querySelector('p.elm-active,h1.elm-active,h2.elm-active,h3.elm-active,h4.elm-active,h5.elm-active,h6.elm-active');
79542
- if (elmActive) {
79543
- let elms = elmActive.querySelectorAll('p,h1,h2,h3,h4,h5,h6');
79544
- if (elms.length > 0) {
79545
- let elmClosestElement = elmActive.nextElementSibling;
79546
-
79547
- //Fix text that doesn't have paragraph
79548
- let textNodes = Array.from(elmActive.childNodes).filter(node => node.nodeType === 3 && node.textContent.trim().length > 1);
79549
- textNodes.forEach(node => {
79550
- const span = document.createElement('p');
79551
- node.after(span);
79552
- span.appendChild(node);
79553
- });
79554
- if (elmActive.firstElementChild && elmActive.childNodes.length === 1) {
79555
- if (elmActive.firstElementChild.tagName === 'SPAN') {
79556
- // Paste HTML with styles
79429
+ let elms = contentword.querySelectorAll('li');
79430
+ Array.prototype.forEach.call(elms, elm => {
79431
+ elm.style.whiteSpace = '';
79432
+ const childNodes = elm.childNodes;
79433
+ let i = childNodes.length;
79434
+ while (i--) {
79435
+ if (childNodes[i].tagName === 'P') {
79436
+ childNodes[i].outerHTML = childNodes[i].innerHTML;
79437
+ }
79438
+ }
79439
+ });
79557
79440
 
79558
- elmActive.outerHTML = elmActive.firstElementChild.innerHTML; //fix
79441
+ // NOTE: paste <h1><p> jadi nempel
79559
79442
 
79560
- // Re-clean empty elements
79561
- this.activeCol.querySelectorAll('*:empty').forEach(x => {
79562
- x.remove();
79563
- });
79443
+ // // Source: https://gist.github.com/sbrin/6801034
79444
+ // jQuery('p', $editor).each(function(){
79445
+ // var str = jQuery(this).attr('style');
79446
+ // var matches = /mso-list:\w+ \w+([0-9]+)/.exec(str);
79447
+ // if (matches) {
79448
+ // jQuery(this).data('_listLevel', parseInt(matches[1], 10));
79449
+ // }
79450
+ // });
79451
+ // var last_level=0;
79452
+ // var pnt = null;
79453
+ // jQuery('p', $editor).each(function(){
79454
+ // var cur_level = jQuery(this).data('_listLevel');
79455
+ // if(cur_level !== undefined){
79456
+ // var txt = jQuery(this).text();
79457
+ // var list_tag = '<ul></ul>';
79458
+ // if (/^\s*\w+\./.test(txt)) {
79459
+ // var matches = /([0-9])\./.exec(txt);
79460
+ // if (matches) {
79461
+ // var start = parseInt(matches[1], 10);
79462
+ // list_tag = start>1 ? '<ol start="' + start + '"></ol>' : '<ol></ol>';
79463
+ // }else{
79464
+ // list_tag = '<ol></ol>';
79465
+ // }
79466
+ // }
79467
+
79468
+ // if(cur_level>last_level){
79469
+ // if(last_level===0){
79470
+ // jQuery(this).before(list_tag);
79471
+ // pnt = jQuery(this).prev();
79472
+ // }else{
79473
+ // pnt = jQuery(list_tag).appendTo(pnt);
79474
+ // }
79475
+ // }
79476
+ // if(cur_level<last_level){
79477
+ // for(var i=0; i<last_level-cur_level; i++){
79478
+ // pnt = pnt.parent();
79479
+ // }
79480
+ // }
79481
+ // jQuery('span:first', this).remove();
79482
+ // pnt.append('<li>' + jQuery(this).html() + '</li>');
79483
+ // jQuery(this).remove();
79484
+ // last_level = cur_level;
79485
+ // }else{
79486
+ // last_level = 0;
79487
+ // }
79488
+ // });
79489
+ // //jQuery('[style]', $editor).removeAttr('style'); //done (see cleanHTML)
79490
+ // jQuery('[align]', $editor).removeAttr('align');
79491
+ // //jQuery('span', $editor).replaceWith(function() {return jQuery(this).contents();}); //done (see cleanHTML)
79492
+ // jQuery('span:empty', $editor).remove();
79493
+ // //jQuery("[class^='Mso']", $editor).removeAttr('class'); //done (see cleanHTML)
79494
+ // jQuery('p:empty', $editor).remove();
79564
79495
 
79565
- //place cursor
79566
- if (elmClosestElement) this.dom.moveCursorToElement(elmClosestElement.previousElementSibling);else this.dom.moveCursorToElement(this.activeCol);
79567
- let builderActive = this.doc.querySelector('.builder-active');
79568
- if (builderActive) this.applyBehaviorOn(builderActive);
79496
+ sPastedText = contentword.innerHTML;
79497
+ }
79498
+ }
79499
+ contentword = this.doc.querySelector('#idContentWord');
79500
+ if (contentword) contentword.parentNode.removeChild(contentword);
79501
+ util.restoreSelection();
79569
79502
 
79570
- //Trigger Change event
79571
- this.opts.onChange();
79503
+ /*
79504
+ var oSel = this.win.getSelection();
79505
+ var range = oSel.getRangeAt(0);
79506
+ range.extractContents();
79507
+ range.collapse(true);
79508
+ var docFrag = range.createContextualFragment(sPastedText);
79509
+ var lastNode = docFrag.lastChild;
79510
+ range.insertNode(docFrag);
79511
+ */
79512
+ document.execCommand('insertHTML', false, sPastedText);
79513
+ if (this.activeCol) {
79514
+ /*
79515
+ Additional Cleanup:
79516
+ - Remove empty elements (empty p, etc)
79517
+ */
79518
+ // this.activeCol.find('h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty,p:empty').remove();
79519
+ // this.activeCol.querySelectorAll('*:empty').forEach((x)=>{x.remove();}); // Makes <img> removed
79520
+ this.activeCol.querySelectorAll('h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty,p:empty').forEach(x => {
79521
+ x.remove();
79522
+ });
79572
79523
 
79573
- //Trigger Render event
79574
- this.opts.onRender();
79575
- return;
79576
- }
79577
- }
79524
+ /*
79525
+ Additional Cleanup:
79526
+ Fix HTML structure. The problem:
79527
+ <p class="elm-active">
79528
+ ...Sometimes h1, h2, p can be pasted here..
79529
+ </p>
79530
+ */
79531
+ let elmActive = this.activeCol.querySelector('p.elm-active,h1.elm-active,h2.elm-active,h3.elm-active,h4.elm-active,h5.elm-active,h6.elm-active');
79532
+ if (elmActive) {
79533
+ let elms = elmActive.querySelectorAll('p,h1,h2,h3,h4,h5,h6');
79534
+ if (elms.length > 0) {
79535
+ let elmClosestElement = elmActive.nextElementSibling;
79536
+
79537
+ //Fix text that doesn't have paragraph
79538
+ let textNodes = Array.from(elmActive.childNodes).filter(node => node.nodeType === 3 && node.textContent.trim().length > 1);
79539
+ textNodes.forEach(node => {
79540
+ const span = document.createElement('p');
79541
+ node.after(span);
79542
+ span.appendChild(node);
79543
+ });
79544
+ if (elmActive.firstElementChild && elmActive.childNodes.length === 1) {
79545
+ if (elmActive.firstElementChild.tagName === 'SPAN') {
79546
+ // Paste HTML with styles
79578
79547
 
79579
- // Paste HTML without styles
79580
- elmActive.outerHTML = elmActive.innerHTML; //fix
79548
+ elmActive.outerHTML = elmActive.firstElementChild.innerHTML; //fix
79581
79549
 
79582
- // Re-clean empty elements
79583
- // this.activeCol.querySelectorAll('*:empty').forEach((x)=>{x.remove();}); // Makes <img> removed
79584
- this.activeCol.find('h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty,p:empty').remove();
79550
+ // Re-clean empty elements
79551
+ this.activeCol.querySelectorAll('*:empty').forEach(x => {
79552
+ x.remove();
79553
+ });
79585
79554
 
79586
- //place cursor
79587
- if (elmClosestElement) this.dom.moveCursorToElement(elmClosestElement.previousElementSibling);else this.dom.moveCursorToElement(this.activeCol);
79588
- let builderActive = this.doc.querySelector('.builder-active');
79589
- if (builderActive) this.applyBehaviorOn(builderActive);
79555
+ //place cursor
79556
+ if (elmClosestElement) this.dom.moveCursorToElement(elmClosestElement.previousElementSibling);else this.dom.moveCursorToElement(this.activeCol);
79557
+ let builderActive = this.doc.querySelector('.builder-active');
79558
+ if (builderActive) this.applyBehaviorOn(builderActive);
79590
79559
 
79591
- //Trigger Change event
79592
- this.opts.onChange();
79560
+ //Trigger Change event
79561
+ this.opts.onChange();
79593
79562
 
79594
- //Trigger Render event
79595
- this.opts.onRender();
79596
- return;
79563
+ //Trigger Render event
79564
+ this.opts.onRender();
79565
+ return;
79566
+ }
79597
79567
  }
79568
+
79569
+ // Paste HTML without styles
79570
+ elmActive.outerHTML = elmActive.innerHTML; //fix
79571
+
79572
+ // Re-clean empty elements
79573
+ // this.activeCol.querySelectorAll('*:empty').forEach((x)=>{x.remove();}); // Makes <img> removed
79574
+ this.activeCol.find('h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty,p:empty').remove();
79575
+
79576
+ //place cursor
79577
+ if (elmClosestElement) this.dom.moveCursorToElement(elmClosestElement.previousElementSibling);else this.dom.moveCursorToElement(this.activeCol);
79578
+ let builderActive = this.doc.querySelector('.builder-active');
79579
+ if (builderActive) this.applyBehaviorOn(builderActive);
79580
+
79581
+ //Trigger Change event
79582
+ this.opts.onChange();
79583
+
79584
+ //Trigger Render event
79585
+ this.opts.onRender();
79586
+ return;
79598
79587
  }
79599
79588
  }
79600
- range.setStartAfter(lastNode);
79601
- range.setEndAfter(lastNode);
79602
- range.collapse(false);
79603
- var comCon = range.commonAncestorContainer;
79604
- if (comCon && comCon.parentNode) {
79605
- try {
79606
- comCon.parentNode.normalize();
79607
- } catch (e) {
79608
- // Do Nothing
79589
+ }
79590
+
79591
+ /*
79592
+ range.setStartAfter(lastNode);
79593
+ range.setEndAfter(lastNode);
79594
+ range.collapse(false);
79595
+ var comCon = range.commonAncestorContainer;
79596
+ if (comCon && comCon.parentNode) {
79597
+ try { comCon.parentNode.normalize(); } catch (e) {
79598
+ // Do Nothing
79609
79599
  }
79610
- }
79611
- oSel.removeAllRanges();
79612
- oSel.addRange(range);
79613
- let builderActive = this.doc.querySelector('.builder-active');
79614
- if (builderActive) this.applyBehaviorOn(builderActive);
79600
+ }
79601
+ oSel.removeAllRanges();
79602
+ oSel.addRange(range);
79603
+ */
79615
79604
 
79616
- //Trigger Change event
79617
- this.opts.onChange();
79605
+ let builderActive = this.doc.querySelector('.builder-active');
79606
+ if (builderActive) this.applyBehaviorOn(builderActive);
79618
79607
 
79619
- //Trigger Render event
79620
- this.opts.onRender();
79621
- } catch (e) {
79622
- let contentword = this.doc.querySelector('#idContentWord');
79623
- if (contentword) contentword.parentNode.removeChild(contentword);
79624
- }
79625
- }, 800);
79608
+ //Trigger Change event
79609
+ this.opts.onChange();
79610
+
79611
+ //Trigger Render event
79612
+ this.opts.onRender();
79613
+ } catch (e) {
79614
+
79615
+ // Do Nothing
79616
+ }
79626
79617
  }
79627
79618
  cellSelected() {
79628
79619
  const util = this.util;