SCRIPTING:

Nadja Auermann
LOCATE PREVAILING STYLE SHEET FOR A LAYER
Style sheets can affect a layer accordingly to a cascading order: a function to locate for sure what style sheet is prevailing.

Inline style declaration checked first, then document style sheets (including style tags) are scanned from bottom up and the first class matching for the layer is stored. Then a further scanning is performed to locate any possible #layerId class rule notation because such notation would prevail on the dot class notation regardless of the fact the latter declaration is located after the former.
June 2004
{ @ }
The model above is Nadja Auermann
LOADS OF NADJA AUERMANN ON THE NET


Purpose of the script
What is the problem that this script solves

Salvador Dali
Salvador Dali, Moving Still Nature, 1956
This script I feature here works on all generation 5 browsers upward, namely Internet Explorer 5 and higher, and Netscape 5 and higher, and on all browsers which recognize the World Wide Web Consortium syntax:
document.styleSheets

That syntax is generation 5, and is an official recommendation; yet be aware that a few allegedly generation 5 compliant browsers are still not fully compliant: the remarkable case in point to date, namely at least until version 7, is Opera: Opera seems completely unable to understand that document.styleSheets syntax, though it perfectly understands other generation 5 browsers syntaxes.

Enough about compliance.
As for style sheets, style sheets can cause multiple problems when you try to address them by javascript, because they are burry objects. An incredibly consistent set of functions that deal with style sheets can be found clicking here.
Yet that file deals with style sheets in order to find all the declarations that belong to a class, or downright all the rules that belong to one style sheet, or even the rules of all style sheets, plus a few additional features like switching style sheet or writing onto a class.
As such, we had there a twofold "limitation" (if we want to call limitation that massive amount of functions): the functions were mainly, though not uniquely, concerned with style sheets as whole sheets, and they would detect classes only after the mainstream dot-class notation.

In fact, style sheet declaration cascade and follow these rules:
  1. Whatever tag inline declaration will prevail on all the rest:
    <div id="anId" class="aClass" style="color:#000000;">
    In this case, being the color declared inline, this latest declaration overrides whatever other color declaration that may have appeared in other locations/style sheets for this layer.
  2. Style sheets can be included either by a <style> independent tag (<style>rules etc...</style>) or by loading external css files by a standalone <link> tag.

    In both cases they are all valid style sheet nodes belonging all to the collection:
    document.styleSheets
  3. Within such latest style sheets, there could even be multiple classes (synonym: rules) carrying (arguably by mistake, but not necessarily so) the same name.

    Yet among these, the only one which prevails is the last one declared in the line (provided it is not all overridden by, as I said, inline tag style property declaration - see #1).

    Thus the correct way to scan style sheets is from bottom up, and as soon as one matching class declaration is found, return that one only: the others with the same name which could be there, are simply overwritten by this last one that we report and which is the one truly enforced.
  4. Now, there can be a tricky issue: though a tag can carry a class="someClassName" property, which is reflected in the style sheet nodes by a class that follows the notation dot+class name:
    .someClassName{color: blah blah...}
    yet it is still possible that there exist class notations, in the style sheets, that follow this other notation fashion:
    #layerID{color: blah blah...}
    Namely a class that uses the # plus the layer id rather than the dot plus the class name.

    The issue is now that if such a notation rule, namely preceded by the # sign exist, this would prevail on every dot-class notation even if such # rule is located somewhere earlier the dot one (the last one should prevail, remember?).
    On their own, both class dot notations and # notations would prevail on classes notations that report just the tag name they are meant to be applied unto (which is another valid class procedure to assign class properties to tags).

    Therefore this function I provide here will also scan for that and will correctly report the last one of such #layerId notations if it finds one, as the truly prevailing notation, also if the layer has a different class attribution.
  5. WARNING: be aware that whereas all the above applies, it applies no longer in case a property, like say width, is declared in a rule but not in another, and both rules affect the layer: in this last case the applied property is the one in the rule where such property is actually mentioned, regardless of the above depicted priorities.
    This script detects these cases correctly!
  6. Setback: within a class declaration would even be possible including more classes, separating them by a white space. This is not common at all, even more many scripters are not even aware this is possible.
    Yet, this script will not take into account of this far fetched case, in order to contain its code length (thus far a few dozens lines, which is acceptable for such complex a necessity).
    Also, to avoid making this function too long, I didn't arrange it to device more complex cases like tagName.className notations or multiple notations separated by a comma. This script assumes you've defined your styles one of these ways:
    • inline the tag by the style property
    • by a tag notation such as span{ecc...}
    • by a dot class notation such as .className{ecc...}
    • by a #layer id notation such as #layerId{ecc...}


Script codes and arguments overview
How the script can be invoked and used

Here is first your script, and later what its argument are for and how you can pass them.

William Turner
William Turner, Ship on fire, 1826-30


The function will return always an array of three entries [their indexes are, obviously: 0,1,2].

In case of no success, the array will have all its entries as empty strings: so to check a failure please do the following: check whether the last entry [index 2] is equal to an empty string: "".
Do not check the first entry for a failure into locating a prevailing style rule for the layer, check the last entry please: in fact there are cases, as you will see, which we could dub nearly-successful where the first entry of the returned array can be empty, but the others are not.

These three entries report in this fashion:
  1. [0]: if you searched for a property (you can pass it as an argument, see further on), this entry will report the value of such property on the style node that truly prevails!
    If no property was passed to search for, or no such property is anywhere declared to be found, this entry will be an empty string.
  2. [1]: this is the located style Object itself where that class definition was found, in case you want to manipulate it! To manipulate it namely for instance to change one property, append its property in the javaScript notation (that is, remove dashes and uppercase the next char: background-color becomes backgroundColor) and add it as a string (in between quotes, that is) and set its new value by an equal sign, instance:
    var foo=classProperty("anId", "backgroundColor");
    foo[1]["backgroundColor"]="#000000";

    or:
    foo[1].backgroundColor="#000000";
    Since such [1] style object will be the prevailing one, it could be either the inline tag style attribute or a style sheet node accordingly to what was detected as prevailing.
    To guess which the case actually is, you check the next argument.
  3. [2]: this is a string, and reports:
    • The string: "style", if the prevailing sheet for that property was an inline tag style declaration.
    • The name of the class of the prevailing sheet for that property, inclusive of the dot if present, if a tag name or a class name is prevailing for that property in the style sheet rules.
    • The name of the class of the prevailing sheet for that property, inclusive of the # sign, if a class with the # notation is prevailing
    • If no property was passed to be searched for, this returned entry will be the name, either dot plus class or # plus layer id, of the prevailing rule.

      You must be aware though that if you searched for no specific property, this last class is indeed the prevailing one, but it is still possible that for some other given specific property, another different rule is actually prevailing. This is why this function is geared to scan for a property too ideally.
      Such an instance would be one as follows: the script reports that some, say, prevailing #foo class prevails indeed.
      Yet, since you have not searched for a specific property, beware it is still possible that this #foo rule carries no specification for, say, the background-color. Yet if another class, even with a simple dot class notation, is present and affects such layer and this class defines the background-color property, it is this latter rule which would prevail!

      So my advice is: run this function always asking for a property.
The arguments to pass are as follows:

William Turner
William Turner, Looking east from the Giudecca: early morning, 1819
ARGUMENTS OVERVIEW
targetId
It is the only mandatory argument.
It must be either a String (namely in between quotes) carrying the id property of a layer, or can also be a valid layer object, as such would be one passed by, say:
document.getElementById("anIdHere");
findProperty
It is the property you're searching for, and should be a String (in between quotes, that is).

If you don't pass it, the function may return an array of three empty sets or, if you don't pass this argument but you do pass the argument named justReturn, the function will return an array of one empty set and two valid sets carrying references to the prevailing style rule (object, string carrying the class name, at times called selector).

The way you'd pass this argument is, ideally, in the same way you'd declare this property within a rule. Say for instance:
background-color

The script will take care of manipulating the dashes for javascript compliance, don't even worry about that (in javascript, style dashes should be removed and the next letter capitalized: the script does that on its own if it finds dashes in the findProperty argument!).

If anyway you want to pass that as:
backgroundColor
namely already javascript compliant, the script won't complain. But be sure the capitalization is correct or the script would fail: it is case sensitive.

Last but not least, if you search for, say, the background-color, always pass the most specific reference; this means that in a style rule a statement like:
background: #00000
is equivalent to:
background-color: #000000
But javascript can detect correctly from the most specific one to the less specific one but not vice versa, namely javascript can find the color if you ask:
backgroundColor and the rule carries just background
but it will fail if you pass just
background and the rule carries background-color, got it?

By the way, for your joy: two more bonus snippets to convert any css style property syntax into its equivalent javascript syntax (say: background-color -> backgroundColor), and to convert javascript style property syntax into its equivalent css syntax (say: backgroundColor -> background-color): just pass to them as their only argument the string (in between quotes, that is) you want to convert.
What other website does so much for you and provides you with such a wealth of stuff and details?

FROM CSS TO JS
FROM JS TO CSS


justPrevalent
It is entirely optional; if you do not pass a property to find (such as you pass an empty string), do pass this argument as 1, and the script will return just the prevailing rule found, namely an array whose first entry is empty but whose other two entries are populated.

As said above, be aware that a prevailing rule without defining any specific property to search for, can still be the prevailing rule but maybe not for some specific property.

This is why it is better to run this script when you wonder about the value of a specified property in an environment where you are not sure whether inline style tag declaration or rules with unknown precedence are prevailing and actually affecting the layer features.
styleSheetIndex
It is entirely optional; if you pass it, it must be the numerical index of a style sheet node, so it assumes you know what the position of the concerned style sheet is, and the script will report scanning that sheet only.
It just saves a few picoseconds, if you have say 20 style sheets applied on the same document, which is actually unlikely but not downright impossible of course.

If you pass it as a string, it should be just the name of the style sheet (inclusive of the .css extension), without the path, and the script will try to see if a style sheet link is present with such name present somewhere in its href.
If it finds no suitable href, the function will make such value default to the index of the last available style sheet (if any), and scan only such style sheet.

Remember: if you pass this, the search will be limited to that style sheet.


Test Form
Try the function in action

Here is your test form where you can triger the function and see what it returns also changing its arguments.
The script has a small test layer (you will see it inside the test form below) whose id is id="anId" (and to simplify the test you cannot change that) and which has a class declared as class="foo" and an inline style tag too, which sets its background to white: style="background-color: #ffffff;".

With the test form you can do two things:
  1. Change the layer's settings (as said, except the layer id) so that you can even overwrite its class declaration to be blank or pointing to some non existent class too if you want to see how the function reacts.
  2. Change the settings of the classProperty function arguments, and see what it returns in these various cases.
This document has a few foo foo declarations to perform as multiple style rules insisting upon the same layer object.
These rules are defined as it appears in the test form below (rule duplicates are intentional, so you can spot better that the classProperty function can successfully meet every challenge) and which you can even edit and then apply onto this very same document (!) by clicking, after you have edited them, the Apply These (rules) button.
Yet beware, in this case the correctness of the css syntax is up to you of course!

By the way newly edited rules are applied using two functions named deleteClass and addClass which you can find on this file.

So, enough "chatting": here is your test layer along with the editable rule field and the layer editable tag settings (note: any applied change will reflect on the layer too): be sure you have understood how precedence works before arguing the function or the form don't work: inline declaration prevails, then # notations, then class notations. But if a property is quoted in a duplicate only, that single property will affect the layer anyway.

Domenico Ghirlandaio
Domenico Ghirlandaio, Santo Stefano between Jacopo and Pietro, 1493
THE TEST FORM
LAYER SETTINGS
  Small test layer  
EDIT RULES (optional)







[click out of the reset button too, if you have clicked it]


or reload frame:

CHANGE LAYER CLASS

You can here change the class that affects the layer.
Leave the field blank to apply no class, namely: class=""

The layer above is affected by inline style declaration: change those first, if you want to see fully reflected changes in class, or class modifications.

Remember also that # notations keep prevailing on dot notations if for the chosen property a # notation affects it: delete # notations on the left and click apply on the left if you want this className to prevail.

Layer className=
(hint: try foo2)

CHANGE LAYER INLINE TAG STYLE

If upon clicking Apply a property shows up again unchanged, to override it leave its value blank, example:
background-color:;

Layer inline tag style declaration (current): <... style=

classProperty SETTINGS
classProperty(
"anId",
findProperty= ,
justPrevalent= ,
styleSheetIndex=
);


Or set for that style object this property: