Monthly Archives: October 2008
CSS Organizer and Minifier
The Problem
During the development process I may have several CSS files containing all sorts of rules. These names may be based by page or the general rules contained in each file. However, in production, from both a maintainability and performance perspective, the last thing you want is several files. Ideally, you would like a single, compact CSS file for production. If usings themes, you may want more. So between development and production, you want two very different things.
The Proposed Solution
Normally, when one needs to go from a raw material to a finished products, a tool is used. In this case, I need something that can process my CSS files between development and production. Maybe it can also do some additional items during processing, like code formatting, file organization, or minification. I did not find such a tool that existed. So I have undertaken this project to develop such a tool.
With any tool there are guidelines or a practice. You wouldn’t use a chainsaw while building a dollhouse. So even though this will not fit the need, my hope is that this tool will nonetheless help.
Project Specification
I know we are all different, which makes this project near impossible. I have done the best to accommodate that into this spec. Nonetheless, with every tool there are guidelines. I mean you wouldn’t use a chainsaw while building a dollhouse. My hope is that by adopting a few industry conventions, and drawing some lines, this tool will help a maximum audience.
- Accept CSS files
- files can be within directories
- ability to provide file cascade manually or automatically from convention
- Process CSS files
- categorize declarations into three groups: layout, typography, and style
- output categorized CSS into repectively named files
- Miscellaneous
- validation
- simple formatting options
- simple minification options: whitespace, shorthands, duplication
In Closing
I have begun an alpha version following the above spec in Java. My goal is to create a proof of concept and use it during a project before releasing a web version on this site. However, you requests are required. So please, post comments or send me feedback directly.
JavaScript Cookie Object using Prototype
I have been using Prototype for the last year. I am still relatively new, but so far it does everything I need it to do natively. I have build many reusable scripts that do everything from adding simple events to automatic front-end form validation. With additional visual effects by the partnering Scriptaculous library, there isn’t much left. That is until I came across the need for front-end cookie management.
Why Front-End Cookie Management
As a back-end programmer, front-end cookie management seems silly. Why would I need or want to use something like JavaScript to manage cookies. Until recently, I would have just used PHP or Ruby for the job. However, I have found myself on contract as Lead Front-End developer. As such, those technologies are not available to me. Furthermore, tasking someone down on the IT side of the house can be a time consuming hassle. And came you blame them? I’m able to reverse the roles, and if some marketing guy asked me to set up a cookie to store XYZ, I’d laugh. Rightly so too, why should I waste such time storing things like text size, toggled modules, etc on the back-end. After all, aren’t such examples why cookies exist. User settings or preferences may necessitate back-end involvement, and these can be stored in a cookie for convenience. Yet, something dealing with the UI doesn’t really warrant involvement.
Where’s the Cookie Monster
So the obvious choice to manage cookies on front-end is JavaScript. During research, I came across two interesting pages. The first was a collection of Top 10 JavaScripts, with the top being cookie management functions ported from PHP. Second was a JavaScript class called CookieJar. At first, I didn’t quite understand the point. See to JavaScript the cookie comes across as a simple key value pair as semi-colon separate string in document.cookie. If you want to track several variables, you would need to set as many cookies. That would get old… err stale. Anyway, instead of having all these cookies floating around, the JavaScript CookieJar organized then for you.
Enter Prototype
CookieJar was a little primitive. The premise, to store the variables as a hash in a single cookie, was sound. But it didn’t actually handle cookie storage. Now this may be kitchen for the Object Oriented elitists, but I merged the two scripts. To regain some ground, I wanted my Cookie class to be a Singleton Gateway. As such, it should do everything required to access, manage, and maintain the Cookie. Since I was already using Prototype, I took advantage of its Hash object. I ended up with the script below.
var Cookie = {
data: {},
options: {expires: 1, domain: "", path: "", secure: false},
init: function(options, data) {
Cookie.options = Object.extend(Cookie.options, options || {});
var payload = Cookie.retrieve();
if(payload) {
Cookie.data = payload.evalJSON();
}
else {
Cookie.data = data || {};
}
Cookie.store();
},
getData: function(key) {
return Cookie.data[key];
},
setData: function(key, value) {
Cookie.data[key] = value;
Cookie.store();
},
removeData: function(key) {
delete Cookie.data[key];
Cookie.store();
},
retrieve: function() {
var start = document.cookie.indexOf(Cookie.options.name + "=");
if(start == -1) {
return null;
}
if(Cookie.options.name != document.cookie.substr(start, Cookie.options.name.length)) {
return null;
}
var len = start + Cookie.options.name.length + 1;
var end = document.cookie.indexOf(';', len);
if(end == -1) {
end = document.cookie.length;
}
return unescape(document.cookie.substring(len, end));
},
store: function() {
var expires = '';
if (Cookie.options.expires) {
var today = new Date();
expires = Cookie.options.expires * 86400000;
expires = ';expires=' + new Date(today.getTime() + expires);
}
document.cookie = Cookie.options.name + '=' + escape(Object.toJSON(Cookie.data)) + Cookie.getOptions() + expires;
},
erase: function() {
document.cookie = Cookie.options.name + '=' + Cookie.getOptions() + ';expires=Thu, 01-Jan-1970 00:00:01 GMT';
},
getOptions: function() {
return (Cookie.options.path ? ';path=' + Cookie.options.path : '') + (Cookie.options.domain ? ';domain=' + Cookie.options.domain : '') + (Cookie.options.secure ? ';secure' : '');
}
};
Example Usage
Currently, the Cookie class only handles a single named cookie. This is acceptable since you can store multiple variables in a single cookie. However, I want to refactor this class from a Singleton to a Factory. Look for that in the future. In the meantime, here are some current sample uses:
Cookie that expires 90 days from visit, and sets a value:
Cookie.init({name: 'yourdata', expires: 90});
Cookie.setData('favorites', false);
Cookie that only lasts the session, with default data:
Cookie.init({name: 'mydata'}, {foo: 'bar', x: 0});
alert(Cookie.getData('foo'));
A Few Sweet Spots
I wanted all the cookie variables to be stored in a single cookie. The class does allow you to still make independent Cookies. In order to store data, I would need some format to store my Cookie data. What better than JSON, and Prototype has a toJSON method.
I also wanted to encapsulate the cookie data. Plus since I was storing the cookie data as a Hash, I may have future changes. So the getData, setData accessor methods can be used for data management. And In Rails-esk fashion, I auto-save the cookie at the end of setData.
Finally, the Cookie auto-loads or is auto-created depending on the name passed to init. It will look in document.cookie and if it doesn’t exist it will create a cookie with the settings provided. Finally, it loads the cookie data.
In Closing
Prototype did not natively extend JavaScript with a Cookie object. However, by leveraging a few other classes, and the scripts mentioned above, I came up with a quick solution. Given, this class does not contain everything and could benefit from a code review. In the future, I may revisit the loading and possibly build some convenience methods to allow Cookie['key'] instead of Cookie.getData('key'). Yet for what it does in 60 lines, it is more than able to handle my front-end needs.