TinyMce 5 setcontent unable to set html properly - javascript

I am writing a tinymce custom plugin called Mergetable. which will merger two user selected table.
Problem statement:
TinyMce is not allowing to select two table , by using shift and mouse I can select content of the table. So I can't use tinmce.activeeditor.selection.getNode() method instead using tinmce.activeeditor.selection.getContent().
Form getcontent() method I am getting proper html of both table. After do some operation while setting content using tinmce.activeeditor.selection.setContent() both table merged properly but two more table with empty td created one in top and one in bottom . Please see below plugin code.
code:
(function () {
var mergeTable = (function () {
'use strict';
tinymce.PluginManager.add("mergeTable", function (editor, url) {
function Merge(){
var selectedhtml=editor.selection.getContent();
//using getContent() as getnode returning body node
var dv=document.createElement('div');
dv.innerHTML= selectedhtml;
var tableElements = dv.getElementsByTagName('TABLE');
if (tableElements.length == 2) {
var tableOne = tableElements[0];
var tableTwo = tableElements[1];
var tempTable = null;
var offsetLeft = tableOne.offsetLeft;
var offsetTop = tableOne.offsetTop;
var elem = tableElements[0];
if (tableOne.nodeName == "TABLE" && tableTwo.nodeName == "TABLE") {
for (var r = 0; r < tableTwo.rows.length; r++) {
var newTR = tableOne.insertRow(tableOne.rows.length);
for (var i = 0; i < tableTwo.rows[r].cells.length; i++) {
var newTD = newTR.insertCell()
newTD.innerHTML = tableTwo.rows[r].cells[i].innerHTML;
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan;
newTD.rowSpan = tableTwo.rows[r].cells[i].rowSpan;
newTD.style.cssText = tableTwo.rows[r].cells[i].style.cssText;
if (tableOne.style.border != "") {
newTD.style.border = "1px dotted #BFBFBF"
}
}
}
tableTwo.remove();
console.log(dv.innerHTML);
editor.selection.setContent(dv.innerHTML);
editor.nodeChanged();
}
else {
alert("Please select two tables");
}
}
}
editor.ui.registry.addButton('mergeTable', {
text: "Merge Table",
onAction: function(){ Merge();}
});
});
}());
}());

I am able to fix my problem by using some work around . Instead use setContent() method. I have remove selected content and use insertContent().
Please find working code below.
(function () {
var mergeTable = (function () {
'use strict';
tinymce.PluginManager.add("mergeTable", function (editor, url) {
var cmd = function (command) {
return function () {
return editor.execCommand(command);
};
};
function Merge(){
var selectedhtml=editor.selection.getContent();
var dv=document.createElement('div');
dv.innerHTML= selectedhtml;
var tableElements = dv.getElementsByTagName('TABLE');
if (tableElements.length == 2) {
var tableOne = tableElements[0];
var tableTwo = tableElements[1];
var tempTable = null;
var tableOneMaxCell=0
var tabletwoMaxCell=0
var tempCellcount=0
var tableOneRowcount=tableOne.rows.length;
tableOne.querySelectorAll("tr").forEach(function(e){
tempCellcount= e.querySelectorAll("td").length ;
if(tempCellcount>tableOneMaxCell)
{
tableOneMaxCell=tempCellcount;
}
});
tableTwo.querySelectorAll("tr").forEach(function(e){
tempCellcount= e.querySelectorAll("td").length ;
if(tempCellcount>tabletwoMaxCell)
{
tabletwoMaxCell=tempCellcount;
}
});
if (tableOne.nodeName == "TABLE" && tableTwo.nodeName == "TABLE") {
for (var r = 0; r < tableTwo.rows.length; r++) {
var newTR = tableOne.insertRow(tableOne.rows.length);
for (var i = 0; i < tableTwo.rows[r].cells.length; i++) {
var newTD = newTR.insertCell()
newTD.innerHTML = tableTwo.rows[r].cells[i].innerHTML;
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan;
newTD.rowSpan = tableTwo.rows[r].cells[i].rowSpan;
newTD.style.cssText = tableTwo.rows[r].cells[i].style.cssText;
if (tableOne.style.border != "") {
newTD.style.border = "1px dotted #BFBFBF"
}
if(i==tableTwo.rows[r].cells.length-1 && tableOneMaxCell>tabletwoMaxCell){
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan + (tableOneMaxCell-tabletwoMaxCell);
}
}
}
for( var t1=0; t1<tableOneRowcount; t1++ ){
var celllen=tableOne.rows[t1].cells.length;
tableOne.rows[t1].cells[celllen-1].colSpan=tableOne.rows[t1].cells[celllen-1].colSpan+(tabletwoMaxCell-tableOneMaxCell)
}
tableTwo.remove();
// cmd('mceTableDelete');
// var selObj = editor.selection;
// var selstartRange = selObj.getStart();
// var selectendRange= selObj.getEnd();
// var selrng=selObj.getRng();
// console.log(selstartRange);
// console.log(selectendRange);
// editor.execCommand('mceTableDelete');
// selObj.removeAllRanges();
editor.selection.getSelectedBlocks().forEach(function(elm){
elm.remove();
});
// selObj.setRng(selrng,true);
editor.insertContent(dv.innerHTML);
editor.nodeChanged();
}
else {
editor.notificationManager.open({
text: 'Please select two table.',
type: 'error'
});
}
}
else {
editor.notificationManager.open({
text: 'Please select two table.',
type: 'error'
});
}
}
editor.ui.registry.addButton('mergeTable', {
text: "MergeTable",
onAction: function(){ Merge();}
});
});
}());
}());

Related

String is empty after first iteration in loop

I'm replacing the contents in a string using a setTimeout-function. The code looks as follows:
(function ($) {
"use strict";
/*
GENERAL DESCRIPTION:
*/
$(document).ready(function () {
var page_title = $(".page-content")[0].title;
var replacement_string = "åpöälokjixrytgöh";
//$(window).scroll(function () {
window.setInterval(function () {
var fixed = $(".changing-title");
var fixed_position = $(".changing-title").offset().top;
var fixed_height = $(".changing-title").height();
var title_array = [];
var offset_array = [];
var height_array = [];
var $pageGridPictures = $(".page-grid-picture");
$pageGridPictures.each(function (index, element) {
var $this = $(element);
title_array.push(element.title);
offset_array.push($this.offset().top);
height_array.push($this.height());
});
for (var i = 0; i < offset_array.length; i++) {
if (fixed_position + fixed_height > offset_array[i] && fixed_position + fixed_height < offset_array[i + 1]) {
if (title_array[i] !== fixed.text()) {
var j;
var text_one = title_array[i];
var text_two = "";
fixed.text(title_array[i]);
for (j in title_array[i]) {
(function (j) {
setTimeout(function () {
text_two = text_one.substring(0, j) + replacement_string[j] + text_one.substring(j + 2, text_one.length);
fixed.text(text_two);
if (j == text_one.length - 1) {
fixed.text(text_one);
}
}, 80 * j);
}(j))
};
}
}
}
}, 1200);
});
})(jQuery);
The problem is that the last substring added to text_two in the setTimeout-function is empty after the first iteration. It works the first time. It then contains the correct substring and has the correct length. After that it's just empty. Why is that? I'm going crazy over here! ^^
Thanks in advance.

Show all tabs content vanilla js

How can I change this javascript code, that when I click on "Green" I want the content from all tabs to be displayed? https://codepen.io/wangel13/pen/OXBrRp
'use strict';
function Tabs() {
var bindAll = function() {
var menuElements = document.querySelectorAll('[data-tab]');
for(var i = 0; i < menuElements.length ; i++) {
menuElements[i].addEventListener('click', change, false);
}
}
var clear = function() {
var menuElements = document.querySelectorAll('[data-tab]');
for(var i = 0; i < menuElements.length ; i++) {
menuElements[i].classList.remove('active');
var id = menuElements[i].getAttribute('data-tab');
document.getElementById(id).classList.remove('active');
}
}
var change = function(e) {
clear();
e.target.classList.add('active');
var id = e.currentTarget.getAttribute('data-tab');
document.getElementById(id).classList.add('active');
}
bindAll();
}
var connectTabs = new Tabs();
Take a look at this:
'use strict';
function Tabs() {
var bindAll = function() {
var menuElements = document.querySelectorAll('[data-tab]');
for(var i = 0; i < menuElements.length ; i++) {
menuElements[i].addEventListener('click', change, false);
}
}
var clear = function() {
var menuElements = document.querySelectorAll('[data-tab]');
for(var i = 0; i < menuElements.length ; i++) {
menuElements[i].classList.remove('active');
var id = menuElements[i].getAttribute('data-tab');
document.getElementById(id).classList.remove('active');
}
}
function makeAllActive() {
var tabs = document.querySelectorAll('.b-tab');
Array.from(tabs).map(item => {
item.classList.add('active');
});
}
var change = function(e) {
clear();
e.target.classList.add('active');
var id = e.currentTarget.getAttribute('data-tab');
if(id === "green") {
makeAllActive();
return;
}
document.getElementById(id).classList.add('active');
}
bindAll();
}
var connectTabs = new Tabs();

Linkedin Autoconnect With User role

I am trying to fix this script to automatically connect people you may know on Linkedin based on User roles (CEO e.t.c), Can someone help me fix this, Below is my code; I have tried the script on almost all browsers, Somebody help fix this.
var userRole = [
"CEO",
"CIO"
];
var inviter = {} || inviter;
inviter.userList = [];
inviter.className = 'button-secondary-small';
inviter.refresh = function () {
window.scrollTo(0, document.body.scrollHeight);
window.scrollTo(document.body.scrollHeight, 0);
window.scrollTo(0, document.body.scrollHeight);
};
inviter.initiate = function()
{
inviter.refresh();
var connectBtns = $(".button-secondary-small:visible");
//
if (connectBtns == null) {var connectBtns = inviter.initiate();}
return connectBtns;
};
inviter.invite = function () {
var connectBtns = inviter.initiate();
var buttonLength = connectBtns.length;
for (var i = 0; i < buttonLength; i++) {
if (connectBtns != null && connectBtns[i] != null) {inviter.handleRepeat(connectBtns[i]);}
//if there is a connect button and there is at least one that has not been pushed, repeat
if (i == buttonLength - 1) {
console.log("done: " + i);
inviter.refresh();
}
}
};
inviter.handleRepeat = function(button)
{
var nameValue = button.children[1].textContent
var name = nameValue.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
function hasRole(role){
for(var i = 0; i < role.length; i++) {
// cannot read children of undefined
var position = button.parentNode.parentNode.children[1].children[1].children[0].children[3].textContent;
var formatedPosition = position.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
var hasRole = formatedPosition.indexOf(role[i]) == -1 ? false : true;
console.log('Has role: ' + role[i] + ' -> ' + hasRole);
if (hasRole) {
return hasRole;
}
}
return false;
}
if(inviter.arrayContains(name))
{
console.log("canceled");
var cancel = button.parentNode.parentNode.children[0];
cancel.click();
}
else if (hasRole(userRole) == false) {
console.log("cancel");
var cancel = button.parentNode.parentNode.children[0];
cancel.click();
}
else if (button.textContent.indexOf("Connect")<0){
console.log("skipped");
inviter.userList.push(name); // it's likely that this person didn't join linkedin in the meantime, so we'll ignore them
var cancel = button.parentNode.parentNode.children[0];
cancel.click();
}
else {
console.log("added");
inviter.userList.push(name);
button.click();
}
};
inviter.arrayContains = function(item)
{
return (inviter.userList.indexOf(item) > -1);
};
inviter.usersJson = {};
inviter.loadResult = function()
{
var retrievedObject = localStorage.getItem('inviterList');
var temp = JSON.stringify(retrievedObject);
inviter.userList = JSON.parse(temp);
};
inviter.saveResult = function()
{
inviter.usersJson = JSON.stringify(inviter.userList);
localStorage.setItem('inviterList', inviter.usersJson);
};
setInterval(function () { inviter.invite(); }, 5000);
`
When I try executing this, I get the following error:
VM288:49 Uncaught TypeError: Cannot read property 'children' of undefined
at hasRole (<anonymous>:49:71)
at Object.inviter.handleRepeat (<anonymous>:66:11)
at Object.inviter.invite (<anonymous>:30:69)
at <anonymous>:108:35
Any ideas as to how to fix it?

Javascript dynamic onChange event on select

I have this javascript snippet:
var selectName["id1","id2","id3"];
setOnClickSelect = function (prefix, selectName) {
for(var i=0; i<selectName.length; i++) {
var selId = selectName[i];
alert(selId);
$(selId).onchange = function() {
$(selId).value = $(selId).options[$(selId).selectedIndex].text;
}
}
}
But when I change value to my id1 element, the alert wrote me always "id3".
Can I fix it?
EDIT:
I've changed my snippet with these statements:
setOnChangeSelect = function (prefix, selectName) {
for(var i=0; i<selectName.length; i++) {
var selId = selectName[i];
$(selId).onchange = (function (thisId) {
return function() {
$(selId).value = $(thisId).options[$(thisId).selectedIndex].text;
}
})(selId);
}
}
But selId is always the last element.
This is caused by the behavior of javaScript Closure, selId has been set to the selectName[2] at the end of the loop and that's why you get 'id3' back.
An fix is as following, the key is wrap the callback function inside another function to create another closure.
var selectName = ["id1","id2","id3"];
var setOnClickSelect = function (prefix, selectName) {
for(var i = 0; i < selectName.length; i++) {
var selId = selectName[i];
$(selId).onchange = (function (thisId) {
return function() {
$(thisId).value = $(thisId).options[$(thisId).selectedIndex].text;
}
})(selId);
}
};
Ps: there is synyax error for var selectName["id1","id2","id3"], you should use var selectName = ["id1","id2","id3"];

Javascript refactor

Is there a better way to write this function? I've inherited some javascript code and I'd like to make this more concise if possible. Also, I'll probably be adding many more "theme" elements and don't want to copy and paste over and over.
function imageClick() {
var theme1 = document.getElementById("li-theme1");
var theme2 = document.getElementById("li-theme2");
var theme3 = document.getElementById("li-theme3");
var imgtheme1 = theme1.getElementsByTagName("img");
var imgtheme2 = theme2.getElementsByTagName("img");
var imgtheme3 = theme3.getElementsByTagName("img");
var inputtheme1 = document.getElementById("radiotheme1");
var inputtheme2 = document.getElementById("radiotheme2");
var inputtheme3 = document.getElementById("radiotheme3");
imgtheme1[0].onclick = function() {
inputtheme1.checked = true;
highlightChoice("li-theme1");
}
imgtheme2[0].onclick = function() {
inputtheme2.checked = true;
highlightChoice("li-theme2");
}
imgtheme3[0].onclick = function() {
inputtheme3.checked = true;
highlightChoice("li-theme3");
}
}
function imageClick()
{
for (var i=1; i<4; i++)
{
var theme = document.getElementById("li-theme"+i);
var imgtheme = theme.getElementsByTagName("img");
imgtheme[0].onclick = (function (current)
{
return function()
{
document.getElementById("inputtheme"+current) = true;
highlightChoice("li-theme"+current);
}
})(i);
}
}
If you want to add more iterations at the later date, just increase the 4 in i<4 to the number of iterations you'd like to perform + 1.
I've "hardcoded" the imageClick() function to the ones that you've specified, but you could change this to be a "for(var i=1;i<4;i++) {imageClickItem(i);}" type loop if you wished.
function imageClick()
{
imageClickItem(1);
imageClickItem(2);
imageClickItem(3);
}
function imageClickItem(itemNumber)
{
var theme = document.getElementById("li-theme" + itemNumber);
var imgtheme = theme.getElementsByTagName("img");
var inputtheme = document.getElementById("radiotheme" + itemNumber);
imgtheme[0].onclick = function()
{
inputtheme.checked = true;
highlightChoice(theme.id);
}
}

Categories