Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Useful for manipulating CSS
(function($) {
var rules = [], stylesheets = [], createCount = 0;
/**
* Given a scope (typically $(document)) all sheets are scanned until requested rule is found
*
* @author Adam Yanalunas
* @since 2010-01-24
*
* @param string|array Rules to be returned
* @return CSSStyleRule|null
*/
$.fn.CSSelection = function(action) {
if (0 == stylesheets.length) {
stylesheets = retrieveStylesheets($(document)[0]);
//What if there aren't any stylesheets on the page?
if(0 == stylesheets.length) {
stylesheets.push(createStylesheet());
}
}
if (typeof action === 'object') {
var rule = retrieveRule(this.selector);
//Only add if this rule doesn't already exist
if (null === rule) {
var addResult = addRule(this.selector, arguments[0]);
return this;
} else {
//Turn the CSS rule name into a JavaScript rule name (i.e.: border-color = borderColor)
for (ruleName in arguments[0].rules) {
var nameParts = ruleName.split('-');
for (var i = 1, len = nameParts.length; i < len; i++) {
nameParts[i] = nameParts[i].substring(0, 1).toUpperCase() + nameParts[i].substring(1, nameParts[i].length);
}
var cssName = nameParts.join('');
rule.style[cssName] = arguments[0].rules[ruleName];
}
return this;
}
} else if ('remove' === action) {
return removeRule(retrieveRule(this.selector));
} else {
return retrieveRule(this.selector);
return this;
}
}
/**
* Create a new stylesheet in the DOM
*
* @author Adam Yanalunas
* @since 2010-08-16
*
* @return HTMLStyle Reference to the newly-created, blank stylesheet
*/
var createStylesheet = function() {
var cssNode = document.createElement('style');
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
//cssNode.media = 'screen';
cssNode.title = 'dynamicSheet' + createCount;
document.getElementsByTagName("head")[0].appendChild(cssNode);
return cssNode.sheet;
}
/**
* Go through all style sheets. Sheets using @import are iterated over and added to flat list
* Interesting note: IE does not resolve .href to absolute path with protocol and host prefix.
* Therefore, if there's a protocol in .href using IE you know it's not a local styleSheet
*
* @author Adam Yanalunas
* @since 2010-01-25
*
* @param scope Typically $(document) but can be any given scope
* @return array One-dimensional list of all stylesheets loaded in scope
*/
var retrieveStylesheets = function(scope) {
var collection = scope.styleSheets;
var sheets = [];
var localDomain = document.location.host;
for (var i = 0, len = collection.length; i < len; i++) {
var sheetHref = collection[i].href || '';
var sheetHost = sheetHref.substring(sheetHref.indexOf('://')+3,sheetHref.length);
if(localDomain != sheetHost.substring(0,sheetHost.indexOf('/')) && 'http' == sheetHref.substring(0, 4)) continue;
var entries = getEntries(collection[i]);
if (0 < entries.length && 3 == entries[0].type) {
for (var j = 0; j < entries.length; j++) {
sheets.push(entries[j].styleSheet);
}
} else {
sheets.push(collection[i]);
}
}
return sheets;
}
/**
* Based on browser support return an array of CSS rules for a provided stylesheet
*
* @author Adam Yanalunas
* @since 2010-01-24
*
* @param sheet StyleSheet A style sheet object
* @return array List of rules, if any, in provided stylesheet
*/
var getEntries = function(sheet) {
if(typeof sheet == 'undefined') return [];
//if(0 == sheet.media.length) return [];
var rules = [];
if (sheet.rules) {
rules = sheet.rules;
} else if (sheet.cssRules) {
rules = sheet.cssRules;
}
return rules;
}
/**
* With local-global stylesheet list, searches for requested rule
*
* @author Adam Yanalunas
* @since 2010-01-24
*
* @param string ruleName Full scope name of rule
* @return CSSStyleRule|null
*/
var retrieveRule = function(ruleName) {
var rule = null;
for (var i = 0, slen = stylesheets.length; i < slen && rule == null; i++) {
var entries = getEntries(stylesheets[i]);
for (var j = 0, elen = entries.length; j < elen && rule == null; j++) {
if (entries[j].selectorText == ruleName) {
rule = entries[j];
/*rule.position = j;*/
}
}
}
return rule;
}
var makeRuleText = function(ruleSet) {
var rules = [];
for (var ruleName in ruleSet) {
rules.push([ruleName, ': ', ruleSet[ruleName], ';'].join(''));
}
return rules.join(' ');
}
/**
* Given a selector from jQuery, add a CSS rule with options for stylesheet and position
*
* @author Adam Yanalunas
* @since 2010-02-05
*
* @param jQuery selector CSS selector to have rule added
* @param settings Object literal with rule, stylesheet and poisition entry
* @return boolean
*/
var addRule = function(selector, settings) {
var styleSheet = settings.styleSheet || stylesheets[stylesheets.length - 1];
var position = settings.position || getEntries(styleSheet).length;
var rules = makeRuleText(settings.rules);
//IE
if (styleSheet.addRule) {
return styleSheet.addRule(selector, rules);
}
//Mozilla
else if (styleSheet.insertRule) {
return styleSheet.insertRule(selector + '{' + rules + '}', position);
}
return false;
}
/**
* Given a rule object, finds the parent stylesheet and uses supplied position to remove from list
*
* @author Adam Yanalunas
* @since 2010-02-05
*
* @param CSSelection rule Rule already selected from stylesheet
* @return boolean
*/
var removeRule = function(rule) {
if (rule) {
var styleSheet = rule.parentStyleSheet;
//Mozilla selector
if (styleSheet.cssRules) {
return styleSheet.deleteRule(rule.position);
//Others
} else {
return styleSheet.removeRule(rule.position);
}
}
return false;
}
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment