Section D. Changing entire style sheets


D. Changing entire style sheets

Warning

Browser incompatibilities ahead


Changing entire style sheets works in Internet Explorer for Windows and Mozilla, and in no other browsers. Therefore this technique isn't ready for prime time yet, apart from the fact that editing an entire style sheet rarely makes sense. However, we'll take a look at it anyway, since I use this technique in Edit Style Sheet.

Theory

A document contains one or more style sheets, each of which contain one or more rules. Every rule contains one selector and an unlimited number of style declarations. Just as with the inline styles, these style declarations are accessible through the style property of the rule.

Figure 9.2. Every style sheet contains one or more rules. Every rule contains a selector and one or more declarations, each of which consists of a name/value pair.


In addition, Explorer and Mozilla support the addition and removal of entire rules from the style sheet. Although Edit Style Sheet doesn't use this feature, we'll treat it below.

Although the addition and removal of rules has been specified by W3C, Explorer supports only its own version. So a bit of object detection is necessary when you want to use these features.

document.styleSheets

The first requirement for successful style-sheet editing is support for the document.styleSheets nodeList. If the browser doesn't support that, the script won't work.

Therefore, Edit Style Sheet's initStyleChange() function starts by checking support:

[Edit Style Sheet, lines 5-7]

function initStyleChange() {     if (!document.styleSheets) return;     var sheets = document.styleSheets; 


If the browser doesn't support document.styleSheets at all, the function ends immediately. Otherwise, the script creates a sheets variable that refers to the document.styleSheets nodeList.

document.styleSheets contains all style sheets in the document, whether they're embedded or linked. Take this bit of HTML:

<head> <link type="text/css" rel="stylesheet" href="main.css" /> <link type="text/css" rel="stylesheet" href="colors.css" /> <style type="text/css"> .specialCase {     color: #cc0000; } </style> </head> 


Now document.styleSheets contains three style sheets: the linked main.css, the linked colors.css, and the embedded .specialCase rule. As usual, they're numbered in the order they appear in the source code, and the first one has index 0. Therefore, the embedded style sheet is document.styleSheets[2].

Edit Style Sheet has to search for the style sheet that users are allowed to edit. In my example script, it's called colors.css:

[Edit Style Sheet, lines 8-13]

for (var i=0;i<sheets.length;i++) {    var ssName = sheets[i].href.substring(sheets[i].href.lastIndexOf('/')+1);    if (ssName == 'colors.css')            var currentSheet = sheets[i]; } if (!currentSheet) return; 


The script goes through all style sheets and searches to their href property to find the style-sheet name after the last slash. If this name is equal to colors.css, the script has found the correct style sheet, and stores it in currentSheet.

If currentSheet doesn't have a value after this loop, colors.css is missing, and the function ends.

cssRules[] and rules[]

Warning

Browser incompatibilities ahead


Edit Style Sheet needs access to all the rules in the style sheet. Mozilla uses the W3C-specified cssRules[] nodeList, while Explorer needs the Microsoft-proprietary rules[] nodeList. Fortunately, these two nodeLists are exactly the same except for their names:

[Edit Style Sheet, lines 14-18]

if (currentSheet.cssRules)    sheetRules = currentSheet.cssRules; else if (currentSheet.rules)    sheetRules = currentSheet.rules; else return; 


Therefore, a simple object detection is enough. If the browser supports cssRules[], store this nodeList in sheetRules; if it supports rules[], store that nodeList in sheetRules. If the browser supports neither, the script won't work, and it ends.

Note that sheetRules is a global variable; other functions will need this information, too.

selectorText

Every rule has a selectorText, which contains, unsurprisingly, the rule selector as a string.

When the user selects a new rule to edit from the first select, the assignRule() function searches for this rule and opens it for editing:

[Edit Style Sheet, lines 48-55]

function assignRule() {    var selector = this.value;    for (var i=0;i<sheetRules.length;i++)            if (sheetRules[i].selectorText.toLowerCase() == selector.toLowerCase())                    currentRule = sheetRules[i]; } 


It takes the desired selector (i.e., the select box's value), and then goes through all the rules in sheetRules. When it finds a rule with a matching selectorText, it points currentRule to this rule. currentRule, too, is a global variable, since other functions need access to the rule that's currently being edited.

One word of warning: some browsers (Explorer and Safari at the time of writing) return an UPPERCASE selector text. Therefore, the above function compares selectorText.toLowerCase() to selector.toLowerCase().

style

Every rule has a style property that works exactly like the style property of individual HTML elements we discussed in 9A. If we wanted to change the color of currentRule to green we could do this:

currentRule.style.color = '#00cc00'; 


Now all elements that take their style information from this rule will change their color to green.

The assignStyles() function is called whenever the user changes a style declaration through the main form. It sets the correct style of the current rule to the correct value:

[Edit Style Sheets, lines 57-64]

function assignStyles() {     if (!currentRule) return;     var styleName = this.name;     var styleValue = this.value;     if (this.type == 'checkbox' && !this.checked)            styleValue = '';     currentRule.style[styleName] = styleValue; } 


First it checks for a currentRule, and if there is none, it exits. Then it takes the name and value of the form field the user has changed:

<input type="checkbox" name="fontWeight" value="bold" /> 


Checkboxes need special treatment: if they are not checked, the CSS property value they set should be empty. We already discussed the last line of this function in 5G. It sets the correct style property of the current rule (currentRule.style[styleName]) to the correct value.

Now the browser implements the revised styles, and the user immediately sees the effect of her changes.

cssText and submitting the style sheet

Since Edit Style Sheet never left the prototype phase, I never devised a way to send the edited style sheet back to the server. Nonetheless, the script is useless without some sort of submission that allows the server to store and use the updated style sheet.

The simplest way would be to copy the entire text content of the style sheet, store it in a hidden textarea, and send it to the server. A server-side program would create a neat file and store it as colors.css. Thus the style sheet would become available to all users of the site.

Warning

Browser incompatibilities ahead


The problem is that there's no simple cross-browser way of reading the entire text of the style sheet. The W3C DOM CSS module contains the cssText property, but the browsers don't entirely agree on the scope of this property.

cssText contains style declarations as a string. But which style declarations? There are three ways to use cssText:

1. document.styleSheets[0].cssText; 2. document.styleSheets[0].cssRules[0].cssText; 3. document.styleSheets[0].cssRules[0].style.cssText; 


The first example would give the entire style sheet as a string; that's exactly what we need for Edit Style Sheets. If we pasted document.styleSheets[0].cssText into a hidden text area, we'd be ready.

Unfortunately, Mozilla doesn't support this use of cssText. For this reason, I was sorely tempted to restrict this script to Explorer Windows, but its implementation was delayed several times, and in the end I didn't solve this conundrum.

Browser Compatibility

At the time of writing, the first use of cssText was supported only by Explorer (Windows and Mac), the second one only by Explorer Mac and Mozilla, while only the third one is supported by all browsers. These compatibility patterns may change, though.


Inserting and deleting rules

You can insert new rules into a style sheet, or remove rules from it. This feature is not used in Edit Style SheetI definitely don't want a user who knows little of CSS to insert new rules that might mess up the entire page.

Warning

Browser incompatibilities ahead


Nonetheless, inserting and deleting rules is important enough to treat. Unfortunately, this area of JavaScript again contains some browser incompatibilities. Mozilla uses the W3C-specified insertRule() and deleteRule() methods, while Explorer uses the Microsoft-proprietary addRule() and removeRule() methods. Safari and Opera don't support these actions at all.

As soon as you insert a rule, the style declarations in it are immediately applied to all relevant elements. Deleting a rule immediately removes these style declarations from all relevant elements.

insertRule() and addRule()

When you are inserting a new rule, the browsers expect three bits of information:

  1. The selector of the new rule.

  2. The style declarations of the new rule, as a string.

  3. The position of the new rule (first rule of the style sheet, last rule, somewhere in between?).

The W3C insertRule() and Microsoft addRule() methods need this information, but they differ in the way they want it delivered.

W3C's insertRule() expects two arguments:

  1. The entire rule (selector + declarations) as a string.

  2. The position of the new rule (0 = first rule in the style sheet, etc.).

Example:

var x = document.styleSheets[0]; x.insertRule('PRE {font: 0.9em verdana}',2) 


Now this CSS rule is added to the first style sheet of the page, as the third rule (with index 2).

pre {     font: 0.9em verdana; } 


Microsoft's addRule() expects three arguments:

  1. The selector as a string.

  2. The declarations as a string.

  3. The position of the new rule.

Example:

var x = document.styleSheets[0] x.addRule('PRE', 'font: 0.9em verdana',2) 


This gives exactly the same result as the previous code example: the same CSS rule is added as the third rule in the style sheet.

deleteRule() and removeRule()

If you want to delete a rule, you should specify which one by giving its index number. So in order to delete the rule we just inserted, we should do this:

var x = document.styleSheets[0] x.deleteRule(2); // W3C x.removeRule(2); // Microsoft 


Now the third rule in the first style sheet is deleted.

Helper functions

In order to defeat these rule-related browser incompatibilities, we have to create two helper functions. Deletion is easy:

function deleteCSS(sheet,index) {     if (sheet.deleteRule)             sheet.deleteRule(index);     else if (sheet.removeRule)             sheet.removeRule(index); } 


Inserting a rule is slightly more complicated because of the different arguments the functions expect:

function insertCSS(sheet,selector,declarations,index) {    if (sheet.insertRule) {            var toBeInserted  = selector + ' {' + declarations + '}';            sheet.insertRule(toBeInserted,index);    }    else if (sheet.addRule)            sheet.addRule(selector,declarations,index); } 




ppk on JavaScript. Modern, Accessible, Unobtrusive JavaScript Explained by Means of Eight Real-World Example Scripts2006
ppk on JavaScript. Modern, Accessible, Unobtrusive JavaScript Explained by Means of Eight Real-World Example Scripts2006
ISBN: N/A
EAN: N/A
Year: 2005
Pages: 116

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net