]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/stylesheet/stylesheet.js
Release 6.5.0
[Github/sugarcrm.git] / include / javascript / yui / build / stylesheet / stylesheet.js
1 /*
2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 2.9.0
6 */
7 /**
8  * The StyleSheet component is a utility for managing css rules at the
9  * stylesheet level
10  *
11  * @module stylesheet
12  * @namespace YAHOO.util
13  * @requires yahoo
14  */
15 (function () {
16
17 var d      = document,
18     p      = d.createElement('p'), // Have to hold the node (see notes)
19     workerStyle = p.style, // worker style collection
20     lang   = YAHOO.lang,
21     selectors = {},
22     sheets = {},
23     ssId   = 0,
24     floatAttr = ('cssFloat' in workerStyle) ? 'cssFloat' : 'styleFloat',
25     _toCssText,
26     _unsetOpacity,
27     _unsetProperty;
28
29 /*
30  * Normalizes the removal of an assigned style for opacity.  IE uses the filter property.
31  */
32 _unsetOpacity = ('opacity' in workerStyle) ?
33     function (style) { style.opacity = ''; } :
34     function (style) { style.filter = ''; };
35         
36 /*
37  * Normalizes the removal of an assigned style for a given property.  Expands
38  * shortcut properties if necessary and handles the various names for the float property.
39  */
40 workerStyle.border = "1px solid red";
41 workerStyle.border = ''; // IE doesn't unset child properties
42 _unsetProperty = workerStyle.borderLeft ?
43     function (style,prop) {
44         var p;
45         if (prop !== floatAttr && prop.toLowerCase().indexOf('float') != -1) {
46             prop = floatAttr;
47         }
48         if (typeof style[prop] === 'string') {
49             switch (prop) {
50                 case 'opacity':
51                 case 'filter' : _unsetOpacity(style); break;
52                 case 'font'   :
53                     style.font       = style.fontStyle = style.fontVariant =
54                     style.fontWeight = style.fontSize  = style.lineHeight  =
55                     style.fontFamily = '';
56                     break;
57                 default       :
58                     for (p in style) {
59                         if (p.indexOf(prop) === 0) {
60                             style[p] = '';
61                         }
62                     }
63             }
64         }
65     } :
66     function (style,prop) {
67         if (prop !== floatAttr && prop.toLowerCase().indexOf('float') != -1) {
68             prop = floatAttr;
69         }
70         if (lang.isString(style[prop])) {
71             if (prop === 'opacity') {
72                 _unsetOpacity(style);
73             } else {
74                 style[prop] = '';
75             }
76         }
77     };
78     
79 /**
80  * Create an instance of YAHOO.util.StyleSheet to encapsulate a css stylesheet.
81  * The constructor can be called using function or constructor syntax.
82  * <pre><code>var sheet = YAHOO.util.StyleSheet(..);</pre></code>
83  * or
84  * <pre><code>var sheet = new YAHOO.util.StyleSheet(..);</pre></code>
85  *
86  * The first parameter passed can be any of the following things:
87  * <ul>
88  *   <li>The desired string name to register a new empty sheet</li>
89  *   <li>The string name of an existing YAHOO.util.StyleSheet instance</li>
90  *   <li>The unique yuiSSID generated for an existing YAHOO.util.StyleSheet instance</li>
91  *   <li>The id of an existing <code>&lt;link&gt;</code> or <code>&lt;style&gt;</code> node</li>
92  *   <li>The node reference for an existing <code>&lt;link&gt;</code> or <code>&lt;style&gt;</code> node</li>
93  *   <li>A chunk of css text to create a new stylesheet from</li>
94  * </ul>
95  *
96  * <p>If a string is passed, StyleSheet will first look in its static name
97  * registry for an existing sheet, then in the DOM for an element with that id.
98  * If neither are found and the string contains the { character, it will be
99  * used as a the initial cssText for a new StyleSheet.  Otherwise, a new empty
100  * StyleSheet is created, assigned the string value as a name, and registered
101  * statically by that name.</p>
102  *
103  * <p>The optional second parameter is a string name to register the sheet as.
104  * This param is largely useful when providing a node id/ref or chunk of css
105  * text to create a populated instance.</p>
106  * 
107  * @class StyleSheet
108  * @constructor
109  * @param seed {String|&lt;style&gt; element} a style or link node, its id, or a name or
110  *              yuiSSID of a StyleSheet, or a string of css text (see above)
111  * @param name {String} OPTIONAL name to register instance for future static
112  *              access
113  */
114 function StyleSheet(seed, name) {
115     var head,
116         node,
117         sheet,
118         cssRules = {},
119         _rules,
120         _insertRule,
121         _deleteRule,
122         i,r,sel;
123
124     // Factory or constructor
125     if (!(this instanceof StyleSheet)) {
126         return new StyleSheet(seed,name);
127     }
128
129     // capture the DOM node if the string is an id
130     node = seed && (seed.nodeName ? seed : d.getElementById(seed));
131
132     // Check for the StyleSheet in the static registry
133     if (seed && sheets[seed]) {
134         return sheets[seed];
135     } else if (node && node.yuiSSID && sheets[node.yuiSSID]) {
136         return sheets[node.yuiSSID];
137     }
138
139     // Create a style node if necessary
140     if (!node || !/^(?:style|link)$/i.test(node.nodeName)) {
141         node = d.createElement('style');
142         node.type = 'text/css';
143     }
144
145     if (lang.isString(seed)) {
146         // Create entire sheet from seed cssText
147         if (seed.indexOf('{') != -1) {
148             // Not a load-time fork because low run-time impact and IE fails
149             // test for s.styleSheet at page load time (oddly)
150             if (node.styleSheet) {
151                 node.styleSheet.cssText = seed;
152             } else {
153                 node.appendChild(d.createTextNode(seed));
154             }
155         } else if (!name) {
156             name = seed;
157         }
158     }
159
160     if (!node.parentNode || node.parentNode.nodeName.toLowerCase() !== 'head') {
161         head = (node.ownerDocument || d).getElementsByTagName('head')[0];
162         // styleSheet isn't available on the style node in FF2 until appended
163         // to the head element.  style nodes appended to body do not affect
164         // change in Safari.
165         head.appendChild(node);
166     }
167
168     // Begin setting up private aliases to the important moving parts
169     // 1. The stylesheet object
170     // IE stores StyleSheet under the "styleSheet" property
171     // Safari doesn't populate sheet for xdomain link elements
172     sheet = node.sheet || node.styleSheet;
173
174     // 2. The style rules collection
175     // IE stores the rules collection under the "rules" property
176     _rules = sheet && ('cssRules' in sheet) ? 'cssRules' : 'rules';
177
178     // 3. The method to remove a rule from the stylesheet
179     // IE supports removeRule
180     _deleteRule = ('deleteRule' in sheet) ?
181         function (i) { sheet.deleteRule(i); } :
182         function (i) { sheet.removeRule(i); };
183
184     // 4. The method to add a new rule to the stylesheet
185     // IE supports addRule with different signature
186     _insertRule = ('insertRule' in sheet) ?
187         function (sel,css,i) { sheet.insertRule(sel+' {'+css+'}',i); } :
188         function (sel,css,i) { sheet.addRule(sel,css,i); };
189
190     // 5. Initialize the cssRules map from the node
191     // xdomain link nodes forbid access to the cssRules collection, so this
192     // will throw an error.
193     // TODO: research alternate stylesheet, @media
194     for (i = sheet[_rules].length - 1; i >= 0; --i) {
195         r   = sheet[_rules][i];
196         sel = r.selectorText;
197
198         if (cssRules[sel]) {
199             cssRules[sel].style.cssText += ';' + r.style.cssText;
200             _deleteRule(i);
201         } else {
202             cssRules[sel] = r;
203         }
204     }
205
206     // Cache the instance by the generated Id
207     node.yuiSSID = 'yui-stylesheet-' + (ssId++);
208     StyleSheet.register(node.yuiSSID,this);
209
210     // Register the instance by name if provided or defaulted from seed
211     if (name) {
212         StyleSheet.register(name,this);
213     }
214
215     // Public API
216     lang.augmentObject(this,{
217         /**
218          * Get the unique yuiSSID for this StyleSheet instance
219          *
220          * @method getId
221          * @return {Number} the static id
222          */
223         getId : function () { return node.yuiSSID; },
224
225         /**
226          * The &lt;style&gt; element that this instance encapsulates
227          *
228          * @property node
229          * @type HTMLElement
230          */
231         node : node,
232
233         /**
234          * Enable all the rules in the sheet
235          *
236          * @method enable
237          * @return {StyleSheet} the instance
238          * @chainable
239          */
240         // Enabling/disabling the stylesheet.  Changes may be made to rules
241         // while disabled.
242         enable : function () { sheet.disabled = false; return this; },
243
244         /**
245          * Disable all the rules in the sheet.  Rules may be changed while the
246          * StyleSheet is disabled.
247          *
248          * @method disable
249          * @return {StyleSheet} the instance
250          * @chainable
251          */
252         disable : function () { sheet.disabled = true; return this; },
253
254         /**
255          * Returns boolean indicating whether the StyleSheet is enabled
256          *
257          * @method isEnabled
258          * @return {Boolean} is it enabled?
259          */
260         isEnabled : function () { return !sheet.disabled; },
261
262         /**
263          * <p>Set style properties for a provided selector string.
264          * If the selector includes commas, it will be split into individual
265          * selectors and applied accordingly.  If the selector string does not
266          * have a corresponding rule in the sheet, it will be added.</p>
267          *
268          * <p>The second parameter can be either a string of CSS text,
269          * formatted as CSS ("font-size: 10px;"), or an object collection of
270          * properties and their new values.  Object properties must be in
271          * JavaScript format ({ fontSize: "10px" }).</p>
272          *
273          * <p>The float style property will be set by any of &quot;float&quot;,
274          * &quot;styleFloat&quot;, or &quot;cssFloat&quot; if passed in the
275          * object map.  Use "float: left;" format when passing a CSS text
276          * string.</p>
277          *
278          * @method set
279          * @param sel {String} the selector string to apply the changes to
280          * @param css {Object|String} Object literal of style properties and
281          *                      new values, or a string of cssText
282          * @return {StyleSheet} the StyleSheet instance
283          * @chainable
284          */
285         set : function (sel,css) {
286             var rule = cssRules[sel],
287                 multi = sel.split(/\s*,\s*/),i,
288                 idx;
289
290             // IE's addRule doesn't support multiple comma delimited selectors
291             if (multi.length > 1) {
292                 for (i = multi.length - 1; i >= 0; --i) {
293                     this.set(multi[i], css);
294                 }
295                 return this;
296             }
297
298             // Some selector values can cause IE to hang
299             if (!StyleSheet.isValidSelector(sel)) {
300                 return this;
301             }
302
303             // Opera throws an error if there's a syntax error in assigned
304             // cssText. Avoid this using a worker style collection, then
305             // assigning the resulting cssText.
306             if (rule) {
307                 rule.style.cssText = StyleSheet.toCssText(css,rule.style.cssText);
308             } else {
309                 idx = sheet[_rules].length;
310                 css = StyleSheet.toCssText(css);
311
312                 // IE throws an error when attempting to addRule(sel,'',n)
313                 // which would crop up if no, or only invalid values are used
314                 if (css) {
315                     _insertRule(sel, css, idx);
316
317                     // Safari replaces the rules collection, but maintains the
318                     // rule instances in the new collection when rules are
319                     // added/removed
320                     cssRules[sel] = sheet[_rules][idx];
321                 }
322             }
323             return this;
324         },
325
326         /**
327          * <p>Unset style properties for a provided selector string, removing
328          * their effect from the style cascade.</p>
329          *
330          * <p>If the selector includes commas, it will be split into individual
331          * selectors and applied accordingly.  If there are no properties
332          * remaining in the rule after unsetting, the rule is removed.</p>
333          *
334          * <p>The style property or properties in the second parameter must be the
335          * <p>JavaScript style property names. E.g. fontSize rather than font-size.</p>
336          *
337          * <p>The float style property will be unset by any of &quot;float&quot;,
338          * &quot;styleFloat&quot;, or &quot;cssFloat&quot;.</p>
339          *
340          * @method unset
341          * @param sel {String} the selector string to apply the changes to
342          * @param css {String|Array} style property name or Array of names
343          * @return {StyleSheet} the StyleSheet instance
344          * @chainable
345          */
346         unset : function (sel,css) {
347             var rule = cssRules[sel],
348                 multi = sel.split(/\s*,\s*/),
349                 remove = !css,
350                 rules, i;
351
352             // IE's addRule doesn't support multiple comma delimited selectors
353             // so rules are mapped internally by atomic selectors
354             if (multi.length > 1) {
355                 for (i = multi.length - 1; i >= 0; --i) {
356                     this.unset(multi[i], css);
357                 }
358                 return this;
359             }
360
361             if (rule) {
362                 if (!remove) {
363                     if (!lang.isArray(css)) {
364                         css = [css];
365                     }
366
367                     workerStyle.cssText = rule.style.cssText;
368                     for (i = css.length - 1; i >= 0; --i) {
369                         _unsetProperty(workerStyle,css[i]);
370                     }
371
372                     if (workerStyle.cssText) {
373                         rule.style.cssText = workerStyle.cssText;
374                     } else {
375                         remove = true;
376                     }
377                 }
378                 
379                 if (remove) { // remove the rule altogether
380                     rules = sheet[_rules];
381                     for (i = rules.length - 1; i >= 0; --i) {
382                         if (rules[i] === rule) {
383                             delete cssRules[sel];
384                             _deleteRule(i);
385                             break;
386                         }
387                     }
388                 }
389             }
390             return this;
391         },
392
393         /**
394          * Get the current cssText for a rule or the entire sheet.  If the
395          * selector param is supplied, only the cssText for that rule will be
396          * returned, if found.  If the selector string targets multiple
397          * selectors separated by commas, the cssText of the first rule only
398          * will be returned.  If no selector string, the stylesheet's full
399          * cssText will be returned.
400          *
401          * @method getCssText
402          * @param sel {String} Selector string
403          * @return {String}
404          */
405         getCssText : function (sel) {
406             var rule, css, selector;
407
408             if (lang.isString(sel)) {
409                 // IE's addRule doesn't support multiple comma delimited
410                 // selectors so rules are mapped internally by atomic selectors
411                 rule = cssRules[sel.split(/\s*,\s*/)[0]];
412
413                 return rule ? rule.style.cssText : null;
414             } else {
415                 css = [];
416                 for (selector in cssRules) {
417                     if (cssRules.hasOwnProperty(selector)) {
418                         rule = cssRules[selector];
419                         css.push(rule.selectorText+" {"+rule.style.cssText+"}");
420                     }
421                 }
422                 return css.join("\n");
423             }
424         }
425     },true);
426
427 }
428
429 _toCssText = function (css,base) {
430     var f = css.styleFloat || css.cssFloat || css['float'],
431         prop;
432
433     // A very difficult to repro/isolate IE 9 beta (and Platform Preview 7) bug
434     // was reduced to this line throwing the error:
435     // "Invalid this pointer used as target for method call"
436     // It appears that the style collection is corrupted. The error is
437     // catchable, so in a best effort to work around it, replace the
438     // p and workerStyle and try the assignment again.
439     try {
440         workerStyle.cssText = base || '';
441     } catch (ex) {
442         p = d.createElement('p');
443         workerStyle = p.style;
444         workerStyle.cssText = base || '';
445     }
446
447     if (lang.isString(css)) {
448         // There is a danger here of incremental memory consumption in Opera
449         workerStyle.cssText += ';' + css;
450     } else {
451         if (f && !css[floatAttr]) {
452             css = lang.merge(css);
453             delete css.styleFloat; delete css.cssFloat; delete css['float'];
454             css[floatAttr] = f;
455         }
456
457         for (prop in css) {
458             if (css.hasOwnProperty(prop)) {
459                 try {
460                     // IE throws Invalid Value errors and doesn't like whitespace
461                     // in values ala ' red' or 'red '
462                     workerStyle[prop] = lang.trim(css[prop]);
463                 }
464                 catch (e) {
465                 }
466             }
467         }
468     }
469
470     return workerStyle.cssText;
471 };
472
473 lang.augmentObject(StyleSheet, {
474     /**
475      * <p>Converts an object literal of style properties and values into a string
476      * of css text.  This can then be assigned to el.style.cssText.</p>
477      *
478      * <p>The optional second parameter is a cssText string representing the
479      * starting state of the style prior to alterations.  This is most often
480      * extracted from the eventual target's current el.style.cssText.</p>
481      *
482      * @method StyleSheet.toCssText
483      * @param css {Object} object literal of style properties and values
484      * @param cssText {String} OPTIONAL starting cssText value
485      * @return {String} the resulting cssText string
486      * @static
487      */
488     toCssText : (('opacity' in workerStyle) ? _toCssText :
489         // Wrap IE's toCssText to catch opacity.  The copy/merge is to preserve
490         // the input object's integrity, but if float and opacity are set, the
491         // input will be copied twice in IE.  Is there a way to avoid this
492         // without increasing the byte count?
493         function (css, cssText) {
494             if (lang.isObject(css) && 'opacity' in css) {
495                 css = lang.merge(css,{
496                         filter: 'alpha(opacity='+(css.opacity*100)+')'
497                       });
498                 delete css.opacity;
499             }
500             return _toCssText(css,cssText);
501         }),
502
503     /**
504      * Registers a StyleSheet instance in the static registry by the given name
505      *
506      * @method StyleSheet.register
507      * @param name {String} the name to assign the StyleSheet in the registry
508      * @param sheet {StyleSheet} The StyleSheet instance
509      * @return {Boolean} false if no name or sheet is not a StyleSheet
510      *              instance. true otherwise.
511      * @static
512      */
513     register : function (name,sheet) {
514         return !!(name && sheet instanceof StyleSheet &&
515                   !sheets[name] && (sheets[name] = sheet));
516     },
517
518     /**
519      * <p>Determines if a selector string is safe to use.  Used internally
520      * in set to prevent IE from locking up when attempting to add a rule for a
521      * &quot;bad selector&quot;.</p>
522      *
523      * <p>Bad selectors are considered to be any string containing unescaped
524      * `~!@$%^&()+=|{}[];'"?< or space. Also forbidden are . or # followed by
525      * anything other than an alphanumeric.  Additionally -abc or .-abc or
526      * #_abc or '# ' all fail.  There are likely more failure cases, so
527      * please file a bug if you encounter one.</p>
528      *
529      * @method StyleSheet.isValidSelector
530      * @param sel {String} the selector string
531      * @return {Boolean}
532      * @static
533      */
534     isValidSelector : function (sel) {
535         var valid = false;
536
537         if (sel && lang.isString(sel)) {
538
539             if (!selectors.hasOwnProperty(sel)) {
540                 // TEST: there should be nothing but white-space left after
541                 // these destructive regexs
542                 selectors[sel] = !/\S/.test(
543                     // combinators
544                     sel.replace(/\s+|\s*[+~>]\s*/g,' ').
545                     // attribute selectors (contents not validated)
546                     replace(/([^ ])\[.*?\]/g,'$1').
547                     // pseudo-class|element selectors (contents of parens
548                     // such as :nth-of-type(2) or :not(...) not validated)
549                     replace(/([^ ])::?[a-z][a-z\-]+[a-z](?:\(.*?\))?/ig,'$1').
550                     // element tags
551                     replace(/(?:^| )[a-z0-6]+/ig,' ').
552                     // escaped characters
553                     replace(/\\./g,'').
554                     // class and id identifiers
555                     replace(/[.#]\w[\w\-]*/g,''));
556             }
557
558             valid = selectors[sel];
559         }
560
561         return valid;
562     }
563 },true);
564
565 YAHOO.util.StyleSheet = StyleSheet;
566
567 })();
568
569 /*
570
571 NOTES
572  * Style node must be added to the head element.  Safari does not honor styles
573    applied to StyleSheet objects on style nodes in the body.
574  * StyleSheet object is created on the style node when the style node is added
575    to the head element in Firefox 2 (and maybe 3?)
576  * The cssRules collection is replaced after insertRule/deleteRule calls in
577    Safari 3.1.  Existing Rules are used in the new collection, so the collection
578    cannot be cached, but the rules can be.
579  * Opera requires that the index be passed with insertRule.
580  * Same-domain restrictions prevent modifying StyleSheet objects attached to
581    link elements with remote href (or "about:blank" or "javascript:false")
582  * Same-domain restrictions prevent reading StyleSheet cssRules/rules
583    collection of link elements with remote href (or "about:blank" or
584    "javascript:false")
585  * Same-domain restrictions result in Safari not populating node.sheet property
586    for link elements with remote href (et.al)
587  * IE names StyleSheet related properties and methods differently (see code)
588  * IE converts tag names to upper case in the Rule's selectorText
589  * IE converts empty string assignment to complex properties to value settings
590    for all child properties.  E.g. style.background = '' sets non-'' values on
591    style.backgroundPosition, style.backgroundColor, etc.  All else clear
592    style.background and all child properties.
593  * IE assignment style.filter = '' will result in style.cssText == 'FILTER:'
594  * All browsers support Rule.style.cssText as a read/write property, leaving
595    only opacity needing to be accounted for.
596  * Benchmarks of style.property = value vs style.cssText += 'property: value'
597    indicate cssText is slightly slower for single property assignment.  For
598    multiple property assignment, cssText speed stays relatively the same where
599    style.property speed decreases linearly by the number of properties set.
600    Exception being Opera 9.27, where style.property is always faster than
601    style.cssText.
602  * Opera 9.5b throws a syntax error when assigning cssText with a syntax error.
603  * Opera 9.5 doesn't honor rule.style.cssText = ''.  Previous style persists.
604    You have to remove the rule altogether.
605  * Stylesheet properties set with !important will trump inline style set on an
606    element or in el.style.property.
607  * Creating a worker style collection like document.createElement('p').style;
608    will fail after a time in FF (~5secs of inactivity).  Property assignments
609    will not alter the property or cssText.  It may be the generated node is
610    garbage collected and the style collection becomes inert (speculation).
611  * IE locks up when attempting to add a rule with a selector including at least
612    characters {[]}~`!@%^&*()+=|? (unescaped) and leading _ or -
613    such as addRule('-foo','{ color: red }') or addRule('._abc','{...}')
614  * IE's addRule doesn't support comma separated selectors such as
615    addRule('.foo, .bar','{..}')
616  * IE throws an error on valid values with leading/trailing white space.
617  * When creating an entire sheet at once, only FF2/3 & Opera allow creating a
618    style node, setting its innerHTML and appending to head.
619  * When creating an entire sheet at once, Safari requires the style node to be
620    created with content in innerHTML of another element.
621  * When creating an entire sheet at once, IE requires the style node content to
622    be set via node.styleSheet.cssText
623  * When creating an entire sheet at once in IE, styleSheet.cssText can't be
624    written until node.type = 'text/css'; is performed.
625  * When creating an entire sheet at once in IE, load-time fork on
626    var styleNode = d.createElement('style'); _method = styleNode.styleSheet ?..
627    fails (falsey).  During run-time, the test for .styleSheet works fine
628  * Setting complex properties in cssText will SOMETIMES allow child properties
629    to be unset
630    set         unset              FF2  FF3  S3.1  IE6  IE7  Op9.27  Op9.5
631    ----------  -----------------  ---  ---  ----  ---  ---  ------  -----
632    border      -top               NO   NO   YES   YES  YES  YES     YES
633                -top-color         NO   NO   YES             YES     YES
634                -color             NO   NO   NO              NO      NO
635    background  -color             NO   NO   YES             YES     YES
636                -position          NO   NO   YES             YES     YES
637                -position-x        NO   NO   NO              NO      NO
638    font        line-height        YES  YES  NO    NO   NO   NO      YES
639                -style             YES  YES  NO              YES     YES
640                -size              YES  YES  NO              YES     YES
641                -size-adjust       ???  ???  n/a   n/a  n/a  ???     ???
642    padding     -top               NO   NO   YES             YES     YES
643    margin      -top               NO   NO   YES             YES     YES
644    list-style  -type              YES  YES  YES             YES     YES
645                -position          YES  YES  YES             YES     YES
646    overflow    -x                 NO   NO   YES             n/a     YES
647
648    ??? - unsetting font-size-adjust has the same effect as unsetting font-size
649  * FireFox and WebKit populate rule.cssText as "SELECTOR { CSSTEXT }", but
650    Opera and IE do not.
651  * IE6 and IE7 silently ignore the { and } if passed into addRule('.foo','{
652    color:#000}',0).  IE8 does not and creates an empty rule.
653  * IE6-8 addRule('.foo','',n) throws an error.  Must supply *some* cssText
654 */
655
656 YAHOO.register("stylesheet", YAHOO.util.StyleSheet, {version: "2.9.0", build: "2800"});