if text contains '#' change color of '#' - javascript

I'm looking for a solution for my problem.
I have a paragraph with some text from a twitter tweet. Now I would like to change all the '#'s to a color.
This is what I do to look for '#'s in my text:
if (status.indexOf("#") >= 0)
{
}
But now how can I change the color of the #? (Add a span and class or something ...)
The status is a variable with content for ex. like this:
Dita Von Teese draagt geprinte 3D-jurk <a target="_blank" href="http://t.co/s2y6b21S0I">http://t.co/s2y6b21S0I</a> via #<a target="_blank" href="http://twitter.com/Knackweekend">Knackweekend</a>

Without seeing your HTML, the best I can offer is a simple replace, and I'm assuming that status is a jQuery collection of HTML elements/nodes:
status.html(function(i,h){
return h.replace(/#/g,'<span class="atSign">#</span>');
});
Coupled with the CSS:
.atSign {
color: #f90;
}
Updated, since status appears to be a string (from the comments, below):
var status = '<a target="_blank" href="t.co/s2y6b21S0I">http://t.co/s2y6b21S0I</a>; via #<a target="_blank" href="twitter.com/Knackweekend">Knackweekend</a>',
newStatus = status.replace(/#/g,'<span class="atSign">#</span>');
console.log(newStatus);
JS Fiddle demo.
To colour the # and the following a element, with CSS:
.atSign,
.atSign + a {
color: #f90;
}
JS Fiddle demo.
To wrap the # and the following a element within the span:
var status = '<a target="_blank" href="t.co/s2y6b21S0I">http://t.co/s2y6b21S0I</a>; via #<a target="_blank" href="twitter.com/Knackweekend">Knackweekend</a>',
newStatus = status.replace(/(#.+<\/a>)/g,function(a){
return '<span class="atSign">' + a + '</span>';
});
console.log(newStatus);
JS Fiddle demo.
References:
html().
JavaScript regular expressions.
String.replace().

You can insert a new span on same index and remove the existing item in that index.

Yes, you will need to wrap the # in a span with a class so that you can change the colour with CSS.
You could manipulate the DOM like this
CSS
.atSign {
color: #f90;
}
HTML
<div id="status">Some # text <div>that # contains#what</div>we will# demonstrate</div>
Javascript
/*jslint maxerr: 50, indent: 4, browser: true */
(function () {
"use strict";
function walkTheDOM(node, func) {
func(node);
node = node.firstChild;
while (node) {
walkTheDOM(node, func);
node = node.nextSibling;
}
}
function getTextNodes(element) {
var nodes = [];
walkTheDOM(element, function (node) {
if (node.nodeType === 3) {
nodes.push(node);
}
});
return nodes;
}
function highlight(element, string, classname) {
var nodes = getTextNodes(element),
length = nodes.length,
stringLength = string.length,
i = 0,
index,
text,
newContent,
span,
node;
while (i < length) {
node = nodes[i];
newContent = document.createDocumentFragment();
text = node.nodeValue;
index = text.indexOf(string);
while (index !== -1) {
newContent.appendChild(document.createTextNode(text.slice(0, index)));
text = text.slice(index + stringLength);
span = document.createElement("span");
span.className = classname;
span.appendChild(document.createTextNode(string));
newContent.appendChild(span);
index = text.indexOf(string);
}
newContent.appendChild(document.createTextNode(text));
node.parentNode.replaceChild(newContent, node);
i += 1;
}
}
highlight(document.getElementById("status"), "#", "atSign");
}());
On jsfiddle
How can you use this with your HTML string you ask?
Javascript
var div = document.createElement("div"),
html;
div.innerHTML = 'Dita Von Teese draagt geprinte 3D-jurk <a target="_blank" href="http://t.co/s2y6b21S0I">http://t.co/s2y6b21S0I</a> via #<a target="_blank" href="http://twitter.com/Knackweekend">Knackweekend</a>';
highlight(div, "#", "atSign");
html = div.innerHTML;
console.log(html);
Output
Dita Von Teese draagt geprinte 3D-jurk <a target="_blank" href="http://t.co/s2y6b21S0I">http://t.co/s2y6b21S0I</a> via <span class="atSign">#</span><a target="_blank" href="http://twitter.com/Knackweekend">Knackweekend</a>
On jsfiddle
And no jquery or regexs in sight :)

Related

wrapping keywords in hyperlinks - replacement takes place infinitely many times

Trying to wrap specific keywords in hyperlinks, but replacements take place inifitely many times:
var replacements = [
{ txt: 'magicFunction', link: 'https://www.example.com/doc/api/magicFunction.htm' },
];
$(function() {
$.each(replacements,
function() {
var searchWord = this.txt;
var link = this.link;
$('body:contains("' + searchWord + '")').each(function() {
var newHtml = $(this).html().replace(searchWord,
'' + searchWord + '');
$(this).html(newHtml);
});
}
);
});
I'd need a condition around the matching part to say that if is already wrapped in a hyperlink then don't do anything, or some other workaround.
How can it be fixed?
https://jsfiddle.net/m4j28s13/
You can select all nodes in the body but exclude all <a> elements:
$('body *:not(a):contains("' + searchWord + '")').each(...)
See proof-of-concept example:
var replacements = [{
txt: 'magicFunction',
link: 'https://www.example.com/doc/api/magicFunction.htm'
}, ];
$.each(replacements,
function() {
var searchWord = this.txt;
var link = this.link;
$('body *:not(a):contains("' + searchWord + '")').each(function() {
var newHtml = $(this).html().replace(searchWord,
'' + searchWord + '');
$(this).html(newHtml);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>This sentence mentions magicFunction() in a paragraph.</p>
<p>The following code block (from API reference) mentions it too:</p>
<code class="code-block hljs lua">if a==0 then
h=magicFunction('foo')
end</code>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.6.0/highlight.min.js"></script>
Update: to handle cases where an <a> element may contain nested tags that contain the replacement word, another solution will be to actually replace :contains with a custom guard clause in the callback, which will check if the child textNodes contain the keyword. If it does, then perform the replacement:
var replacements = [{
txt: 'magicFunction',
link: 'https://www.example.com/doc/api/magicFunction.htm'
}, ];
$.each(replacements,
function() {
var searchWord = this.txt;
var link = this.link;
$('*:not(a, script)').each(function() {
const textContent = $(this).contents().filter(function() {
return this.nodeType === Node.TEXT_NODE;
}).text();
if (textContent.match(searchWord)) {
var newHtml = $(this).html().replace(searchWord,
'' + searchWord + '');
$(this).html(newHtml);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>This sentence mentions magicFunction() in a paragraph.</p>
<p>The following code block (from API reference) mentions it too:</p>
<code class="code-block hljs lua">if a==0 then
h=magicFunction('foo')
end</code>
<p>This mention is already linked (should not be linked again): <a class="postlink" href="//www.example2.com/doc/api/magicFunction"><code style="display:inline">magicFunction</code></a></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.6.0/highlight.min.js"></script>

Twitter API - filter out #, # and other links

I'm using the Twitter API to get top 5 tweets for my app. I need to highlight, or link parts of the tweets differently. Ex, #'s will be orange, #'s will be red and clickable, etc...
From their API, they offer user_timeline endpoint:
https://dev.twitter.com/rest/reference/get/statuses/user_timeline
But the tweets object's text returns with those special characters embedded within it. I don't see options to pull out those #, # and href from the object:
Tweets object:
{
...
text: "This is some text #tagName that I'd like to #parse here https://t.co/m9Addr4IlS",
...
}
While I can write my own string parser to look for those things, is there something the Twitter API offers to handle this?
EDIT: <tweets> is an Angular directive that ng-repeats over my tweets from ModulesService. replace doesn't seem to be appending the DOM tags
scope.getTweets = function() {
ModulesService.getTweets().success(function(res) {
if (res && Array.isArray(res)) {
scope.tweets = parseTweets(res);
}
});
};
scope.getTweets();
var parseTweets = function (tweets) {
tweets.forEach(function (tweet) {
tweet.text.replace(/(#[^ ]+)/g, '<a class="user">$1</a>').
replace(/(#[^ ]+)/g, '<span class="hash">$1</span>').
replace(/(https?:\/\/[^ ]+)/g, '$1');
console.log('tweet!', tweet.text); //does not contain altered HTML
});
return tweets;
};
HTML:
<div ng-repeat="tweet in tweets" class="post-body clearfix">
{{tweet.text}}
</div>
recommended solution
The library twitter-text does the work for you.
As per their examples:
autolink
var twitter = require('twitter-text')
twitter.autoLink(twitter.htmlEscape('#hello < #world >'))
extract entities
var usernames = twttr.txt.extractMentions("Mentioning #twitter and #jack")
// usernames == ["twitter", "jack"]
Using that solution will save you from re-inventing the wheel and will provide you with a stable working code :)
alternative
Inside the tweet object that you receive from the user_timeline API endpoint, the entities property stores the list of urls, hashtags and mentions included inside the tweet. These contain the text content as well as the position (start / end character indices) of each entity.
Example hashtag entity:
"entities": {
"hashtags": [
"text": "pleaseRT"
"indices": [
6,
13
]
]
cf Entities documentation for more info.
Try:
var text = "This is some text #tagName that I'd like to #parse here https://t.co/m9Addr4IlS";
var div = document.getElementsByTagName('div')[0];
div.innerHTML = text.replace(/(#[^ ]+)/g, '<a class="user">$1</a>').
replace(/(#[^ ]+)/g, '<span class="hash">$1</span>').
replace(/(https?:\/\/[^ ]+)/g, '$1');
.hash { color: orange; }
.user { color: red; }
<div></div>
Loop over the returned tweets and modify the tweet text according to some conditions:
returnValues.forEach(function (tweet) {
if (tweet.text.search(/#|#/ig) > -1) {
var words = obj.text.split(' ');
var parsedTweetText = words.map(function (word) {
if (word.indexOf('#') === 0)
return '<span class="hashtag">' + word + '</span>';
else if (word.indexOf('#') === 0)
return '<span class="at-user">' + word + '</span>';
else
return word;
}).join(' ');
tweet.text = parsedTweetText;
}
});

JavaScript convert string hrefs into onClicks

I've got strings with multiple standard links like
Name of Link
and I'm trying to turn them into
<a onClick="myFunc('http://example.com','Name of Link')">Name of Link</a>
or even just:
<a onClick="myFunc('http://example.com')">Name of Link</a>
would be great if the former was unnecessarily difficult. The links are being dynamically inserted into the DOM so event handlers won't do.
You need event handlers that prevents the default action and get the href
var anchors = document.getElementsByTagName('a');
for (var i=anchors.length; i--;) {
anchors[i].addEventListener('click', func, false);
}
function func(e) {
e.preventDefault();
var href = this.getAttribute('href'),
text = this.innerText;
myFunc(href, text);
}
FIDDLE
If you have to work with strings, you can do something like this
var str = 'Name of Link 1<br />Name of Link 2<br />Name of Link 3<br />Name of Link 4';
var parser = new DOMParser();
var doc = parser.parseFromString(str, "text/html");
var anchors = doc.getElementsByTagName('a');
for (var i=anchors.length; i--;) {
var href = anchors[i].getAttribute('href'),
text = anchors[i].innerText;
anchors[i].setAttribute('onclick', "myFunc('"+href+"', '"+text+"')");
anchors[i].removeAttribute('href');
}
str = doc.body.innerHTML;
document.body.innerHTML = str;
function myFunc(href, text) {
alert(href + ' - ' + text);
}
You can do like this
HTML
<a href="http://example.com" onclick="myFunction(this.href,this.textContent)">
My link
</a>
JS
function myFunction(getAttr,text){
console.log(getAttr,text);
}
EXAMPLE
EDIT
if you are looking to prohibit href action then you have to use
event.preventDefault();
Updated JS
function myFunction(event,getAttr,text){
event.preventDefault();
console.log(getAttr,text);
}
UPDATED JSFIDDLE
Append your string in a temporary element and manipulate it as explained by adeneo
Try this:
var str = 'Name of Link';
var elem = document.createElement('div');
elem.innerHTML = str;
var targetEleme = elem.getElementsByTagName('a')[0];
targetEleme.addEventListener('click', function(e) {
e.preventDefault();
var href = this.getAttribute('href'),
text = this.innerText;
myFunc(href, text);
});
document.body.appendChild(targetEleme);
function myFunc(href, text) {
alert('HREF: ' + href + ' TEXT: ' + text);
}
Fiddle here

Extract the text out of HTML string using JavaScript

I am trying to get the inner text of HTML string, using a JS function(the string is passed as an argument). Here is the code:
function extractContent(value) {
var content_holder = "";
for (var i = 0; i < value.length; i++) {
if (value.charAt(i) === '>') {
continue;
while (value.charAt(i) != '<') {
content_holder += value.charAt(i);
}
}
}
console.log(content_holder);
}
extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>");
The problem is that nothing gets printed on the console(*content_holder* stays empty). I think the problem is caused by the === operator.
Create an element, store the HTML in it, and get its textContent:
function extractContent(s) {
var span = document.createElement('span');
span.innerHTML = s;
return span.textContent || span.innerText;
};
alert(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>"));
Here's a version that allows you to have spaces between nodes, although you'd probably want that for block-level elements only:
function extractContent(s, space) {
var span= document.createElement('span');
span.innerHTML= s;
if(space) {
var children= span.querySelectorAll('*');
for(var i = 0 ; i < children.length ; i++) {
if(children[i].textContent)
children[i].textContent+= ' ';
else
children[i].innerText+= ' ';
}
}
return [span.textContent || span.innerText].toString().replace(/ +/g,' ');
};
console.log(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>. Nice to <em>see</em><strong><em>you!</em></strong>"));
console.log(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>. Nice to <em>see</em><strong><em>you!</em></strong>",true));
One line (more precisely, one statement) version:
function extractContent(html) {
return new DOMParser()
.parseFromString(html, "text/html")
.documentElement.textContent;
}
textContext is a very good technique for achieving desired results but sometimes we don't want to load DOM. So simple workaround will be following regular expression:
let htmlString = "<p>Hello</p><a href='http://w3c.org'>W3C</a>"
let plainText = htmlString.replace(/<[^>]+>/g, '');
use this regax for remove html tags and store only the inner text in html
it shows the HelloW3c only check it
var content_holder = value.replace(/<(?:.|\n)*?>/gm, '');
Try This:-
<!DOCTYPE html>
<html>
<body>
<script type="text/javascript">
function extractContent(value){
var div = document.createElement('div')
div.innerHTML=value;
var text= div.textContent;
return text;
}
window.onload=function()
{
alert(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>"));
};
</script>
</body>
</html>
For Node.js
This will use the jsdom library, since node.js doesn't have dom features as in browser.
import * as jsdom from "jsdom";
const html = "<h1>Testing<h1>";
const text = new jsdom.JSDOM(html).window.document.textContent;
console.log(text);
Use match() function to bring out HTML tags
const text = `<div>Hello World</div>`;
console.log(text.match(/<[^>]*?>/g));
You could temporarily write it out to a block level element that is positioned off the page .. some thing like this:
HTML:
<div id="tmp" style="position:absolute;top:-400px;left:-400px;">
</div>
JavaScript:
<script type="text/javascript">
function extractContent(value){
var div=document.getElementById('tmp');
div.innerHTML=value;
console.log(div.children[0].innerHTML);//console out p
}
extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>");
</script>
Using jQuery, in jQuery we can add comma seperated tags.
var readableText = [];
$("p, h1, h2, h3, h4, h5, h6").each(function(){
readableText.push( $(this).text().trim() );
})
console.log( readableText.join(' ') );
you need array to hold values
function extractContent(value) {
var content_holder = new Array();
for(var i=0;i<value.length;i++) {
if(value.charAt(i) === '>') {
continue;
while(value.charAt(i) != '<') {
content_holder.push(value.charAt(i));
console.log(content_holder[i]);
}
}
}
}extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>");

Append element in tag right before contents with Javascript

I'll illustrate with an example: I need to convert the following html with javascript
<a>Text 1</a>
<a>Text 2</a>
<a>Text 3</a>
...
to code
<a><input/>Text 1</a>
<a><input/>Text 2</a>
<a><input/>Text 3</a>
...
I don't have a clue how to achieve that with createElement, appendChild or insertBefore/After.
It's not that hard :)
​(function() {
var links = document.getElementsByTagName("a"),
input,
i = links.length;
while (i--) {
input = document.createElement("input");
links[i].insertBefore(input, links[i].firstChild);
}
}())​
.insertBefore, and .firstChild
You could insert your new input element before the first child of each anchor:
// Gather up a reference to all anchors
var anchors = document.getElementsByTagName("a"), inputEl;
// Cycle over all of them
for ( var i = 0; i < anchors.length; i++ ) {
// Create a new input field
inputEl = document.createElement("input");
// Insert it before the first child of the anchor
anchors[i].insertBefore( inputEl, anchors[i].firstChild );
}
Demo: http://jsbin.com/ibugul/edit#javascript,html
Regular Expression
Or you could use the replace method:
var a = document.getElementsByTagName("a"),
c = a.length;
while ( c-- ) {
a[c].innerHTML = a[c].innerHTML.replace( /(.*)/, function( s, c2 ){
return "<input />" + c2;
});
}
Modify .innerHTML
var a = document.getElementsByTagName("a"),
c = a.length;
while ( c-- ) a[c].innerHTML = "<input />" + a[c].innerHTML;
jQuery
If you're already using jQuery on your site, you could use that to make this even shorter:
$("a").prepend("<input />");
Note, it is not worth including the library just for this.

Categories

Resources