Highlight a text from html document - javascript

I am new to web development. Here, I want to highlight the text from the html document. I am using text-angular for showing the html document. Let's say this is a document:
<!DOCTYPE html>
<html>
<head>
<title>Example of Text Highlight</title>
<style type="text/css" media="screen">
.highlight{ background: #D3E18A;}
.light{ background-color: yellow;}
</style>
</head>
<body>
<div id="testDocument">
<p style="padding:0;color:#000000;font-size:12pt;line-height:1.0;margin-right:0;margin-left:72pt;text-indent:-72pt;font-family:"Times New Roman";margin-top:0;orphans:2;margin-bottom:0;widows:2;text-align:justify"><span style="vertical-align:baseline;font-size:11pt;font-family:"Calibri";font-weight:700">Description: </span><span style="color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Calibri";font-style:normal">Developed web app for add management.</span></p>
<span style="vertical-align:baseline;font-size:11pt;font-family:"Calibri";font-weight:700">Contribution: </span><span style="vertical-align:baseline;font-size:11pt;font-family:"Calibri";font-weight:400">It was the internal use web app for the <br>we developed the app for the add management for the. </span>
</div>
</body>
</html>
This whole document is having a div with id ="textcontent".
This is a Html document, which represents it
Description: Developed web app for add management.
Contribution: It was the internal use web app for the
we developed the app for the add management for the
Here, I am able to highlight a single word from this text. what I want is to highlight a whole text like from Description to the word, which I am getting as an input. I tried Different options like,
Currently, I have the following code with which it highlights the text which is in one span. But if the half of highlighting text is in one span and half is in another span it it is not working.
Code is like:
var InstantSearch = {
"highlight": function (container, highlightText)
{
var internalHighlighter = function (options)
{
var id = {
container: "container",
tokens: "tokens",
all: "all",
token: "token",
className: "className",
sensitiveSearch: "sensitiveSearch"
},
tokens = options[id.tokens],
allClassName = options[id.all][id.className],
allSensitiveSearch = options[id.all][id.sensitiveSearch];
function checkAndReplace(node, tokenArr, classNameAll, sensitiveSearchAll)
{
var nodeVal = node.nodeValue, parentNode = node.parentNode,
i, j, curToken, myToken, myClassName, mySensitiveSearch,
finalClassName, finalSensitiveSearch,
foundIndex, begin, matched, end,
textNode, span, isFirst;
for (i = 0, j = tokenArr.length; i < j; i++)
{
curToken = tokenArr[i];
myToken = curToken[id.token];
myClassName = curToken[id.className];
mySensitiveSearch = curToken[id.sensitiveSearch];
finalClassName = (classNameAll ? myClassName + " " + classNameAll : myClassName);
finalSensitiveSearch = (typeof sensitiveSearchAll !== "undefined" ? sensitiveSearchAll : mySensitiveSearch);
isFirst = true;
while (true)
{
if (finalSensitiveSearch)
foundIndex = nodeVal.indexOf(myToken);
else
foundIndex = nodeVal.toLowerCase().indexOf(myToken.toLowerCase());
if (foundIndex < 0)
{
if (isFirst)
break;
if (nodeVal)
{
textNode = document.createTextNode(nodeVal);
parentNode.insertBefore(textNode, node);
} // End if (nodeVal)
parentNode.removeChild(node);
break;
} // End if (foundIndex < 0)
isFirst = false;
begin = nodeVal.substring(0, foundIndex);
matched = nodeVal.substr(foundIndex, myToken.length);
if (begin)
{
textNode = document.createTextNode(begin);
parentNode.insertBefore(textNode, node);
} // End if (begin)
span = document.createElement("span");
span.className += finalClassName;
span.appendChild(document.createTextNode(matched));
parentNode.insertBefore(span, node);
nodeVal = nodeVal.substring(foundIndex + myToken.length);
} // Whend
} // Next i
}; // End Function checkAndReplace
function iterator(p)
{
if (p === null) return;
var children = Array.prototype.slice.call(p.childNodes), i, cur;
if (children.length)
{
for (i = 0; i < children.length; i++)
{
cur = children[i];
if (cur.nodeType === 3)
{
checkAndReplace(cur, tokens, allClassName, allSensitiveSearch);
}
else if (cur.nodeType === 1)
{
iterator(cur);
}
}
}
}; // End Function iterator
iterator(options[id.container]);
} // End Function highlighter
;
internalHighlighter(
{
container: container
, all:
{
className: "highlighter"
}
, tokens: [
{
token: highlightText
, className: "highlight"
, sensitiveSearch: false
}
]
}
); // End Call internalHighlighter
} // End Function highlight
};
function TestTextHighlighting(highlightText)
{
var container = document.getElementById("textcontent");
InstantSearch.highlight(container, highlightText);
}
How can I handle this?

Indeed i have catched little bit about your question, but the core of your question is about how to highlight some text that called paragraph. Like this ?
Maybe you can try this answer , this is using jquery.mark and you able to highlights the text that you want by the keywords. i hope it will helpful for you.
Here for the simple usage:
$(".context").mark("keyword");

Related

Javascript - a problem with a two-step text input word conversion

Here I am making a word conversion tool which changes a certain word X into Y, or X to Y to Z by using javascript.
Progress: HERE
Here is the entire javascript:
var conversion = {
"one":"two",
};
var conversion2 = {
"two":"three",
};
var maxLength = Object.keys(conversion)
.reduce((a, b) => a.length > b.length ? a : b)
.length;
function convert (text) {
var converted = "";
var cur = 0;
while (cur < text.length) {
var testedPhoneme;
var symbol = undefined;
for (var length = maxLength; length > 0; length --) {
testedPhoneme = text.substr(cur, length);
if (conversion[testedPhoneme]) {
symbol = conversion[testedPhoneme];
break; // stop the loop
}
}
if (symbol) {
converted += symbol;
cur += testedPhoneme.length;
}
else {
converted += text[cur]
cur++;
}
}
return converted
}
var maxLength2 = Object.keys(conversion2)
.reduce((a, b) => a.length > b.length ? a : b)
.length;
function convert2 (text) {
var converted2 = "";
var cur2 = 0;
while (cur2 < text.length) {
var testedPhoneme2;
var symbol2 = undefined;
for (var length = maxLength2; length > 0; length --) {
testedPhoneme2 = text.substr(cur2, length);
if (conversion2[testedPhoneme2]) {
symbol2 = conversion2[testedPhoneme2];
break; // stop the loop
}
}
if (symbol2) {
converted2 += symbol2;
cur2 += testedPhoneme2.length;
}
else {
converted2 += text[cur2]
cur2++;
}
}
return converted2
}
function onInputTextChange(txt) {
var outputTextareaElem = document.getElementById("output_textarea");
var div = document.createElement("div");
var outputHtmlEntities = convert(txt);
div.innerHTML = outputHtmlEntities;
outputTextareaElem.value = div.innerText;
}
function onOutputTextChange(txt) {
var outputTextareaElem2 = document.getElementById("output_textarea2");
var div = document.createElement("div");
var outputHtmlEntities2 = convert2(txt);
div.innerHTML = outputHtmlEntities2;
outputTextareaElem2.value = div.innerText;
}
In the page that I made so far, there are three <textarea>s; Input, Output and Output2.
Currently, thanks to this piece of code;
var conversion = {
"one":"two",
};
var conversion2 = {
"two":"three",
};
If one is typed into Input, Output renders two. If two is manually typed into Output, three gets rendered in Output2.
Here is the problem, I want to render three in Output2 only through typing one into Input, but a direct two-step conversion seems unavailable yet. In other words, Input > Output (one > two) and Output > Output2 (two > three) conversion is available, but Input > Output > Output2 (one > two > three) is unavailable.
What needs to be done to solve this? Any help would be appreciated.
Ok, not exactly what you asked, but I could do something that works
Here is the example : https://jsfiddle.net/alias_gui3/8knw57u0/94/
how to use it :
to add new characters OR new languages/scripts
just complete the dictionnary :
var dictionnary = [
{
latin: "u",
japanese: "う",
emoji: "👋"
// add any script for every characters
},{
latin: "ku",
japanese: "く",
emoji: "👀"
},{
latin: "tsu",
japanese: "つ",
emoji: "🤖"
}
// add any character with the same format
]
to add new textareas :
give your textarea a recognizable id (eg. id="cyrillic")
then connect your textarea with this method:
// connect your textareas below !!
addTextArea(
document.querySelector("#latin"),
"latin"
);
addTextArea(
document.querySelector("#japanese"),
"japanese"
);
addTextArea(
document.querySelector("#emoji"),
"emoji"
);
// add new textarea with a new language here
then all the connections are done, you can edit all your textareas, if they recognise a character they will translate it in all the other textareas
full code
var dictionnary = [
{
latin: "u",
japanese: "う",
emoji: "👋"
// add any script for every characters
},{
latin: "ku",
japanese: "く",
emoji: "👀"
},{
latin: "tsu",
japanese: "つ",
emoji: "🤖"
}
// add any character with the same format
]
// calculate the max length for each language :
var max = {}
dictionnary.forEach(
char => {
Object.keys(char).forEach(script => {
max[script] = max[script]
? char[script].length > max[script]
? char[script].length
: max[script]
: char[script].length
})
}
)// now max contains the maximum length of sequence
// for each language
function findSymbol (
originSymbol,
originScript,
destinationScript
) {
for (var i = 0; i < dictionnary.length; i++) {
var char = dictionnary[i];
if (char[originScript] === originSymbol) {
return char[destinationScript]
}
}
return false // if not found
}
function translate (
text,
originScript,
destinationScript
) {
var cur = 0;
var translated = "";
var maxLength = max[originScript]
while (cur < text.length) {
var testedPhoneme;
var symbol = false;
for (var length=maxLength; length > 0; length--) {
testedPhoneme = text.substr(cur, length);
symbol = findSymbol(
testedPhoneme,
originScript,
destinationScript
)
if (symbol) {
break; // stop the loop
}
}
if (symbol) {
translated += symbol;
cur += testedPhoneme.length;
}
else {
translated += text[cur];
cur++;
}
}
return translated
}
var textareas = []; // the list of your textareas
function addTextArea(element, originScript) {
textareas.push({
element: element,
script: originScript
})
element.addEventListener("input", function (e) {
signalTextChanged(element, originScript)
});
}
function signalTextChanged (
originElement,
originScript
) {
var originText = originElement.value;
textareas.forEach(function (textarea) {
if (textarea.element !== originElement) {
var translated = translate(
originText,
originScript,
textarea.script
)
textarea.element.value = translated;
}
})
}
// connect your textareas below !!
addTextArea(
document.querySelector("#latin"),
"latin"
);
addTextArea(
document.querySelector("#japanese"),
"japanese"
);
addTextArea(
document.querySelector("#emoji"),
"emoji"
);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript">
</script>
</head>
<body>
<center>
<h1>Latin to foreign script converter 3</h1>
<p>type in u, ku, tsu in the FIRST panel</p>
<textarea
id="latin"
autofocus=""
placeholder="type text in latin ! (u ku or tsu)"
rows="10"
style="width:300px"></textarea>
<textarea
id="japanese"
rows="10"
placeholder="type text in japanese !"
style="width:300px"></textarea>
<textarea
id="emoji"
rows="10"
placeholder="type text in emojis !!"
style="width:300px"></textarea>
</center>
</center>
</body>
</html>
I'm not sure if I fully understand what you're trying to achieve here
There are some duplications in your code, what if you'll have 10 fields for output, will you create a special function for each of them?
Try to simplify things.
One way would be to loop through all of your lists as follows:
Put all your conversation in a list
var lists = [conversion, conversion2];
Add isInNextList function to check if your text is a key in the next list
function isInNextList(index, key) {
if (lists.length < index) {
return false;
}
return Object.keys(lists[index]).includes(key);
}
change your onInputTextChange function as follow:
function onInputTextChange(txt) {
var index = 0;
var text = txt;
while (isInNextList(index, text)) {
var outputTextareaElem = document.getElementById(
'output_textarea_' + index
);
var div = document.createElement('div');
text = lists[index][text]; //next key
index++;
div.innerHTML = text;
outputTextareaElem.value = div.innerText;
}
}
change your output textarea's ids to contain the index
id="output_textarea_0"
id="output_textarea_1"
There are other improvements that can be made like:
Creating the output fields dynamically,
Clear output fields etc.

How to add CSS styles via JavaScript at runtime? [duplicate]

I need to create a CSS stylesheet class dynamically in JavaScript and assign it to some HTML elements like - div, table, span, tr, etc and to some controls like asp:Textbox, Dropdownlist and datalist.
Is it possible?
It would be nice with a sample.
Here is an option:
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.cssClass { color: #f00; }';
document.getElementsByTagName('head')[0].appendChild(style);
document.getElementById('someElementId').className = 'cssClass';
<div id="someElementId">test text</div>
Found a better solution, which works across all browsers.
Uses document.styleSheet to add or replace rules. Accepted answer is short and handy but this works across IE8 and less too.
function createCSSSelector (selector, style) {
if (!document.styleSheets) return;
if (document.getElementsByTagName('head').length == 0) return;
var styleSheet,mediaType;
if (document.styleSheets.length > 0) {
for (var i = 0, l = document.styleSheets.length; i < l; i++) {
if (document.styleSheets[i].disabled)
continue;
var media = document.styleSheets[i].media;
mediaType = typeof media;
if (mediaType === 'string') {
if (media === '' || (media.indexOf('screen') !== -1)) {
styleSheet = document.styleSheets[i];
}
}
else if (mediaType=='object') {
if (media.mediaText === '' || (media.mediaText.indexOf('screen') !== -1)) {
styleSheet = document.styleSheets[i];
}
}
if (typeof styleSheet !== 'undefined')
break;
}
}
if (typeof styleSheet === 'undefined') {
var styleSheetElement = document.createElement('style');
styleSheetElement.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(styleSheetElement);
for (i = 0; i < document.styleSheets.length; i++) {
if (document.styleSheets[i].disabled) {
continue;
}
styleSheet = document.styleSheets[i];
}
mediaType = typeof styleSheet.media;
}
if (mediaType === 'string') {
for (var i = 0, l = styleSheet.rules.length; i < l; i++) {
if(styleSheet.rules[i].selectorText && styleSheet.rules[i].selectorText.toLowerCase()==selector.toLowerCase()) {
styleSheet.rules[i].style.cssText = style;
return;
}
}
styleSheet.addRule(selector,style);
}
else if (mediaType === 'object') {
var styleSheetLength = (styleSheet.cssRules) ? styleSheet.cssRules.length : 0;
for (var i = 0; i < styleSheetLength; i++) {
if (styleSheet.cssRules[i].selectorText && styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase()) {
styleSheet.cssRules[i].style.cssText = style;
return;
}
}
styleSheet.insertRule(selector + '{' + style + '}', styleSheetLength);
}
}
Function is used as follows.
createCSSSelector('.mycssclass', 'display:none');
Short answer, this is compatible "on all browsers" (specifically, IE8/7):
function createClass(name,rules){
var style = document.createElement('style');
style.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(style);
if(!(style.sheet||{}).insertRule)
(style.styleSheet || style.sheet).addRule(name, rules);
else
style.sheet.insertRule(name+"{"+rules+"}",0);
}
createClass('.whatever',"background-color: green;");
And this final bit applies the class to an element:
function applyClass(name,element,doRemove){
if(typeof element.valueOf() == "string"){
element = document.getElementById(element);
}
if(!element) return;
if(doRemove){
element.className = element.className.replace(new RegExp("\\b" + name + "\\b","g"));
}else{
element.className = element.className + " " + name;
}
}
Here's a little test page as well: https://gist.github.com/shadybones/9816763
The key little bit is the fact that style elements have a "styleSheet"/"sheet" property which you can use to to add/remove rules on.
There is a light jQuery plugin which allows to generate CSS declarations: jQuery-injectCSS
In fact, it uses JSS (CSS described by JSON), but it's quite easy to handle in order to generate dynamic css stylesheets.
$.injectCSS({
"#test": {
height: 123
}
});
YUI has by far the best stylesheet utility I have seen out there. I encourage you to check it out, but here's a taste:
// style element or locally sourced link element
var sheet = YAHOO.util.StyleSheet(YAHOO.util.Selector.query('style',null,true));
sheet = YAHOO.util.StyleSheet(YAHOO.util.Dom.get('local'));
// OR the id of a style element or locally sourced link element
sheet = YAHOO.util.StyleSheet('local');
// OR string of css text
var css = ".moduleX .alert { background: #fcc; font-weight: bold; } " +
".moduleX .warn { background: #eec; } " +
".hide_messages .moduleX .alert, " +
".hide_messages .moduleX .warn { display: none; }";
sheet = new YAHOO.util.StyleSheet(css);
There are obviously other much simpler ways of changing styles on the fly such as those suggested here. If they make sense for your problem, they might be best, but there are definitely reasons why modifying CSS is a better solution. The most obvious case is when you need to modify a large number of elements. The other major case is if you need your style changes to involve the cascade. Using the DOM to modify an element will always have a higher priority. It's the sledgehammer approach and is equivalent to using the style attribute directly on the HTML element. That is not always the desired effect.
As of IE 9. You can now load a text file and set a style.innerHTML property. So essentially you can now load a css file through ajax (and get the callback) and then just set the text inside of a style tag like this.
This works in other browsers, not sure how far back. But as long as you don't need to support IE8 then it would work.
// RESULT: doesn't work in IE8 and below. Works in IE9 and other browsers.
$(document).ready(function() {
// we want to load the css as a text file and append it with a style.
$.ajax({
url:'myCss.css',
success: function(result) {
var s = document.createElement('style');
s.setAttribute('type', 'text/css');
s.innerHTML = result;
document.getElementsByTagName("head")[0].appendChild(s);
},
fail: function() {
alert('fail');
}
})
});
and then you can have it pull an external file like the myCss.css
.myClass { background:#F00; }
Using google closure:
you can just use the ccsom module:
goog.require('goog.cssom');
var css_node = goog.cssom.addCssText('.cssClass { color: #F00; }');
The javascript code attempts to be cross browser when putting the css node into the document head.
Here is Vishwanath's solution slightly rewritten with comments :
function setStyle(cssRules, aSelector, aStyle){
for(var i = 0; i < cssRules.length; i++) {
if(cssRules[i].selectorText && cssRules[i].selectorText.toLowerCase() == aSelector.toLowerCase()) {
cssRules[i].style.cssText = aStyle;
return true;
}
}
return false;
}
function createCSSSelector(selector, style) {
var doc = document;
var allSS = doc.styleSheets;
if(!allSS) return;
var headElts = doc.getElementsByTagName("head");
if(!headElts.length) return;
var styleSheet, media, iSS = allSS.length; // scope is global in a function
/* 1. search for media == "screen" */
while(iSS){ --iSS;
if(allSS[iSS].disabled) continue; /* dont take into account the disabled stylesheets */
media = allSS[iSS].media;
if(typeof media == "object")
media = media.mediaText;
if(media == "" || media=='all' || media.indexOf("screen") != -1){
styleSheet = allSS[iSS];
iSS = -1; // indication that media=="screen" was found (if not, then iSS==0)
break;
}
}
/* 2. if not found, create one */
if(iSS != -1) {
var styleSheetElement = doc.createElement("style");
styleSheetElement.type = "text/css";
headElts[0].appendChild(styleSheetElement);
styleSheet = doc.styleSheets[allSS.length]; /* take the new stylesheet to add the selector and the style */
}
/* 3. add the selector and style */
switch (typeof styleSheet.media) {
case "string":
if(!setStyle(styleSheet.rules, selector, style));
styleSheet.addRule(selector, style);
break;
case "object":
if(!setStyle(styleSheet.cssRules, selector, style));
styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
break;
}
One liner, attach one or many new cascading rule(s) to the document.
This example attach a cursor:pointer to every button, input, select.
document.body.appendChild(Object.assign(document.createElement("style"), {textContent: "select, button, input {cursor:pointer}"}))
https://jsfiddle.net/xk6Ut/256/
One option to dynamically create and update CSS class in JavaScript:
Using Style Element to create a CSS section
Using an ID for the style element so that we can update the CSS
class
.....
function writeStyles(styleName, cssText) {
var styleElement = document.getElementById(styleName);
if (styleElement)
document.getElementsByTagName('head')[0].removeChild(
styleElement);
styleElement = document.createElement('style');
styleElement.type = 'text/css';
styleElement.id = styleName;
styleElement.innerHTML = cssText;
document.getElementsByTagName('head')[0].appendChild(styleElement);
}
...
var cssText = '.testDIV{ height:' + height + 'px !important; }';
writeStyles('styles_js', cssText)
An interesting project which could help you out in your task is JSS.
JSS is an authoring tool for CSS which allows you to use JavaScript to describe styles in a declarative, conflict-free and reusable way. It can compile in the browser, server-side or at build time in Node.
JSS library allows you to inject in the DOM/head section using the .attach() function.
Repl online version for evaluation.
Further information on JSS.
An example:
// Use plugins.
jss.use(camelCase())
// Create your style.
const style = {
myButton: {
color: 'green'
}
}
// Compile styles, apply plugins.
const sheet = jss.createStyleSheet(style)
// If you want to render on the client, insert it into DOM.
sheet.attach()
I was looking through some of the answers here, and I couldn't find anything that automatically adds a new stylesheet if there are none, and if not simply modifies an existing one that already contains the style needed, so I made a new function (should work accross all browsers, though not tested, uses addRule and besides that only basic native JavaScript, let me know if it works):
function myCSS(data) {
var head = document.head || document.getElementsByTagName("head")[0];
if(head) {
if(data && data.constructor == Object) {
for(var k in data) {
var selector = k;
var rules = data[k];
var allSheets = document.styleSheets;
var cur = null;
var indexOfPossibleRule = null,
indexOfSheet = null;
for(var i = 0; i < allSheets.length; i++) {
indexOfPossibleRule = findIndexOfObjPropInArray("selectorText",selector,allSheets[i].cssRules);
if(indexOfPossibleRule != null) {
indexOfSheet = i;
break;
}
}
var ruleToEdit = null;
if(indexOfSheet != null) {
ruleToEdit = allSheets[indexOfSheet].cssRules[indexOfPossibleRule];
} else {
cur = document.createElement("style");
cur.type = "text/css";
head.appendChild(cur);
cur.sheet.addRule(selector,"");
ruleToEdit = cur.sheet.cssRules[0];
console.log("NOPE, but here's a new one:", cur);
}
applyCustomCSSruleListToExistingCSSruleList(rules, ruleToEdit, (err) => {
if(err) {
console.log(err);
} else {
console.log("successfully added ", rules, " to ", ruleToEdit);
}
});
}
} else {
console.log("provide one paramter as an object containing the cssStyles, like: {\"#myID\":{position:\"absolute\"}, \".myClass\":{background:\"red\"}}, etc...");
}
} else {
console.log("run this after the page loads");
}
};
then just add these 2 helper functions either inside the above function, or anywhere else:
function applyCustomCSSruleListToExistingCSSruleList(customRuleList, existingRuleList, cb) {
var err = null;
console.log("trying to apply ", customRuleList, " to ", existingRuleList);
if(customRuleList && customRuleList.constructor == Object && existingRuleList && existingRuleList.constructor == CSSStyleRule) {
for(var k in customRuleList) {
existingRuleList["style"][k] = customRuleList[k];
}
} else {
err = ("provide first argument as an object containing the selectors for the keys, and the second argument is the CSSRuleList to modify");
}
if(cb) {
cb(err);
}
}
function findIndexOfObjPropInArray(objPropKey, objPropValue, arr) {
var index = null;
for(var i = 0; i < arr.length; i++) {
if(arr[i][objPropKey] == objPropValue) {
index = i;
break;
}
}
return index;
}
(notice that in both of them I use a for loop instead of .filter, since the CSS style / rule list classes only have a length property, and no .filter method.)
Then to call it:
myCSS({
"#coby": {
position:"absolute",
color:"blue"
},
".myError": {
padding:"4px",
background:"salmon"
}
})
Let me know if it works for your browser or gives an error.
Looked through the answers and the most obvious and straight forward is missing: use document.write() to write out a chunk of CSS you need.
Here is an example (view it on codepen: http://codepen.io/ssh33/pen/zGjWga):
<style>
#import url(http://fonts.googleapis.com/css?family=Open+Sans:800);
.d, body{ font: 3vw 'Open Sans'; padding-top: 1em; }
.d {
text-align: center; background: #aaf;
margin: auto; color: #fff; overflow: hidden;
width: 12em; height: 5em;
}
</style>
<script>
function w(s){document.write(s)}
w("<style>.long-shadow { text-shadow: ");
for(var i=0; i<449; i++) {
if(i!= 0) w(","); w(i+"px "+i+"px #444");
}
w(";}</style>");
</script>
<div class="d">
<div class="long-shadow">Long Shadow<br> Short Code</div>
</div>
For the benefit of searchers; if you are using jQuery, you can do the following:
var currentOverride = $('#customoverridestyles');
if (currentOverride) {
currentOverride.remove();
}
$('body').append("<style id=\"customoverridestyles\">body{background-color:pink;}</style>");
Obviously you can change the inner css to whatever you want.
Appreciate some people prefer pure JavaScript, but it works and has been pretty robust for writing/overwriting styles dynamically.
function createCSSClass(selector, style, hoverstyle)
{
if (!document.styleSheets)
{
return;
}
if (document.getElementsByTagName("head").length == 0)
{
return;
}
var stylesheet;
var mediaType;
if (document.styleSheets.length > 0)
{
for (i = 0; i < document.styleSheets.length; i++)
{
if (document.styleSheets[i].disabled)
{
continue;
}
var media = document.styleSheets[i].media;
mediaType = typeof media;
if (mediaType == "string")
{
if (media == "" || (media.indexOf("screen") != -1))
{
styleSheet = document.styleSheets[i];
}
}
else if (mediaType == "object")
{
if (media.mediaText == "" || (media.mediaText.indexOf("screen") != -1))
{
styleSheet = document.styleSheets[i];
}
}
if (typeof styleSheet != "undefined")
{
break;
}
}
}
if (typeof styleSheet == "undefined") {
var styleSheetElement = document.createElement("style");
styleSheetElement.type = "text/css";
document.getElementsByTagName("head")[0].appendChild(styleSheetElement);
for (i = 0; i < document.styleSheets.length; i++) {
if (document.styleSheets[i].disabled) {
continue;
}
styleSheet = document.styleSheets[i];
}
var media = styleSheet.media;
mediaType = typeof media;
}
if (mediaType == "string") {
for (i = 0; i < styleSheet.rules.length; i++)
{
if (styleSheet.rules[i].selectorText.toLowerCase() == selector.toLowerCase())
{
styleSheet.rules[i].style.cssText = style;
return;
}
}
styleSheet.addRule(selector, style);
}
else if (mediaType == "object")
{
for (i = 0; i < styleSheet.cssRules.length; i++)
{
if (styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase())
{
styleSheet.cssRules[i].style.cssText = style;
return;
}
}
if (hoverstyle != null)
{
styleSheet.insertRule(selector + "{" + style + "}", 0);
styleSheet.insertRule(selector + ":hover{" + hoverstyle + "}", 1);
}
else
{
styleSheet.insertRule(selector + "{" + style + "}", 0);
}
}
}
createCSSClass(".modalPopup .header",
" background-color: " + lightest + ";" +
"height: 10%;" +
"color: White;" +
"line-height: 30px;" +
"text-align: center;" +
" width: 100%;" +
"font-weight: bold; ", null);
Here is my modular solution:
var final_style = document.createElement('style');
final_style.type = 'text/css';
function addNewStyle(selector, style){
final_style.innerHTML += selector + '{ ' + style + ' } \n';
};
function submitNewStyle(){
document.getElementsByTagName('head')[0].appendChild(final_style);
final_style = document.createElement('style');
final_style.type = 'text/css';
};
function submitNewStyleWithMedia(mediaSelector){
final_style.innerHTML = '#media(' + mediaSelector + '){\n' + final_style.innerHTML + '\n};';
submitNewStyle();
};
You basically anywhere in your code do:
addNewStyle('body', 'color: ' + color1); , where color1 is defined variable.
When you want to "post" the current CSS file you simply do submitNewStyle(),
and then you can still add more CSS later.
If you want to add it with "media queries", you have the option.
After "addingNewStyles" you simply use submitNewStyleWithMedia('min-width: 1280px');.
It was pretty useful for my use-case, as I was changing CSS of public (not mine) website according to current time. I submit one CSS file before using "active" scripts, and the rest afterwards (makes the site look kinda-like it should before accessing elements through querySelector).
This is what worked for me in Angular:
In HTML I have button with programmatically created CSS with specific ID:
<button [id]="'hoverbutton1'+item.key" [ngClass]="getHoverButtonClass()">
<mat-icon class="icon">open_in_new</mat-icon>
</button>
In typescript I created CSS and assign it to specific element with given ID:
addClasses(){
var style1 = document.createElement('style');
style1.innerHTML = '.hoverbutton'+this.item.key+' { display: none; }';
document.getElementsByTagName('head')[0].appendChild(style1);
}
getHoverButtonClass() {
return "hoverbutton"+this.item.key
}
This way I can create as many CSS classes as I want and assign them to elements individually. :)

Need Help In Javascript Text Typer Effect

I have a javascript text typer code:
CSS:
body
{
background-color:black;
}
#writer
{
font-family:Courier;
font-size:12px;
color:#24FF00;
background-color:black;
}
Javascript:
var text = "Help Please, i want help.";
var counter = 0;
var speed = 25;
function type()
{
lastText = document.getElementById("writer").innerHTML;
lastText+=text.charAt(counter);
counter++;
document.getElementById("writer").innerHTML = lastText;
}
setInterval(function(){type()},speed);
HTML:
<div id="writer"></div>
I want to know how can i use <br> tag (skipping a line or moving to another line). I tried many ways but failed, I want that if I Typed My name is Master M1nd. and then i want to go on the other line how would i go?
I've made a jQuery plugin, hope this will make things easier for you. Here is a live demo : http://jsfiddle.net/wared/V7Tv6/. As you can see, jQuery is loaded thanks to the first <script> tag. You can then do the same for the other <script> tags if you like, this is not necessary but considered as a good practice. Just put the code inside each tag into separate files, then set appropriate src attributes in the following order :
<script src=".../jquery.min.js"></script>
<script src=".../jquery.marquee.js"></script>
<script src=".../init.js"></script>
⚠ Only tested with Chrome ⚠
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
jQuery.fn.marquee = function ($) {
function findTextNodes(node) {
var result = [],
i = 0,
child;
while (child = node.childNodes[i++]) {
if (child.nodeType === 3) {
result.push(child);
} else {
result = result.concat(
findTextNodes(child)
);
}
}
return result;
}
function write(node, text, fn) {
var i = 0;
setTimeout(function () {
node.nodeValue += text[i++];
if (i < text.length) {
setTimeout(arguments.callee, 50);
} else {
fn();
}
}, 50);
}
return function (html) {
var fragment, textNodes, text;
fragment = $('<div>' + html + '</div>');
textNodes = findTextNodes(fragment[0]);
text = $.map(textNodes, function (node) {
var text = node.nodeValue;
node.nodeValue = '';
return text;
});
this.each(function () {
var clone = fragment.clone(),
textNodes = findTextNodes(clone[0]),
i = 0;
$(this).append(clone.contents());
(function next(node) {
if (node = textNodes[i]) {
write(node, text[i++], next);
}
})();
});
return this;
};
}(jQuery);
</script>
<script>
jQuery(function init($) {
var html = 'A <i>marquee</i> which handles <u><b>HTML</b></u>,<br/> only tested with Chrome. Replay';
$('p').marquee(html);
$('a').click(function (e) {
e.preventDefault();
$('p').empty();
$('a').off('click');
init($);
});
});
</script>
<p></p>
<p></p>
Instead of passing <br> char by char, you can put a \n and transform it to <br> when you modify the innerHTML.
For example (http://jsfiddle.net/qZ4u9/1/):
function escape(c) {
return (c === '\n') ? '<br>':c;
}
function writer(text, out) {
var current = 0;
return function () {
if (current < text.length) {
out.innerHTML += escape(text.charAt(current++));
}
return current < text.length;
};
}
var typeNext = writer('Hello\nWorld!', document.getElementById('writer'));
function type() {
if (typeNext()) setInterval(type, 500);
}
setInterval(type, 500);
Also probably you'll be interested in exploring requestAnimationFrame (http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/), for your typing animation :)

Wrapping Sentences within <p> Tags with <span>'s, But Keep Other Tags

To give you an idea of what I need, I have been using the below code to parse content within tags and wrap each sentence within tags so I can then interact with sentences on a page.
$('p').each(function() {
var sentences = $(this)
.text()
.replace(/(((?![.!?]['"]?\s).)*[.!?]['"]?)(\s|$)/g,
'<span class="sentence">$1</span>$3');
$(this).html(sentences);
});
However, the following line demonstrates my problem:
<p>This is a link and it is removed with the above code! Here is another sentence.</p>
Nested tags such as <a>, <img> etc...within <p> tags that I'm searching through are removed with the code that I'm using. I need to keep these tags intact, so the content stays the same within the <p> tags.
I need:
<p><span class="sentence">This is a link and it is removed with the above code!</sentence><sentence>Here is another sentence.</sentence></p>
After reading this barn-burner about parsing HTML with regex, I've concluded that I need to use a combo of an HTML parser of some sort to traverse through sub-tags within a <p> tag, and then use a regex to find the sentences. I think the regex I have listed above should work for most of my uses, if that helps.
So: how should I do it?
It is really difficult to tokenise language, reliably, into sentences and that is without the added complexity of throwing html into the equation. There are some applications etc out there that attempt to deal with Natural Language Processing, an example would be the Stanford Tokenizer with runs on Java (not Javascript)
And as people keep mentioning, a regex is not the solution to this problem, language is not regular so don't expect a Regular Expression only solution.
There is a question here on SO, Basic NLP in CoffeeScript or JavaScript — Punkt tokenizaton, simple trained Bayes models — where to start? Which I think summarises things fairly simply for Javascript.
Anyway, to at least give you a little something that you could play with, I knocked up a little code for you. This works reasonable well until the markup/language begins to resemble anything slightly complex or different, but ultimately fails the mark by a long way. But, it may be enough for what you need, I don't know.
CSS
.emphasis {
font-style: italic;
}
.bold {
font-weight: bold;
}
.emphasis.bold {
font-style: italic;
font-weight: bold;
}
.unidentified {
background-color: pink;
}
.sentence0 {
background-color: yellow;
}
.sentence1 {
background-color: green;
}
.sentence2 {
background-color: red;
}
.whitespace {
white-space: pre;
background-color: blue;
}
Javascript
/*jslint maxerr: 50, indent: 4, browser: true */
(function () {
"use strict";
var rxOpen = new RegExp("<[^\\/].+?>"),
rxClose = new RegExp("<\\/.+?>"),
rxWhitespace = new RegExp("^\\s+?"),
rxSupStart = new RegExp("^<sup\\b[^>]*>"),
rxSupEnd = new RegExp("<\/sup>"),
sentenceEnd = [],
color = 0,
rxIndex;
sentenceEnd.push(new RegExp("[^\\d][\\.!\\?]+"));
sentenceEnd.push(new RegExp("(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*?$)"));
sentenceEnd.push(new RegExp("(?![^\\(]*?\\))"));
sentenceEnd.push(new RegExp("(?![^\\[]*?\\])"));
sentenceEnd.push(new RegExp("(?![^\\{]*?\\})"));
sentenceEnd.push(new RegExp("(?![^\\|]*?\\|)"));
//sentenceEnd.push(new RegExp("(?![^\\\\]*?\\\\)"));
//sentenceEnd.push(new RegExp("(?![^\\/.]*\\/)")); // all could be a problem, but this one is problematic
rxIndex = new RegExp(sentenceEnd.reduce(function (previousValue, currentValue) {
return previousValue + currentValue.source;
}, ""));
function indexSentenceEnd(html) {
var index = html.search(rxIndex);
if (index !== -1) {
index += html.match(rxIndex)[0].length - 1;
}
return index;
}
function pushSpan(array, className, string, classNameOpt) {
if (className === "sentence") {
className += color % 2;
if (classNameOpt) {
className += " " + classNameOpt;
}
color += 1;
}
array.push('<span class="' + className + '">' + string + '</span>');
}
function addSupToPrevious(html, array) {
var sup = html.search(rxSupStart),
end = 0,
last;
if (sup !== -1) {
end = html.search(rxSupEnd);
if (end !== -1) {
last = array.pop();
end = end + 6;
array.push(last.slice(0, -7) + html.slice(0, end) + last.slice(-7));
}
}
return html.slice(end);
}
function leadingWhitespaces(html, array) {
var whitespace = html.search(rxWhitespace),
count = 0;
if (whitespace !== -1) {
count = html.match(rxWhitespace)[0].length;
pushSpan(array, "whitespace", html.slice(0, count));
}
return html.slice(count);
}
function paragraphIsSentence(html, array) {
var index = indexSentenceEnd(html);
if (index === -1 || index === html.length) {
pushSpan(array, "sentence", html, "paragraphIsSentence");
html = "";
}
return html;
}
function paragraphNoMarkup(html, array) {
var open = html.search(rxOpen),
index = 0;
if (open === -1) {
index = indexSentenceEnd(html);
if (index === -1) {
index = html.length;
}
pushSpan(array, "sentence", html.slice(0, index += 1), "paragraphNoMarkup");
}
return html.slice(index);
}
function sentenceUncontained(html, array) {
var open = html.search(rxOpen),
index = 0,
close;
if (open !== -1) {
index = indexSentenceEnd(html);
if (index === -1) {
index = html.length;
}
close = html.search(rxClose);
if (index < open || index > close) {
pushSpan(array, "sentence", html.slice(0, index += 1), "sentenceUncontained");
} else {
index = 0;
}
}
return html.slice(index);
}
function sentenceContained(html, array) {
var open = html.search(rxOpen),
index = 0,
close,
count;
if (open !== -1) {
index = indexSentenceEnd(html);
if (index === -1) {
index = html.length;
}
close = html.search(rxClose);
if (index > open && index < close) {
count = html.match(rxClose)[0].length;
pushSpan(array, "sentence", html.slice(0, close + count), "sentenceContained");
index = close + count;
} else {
index = 0;
}
}
return html.slice(index);
}
function anythingElse(html, array) {
pushSpan(array, "sentence2", html, "anythingElse");
return "";
}
function guessSenetences() {
var paragraphs = document.getElementsByTagName("p");
Array.prototype.forEach.call(paragraphs, function (paragraph) {
var html = paragraph.innerHTML,
length = html.length,
array = [],
safety = 100;
while (length && safety) {
html = addSupToPrevious(html, array);
if (html.length === length) {
html = leadingWhitespaces(html, array);
if (html.length === length) {
html = paragraphIsSentence(html, array);
if (html.length === length) {
html = paragraphNoMarkup(html, array);
if (html.length === length) {
html = sentenceUncontained(html, array);
if (html.length === length) {
html = sentenceContained(html, array);
if (html.length === length) {
html = anythingElse(html, array);
}
}
}
}
}
}
length = html.length;
safety -= 1;
}
paragraph.innerHTML = array.join("");
});
}
guessSenetences();
}());
On jsfiddle
you need to use .html() instead of .text() if you want to keep tags intact.
Check below code and let me know if it doesn't work out.
DEMO
$('p').each(function() {
var sentences = $(this)
.html()
.replace(/(((?![.!?]['"]?\s).)*[.!?]['"]?)(\s|$)/g,
'<span class="sentence">$1</span>$3');
$(this).html(sentences);
});

JQuery/Javascript - Search DOM for text and insert HTML

How do I search the DOM for a certain string in the document's text (say, "cheese") then insert some HTML immediately after that string (say, "< b >is fantastic< /b >").
I have tried the following:
for (var tag in document.innerHTML) {
if (tag.matches(/cheese/) != undefined) {
document.innerHTML.append(<b>is fantastic</b>
}
}
(The above is more of an illustration of what I have tried, not the actual code. I expect the syntax is horribly wrong so please excuse any errors, they are not the problem).
Cheers,
Pete
There are native methods for finding text inside a document:
MSIE:textRange.findText()
Others: window.find()
Manipulate the given textRange if something was found.
Those methods should provide much more performance than the traversing of the whole document.
Example:
<html>
<head>
<script>
function fx(a,b)
{
if(window.find)
{
while(window.find(a))
{
var node=document.createElement('b');
node.appendChild(document.createTextNode(b));
var rng=window.getSelection().getRangeAt(0);
rng.collapse(false);
rng.insertNode(node);
}
}
else if(document.body.createTextRange)
{
var rng=document.body.createTextRange();
while(rng.findText(a))
{
rng.collapse(false);
rng.pasteHTML('<b>'+b+'</b>');
}
}
}
</script>
</head>
<body onload="fx('cheese','is wonderful')">
<p>I've made a wonderful cheesecake with some <i>cheese</i> from my <u>chees</u>e-factory!</p>
</body>
</html>
This is crude and not the way to do it, but;
document.body.innerHTML = document.body.innerHTML.replace(/cheese/, 'cheese <b>is fantastic</b>');
You can use this with JQuery:
$('*:contains("cheese")').each(function (idx, elem) {
var changed = $(elem).html().replace('cheese', 'cheese <b>is fantastic</b>');
$(elem).html(changed);
});
I haven't tested this, but something along these lines should work.
Note that * will match all elements, even html, so you may want to use body *:contains(...) instead to make sure only elements that are descendants of the document body are looked at.
Sample Solution:
<ul>
<li>cheese</li>
<li>cheese</li>
<li>cheese</li>
</ul>
Jquery codes:
$('ul li').each(function(index) {
if($(this).text()=="cheese")
{
$(this).text('cheese is fantastic');
}
});
The way to do this is to traverse the document and search each text node for the desired text. Any way involving innerHTML is hopelessly flawed.
Here's a function that works in all browsers and recursively traverses the DOM within the specified node and replaces occurrences of a piece of text with nodes copied from the supplied template node replacementNodeTemplate:
function replaceText(node, text, replacementNodeTemplate) {
if (node.nodeType == 3) {
while (node) {
var textIndex = node.data.indexOf(text), currentNode = node;
if (textIndex == -1) {
node = null;
} else {
// Split the text node after the text
var splitIndex = textIndex + text.length;
var replacementNode = replacementNodeTemplate.cloneNode(true);
if (splitIndex < node.length) {
node = node.splitText(textIndex + text.length);
node.parentNode.insertBefore(replacementNode, node);
} else {
node.parentNode.appendChild(replacementNode);
node = null;
}
currentNode.deleteData(textIndex, text.length);
}
}
} else {
var child = node.firstChild, nextChild;
while (child) {
nextChild = child.nextSibling;
replaceText(child, text, replacementNodeTemplate);
child = nextChild;
}
}
}
Here's an example use:
replaceText(document.body, "cheese", document.createTextNode("CHEESE IS GREAT"));
If you prefer, you can create a wrapper function to allow you to specify the replacement content as a string of HTML instead:
function replaceTextWithHtml(node, text, html) {
var div = document.createElement("div");
div.innerHTML = html;
var templateNode = document.createDocumentFragment();
while (div.firstChild) {
templateNode.appendChild(div.firstChild);
}
replaceText(node, text, templateNode);
}
Example:
replaceTextWithHtml(document.body, "cheese", "cheese <b>is fantastic</b>");
I've incorporated this into a jsfiddle example: http://jsfiddle.net/timdown/azZsa/
Works in all browsers except IE I think, need confirmation though.
This supports content in iframes as well.
Note, other examples I have seen, like the one above, are RECURSIVE which is potentially bad in javascript which can end in stack overflows, especially in a browser client which has limited memory for such things. Too much recursion can cause javascript to stop executing.
If you don't believe me, try the examples here yourself...
If anyone would like to contribute, the code is here.
function grepNodes(searchText, frameId) {
var matchedNodes = [];
var regXSearch;
if (typeof searchText === "string") {
regXSearch = new RegExp(searchText, "g");
}
else {
regXSearch = searchText;
}
var currentNode = null, matches = null;
if (frameId && !window.frames[frameId]) {
return null;
}
var theDoc = (frameId) ? window.frames[frameId].contentDocument : document;
var allNodes = (theDoc.all) ? theDoc.all : theDoc.getElementsByTagName('*');
for (var nodeIdx in allNodes) {
currentNode = allNodes[nodeIdx];
if (!currentNode.nodeName || currentNode.nodeName === undefined) {
break;
}
if (!(currentNode.nodeName.toLowerCase().match(/html|script|head|meta|link|object/))) {
matches = currentNode.innerText.match(regXSearch);
var totalMatches = 0;
if (matches) {
var totalChildElements = 0;
for (var i=0;i<currentNode.children.length;i++) {
if (!(currentNode.children[i].nodeName.toLowerCase().match(/html|script|head|meta|link|object/))) {
totalChildElements++;
}
}
matchedNodes.push({node: currentNode, numMatches: matches.length, childElementsWithMatch: 0, nodesYetTraversed: totalChildElements});
}
for (var i = matchedNodes.length - 1; i >= 0; i--) {
previousElement = matchedNodes[i - 1];
if (!previousElement) {
continue;
}
if (previousElement.nodesYetTraversed !== 0 && previousElement.numMatches !== previousElement.childElementsWithMatch) {
previousElement.childElementsWithMatch++;
previousElement.nodesYetTraversed--;
}
else if (previousElement.nodesYetTraversed !== 0) {
previousElement.nodesYetTraversed--;
}
}
}
}
var processedMatches = [];
for (var i =0; i < matchedNodes.length; i++) {
if (matchedNodes[i].numMatches > matchedNodes[i].childElementsWithMatch) {
processedMatches.push(matchedNodes[i].node);
}
}
return processedMatches;
};

Categories