Tuesday, November 6, 2007

jQuery.Rule

This plugin allows quick creation/manipulation of CSS Rules, in a "jQuery-way". It includes features like chaining, iteration using each, selectors with context. Many functions are available, like slice, pushStack, not, add, remove, append, css, and some more. As far as it has been tested, the plugin should perform well in most browsers, some specials methods still need some more testing. Feedback is much appreciated.

Links

Downloads

Downloads: I really advice using the minified versions. The code is optimized for those releases. Source versions should only be used to learn.

62 comments:

Anonymous said...

This is really neat code, and I have a great idea of how to use it to implement 'client-side hierarchical CSS,' like the SASS plugin for Ruby on Rails. However, I do note that the code does not work on the iPhone.

Flesler said...

Hi
I'm glad that you like my plugin, and you find it useful.
I haven't tried it on any iphone. I suppose DOM CSS rules have some quirks in Safari 3 IPhone. I did test it on Safari 3 Windows, and it worked perfectly.
Cheers.

Adrien said...

Hi,

Really good piece of code, great ideas, nice use of the power of jQuery... I love it!

I've found one minor "bug" and proposed some feature change > see the issues @ the jQuery plugin's page.

I'll post some code about new features too (import/disable sheet).

It could be nice to talk about the posibility to work on media too.

Ariel Flesler said...

Hi Adrien,

I see you added many bug reports, thanks for that!
I'll try to check them ASAP (I'm not very free but I can handle).

Enabling and disabling sheets can be done with the attribute 'disabled'. Did you get any problem with it ?

If you want to contact me, the email is in the header of the source code (of jQuery.Rule), That's my GTalk.

Cheers Adrien

Yereth said...

Man, I was just considering writing this plugin myself, because I thought it would be way cool if you could actually edit the CSS in general, instead of adding style properties to every matched item.

Then I found yours, which saves me many hours of work! Neat!

Ariel Flesler said...

Thanks Yereth

This plugin required a lot of work actually, DOM CSS rules are very very hard to manipulate in a safe and normalized way, among all four most used browsers.

Enjoy :)

Joe said...

Once again, excellent work Ariel. At first, I was thinking, "when would I use this?" But after realizing that it is actually changing the RULE itself, it can come in quite handy, especially if AJAX-generated content needs to be re-styled, so to speak.

Aman Gupta said...

Using $.rule to add styles fails when the css selectors contains commas themselves:

$.rule(" p{ margin: 0 } ").appendTo('link') // works
$.rule(" p,a{ margin: 0 } ").appendTo('link') // fails

Why do rules need to be comma delimited? It can split on } instead to break up the string into rules.

Ariel Flesler said...

Hi Aman

I actually fixed it, they don't get splitted by comma anymore.
But MSIE doesn't accept comma separated selectors within the function addRule.

I commented in the changelog, that this can be worked around, by splitting them manually, but that would yield more rule than expected, and different results depending on the browser.

That's why, while comma separated selectors are recognized.. they still error.

I advice you to just create two rules, or to use a class instead.

Cheers

Aman Gupta said...

This patch fixes the issue with commas in selectors, and makes commas optional when passing in css (should be backwards compatible though): http://p.ramaze.net/1339

@@ -99,8 +99,9 @@
return r;
},
clean:function( r ){
- return $.map( r.split(/\s*,\s*/), function( txt ){
- return $.rule.appendTo( txt, storage );//parse the string.
+ return $.map( r.split(/\s*}\s*,?\s*/), function( txt ){
+ if (!txt) return;
+ return $.rule.appendTo( txt+'}', storage );//parse the string.
});
},
parent:function( r ){//CSS rules in IE don't have parentStyleSheet attribute

Aman Gupta said...

Thanks Ariel. I upgraded to 1.0.1 and was having some issues because of newlines and no return in the $.map. This patch fixes my issues: http://p.ramaze.net/1340

@@ -111,8 +111,8 @@
},
clean:function( r ){
return $.map( r.split('}'), function( txt ){
- if( txt )
- return $rule.appendTo( txt + '}' /*, storage*/ );//parse the string, storage implied
+ if( !$.trim(txt) ) return;
+ return $rule.appendTo( txt + '}' /*, storage*/ );//parse the string, storage implied
});
},
parent:function( r ){//CSS rules in IE don't have parentStyleSheet attribute

I think it would be worth adding in an IE only hack that splits comma selectors into multiple selectors.

Ariel Flesler said...

Thanks for taking the time to make a diff.
I assumed you had the last release.

So, I don't now much change in your diff, you're only trimming 'txt' which I don't think is crucial.

As I told you, If I split the selectors on IE, it will generate more rules than on the rest of the browsers.
Then if you use methods like .eq() or .filter(), it will yield different results, leading to unexpectable problems/errors.

What do you think ?

Aman Gupta said...

Without the $.trim() and return, I get errors, especially if the css has trailing newlines.

I think slightly different but working results in IE is better than it just breaking.

Also, my first patch included a regex instead of simply splitting on '}'. That might be worth using instead, to keep backwards compatibility with people still using commas to delimit css rules.

Finally, the documentation at the top of the file still says to use commas when provides rules to append to the page.

Ariel Flesler said...

Ok thanks :)
I'll review this soon.. I need to think about it.

Cheers

Charles said...

Dear Ariel,

Thanks for your code. I have ahd a couple of problems:

1. In IE, it seems to be necessary to specify the CSS rule using capitals for the HTML elements, e.g.

DIV.resMed#main DIV#detMedia

even when in the style sheet it is in lower-case. Is this right? Firefox seems to be case-insensitive.

The other problem was that I sometimes got an error which looked like it was because of a cross-domain AJAX request, when accessing styles in an external stylesheet (i.e. using the 'link' element), even though the style sheet was on my domain. Strangely, it only happened some of the time and was quite difficult to replicate (although if you want I will try). This problem cleared up when I put the rule I wanted to change in a 'style' element instead.

Thanks again anyway - a useful plugin and an underestimated technique,
Charles

Ariel Flesler said...

Hi Charles

I never met the situation you first describe.
Do you think you can prepare a demo reproducing the problem ?

About the second issue... I don't recall very well, but I think it's not possible to access some link nodes, or they were read-only, something like that.

I'm not sure if it was a cross-domain thing, or any link.
The demo of this plugin does modify items in the link, so I suppose it is possible in some cases.

Cheers

Trevor Harrison said...

Great plugin.

However, it seems like its not working with the latest jQuery 1.2.6. If I backrev to 1.2.1 (which is the version your demo is using), it works fine.

Ariel Flesler said...

I haven't actually tested.
What is the problem you see ? nothing works ?

Trevor Harrison said...

Just the animation stuff is busted. (does nothing)

(Sorry, should have been more specific. I hate those vague 'it doesn't work' messages. )

Trevor Harrison said...

Oh, also, could you expound upon the difference between your "link" and "style" sections? I'm confused as to why there are 2 places to store css definitions.

Ariel Flesler said...

The 2nd (optional) argument of $.rule() is the context (just like with jQuery).

You specify where to look for rules that will match the selector.
$.rule('foo','link') will retrieve all the rules inside link elements, that match the selector 'foo'.

The context can be any jQuery selector.
if none is specified, it means all.

Andrew said...

Hi Ariel,

great, useful little plugin. Keep up the good work

cmroanirgo said...

Hey thanks Ariel for this plugin.

I seem to having some "Security Error" exceptions being thrown in FF using jQuery 1.2.6:

eg:
try { $.rule('span{font-size:30px;}').appendTo('link'); } catch (e) { alert(e.message || e); }

Will show 'Security Error'

It seems to work fine in IE7 however.

Ariel Flesler said...

Yeah, is the link included from another domain ? that's likely to cause a securityError.

Even if it's local, might happen too, I don't recall.

You can use an empty style (can be created with js) to achieve the same effect.

Eric said...

Hi Ariel -

Great helpful plugin.

I am having trouble with the conversion of rules to lower case. Since IE is case sensitive, getting and then re-applying the css is problematic when the classes applied to elements has any upper case in it.

Is there a critical reason why .cssText() and outerText() have to return everything converted to lower? e.g. if I remove the toLowerCase() will it blow up?

Thanks
Eric

Ariel Flesler said...

Hi Eric
IE makes it all uppercase (as far as I remember), so either way, the case won't be respected.

Damjan said...

Hi Ariel,

this is excellent plugin.

Is it possible to reset all changes made with this plugin, and keep other css rules (from css file)?

Thanks in advance!

Ariel Flesler said...

Hi

You could simply add all them to an empty style tag and whenever you want to reset, you either remove the rules or the style or disable the latter.

k@z@l said...

http://demos.flesler.com/jquery/scrollShow/

This scroll-show cold not show twice in a one page/layouy.Its id conflict to one another.Have any solution for multiply scroll-show in one layout?

Ariel Flesler said...

Hi
I'm no longer dev'ing scrollShow. I'd advice you to try serialScroll instead.

Anonymous said...

In FF3.5 (seems to be the same with chrome), storageNode stylesheet is inserted after the script tag used to load jquery.rule. So added rules can be without effect, because overwriten by already existing stylesheets. Perhaps the storageNode should be added only when the dom is ready

Ariel Flesler said...

That would generate an error for any rule added before document.ready... I'll check this asap.

anirudha said...

hello ariel i am anirudha
when i write a article in blogspot then blogspot give me small size in middle of page but i want to write look like your blog how it can possible in blogspot so send me answer to anirudhakumar.gupta@gmail.com

Ariel Flesler said...

I don't know, maybe it's a setting or part of the template, no idea :(

jim said...

suppose you had 2 style rules like:
p,li, h4, textarea{font-size:12px;}
p{font-family:sans-serif;}

now add:
$.rule('p','style').append('color:#333');

are you aware that it appends to both rules?

and when you remove:
$.rule('p','style').remove();
or
$.rule('p, li, h4, textarea','style').remove();

it removes both rules

Ariel Flesler said...

Yes, that's the expected behavior.

Anonymous said...

I got an error when the css string had a trailing whitespace, like so:

$.rule('#registerbox p{color:red} ');

Small bug, is it?

Ivan said...

Hi Ariel, thaks for the plugin, that´s a great job!

i'm having some troubles with firefox selecting a rule when it has more than one externals css ("link-rel"), for example i've added a twitter plugin into my page, and ff can´t build $.rule();

a suggestion would be that in the constructor the 2nd parameter you coud select 'style' or the name of the external 'css' not just 'link' because we could have same rules in diferent css files.

so, keep your effort.

regards,

ivan.gerardo@gmail.com

Ariel Flesler said...

@Ivan
The second parameter can be any css selector supported by jQuery.

Andreescu said...

Have anyone tested jQuery.rule with jQuery 1.4?

Not working anymore as expected (especially when working with style tag, with link seems OK)... see here http://dev4.clientproof.co.uk/gremki/test/jQuery.Rule.html

Chris said...

Hi. I like your plugin, but I've run into a problem when trying to unit test an application that uses it. I'm running it through Rhino with the Env.js DOM, and the storageNode on line 39 has neither "sheet" nor "styleSheet" attributes, causing an error. I'm not sure whether this is a problem with jQuery.Rule or Env.js, but I thought I'd let you know.

Obviously, it's not critical that styles work properly in a DOM that never gets rendered, so to avoid the errors I've just conditionally disabled parts of the plugin when running tests on Rhino.

Ariel Flesler said...

@Andreescu
The problem seems to be that jQuery.prop no longer exists on 1.4. Will handle this asap.

@Chris
Probably that is missing on env.js. It works on regular browsers.

Phrogz said...

Another problem with 1.4 can be seen here in this bug report.

przemek said...

Here is an example how to get .ui-widget-content class background style value in a cross-browser manner.
As you see you have to parse style text yourself with regular expression.

alert($.rule('.ui-widget-content','link').text().replace(/.*background[^:;]*:[^:;]*(#[0-9a-f]*|rgb[^)]*\)).*/i,'$1'));

Btw this plugin doesn't work with JQuery 1.4.2.
But with 1.4.1 version it works ok.

Cooper, Robertson & Partners said...

Hi,
I have a submenu of a parent item which is always expanded on all pages of my site. The submenu links to anchors within the page that the parent item links to. I have localscroll working nicely when you are on the page that contains the anchors but when I try link to one of the anchors from a different page it does not animate or retain the top offset specified. Is there a way to do this?

The only setting I have currently is:
$.localScroll({
offset:-147
});

I apologize if this is already mentioned somewhere, I spent some time looking but it’s been a long day so might have missed it :) .

Greatly appreciate any feedback,
Cecilia

zolid said...

To get this plugin back working in jQuery 1.4.2 add this little thingy:

jQuery.fn.setArray = function( elems ) { //fix for jQuery 1.4.2
this.length = 0;
jQuery.fn.push.apply( this, elems );
return this;
}

JulienW said...

to make it work in last jQuery, I replaced all "this.setArray" by "$.makeArray" and adding the parameter "this" at the end, like that :

if( typeof r == 'object' && !r.exec )
return $.makeArray(r.get ? r.get() : r.splice ? r : [r], this);
$.makeArray(this.sheets.cssRules().get(), this);

Chris said...

Here's a version that
1) works with jQuery 1.4.2
2) also loads all sheets imported with an @import directive

Dejan said...

Does anyone have working code for JQuery 1.4.2 version? can you send me to dejanc at gmail dot com?

BluffIT said...

Nice tool.

I'd like to replicate the block tags
i.e. H1 as a class (say .H1)

In other words create a class .h1 that equals h1

How would I do this? thank you.

BluffIT said...
This comment has been removed by the author.
Jonas Lundman said...

This is a Great plugin and I´ve been using it for a time. However I couldn´t find an update or a recent version, since my project upgraded jquery core. Finally I stumbled on a google search and fixed the old version to work. That version is from may 2010. Please give this tool a better place to live & survive, to be found (update jQ plugin page) and make more people happy -as I am for this little goodie! Thanks Arial.

524684 said...

Hello,

I am really exited about this plugin. Unfortunately it doesn't seem to be compatible with jquery 1.5.

I get a "jQuery is not defined" in firebug.

Is there any chance this will be supported soon?

Thanks,

Tim

medihack said...

There is a very nice up-to-date library for fetching and setting CSS rules named JSS (https://github.com/Box9/jss). It is not jQuery but pure Javascript. It has a really nice API and is quite small. And if you are looking for animations using CSS rules then I just relased a tiny jQuery extension named jQuery Fanimate (https://github.com/medihack/jquery-fanimate). Works with jQuery 1.4.3+.

medihack said...

I just want to let you know that jQuery Fanimate (mentioned in my last comment) is now called jQuery Mass Animate.
Project at GitHub, Demo

ESquared said...

Could you run your code through jslint please (http://jslint.com/)? There are some best practices that your code urgently needs to adopt. The worst is the dual use of $rule as both a constructor and an instantiated object. The use of '==' instead of '===' and 'property in object' are additional problematic aspects. Thank you for the great tool.

ESquared said...

Could you run your code through jslint please (http://jslint.com/)? There are some best practices that your code urgently needs to adopt. The worst is the dual use of $rule as both a constructor and an instantiated object. The use of '==' instead of '===' and 'property in object' are additional problematic aspects. Thank you for the great tool.

luka.ramishvili said...

can there be ANY documentation for this plugin? I really appreciate the hard work that has been done, but until there's decent documentation, the plugin is making people's lives harder, not easier.
P.S. the 27-line (31 if you count blank lines) is NOT a documentation, and I'm sad that I cannot write the docs myself because I'm not that familiar with the code.

madhuri said...

Thanks for sharing about the JQuery rule for all the files and docs.It would help me out.
Cheers !
web design company

Erebcab SAĞIROĞLU said...

Hi,
My style block as that:

#mydiv{background-color:red;color:yellow;font-size:15px;height:400px;}


my question is: how can i remove just height rule.
thanks

zeah said...

Hey i wasnt able to use the plug with jquery1.6.2

i tried
$.rule('.scale_1x .rating_scale .foils li','style').css('max-width',''+css_width+'');

to change calculated width to the style sheet.

Any ideas?

Alux-Studio said...

$.curCSS is not available in jQuery 1.8, breaking the plugin