[SPIP] +2.1.12
[velocampus/web/www.git] / www / extensions / msie_compat / javascript / IE9.js
1 /*
2 IE7/IE8/IE9.js - copyright 2004-2010, Dean Edwards
3 http://code.google.com/p/ie7-js/
4 http://www.opensource.org/licenses/mit-license.php
5 */
6
7 /* W3C compliance for Microsoft Internet Explorer */
8
9 /* credits/thanks:
10 Shaggy, Martijn Wargers, Jimmy Cerra, Mark D Anderson,
11 Lars Dieckow, Erik Arvidsson, Gellért Gyuris, James Denny,
12 Unknown W Brackets, Benjamin Westfarer, Rob Eberhardt,
13 Bill Edney, Kevin Newman, James Crompton, Matthew Mastracci,
14 Doug Wright, Richard York, Kenneth Kolano, MegaZone,
15 Thomas Verelst, Mark 'Tarquin' Wilton-Jones, Rainer Åhlfors,
16 David Zulaica, Ken Kolano, Kevin Newman, Sjoerd Visscher,
17 Ingo Chao
18 */
19
20 // timestamp: Sun, 07 Mar 2010 18:13:50
21
22 (function(window, document) {
23
24 var IE7 = window.IE7 = {
25 version: "2.1(beta3)",
26 toString: K("[IE7]")
27 };
28 IE7.compat = 9;
29 var appVersion = IE7.appVersion = navigator.appVersion.match(/MSIE (\d\.\d)/)[1] - 0;
30
31 if (/ie7_off/.test(top.location.search) || appVersion < 5.5 || appVersion >= IE7.compat) return;
32
33 var MSIE5 = appVersion < 6;
34
35 var Undefined = K();
36 var documentElement = document.documentElement, body, viewport;
37 var ANON = "!";
38 var HEADER = ":link{ie7-link:link}:visited{ie7-link:visited}";
39
40 // -----------------------------------------------------------------------
41 // external
42 // -----------------------------------------------------------------------
43
44 var RELATIVE = /^[\w\.]+[^:]*$/;
45 function makePath(href, path) {
46 if (RELATIVE.test(href)) href = (path || "") + href;
47 return href;
48 };
49
50 function getPath(href, path) {
51 href = makePath(href, path);
52 return href.slice(0, href.lastIndexOf("/") + 1);
53 };
54
55 // Get the path to this script
56 var script = document.scripts[document.scripts.length - 1];
57 var path = getPath(script.src);
58
59 // Use microsoft's http request object to load external files
60 try {
61 var httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
62 } catch (ex) {
63 // ActiveX disabled
64 }
65
66 var fileCache = {};
67 function loadFile(href, path) {
68 try {
69 href = makePath(href, path);
70 if (!fileCache[href]) {
71 httpRequest.open("GET", href, false);
72 httpRequest.send();
73 if (httpRequest.status == 0 || httpRequest.status == 200) {
74 fileCache[href] = httpRequest.responseText;
75 }
76 }
77 } catch (ex) {
78 // ignore errors
79 }
80 return fileCache[href] || "";
81 };
82
83 // -----------------------------------------------------------------------
84 // OO support
85 // -----------------------------------------------------------------------
86
87
88 // This is a cut-down version of base2 (http://code.google.com/p/base2/)
89
90 var _slice = Array.prototype.slice;
91
92 // private
93 var _FORMAT = /%([1-9])/g;
94 var _LTRIM = /^\s\s*/;
95 var _RTRIM = /\s\s*$/;
96 var _RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g; // safe regular expressions
97 var _BASE = /\bbase\b/;
98 var _HIDDEN = ["constructor", "toString"]; // only override these when prototyping
99
100 var prototyping;
101
102 function Base(){};
103 Base.extend = function(_instance, _static) {
104 // Build the prototype.
105 prototyping = true;
106 var _prototype = new this;
107 extend(_prototype, _instance);
108 prototyping = false;
109
110 // Create the wrapper for the constructor function.
111 var _constructor = _prototype.constructor;
112 function klass() {
113 // Don't call the constructor function when prototyping.
114 if (!prototyping) _constructor.apply(this, arguments);
115 };
116 _prototype.constructor = klass;
117
118 // Build the static interface.
119 klass.extend = arguments.callee;
120 extend(klass, _static);
121 klass.prototype = _prototype;
122 return klass;
123 };
124 Base.prototype.extend = function(source) {
125 return extend(this, source);
126 };
127
128
129 // A collection of regular expressions and their associated replacement values.
130 // A Base class for creating parsers.
131
132 var HASH = "#";
133 var ITEMS = "#";
134 var KEYS = ".";
135 var COMPILED = "/";
136
137 var REGGRP_BACK_REF = /\\(\d+)/g,
138 REGGRP_ESCAPE_COUNT = /\[(\\.|[^\]\\])+\]|\\.|\(\?/g,
139 REGGRP_PAREN = /\(/g,
140 REGGRP_LOOKUP = /\$(\d+)/,
141 REGGRP_LOOKUP_SIMPLE = /^\$\d+$/,
142 REGGRP_LOOKUPS = /(\[(\\.|[^\]\\])+\]|\\.|\(\?)|\(/g,
143 REGGRP_DICT_ENTRY = /^<#\w+>$/,
144 REGGRP_DICT_ENTRIES = /<#(\w+)>/g;
145
146 var RegGrp = Base.extend({
147 constructor: function(values) {
148 this[KEYS] = [];
149 this[ITEMS] = {};
150 this.merge(values);
151 },
152
153 //dictionary: null,
154 //ignoreCase: false,
155
156 add: function(expression, replacement) {
157 delete this[COMPILED];
158 if (expression instanceof RegExp) {
159 expression = expression.source;
160 }
161 if (!this[HASH + expression]) this[KEYS].push(String(expression));
162 return this[ITEMS][HASH + expression] = new RegGrp.Item(expression, replacement, this);
163 },
164
165 compile: function(recompile) {
166 if (recompile || !this[COMPILED]) {
167 this[COMPILED] = new RegExp(this, this.ignoreCase ? "gi" : "g");
168 }
169 return this[COMPILED];
170 },
171
172 merge: function(values) {
173 for (var i in values) this.add(i, values[i]);
174 },
175
176 exec: function(string) {
177 var group = this,
178 patterns = group[KEYS],
179 items = group[ITEMS], item;
180 var result = this.compile(true).exec(string);
181 if (result) {
182 // Loop through the RegGrp items.
183 var i = 0, offset = 1;
184 while ((item = items[HASH + patterns[i++]])) {
185 var next = offset + item.length + 1;
186 if (result[offset]) { // do we have a result?
187 if (item.replacement === 0) {
188 return group.exec(string);
189 } else {
190 var args = result.slice(offset, next), j = args.length;
191 while (--j) args[j] = args[j] || ""; // some platforms return null/undefined for non-matching sub-expressions
192 args[0] = {match: args[0], item: item};
193 return args;
194 }
195 }
196 offset = next;
197 }
198 }
199 return null;
200 },
201
202 parse: function(string) {
203 string += ""; // type safe
204 var group = this,
205 patterns = group[KEYS],
206 items = group[ITEMS];
207 return string.replace(this.compile(), function(match) {
208 var args = [], item, offset = 1, i = arguments.length;
209 while (--i) args[i] = arguments[i] || ""; // some platforms return null/undefined for non-matching sub-expressions
210 // Loop through the RegGrp items.
211 while ((item = items[HASH + patterns[i++]])) {
212 var next = offset + item.length + 1;
213 if (args[offset]) { // do we have a result?
214 var replacement = item.replacement;
215 switch (typeof replacement) {
216 case "function":
217 return replacement.apply(group, args.slice(offset, next));
218 case "number":
219 return args[offset + replacement];
220 default:
221 return replacement;
222 }
223 }
224 offset = next;
225 }
226 return match;
227 });
228 },
229
230 toString: function() {
231 var strings = [],
232 keys = this[KEYS],
233 items = this[ITEMS], item;
234 for (var i = 0; item = items[HASH + keys[i]]; i++) {
235 strings[i] = item.source;
236 }
237 return "(" + strings.join(")|(") + ")";
238 }
239 }, {
240 IGNORE: null, // a null replacement value means that there is no replacement.
241
242 Item: Base.extend({
243 constructor: function(source, replacement, owner) {
244 var length = source.indexOf("(") === -1 ? 0 : RegGrp.count(source);
245
246 var dictionary = owner.dictionary;
247 if (dictionary && source.indexOf("<#") !== -1) {
248 if (REGGRP_DICT_ENTRY.test(source)) {
249 var entry = dictionary[ITEMS][HASH + source.slice(2, -1)];
250 source = entry.replacement;
251 length = entry._length;
252 } else {
253 source = dictionary.parse(source);
254 }
255 }
256
257 if (typeof replacement == "number") replacement = String(replacement);
258 else if (replacement == null) replacement = 0;
259
260 // Does the expression use sub-expression lookups?
261 if (typeof replacement == "string" && REGGRP_LOOKUP.test(replacement)) {
262 if (REGGRP_LOOKUP_SIMPLE.test(replacement)) { // A simple lookup? (e.g. "$2").
263 // Store the index (used for fast retrieval of matched strings).
264 var index = replacement.slice(1) - 0;
265 if (index && index <= length) replacement = index;
266 } else {
267 // A complicated lookup (e.g. "Hello $2 $1.").
268 var lookup = replacement, regexp;
269 replacement = function(match) {
270 if (!regexp) {
271 regexp = new RegExp(source, "g" + (this.ignoreCase ? "i": ""));
272 }
273 return match.replace(regexp, lookup);
274 };
275 }
276 }
277
278 this.length = length;
279 this.source = String(source);
280 this.replacement = replacement;
281 }
282 }),
283
284 count: function(expression) {
285 return (String(expression).replace(REGGRP_ESCAPE_COUNT, "").match(REGGRP_PAREN) || "").length;
286 }
287 });
288
289 var Dictionary = RegGrp.extend({
290 parse: function(phrase) {
291 // Prevent sub-expressions in dictionary entries from capturing.
292 var entries = this[ITEMS];
293 return phrase.replace(REGGRP_DICT_ENTRIES, function(match, entry) {
294 entry = entries[HASH + entry];
295 return entry ? entry._nonCapturing : match;
296 });
297 },
298
299 add: function(expression, replacement) {
300 // Get the underlying replacement value.
301 if (replacement instanceof RegExp) {
302 replacement = replacement.source;
303 }
304 // Translate the replacement.
305 // The result is the original replacement recursively parsed by this dictionary.
306 var nonCapturing = replacement.replace(REGGRP_LOOKUPS, _nonCapture);
307 if (replacement.indexOf("(") !== -1) {
308 var realLength = RegGrp.count(replacement);
309 }
310 if (replacement.indexOf("<#") !== -1) {
311 replacement = this.parse(replacement);
312 nonCapturing = this.parse(nonCapturing);
313 }
314 var item = this.base(expression, replacement);
315 item._nonCapturing = nonCapturing;
316 item._length = realLength || item.length; // underlying number of sub-groups
317 return item;
318 },
319
320 toString: function() {
321 return "(<#" + this[PATTERNS].join(">)|(<#") + ">)";
322 }
323 });
324
325 function _nonCapture(match, escaped) {
326 return escaped || "(?:"; // non-capturing
327 };
328
329 // =========================================================================
330 // lang/extend.js
331 // =========================================================================
332
333 function extend(object, source) { // or extend(object, key, value)
334 if (object && source) {
335 var proto = (typeof source == "function" ? Function : Object).prototype;
336 // Add constructor, toString etc
337 var i = _HIDDEN.length, key;
338 if (prototyping) while (key = _HIDDEN[--i]) {
339 var value = source[key];
340 if (value != proto[key]) {
341 if (_BASE.test(value)) {
342 _override(object, key, value)
343 } else {
344 object[key] = value;
345 }
346 }
347 }
348 // Copy each of the source object's properties to the target object.
349 for (key in source) if (typeof proto[key] == "undefined") {
350 var value = source[key];
351 // Check for method overriding.
352 if (object[key] && typeof value == "function" && _BASE.test(value)) {
353 _override(object, key, value);
354 } else {
355 object[key] = value;
356 }
357 }
358 }
359 return object;
360 };
361
362 function _override(object, name, method) {
363 // Override an existing method.
364 var ancestor = object[name];
365 object[name] = function() {
366 var previous = this.base;
367 this.base = ancestor;
368 var returnValue = method.apply(this, arguments);
369 this.base = previous;
370 return returnValue;
371 };
372 };
373
374 function combine(keys, values) {
375 // Combine two arrays to make a hash.
376 if (!values) values = keys;
377 var hash = {};
378 for (var i in keys) hash[i] = values[i];
379 return hash;
380 };
381
382 function format(string) {
383 // Replace %n with arguments[n].
384 // e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls");
385 // ==> "she sells sea shells"
386 // Only %1 - %9 supported.
387 var args = arguments;
388 var _FORMAT = new RegExp("%([1-" + arguments.length + "])", "g");
389 return String(string).replace(_FORMAT, function(match, index) {
390 return index < args.length ? args[index] : match;
391 });
392 };
393
394 function match(string, expression) {
395 // Same as String.match() except that this function will return an empty
396 // array if there is no match.
397 return String(string).match(expression) || [];
398 };
399
400 function rescape(string) {
401 // Make a string safe for creating a RegExp.
402 return String(string).replace(_RESCAPE, "\\$1");
403 };
404
405 // http://blog.stevenlevithan.com/archives/faster-trim-javascript
406 function trim(string) {
407 return String(string).replace(_LTRIM, "").replace(_RTRIM, "");
408 };
409
410 function K(k) {
411 return function() {
412 return k;
413 };
414 };
415
416 // -----------------------------------------------------------------------
417 // parsing
418 // -----------------------------------------------------------------------
419
420 var Parser = RegGrp.extend({ignoreCase: true});
421
422 var SINGLE_QUOTES = /'/g,
423 ESCAPED = /'(\d+)'/g,
424 ESCAPE = /\\/g,
425 UNESCAPE = /\\([nrtf'"])/g;
426
427 var strings = [];
428
429 var encoder = new Parser({
430 // comments
431 "<!\\-\\-|\\-\\->": "",
432 "\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/": "",
433 // get rid
434 "@(namespace|import)[^;\\n]+[;\\n]": "",
435 // strings
436 "'(\\\\.|[^'\\\\])*'": encodeString,
437 '"(\\\\.|[^"\\\\])*"': encodeString,
438 // white space
439 "\\s+": " "
440 });
441
442 function encode(selector) {
443 return encoder.parse(selector).replace(UNESCAPE, "$1");
444 };
445
446 function decode(query) {
447 // put string values back
448 return query.replace(ESCAPED, decodeString);
449 };
450
451 function encodeString(string) {
452 var index = strings.length;
453 strings[index] = string.slice(1, -1)
454 .replace(UNESCAPE, "$1")
455 .replace(SINGLE_QUOTES, "\\'");
456 return "'" + index + "'";
457 };
458
459 function decodeString(match, index) {
460 var string = strings[index];
461 if (string == null) return match;
462 return "'" + strings[index] + "'";
463 };
464
465 function getString(value) {
466 return value.indexOf("'") === 0 ? strings[value.slice(1, - 1)] : value;
467 };
468
469 // clone a "width" function to create a "height" function
470 var rotater = new RegGrp({
471 Width: "Height",
472 width: "height",
473 Left: "Top",
474 left: "top",
475 Right: "Bottom",
476 right: "bottom",
477 onX: "onY"
478 });
479
480 function rotate(fn) {
481 return rotater.parse(fn);
482 };
483
484 // -----------------------------------------------------------------------
485 // event handling
486 // -----------------------------------------------------------------------
487
488 var eventHandlers = [];
489
490 function addResize(handler) {
491 addRecalc(handler);
492 addEventHandler(window, "onresize", handler);
493 };
494
495 // add an event handler (function) to an element
496 function addEventHandler(element, type, handler) {
497 element.attachEvent(type, handler);
498 // store the handler so it can be detached later
499 eventHandlers.push(arguments);
500 };
501
502 // remove an event handler assigned to an element by IE7
503 function removeEventHandler(element, type, handler) {
504 try {
505 element.detachEvent(type, handler);
506 } catch (ex) {
507 // write a letter of complaint to microsoft..
508 }
509 };
510
511 // remove event handlers (they eat memory)
512 addEventHandler(window, "onunload", function() {
513 var handler;
514 while (handler = eventHandlers.pop()) {
515 removeEventHandler(handler[0], handler[1], handler[2]);
516 }
517 });
518
519 function register(handler, element, condition) { // -@DRE
520 //var set = handler[element.uniqueID];
521 if (!handler.elements) handler.elements = {};
522 if (condition) handler.elements[element.uniqueID] = element;
523 else delete handler.elements[element.uniqueID];
524 //return !set && condition;
525 return condition;
526 };
527
528 addEventHandler(window, "onbeforeprint", function() {
529 if (!IE7.CSS.print) new StyleSheet("print");
530 IE7.CSS.print.recalc();
531 });
532
533 // -----------------------------------------------------------------------
534 // pixel conversion
535 // -----------------------------------------------------------------------
536
537 // this is handy because it means that web developers can mix and match
538 // measurement units in their style sheets. it is not uncommon to
539 // express something like padding in "em" units whilst border thickness
540 // is most often expressed in pixels.
541
542 var PIXEL = /^\d+(px)?$/i;
543 var PERCENT = /^\d+%$/;
544 var getPixelValue = function(element, value) {
545 if (PIXEL.test(value)) return parseInt(value);
546 var style = element.style.left;
547 var runtimeStyle = element.runtimeStyle.left;
548 element.runtimeStyle.left = element.currentStyle.left;
549 element.style.left = value || 0;
550 value = element.style.pixelLeft;
551 element.style.left = style;
552 element.runtimeStyle.left = runtimeStyle;
553 return value;
554 };
555
556 // -----------------------------------------------------------------------
557 // generic
558 // -----------------------------------------------------------------------
559
560 var $IE7 = "ie7-";
561
562 var Fix = Base.extend({
563 constructor: function() {
564 this.fixes = [];
565 this.recalcs = [];
566 },
567 init: Undefined
568 });
569
570 // a store for functions that will be called when refreshing IE7
571 var recalcs = [];
572 function addRecalc(recalc) {
573 recalcs.push(recalc);
574 };
575
576 IE7.recalc = function() {
577 IE7.HTML.recalc();
578 // re-apply style sheet rules (re-calculate ie7 classes)
579 IE7.CSS.recalc();
580 // apply global fixes to the document
581 for (var i = 0; i < recalcs.length; i++) recalcs[i]();
582 };
583
584 function isFixed(element) {
585 return element.currentStyle["ie7-position"] == "fixed";
586 };
587
588 // original style
589 function getDefinedStyle(element, propertyName) {
590 return element.currentStyle[$IE7 + propertyName] || element.currentStyle[propertyName];
591 };
592
593 function setOverrideStyle(element, propertyName, value) {
594 if (element.currentStyle[$IE7 + propertyName] == null) {
595 element.runtimeStyle[$IE7 + propertyName] = element.currentStyle[propertyName];
596 }
597 element.runtimeStyle[propertyName] = value;
598 };
599
600 // Create a temporary element which is used to inherit styles
601 // from the target element.
602 function createTempElement(tagName) {
603 var element = document.createElement(tagName || "object");
604 element.style.cssText = "position:absolute;padding:0;display:block;border:none;clip:rect(0 0 0 0);left:-9999";
605 element.ie7_anon = true;
606 return element;
607 };
608
609
610 // =========================================================================
611 // ie7-css.js
612 // =========================================================================
613
614 var NEXT_SIBLING = "(e.nextSibling&&IE7._getElementSibling(e,'next'))",
615 PREVIOUS_SIBLING = NEXT_SIBLING.replace(/next/g, "previous"),
616 IS_ELEMENT = "e.nodeName>'@'",
617 IF_ELEMENT = "if(" + IS_ELEMENT + "){";
618
619 var ID_ATTRIBUTE = "(e.nodeName==='FORM'?IE7._getAttribute(e,'id'):e.id)";
620
621 var HYPERLINK = /a(#[\w-]+)?(\.[\w-]+)?:(hover|active)/i;
622 var FIRST_LINE_LETTER = /(.*)(:first-(line|letter))/;
623 var SPACE = /\s/;
624 var RULE = /((?:\\.|[^{\\])+)\{((?:\\.|[^}\\])+)\}/g;
625 var SELECTOR = /(?:\\.|[^,\\])+/g;
626
627 var styleSheets = document.styleSheets;
628
629 var inheritedProperties = [];
630
631 IE7.CSS = new (Fix.extend({ // single instance
632 parser: new Parser,
633 screen: "",
634 print: "",
635 styles: [],
636 rules: [],
637 pseudoClasses: appVersion < 7 ? "first\\-child" : "",
638 dynamicPseudoClasses: {
639 toString: function() {
640 var strings = [];
641 for (var pseudoClass in this) strings.push(pseudoClass);
642 return strings.join("|");
643 }
644 },
645
646 init: function() {
647 var NONE = "^\x01$";
648 var CLASS = "\\[class=?[^\\]]*\\]";
649 var pseudoClasses = [];
650 if (this.pseudoClasses) pseudoClasses.push(this.pseudoClasses);
651 var dynamicPseudoClasses = this.dynamicPseudoClasses.toString();
652 if (dynamicPseudoClasses) pseudoClasses.push(dynamicPseudoClasses);
653 pseudoClasses = pseudoClasses.join("|");
654 var unknown = appVersion < 7 ? ["[>+~\\[(]|([:.])[\\w-]+\\1"] : [CLASS];
655 if (pseudoClasses) unknown.push(":(" + pseudoClasses + ")");
656 this.UNKNOWN = new RegExp(unknown.join("|") || NONE, "i");
657 var complex = appVersion < 7 ? ["\\[[^\\]]+\\]|[^\\s(\\[]+\\s*[+~]"] : [CLASS];
658 var complexRule = complex.concat();
659 if (pseudoClasses) complexRule.push(":(" + pseudoClasses + ")");
660 Rule.COMPLEX = new RegExp(complexRule.join("|") || NONE, "ig");
661 if (this.pseudoClasses) complex.push(":(" + this.pseudoClasses + ")");
662 DynamicRule.COMPLEX = new RegExp(complex.join("|") || NONE, "i");
663 dynamicPseudoClasses = "not\\(:" + dynamicPseudoClasses.split("|").join("\\)|not\\(:") + "\\)|" + dynamicPseudoClasses;
664 DynamicRule.MATCH = new RegExp(dynamicPseudoClasses ? "(.*?):(" + dynamicPseudoClasses + ")(.*)" : NONE, "i");
665
666 this.createStyleSheet();
667 this.refresh();
668 },
669
670 addEventHandler: function() {
671 addEventHandler.apply(null, arguments);
672 },
673
674 addFix: function(expression, replacement) {
675 this.parser.add(expression, replacement);
676 },
677
678 addRecalc: function(propertyName, test, handler, replacement) {
679 // recalcs occur whenever the document is refreshed using document.recalc()
680 propertyName = propertyName.source || propertyName;
681 test = new RegExp("([{;\\s])" + propertyName + "\\s*:\\s*" + test + "[^;}]*");
682 var id = this.recalcs.length;
683 if (typeof replacement == "string") replacement = propertyName + ":" + replacement;
684 this.addFix(test, function(match) {
685 if (typeof replacement == "function") replacement = replacement(match);
686 return (replacement ? replacement : match) + ";ie7-" + match.slice(1) + ";ie7_recalc" + id + ":1";
687 });
688 this.recalcs.push(arguments);
689 return id;
690 },
691
692 apply: function() {
693 this.getInlineCSS();
694 new StyleSheet("screen");
695 this.trash();
696 },
697
698 createStyleSheet: function() {
699 // create the IE7 style sheet
700 document.getElementsByTagName("head")[0].appendChild(document.createElement("style"));
701 this.styleSheet = styleSheets[styleSheets.length - 1];
702 // flag it so we can ignore it during parsing
703 this.styleSheet.ie7 = true;
704 this.styleSheet.owningElement.ie7 = true;
705 this.styleSheet.cssText = HEADER;
706 },
707
708 getInlineCSS: function() {// load inline styles
709 var styleSheets = document.getElementsByTagName("style"), styleSheet;
710 for (var i = styleSheets.length - 1; styleSheet = styleSheets[i]; i--) {
711 if (!styleSheet.disabled && !styleSheet.ie7) {
712 styleSheet._cssText = styleSheet.innerHTML;
713 }
714 }
715 },
716
717 getText: function(styleSheet, path) {
718 // Internet Explorer will trash unknown selectors (it converts them to "UNKNOWN").
719 // So we must reload external style sheets (internal style sheets can have their text
720 // extracted through the innerHTML property).
721
722 // load the style sheet text from an external file
723 try {
724 var cssText = styleSheet.cssText;
725 } catch (e) {
726 cssText = "";
727 }
728 if (httpRequest) cssText = loadFile(styleSheet.href, path) || cssText;
729 return cssText;
730 },
731
732 recalc: function() {
733 this.screen.recalc();
734 // we're going to read through all style rules.
735 // certain rules have had ie7 properties added to them.
736 // e.g. p{top:0; ie7_recalc2:1; left:0}
737 // this flags a property in the rule as needing a fix.
738 // the selector text is then used to query the document.
739 // we can then loop through the results of the query
740 // and fix the elements.
741 // we ignore the IE7 rules - so count them in the header
742 var RECALCS = /ie7_recalc\d+/g;
743 var start = HEADER.match(/[{,]/g).length;
744 // only calculate screen fixes. print fixes don't show up anyway
745 var rules = this.styleSheet.rules, rule;
746 var calcs, calc, elements, element, i, j, k, id;
747 // loop through all rules
748 for (i = start; rule = rules[i]; i++) {
749 var cssText = rule.style.cssText;
750 // search for the "ie7_recalc" flag (there may be more than one)
751 if (calcs = cssText.match(RECALCS)) {
752 // use the selector text to query the document
753 elements = cssQuery(rule.selectorText);
754 // if there are matching elements then loop
755 // through the recalc functions and apply them
756 // to each element
757 if (elements.length) for (j = 0; j < calcs.length; j++) {
758 // get the matching flag (e.g. ie7_recalc3)
759 id = calcs[j];
760 // extract the numeric id from the end of the flag
761 // and use it to index the collection of recalc
762 // functions
763 calc = IE7.CSS.recalcs[id.slice(10)][2];
764 for (k = 0; (element = elements[k]); k++) {
765 // apply the fix
766 if (element.currentStyle[id]) calc(element, cssText);
767 }
768 }
769 }
770 }
771 },
772
773 refresh: function() {
774 this.styleSheet.cssText = HEADER + this.screen + this.print;
775 },
776
777 trash: function() {
778 // trash the old style sheets
779 for (var i = 0; i < styleSheets.length; i++) {
780 if (!styleSheets[i].ie7) {
781 try {
782 var cssText = styleSheets[i].cssText;
783 } catch (e) {
784 cssText = "";
785 }
786 if (cssText) styleSheets[i].cssText = "";
787 }
788 }
789 }
790 }));
791
792 // -----------------------------------------------------------------------
793 // IE7 StyleSheet class
794 // -----------------------------------------------------------------------
795
796 var StyleSheet = Base.extend({
797 constructor: function(media) {
798 this.media = media;
799 this.load();
800 IE7.CSS[media] = this;
801 IE7.CSS.refresh();
802 },
803
804 createRule: function(selector, cssText) {
805 var match;
806 if (PseudoElement && (match = selector.match(PseudoElement.MATCH))) {
807 return new PseudoElement(match[1], match[2], cssText);
808 } else if (match = selector.match(DynamicRule.MATCH)) {
809 if (!HYPERLINK.test(match[0]) || DynamicRule.COMPLEX.test(match[0])) {
810 return new DynamicRule(selector, match[1], match[2], match[3], cssText);
811 }
812 } else {
813 return new Rule(selector, cssText);
814 }
815 return selector + " {" + cssText + "}";
816 },
817
818 getText: function() {
819 // store for style sheet text
820 // parse media decalarations
821 var MEDIA = /@media\s+([^{]+?)\s*\{([^@]+\})\s*\}/gi;
822 var IMPORTS = /@import[^;\n]+/gi;
823 var TRIM_IMPORTS = /@import\s+url\s*\(\s*["']?|["']?\s*\)\s*/gi;
824 var URL = /(url\s*\(\s*['"]?)([\w\.]+[^:\)]*['"]?\))/gi;
825
826 var self = this;
827
828 // Store loaded cssText URLs
829 var fileCache = {};
830
831 function getCSSText(styleSheet, path, media, level) {
832 var cssText = "";
833 if (!level) {
834 media = toSimpleMedia(styleSheet.media);
835 level = 0;
836 }
837 if (media === "none") {
838 styleSheet.disabled = true;
839 return "";
840 }
841 if (media === "all" || media === self.media) {
842 // IE only allows importing style sheets three levels deep.
843 // it will crash if you try to access a level below this
844 if (level < 3 && styleSheet.cssText) {
845 var hrefs = styleSheet.cssText.match(IMPORTS);
846 // loop through imported style sheets
847 for (var i = 0, imported; i < styleSheet.imports.length; i++) {
848 var imported = styleSheet.imports[i];
849 var href = styleSheet._href || styleSheet.href;
850 imported._href = hrefs[i].replace(TRIM_IMPORTS, "");
851 // call this function recursively to get all imported style sheets
852 cssText += getCSSText(imported, getPath(href, path), media, level + 1);
853 }
854 }
855 // retrieve inline style or load an external style sheet
856 cssText += encode(styleSheet.href ? loadStyleSheet(styleSheet, path) : styleSheet.owningElement._cssText);
857 cssText = parseMedia(cssText, self.media);
858 }
859 return cssText;
860 };
861
862 // Load all style sheets in the document
863 for (var i = 0; i < styleSheets.length; i++) {
864 var styleSheet = styleSheets[i];
865 if (!styleSheet.disabled && !styleSheet.ie7) this.cssText += getCSSText(styleSheet);
866 }
867
868 // helper functions
869 function parseMedia(cssText, media) {
870 filterMedia.value = media;
871 return cssText.replace(MEDIA, filterMedia);
872 };
873
874 function filterMedia(match, media, cssText) {
875 media = toSimpleMedia(media);
876 switch (media) {
877 case "screen":
878 case "print":
879 if (media !== filterMedia.value) return "";
880 case "all":
881 return cssText;
882 }
883 return "";
884 };
885
886 function toSimpleMedia(media) {
887 if (!media) return "all";
888 var split = media.toLowerCase().split(/\s*,\s*/);
889 media = "none";
890 for (var i = 0; i < split.length; i++) {
891 if (split[i] === "all") return "all";
892 if (split[i] === "screen") {
893 if (media === "print") return "all";
894 media = "screen";
895 } else if (split[i] === "print") {
896 if (media === "screen") return "all";
897 media = "print";
898 }
899 }
900 return media;
901 };
902
903 // Load an external style sheet
904 function loadStyleSheet(styleSheet, path) {
905 var href = styleSheet._href || styleSheet.href;
906 var url = makePath(href, path);
907 // If the style sheet has already loaded then don't reload it
908 if (fileCache[url]) return "";
909 // Load from source
910 fileCache[url] = styleSheet.disabled ? "" :
911 fixUrls(IE7.CSS.getText(styleSheet, path), getPath(href, path));
912 return fileCache[url];
913 };
914
915 // Fix CSS paths.
916 // We're lumping all css text into one big style sheet so relative
917 // paths have to be fixed. This is necessary anyway because of other
918 // Internet Explorer bugs.
919 function fixUrls(cssText, pathname) {
920 // hack & slash
921 return cssText.replace(URL, "$1" + pathname.slice(0, pathname.lastIndexOf("/") + 1) + "$2");
922 };
923 },
924
925 load: function() {
926 this.cssText = "";
927 this.getText();
928 this.parse();
929 if (inheritedProperties.length) {
930 this.cssText = parseInherited(this.cssText);
931 }
932 this.cssText = decode(this.cssText);
933 fileCache = {};
934 },
935
936 parse: function() {
937 this.cssText = IE7.CSS.parser.parse(this.cssText);
938
939 // Parse the style sheet
940 var offset = IE7.CSS.rules.length;
941 var rules = [], rule;
942 while ((rule = RULE.exec(this.cssText))) {
943 var cssText = rule[2];
944 if (cssText) {
945 var fixDescendants = appVersion < 7 && cssText.indexOf("AlphaImageLoader") !== -1;
946 var selectors = rule[1].match(SELECTOR), selector;
947 for (var i = 0; selector = selectors[i]; i++) {
948 selector = trim(selector);
949 var isUnknown = IE7.CSS.UNKNOWN.test(selector);
950 selectors[i] = isUnknown ? this.createRule(selector, cssText) : selector + "{" + cssText + "}";
951 if (fixDescendants) selectors[i] += this.createRule(selector + ">*", "position:relative");
952 }
953 rules.push(selectors.join("\n"));
954 }
955 }
956 this.cssText = rules.join("\n");
957 this.rules = IE7.CSS.rules.slice(offset);
958 },
959
960 recalc: function() {
961 var rule, i;
962 for (i = 0; (rule = this.rules[i]); i++) rule.recalc();
963 },
964
965 toString: function() {
966 return "@media " + this.media + "{" + this.cssText + "}";
967 }
968 });
969
970 var PseudoElement;
971
972 // -----------------------------------------------------------------------
973 // IE7 style rules
974 // -----------------------------------------------------------------------
975
976 var Rule = IE7.Rule = Base.extend({
977 constructor: function(selector, cssText) {
978 this.id = IE7.CSS.rules.length;
979 this.className = Rule.PREFIX + this.id;
980 var pseudoElement = selector.match(FIRST_LINE_LETTER);
981 this.selector = (pseudoElement ? pseudoElement[1] : selector) || "*";
982 this.selectorText = this.parse(this.selector) + (pseudoElement ? pseudoElement[2] : "");
983 this.cssText = cssText;
984 this.MATCH = new RegExp("\\s" + this.className + "(\\s|$)", "g");
985 IE7.CSS.rules.push(this);
986 this.init();
987 },
988
989 init: Undefined,
990
991 add: function(element) {
992 // allocate this class
993 element.className += " " + this.className;
994 },
995
996 recalc: function() {
997 // execute the underlying css query for this class
998 var match = cssQuery(this.selector);
999 // add the class name for all matching elements
1000 for (var i = 0; i < match.length; i++) this.add(match[i]);
1001 },
1002
1003 parse: function(selector) {
1004 // attempt to preserve specificity for "loose" parsing by
1005 // removing unknown tokens from a css selector but keep as
1006 // much as we can..
1007 var simple = selector.replace(Rule.CHILD, " ").replace(Rule.COMPLEX, "");
1008 if (appVersion < 7) simple = simple.replace(Rule.MULTI, "");
1009 var tags = match(simple, Rule.TAGS).length - match(selector, Rule.TAGS).length;
1010 var classes = match(simple, Rule.CLASSES).length - match(selector, Rule.CLASSES).length + 1;
1011 while (classes > 0 && Rule.CLASS.test(simple)) {
1012 simple = simple.replace(Rule.CLASS, "");
1013 classes--;
1014 }
1015 while (tags > 0 && Rule.TAG.test(simple)) {
1016 simple = simple.replace(Rule.TAG, "$1*");
1017 tags--;
1018 }
1019 simple += "." + this.className;
1020 classes = Math.min(classes, 2);
1021 tags = Math.min(tags, 2);
1022 var score = -10 * classes - tags;
1023 if (score > 0) {
1024 simple = simple + "," + Rule.MAP[score] + " " + simple;
1025 }
1026 return simple;
1027 },
1028
1029 remove: function(element) {
1030 // deallocate this class
1031 element.className = element.className.replace(this.MATCH, "$1");
1032 },
1033
1034 toString: function() {
1035 return format("%1 {%2}", this.selectorText, this.cssText);
1036 }
1037 }, {
1038 CHILD: />/g,
1039 CLASS: /\.[\w-]+/,
1040 CLASSES: /[.:\[]/g,
1041 MULTI: /(\.[\w-]+)+/g,
1042 PREFIX: "ie7_class",
1043 TAG: /^\w+|([\s>+~])\w+/,
1044 TAGS: /^\w|[\s>+~]\w/g,
1045 MAP: {
1046 "1": "html",
1047 "2": "html body",
1048 "10": ".ie7_html",
1049 "11": "html.ie7_html",
1050 "12": "html.ie7_html body",
1051 "20": ".ie7_html .ie7_body",
1052 "21": "html.ie7_html .ie7_body",
1053 "22": "html.ie7_html body.ie7_body"
1054 }
1055 });
1056
1057 // -----------------------------------------------------------------------
1058 // IE7 dynamic style
1059 // -----------------------------------------------------------------------
1060
1061 // object properties:
1062 // attach: the element that an event handler will be attached to
1063 // target: the element that will have the IE7 class applied
1064
1065 var DynamicRule = Rule.extend({
1066 // properties
1067 constructor: function(selector, attach, dynamicPseudoClass, target, cssText) {
1068 this.negated = dynamicPseudoClass.indexOf("not") === 0;
1069 if (this.negated) dynamicPseudoClass = dynamicPseudoClass.slice(5, -1);
1070 // initialise object properties
1071 this.attach = attach || "*";
1072 this.dynamicPseudoClass = IE7.CSS.dynamicPseudoClasses[dynamicPseudoClass];
1073 this.target = target;
1074 this.base(selector, cssText);
1075 },
1076
1077 recalc: function() {
1078 // execute the underlying css query for this class
1079 var attaches = cssQuery(this.attach), attach;
1080 // process results
1081 for (var i = 0; attach = attaches[i]; i++) {
1082 // retrieve the event handler's target element(s)
1083 var target = this.target ? cssQuery(this.target, attach) : [attach];
1084 // attach event handlers for dynamic pseudo-classes
1085 if (target.length) this.dynamicPseudoClass.apply(attach, target, this);
1086 }
1087 }
1088 });
1089
1090 // -----------------------------------------------------------------------
1091 // IE7 dynamic pseudo-classes
1092 // -----------------------------------------------------------------------
1093
1094 var DynamicPseudoClass = Base.extend({
1095 constructor: function(name, apply) {
1096 this.name = name;
1097 this.apply = apply;
1098 this.instances = {};
1099 IE7.CSS.dynamicPseudoClasses[name] = this;
1100 },
1101
1102 register: function(instance, negated) {
1103 // an "instance" is actually an Arguments object
1104 var _class = instance[2];
1105 if (!negated && _class.negated) {
1106 this.unregister(instance, true);
1107 } else {
1108 instance.id = _class.id + instance[0].uniqueID;
1109 if (!this.instances[instance.id]) {
1110 var target = instance[1], j;
1111 for (j = 0; j < target.length; j++) _class.add(target[j]);
1112 this.instances[instance.id] = instance;
1113 }
1114 }
1115 },
1116
1117 unregister: function(instance, negated) {
1118 var _class = instance[2];
1119 if (!negated && _class.negated) {
1120 this.register(instance, true);
1121 } else {
1122 if (this.instances[instance.id]) {
1123 var target = instance[1], j;
1124 for (j = 0; j < target.length; j++) _class.remove(target[j]);
1125 delete this.instances[instance.id];
1126 }
1127 }
1128 }
1129 });
1130
1131 // -----------------------------------------------------------------------
1132 // dynamic pseudo-classes
1133 // -----------------------------------------------------------------------
1134
1135 if (appVersion < 7) {
1136 var Hover = new DynamicPseudoClass("hover", function(element) {
1137 var instance = arguments;
1138 IE7.CSS.addEventHandler(element, "onmouseenter", function() {
1139 Hover.register(instance);
1140 });
1141 IE7.CSS.addEventHandler(element, "onmouseleave", function() {
1142 Hover.unregister(instance);
1143 });
1144 });
1145
1146 // globally trap the mouseup event (thanks Martijn!)
1147 addEventHandler(document, "onmouseup", function() {
1148 var instances = Hover.instances;
1149 for (var i in instances)
1150 if (!instances[i][0].contains(event.srcElement))
1151 Hover.unregister(instances[i]);
1152 });
1153 }
1154
1155 var ATTR = {
1156 "=": "%1==='%2'", // "[@%1='%2']"
1157 "~=": "(' '+%1+' ').indexOf(' %2 ')!==-1", // "[contains(concat(' ',@%1,' '),' %2 ')]",
1158 "|=": "%1==='%2'||%1.indexOf('%2-')===0", // "[@%1='%2' or starts-with(@%1,'%2-')]",
1159 "^=": "%1.indexOf('%2')===0", // "[starts-with(@%1,'%2')]",
1160 "$=": "%1.slice(-'%2'.length)==='%2'", // "[ends-with(@%1,'%2')]",
1161 "*=": "%1.indexOf('%2')!==-1" // "[contains(@%1,'%2')]"
1162 };
1163 ATTR[""] = "%1!=null"; // "[@%1]"
1164
1165 var FILTER = {
1166 "<#attr>": function(match, name, operator, value) {
1167 var attr = "IE7._getAttribute(e,'" + name + "')";
1168 value = getString(value);
1169 if (operator.length > 1) {
1170 if (!value || operator === "~=" && SPACE.test(value)) {
1171 return "false&&";
1172 }
1173 attr = "(" + attr + "||'')";
1174 }
1175 return "(" + format(ATTR[operator], attr, value) + ")&&";
1176 },
1177
1178 "<#id>": ID_ATTRIBUTE + "==='$1'&&",
1179
1180 "<#class>": "e.className&&(' '+e.className+' ').indexOf(' $1 ')!==-1&&",
1181
1182 // PSEDUO
1183 ":first-child": "!" + PREVIOUS_SIBLING + "&&",
1184 ":link": "e.href&&(e.nodeName==='A'||e.nodeName==='AREA')&&",
1185 ":visited": "false&&" // not implemented (security)
1186 };
1187
1188 // =========================================================================
1189 // ie7-html.js
1190 // =========================================================================
1191
1192 // default font-sizes
1193 //HEADER += "h1{font-size:2em}h2{font-size:1.5em;}h3{font-size:1.17em;}h4{font-size:1em}h5{font-size:.83em}h6{font-size:.67em}";
1194
1195 IE7.HTML = new (Fix.extend({ // single instance
1196 fixed: {},
1197
1198 init: Undefined,
1199
1200 addFix: function() {
1201 // fixes are a one-off, they are applied when the document is loaded
1202 this.fixes.push(arguments);
1203 },
1204
1205 apply: function() {
1206 for (var i = 0; i < this.fixes.length; i++) {
1207 var match = cssQuery(this.fixes[i][0]);
1208 var fix = this.fixes[i][1];
1209 for (var j = 0; j < match.length; j++) fix(match[j]);
1210 }
1211 },
1212
1213 addRecalc: function() {
1214 // recalcs occur whenever the document is refreshed using document.recalc()
1215 this.recalcs.push(arguments);
1216 },
1217
1218 recalc: function() {
1219 // loop through the fixes
1220 for (var i = 0; i < this.recalcs.length; i++) {
1221 var match = cssQuery(this.recalcs[i][0]);
1222 var recalc = this.recalcs[i][1], element;
1223 var key = Math.pow(2, i);
1224 for (var j = 0; (element = match[j]); j++) {
1225 var uniqueID = element.uniqueID;
1226 if ((this.fixed[uniqueID] & key) === 0) {
1227 element = recalc(element) || element;
1228 this.fixed[uniqueID] |= key;
1229 }
1230 }
1231 }
1232 }
1233 }));
1234
1235 if (appVersion < 7) {
1236 // provide support for the <abbr> tag.
1237 document.createElement("abbr");
1238
1239 // bind to the first child control
1240 IE7.HTML.addRecalc("label", function(label) {
1241 if (!label.htmlFor) {
1242 var firstChildControl = cssQuery("input,textarea", label, true);
1243 if (firstChildControl) {
1244 addEventHandler(label, "onclick", function() {
1245 firstChildControl.click();
1246 });
1247 }
1248 }
1249 });
1250 }
1251
1252 // =========================================================================
1253 // ie7-layout.js
1254 // =========================================================================
1255
1256 var NUMERIC = "[.\\d]";
1257
1258 (function() {
1259 var layout = IE7.Layout = {};
1260
1261 // big, ugly box-model hack + min/max stuff
1262
1263 // #tantek > #erik > #dean { voice-family: hacker; }
1264
1265 // -----------------------------------------------------------------------
1266 // "layout"
1267 // -----------------------------------------------------------------------
1268
1269 HEADER += "*{boxSizing:content-box}";
1270
1271 // give an element "layout"
1272 layout.boxSizing = function(element) {
1273 if (!element.currentStyle.hasLayout) {
1274 //# element.runtimeStyle.fixedHeight =
1275 element.style.height = "0cm";
1276 if (element.currentStyle.verticalAlign === "auto")
1277 element.runtimeStyle.verticalAlign = "top";
1278 // when an element acquires "layout", margins no longer collapse correctly
1279 collapseMargins(element);
1280 }
1281 };
1282
1283 // -----------------------------------------------------------------------
1284 // Margin Collapse
1285 // -----------------------------------------------------------------------
1286
1287 function collapseMargins(element) {
1288 if (element != viewport && element.currentStyle.position !== "absolute") {
1289 collapseMargin(element, "marginTop");
1290 collapseMargin(element, "marginBottom");
1291 }
1292 };
1293
1294 function collapseMargin(element, type) {
1295 if (!element.runtimeStyle[type]) {
1296 var parentElement = element.parentElement;
1297 var isTopMargin = type === "marginTop";
1298 if (parentElement && parentElement.currentStyle.hasLayout && !IE7._getElementSibling(element, isTopMargin ? "previous" : "next")) return;
1299 var child = element[isTopMargin ? "firstChild" : "lastChild"];
1300 if (child && child.nodeName < "@") child = IE7._getElementSibling(child, isTopMargin ? "next" : "previous");
1301 if (child && child.currentStyle.styleFloat === "none" && child.currentStyle.hasLayout) {
1302 collapseMargin(child, type);
1303 margin = _getMargin(element, element.currentStyle[type]);
1304 childMargin = _getMargin(child, child.currentStyle[type]);
1305 if (margin < 0 || childMargin < 0) {
1306 element.runtimeStyle[type] = margin + childMargin;
1307 } else {
1308 element.runtimeStyle[type] = Math.max(childMargin, margin);
1309 }
1310 child.runtimeStyle[type] = "0px";
1311 }
1312 }
1313 };
1314
1315 function _getMargin(element, value) {
1316 return value === "auto" ? 0 : getPixelValue(element, value);
1317 };
1318
1319 // -----------------------------------------------------------------------
1320 // box-model
1321 // -----------------------------------------------------------------------
1322
1323 // constants
1324 var UNIT = /^[.\d][\w]*$/, AUTO = /^(auto|0cm)$/;
1325
1326 var apply = {};
1327 layout.borderBox = function(element){
1328 apply.Width(element);
1329 apply.Height(element);
1330 };
1331
1332 var _fixWidth = function(HEIGHT) {
1333 apply.Width = function(element) {
1334 if (!PERCENT.test(element.currentStyle.width)) _fixWidth(element);
1335 if (HEIGHT) collapseMargins(element);
1336 };
1337
1338 function _fixWidth(element, value) {
1339 if (!element.runtimeStyle.fixedWidth) {
1340 if (!value) value = element.currentStyle.width;
1341 element.runtimeStyle.fixedWidth = UNIT.test(value) ? Math.max(0, getFixedWidth(element, value)) + "px" : value;
1342 setOverrideStyle(element, "width", element.runtimeStyle.fixedWidth);
1343 }
1344 };
1345
1346 function layoutWidth(element) {
1347 if (!isFixed(element)) {
1348 var layoutParent = element.offsetParent;
1349 while (layoutParent && !layoutParent.currentStyle.hasLayout) layoutParent = layoutParent.offsetParent;
1350 }
1351 return (layoutParent || viewport).clientWidth;
1352 };
1353
1354 function getPixelWidth(element, value) {
1355 if (PERCENT.test(value)) return parseInt(parseFloat(value) / 100 * layoutWidth(element));
1356 return getPixelValue(element, value);
1357 };
1358
1359 var getFixedWidth = function(element, value) {
1360 var borderBox = element.currentStyle["ie7-box-sizing"] === "border-box";
1361 var adjustment = 0;
1362 if (MSIE5 && !borderBox)
1363 adjustment += getBorderWidth(element) + getWidth(element, "padding");
1364 else if (!MSIE5 && borderBox)
1365 adjustment -= getBorderWidth(element) + getWidth(element, "padding");
1366 return getPixelWidth(element, value) + adjustment;
1367 };
1368
1369 // easy way to get border thickness for elements with "layout"
1370 function getBorderWidth(element) {
1371 return element.offsetWidth - element.clientWidth;
1372 };
1373
1374 // have to do some pixel conversion to get padding/margin thickness :-(
1375 function getWidth(element, type) {
1376 return getPixelWidth(element, element.currentStyle[type + "Left"]) + getPixelWidth(element, element.currentStyle[type + "Right"]);
1377 };
1378
1379 // -----------------------------------------------------------------------
1380 // min/max
1381 // -----------------------------------------------------------------------
1382
1383 HEADER += "*{minWidth:none;maxWidth:none;min-width:none;max-width:none}";
1384
1385 // handle min-width property
1386 layout.minWidth = function(element) {
1387 // IE6 supports min-height so we frig it here
1388 //#if (element.currentStyle.minHeight === "auto") element.runtimeStyle.minHeight = 0;
1389 if (element.currentStyle["min-width"] != null) {
1390 element.style.minWidth = element.currentStyle["min-width"];
1391 }
1392 if (register(arguments.callee, element, element.currentStyle.minWidth !== "none")) {
1393 layout.boxSizing(element);
1394 _fixWidth(element);
1395 resizeWidth(element);
1396 }
1397 };
1398
1399 // clone the minWidth function to make a maxWidth function
1400 eval("IE7.Layout.maxWidth=" + String(layout.minWidth).replace(/min/g, "max"));
1401
1402 // apply min/max restrictions
1403 function resizeWidth(element) {
1404 // check boundaries
1405 if (element == document.body) {
1406 var width = element.clientWidth;
1407 } else {
1408 var rect = element.getBoundingClientRect();
1409 width = rect.right - rect.left;
1410 }
1411 if (element.currentStyle.minWidth !== "none" && width < getFixedWidth(element, element.currentStyle.minWidth)) {
1412 element.runtimeStyle.width = element.currentStyle.minWidth;
1413 } else if (element.currentStyle.maxWidth !== "none" && width >= getFixedWidth(element, element.currentStyle.maxWidth)) {
1414 element.runtimeStyle.width = element.currentStyle.maxWidth;
1415 } else {
1416 element.runtimeStyle.width = element.runtimeStyle.fixedWidth;
1417 }
1418 };
1419
1420 // -----------------------------------------------------------------------
1421 // right/bottom
1422 // -----------------------------------------------------------------------
1423
1424 function fixRight(element) {
1425 if (register(fixRight, element, /^(fixed|absolute)$/.test(element.currentStyle.position) &&
1426 getDefinedStyle(element, "left") !== "auto" &&
1427 getDefinedStyle(element, "right") !== "auto" &&
1428 AUTO.test(getDefinedStyle(element, "width")))) {
1429 resizeRight(element);
1430 layout.boxSizing(element);
1431 }
1432 };
1433 layout.fixRight = fixRight;
1434
1435 function resizeRight(element) {
1436 var left = getPixelWidth(element, element.runtimeStyle._left || element.currentStyle.left);
1437 var width = layoutWidth(element) - getPixelWidth(element, element.currentStyle.right) - left - getWidth(element, "margin");
1438 if (parseInt(element.runtimeStyle.width) === width) return;
1439 element.runtimeStyle.width = "";
1440 if (isFixed(element) || HEIGHT || element.offsetWidth < width) {
1441 if (!MSIE5) width -= getBorderWidth(element) + getWidth(element, "padding");
1442 if (width < 0) width = 0;
1443 element.runtimeStyle.fixedWidth = width;
1444 setOverrideStyle(element, "width", width);
1445 }
1446 };
1447
1448 // -----------------------------------------------------------------------
1449 // window.onresize
1450 // -----------------------------------------------------------------------
1451
1452 // handle window resize
1453 var clientWidth = 0;
1454 addResize(function() {
1455 if (!viewport) return;
1456 var i, wider = (clientWidth < viewport.clientWidth);
1457 clientWidth = viewport.clientWidth;
1458 // resize elements with "min-width" set
1459 var elements = layout.minWidth.elements;
1460 for (i in elements) {
1461 var element = elements[i];
1462 var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.minWidth));
1463 if (wider && fixedWidth) element.runtimeStyle.width = "";
1464 if (wider == fixedWidth) resizeWidth(element);
1465 }
1466 // resize elements with "max-width" set
1467 var elements = layout.maxWidth.elements;
1468 for (i in elements) {
1469 var element = elements[i];
1470 var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.maxWidth));
1471 if (!wider && fixedWidth) element.runtimeStyle.width = "";
1472 if (wider !== fixedWidth) resizeWidth(element);
1473 }
1474 // resize elements with "right" set
1475 for (i in fixRight.elements) resizeRight(fixRight.elements[i]);
1476 });
1477
1478 // -----------------------------------------------------------------------
1479 // fix CSS
1480 // -----------------------------------------------------------------------
1481 if (MSIE5) {
1482 IE7.CSS.addRecalc("width", NUMERIC, apply.Width);
1483 }
1484 if (appVersion < 7) {
1485 IE7.CSS.addRecalc("max-width", NUMERIC, layout.maxWidth);
1486 IE7.CSS.addRecalc("right", NUMERIC, fixRight);
1487 } else if (appVersion == 7) {
1488 if (HEIGHT) IE7.CSS.addRecalc("height", "[\\d.]+%", function(element) {
1489 element.runtimeStyle.pixelHeight = parseInt(layoutWidth(element) * element.currentStyle["ie7-height"].slice(0, -1) / 100);
1490 });
1491 }
1492 };
1493
1494 eval("var _fixHeight=" + rotate(_fixWidth));
1495
1496 // apply box-model + min/max fixes
1497 _fixWidth();
1498 _fixHeight(true);
1499
1500 if (appVersion < 7) {
1501 IE7.CSS.addRecalc("min-width", NUMERIC, layout.minWidth);
1502 IE7.CSS.addFix(/\bmin-height\s*/, "height");
1503 }
1504 })();
1505
1506 // =========================================================================
1507 // ie7-graphics.js
1508 // =========================================================================
1509
1510 // a small transparent image used as a placeholder
1511 var BLANK_GIF = makePath("blank.gif", path);
1512
1513 var ALPHA_IMAGE_LOADER = "DXImageTransform.Microsoft.AlphaImageLoader";
1514 var PNG_FILTER = "progid:" + ALPHA_IMAGE_LOADER + "(src='%1',sizingMethod='%2')";
1515
1516 // regular expression version of the above
1517 var PNG;
1518
1519 var filtered = [];
1520
1521 function fixImage(element) {
1522 if (PNG.test(element.src)) {
1523 // we have to preserve width and height
1524 var image = new Image(element.width, element.height);
1525 image.onload = function() {
1526 element.width = image.width;
1527 element.height = image.height;
1528 image = null;
1529 };
1530 image.src = element.src;
1531 // store the original url (we'll put it back when it's printed)
1532 element.pngSrc = element.src;
1533 // add the AlphaImageLoader thingy
1534 addFilter(element);
1535 }
1536 };
1537
1538 if (appVersion < 7) {
1539 // ** IE7 VARIABLE
1540 // e.g. apply the hack to all files ending in ".png"
1541 // IE7_PNG_SUFFIX = ".png";
1542 // You can also set it to a RegExp
1543 // IE7_PNG_SUFFIX = /\d+\.png$/;
1544
1545 // replace background(-image): url(..) .. with background(-image): .. ;filter: ..;
1546 IE7.CSS.addFix(/background(-image)?\s*:\s*([^};]*)?url\(([^\)]+)\)([^;}]*)?/, function(match, $1, $2, url, $4) {
1547 url = getString(url);
1548 return PNG.test(url) ? "filter:" + format(PNG_FILTER, url, $4.indexOf("no-repeat") === -1 ? "scale" : "crop") +
1549 ";zoom:1;background" + ($1||"") + ":" + ($2||"") + "none" + ($4||"") : match;
1550 });
1551
1552 // list-style-image
1553 IE7.CSS.addRecalc(/list\-style(\-image)?/, "[^};]*url", function(element) {
1554 var url = element.currentStyle.listStyleImage.slice(5, -2);
1555 if (PNG.test(url)) {
1556 if (element.nodeName === "LI") {
1557 fixListStyleImage(element, url)
1558 } else if (element.nodeName === "UL") {
1559 for (var i = 0, li; li = element.childNodes[i]; i++) {
1560 if (li.nodeName === "LI") fixListStyleImage(li, url);
1561 }
1562 }
1563 }
1564 });
1565
1566 function fixListStyleImage(element, src) {
1567 var style = element.runtimeStyle;
1568 var originalHeight = element.offsetHeight;
1569 var image = new Image;
1570 image.onload = function() {
1571 var paddingLeft = element.currentStyle.paddingLeft;
1572 paddingLeft = paddingLeft === "0px" ? 0 : getPixelValue(element, paddingLeft);
1573 style.paddingLeft = (paddingLeft + this.width) + "px";
1574 style.marginLeft = -this.width + "px";
1575 style.listStyleType = "none";
1576 style.listStyleImage = "none";
1577 style.paddingTop = Math.max(originalHeight - element.offsetHeight, 0) + "px";
1578 addFilter(element, "crop", src);
1579 element.style.zoom = "100%";
1580 };
1581 image.src = src;
1582 };
1583
1584 // -----------------------------------------------------------------------
1585 // fix PNG transparency (HTML images)
1586 // -----------------------------------------------------------------------
1587
1588 IE7.HTML.addRecalc("img,input", function(element) {
1589 if (element.nodeName === "INPUT" && element.type !== "image") return;
1590 fixImage(element);
1591 addEventHandler(element, "onpropertychange", function() {
1592 if (!printing && event.propertyName === "src" &&
1593 element.src.indexOf(BLANK_GIF) === -1) fixImage(element);
1594 });
1595 });
1596
1597 // assume that background images should not be printed
1598 // (if they are not transparent then they'll just obscure content)
1599 // but we'll put foreground images back...
1600 var printing = false;
1601 addEventHandler(window, "onbeforeprint", function() {
1602 printing = true;
1603 for (var i = 0; i < filtered.length; i++) removeFilter(filtered[i]);
1604 });
1605 addEventHandler(window, "onafterprint", function() {
1606 for (var i = 0; i < filtered.length; i++) addFilter(filtered[i]);
1607 printing = false;
1608 });
1609 }
1610
1611 // apply a filter
1612 function addFilter(element, sizingMethod, src) {
1613 var filter = element.filters[ALPHA_IMAGE_LOADER];
1614 if (filter) {
1615 filter.src = src || element.src;
1616 filter.enabled = true;
1617 } else {
1618 element.runtimeStyle.filter = format(PNG_FILTER, src || element.src, sizingMethod || "scale");
1619 filtered.push(element);
1620 }
1621 // remove the real image
1622 element.src = BLANK_GIF;
1623 };
1624
1625 function removeFilter(element) {
1626 element.src = element.pngSrc;
1627 element.filters[ALPHA_IMAGE_LOADER].enabled = false;
1628 };
1629
1630 // =========================================================================
1631 // ie7-fixed.js
1632 // =========================================================================
1633
1634 (function() {
1635 if (appVersion >= 7) return;
1636
1637 // some things to consider for this hack.
1638 // the document body requires a fixed background. even if
1639 // it is just a blank image.
1640 // you have to use setExpression instead of onscroll, this
1641 // together with a fixed body background helps avoid the
1642 // annoying screen flicker of other solutions.
1643
1644 IE7.CSS.addRecalc("position", "fixed", _positionFixed, "absolute");
1645 IE7.CSS.addRecalc("background(-attachment)?", "[^};]*fixed", _backgroundFixed);
1646
1647 // scrolling is relative to the documentElement (HTML tag) when in
1648 // standards mode, otherwise it's relative to the document body
1649 var $viewport = MSIE5 ? "body" : "documentElement";
1650
1651 function _fixBackground() {
1652 // this is required by both position:fixed and background-attachment:fixed.
1653 // it is necessary for the document to also have a fixed background image.
1654 // we can fake this with a blank image if necessary
1655 if (body.currentStyle.backgroundAttachment !== "fixed") {
1656 if (body.currentStyle.backgroundImage === "none") {
1657 body.runtimeStyle.backgroundRepeat = "no-repeat";
1658 body.runtimeStyle.backgroundImage = "url(" + BLANK_GIF + ")"; // dummy
1659 }
1660 body.runtimeStyle.backgroundAttachment = "fixed";
1661 }
1662 _fixBackground = Undefined;
1663 };
1664
1665 var _tmp = createTempElement("img");
1666
1667 function _isFixed(element) {
1668 return element ? isFixed(element) || _isFixed(element.parentElement) : false;
1669 };
1670
1671 function _setExpression(element, propertyName, expression) {
1672 setTimeout("document.all." + element.uniqueID + ".runtimeStyle.setExpression('" + propertyName + "','" + expression + "')", 0);
1673 };
1674
1675 // -----------------------------------------------------------------------
1676 // backgroundAttachment: fixed
1677 // -----------------------------------------------------------------------
1678
1679 function _backgroundFixed(element) {
1680 if (register(_backgroundFixed, element, element.currentStyle.backgroundAttachment === "fixed" && !element.contains(body))) {
1681 _fixBackground();
1682 util.bgLeft(element);
1683 util.bgTop(element);
1684 _backgroundPosition(element);
1685 }
1686 };
1687
1688 function _backgroundPosition(element) {
1689 _tmp.src = element.currentStyle.backgroundImage.slice(5, -2);
1690 var parentElement = element.canHaveChildren ? element : element.parentElement;
1691 parentElement.appendChild(_tmp);
1692 util.setOffsetLeft(element);
1693 util.setOffsetTop(element);
1694 parentElement.removeChild(_tmp);
1695 };
1696
1697 // -----------------------------------------------------------------------
1698 // position: fixed
1699 // -----------------------------------------------------------------------
1700
1701 function _positionFixed(element) {
1702 if (register(_positionFixed, element, isFixed(element))) {
1703 setOverrideStyle(element, "position", "absolute");
1704 setOverrideStyle(element, "left", element.currentStyle.left);
1705 setOverrideStyle(element, "top", element.currentStyle.top);
1706 _fixBackground();
1707 IE7.Layout.fixRight(element);
1708 //IE7.Layout.fixBottom(element);
1709 _foregroundPosition(element);
1710 }
1711 };
1712
1713 function _foregroundPosition(element, recalc) {
1714 document.body.getBoundingClientRect(); // force a reflow
1715 util.positionTop(element, recalc);
1716 util.positionLeft(element, recalc, true);
1717 if (!element.runtimeStyle.autoLeft && element.currentStyle.marginLeft === "auto" &&
1718 element.currentStyle.right !== "auto") {
1719 var left = viewport.clientWidth - util.getPixelWidth(element, element.currentStyle.right) -
1720 util.getPixelWidth(element, element.runtimeStyle._left) - element.clientWidth;
1721 if (element.currentStyle.marginRight === "auto") left = parseInt(left / 2);
1722 if (_isFixed(element.offsetParent)) element.runtimeStyle.pixelLeft += left;
1723 else element.runtimeStyle.shiftLeft = left;
1724 }
1725 if (!element.runtimeStyle.fixedWidth) util.clipWidth(element);
1726 if (!element.runtimeStyle.fixedHeight) util.clipHeight(element);
1727 };
1728
1729 // -----------------------------------------------------------------------
1730 // capture window resize
1731 // -----------------------------------------------------------------------
1732
1733 function _resize() {
1734 // if the window has been resized then some positions need to be
1735 // recalculated (especially those aligned to "right" or "top"
1736 var elements = _backgroundFixed.elements;
1737 for (var i in elements) _backgroundPosition(elements[i]);
1738 elements = _positionFixed.elements;
1739 for (i in elements) {
1740 _foregroundPosition(elements[i], true);
1741 _foregroundPosition(elements[i], true);
1742 }
1743 _timer = 0;
1744 };
1745
1746 // use a timer (sometimes this is a good way to prevent resize loops)
1747 var _timer;
1748 addResize(function() {
1749 if (!_timer) _timer = setTimeout(_resize, 100);
1750 });
1751
1752 // -----------------------------------------------------------------------
1753 // rotated
1754 // -----------------------------------------------------------------------
1755
1756 var util = {};
1757
1758 var _horizontal = function(util) {
1759 util.bgLeft = function(element) {
1760 element.style.backgroundPositionX = element.currentStyle.backgroundPositionX;
1761 if (!_isFixed(element)) {
1762 _setExpression(element, "backgroundPositionX", "(parseInt(runtimeStyle.offsetLeft)+document." + $viewport + ".scrollLeft)||0");
1763 }
1764 };
1765
1766 util.setOffsetLeft = function(element) {
1767 var propertyName = _isFixed(element) ? "backgroundPositionX" : "offsetLeft";
1768 element.runtimeStyle[propertyName] =
1769 util.getOffsetLeft(element, element.style.backgroundPositionX) -
1770 element.getBoundingClientRect().left - element.clientLeft + 2;
1771 };
1772
1773 util.getOffsetLeft = function(element, position) {
1774 switch (position) {
1775 case "left":
1776 case "top":
1777 return 0;
1778 case "right":
1779 case "bottom":
1780 return viewport.clientWidth - _tmp.offsetWidth;
1781 case "center":
1782 return (viewport.clientWidth - _tmp.offsetWidth) / 2;
1783 default:
1784 if (PERCENT.test(position)) {
1785 return parseInt((viewport.clientWidth - _tmp.offsetWidth) * parseFloat(position) / 100);
1786 }
1787 _tmp.style.left = position;
1788 return _tmp.offsetLeft;
1789 }
1790 };
1791
1792 util.clipWidth = function(element) {
1793 var fixWidth = element.runtimeStyle.fixWidth;
1794 element.runtimeStyle.borderRightWidth = "";
1795 element.runtimeStyle.width = fixWidth ? util.getPixelWidth(element, fixWidth) + "px" : "";
1796 if (element.currentStyle.width !== "auto") {
1797 var rect = element.getBoundingClientRect();
1798 var width = element.offsetWidth - viewport.clientWidth + rect.left - 2;
1799 if (width >= 0) {
1800 element.runtimeStyle.borderRightWidth = "0px";
1801 width = Math.max(getPixelValue(element, element.currentStyle.width) - width, 0);
1802 setOverrideStyle(element, "width", width);
1803 return width;
1804 }
1805 }
1806 };
1807
1808 util.positionLeft = function(element, recalc) {
1809 // if the element's width is in % units then it must be recalculated
1810 // with respect to the viewport
1811 if (!recalc && PERCENT.test(element.currentStyle.width)) {
1812 element.runtimeStyle.fixWidth = element.currentStyle.width;
1813 }
1814 if (element.runtimeStyle.fixWidth) {
1815 element.runtimeStyle.width = util.getPixelWidth(element, element.runtimeStyle.fixWidth);
1816 }
1817 //if (recalc) {
1818 // // if the element is fixed on the right then no need to recalculate
1819 // if (!element.runtimeStyle.autoLeft) return;
1820 //} else {
1821 element.runtimeStyle.shiftLeft = 0;
1822 element.runtimeStyle._left = element.currentStyle.left;
1823 // is the element fixed on the right?
1824 element.runtimeStyle.autoLeft = element.currentStyle.right !== "auto" && element.currentStyle.left === "auto";
1825 //}
1826 // reset the element's "left" value and get it's natural position
1827 element.runtimeStyle.left = "";
1828 element.runtimeStyle.screenLeft = util.getScreenLeft(element);
1829 element.runtimeStyle.pixelLeft = element.runtimeStyle.screenLeft;
1830 // if the element is contained by another fixed element then there is no need to
1831 // continually recalculate it's left position
1832 if (!recalc && !_isFixed(element.offsetParent)) {
1833 // onsrcoll produces jerky movement, so we use an expression
1834 _setExpression(element, "pixelLeft", "runtimeStyle.screenLeft+runtimeStyle.shiftLeft+document." + $viewport + ".scrollLeft");
1835 }
1836 };
1837
1838 // I've forgotten how this works...
1839 util.getScreenLeft = function(element) { // thanks to kevin newman (captainn)
1840 var screenLeft = element.offsetLeft, nested = 1;
1841 if (element.runtimeStyle.autoLeft) {
1842 screenLeft = viewport.clientWidth - element.offsetWidth - util.getPixelWidth(element, element.currentStyle.right);
1843 }
1844 // accommodate margins
1845 if (element.currentStyle.marginLeft !== "auto") {
1846 screenLeft -= util.getPixelWidth(element, element.currentStyle.marginLeft);
1847 }
1848 while (element = element.offsetParent) {
1849 if (element.currentStyle.position !== "static") nested = -1;
1850 screenLeft += element.offsetLeft * nested;
1851 }
1852 return screenLeft;
1853 };
1854
1855 util.getPixelWidth = function(element, value) {
1856 return PERCENT.test(value) ? parseInt(parseFloat(value) / 100 * viewport.clientWidth) : getPixelValue(element, value);
1857 };
1858 };
1859 eval("var _vertical=" + rotate(_horizontal));
1860 _horizontal(util);
1861 _vertical(util);
1862 })();
1863
1864 // =========================================================================
1865 // ie7-oveflow.js
1866 // =========================================================================
1867
1868 /* ---------------------------------------------------------------------
1869
1870 This module alters the structure of the document.
1871 It may adversely affect other CSS rules. Be warned.
1872
1873 --------------------------------------------------------------------- */
1874
1875 if (appVersion < 7) {
1876 var WRAPPER_STYLE = {
1877 backgroundColor: "transparent",
1878 backgroundImage: "none",
1879 backgroundPositionX: null,
1880 backgroundPositionY: null,
1881 backgroundRepeat: null,
1882 borderTopWidth: 0,
1883 borderRightWidth: 0,
1884 borderBottomWidth: 0,
1885 borderLeftStyle: "none",
1886 borderTopStyle: "none",
1887 borderRightStyle: "none",
1888 borderBottomStyle: "none",
1889 borderLeftWidth: 0,
1890 borderLeftColor: "#000",
1891 borderTopColor: "#000",
1892 borderRightColor: "#000",
1893 borderBottomColor: "#000",
1894 height: null,
1895 marginTop: 0,
1896 marginBottom: 0,
1897 marginRight: 0,
1898 marginLeft: 0,
1899 width: "100%"
1900 };
1901
1902 IE7.CSS.addRecalc("overflow", "visible", function(element) {
1903 if (element.currentStyle.position === "absolute") return;
1904
1905 // don't do this again
1906 if (element.parentNode.ie7_wrapped) return;
1907
1908 // if max-height is applied, makes sure it gets applied first
1909 if (IE7.Layout && element.currentStyle["max-height"] !== "auto") {
1910 IE7.Layout.maxHeight(element);
1911 }
1912
1913 if (element.currentStyle.marginLeft === "auto") element.style.marginLeft = 0;
1914 if (element.currentStyle.marginRight === "auto") element.style.marginRight = 0;
1915
1916 var wrapper = document.createElement(ANON);
1917 wrapper.ie7_wrapped = element;
1918 for (var propertyName in WRAPPER_STYLE) {
1919 wrapper.style[propertyName] = element.currentStyle[propertyName];
1920 if (WRAPPER_STYLE[propertyName] != null) {
1921 element.runtimeStyle[propertyName] = WRAPPER_STYLE[propertyName];
1922 }
1923 }
1924 wrapper.style.display = "block";
1925 wrapper.style.position = "relative";
1926 element.runtimeStyle.position = "absolute";
1927 element.parentNode.insertBefore(wrapper, element);
1928 wrapper.appendChild(element);
1929 });
1930 }
1931
1932 // =========================================================================
1933 // ie7-quirks.js
1934 // =========================================================================
1935
1936 function ie7Quirks() {
1937 var FONT_SIZES = "xx-small,x-small,small,medium,large,x-large,xx-large".split(",");
1938 for (var i = 0; i < FONT_SIZES.length; i++) {
1939 FONT_SIZES[FONT_SIZES[i]] = FONT_SIZES[i - 1] || "0.67em";
1940 }
1941
1942 IE7.CSS.addFix(/(font(-size)?\s*:\s*)([\w.-]+)/, function(match, label, size, value) {
1943 return label + (FONT_SIZES[value] || value);
1944 });
1945
1946 var NEGATIVE = /^\-/, LENGTH = /(em|ex)$/i;
1947 var EM = /em$/i, EX = /ex$/i;
1948
1949 getPixelValue = function(element, value) {
1950 if (PIXEL.test(value)) return parseInt(value)||0;
1951 var scale = NEGATIVE.test(value)? -1 : 1;
1952 if (LENGTH.test(value)) scale *= getFontScale(element);
1953 temp.style.width = scale < 0 ? value.slice(1) : value;
1954 body.appendChild(temp);
1955 // retrieve pixel width
1956 value = scale * temp.offsetWidth;
1957 // remove the temporary element
1958 temp.removeNode();
1959 return parseInt(value);
1960 };
1961
1962 var temp = createTempElement();
1963 function getFontScale(element) {
1964 var scale = 1;
1965 temp.style.fontFamily = element.currentStyle.fontFamily;
1966 temp.style.lineHeight = element.currentStyle.lineHeight;
1967 //temp.style.fontSize = "";
1968 while (element != body) {
1969 var fontSize = element.currentStyle["ie7-font-size"];
1970 if (fontSize) {
1971 if (EM.test(fontSize)) scale *= parseFloat(fontSize);
1972 else if (PERCENT.test(fontSize)) scale *= (parseFloat(fontSize) / 100);
1973 else if (EX.test(fontSize)) scale *= (parseFloat(fontSize) / 2);
1974 else {
1975 temp.style.fontSize = fontSize;
1976 return 1;
1977 }
1978 }
1979 element = element.parentElement;
1980 }
1981 return scale;
1982 };
1983
1984 // cursor:pointer (IE5.x)
1985 IE7.CSS.addFix(/cursor\s*:\s*pointer/, "cursor:hand");
1986 // display:list-item (IE5.x)
1987 IE7.CSS.addFix(/display\s*:\s*list-item/, "display:block");
1988
1989 // -----------------------------------------------------------------------
1990 // margin:auto
1991 // -----------------------------------------------------------------------
1992
1993 function fixMargin(element) {
1994 var parent = element.parentElement;
1995 var margin = parent.offsetWidth - element.offsetWidth - getPaddingWidth(parent);
1996 var autoRight = (element.currentStyle["ie7-margin"] && element.currentStyle.marginRight === "auto") ||
1997 element.currentStyle["ie7-margin-right"] === "auto";
1998 switch (parent.currentStyle.textAlign) {
1999 case "right":
2000 margin = autoRight ? parseInt(margin / 2) : 0;
2001 element.runtimeStyle.marginRight = margin + "px";
2002 break;
2003 case "center":
2004 if (autoRight) margin = 0;
2005 default:
2006 if (autoRight) margin /= 2;
2007 element.runtimeStyle.marginLeft = parseInt(margin) + "px";
2008 }
2009 };
2010
2011 function getPaddingWidth(element) {
2012 return getPixelValue(element, element.currentStyle.paddingLeft) +
2013 getPixelValue(element, element.currentStyle.paddingRight);
2014 };
2015
2016 IE7.CSS.addRecalc("margin(-left|-right)?", "[^};]*auto", function(element) {
2017 if (register(fixMargin, element,
2018 element.parentElement &&
2019 element.currentStyle.display === "block" &&
2020 element.currentStyle.marginLeft === "auto" &&
2021 element.currentStyle.position !== "absolute")) {
2022 fixMargin(element);
2023 }
2024 });
2025
2026 addResize(function() {
2027 for (var i in fixMargin.elements) {
2028 var element = fixMargin.elements[i];
2029 element.runtimeStyle.marginLeft =
2030 element.runtimeStyle.marginRight = "";
2031 fixMargin(element);
2032 }
2033 });
2034 };
2035
2036
2037 // =========================================================================
2038 // ie8-css.js
2039 // =========================================================================
2040
2041 var BRACKETS = "\\([^)]+\\)";
2042
2043 // pseudo-elements can be declared with a double colon
2044 encoder.add(/::(before|after)/, ":$1");
2045
2046 if (appVersion < 8) {
2047
2048 if (IE7.CSS.pseudoClasses) IE7.CSS.pseudoClasses += "|";
2049 IE7.CSS.pseudoClasses += "before|after|lang" + BRACKETS;
2050
2051 // -----------------------------------------------------------------------
2052 // propertyName: inherit;
2053 // -----------------------------------------------------------------------
2054
2055 function parseInherited(cssText) {
2056 return cssText.replace(new RegExp("([{;\\s])(" + inheritedProperties.join("|") + ")\\s*:\\s*([^;}]+)", "g"), "$1$2:$3;ie7-$2:$3");
2057 };
2058
2059 var INHERITED = /[\w-]+\s*:\s*inherit/g;
2060 var STRIP_IE7_FLAGS = /ie7\-|\s*:\s*inherit/g;
2061 var DASH_LOWER = /\-([a-z])/g;
2062 function toUpper(match, chr) {return chr.toUpperCase()};
2063
2064 IE7.CSS.addRecalc("[\\w-]+", "inherit", function(element, cssText) {
2065 if (element.parentElement) {
2066 var inherited = cssText.match(INHERITED);
2067 for (var i = 0; i < inherited.length; i++) {
2068 var propertyName = inherited[i].replace(STRIP_IE7_FLAGS, "");
2069 if (element.currentStyle["ie7-" + propertyName] === "inherit") {
2070 propertyName = propertyName.replace(DASH_LOWER, toUpper);
2071 element.runtimeStyle[propertyName] = element.parentElement.currentStyle[propertyName];
2072 }
2073 }
2074 }
2075 }, function(match) {
2076 inheritedProperties.push(rescape(match.slice(1).split(":")[0]));
2077 return match;
2078 });
2079
2080 // -----------------------------------------------------------------------
2081 // dynamic pseudo-classes
2082 // -----------------------------------------------------------------------
2083
2084 var Focus = new DynamicPseudoClass("focus", function(element) {
2085 var instance = arguments;
2086
2087 IE7.CSS.addEventHandler(element, "onfocus", function() {
2088 Focus.unregister(instance); // in case it starts with focus
2089 Focus.register(instance);
2090 });
2091
2092 IE7.CSS.addEventHandler(element, "onblur", function() {
2093 Focus.unregister(instance);
2094 });
2095
2096 // check the active element for initial state
2097 if (element == document.activeElement) {
2098 Focus.register(instance)
2099 }
2100 });
2101
2102 var Active = new DynamicPseudoClass("active", function(element) {
2103 var instance = arguments;
2104 IE7.CSS.addEventHandler(element, "onmousedown", function() {
2105 Active.register(instance);
2106 });
2107 });
2108
2109 // globally trap the mouseup event (thanks Martijn!)
2110 addEventHandler(document, "onmouseup", function() {
2111 var instances = Active.instances;
2112 for (var i in instances) Active.unregister(instances[i]);
2113 });
2114
2115 // -----------------------------------------------------------------------
2116 // IE7 pseudo elements
2117 // -----------------------------------------------------------------------
2118
2119 // constants
2120 var URL = /^url\s*\(\s*([^)]*)\)$/;
2121 var POSITION_MAP = {
2122 before0: "beforeBegin",
2123 before1: "afterBegin",
2124 after0: "afterEnd",
2125 after1: "beforeEnd"
2126 };
2127
2128 var PseudoElement = IE7.PseudoElement = Rule.extend({
2129 constructor: function(selector, position, cssText) {
2130 // initialise object properties
2131 this.position = position;
2132 var content = cssText.match(PseudoElement.CONTENT), match, entity;
2133 if (content) {
2134 content = content[1];
2135 match = content.split(/\s+/);
2136 for (var i = 0; (entity = match[i]); i++) {
2137 match[i] = /^attr/.test(entity) ? {attr: entity.slice(5, -1)} :
2138 entity.charAt(0) === "'" ? getString(entity) : decode(entity);
2139 }
2140 content = match;
2141 }
2142 this.content = content;
2143 // CSS text needs to be decoded immediately
2144 this.base(selector, decode(cssText));
2145 },
2146
2147 init: function() {
2148 // execute the underlying css query for this class
2149 this.match = cssQuery(this.selector);
2150 for (var i = 0; i < this.match.length; i++) {
2151 var runtimeStyle = this.match[i].runtimeStyle;
2152 if (!runtimeStyle[this.position]) runtimeStyle[this.position] = {cssText:""};
2153 runtimeStyle[this.position].cssText += ";" + this.cssText;
2154 if (this.content != null) runtimeStyle[this.position].content = this.content;
2155 }
2156 },
2157
2158 create: function(target) {
2159 var generated = target.runtimeStyle[this.position];
2160 if (generated) {
2161 // copy the array of values
2162 var content = [].concat(generated.content || "");
2163 for (var j = 0; j < content.length; j++) {
2164 if (typeof content[j] == "object") {
2165 content[j] = target.getAttribute(content[j].attr);
2166 }
2167 }
2168 content = content.join("");
2169 var url = content.match(URL);
2170 var cssText = "overflow:hidden;" + generated.cssText.replace(/'/g, '"');
2171 var position = POSITION_MAP[this.position + Number(target.canHaveChildren)];
2172 var id = 'ie7_pseudo' + PseudoElement.count++;
2173 target.insertAdjacentHTML(position, format(PseudoElement.ANON, this.className, id, cssText, url ? "" : content));
2174 if (url) {
2175 var src = getString(url[1]);
2176 var pseudoElement = document.getElementById(id);
2177 pseudoElement.src = src;
2178 addFilter(pseudoElement, "crop");
2179 var targetIsFloated = target.currentStyle.styleFloat !== "none";
2180 if (pseudoElement.currentStyle.display === "inline" || targetIsFloated) {
2181 if (appVersion < 7 && targetIsFloated && target.canHaveChildren) {
2182 target.runtimeStyle.display = "inline";
2183 target.runtimeStyle.position = "relative";
2184 pseudoElement.runtimeStyle.position = "absolute";
2185 }
2186 pseudoElement.style.display = "inline-block";
2187 if (target.currentStyle.styleFloat !== "none") {
2188 pseudoElement.style.pixelWidth = target.offsetWidth;
2189 }
2190 var image = new Image;
2191 image.onload = function() {
2192 pseudoElement.style.pixelWidth = this.width;
2193 pseudoElement.style.pixelHeight = Math.max(this.height, pseudoElement.offsetHeight);
2194 };
2195 image.src = src;
2196 }
2197 }
2198 target.runtimeStyle[this.position] = null;
2199 }
2200 },
2201
2202 recalc: function() {
2203 if (this.content == null) return;
2204 for (var i = 0; i < this.match.length; i++) {
2205 this.create(this.match[i]);
2206 }
2207 },
2208
2209 toString: function() {
2210 return "." + this.className + "{display:inline}";
2211 }
2212 }, {
2213 CONTENT: /content\s*:\s*([^;]*)(;|$)/,
2214 ANON: "<ie7:! class='ie7_anon %1' id=%2 style='%3'>%4</ie7:!>",
2215 MATCH: /(.*):(before|after).*/,
2216
2217 count: 0
2218 });
2219
2220 IE7._getLang = function(element) {
2221 var lang = "";
2222 while (element && element.nodeType === 1) {
2223 lang = element.lang || element.getAttribute("lang") || "";
2224 if (lang) break;
2225 element = element.parentNode;
2226 }
2227 return lang;
2228 };
2229
2230 FILTER = extend(FILTER, {
2231 ":lang\\(([^)]+)\\)": "((ii=IE7._getLang(e))==='$1'||ii.indexOf('$1-')===0)&&"
2232 });
2233 }
2234
2235 // =========================================================================
2236 // ie8-html.js
2237 // =========================================================================
2238
2239 var UNSUCCESSFUL = /^(submit|reset|button)$/;
2240
2241 // -----------------------------------------------------------------------
2242 // <button>
2243 // -----------------------------------------------------------------------
2244
2245 // IE bug means that innerText is submitted instead of "value"
2246 IE7.HTML.addRecalc("button,input", function(button) {
2247 if (button.nodeName === "BUTTON") {
2248 var match = button.outerHTML.match(/ value="([^"]*)"/i);
2249 button.runtimeStyle.value = match ? match[1] : "";
2250 }
2251 // flag the button/input that was used to submit the form
2252 if (button.type === "submit") {
2253 addEventHandler(button, "onclick", function() {
2254 button.runtimeStyle.clicked = true;
2255 setTimeout("document.all." + button.uniqueID + ".runtimeStyle.clicked=false", 1);
2256 });
2257 }
2258 });
2259
2260 // -----------------------------------------------------------------------
2261 // <form>
2262 // -----------------------------------------------------------------------
2263
2264 // only submit "successful controls
2265 IE7.HTML.addRecalc("form", function(form) {
2266 addEventHandler(form, "onsubmit", function() {
2267 for (var element, i = 0; element = form[i]; i++) {
2268 if (UNSUCCESSFUL.test(element.type) && !element.disabled && !element.runtimeStyle.clicked) {
2269 element.disabled = true;
2270 setTimeout("document.all." + element.uniqueID + ".disabled=false", 1);
2271 } else if (element.nodeName === "BUTTON" && element.type === "submit") {
2272 setTimeout("document.all." + element.uniqueID + ".value='" + element.value + "'", 1);
2273 element.value = element.runtimeStyle.value;
2274 }
2275 }
2276 });
2277 });
2278
2279 // -----------------------------------------------------------------------
2280 // <img>
2281 // -----------------------------------------------------------------------
2282
2283 // get rid of the spurious tooltip produced by the alt attribute on images
2284 IE7.HTML.addRecalc("img", function(img) {
2285 if (img.alt && !img.title) img.title = "";
2286 });
2287
2288 // =========================================================================
2289 // ie8-layout.js
2290 // =========================================================================
2291
2292 if (appVersion < 8) {
2293 IE7.CSS.addRecalc("border-spacing", NUMERIC, function(element) {
2294 if (element.currentStyle.borderCollapse !== "collapse") {
2295 element.cellSpacing = getPixelValue(element, element.currentStyle["ie7-border-spacing"].split(" ")[0]);
2296 }
2297 });
2298 IE7.CSS.addRecalc("box-sizing", "content-box", IE7.Layout.boxSizing);
2299 IE7.CSS.addRecalc("box-sizing", "border-box", IE7.Layout.borderBox);
2300 }
2301
2302 // =========================================================================
2303 // ie8-graphics.js
2304 // =========================================================================
2305
2306 if (appVersion < 8) {
2307 // fix object[type=image/*]
2308 var IMAGE = /^image/i;
2309 IE7.HTML.addRecalc("object", function(element) {
2310 if (IMAGE.test(element.type)) {
2311 element.body.style.cssText = "margin:0;padding:0;border:none;overflow:hidden";
2312 return element;
2313 }
2314 });
2315 }
2316
2317 // =========================================================================
2318 // ie9-css.js
2319 // =========================================================================
2320
2321 var NOT_NEXT_BY_TYPE = "!IE7._getElementSiblingByType(e,'next')&&",
2322 NOT_PREVIOUS_BY_TYPE = NOT_NEXT_BY_TYPE.replace("next", "previous");
2323
2324 if (IE7.CSS.pseudoClasses) IE7.CSS.pseudoClasses += "|";
2325 IE7.CSS.pseudoClasses += "(?:first|last|only)\\-(?:child|of\\-type)|empty|root|target|" +
2326 ("not|nth\\-child|nth\\-last\\-child|nth\\-of\\-type|nth\\-last\\-of\\-type".split("|").join(BRACKETS + "|") + BRACKETS);
2327
2328 // :checked
2329 var Checked = new DynamicPseudoClass("checked", function(element) {
2330 if (typeof element.checked !== "boolean") return;
2331 var instance = arguments;
2332 IE7.CSS.addEventHandler(element, "onpropertychange", function() {
2333 if (event.propertyName === "checked") {
2334 if (element.checked === true) Checked.register(instance);
2335 else Checked.unregister(instance);
2336 }
2337 });
2338 // check current checked state
2339 if (element.checked === true) Checked.register(instance);
2340 });
2341
2342 // :enabled
2343 var Enabled = new DynamicPseudoClass("enabled", function(element) {
2344 if (typeof element.disabled !== "boolean") return;
2345 var instance = arguments;
2346 IE7.CSS.addEventHandler(element, "onpropertychange", function() {
2347 if (event.propertyName === "disabled") {
2348 if (element.disabled === false) Enabled.register(instance);
2349 else Enabled.unregister(instance);
2350 }
2351 });
2352 // check current disabled state
2353 if (element.disabled === false) Enabled.register(instance);
2354 });
2355
2356 // :disabled
2357 var Disabled = new DynamicPseudoClass("disabled", function(element) {
2358 if (typeof element.disabled !== "boolean") return;
2359 var instance = arguments;
2360 IE7.CSS.addEventHandler(element, "onpropertychange", function() {
2361 if (event.propertyName === "disabled") {
2362 if (element.disabled === true) Disabled.register(instance);
2363 else Disabled.unregister(instance);
2364 }
2365 });
2366 // check current disabled state
2367 if (element.disabled === true) Disabled.register(instance);
2368 });
2369
2370 // :indeterminate (Kevin Newman)
2371 var Indeterminate = new DynamicPseudoClass("indeterminate", function(element) {
2372 if (typeof element.indeterminate !== "boolean") return;
2373 var instance = arguments;
2374 IE7.CSS.addEventHandler(element, "onpropertychange", function() {
2375 if (event.propertyName === "indeterminate") {
2376 if (element.indeterminate === true) Indeterminate.register(instance);
2377 else Indeterminate.unregister(instance);
2378 }
2379 });
2380 IE7.CSS.addEventHandler(element, "onclick", function() {
2381 Indeterminate.unregister(instance);
2382 });
2383 // clever Kev says no need to check this up front
2384 });
2385
2386 // :target
2387 var Target = new DynamicPseudoClass("target", function(element) {
2388 var instance = arguments;
2389 // if an element has a tabIndex then it can become "active".
2390 // The default is zero anyway but it works...
2391 if (!element.tabIndex) element.tabIndex = 0;
2392 // this doesn't detect the back button. I don't know how to do that without adding an iframe :-(
2393 IE7.CSS.addEventHandler(document, "onpropertychange", function() {
2394 if (event.propertyName === "activeElement") {
2395 if (element.id && element.id === location.hash.slice(1)) Target.register(instance);
2396 else Target.unregister(instance);
2397 }
2398 });
2399 // check the current location
2400 if (element.id && element.id === location.hash.slice(1)) Target.register(instance);
2401 });
2402
2403 // Register a node and index its siblings.
2404 var _currentIndex = 1, // -@DRE
2405 allIndexes = {_currentIndex: 1};
2406
2407 IE7._indexOf = function(element, last, ofType) {
2408 var parent = element.parentNode;
2409 if (!parent || parent.nodeType !== 1) return NaN;
2410
2411 var tagName = ofType ? element.nodeName : "";
2412 if (tagName === "TR" && element.sectionRowIndex >= 0) {
2413 var index = element.sectionRowIndex;
2414 return last ? element.parentNode.rows.length - index + 1 : index;
2415 }
2416 if ((tagName === "TD" || tagName === "TH") && element.cellIndex >= 0) {
2417 index = element.cellIndex;
2418 return last ? element.parentNode.cells.length - index + 1 : index;
2419 }
2420 if (allIndexes._currentIndex !== _currentIndex) {
2421 allIndexes = {_currentIndex: _currentIndex};
2422 }
2423 var id = (parent.uniqueID) + "-" + tagName,
2424 indexes = allIndexes[id];
2425 if (!indexes) {
2426 indexes = {};
2427 var index = 0,
2428 child = parent.firstChild;
2429 while (child) {
2430 if (ofType ? child.nodeName === tagName : child.nodeName > "@") {
2431 indexes[child.uniqueID] = ++index;
2432 }
2433 child = child.nextSibling;
2434 }
2435 indexes.length = index;
2436 allIndexes[id] = indexes;
2437 }
2438 index = indexes[element.uniqueID];
2439 return last ? indexes.length - index + 1 : index;
2440 };
2441
2442 IE7._isEmpty = function(node) {
2443 node = node.firstChild;
2444 while (node) {
2445 if (node.nodeType === 3 || node.nodeName > "@") return false;
2446 node = node.nextSibling;
2447 }
2448 return true;
2449 };
2450
2451 IE7._getElementSiblingByType = function(node, direction) {
2452 var tagName = node.nodeName;
2453 direction += "Sibling";
2454 do {
2455 node = node[direction];
2456 if (node && node.nodeName === tagName) break;
2457 } while (node);
2458 return node;
2459 };
2460
2461 var ONE = {"+": 1, "-": -1}, SPACES = / /g;
2462
2463 FILTER = extend(extend({
2464 ":nth(-last)?-(?:child|(of-type))\\((<#nth_arg>)\\)(<#filter>)?": function(match, last, ofType, args, filters) { // :nth- pseudo classes
2465 args = args.replace(SPACES, "");
2466
2467 var index = "IE7._indexOf(e," + !!last + "," + !!ofType + ")";
2468
2469 if (args === "even") args = "2n";
2470 else if (args === "odd") args = "2n+1";
2471 else if (!isNaN(args)) args = "0n" + ~~args;
2472
2473 args = args.split("n");
2474 var a = ~~(ONE[args[0]] || args[0] || 1),
2475 b = ~~args[1];
2476 if (a === 0) {
2477 var expr = index + "===" + b;
2478 } else {
2479 expr = "((ii=" + index + ")-(" + b + "))%" + a + "===0&&ii" + (a < 0 ? "<" : ">") + "=" + b;
2480 }
2481 return this.parse(filters) + expr + "&&";
2482 },
2483
2484 "<#negation>": function(match, simple) {
2485 if (/:not/i.test(simple)) throwSelectorError();
2486
2487 if (/^[#.:\[]/.test(simple)) {
2488 simple = "*" + simple;
2489 }
2490 return "!(" + MATCHER.parse(simple).slice(3, -2) + ")&&";
2491 }
2492 }, FILTER), {
2493 ":checked": "e.checked===true&&",
2494 ":disabled": "e.disabled===true&&",
2495 ":enabled": "e.disabled===false&&",
2496 ":last-child": "!" + NEXT_SIBLING + "&&",
2497 ":only-child": "!" + PREVIOUS_SIBLING + "&&!" + NEXT_SIBLING + "&&",
2498 ":first-of-type": NOT_PREVIOUS_BY_TYPE,
2499 ":last-of-type": NOT_NEXT_BY_TYPE,
2500 ":only-of-type": NOT_PREVIOUS_BY_TYPE + NOT_NEXT_BY_TYPE,
2501
2502 ":empty": "IE7._isEmpty(e)&&",
2503 ":root": "e==R&&",
2504 ":target": "H&&" + ID_ATTRIBUTE + "===H&&"
2505 });
2506
2507 // =========================================================================
2508 // ie9-layout.js
2509 // =========================================================================
2510
2511 // =========================================================================
2512 // ie9-graphics.js
2513 // =========================================================================
2514
2515 if (appVersion === 8) {
2516 IE7.CSS.addFix(/\bopacity\s*:/, "-ms-opacity:");
2517 } else {
2518 IE7.CSS.addFix(/\bopacity\s*:\s*([\d.]+)/, function(match, value) {
2519 return "zoom:1;filter:Alpha(opacity=" + ((value * 100) || 1) + ")";
2520 });
2521 }
2522
2523 var MATCHER;
2524
2525 var cssQuery = (function() {
2526 var CONTEXT = /^[>+~]/;
2527
2528 var useContext = false;
2529
2530 // This is not a selector engine in the strictest sense. So it's best to silently error.
2531 function cssQuery(selector, context, single) {
2532 selector = trim(selector);
2533 if (!context) context = document;
2534 var ref = context;
2535 useContext = CONTEXT.test(selector);
2536 if (useContext) {
2537 context = context.parentNode;
2538 selector = "*" + selector;
2539 }
2540 try {
2541 return selectQuery.create(selector, useContext)(context, single ? null : [], ref);
2542 } catch (ex) {
2543 return single ? null : [];
2544 }
2545 };
2546
2547 var VALID_SELECTOR = /^(\\.|[' >+~#.\[\]:*(),\w-\^|$=]|[^\x00-\xa0])+$/;
2548
2549 var _EVALUATED = /^(href|src)$/;
2550 var _ATTRIBUTES = {
2551 "class": "className",
2552 "for": "htmlFor"
2553 };
2554
2555 var IE7_CLASS_NAMES = /\sie7_\w+/g;
2556
2557 var USE_IFLAG = /^(action|cite|codebase|data|dynsrc|href|longdesc|lowsrc|src|usemap|url)$/i;
2558
2559 IE7._getAttribute = function(element, name) {
2560 if (element.getAttributeNode) {
2561 var attribute = element.getAttributeNode(name);
2562 }
2563 name = _ATTRIBUTES[name.toLowerCase()] || name;
2564 if (!attribute) attribute = element.attributes[name];
2565 var specified = attribute && attribute.specified;
2566
2567 if (element[name] && typeof element[name] == "boolean") return name.toLowerCase();
2568 if ((specified && USE_IFLAG.test(name)) || (!attribute && MSIE5) || name === "value" || name === "type") {
2569 return element.getAttribute(name, 2);
2570 }
2571 if (name === "style") return element.style.cssText.toLowerCase() || null;
2572
2573 return specified ? String(attribute.nodeValue) : null;
2574 };
2575
2576 var names = "colSpan,rowSpan,vAlign,dateTime,accessKey,tabIndex,encType,maxLength,readOnly,longDesc";
2577 // Convert the list of strings to a hash, mapping the lowercase name to the camelCase name.
2578 extend(_ATTRIBUTES, combine(names.toLowerCase().split(","), names.split(",")));
2579
2580 IE7._getElementSibling = function(node, direction) {
2581 direction += "Sibling";
2582 do {
2583 node = node[direction];
2584 if (node && node.nodeName > "@") break;
2585 } while (node);
2586 return node;
2587 };
2588
2589 var IMPLIED_ASTERISK = /(^|[, >+~])([#.:\[])/g,
2590 BLOCKS = /\)\{/g,
2591 COMMA = /,/,
2592 QUOTED = /^['"]/,
2593 HEX_ESCAPE = /\\([\da-f]{2,2})/gi,
2594 LAST_CHILD = /last/i;
2595
2596 IE7._byId = function(document, id) {
2597 var result = document.all[id] || null;
2598 // Returns a single element or a collection.
2599 if (!result || (result.nodeType && IE7._getAttribute(result, "id") === id)) return result;
2600 // document.all has returned a collection of elements with name/id
2601 for (var i = 0; i < result.length; i++) {
2602 if (IE7._getAttribute(result[i], "id") === id) return result[i];
2603 }
2604 return null;
2605 };
2606
2607 // =========================================================================
2608 // dom/selectors-api/CSSSelectorParser.js
2609 // =========================================================================
2610
2611 // http://www.w3.org/TR/css3-selectors/#w3cselgrammar (kinda)
2612 var CSSSelectorParser = RegGrp.extend({
2613 dictionary: new Dictionary({
2614 ident: /\-?(\\.|[_a-z]|[^\x00-\xa0])(\\.|[\w-]|[^\x00-\xa0])*/,
2615 combinator: /[\s>+~]/,
2616 operator: /[\^~|$*]?=/,
2617 nth_arg: /[+-]?\d+|[+-]?\d*n(?:\s*[+-]\s*\d+)?|even|odd/,
2618 tag: /\*|<#ident>/,
2619 id: /#(<#ident>)/,
2620 'class': /\.(<#ident>)/,
2621 pseudo: /\:([\w-]+)(?:\(([^)]+)\))?/,
2622 attr: /\[(<#ident>)(?:(<#operator>)((?:\\.|[^\[\]#.:])+))?\]/,
2623 negation: /:not\((<#tag>|<#id>|<#class>|<#attr>|<#pseudo>)\)/,
2624 sequence: /(\\.|[~*]=|\+\d|\+?\d*n\s*\+\s*\d|[^\s>+~,\*])+/,
2625 filter: /[#.:\[]<#sequence>/,
2626 selector: /[^>+~](\\.|[^,])*?/,
2627 grammar: /^(<#selector>)((,<#selector>)*)$/
2628 }),
2629
2630 ignoreCase: true
2631 });
2632
2633 var normalizer = new CSSSelectorParser({
2634 "\\\\.|[~*]\\s+=|\\+\\s+\\d": RegGrp.IGNORE,
2635 "\\[\\s+": "[",
2636 "\\(\\s+": "(",
2637 "\\s+\\)": ")",
2638 "\\s+\\]": "]",
2639 "\\s*([,>+~]|<#operator>)\\s*": "$1",
2640 "\\s+$": "",
2641 "\\s+": " "
2642 });
2643
2644 function normalize(selector) {
2645 selector = normalizer.parse(selector.replace(HEX_ESCAPE, "\\x$1"))
2646 .replace(UNESCAPE, "$1")
2647 .replace(IMPLIED_ASTERISK, "$1*$2");
2648 if (!VALID_SELECTOR.test(selector)) throwSelectorError();
2649 return selector;
2650 };
2651
2652 function unescape(query) {
2653 // put string values back
2654 return query.replace(ESCAPED, unescapeString);
2655 };
2656
2657 function unescapeString(match, index) {
2658 return strings[index];
2659 };
2660
2661 var BRACES = /\{/g, BRACES_ESCAPED = /\\{/g;
2662
2663 function closeBlock(group) {
2664 return Array((group.replace(BRACES_ESCAPED, "").match(BRACES) || "").length + 1).join("}");
2665 };
2666
2667 FILTER = new CSSSelectorParser(FILTER);
2668
2669 var TARGET = /:target/i, ROOT = /:root/i;
2670
2671 function getConstants(selector) {
2672 var constants = "";
2673 if (ROOT.test(selector)) constants += ",R=d.documentElement";
2674 if (TARGET.test(selector)) constants += ",H=d.location;H=H&&H.hash.replace('#','')";
2675 if (constants || selector.indexOf("#") !== -1) {
2676 constants = ",t=c.nodeType,d=t===9?c:c.ownerDocument||(c.document||c).parentWindow.document" + constants;
2677 }
2678 return "var ii" + constants + ";";
2679 };
2680
2681 var COMBINATOR = {
2682 " ": ";while(e!=s&&(e=e.parentNode)&&e.nodeType===1){",
2683 ">": ".parentElement;if(e){",
2684 "+": ";while((e=e.previousSibling)&&!(" + IS_ELEMENT + "))continue;if(e){",
2685 "~": ";while((e=e.previousSibling)){" + IF_ELEMENT
2686 };
2687
2688 var TOKEN = /\be\b/g;
2689
2690 MATCHER = new CSSSelectorParser({
2691 "(?:(<#selector>)(<#combinator>))?(<#tag>)(<#filter>)?$": function(match, before, combinator, tag, filters) {
2692 var group = "";
2693 if (tag !== "*") {
2694 var TAG = tag.toUpperCase();
2695 group += "if(e.nodeName==='" + TAG + (TAG === tag ? "" : "'||e.nodeName==='" + tag) + "'){";
2696 }
2697 if (filters) {
2698 group += "if(" + FILTER.parse(filters).slice(0, -2) + "){";
2699 }
2700 group = group.replace(TOKEN, "e" + this.index);
2701 if (combinator) {
2702 group += "var e=e" + (this.index++) + COMBINATOR[combinator];
2703 group = group.replace(TOKEN, "e" + this.index);
2704 }
2705 if (before) {
2706 group += this.parse(before);
2707 }
2708 return group;
2709 }
2710 });
2711
2712 var BY_ID = "e0=IE7._byId(d,'%1');if(e0){",
2713 BY_TAG_NAME = "var n=c.getElementsByTagName('%1');",
2714 STORE = "if(r==null)return e0;r[k++]=e0;";
2715
2716 var TAG_NAME = 1;
2717
2718 var SELECTOR = new CSSSelectorParser({
2719 "^((?:<#selector>)?(?:<#combinator>))(<#tag>)(<#filter>)?$": true
2720 });
2721
2722 var cache = {};
2723
2724 var selectById = new CSSSelectorParser({
2725 "^(<#tag>)#(<#ident>)(<#filter>)?( [^,]*)?$": function(match, tagName, id, filters, after) {
2726 var block = format(BY_ID, id), endBlock = "}";
2727 if (filters) {
2728 block += MATCHER.parse(tagName + filters);
2729 endBlock = closeBlock(block);
2730 }
2731 if (after) {
2732 block += "s=c=e0;" + selectQuery.parse("*" + after);
2733 } else {
2734 block += STORE;
2735 }
2736 return block + endBlock;
2737 },
2738
2739 "^([^#,]+)#(<#ident>)(<#filter>)?$": function(match, before, id, filters) {
2740 var block = format(BY_ID, id);
2741 if (before === "*") {
2742 block += STORE;
2743 } else {
2744 block += MATCHER.parse(before + filters) + STORE + "break";
2745 }
2746 return block + closeBlock(block);
2747 },
2748
2749 "^.*$": ""
2750 });
2751
2752 var selectQuery = new CSSSelectorParser({
2753 "<#grammar>": function(match, selector, remainingSelectors) {
2754 if (!this.groups) this.groups = [];
2755
2756 var group = SELECTOR.exec(" " + selector);
2757
2758 if (!group) throwSelectorError();
2759
2760 this.groups.push(group.slice(1));
2761
2762 if (remainingSelectors) {
2763 return this.parse(remainingSelectors.replace(COMMA, ""));
2764 }
2765
2766 var groups = this.groups,
2767 tagName = groups[0][TAG_NAME]; // first tag name
2768
2769 for (var i = 1; group = groups[i]; i++) { // search tag names
2770 if (tagName !== group[TAG_NAME]) {
2771 tagName = "*"; // mixed tag names, so use "*"
2772 break;
2773 }
2774 }
2775
2776 var matcher = "", store = STORE + "continue filtering;";
2777
2778 for (var i = 0; group = groups[i]; i++) {
2779 MATCHER.index = 0;
2780 if (tagName !== "*") group[TAG_NAME] = "*"; // we are already filtering by tagName
2781 group = group.join("");
2782 if (group === " *") { // select all
2783 matcher = store;
2784 break;
2785 } else {
2786 group = MATCHER.parse(group);
2787 if (useContext) group += "if(e" + MATCHER.index + "==s){";
2788 matcher += group + store + closeBlock(group);
2789 }
2790 }
2791
2792 // reduce to a single loop
2793 var isWild = tagName === "*";
2794 return (isWild ? "var n=c.all;" : format(BY_TAG_NAME, tagName)) +
2795 "filtering:while((e0=n[i++]))" +
2796 (isWild ? IF_ELEMENT.replace(TOKEN, "e0") : "{") +
2797 matcher +
2798 "}";
2799 },
2800
2801 "^.*$": throwSelectorError
2802 });
2803
2804 var REDUNDANT_NODETYPE_CHECKS = /\&\&(e\d+)\.nodeType===1(\)\{\s*if\(\1\.nodeName=)/g;
2805
2806 selectQuery.create = function(selector) {
2807 if (!cache[selector]) {
2808 selector = normalize(selector);
2809 this.groups = null;
2810 MATCHER.index = 0;
2811 var block = this.parse(selector);
2812 this.groups = null;
2813 MATCHER.index = 0;
2814 if (selector.indexOf("#") !== -1) {
2815 var byId = selectById.parse(selector);
2816 if (byId) {
2817 block =
2818 "if(t===1||t===11|!c.getElementById){" +
2819 block +
2820 "}else{" +
2821 byId +
2822 "}";
2823 }
2824 }
2825 // remove redundant nodeType==1 checks
2826 block = block.replace(REDUNDANT_NODETYPE_CHECKS, "$2");
2827 block = getConstants(selector) + decode(block);
2828 cache[selector] = new Function("return function(c,r,s){var i=0,k=0,e0;" + block + "return r}")();
2829 }
2830 return cache[selector];
2831 };
2832
2833 return cssQuery;
2834 })();
2835
2836 function throwSelectorError() {
2837 throw new SyntaxError("Invalid selector.");
2838 };
2839
2840 // -----------------------------------------------------------------------
2841 // initialisation
2842 // -----------------------------------------------------------------------
2843
2844 IE7.loaded = true;
2845
2846 (function() {
2847 try {
2848 // http://javascript.nwbox.com/IEContentLoaded/
2849 if (!document.body) throw "continue";
2850 documentElement.doScroll("left");
2851 } catch (ex) {
2852 setTimeout(arguments.callee, 1);
2853 return;
2854 }
2855 // execute the inner text of the IE7 script
2856 try {
2857 eval(script.innerHTML);
2858 } catch (ex) {
2859 // ignore errors
2860 }
2861 if (typeof IE7_PNG_SUFFIX == "object") {
2862 PNG = IE7_PNG_SUFFIX;
2863 } else {
2864 PNG = new RegExp(rescape(window.IE7_PNG_SUFFIX || "-trans.png") + "(\\?.*)?$", "i");
2865 }
2866
2867 // frequently used references
2868 body = document.body;
2869 viewport = MSIE5 ? body : documentElement;
2870
2871 // classes
2872 body.className += " ie7_body";
2873 documentElement.className += " ie7_html";
2874
2875 if (MSIE5) ie7Quirks();
2876
2877 IE7.CSS.init();
2878 IE7.HTML.init();
2879
2880 IE7.HTML.apply();
2881 IE7.CSS.apply();
2882
2883 IE7.recalc();
2884 })();
2885
2886 })(this, document);