Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

IE support and partial Opera support

  • Loading branch information...
commit 04e3560a3c8b51115d1e99be75189f46e9febdce 1 parent 7406cf9
thingsinjars authored
Showing with 191 additions and 156 deletions.
  1. +32 −26 index.html
  2. +159 −130 jquery.scoped.js
View
58 index.html
@@ -1,52 +1,58 @@
<!DOCTYPE html>
<html>
-<head>
- <meta charset="utf-8" />
- <title>jQuery Scoped CSS</title>
- <style type="text/css">
- body {
- margin:0 auto;
- background:#646362;
- text-align:center;
- width:75%;
- font-family:helvetica,arial,sans-serif;
- }
- p {
- border-radius:5px;
- }
- p {padding:1em;margin:1em;}
- </style>
-
+ <head>
+ <meta charset="utf-8" />
+ <title>jQuery Scoped CSS</title>
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+ <!-- Unscoped block -->
+ <style type="text/css">
+ body {
+ margin:0 auto;
+ background:#646362;
+ text-align:center;
+ width:75%;
+ font-family:helvetica,arial,sans-serif;
+ }
+ p {
+ padding:1em;
+ margin:1em;
+ border-radius:5px;
+ }
+ </style>
</head>
<body>
- <!-- Unscoped block -->
+ <!-- Unscoped block -->
<style type="text/css">
p {background:#22ab22;color:white;}
a {outline:1px solid yellow;color:white;}
- p.bordered {border:3px solid white;}
+ p.bordered {border:3px solid white;}
</style>
<p><button onclick="$.scoped();">Enable scoping</button></p>
<p>ForestGreen background, white text</p>
- <p class="bordered">White border. <a href="#nowhere">Yellow outline</a>.</p>
+ <p class="bordered">White border. <a href="#nowhere">Yellow outline</a>.</p>
<section>
+ <!-- Scoped block -->
<style type="text/css" scoped="scoped">
p {background:#ffdead;color:black;}
a {outline:1px solid black; color:black;}
- p.bordered {border:3px solid black;}
+ p.bordered {border:3px solid black;}
</style>
<p>NavajoWhite background, black text</p>
- <p class="bordered">Black border. <a href="#nowhere">This should have a black outline</a>.</p>
+ <p class="bordered">Black border. <a href="#nowhere">This should have a black outline</a>.</p>
</section>
<section>
+ <!-- Scoped block -->
<style type="text/css" scoped="true">
- @import url('external.css');
+ @import url('external.css');
p {background:#ff4500;color:white;}
a {outline:1px solid white;}
</style>
<p>OrangeRed background, white text</p>
- <p class="bordered">No border. <a href="#nowhere">White outline</a>. External @import.</p>
+ <p class="bordered">No border. <a href="#nowhere">White outline</a>. External @import.</p>
</section>
- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
- <script src="jquery.scoped.js"></script>
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.js"></script>
+ <script src="jquery.scoped.js"></script>
</body>
</html>
View
289 jquery.scoped.js
@@ -1,160 +1,189 @@
/*
- * jQuery Scoped CSS plugin
+ * jQuery Scoped CSS plugin
* This adds support for the CSS scoped attribute to limit a block of style declarations
* to a specific area of the HTML. You can also use @import and media filters in scoped blocks
* http://www.w3.org/TR/html5/semantics.html#the-style-element
*
- * Simon Madine, 30 January 2011
- *
- * Use:
+ * Simon Madine, 30 January 2011
+ *
+ * Use:
* Include this plugin file (minified, ideally) and call $.scoped() on load
*
* Limitations:
* - If you're using multiple nested declarations, Webkit might apply different inheritance
* specificity rules from the other engines. I don't know who's right.
- *
+ *
* Notes:
- * - Style elements really shouldn't have classes added to them. This functionality should
+ * - Style elements really shouldn't have classes added to them. This functionality should
* probably use some kind of data attribute.
- * - The scoped blocks are emptied out because there is also no support for the disabled
+ * - The scoped blocks are emptied out in non-IE because there is also no support for the disabled
* attribute. This plugin could probably enable that attribute as well at no extra cost.
* - Currently, getElementStyles is hand-rolled and probably wrong.
*
* v0.5 2011-01-30
- * Sibling blocks work, most nested blocks work but some oddness in Webkit means that some
+ * Sibling blocks work, most nested blocks work but some oddness in Webkit means that some
* styles don't inherit correctly when there are multiple nested declarations.
*
- * v0.4 2011-01-29
- * First jQuery plugin version. Works for most cases but gets confused when there are
+ * v0.4 2011-01-29
+ * First jQuery plugin version. Works for most cases but gets confused when there are
* multiple scoped blocks affecting the same context (siblings).
*
*/
(function ($) {
- //Add this to the global jQuery object as we want to apply this once to the entire document
- $.scoped = function() {
-
- //Backup the original styles
- backupBlocks();
-
- //Go through once to add dependencies
- $('style').each(function(index) {
- if( isScoped($(this)) ) {
- $this = $(this);
- $this.addClass('this_is_'+index);
-
- //Get all style blocks in this scope
- //Including nested blocks
- $this.parent().find('style').each(function(i) {
- //Add a dependency class here to check for later
- $(this).addClass('depends_on_'+index);
- });
- }
- });
+ //Add this to the global jQuery object as we want to apply this once to the entire document
+ $.scoped = function() {
- //Go through a second time to process the scopes
- $('style').each(function(index) {
- $this = $(this);
- if( isScoped($this) ) {
-
- //Empty all scoped style blocks
- //Except those that this context is dependant on
- emptyBlocks($this);
+ //Backup the original styles
+ backupBlocks();
- var holdingArea = [];
+ //Go through once to add dependencies
+ $('style').each(function(index) {
+ if( isScoped($(this)) ) {
+ $this = $(this);
+ $this.addClass('this_is_'+index);
- //Read all styles and copy them to a holding area
- $this.parent().find('*').each(function() {
- var this_tag = this.nodeName;
- $(this).css('cssText','');
- if(this.nodeName != 'STYLE') {
- holdingArea.push(getStylesText(this));
- }
- });
+ //Get all style blocks in this scope
+ //Including nested blocks
+ $this.parent().find('style').each(function(i) {
+ //Add a dependency class here to check for later
+ $(this).addClass('depends_on_'+index);
+ });
+ }
+ });
- //Copy all the styles back from the holding area onto the in-scope elements
- $this.parent().find('*').each(function() {
- var this_tag = this.nodeName;
- if(this.nodeName != 'STYLE') {
- $(this).css('cssText',holdingArea.shift());
- }
- });
-
- //Put all other style blocks back
- fillBlocks();
- }
- });
-
- //Measurements done and styles applied, now clear styles from this style block
- //This will stop them affecting out-of-scope elements
- $('style').each(function(index) {
- if( isScoped($(this)) ) {
- $(this).html('');
- }
- });
+ //Go through a second time to process the scopes
+ $('style').each(function(index) {
+ $this = $(this);
+ if( isScoped($this) ) {
- //Standard jQuery attribute selector $('style[scoped]') doesn't
- //work with empty boolean attributes so this is used instead
- function isScoped(styleBlock) {
- return ( $(styleBlock).attr('scoped') != undefined );
- }
+ //Empty all scoped style blocks
+ //Except those that this context is dependant on
+ emptyBlocks($this);
- //Save all style tag contents to a temporary array.
- //It might be better to move the contents to a data attr
- function backupBlocks() {
- $('style').each(function(i) {
- if( isScoped($(this)) ) {
- $(this).data('original-style', $(this).html());
- }
- });
- }
- //Each style block now has class="depends_on_1 depends_on_2"
- //We switch off all the scoped style blocks not mentioned in that list
- function emptyBlocks(currentBlock) {
- $('style').each(function(i) {
- if( isScoped($(this)) ) {
- if(!currentBlock.hasClass('depends_on_'+i)) {
- $('style').eq(i).html('');
- }
- }
- });
- }
-
- //Put all the styles back to reset for the next loop
- function fillBlocks() {
- $('style').each(function(i) {
- if( isScoped($(this)) ) {
- $(this).html($(this).data('original-style'));
+ var holdingArea = [];
+
+ //Read all styles and copy them to a holding area
+ $this.parent().find('*').each(function() {
+ var this_tag = this.nodeName;
+ $(this).css('cssText','');
+ if(this.nodeName != 'STYLE') {
+ holdingArea.push(getStylesText(this));
+ }
+ });
+
+ //Copy all the styles back from the holding area onto the in-scope elements
+ $this.parent().find('*').each(function() {
+ var this_tag = this.nodeName;
+ if(this.nodeName != 'STYLE') {
+ var this_style = holdingArea.shift();
+ if($.browser.msie) {
+ for(var n in this_style) {
+ this.style[n]=this_style[n];
+ }
+ } else if($.browser.opera) {
+ for(var n in this_style) {
+ this.style.setProperty(n, this_style[n]);
+ }
+ } else {
+ $(this).css('cssText',this_style);
+ }
+ }
+ });
+
+ //Put all other style blocks back
+ fillBlocks();
+ }
+ });
+
+ //Measurements done and styles applied, now clear styles from this style block
+ //This will stop them affecting out-of-scope elements
+ $('style').each(function(index) {
+ if( isScoped($(this)) ) {
+ if($.browser.msie) {
+ $(this).attr('disabled', 'disabled');
+ } else {
+ $(this).html('');
}
- });
- }
-
- //Update this bit with some jQuery magic later
- function getStylesText(element) {
- if(navigator.userAgent.indexOf("MSIE") != -1) {
- //isIE (untested)
- return element.currentStyle;
- } else if(navigator.userAgent.indexOf("Firefox") != -1) {
- //isFirefox
- var temp = document.defaultView.getComputedStyle(element, null);
- var styles = '';
- for(var n in temp) {
- if(parseInt(n,10)) {
- var key = camelize(temp[n]);
- if(temp[key] != undefined) {
- styles += temp[n]+':'+temp[key]+';\n';
- }
- }
- }
- return styles;
- } else {
- return document.defaultView.getComputedStyle(element, null).cssText;
- }
- }
- //from Prototype
- function camelize(string) {
- return string.replace(/-+(.)?/g, function(match, chr) {
- return chr ? chr.toUpperCase() : '';
- });
- }
- }
+ }
+ });
+
+ //Standard jQuery attribute selector $('style[scoped]') doesn't
+ //work with empty boolean attributes so this is used instead
+ function isScoped(styleBlock) {
+ return ( $(styleBlock).attr('scoped') != undefined );
+ }
+
+ //Save all style tag contents to a data object
+ function backupBlocks() {
+ $('style').each(function(i) {
+ if( isScoped($(this)) ) {
+ $(this).data('original-style', $(this).html());
+ }
+ });
+ }
+
+ //Each style block now has class="depends_on_1 depends_on_2"
+ //We switch off all the scoped style blocks not mentioned in that list
+ //The disabled attribute only works on IE but coincidentally,
+ //IE doesn't allow .html() on style blocks.
+ function emptyBlocks(currentBlock) {
+ $('style').each(function(i) {
+ if( isScoped($(this)) ) {
+ if(!currentBlock.hasClass('depends_on_'+i)) {
+ if($.browser.msie) {
+ $('style').eq(i).attr('disabled', 'disabled');
+ } else {
+ $('style').eq(i).html('');
+ }
+ }
+ }
+ });
+ }
+
+ //Put all the styles back to reset for the next loop
+ function fillBlocks() {
+ $('style').each(function(i) {
+ if( isScoped($(this)) ) {
+ if($.browser.msie) {
+ $(this).removeAttr('disabled');
+ } else {
+ $(this).html($(this).data('original-style'));
+ }
+ }
+ });
+ }
+
+ //Update this bit with some jQuery magic later
+ function getStylesText(element) {
+ if($.browser.msie || $.browser.opera) {
+ //We actually work with a style object in IE rather than the text
+ return element.currentStyle;
+ } else if($.browser.mozilla) {
+ //We extract and process the ComputedCSSStyleObject into text
+ var temp = document.defaultView.getComputedStyle(element, null);
+ var styles = '';
+ for(var n in temp) {
+ if(parseInt(n,10)) {
+ var key = camelize(temp[n]);
+ if(temp[key] != undefined) {
+ styles += temp[n]+':'+temp[key]+';\n';
+ }
+ }
+ }
+ return styles;
+ } else {
+ //Webkit implements cssText on ComputedCSSStyleObjects so we can use it here
+ return document.defaultView.getComputedStyle(element, null).cssText;
+ }
+ }
+ //from Prototype
+ function camelize(string) {
+ return string.replace(/-+(.)?/g, function(match, chr) {
+ return chr ? chr.toUpperCase() : '';
+ });
+ }
+ function uncamelize(string) {
+ return string.replace(/[A-Z]/g, '-$&').toLowerCase();
+ }
+ }
})(jQuery);
Please sign in to comment.
Something went wrong with that request. Please try again.