Log in

View Full Version : CSS Camelizer



magicyte
03-01-2009, 06:46 PM
This script takes normal css (e.g. "background-color") and converts it into "camel style" which can be parsed by JavaScript. Of course, it applies these styles to any element. Here:


function css(elem, options) {
var ss = (options.replace(/ /g, "")).split(";");
var privates = {};
for (var i = 0; i < ss.length; ++i) {
var s = ss[i].split(":");
while (1) {
if (s[0].indexOf("-") != -1) {
s[0] = s[0].replace(new RegExp(s[0].substr(s[0].indexOf("-"), 2), "g"), (s[0].substr(s[0].indexOf("-"), 2))[1].toUpperCase());
} else {
break;
}
}
document.getElementById(elem).style[s[0]] = s[1];
}
}

Syntax: css("myElement1", "background-color: blue; color: red; width: 200; height: 100;");

There's one flaw where if you try "border: 1px solid black;", its result will be "border:1pxsolidblack", thus "1pxsolidblack" is applied to border. This isn't an actual style, however, there is a messy way to avoid this, though I may not use it. Does anyone have an idea how I would avoid this problem cleanly?

Twey
03-01-2009, 09:19 PM
Like this:


function css(elem, options) {
if (typeof elem === "string")
elem = document.getElementById("elem");

elem.style.cssText += "; " + options;
}

Never make the user pass in an ID if they've got a reference to the element lying around. It's horribly inefficient, and very messy — and, of course, requires giving all their elements IDs.

However, this is passing around strings of code, and is a perfect example as to why doing so is a bad idea. Say, for example, since we don't want our viewers to suffer epileptic fits whilst reading our page, we want to first apply a filter function that will strip out all text-decoration: blink instructions. The only decent way to do this is to parse the string and break it down into a native data-type, remove the offending property, and then compile it back into a string! Horrible. Additionally, long strings get very difficult to read. Rather, it would be preferable to pass an object in the first place:


function css(elem, options) {
if (typeof elem === "string")
elem = document.getElementById(elem);

for (var x in options)
elem.style[x] = options[x];

return elem;
}

... and use it like:


css("myElement1", {
backgroundColor: "blue",
color: "red",
width: "200px",
height: "100px"
});

This is much more readable, allows us to apply proper formatting, and is much easier to work with, too: we can simply write our filter function thus:


Object.copy = function(o) {
var r = {};

for (var x in o)
if (o.hasOwnProperty(x))
r[x] = o[x];

return r;
};

function removeBlink(cssObj) {
var r = Object.copy(cssObj);

if (r.textDecoration === "blink")
delete r.textDecoration;

return r;
}

To half-answer your previous question, the proper way to parse such a string into an object would be:



Array.map = function(f, a) {
for (var i = a.length - 1, r = []; i >= 0; --i)
r[i] = f(a[i], i);

return r;
};

String.upperFirst = function(s) {
return s.charAt(0).toUpperCase() + s.substr(1);
};

String.trim = function(s) {
return s.replace(/^\s+/, "").replace(/\s+$/, "");
};

Object.fromArray = function(a) {
var r = {};

Array.map(function(pair) { r[pair[0]] = pair[1]; }, a);

return r;
};

var Css = (function() {
var jsEquivs = {
'float' : "css-float"
// &c.
};

function cssToObject(s) {
return Object.fromArray(Array.map(textToPair, s.split(";")));
}

function textToPair(s) {
var r = Array.map(String.trim, s.split(":"));

r[0] = propertyToCss(r[0]);

return r;
}

function propertyToJs(s) {
return Array.map(String.upperFirst, (jsEquivs[s] || s).split("-")).join("");
}

return {
propertyToJs: propertyToJs,
cssToObject: cssToObject
};
})();


Also note that "100" is not a proper value for a CSS property: it requires a unit.