Create Styleshhet and insertRule/addRule - javascript

im trying t create a stylesheet with JS and append some rules but it wont work.
if (style == null) {
var style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.setAttribute('data-style', 13);
if (style.styleSheet) {
style.styleSheet.cssText = '';
} else {
style.appendChild(document.createTextNode(''));
}
document.head.appendChild(style);
}
if (typeof style.insertRule === 'function') {
style.insertRule("main > section[data-y='0']{top: 200px;}");
} else if (typeof style.addRule === 'function') {
style.addRule("main > section[data-y='0']", "{top: 200px;}");
}
Sorry im new in Js.
Can someone tell me why this wont working?

I have similar task, my example:
$('head').append('<link rel="stylesheet" type="text/css" href="css/test.css">');
var sheets = document.styleSheets;
console.log(sheets) //need to know number of my file, in my case e.g. it was 2
var sheet = document.styleSheets[2];
//also you forgot add index in the end of next line
sheet.insertRule("body { background-color: #000; }", 1);
its not a best example but it's work for me
and I found rly nice article about this task
https://davidwalsh.name/add-rules-stylesheets

GOT IT!
addRule / insertRule isnt a function of style! Its a function of style.sheet and i forgot to set the index so it should be
if (typeof style.sheet.insertRule === 'function') {
style.sheet.insertRule("main > section[data-y='0']{top: 200px;}",0);
} else if (typeof style.sheet.addRule === 'function') {
style.sheet.addRule("main > section[data-y='0']", "{top: 200px;}",0);
}

Related

Remove specific inline CSS with pure JavaScript

I want to remove following inline CSS:
<style type="text/css">.gm-style .gm-style-cc span, .gm-style .gm-style-cc a,.gm-style .gm-style-mtc div{font-size:10px}
</style>
...
With following script i try to remove the CSS, which contains '.gm':
var inline_css = document.querySelectorAll('style[innerText*=".gm"]');
if (inline_css) {
for (var i = 0; i < inline_css.length; i++) {
inline_css[i].parentNode.removeChild(inline_css[i]);
}
}
But it don't work.
querySelectorAll returns a list of elements. From those elements you can match the inner text. And if it matches your style (at all), you may remove it. Like so:
var ar = document.querySelectorAll('style');
console.log("found styles: " + ar.length)
for(i = 0; i < ar.length; i++){
if(ar[i].innerText.match('.gm')){
ar[i].remove()
}
}
// to check it worked
var ar = document.querySelectorAll('style');
console.log("remaining syltes: " + ar.length)
<style type="text/css">.gm-style .gm-style-cc span, .gm-style .gm-style-cc a,.gm-style .gm-style-mtc div{font-size:10px}
</style>
<style type="text/css">.other .style{}
</style>
In case you have a few tags, you can pinpoint the exact one you need.
Give your <style> tag an ID, and then you'll be able to select that <style> tag with Javascript and use the remove() method to make it magically disappear. The associated styling will also be removed.
HTML:
<style type="text/css" id="style>.gm-style .gm-style-cc span, .gm-style .gm-style-cc a,.gm-style .gm-style-mtc div{font-size:10px}
</style>
JS:
var style= document.getElementById("style");
style.remove();
(() => {
'use-strict';
let needle = '.gm-style';
if ( needle === '' || needle === '{{1}}' ) {
needle = '.?';
} else if ( needle.slice(0,1) === '/' && needle.slice(-1) === '/' ) {
needle = needle.slice(1,-1);
} else {
needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
needle = new RegExp(needle);
let cssnode = () => {
let css = document.querySelectorAll('style');
for (let cs of css) {
if (cs.outerHTML.match(needle)) {
cs.remove();
}
}
};
if (document.readyState === 'interactive' || document.readyState === 'complete') {
cssnode();
} else {
addEventListener('DOMContentLoaded', cssnode);
}
})();
Has regex support too, if you need to remove multiple <style> tags.

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. :)

Change font size on my website with Javascript

This is my website http://natjecanje.interes.hr/
I want to have big A and small A and by pressing one of this "A" people can change all letters size on website, all elements need change font size, Thank you! :)
P.S. I did google search, but i didn't find what i was looking for.
You need to use 2 differents CCS Style, a little JS script
Please Find below Javascript :
function setActiveStyleSheet(title) {
var i, a, main;
for(i=0; (a = document.getElementsByTagName("link")); i++) {
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
a.disabled = true;
if(a.getAttribute("title") == title) a.disabled = false;
}
}
if (navigator.appName == "Microsoft Internet Explorer") {
window.resizeBy(0,-10);
window.resizeBy(0,+10);
}
}
function getActiveStyleSheet() {
var i, a;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title") && !a.disabled) return a.getAttribute("title");
}
return null;
}
function getPreferredStyleSheet() {
var i, a;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
if(a.getAttribute("rel").indexOf("style") != -1
&& a.getAttribute("rel").indexOf("alt") == -1
&& a.getAttribute("title")
) return a.getAttribute("title");
}
return null;
}
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
window.onload = function(e) {
var cookie = readCookie("style");
var title = cookie ? cookie : getPreferredStyleSheet();
setActiveStyleSheet(title);
}
window.onunload = function(e) {
var title = getActiveStyleSheet();
createCookie("style", title, 365);
}
var cookie = readCookie("style");
var title = cookie ? cookie : getPreferredStyleSheet();
setActiveStyleSheet(title);
You can save this script in a fil named : changement_css.js
Now you need a first CCS style whit regular font-size, and another one with a different font size, and include it in your HTML file.
<!--Default CSS-->
<link rel="stylesheet" type="text/css" href="normal.css" title="normal">
<!--Alternate CSS-->
<link rel="alternate stylesheet" type="text/css" href="grand.css" title="grand">
Copy those line instead of your regular CSS
Then, use this code to call your JS after your CSS link :
<script language="JavaScript" src="changement_css.js" type="text/javascript"></script>
Then, you need a button to change font-size :
<ul>
<li>Normal</li>
<li>Grand</li>
</ul>
I hope this could help you.
This message is translate from : http://forum.alsacreations.com/topic-6-11551-1-Boutons-AugmenterDiminuer-la-Taille-du-Texte-.html
function promjenaVelicineFonta(inc)
{
var p = document.getElementsByTagName('p');
for(n=0; n<p.length; n++) {
if(p[n].style.fontSize) {
var size = parseInt(p[n].style.fontSize.replace("px", ""));
} else {
var size = 14;
}
p[n].style.fontSize = size+inc + 'px';
}
var span = document.getElementsByTagName('span');
for(n=0; n<span.length; n++) {
if(span[n].style.fontSize) {
var size = parseInt(span[n].style.fontSize.replace("px", ""));
} else {
var size = 14;
}
span[n].style.fontSize = size+inc + 'px';
}
}
I found a solution, here it is.
Do you mean font size (i.e. 10pt, 12pt etc) or font capitalisation (i.e. a or A)? I think you mean capitalisation based on the theme of your question (because you said 'big' and 'small')?
You can control capitalisation with CSS via the 'text-transform' property (http://www.w3schools.com/cssref/pr_text_text-transform.asp).
You can use JavaScript to add remove CSS classes which is outlined in this thread: Change an element's class with JavaScript
Using this approach you could add remove CSS classes which use text-transform to change the capitalisation of the font.

pure javascript to check if something has hover (without setting on mouseover/out)

I have seen this jQuery syntax:
if($(element).is(':hover')) { do something}
Since I am not using jQuery, I am looking for the best way to do this in pure javascript.
I know I could keep a global variable and set/unset it using mouseover and mouseout, but I'm wondering if there is some way to inspect the element's native properties via the DOM instead? Maybe something like this:
if(element.style.className.hovered === true) {do something}
Also, it must be cross browser compatible.
Simply using element.matches(':hover') seems to work well for me, you can use a comprehensive polyfill for older browsers too: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
You can use querySelector for IE>=8:
const isHover = e => e.parentElement.querySelector(':hover') === e;
const myDiv = document.getElementById('mydiv');
document.addEventListener('mousemove', function checkHover() {
const hovered = isHover(myDiv);
if (hovered !== checkHover.hovered) {
console.log(hovered ? 'hovered' : 'not hovered');
checkHover.hovered = hovered;
}
});
.whyToCheckMe {position: absolute;left: 100px;top: 50px;}
<div id="mydiv">HoverMe
<div class="whyToCheckMe">Do I need to be checked too?</div>
</div>
to fallback I think it is ok #Kolink answer.
First you need to keep track of which elements are being hovered on. Here's one way of doing it:
(function() {
var matchfunc = null, prefixes = ["","ms","moz","webkit","o"], i, m;
for(i=0; i<prefixes.length; i++) {
m = prefixes[i]+(prefixes[i] ? "Matches" : "matches");
if( document.documentElement[m]) {matchfunc = m; break;}
m += "Selector";
if( document.documentElement[m]) {matchfunc = m; break;}
}
if( matchfunc) window.isHover = function(elem) {return elem[matchfunc](":hover");};
else {
window.onmouseover = function(e) {
e = e || window.event;
var t = e.srcElement || e.target;
while(t) {
t.hovering = true;
t = t.parentNode;
}
};
window.onmouseout = function(e) {
e = e || window.event;
var t = e.srcElement || e.target;
while(t) {
t.hovering = false;
t = t.parentNode;
}
};
window.isHover = function(elem) {return elem.hovering;};
}
})();
it occurred to me that one way to check if an element is being hovered over is to set an unused property in css :hover and then check if that property exists in javascript. its not a proper solution to the problem since it is not making use of a dom-native hover property, but it is the closest and most minimal solution i can think of.
<html>
<head>
<style type="text/css">
#hover_el
{
border: 0px solid blue;
height: 100px;
width: 100px;
background-color: blue;
}
#hover_el:hover
{
border: 0px dashed blue;
}
</style>
<script type='text/javascript'>
window.onload = function() {check_for_hover()};
function check_for_hover() {
var hover_element = document.getElementById('hover_el');
var hover_status = (getStyle(hover_element, 'border-style') === 'dashed') ? true : false;
document.getElementById('display').innerHTML = 'you are' + (hover_status ? '' : ' not') + ' hovering';
setTimeout(check_for_hover, 1000);
};
function getStyle(oElm, strCssRule) {
var strValue = "";
if(document.defaultView && document.defaultView.getComputedStyle) {
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
}
else if(oElm.currentStyle) {
strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1) {
return p1.toUpperCase();
});
strValue = oElm.currentStyle[strCssRule];
}
return strValue;
};
</script>
</head>
<body>
<div id='hover_el'>hover here</div>
<div id='display'></div>
</body>
</html>
(function getStyle thanks to JavaScript get Styles)
if anyone can think of a better css property to use as a flag than solid/dashed please let me know. preferably the property would be one which is rarely used and cannot be inherited.
EDIT: CSS variable are probably better to use to check this. E.g.
const fps = 60;
setInterval(function() {
if(getComputedStyle(document.getElementById('my-div')).getPropertyValue('--hovered') == 1) {
document.getElementById('result').innerHTML = 'Yes';
} else {
document.getElementById('result').innerHTML = 'No';
};
}, 1000 / fps);
#my-div {
--hovered:0;
color: black;
}
#my-div:hover {
--hovered:1;
color: red;
}
<!DOCTYPE html>
<html>
<head>
<title>Detect if div is hovered with JS, using CSS variables</title>
</head>
<body>
<div id="my-div">Am I hovered?</div>
<div id="result"></div>
</body>
</html>
You can use an if statement with a querySelector. If you add ":hover" to the end of the selector, it will only return the element if it is being hovered. This means you can test if it returns null. It is like the element.matches(":hover) solution above, but I have had more success with this version.
Here is an example:
if (document.querySelector("body > p:hover") != null) {
console.log("hovered");
}
You can put it in an interval to run the code every time you hover:
setInterval(() => {
if (document.querySelector("body > p:hover") != null) {
console.log("hovered");
}
}, 10);

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