Problem in a function : appendchild is not a function - appendchild

I want to make animation on a text, and need to have each letter separated.
This works :
let hero = document.querySelector('.hero');
let text = hero.textContent;
hero.textContent = '';
let letters = text.split('');
letters.forEach((letter) => {
let newSpan = document.createElement('span');
let newContent = document.createTextNode(letter);
newSpan.appendChild(newContent);
if (newSpan.textContent == ' ') {
newSpan.style.marginRight = '5px';
newSpan.style.marginLeft = '5px';
}
hero.appendChild(newSpan);
});
<div class="hero">My awesome sentence</div>
But I would like to use this in another context, so to turn it into a function.
This dosesn't works, message : sentenceDiv.appendChild is not a function
let spanifyText = (sentenceDiv) => {
let text = sentenceDiv.textContent;
sentenceDiv = '';
let letters = text.split('');
letters.forEach((letter) => {
let newSpan = document.createElement('span');
let newContent = document.createTextNode(letter);
newSpan.appendChild(newContent);
if (newSpan.textContent == ' ') {
newSpan.style.marginRight = '5px';
newSpan.style.marginLeft = '5px';
}
sentenceDiv.appendChild(newSpan);
});
};
let hero = document.querySelector('.hero');
spanifyText(hero);
<div class="hero">My awesome sentence</div>
It is certainly a newbie problem but cannot figure it out.
Any help please ?
Thanks in advance

Thanks for pointing out the problem !
Just modified html by adding a span with a class for the original text, then removing it at the end of the function. Code can certainly be improved but it does the job !
let spanifyText = (sentenceDiv) => {
let originalSpan = sentenceDiv.querySelector('.original-span');
let text = sentenceDiv.textContent;
let letters = text.split('');
letters.forEach((letter) => {
let newSpan = document.createElement('span');
let newContent = document.createTextNode(letter);
newSpan.appendChild(newContent);
if (newSpan.textContent == ' ') {
newSpan.style.marginRight = '5px';
newSpan.style.marginLeft = '5px';
}
sentenceDiv.appendChild(newSpan);
});
originalSpan.parentNode.removeChild(originalSpan);
};
let hero = document.querySelector('.hero');
spanifyText(hero);
<div class="hero"><span class="original-span">My Awesome Text</span></div>

Related

Google Apps Script to add links to google Spreadsheet adds 5000+ rows and i dont understand why?

Pretty self explanatory title, im trying to do a script where it takes the number on a column and uses that to search a list of files from google drive and then insert a link to that file.
HOWEVER, every time it inserts that link it also creates like 5000+ empty rows? why would this be?
The purpose is to take a number from a certain column, then look on google drive for the file that matches (at least partially) with that first number, then we should generate a link for that file and insert that link into another column, next to the number.
function CopiarResos() {
let ass = SpreadsheetApp.getActiveSpreadsheet();
let maxRows = ass.getSheetByName('set_de_datos_unificado').getMaxRows();
let columnaResos = ass.getSheetByName('set_de_datos_unificado').getSheetValues(2,2,maxRows,1);
let columnaLinks = ass.getSheetByName('set_de_datos_unificado').getSheetValues(2,53,maxRows,1);
let folder = DriveApp.getFolderById('1FJiet6tVgWXtM91Y7mmhgxDL2iYFm1VE'); // I change the folder ID here
let list = [];
let idList = [];
let files = folder.getFiles();
let match = '';
while (files.hasNext()){
file = files.next();
list.push(file.getName().toString());
idList.push(file.getId().toString());
}
console.log(list);
console.log(idList);
/*
let match = list.find(element => {
if (element.includes(substring)) {
return true;
}
});
*/
for (let i = 0; i in columnaResos; i++){
if(columnaLinks[i] == ""){
let substring = columnaResos[i];
match = list.find(element => {
if (element.includes(substring)) {
let idString = idList[i];
let insertStr = "https://drive.google.com/file/d/" + idString +"view";
let cellInsert = ass.getSheetByName('set_de_datos_unificado').getRange([i]+2,53);
cellInsert.setValue(insertStr);
return true;
}
});
}
};
}
getMaxRows() returns the number of rows that has the sheet (scroll down to the very bottom). You might delete the blank rows below your data or use getLastRow() instead.
References
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getmaxrows
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getlastrow
So, apart from all the thing wasnt written right turns out i was missing a bunch of lines! Mostly i was trying to get a fileid from an array even tho the indexes were completely unrelated (eg: trying to get list[300] instead of doing indexOf(match)
function copiarResos() {
let ass = SpreadsheetApp.getActiveSpreadsheet();
let maxRows = ass.getSheetByName('set_de_datos_unificado').getLastRow();
let columnaResos = ass.getSheetByName('set_de_datos_unificado').getSheetValues(2,2,maxRows,1);
let columnaLinks = ass.getSheetByName('set_de_datos_unificado').getSheetValues(2,53,maxRows,1);
let folder = DriveApp.getFolderById('1FJiet6tVgWXtM91Y7mmhgxDL2iYFm1VE'); // I change the folder ID here
let list = [];
let files = folder.getFiles();
let match = '';
while (files.hasNext()){
file = files.next();
list.push(file.getName().toString(), file.getId().toString());
}
console.log(list);
console.log(columnaLinks)
for (let i = 0; i in columnaResos; i++){
if(columnaLinks[i] == ''){
let substring = columnaResos[i];
match = list.find(element => {
if (element.includes(substring)) {
return true;
}
});
console.log(match);
matchId = list.indexOf(match);
if(matchId !== 0){
console.log(match + " id es" + matchId);
let idString = list[matchId+1];
console.log(idString)
let insertStr = "https://drive.google.com/file/d/" + idString +"/view?usp=sharing";
let cellInsert = ass.getSheetByName('set_de_datos_unificado').getRange(i+2 ,53);
cellInsert.setValue(insertStr);
}
}
match = ''
};
}

How to show duplicates in a UI when searched in google sheets?

I am developing a tracking system for candidates
Attached a search button.
But I want a UI to pop up which will show the duplicates if present.
And when one of the duplicates is clicked, it will fill the required details in the form
I have made this.
But the results are the first row which matches the search text in B4
function Search()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("Form");
var dataS = ss.getSheetByName("Data");
var str = formS.getRange("B4").getValue();
var values = dataS.getDataRange().getValues();
var valuesFound = false;
for (var i = 0; i < values.length; i++)
{
var rowValue = values[i];
if (rowValue[0] == str) {
formS.getRange("B7").setValue(rowValue[0]) ;
formS.getRange("B9").setValue(rowValue[1]) ;
formS.getRange("B11").setValue(rowValue[2]) ;
formS.getRange("B13").setValue(rowValue[3]) ;
formS.getRange("E7").setValue(rowValue[4]) ;
formS.getRange("E9").setValue(rowValue[5]) ;
formS.getRange("E11").setValue(rowValue[6]) ;
formS.getRange("E13").setValue(rowValue[7]) ;
return;
}
}
if(valuesFound==false){
var ui = SpreadsheetApp.getUi();
ui.alert("No record found!");
}
}
Description
You could get all the first name matches and show them in a dialog, numbered so its easier to pick. Once the user picks the name you can fill out the form.
To use a dropdown and pick a name, that would require a custom dialog. Doable but more complex.
This script is executed from a menu item.
Data
Script
function search() {
try {
let spread = SpreadsheetApp.getActiveSpreadsheet();
let dataS = spread.getSheetByName("Data");
let str = "John";
let values = dataS.getDataRange().getValues();
let rowValue = values.filter( row => row[0] === str );
let ui = SpreadsheetApp.getUi();
let prompt = "";
rowValue.forEach( (row,i) => prompt = prompt.concat((i+1).toString(),": ",row[0], " ",row[1],"\n"));
if( rowValue.length === 0 ) {
ui.alert("Name not found ["+str+"]");
return;
}
else if( rowValue.length > 1 ) {
let response = ui.prompt("Pick a name",prompt,ui.ButtonSet.OK_CANCEL);
if( response.getSelectedButton() == ui.Button.OK ) {
str = response.getResponseText();
str = parseInt(str)-1;
rowValue = rowValue[str];
}
}
else {
rowValue = rowValue[0];
}
ui.alert(rowValue.toString());
// Now you can fill out your form with rowValue
}
catch(err) {
SpreadsheetApp.getUi().alert(err);
}
}
Reference
Array.filter()
Array.forEach()
SpreadsheetApp Ui prompt
Description
So I decided to show how a custom dialog can be used to display a list of names to pick from. First a Ui dialog is displayed to use a filter name. If no name is specified all names will be listed.
Using HTMLService a custom dialog is build using the the pushed variable option for an HTM Template.
Once a name is picked from the list google.script.run is used to return the name to the server and the form can be built from there.
Code.gs
function onOpen(e) {
var menu = SpreadsheetApp.getUi().createMenu("My Menu");
menu.addItem("Test","showTest");
menu.addToUi();
}
function showTest() {
try {
let ui = SpreadsheetApp.getUi();
let response = ui.prompt("What name do you want to search for",ui.ButtonSet.OK_CANCEL);
if( response.getSelectedButton() == ui.Button.OK ) {
var name = response.getResponseText();
if( name === "" ) name = "__All";
}
let spread = SpreadsheetApp.getActiveSpreadsheet();
let dataS = spread.getSheetByName("Data");
let data = dataS.getRange(1,1,dataS.getLastRow(),2).getValues(); // Get range A1:B
if( name !== "__All" ) {
data = data.filter( row => row[0] === name );
}
if( data.length === 0 ) {
ui.alert("No names mathcing ["+name+"] found");
return;
}
let html = HtmlService.createTemplateFromFile('HTML_Test');
html.data = data;
html = html.evaluate();
SpreadsheetApp.getUi().showModalDialog(html,"Show Test");
}
catch(err) {
SpreadsheetApp.getUi().alert(err);
}
}
function pickName(name) {
try {
let spread = SpreadsheetApp.getActiveSpreadsheet();
let dataS = spread.getSheetByName("Data");
dataS.getRange(1,5).setValue(name);
// Build your form here
}
catch(err) {
console.log(err);
}
}
HTML_Test.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<select id="selectName">
<? for (let i = 0; i < data.length; i++) { ?>
<option><?= data[i][0]+" "+data[i][1] ?></option>
<? } ?>
</select>
<input type="button" onclick="buttonOnClick()" value="Submit">
<script>
function buttonOnClick() {
let name = document.getElementById("selectName").value;
google.script.run.pickName(name);
google.script.host.close();
}
</script>
</body>
</html>
Reference
HTMLService
HTML Template
google.script.run
google.script.host

how to to convert for to foreach

jslint tell Unexpected 'for'.
so i think that i must convert for with foreach
but how?
if someone can help
thanks
// Grab the original element
var original = document.getElementsByTagName("noscript")[0];
// Create a replacement tag of the desired type
var replacement = document.createElement("span");
var i;
// Grab all of the original's attributes, and pass them to the replacement
for(i = 0, l = original.attributes.length; i < l; ++i){
var nodeName = original.attributes.item(i).nodeName;
var nodeValue = original.attributes.item(i).nodeValue;
replacement.setAttribute(nodeName, nodeValue);
}
// Persist contents
replacement.innerHTML = original.innerHTML;
// Switch!
original.parentNode.replaceChild(replacement, original);
You have a comma after i = 0, <========
it should be semicolon.
Another issue is declaring l = original.attributes.length you don't need the variable l
just use it as for(i = 0; i < original.attributes.length; ++i){
if you still wanna use a forEach you can do it as:
original.attributes.forEach(element => {
var nodeName = element.nodeName;
var nodeValue = element.nodeValue;
replacement.setAttribute(nodeName, nodeValue);
});
thanks for your answer, i got Uncaught TypeError: original.attributes.forEach is not a function
function Switch() {
var original = document.getElementsByTagName("noscript")[0];
var replacement = document.createElement("span");
original.attributes.forEach(element => {
var nodeName = element.nodeName;
var nodeValue = element.nodeValue;
replacement.setAttribute(nodeName, nodeValue);
});
// Persist contents
replacement.innerHTML = original.innerHTML;
// Switch!
original.parentNode.replaceChild(replacement, original);
}

Is it possible to Insert an anchored text frame above a text/word?

I want to mark each CharacterStyle in the document by placing an achored text frame above each text/word. I am quite new to scripting in indesign, so any help is much appreciated.
Here is the expected output:
I found a solution to this, and for those who might encounter the same problem as me here is my code :
app.findChangeGrepOptions.includeFootnotes = false;
app.findChangeGrepOptions.includeHiddenLayers = false;
app.findChangeGrepOptions.includeLockedLayersForFind = false;
app.findChangeGrepOptions.includeLockedStoriesForFind = false;
app.findChangeGrepOptions.includeMasterPages = false;
app.findGrepPreferences = NothingEnum.nothing;
app.findGrepPreferences.appliedCharacterStyle = style;
app.findGrepPreferences.findWhat = ".+";
var found_item = doc.findGrep();
var res_count = found_item.length;
if(res_count > 0){
var found_text = found_item[0].paragraphs.firstItem();
var insertion_character = (found_text.characters.lastItem().index);
var check_insertion_character = insertion_character + 1;
var alt_insertion_character = (found_text.characters.firstItem().index);
var the_story = found_text.parentStory;
try{
app.selection = the_story.insertionPoints[check_insertion_character];
app.selection = the_story.insertionPoints[alt_insertion_character];
}catch(err){
alert(err);
}
var the_anchored_frame = app.selection[0].textFrames.add({geometricBounds:["0","0",1,10],anchoredObjectSettings:{anchoredPosition: AnchorPosition.ABOVE_LINE, horizontalReferencePoint: AnchoredRelativeTo.ANCHOR_LOCATION, verticalReferencePoint: VerticallyRelativeTo.TOP_OF_LEADING}});
the_anchored_frame.contents = style;
// the_anchored_frame.appliedObjectStyle = real_anchor_style;
}
Cheers

javascript getElementById appendChild error

i am having a problem with javascript and i dont know how to solve it.
i am having this code
function addtask(tab){
var tasktag = document.createElement('tr');
var task = document.getElementById(tab).getElementsByTagName('tr').length+1;
task = tab+'r'+task;
tasktag.setAttribute('id',task);
document.getElementById(tab).appendChild(tasktag);
var tasktag2 = document.createElement('td');
var task2 = document.getElementById(task).getElementsByTagName('td').length+1;
task2 = task+'c'+task2;
alert(task2);
tasktag2.setAttribute('id',task2);
tasktag2.innerHTML =''+task2+' <br><input id=\'btn1\' type=\'button\' value=\'remove\' onClick=\"removeElement(\''+num+'\',\'body\')\" />';
document.getElementById(task).appendChild(task2);
}`
i get "Couldn't convert JavaScript argument arg 0 [nsIDOMHTMLTableRowElement.appendChild]"(from firebug).
while this code works perfect
`var num;
function addlist(){
var divTag = document.createElement('table');
if(num==undefined){num = 1;}
else{numi = num.split("t")
num=parseInt(numi[1])+1;}
num = 't'+num;
divTag.setAttribute('id',num);
divTag.setAttribute('align','left');
divTag.setAttribute('style','margin:7px;');
divTag.setAttribute('border',1);
document.body.appendChild(divTag);
var divTag2 = document.createElement('tr');
var num2 = document.getElementById(num).getElementsByTagName('tr').length+1;
num2 = num+'r'+num2;
divTag2.setAttribute('id',num2);
document.getElementById(num).appendChild(divTag2);
var divTag3 = document.createElement('td');
var num3 = document.getElementById(num2).getElementsByTagName('td').length+1;
num3 = num2+'c'+num3;
divTag3.setAttribute('id',num3);
divTag3.innerHTML =''+num+' <br><input id=\'btn1\' type=\'button\' value=\'remove\' onClick=\"removeElement(\''+num+'\',\'body\')\" /><br><input id=\'btn2\' type=\'button\' value=\'task\' onClick=\"addtask(\''+num+'\')\" />';
document.getElementById(num2).appendChild(divTag3);
}
why is this happening?thank you all for your time
When working with tables, you have to use slightly different JavaScript functions:
var row = table.insertRow(table.rows.length);
row.id = ...;
Try re-working your code to use insertRow instead of appendChild, as I am lazy.

Resources