Pass multiple values with button onclick - javascript

There are similar posts but I can't find a solution for my unique case.
I have a script which highlights a keyword when a user clicks the highlight button. Currently it is only highlighting the word "fox", but I need it to highlight additional words, in this case "fence" and "jumped".
Here is HTML:
<div id="inputText">
The fox quickly jumped over the fence.
</div>
<button onclick="highlight('fox')">Highlight</button>
I tried changing 'fox' to '+fox+','+fence+','+jumped+' but no luck.
The javascript is:
function highlight(text)
{
inputText = document.getElementById("inputText")
var innerHTML = inputText.innerHTML
var index = innerHTML.indexOf(text);
if ( index >= 0 )
{
innerHTML = innerHTML.substring(0,index) + "<span class='highlight'>" + innerHTML.substring(index,index+text.length) + "</span>" + innerHTML.substring(index + text.length);
inputText.innerHTML = innerHTML
}
}
and CSS:
.highlight
{
background-color:yellow;}

<button onclick="highlight('fox')+highlight('jumped')+highlight('fence')">Highlight</button>

Instead of using onclick in your markup, you should try to utilize best practice and bind events through javascript only since it's the most unobtrusive way to attach handlers to DOM elements.
Furthermore you can define the words you want to highlight in an array that you iterate the highlighting code over, like the fiddle below.
(function() {
function highlight() {
var wordsToHighlight = ["fox", "fence", "jumped"];
wordsToHighlight.forEach(function(text) {
inputText = document.getElementById("inputText")
var innerHTML = inputText.innerHTML
var index = innerHTML.indexOf(text);
if (index >= 0) {
innerHTML = innerHTML.substring(0, index) + "<span class='highlight'>" + innerHTML.substring(index, index + text.length) + "</span>" + innerHTML.substring(index + text.length);
inputText.innerHTML = innerHTML
}
});
}
button = document.getElementById('btn-highlight');
button.onclick = highlight;
})();
.highlight {
background-color: yellow;
}
<div id="inputText">The fox quickly jumped over the fence.</div>
<br/>
<button id="btn-highlight">Highlight</button>
Notice the id="btn-highlight" in the markup, and the binding of the highlight function to the click event.

We can pass a delimited string and then split that into an array. You can use any delimiter you want, but I chose a comma. You can then loop through this array to highlight the words.
jsfiddle
<div id="inputText">
The fox quickly jumped over the fence.
</div>
<button onclick="highlight('fox,fence,jumped')">Highlight</button>
<script>
function highlight(text){
var i, index, words = text.split(",");
var inputText = document.getElementById("inputText");
var innerHTML = inputText.innerHTML;
for(i=0;i<words.length;i++){
index = innerHTML.indexOf(words[i]);
if (index >= 0) {
innerHTML = innerHTML.substring(0,index) + "<span class='highlight'>" + innerHTML.substring(index,index+words[i].length) + "</span>" + innerHTML.substring(index + words[i].length);
inputText.innerHTML = innerHTML;
}
}
}
</script>

Better approach will be to use a pre-made dictionary like object:
DEMO and source : JSnippet DEMO
JS:
var dic = {
fox:['fox','jumped','fence'],
cat:['cat','happy']
};
function parse(target) {
var inputText = document.getElementById("inputText");
inputText.innerHTML = inputText.innerHTML.replace(/(<([^>]+)>)/ig,"");
if (typeof dic[target] === 'object')
for (var i=0; i<dic[target].length; i++)
tokenize(dic[target][i]);
}
function tokenize(text) {
var inputText = document.getElementById("inputText");
var inner = inputText.innerHTML;
var index = inner.indexOf(text);
if ( index >= 0 ) {
inner = inner.substring(0,index) +
"<span class='highlight'>" + inner.substring(index, index + text.length) + "</span>" +
inner.substring(index + text.length);
inputText.innerHTML = inner;
}
}

Related

Google Docs Apps Script getBackgroundColor(Offset)

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'));
}

JavaScript: Code says "cannot read property 'indexOf' of undefined" but I can't fix the problem

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/);

Add class to specific multiple SPAN's

I want to add class to multiple SPAN (but not all SPAN). In this case i'm choosing to add class to last 2 SPAN's.
So currently my code is taking a string and then inserting each letter as SPAN in html.
So then i want the code to read the last 2 (or any other amount) of span to add another .class (in this case .blue)
I believe this is part of the code i need to use, but because i'm doing += it add another extra SPAN to html which is causing duplicates.
if (i >= 5) {
html += '<span class="blue blast">' + split[i] + '</span>';
}
Full code here and CodePen:
function myFunction() {
var string = document.querySelector('.title').innerHTML
var split = string.split('');
var html = '';
for (let i = 0; i < split.length; i++) {
html += '<span class="blast">' + split[i] + '</span>';
if (i >= 5) {
html += '<span class="blue blast">' + split[i] + '</span>';
}
}
document.querySelector('.title').innerHTML = html;
}
myFunction()
https://codepen.io/MariusZMM/pen/MZdpNb
I already have jQuery code that does this for me. But i want to learn Vanila JavaScript.
Update: with the help from tymeJV i have updated CodePen with a fix:
https://codepen.io/MariusZMM/pen/pqmwgL
You only want to write the blue letters when i > 5 - so wrap the other portion in an else block
if (i >= 5) {
html += '<span class="blue blast">' + split[i] + '</span>';
} else {
html += '<span class="blast">' + split[i] + '</span>';
}
This is my proposition:
function myFunction(num) {
const splitted = document.querySelector('.title').innerHTML.split('');
const newContent = splitted.map((letter, i) => {
const className = i >= splitted.length - num ? 'blue blast' : 'blast';
return '<span class="'+className+'">' + letter + '</span>';
}).join('');
document.querySelector('.title').innerHTML = newContent;
}
myFunction(3);

Replace brackets to span javascript

I want to manipulate the DOM a bit and need some help.
That's my HTML-Markup:
<span class=“content“> This is my content: {#eeeeee}grey text{/#eeeeee} {#f00000}red text{/#f00000}</span>
That's how it should be:
<span class="content">This is my content: <span style="color:#eeeeee;">grey text</span><span style="color:#f00000;">red text</span></span>
The script should replace the brackets with span tags to change the font-color.
The color should the same that is in the bracket.
My approach:
function regcolor(element) {
var text = element.innerText;
var matches = text.match(/\{(#[0-9A-Fa-f]{6})\}([\s\S]*)\{\/\1\}/gim);
if (matches != null) {
var arr = $(matches).map(function (i, val) {
var input = [];
var color = val.slice(1, 8);
var textf = val.slice(9, val.length - 10);
var html = "<span style=\"color: " + color + ";\">" + textf + "</span>";
input.push(html);
return input;
});
var input = $.makeArray(arr);
$(element).html(input.join(''));
};
But it's not working very well and i'm not feeling good with the code, it looks messy.
And the script looses the content that's not in the brackets("This is my content:").
Anyone a idea?
I've used just a touch of jQuery, but it could easily do without. It's just a regular expression string replacement.
$('.content').each(function() {
var re = /\{(#[a-z0-9]{3,6})\}(.*?)\{\/\1\}/g;
// ^ ^
// $1 $2
this.innerHTML = this.innerHTML.replace(re, function($0, $1, $2) {
return '<span style="color: ' + $1 + '">' + $2 + '</span>';
});
});
I'm using a back-reference to properly match the opening and closing braces.
Update
Could be even shorter:
$('.content').each(function() {
var re = /\{(#[a-z0-9]{3,6})\}(.*?)\{\/\1\}/g,
repl = '<span style="color: $1">$2</span>';
this.innerHTML = this.innerHTML.replace(re, repl);
});
Look mum, no jQuery
var nodes = document.getElementsByClassName('content');
for (var i = 0, n = nodes.length; i < n; ++i) {
var re = /\{(#[a-z0-9]{3,6})\}(.*?)\{\/\1\}/g,
repl = '<span style="color: $1">$2</span>';
nodes[i].innerHTML = nodes[i].innerHTML.replace(re, repl);
}
Use the regex to replace the matches directly:
function regcolor2(element) {
var text = element.html();
var i = 0;
var places = text.replace(/\{(#[0-9A-Fa-f]{6})\}([\s\S]*)\{\/\1\}/gim, function( match ) {
var color = match.slice(1, 8);
var textf = match.slice(9, match.length - 10);
var html = "<span style=\"color: " + color + ";\">" + textf + "</span>";
return html;
});
$(element).html(places);
}
it can be shorter with jquery and this method or syntax
$(function() {
$('.content').html($('.content').text().replace( new RegExp('{(.*?)}(.*?){\/.*?}','g'), '<span style="color:$1">$2</span>'));
});

How to wrap text in span tags except first word with jQuery?

Is it possible to wrap the last words in a string with span tags excluding the first word? So it'd be for example:
var string = 'My super text';
Becomes
My <span>super text</span>
I have this:
var text = string.split(" ");
// drop the last word and store it in a variable
var last = text.pop();
// join the text back and if it has more than 1 word add the span tag
// to the last word
if (text.length > 0) {
return text.join(" ") + " <span>" + last + "</span>";
}
else {
return "<span>" + text.join(" ") + last + "</span>";
}
Which wraps the last word with span tags if it has at least two but not sure how to modify it.
You just need to use text.shift() which will return the first word, instead of text.pop() which returns the last word. Then it will be much easier to accomplish this.
var text= string.split(" ");
// get the first word and store it in a variable
var first = text.shift();
// join the text back and if it has more than 1 word add the span tag
// to the last word
if (text.length > 0) {
return first + " <span>" + text.join(" ") + "</span>";
} else {
return "<span>" + first + "</span>";
}
You could do it with a regular expression.
text = text.replace(/\s(.*)$/, ' <span>$1</span>');
However, you should probably turn the following into a recursive function...
$('body').contents().filter(function() {
return this.nodeType == 3;
}).each(function() {
var node = this;
// Normalise node.
node.data = $.trim(node.data);
node.data.replace(/\s+(.*)\s*$/, function(all, match, offset) {
var chunk = node.splitText(offset);
chunk.parentNode.removeChild(chunk);
var span = document.createElement('span');
span.appendChild(document.createTextNode(' ' + match));
node.parentNode.appendChild(span);
});
});
jsFiddle.
This will allow you to modify text nodes and insert the span elements without messing with serialised HTML.
var space = string.indexOf(' ');
if (space !== -1) {
return string.slice(0,space) + " <span>" + string.slice( space ) + "</span>";
} else {
return "<span>" + string + "</span>";
}
You don't have to split the text, just check if there is a space, and insert a span there.
This code inserts a span after the first space, and if there is no space (idx == -1), the span is put at the beginning of the string:
var idx = string.indexOf(' ');
return string.substr(0, idx + 1) + "<span>" + string.substr(idx + 1) + "</span>";

Categories