make text in html page bold with javascript - javascript

What i have done:
function makeBold(strings) {
var myHTML = document.getElementsByTagName('body')[0].innerHTML;
myHTML = myHTML.replace(strings, '<b>' + strings + '</b>');
document.getElementsByTagName('body')[0].innerHTML = myHTML
}
this code works only for the paces where the texts are free from ant tags
Eg: <p class="ClassName">Some free text without any inner html elements</p>
But for sentences below this the above javascript function is not giving any result
Eg sentence which are not working:
<p class="Aclass"><span class="char-style-override-1">Starting from here, </span><span class="char-style-override-2">text resumes after the span tag</span><span class="char-style-override-1">. again text resumes.</span></p>
What I need
i need a functionality to make the above text bold when i pass that text into my js function. and by text i mean only
Starting from here,text resumes after the span tag. again text resumes.
when i call the above mentioned jas function like this
makeBold('Starting from here,text resumes after the span tag. again text resumes.');
nothing happens, the entire sentence does not gets bold nothing happens, because the js function only looks for the occurrence of that string and makes it bold, in my second example the text is mixed with html tags
so that the above mentioned text will get bold when i call my makebold function.
Please note that i dont have the id for the <p> , what i have is a couple of random strings stored in my db and load a couple of webpages, while doing so i want to bold the sentence/text from the webpage if is matches with my passed string from db
While doing my research i got a code to highlight text given to a js. this js function will select the exact text in the html page which is passed to the js function.
the second eg also works for this code. i.e i can select the exact string from the example by passing it to the function.
function selectText(text) {
if (window.find && window.getSelection) {
document.designMode = "on";
var sel = window.getSelection();
sel.collapse(document.body, 0);
while (window.find(text)) {
document.getElementById("button").blur();
document.execCommand("HiliteColor", false, "yellow");
sel.collapseToEnd();
}
document.designMode = "off";
} else if (document.body.createTextRange) {
var textRange = document.body.createTextRange();
while (textRange.findText(text)) {
textRange.execCommand("BackColor", false, "yellow");
textRange.collapse(false);
}
}
}
I tried to customize it so that instead of selecting the passed text, i tried to make it bold. but coudnt succed.
Please help me in getting this done. I am new to js.

I finally got a solution to your problem that works as you want it to (i. e. the function takes an arbitrary substring and marks anything that fits the substring bold while leaving the rest of the string untouched). If the string passed doesn't match any part of the string that you want to modify, the latter remains untouched.
Here goes (Beware: That JS section got really BIG!):
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test case for making arbitrary text bold</title>
<meta charset="UTF-8">
<script type="application/javascript">
// Takes two strings and attempts to intersect them (i. e. the end of p_str1
// must match the beginning of p_str2). The index into p_str1 is returned.
// If no intersection can be found, -1 is returned.
function intersectStrings(p_str1, p_str2)
{
var l_pos = -1;
do
{
l_pos = p_str1.indexOf(p_str2[0], l_pos + 1);
if(p_str1.substr(l_pos) == p_str2.substr(0, p_str1.length - l_pos))
// If the two substrings match, we found something. Return with the position.
break;
}
while(l_pos != -1);
return l_pos;
}
function makeBold(p_string)
{
var l_elem = document.getElementById('modify');
var l_html = l_elem.innerHTML;
var l_text = l_elem.innerText;
var l_aux = l_html.match(/<.+?>/g);
var l_here = l_text.indexOf(p_string);
var l_before;
var l_middle;
var l_behind;
if(typeof(p_string) != 'string')
throw "invalid argument";
// First of all, see whether or not we have a match at all. If no, we don't
// need to continue with this.
if(l_here == -1)
{
console.error('makeBold: Could not find desired substring ' + p_string + '! Stop...');
return;
}
// Take the plain text and split it into three distinct parts (l_middle is of
// interest for us here).
l_before = l_html.slice(0, l_here);
l_behind = l_html.slice(l_here + l_html.length);
l_middle = l_html.slice(l_here, l_here + l_html.length);
if(l_aux)
{
// If we have a set of markup tags, we need to do some additional checks to
// avoid generating tag soup.
let l_target = new Array();
let l_tag;
let l_nexttag;
let l_this;
let l_endpos = 0;
let l_in_str = false;
let l_start;
while(l_aux.length - 1)
{
l_tag = l_aux.shift();
l_target.push(l_tag);
l_nexttag = l_aux[0];
l_endpos = l_html.indexOf(l_nexttag, 1);
l_this = l_html.slice(l_tag.length, l_endpos);
l_html = l_html.slice(l_endpos);
// Skip the entire rigmarole if there are two adjacent tags!
if(l_tag.length == l_endpos)
continue;
if(!l_in_str)
{
if((l_start = l_this.indexOf(p_string)) != -1)
{
// If we find the entire passed string in a fragment of plain text, we can
// modify that, reassemble everything and exit the loop.
l_before = l_this.slice(0, l_start);
l_behind = l_this.slice(l_start + p_string.length);
l_middle = l_this.slice(l_start, l_start + p_string.length);
l_this = l_before + '<strong>' + l_middle + '</strong>' + l_behind;
l_target.push(l_this);
l_target.push(l_html);
l_html = l_target.join('');
console.info('makeBold: The passed string fit between two tags: Done!');
break;
}
// Take the possibility of having to scan across fragments into account. If
// that is the case, we need to piece things together.
if((l_start = intersectStrings(l_this, p_string)) != -1)
{
// Once we wind up here we have a partial match. Now the piecework starts...
l_before = l_this.slice(0, l_start);
l_middle = l_this.slice(l_start);
l_this = l_before + '<strong>' + l_middle + '</strong>';
l_target.push(l_this);
console.info('makeBold: Found starting point of bold string!');
l_in_str = true;
}
else
{
// Nothing to do: Push the unmodified string.
l_target.push(l_this);
}
}
else
if((l_endpos = intersectStrings(p_string, l_this)) == -1)
{
// We haven't arrived at the end position yet: Push the entire segment with
// bold markers onto the stack.
l_this = '<strong>' + l_this + '</strong>';
l_target.push(l_this);
}
else
{
// We have an end position: Treat this fragment accordingly, wrap everything up
// and exit the loop.
l_behind = l_this.slice(l_endpos + 1);
l_middle = l_this.slice(0, l_endpos + 1);
l_this = '<strong>' + l_middle + '</strong>' + l_behind;
l_target.push(l_this);
l_target.push(l_html);
l_html = l_target.join('');
console.info('makeBold: Found the end part: Done!');
break;
}
}
}
else
l_html = l_before + '<strong>' + l_middle + '</strong>' + l_behind;
l_elem.innerHTML = l_html;
}
</script>
</head>
<body>
<header><h1>Test case for making arbitrary text bold by using JavaScript</h1></header>
<main>
<p id="modify"><span class="char-style-override-1">Starting from here, </span><span class="char-style-override-2">text resumes after the span tag</span><span class="char-style-override-1">. again text resumes.</span></p>
</main>
<script type="application/javascript">
// makeBold('Starting from here, text resumes after the span tag. again text resumes.');
// makeBold('from here, text resumes');
// makeBold('resumes after the span');
makeBold('text resumes after the span tag');
</script>
</body>
</html>
Unfortunately this job couldn't be done with a short section, because you need to take various cases into account that need to be handled individually. The control logic that I have come up with addresses all these concerns.
See the annotations in the JS that I have made for details.

Related

How can I highlight the inner text of an HTML article element by index with just vainilla js?

Let's say I have an HTML document with the following body:
<style>
.highlighted {
color: red;
background-color: yellow;
}
</style>
<article>My text in an element</article>
I have the challenge to style the i letter from the in word inside the <article> tag with javascript, and I'm required to do it by it's index [8].
So far I can only think of starting with this...
<script>
const article = document.querySelector('article').innerText
console.log(article[8]);
</script>
Expected output:
<article>My text <span class="highlighted">i</span>n an element</article>
// Console
>>>> "i"
...although I've never tried anything like this before, so I'm kinda lost with the following steps.
I supose I need to insert a <span> tag by this index, but I'm not sure how I would set the closing </span> tag or update the DOM.
What would be a good way to achieve this kind of styling?
//get text of article
const article = document.querySelector('article').innerText;
//find index of word 'in'
const index = article.indexOf('in');
//opening and closing tags
const openingTag = '<span style="color:red">'
const closingTag = '</span>'
//insert tags into article
const newHTML
= article.slice(0, index)
+ openingTag + 'in' + closingTag
+ article.slice(index + 2);
document.querySelector('article').innerHTML = newHTML;
This code styles the first occurrence of the word "in" by setting the text color to red. If you want to do something else, change the style attribute of the opening tag.
article.slice(0, index) returns everything before the word "in." In your example, this would evaluate to 'My text '. article.slice(index + 2) returns everything after the word "in" because "in" is 2 letters long. In your example, this would evaluated to ' an element'. When all the strings are concatenated together, the result is 'My text <span style="color:red">in</span> an element'.
const HIGHLIGHT_IDX = 8;
const article = document.querySelector('article').innerText;
const words = article.split(' ');
let highlightCheck = words[0].length;
let wordToHighlight = words[0].length >= HIGHLIGHT_IDX && '0';
let wordIdx = 1;
while (!wordToHighlight) {
highlightCheck += 1 + words[wordIdx].length;
if (highlightCheck >= HIGHLIGHT_IDX) {
wordToHighlight = wordIdx;
} else {
wordIdx += 1;
}
}
words[wordToHighlight] =
`<span class="highlight">${words[wordToHighlight]}</span>`;
document.querySelector('article').innerText = words.join(' ');

JavaScript/HTML - Passing onclick button parameter to JavaScript function

I'm very new to JavaScript so I apologize if this question has an extremely obvious answer. What I'm trying to do is pass the name of a text box in HTML to a function in Javascript via an onclick button. The goal of the function is to test a given string and highlight it based on certain parameters (for my testing, it is simply length).
There are multiple weird odds and ends within the functions that I'm aware of and working on, I know the functions work as when I remove the parameters and call the code text box directly, it prints exactly what I expect it to. But I want to be able to pass multiple text boxes without needing a specific function per box.
The code I have is as follows. I've included all of it in case the mistake was made somewhere I didn't expect it to be.
<!DOCTYPE html>
<html>
<head>
<style>
.highlight {
background-color: yellow;
}
</style>
</head>
<body>
<label for="wordOne">Word One</label><br>
<input type="text" id="wordOne" name="wordOne"><br>
// Pass the value for the wordOne textbox to verify function
<button type="button" onclick="verify(wordOne,this)">Check</button><br><br>
<label for="wordTwo">Word Two</label><br>
<input type="text" id="wordTwo" name="wordTwo"><br>
// Pass the value for the wordTwo textbox to verify function
<button type="button" onclick="verify(wordTwo,this)">Check</button><br><br>
<p id="test"></p><br>
<p id="error"></p>
<script>
// Highlights any code in a given line.
function highlight(text,id,begin,end) {
// document.getElementById("error").innerHTML = "TEST";
var inputText = document.getElementById(id);
var innerHTML = inputText.innerHTML;
var index = innerHTML.indexOf(text)+begin;
if (index >= 0) {
innerHTML = innerHTML.substring(0,index) + "<span class='highlight'>" + innerHTML.substring(index,index+text.length) + "</span>" + innerHTML.substring(index + text.length-end);
inputText.innerHTML = innerHTML;
return string;
}
}
function verify(button,el){
var begin=1;
var end=1
var id="test";
var string = document.getElementById(button).value;
var len=string.length;
if(len>5)
{
document.getElementById(id).innerHTML = string +" "+len;
highlight(string,id,begin,end);
}
else
{
document.getElementById(id).innerHTML = string;
}
}
</script>
</body>
</html>
I apologize again if this is extremely obvious but I'm honestly not sure what I'm doing wrong. Thanks in advance for any help!
You can get the name of the textbox by the attribute
var x = document.getElementsByTagName("INPUT")[0].getAttribute("name");
And then use it in your function as
var x = document.getElementsByTagName("INPUT")[0].getAttribute("name");
function highlight(x,id,begin,end) {
// document.getElementById("error").innerHTML = "TEST";
var inputText = document.getElementById(id);
var innerHTML = inputText.innerHTML;
var index = innerHTML.indexOf(text)+begin;
if (index >= 0) {
innerHTML = innerHTML.substring(0,index) + "<span class='highlight'>" + innerHTML.substring(index,index+text.length) + "</span>" + innerHTML.substring(index + text.length-end);
inputText.innerHTML = innerHTML;
return string;
}
}
NOTE : By [0] it means the first one that is the first textbox.

Add a space between each character, but in a method

Hey :) I know a similiar question was asked before, but i just cant get it through. I want to create a method called something like makeMeSpaces, so my h2 text will have a space between each character.. and i might want to use it elsewhere aswell. I have this until now, from the logic point of view:
var text = "hello";
var betweenChars = ' '; // a space
document.querySelector("h1").innerHTML = (text.split('').join(betweenChars));
it also works pretty fine, but i think i want to do
<h2>Hello.makeMeSpaces()</h2>
or something like this
Thank you guys!
If you really want this in a 'reusable function,' you'd have to write your own:
function addSpaces(text) {
return text.split('').join(' ');
}
Then, elsewhere in code, you could call it like so:
var elem = document.querySelector('h2');
elem.innerHTML = addSpaces(elem.innerHTML);
Maybe this is what you want , not exactly what you showed but some what similar
Element.prototype.Spacefy = function() {
// innerText for IE < 9
// for others it's just textContent
var elem = (this.innerText) ? this.innerText : this.textContent,
// replacing HTML spaces (' ') with simple spaces (' ')
text = elem.replace(/ /g, " ");
// here , space = " " because HTML ASCII spaces are " "
space = " ",
// The output variable
output = "";
for (var i = 0; i < text.length; i++) {
// first take a character form element text
output += text[i];
// then add a space
output += space;
};
// return output
this.innerHTML = output;
};
function myFunction() {
var H1 = document.getElementById("H1");
// calling function
H1.Spacefy();
};
<h1 id="H1">
<!-- The tags inside the h1 will not be taken as text -->
<div>
Hello
</div>
</h1>
<br />
<button onclick="myFunction ()">Space-fy</button>
You can also click the button more than once :)
Note :- this script has a flow, it will not work for a nested DOM structure refer to chat to know more
Here is a link to chat if you need to discuss anything
Here is a good codepen provided by bgran which works better

Multiple Line textfile output html

I am trying to output the lines of a textfile to a div in an HTA. The text itself comes up just fine, however the lines do not carry over. Instead, the text is grouped together on one big line. If I print to a msgbox it comes up with correct, separated, lines.
function updateTPtally()
{
var fso, appdir, messagefile, ts, messagetext, line;
fso = new ActiveXObject("Scripting.FileSystemObject");
if (MESSAGE_FILE_NAME7.indexOf("\\") == -1) {
appdir = unescape(fso.GetParentFolderName(location.pathname));
messagefile = fso.BuildPath(appdir, MESSAGE_FILE_NAME7);
} else {
messagefile = MESSAGE_FILE_NAME7;
}
try {
// Open the message-of-the-day file as a TextStream.
ts = fso.OpenTextFile(messagefile, 1);
messagetext = "";
while (! ts.AtEndOfStream) {
line = ts.ReadLine();
// If the line contains text, enclose in <p> element;
// otherwise, construct a blank line with a nonbreaking space.
if (line.length > 0)
line = line.replace(/^(.*)$/, "$1");
else
line = "<p> </p>";
messagetext += line;
}
ts.Close();
}
// Construct an error message if an error occurred.
catch(err) {
messagetext = "<p>Can't display the message of the day.</p>"
+ "<p> </p>"
+ "<p>Error <b>0x" + hex(err.number) + "</b><br />"
+ err.description + "</p>";
}
// Update the innerHTML element of the textarea element with the
document.getElementById("TPtallymemo").innerHTML = messagetext;
}
EDIT:
I have added
line = line.replace(/\n/g, "");
This seems to work, however the first word of the text. This is my textfile:
Hello.
This should be line two. And written all in one line.
This should be line three, and also written on one line.
This is what prints out in my span:
Hello.
This
should be line two. And written all in one line.
This
should be line three, and also written on one line.
You are not enclosing the lines on the text after you replace them. Also, you shouldn't enclose the non-breaking space, as paragraph elements account to be correctly separated from each other.
Just one small final observation: you should call for AtEndOfStream() with the parentheses in your while condition.
messagetext = "";
while (! ts.AtEndOfStream()) {
line = ts.ReadLine();
// If the line contains text, enclose in <p> element;
// otherwise, construct a blank line with a nonbreaking space.
if (line.length > 0)
line = line.replace(/^(.*)$/, "<p>$1</p>");
messagetext += line;
}

How to add custom image tag to pagedown?

I'm attempting to duplicate the original img tag's functionality in custom img tag that will be added to the pagedown converter.
e.g I'm copy the original behavior:
![image_url][1] [1]: http://lolink.com gives <img src="http://lolink.com">
into a custom one:
?[image_url][1] [1]: http://lolink.com gives <img class="lol" src="http://lolink.com">
Looking at the docs the only way to do this is through using the preblockgamut hook and then adding another "block level structure." I attempted doing this and got an Uncaught Error: Recursive call to converter.makeHtml
here's the code of me messing around with it:
converter.hooks.chain("preBlockGamut", function (text, dosomething) {
return text.replace(/(\?\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, function (whole, inner) {
return "<img src=" + dosomething(inner) + ">";
});
});
I'm not very experienced with hooks and everything so what would I do to fix it? Thanks.
UPDATE: found out that _DoImages runs after prespangamut, will use that instead of preblockgamut
Figured it out! The solution is very clunky and involves editing the source code because I am very bad at regex and the _DoImage() function uses a lot of internal functions only in the source.
solution:
All edits will be made to the markdown.converter file.
do a ctrl+f for the _DoImage function, you will find that it is named in two places, one in the RunSpanGamut and one defining the function. The solution is simple, copy over the DoImage function and related stuff to a new one in order to mimic the original function and edit it to taste.
next to DoImage function add:
function _DoPotatoImages(text) {
text = text.replace(/(\?\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writePotatoImageTag);
text = text.replace(/(\?\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writePotatoImageTag);
return text;
}
function writePotatoImageTag(wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
var whole_match = m1;
var alt_text = m2;
var link_id = m3.toLowerCase();
var url = m4;
var title = m7;
if (!title) title = "";
if (url == "") {
if (link_id == "") {
link_id = alt_text.toLowerCase().replace(/ ?\n/g, " ");
}
url = "#" + link_id;
if (g_urls.get(link_id) != undefined) {
url = g_urls.get(link_id);
if (g_titles.get(link_id) != undefined) {
title = g_titles.get(link_id);
}
}
else {
return whole_match;
}
}
alt_text = escapeCharacters(attributeEncode(alt_text), "*_[]()");
url = escapeCharacters(url, "*_");
var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
title = attributeEncode(title);
title = escapeCharacters(title, "*_");
result += " title=\"" + title + "\"";
result += " class=\"p\" />";
return result;
}
if you look at the difference between the new _DoPotatoImages() function and the original _DoImages(), you will notice I edited the regex to have an escaped question mark \? instead of the normal exclamation mark !
Also notice how the writePotatoImageTag calls g_urls and g_titles which are some of the internal functions that are called.
After that, add your text = _DoPotatoImages(text); to runSpanGamut function (MAKE SURE YOU ADD IT BEFORE THE text = _DoAnchors(text); LINE BECAUSE THAT FUNCTION WILL OVERRIDE IMAGE TAGS) and now you should be able to write ?[image desc](url) along with ![image desc](url)
done.
The full line (not only the regex) in Markdown.Converter.js goes like this:
text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeImageTag);
so check the function writeImageTag. There you can see how the regex matching text is replaced with a full img tag.
You can change the almost-last line before its return from
result += " />";
to
result += ' class="lol" />';
Thanks for the edit to the main post.
I see what you mean now.
It is a bit weird how it uses empty capture groups to specify tags, but if it works, it works.
It looks like you would need to add on an extra () onto the regex string, then specify m8 as a new extra variable to be passed into the function, and then specify it as class = m8; like the other variables at the top of the function.
Then where it says var result =, instead of class =\"p\" you would just put class + title=\"" + .......

Categories