how to add class name based query string using javascript - javascript

I'd like to make my textarea font family, font size, color different based on query string with javascript. I am not a javascript expert. I hope anyone able to help me to.
EXAMPLE URL: http://www.domain.com/?color=#000&size=32px&fontfamily=serif
So it must generate css like:
textarea {font-family:serif;font-size:32px;color:#000}
Is that seems imposibble done using javascript or jquery?

Although this is a seemingly simple question - accessing query string values in javascript is not directly straightforward. See this question for many answers of how to access them: How can I get query string values in JavaScript?
For the next part, I'm going to work based on the assumption that you're using PHP and have the following added somewhere to give easy access to the query strings. You can change this according to whatever method you prefer to gain access to query paramater values.
<script>window.$_GET = <?php echo json_encode($_GET); ?>;</script>
Next part of this question is how to create the css rules from those query paramaters. There's another Stack Overflow question answering this as well: How to dynamically create CSS class in JavaScript and apply?
Using the method from the accepted answer there here's your code - untested so there may be some minor typos.
var css = 'textarea {';
if ('font' in $_GET) css += 'font-family:'+$_GET.font+';';
if ('size' in $_GET) css += 'font-size:'+$_GET.size+';';
if ('color' in $_GET) css += 'color:'+$_GET.color+';';
css += '}';
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
document.getElementsByTagName('head')[0].appendChild(style);
Also, note your URL is malformed. It should be
http://www.domain.com/?color=#000&size=32px&fontfamily=serif
not
http://www.domain.com/?color=#000?size=32px?fontfamily=serif

As you're not using valid CSS properties in your querystring, and it's not even a valid querystring, you have to first change the querystring as key/value pairs are seperated with & not ?, and then use a map to get proper CSS properties.
Once that is done, it's just a matter of seperating the key/value pairs, and iterating over elements to apply the styles
var cssMap = {
color: 'color',
size : 'fontSize',
fontfamily : 'fontFamily'
}
function applyCSS(selector, qs) {
var props = qs.split('&'),
elems = document.querySelectorAll(selector),
styles = {};
for (var i=props.length; i--;) {
var parts = props[i].split('=');
styles[cssMap[parts[0]]] = parts[1];
}
for (var j=elems.length; j--;) {
for (var style in styles) {
elems[j].style[style] = styles[style];
}
}
return styles;
}
applyCSS('textarea', window.location.search);
FIDDLE

Hope this helps.
function getQueryString() {
var query_string = {};
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (typeof query_string[pair[0]] === "undefined") {
query_string[pair[0]] = pair[1];
} else if (typeof query_string[pair[0]] === "string") {
var arr = [ query_string[pair[0]], pair[1] ];
query_string[pair[0]] = arr;
} else {
query_string[pair[0]].push(pair[1]);
}
}
return query_string;
}
var queryString = getQueryString();
var sColor = queryString.color;
var sSize = queryString.size;
var sFont = queryString.fontfamily;
var textAreaList = document.getElementsByTagName("textarea");
for(var i=0; i < textAreaList.length; i++){
var el = textAreaList[i];
el.style.color = sColor;
el.style.fontSize = sSize;
el.style.fontFamily = sFont;
}

Related

Make a html+css page standalone and static

I'm trying to make a web page "static", with all styles as inline.
For this I first save all computed styles, then remove all applied style (class and css files), check the difference with saved styles and add inline for missing styles.
This is my function:
var allstyles=null;
var allelms=null;
function FixHTML()
{
if (!allstyles)
{
console.log("remove scripts");
var elms=document.getElementsByTagName('SCRIPT');
for(var i=elms.length-1;i>-1;i--)
{
var elm=elms[i];
if (elm.tagName=="SCRIPT" && !elm.innerHTML.match(/FixHTML/))
{
elm.parentElement.removeChild(elm);
}
}
//sauvegarde des styles
console.log("save styles");
allstyles=[];
allelms=document.getElementsByTagName('*');
for(i=0;i<allelms.length;i++)
{
elm=allelms[i];
if (!elm.id)
elm.id="tmpid"+i;
var id=elm.id;
allstyles[id]=[];
var style=getStyleObject(elm);
for(var key in style)
{
allstyles[id][key]=style[key];
}
if (elm.className)
elm.className="";
}
console.log("delete stylesheet links");
elms=document.getElementsByTagName('LINK');
for(i=elms.length-1;i>-1;i--)
{
elm=elms[i];
console.log(elm.href);
if (elm.rel="stylesheet")
elm.href="nowhere";
}
}
setTimeout(RestoreClassStyles,2000);
}
function RestoreClassStyles()
{
console.log("restore class styles",allstyles);
allelms=document.getElementsByTagName('*');
for(var i=0;i<allelms.length;i++)
{
var elm=allelms[i];
var id=elm.id;
var style=getStyleObject(elm);
for(var key in allstyles[id])
{
if (allstyles[id][key]!=style[key])
{
console.log(key);
elm.style[key]=allstyles[id][key];
}
}
}
}
function getStyleObject(dom){
var style;
var returns = {};
if(window.getComputedStyle){
var camelize = function(a,b){
return b.toUpperCase();
};
style = window.getComputedStyle(dom, null);
for(var i = 0, l = style.length; i < l; i++){
var prop = style[i];
var camel = prop.replace(/\-([a-z])/g, camelize);
var val = style.getPropertyValue(prop);
returns[camel] = val;
};
return returns;
};
console.log("not found",elm);
return "";
}
It "works a bit" but some styles are incorrect so I need help to find what I'm missing in that code.
Working example: http://jsfiddle.net/owecfdr2/
Instead of using inline styles, I would convert the link elements to style elements. You can do that like this (I've stuck to ES5 because it looked like you were doing so in your code):
function linkToStyle(link) {
var css = [];
var sheet = link.sheet;
var rules = sheet.cssRules || sheet.rules;
for (var i = 0; i < rules.length; ++i) {
var rule = rules[i];
css.push(rule.cssText);
}
var style = document.createElement("style");
style.type = "text/css";
style.appendChild(
document.createTextNode(css.join("\r\n"))
);
return style;
}
document.querySelectorAll("link[rel=stylesheet]").forEach(function(link) {
var style = linkToStyle(link);
var parent = link.parentNode;
parent.insertBefore(style, link);
parent.removeChild(link);
});
That finds all the link elements with rel="stylesheet" and replaces them with style elements with the same CSS text, by getting the CSS stylesheet object from the link element, looping through its CSS rules, and using the cssText of each rule.
As misorude points out in a comment, any URLs in the linked CSS stylesheets are relative to the stylesheet, not the page linking to the style sheet, so if your stylesheets and page are not in the same place from a URL perspective (e.g., same directory), it gets a bit more complicated: you'll have to adjust the URLs to account for that. A simple version would just handle rules of type CSSRule.STYLE_RULE (which are CSSStyleRules), looping through the properties to find and adjust URLs. (If there are imports, it gets more complicated.)
That code relies on forEach on the NodeList returned by querySelectorAll. Most browsers have that now; this answer shows how to detect if the browser doesn't and polyfill it.

How can I programmatically add to a variably-nested object?

I need a way to add an object into another object. Normally this is quite simple with just
obj[property] = {'name': bob, 'height': tall}
however the object in question is nested so the following would be required:
obj[prop1][prop2] = {'name': bob, 'height': tall}
The clincher though, is that the nesting is variable. That is that I don't know how deeply each new object will be nested before runtime.
Basically I will be generating a string that represents an object path like
"object.secondObj.thirdObj.fourthObj"
and then I need to set data inside the fourth object, but I can't use the bracket [] method because I don't know how many brackets are required beforehand. Is there a way to do this?
I am using jQuery as well, if that's necessary.
Sure, you can either use recursion, or simple iteration. I like recursion better. The following examples are meant to be proof-of-concept, and probably shouldn't be used in production.
var setDeepValue = function(obj, path, value) {
if (path.indexOf('.') === -1) {
obj[path] = value;
return;
}
var dotIndex = path.indexOf('.');
obj = obj[path.substr(0, dotIndex)];
return setDeepValue(obj, path.substr(dotIndex + 1), value);
};
But recursion isn't necessary, because in JavaScript you can just change references.
var objPath = 'secondObj.thirdobj.fourthObj';
var valueToAdd = 'woot';
var topLevelObj = {};
var attributes = objPath.split('.');
var curObj = topLevelObj;
for (var i = 0; i < attributes.length; i++) {
var attr = attributes[i];
if (typeof curObj[attr] === 'undefined') {
curObj[attr] = {};
}
curObj = curObj[attr];
if (i === (attributes.length - 1)) {
// We're at the end - set the value!
curObj['awesomeAttribute'] = valueToAdd;
}
}
Instead of generating a string...
var o="object";
//code
o+=".secondObj";
//code
o+=".thirdObj";
//code
o+=".fourthObj";
...you could do
var o=object;
//code
o=o.secondObj;
//code
o=o.thirdObj;
//code
o=o.fourthObj;
Then you can add data like this:
o.myprop='myvalue';
And object will be updated with the changes.
See it here: http://jsfiddle.net/rFuyG/

Size of a string with a css class

Hi i have build my own text-wrap class. and i've run into a small problem it is kind off slow, because my script that checks the size of the font puts the string into a div with the classes but thats on a big scale intens for the DOM. so is there another way?
as you can see i tryed to build a cache controller but that makes it slower
var textMetrics = function (appendTo) {
var span;
var cache = [];
this.init = function () {
span = document.createElement("span");
appendTo.appendChild(span);
span.style.position = 'absolute';
span.style.left = -9999 + 'px';
};
this.checkCache = function (word, style) {
for (var i = 0; i < cache.length; i++) {
if (cache[i].word == word) {
return cache[i].value;
}
}
return false;
};
this.addCache = function (word, style, value) {
cache.push({
"word": word,
"style": style,
"value": value
});
};
this.getSize = function (word, style) {
word = word.replaceAll(" ", " ");
//var inCache = this.checkCache(word, style);
var inCache = false;
if (inCache === false) {
span.innerHTML = word;
for (var i in style) {
span.style[i] = style[i];
}
var coords = {
"width": span.offsetWidth,
"height": span.offsetHeight
};
for (var i in style) {
span.style[i] = "";
}
span.innerHTML = "";
this.addCache(word, style, coords);
return coords;
}
else {
return inCache;
}
};
this.init();
};
You could consider making your cache a dictionary (JS object) instead of a list:
var cache = {};
this.addCache = function (word, style, value) {
cache[word] = value;
};
this.checkCache = function (word, style) {
var value = cache[word];
if (typeof value != "undefined")
return value;
return false;
};
I didn't really get what your style variable is about — maybe you should add it to the cache key as well.
Since you are basically using a dictionary the best format for your cache is a simple javascript object that behaves as a hashmap.
var cache = {};
You can then assign words to it as follows:
this.addCache = function (word, style, value) {
cache[word] = {style: style, value: value};
};
And check them as follows:
this.checkCache = function (word) {
return cache[word];
};
So then you can:
var cachedItem = this.checkCache(word);
if (cachedItem ) {
alert(cachedItem.value);
}
This should speed up your cache searches considerably as you dont have to loop through an array that keeps getting larger and larger.
You could try to approximate the text width using the widths of individual characters. This will introduce problems when there's special kerning for combinations like "ff", of course.
I wrote a function that caches the widths of pairs of characters to accommodate for that. Thus, only a constant number of DOM manipulations is needed. It's on http://jsfiddle.net/wbL9Q/6/ and https://gist.github.com/1562233 (too much code for here).
However, while this worked for me in Safari (Mac), it did not give the correct results in Firefox. Apparently, some even more complex kerning is applied there. Maybe extending the algorithm to triples of characters (or even more) could help.
(Sorry for posting my 2nd answer, but I thought it makes sense because it's a completely different aspect.)

Listing known CSS classes using Javascript

I'm trying to find a good way to collect the names of classes defined in the stylesheets included with a given document. I know about document.StyleSheetList but it doesn't seem like it'd be easy to parse. What I'm looking for is something like, for a stylesheet document such as:
.my_class {
background: #fff000;
}
.second_class {
color: #000000;
}
I could extract an array like ["my_class", "second_class"]. This obviously assumes the favorable scenario of a fully loaded dom and stylesheets.
I've been looking everywhere for a good way to do something like this and so far, have made little progress. Does anyone have any idea about how to pull this off? Thanks!
This will show all rules defined in the stylesheets.
var allRules = [];
var sSheetList = document.styleSheets;
for (var sSheet = 0; sSheet < sSheetList.length; sSheet++)
{
var ruleList = document.styleSheets[sSheet].cssRules;
for (var rule = 0; rule < ruleList.length; rule ++)
{
allRules.push( ruleList[rule].selectorText );
}
}
The thing, though, is that it includes all rules regardless of being class or tag or id or whatever..
You will need to explain in more detail what you want to happen for non class rules (or combined rules)
You were on track with document.styleSheets (https://developer.mozilla.org/en/DOM/document.styleSheets)
https://developer.mozilla.org/en/DOM/stylesheet.cssRules
Here's a quick and dirty method to output all class selectorTexts to the console in Firefox + Firebug.
var currentSheet = null;
var i = 0;
var j = 0;
var ruleKey = null;
//loop through styleSheet(s)
for(i = 0; i<document.styleSheets.length; i++){
currentSheet = document.styleSheets[i];
///loop through css Rules
for(j = 0; j< currentSheet.cssRules.length; j++){
//log selectorText to the console (what you're looking for)
console.log(currentSheet.cssRules[j].selectorText);
//uncomment to output all of the cssRule contents
/*for(var ruleKey in currentSheet.cssRules[j] ){
console.log(ruleKey +': ' + currentSheet.cssRules[j][ruleKey ]);
}*/
}
}
This is probably not something you really want to be doing except as part of a refactoring process, but here is a function that should do what you want:
function getClasses() {
var classes = {};
// Extract the stylesheets
return Array.prototype.concat.apply([], Array.prototype.slice.call(document.styleSheets)
.map(function (sheet) {
if(null == sheet || null == sheet.cssRules) return;
// Extract the rules
return Array.prototype.concat.apply([], Array.prototype.slice.call(sheet.cssRules)
.map(function(rule) {
// Grab a list of classNames from each selector
return rule.selectorText.match(/\.[\w\-]+/g) || [];
})
);
})
).filter(function(name) {
// Reduce the list of classNames to a unique list
return !classes[name] && (classes[name] = true);
});
}
What about
.something .other_something?
Do you want a pool of classNames that exist? Or a pool of selectors?
Anyway, have you tried iterating through document.styleSheets[i].cssRules? It gives you the selector text. Parsing that with some regexp kungfu should be easier...
Do you need it to be crossbrowser?
You can accompish this with jQuery. Example would be
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script>
$(document).ready(function(){
var allobjects = $("*")
});
</script>
Check out the jQuery website: http://api.jquery.com/all-selector/

How to read get request using Javascript?

So I have html page called A.html it was called like this from B.html : A.html?varString="bla-bla-bla" Is it correct for sending args to JS? How to parse args from JS?
(not using any frameworks like Jquery, working in IE6, FireFox 3)
Here is a function to parse the query string. Pass it the parameter name and it returns the value.
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++)
{
var pair = vars[i].split("=");
if (pair[0] == variable)
{
return pair[1];
}
}
return -1; //not found
}
Use location.search:
alert(location.search); // will display everything from the ? onwards
You probably want to separate the different variables from the query string so that you can access them by name:
var request = {};
var pairs = location.search.substring(1).split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
request[pair[0]] = pair[1];
}
Then you can access it like request['varString'] and that will give you "bla-bla-bla".
Mostly you'd like to handle the parameters passed to your page in the server side, but if you got your reasons why to do it client-side, here's a small script i found:
function gup( name )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
i didn't test it, but i'm pretty sure it'll to the job.
just use it like: gup('parameter') and it'll return the parameter value for you.
To parse the query string through JS, you can view use something like
function getQueryValue(param) {
var queryStringArray = querystring && querystring.substring(1).split("&");
for (var i=0, length = queryStringArray.length; i < length; i++) {
var token = queryStringArray[i],
firstPart = token && token.substring(0, token.indexOf("="));
if (firstPart === param ) {
return token.substring(token.indexOf("=") + 1, token.length);
}
}
}
E.g. Given a URL "http://domain.com.au?aaa=bbb , you can call this fn as getQeuryValue("aaa") and you'll get "bbb"
I uploaded this code on Gist (bit modified to be compliant with a module pattern).
Thanks to the new URLSearchParams interface, it becomes easier:
var url = new URL("https://example.org/?foo=bar&foo2=bar2");
var params = url.searchParams;
// Access to a variable
console.log(params.get("foo"));
// Loop over params
for (var key of params.keys()) {
console.log(params.get(key));
}
You should check Mozilla Developer Network for browser compatibility, since it's a new API.

Categories