The embedded "\n" characters in the following code does NOT produce line breaks in the generated string. What am I to do??? :-)
/* Load array into DOM */
var directory = document.getElementById ("directory");
directory.innerHTML = "";
var numberOfHouses = house.length;
for (i = 0; i < numberOfHouses; i++) {
var houseNode = document.createElement('span');
var text = (house[i][0] + "\n" + house[i][1] + "\n" + house[i][2] + "\n" + house[i][3] + "\n " + house[i][4] + "\n" + house[i][5] + "\n" + house[i][6] + "\n" + house[i][7] + "\n" + house[i][8] + "\n\n");
var houseText = document.createTextNode(text);
houseNode.appendChild(houseText);
directory.appendChild(houseNode);
}
That's because a linefeed in a text node does not render as a linefeed.
If you want a linefeed on a web page, you need to use CSS such as white-space: pre-line; to make them count, or add a <br> element
You need to be using <br> to make the new lines. You are creating the string in javascript, but it is being interpreted in HTML.
var directory = document.getElementById ("directory");
directory.innerHTML = "";
var numberOfHouses = house.length;
for (row = 0; row < numberOfHouses; row++) {
var houseNode = document.createElement('span');
for (column = 0; column < 9; column++) {
var text = (house[row][column]);
var houseText = document.createTextNode(text);
houseNode.appendChild(houseText);
directory.appendChild(houseNode);
var brNode = document.createElement ('br');
houseNode.appendChild(brNode);
}
var pNode = document.createElement('p');
directory.appendChild(pNode);
}
// Fixed!
Related
Let's say I have some sentences in Google Docs. Just one sentences as an example:
"My house is on fire"
I actually changed the background color so that every verb is red and every noun blue.
Now I want to make a list with all the verbs and another one with the nouns. Unfortunately getBackgroundColor() only seems to work with paragraphs and not with single words.
My idea was, to do something like this (I didn't yet have the time to think about how to do the loop, but that's not the point here anyway):
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var paragraphs = body.getParagraphs();
var colorVar = paragraphs[0].getText().match(/\w+/).getBackgroundColor(); // The regEx matches the first word. Next I want to get the background color.
Logger.log(colorVar);
}
The error message I get goes something like this:
"The function getBackgroundColor in the text object couldn't be found"
Thx for any help, or hints or comments!
You want to retrieve the text from a paragraph.
You want to retrieve each word and the background color of each word from the retrieved the text.
In this case, the color is the background color which is not getForegroundColor().
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
At first, the reason of your error is that getBackgroundColor() is the method of Class Text. In your script, getBackgroundColor() is used for the string value. By this, the error occurs.
In this answer, for achieving your goal, each character of the text retrieved from the paragraph is scanned, and each word and the background color of each word can be retrieved.
Sample script:
function myFunction() {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var paragraphs = body.getParagraphs();
var textObj = paragraphs[0].editAsText();
var text = textObj.getText();
var res = [];
var temp = "";
for (var i = 0; i < text.length; i++) {
var c = text[i];
if (c != " ") {
temp += c;
} else {
if (temp != "") res.push({text: temp, color: textObj.getBackgroundColor(i - 1)});
temp = "";
}
}
Logger.log(res) // result
}
When you run the script, the text of 1st paragraph is parsed. And you can see the result with res as an object.
In this sample script, the 1st paragraph is used as a test case. So if you want to retrieve the value from other paragraph, please modify the script.
References:
getBackgroundColor()
getBackgroundColor(offset)
editAsText()
If I misunderstood your question and this was not the direction you want, I apologize.
Here's a script your welcome to take a look at. It highlights text that a user selects...even individual letters. I did it several years ago just to learn more about how documents work.
function highLightCurrentSelection() {
var conclusionStyle = {};
conclusionStyle[DocumentApp.Attribute.BACKGROUND_COLOR]='#ffffff';
conclusionStyle[DocumentApp.Attribute.FOREGROUND_COLOR]='#000000';
conclusionStyle[DocumentApp.Attribute.FONT_FAMILY]='Calibri';
conclusionStyle[DocumentApp.Attribute.FONT_SIZE]=20;
conclusionStyle[DocumentApp.Attribute.BOLD]=false;
conclusionStyle[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT]=DocumentApp.HorizontalAlignment.LEFT;
conclusionStyle[DocumentApp.Attribute.VERTICAL_ALIGNMENT]=DocumentApp.VerticalAlignment.BOTTOM;
conclusionStyle[DocumentApp.Attribute.LINE_SPACING]=1.5;
conclusionStyle[DocumentApp.Attribute.HEIGHT]=2;
conclusionStyle[DocumentApp.Attribute.LEFT_TO_RIGHT]=true;
var br = '<br />';
var selection = DocumentApp.getActiveDocument().getSelection();
var s='';
if(selection) {
s+=br + '<strong>Elements in Current Selection</strong>';
var selectedElements = selection.getRangeElements();
for(var i=0;i<selectedElements.length;i++) {
var selElem = selectedElements[i];
var el = selElem.getElement();
var isPartial = selElem.isPartial();
if(isPartial) {
var selStart = selElem.getStartOffset();
var selEnd = selElem.getEndOffsetInclusive();
s+=br + 'isPartial:true selStart=' + selStart + ' selEnd=' + selEnd ;
var bgcolor = (el.asText().getBackgroundColor(selStart)=='#ffff00')?'#ffffff':'#ffff00';
el.asText().setBackgroundColor(selStart, selEnd, bgcolor)
}else {
var selStart = selElem.getStartOffset();
var selEnd = selElem.getEndOffsetInclusive();
s+=br + 'isPartial:false selStart=' + selStart + ' selEnd=' + selEnd ;
var bgcolor = (el.asText().getBackgroundColor()=='#ffff00')?'#ffffff':'#ffff00';
el.asText().setBackgroundColor(bgcolor);
}
var elType=el.getType();
s+=br + 'selectedElement[' + i + '].getType()= ' + elType;
if(elType==DocumentApp.ElementType.TEXT) {
var txt = selElem.getElement().asText().getText().slice(selStart,selEnd+1);
var elattrs = el.getAttributes();
if(elattrs)
{
s+=br + 'Type:<strong>TEXT</strong>';
s+=br + 'Text:<span style="color:#ff0000">' + txt + '</span>';
s+=br + 'Length: ' + txt.length;
s+=br + '<div id="sel' + Number(i) + '" style="display:none;">';
for(var key in elattrs)
{
s+= br + '<strong>' + key + '</strong>' + ' = ' + elattrs[key];
s+=br + '<input type="text" value="' + elattrs[key] + '" id="elattr' + key + Number(i) + '" />';
s+=br + '<input id="elattrbtn' + Number(i) + '" type="button" value="Save Changes" onClick="setSelectedElementAttribute(\'' + key + '\',' + i + ');" />'
}
s+='</div>Show/Hide';
}
}
if(elType==DocumentApp.ElementType.PARAGRAPH) {
var txt = selElem.getElement().asParagraph().getText();
var elattrs = el.getAttributes();
if(elattrs)
{
s+=br + '<strong>PARAGRAPH Attributes</strong>';
s+=br + 'Text:<span style="color:#ff0000">' + txt + '</span> Text Length= ' + txt.length;
for(var key in elattrs)
{
s+= br + key + ' = ' + elattrs[key];
}
}
}
s+='<hr width="100%"/>';
}
//var finalP=DocumentApp.getActiveDocument().getBody().appendParagraph('Total Number of Elements: ' + Number(selectedElements.length));
//finalP.setAttributes(conclusionStyle);
}else {
s+= br + 'No Elements found in current selection';
}
s+='<input type="button" value="Toggle HighLight" onclick="google.script.run.highLightCurrentSelection();"/>';
//s+='<input type="button" value="Exit" onClick="google.script.host.close();" />';
DocumentApp.getUi().showSidebar(HtmlService.createHtmlOutputFromFile('htmlToBody').append(s).setWidth(800).setHeight(450).setTitle('Selected Elements'));
}
The code is used in a HTML document, where when you press a button the first word in every sentence gets marked in bold
This is my code:
var i = 0;
while(i < restOftext.length) {
if (text[i] === ".") {
var space = text.indexOf(" ", i + 2);
var tekststykke = text.slice(i + 2, space);
var text = text.slice(0, i) + "<b>" + tekststykke + "</b>" + text.slice(i + (tekststykke.length + 2));
var period = text.replace(/<b>/g, ". <b>");
var text2 = "<b>" + firstWord + "</b>" + period.slice(space1);
i++
}
}
document.getElementById("firstWordBold").innerHTML = text2;
}
It's in the first part of the code under function firstWordBold(); where it says there is an error with
var space1 = text.indexOf(" ");
Looks like you're missing a closing quote on your string, at least in the example you provided in the question.
Your problem is the scope of the text variable. In firstWordBold change every text to this.text, except the last two where you re-define text
Also, if you want to apply bold to the first word this is easier...
document.getElementById('test-div-2').innerHTML = '<b>' + firstWord + '</b>' + restOftext;
It now works for me, with no errors and it applies bold to the first word.
Here's how the function ended up,
function firstWordBold() {
console.log('bolding!');
var space1 = this.text.indexOf(' ');
var firstWord = this.text.slice(0, space1);
var restOftext = this.text.slice(space1);
document.getElementById('test-div-2').innerHTML = '<b>' + firstWord + '</b>' + restOftext;
}
To make every first word bold, try this...
function firstWordBold() {
let newHTML = '';
const sentences = this.text.split('.');
for (let sentence of sentences) {
sentence = sentence.trim();
var space1 = sentence.indexOf(' ');
var firstWord = sentence.slice(0, space1);
var restOftext = sentence.slice(space1);
newHTML += '<b>' + firstWord + '</b>' + restOftext + ' ';
}
document.getElementById('test-div-2').innerHTML = newHTML;
}
One last edit, I didn't notice you had sentences ending with anything other that a period before. To split on multiple delimiters use a regex, like so,
const sentences = this.text.split(/(?<=[.?!])\s/);
I have a float e.g. 1377.5 that I want to be splitted with plain JavaScript in this structure:
<span class="digitLarge digit1">1</span>
<span class="digitLarge digit3">3</span>
<span class="digitLarge digit7">7</span>
<span class="digitLarge digit7">7</span>
<span class="digitPoint">.</span>
<span class="digitSmall digit5">5</span>
<span class="digitSmall digit0">0</span>
I tried with something like:
parseFloat(myFloat).toFixed(2).replace(/(.*)/g,'$1');
But here I cannot split in before point = Large and after point = Small. I could surely add multiple RegExes but this is kind of inconvenient...
What is the best way to achieve this?
Thank You!
Cheers,
Tom
You can just split the float into the number and decimal like this:
var a = 12345.67;
var lg = a.toString().split(".")[0]; ///before
var sm = a.toString().split(".")[1]; ///after
alert("large: " + lg + " small: " + sm);
//if you want to further split large
alert(lg.split(""));
var myFloat = 1377.5,
html = '',
dotReached = false;
myFloat = parseFloat(myFloat).toFixed(2);
for (var i = 0, l = myFloat.length; i < l; i++) {
if ('.' === myFloat[i]) {
html += '<span class="digitPoint">.</span>';
dotReached = true;
continue;
}
html += '<span class="' + (dotReached ? 'digitSmall' : 'digitLarge') + ' digit' + myFloat[i] + '">' + myFloat[i] + '</span>'
}
console.info(html);
Why not just use:
var number = 1377.50;
var splitted = String(number).split(".");
var beforePoint = splitted[0];
var afterPoint = splitted[0];
After that:
for(var i=0; i<beforePoint.length; i++){
var span = document.createElement("span");
span.innerHTML=beforePoint[i];
span.className="myClass";
document.body.appendChild(span);
}
var pointSpan = document.createElemnt("span");
pointSpan.innerHTML=".";
pointSpan.className="myClass";
document.body.appendChild(pointSpan);
for(var i=0; i<afterPoint.length; i++){
var span = document.createElement("span");
span.innerHTML=afterPoint[i];
span.className="myClass";
document.body.appendChild(span);
}
for XML string that contains Sales Orders and Details with SKU and Qty...
var myOrders =
"<?xml version='1.0' encoding='UTF-8'?>" +
"<Orders>" +
"<Order>" +
"<OrderHeader>" +
"<OrderNo>12345</OrderNo>" +
"</OrderHeader>" +
"<OrderDetails>" +
"<Sku>ABC</Sku>" +
"<Qty>2</Qty>" +
"<Sku>DEF</Sku>" +
"<Qty>3</Qty>" +
"</OrderDetails>" +
"</Order>"....
"</Orders>";
I can parse with javascript in Mozill alike this..
parser=new DOMParser();
xmlDoc=parser.parseFromString(myOrders,"text/xml");
myValue = xmlDoc.getElementsByTagName("Order");
// list all all SKUs ordered
for(i = 0; i < myValue.length; i++){
console.log(myValue);
var order = myValue[i].firstChild.firstChild.firstChild.nodeValue;
document.write(order + "<br>");
}
Can I replace this line:
var order = myValue[i].firstChild.firstChild.firstChild.nodeValue;
with something more specific
something like...
var order = myValue[i]['Order']['OrderDetail']['Sku'].nodeValue;
You can try querySelector:
myValue[i].querySelector('OrderHeader > OrderNo').textContent
Also consider querySelectorAll:
var elements = xmlDoc.querySelectorAll("Order > OrderHeader > OrderNo");
for(var i = 0; i < elements.length; i++){
var order = elements[i].textContent;
}
Using querySelector and querySelectorAll, this seem to work. Can I get any more efficient? I don't seem to have to use complete path ( A > B > C). Note that I added OrderDetail tags to example below. I validates without this, but just seems cleaner.
var myOrders =
"<?xml version='1.0' encoding='UTF-8'?>" +
"<Orders>" +
"<Order>" +
"<OrderHeader>" +
"<OrderNo>12345</OrderNo>" +
"</OrderHeader>" +
"<OrderDetails>" +
"<OrderDetail>" +
"<Sku>ABC</Sku>" +
"<Qty>2</Qty>" +
"</OrderDetail>" +
"<OrderDetail>" +
"<Sku>DEF</Sku>" +
"<Qty>4</Qty>" +
"</OrderDetail>" +
"</OrderDetails>" +
"</Order>"...;
document.write("</br>4. Get all Orders Numbers and SKU Ordered for each Order</br>");
myOrders= xmlDoc.getElementsByTagName("Order");
// iterate through orders
for(x = 0; x < myOrders.length; x++){
var myOrder = myOrders[x].querySelector('OrderNo').textContent;
document.write(myOrder + "</br>");
// iterate through SKUS in each order
var mySkus = myOrders[x].querySelectorAll('OrderDetail > Sku');
for(y = 0; y < mySkus.length; y++){
document.write("-- SKU: " + mySkus[y].firstChild.nodeValue + "</br>");
}
}
document.write("<hr>");
This is what I got so far but I`m stuck.
var s=`First JavaScript string.`;
var c=`This is second text.`;
var sc = s.concat(c);
var sp=sc.split("");
var colors=[`red`,`black`">;
for(i=0;i<sc.length;i++) {
var span=`<span style="color:`+colors[i % 2">+`;">`+sp+`</span>`;
document.write(span);
}
Don't split the string, just use sc[i] instead of sp in last line.
You are writing the text with your sp variable. What you want is the current character. In your loop you loop over every character. In this for loop the i is the index. Your sc string is actually an array of characters. Therefore sc[i] points to the current character.
If you change sp to sc[i] your code works correct.
var s = "First JavaScript string.";
var c = "This is second text.";
var sc = s.concat(c);
var colors = ['red','black'];
for (i=0; i<sc.length; i++) {
var span = '<span style="color:' + colors[i % 2] + ';">' + sc[i] + '</span>';
document.write(span);
}
However a more efficient way would be:
var s = "First JavaScript string.";
var c = "This is second text.";
var sc = s.concat(c);
var colors = ['red','black'];
var html = "";
for (i=0; i<sc.length; i++) {
html += '<span style="color:' + colors[i % 2] + ';">' +sc[i]+ '</span>';
}
document.write(html);
Fiddle at: http://jsfiddle.net/4Np9u/
Here you go:
var s = "First JavaScript string.";
var c = "This is second text.";
var sc = s.concat(c);
var colors = ['red','black'];
for (i=0; i<sc.length; i++) {
var span = '<span style="color:' + colors[i % 2] + ';">' +sc[i]+ '</span>';
document.write(span);
}
JsFiddle = http://jsfiddle.net/A24q2/