Adding mapbox-gl branch

This commit is contained in:
Andreas Hocevar
2015-03-16 18:50:27 +01:00
parent 7985f030fa
commit 57ee7f52fd
3109 changed files with 943365 additions and 0 deletions
@@ -0,0 +1,454 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview CSS Object Model helper functions.
* References:
* - W3C: http://dev.w3.org/csswg/cssom/
* - MSDN: http://msdn.microsoft.com/en-us/library/ms531209(VS.85).aspx.
* @supported in FF3, IE6, IE7, Safari 3.1.2, Chrome
* TODO(user): Fix in Opera.
* TODO(user): Consider hacking page, media, etc.. to work.
* This would be pretty challenging. IE returns the text for any rule
* regardless of whether or not the media is correct or not. Firefox at
* least supports CSSRule.type to figure out if it's a media type and then
* we could do something interesting, but IE offers no way for us to tell.
*/
goog.provide('goog.cssom');
goog.provide('goog.cssom.CssRuleType');
goog.require('goog.array');
goog.require('goog.dom');
/**
* Enumeration of {@code CSSRule} types.
* @enum {number}
*/
goog.cssom.CssRuleType = {
STYLE: 1,
IMPORT: 3,
MEDIA: 4,
FONT_FACE: 5,
PAGE: 6,
NAMESPACE: 7
};
/**
* Recursively gets all CSS as text, optionally starting from a given
* CSSStyleSheet.
* @param {(CSSStyleSheet|StyleSheetList)=} opt_styleSheet The CSSStyleSheet.
* @return {string} css text.
*/
goog.cssom.getAllCssText = function(opt_styleSheet) {
var styleSheet = opt_styleSheet || document.styleSheets;
return /** @type {string} */ (goog.cssom.getAllCss_(styleSheet, true));
};
/**
* Recursively gets all CSSStyleRules, optionally starting from a given
* CSSStyleSheet.
* Note that this excludes any CSSImportRules, CSSMediaRules, etc..
* @param {(CSSStyleSheet|StyleSheetList)=} opt_styleSheet The CSSStyleSheet.
* @return {Array<CSSStyleRule>} A list of CSSStyleRules.
*/
goog.cssom.getAllCssStyleRules = function(opt_styleSheet) {
var styleSheet = opt_styleSheet || document.styleSheets;
return /** @type {!Array<CSSStyleRule>} */ (
goog.cssom.getAllCss_(styleSheet, false));
};
/**
* Returns the CSSRules from a styleSheet.
* Worth noting here is that IE and FF differ in terms of what they will return.
* Firefox will return styleSheet.cssRules, which includes ImportRules and
* anything which implements the CSSRules interface. IE returns simply a list of
* CSSRules.
* @param {CSSStyleSheet} styleSheet The CSSStyleSheet.
* @throws {Error} If we cannot access the rules on a stylesheet object - this
* can happen if a stylesheet object's rules are accessed before the rules
* have been downloaded and parsed and are "ready".
* @return {CSSRuleList} An array of CSSRules or null.
*/
goog.cssom.getCssRulesFromStyleSheet = function(styleSheet) {
var cssRuleList = null;
try {
// Select cssRules unless it isn't present. For pre-IE9 IE, use the rules
// collection instead.
// It's important to be consistent in using only the W3C or IE apis on
// IE9+ where both are present to ensure that there is no indexing
// mismatches - the collections are subtly different in what the include or
// exclude which can lead to one collection being longer than the other
// depending on the page's construction.
cssRuleList = styleSheet.cssRules /* W3C */ || styleSheet.rules /* IE */;
} catch (e) {
// This can happen if we try to access the CSSOM before it's "ready".
if (e.code == 15) {
// Firefox throws an NS_ERROR_DOM_INVALID_ACCESS_ERR error if a stylesheet
// is read before it has been fully parsed. Let the caller know which
// stylesheet failed.
e.styleSheet = styleSheet;
throw e;
}
}
return cssRuleList;
};
/**
* Gets all CSSStyleSheet objects starting from some CSSStyleSheet. Note that we
* want to return the sheets in the order of the cascade, therefore if we
* encounter an import, we will splice that CSSStyleSheet object in front of
* the CSSStyleSheet that contains it in the returned array of CSSStyleSheets.
* @param {(CSSStyleSheet|StyleSheetList)=} opt_styleSheet A CSSStyleSheet.
* @param {boolean=} opt_includeDisabled If true, includes disabled stylesheets,
* defaults to false.
* @return {!Array<CSSStyleSheet>} A list of CSSStyleSheet objects.
*/
goog.cssom.getAllCssStyleSheets = function(opt_styleSheet,
opt_includeDisabled) {
var styleSheetsOutput = [];
var styleSheet = opt_styleSheet || document.styleSheets;
var includeDisabled = goog.isDef(opt_includeDisabled) ? opt_includeDisabled :
false;
// Imports need to go first.
if (styleSheet.imports && styleSheet.imports.length) {
for (var i = 0, n = styleSheet.imports.length; i < n; i++) {
goog.array.extend(styleSheetsOutput,
goog.cssom.getAllCssStyleSheets(styleSheet.imports[i]));
}
} else if (styleSheet.length) {
// In case we get a StyleSheetList object.
// http://dev.w3.org/csswg/cssom/#the-stylesheetlist
for (var i = 0, n = styleSheet.length; i < n; i++) {
goog.array.extend(styleSheetsOutput,
goog.cssom.getAllCssStyleSheets(styleSheet[i]));
}
} else {
// We need to walk through rules in browsers which implement .cssRules
// to see if there are styleSheets buried in there.
// If we have a CSSStyleSheet within CssRules.
var cssRuleList = goog.cssom.getCssRulesFromStyleSheet(
/** @type {!CSSStyleSheet} */ (styleSheet));
if (cssRuleList && cssRuleList.length) {
// Chrome does not evaluate cssRuleList[i] to undefined when i >=n;
// so we use a (i < n) check instead of cssRuleList[i] in the loop below
// and in other places where we iterate over a rules list.
// See issue # 5917 in Chromium.
for (var i = 0, n = cssRuleList.length, cssRule; i < n; i++) {
cssRule = cssRuleList[i];
// There are more stylesheets to get on this object..
if (cssRule.styleSheet) {
goog.array.extend(styleSheetsOutput,
goog.cssom.getAllCssStyleSheets(cssRule.styleSheet));
}
}
}
}
// This is a CSSStyleSheet. (IE uses .rules, W3c and Opera cssRules.)
if ((styleSheet.type || styleSheet.rules || styleSheet.cssRules) &&
(!styleSheet.disabled || includeDisabled)) {
styleSheetsOutput.push(styleSheet);
}
return styleSheetsOutput;
};
/**
* Gets the cssText from a CSSRule object cross-browserly.
* @param {CSSRule} cssRule A CSSRule.
* @return {string} cssText The text for the rule, including the selector.
*/
goog.cssom.getCssTextFromCssRule = function(cssRule) {
var cssText = '';
if (cssRule.cssText) {
// W3C.
cssText = cssRule.cssText;
} else if (cssRule.style && cssRule.style.cssText && cssRule.selectorText) {
// IE: The spacing here is intended to make the result consistent with
// FF and Webkit.
// We also remove the special properties that we may have added in
// getAllCssStyleRules since IE includes those in the cssText.
var styleCssText = cssRule.style.cssText.
replace(/\s*-closure-parent-stylesheet:\s*\[object\];?\s*/gi, '').
replace(/\s*-closure-rule-index:\s*[\d]+;?\s*/gi, '');
var thisCssText = cssRule.selectorText + ' { ' + styleCssText + ' }';
cssText = thisCssText;
}
return cssText;
};
/**
* Get the index of the CSSRule in it's CSSStyleSheet.
* @param {CSSRule} cssRule A CSSRule.
* @param {CSSStyleSheet=} opt_parentStyleSheet A reference to the stylesheet
* object this cssRule belongs to.
* @throws {Error} When we cannot get the parentStyleSheet.
* @return {number} The index of the CSSRule, or -1.
*/
goog.cssom.getCssRuleIndexInParentStyleSheet = function(cssRule,
opt_parentStyleSheet) {
// Look for our special style.ruleIndex property from getAllCss.
if (cssRule.style && cssRule.style['-closure-rule-index']) {
return cssRule.style['-closure-rule-index'];
}
var parentStyleSheet = opt_parentStyleSheet ||
goog.cssom.getParentStyleSheet(cssRule);
if (!parentStyleSheet) {
// We could call getAllCssStyleRules() here to get our special indexes on
// the style object, but that seems like it could be wasteful.
throw Error('Cannot find a parentStyleSheet.');
}
var cssRuleList = goog.cssom.getCssRulesFromStyleSheet(parentStyleSheet);
if (cssRuleList && cssRuleList.length) {
for (var i = 0, n = cssRuleList.length, thisCssRule; i < n; i++) {
thisCssRule = cssRuleList[i];
if (thisCssRule == cssRule) {
return i;
}
}
}
return -1;
};
/**
* We do some trickery in getAllCssStyleRules that hacks this in for IE.
* If the cssRule object isn't coming from a result of that function call, this
* method will return undefined in IE.
* @param {CSSRule} cssRule The CSSRule.
* @return {CSSStyleSheet} A styleSheet object.
*/
goog.cssom.getParentStyleSheet = function(cssRule) {
return cssRule.parentStyleSheet ||
cssRule.style &&
cssRule.style['-closure-parent-stylesheet'];
};
/**
* Replace a cssRule with some cssText for a new rule.
* If the cssRule object is not one of objects returned by
* getAllCssStyleRules, then you'll need to provide both the styleSheet and
* possibly the index, since we can't infer them from the standard cssRule
* object in IE. We do some trickery in getAllCssStyleRules to hack this in.
* @param {CSSRule} cssRule A CSSRule.
* @param {string} cssText The text for the new CSSRule.
* @param {CSSStyleSheet=} opt_parentStyleSheet A reference to the stylesheet
* object this cssRule belongs to.
* @param {number=} opt_index The index of the cssRule in its parentStylesheet.
* @throws {Error} If we cannot find a parentStyleSheet.
* @throws {Error} If we cannot find a css rule index.
*/
goog.cssom.replaceCssRule = function(cssRule, cssText, opt_parentStyleSheet,
opt_index) {
var parentStyleSheet = opt_parentStyleSheet ||
goog.cssom.getParentStyleSheet(cssRule);
if (parentStyleSheet) {
var index = opt_index >= 0 ? opt_index :
goog.cssom.getCssRuleIndexInParentStyleSheet(cssRule, parentStyleSheet);
if (index >= 0) {
goog.cssom.removeCssRule(parentStyleSheet, index);
goog.cssom.addCssRule(parentStyleSheet, cssText, index);
} else {
throw Error('Cannot proceed without the index of the cssRule.');
}
} else {
throw Error('Cannot proceed without the parentStyleSheet.');
}
};
/**
* Cross browser function to add a CSSRule into a CSSStyleSheet, optionally
* at a given index.
* @param {CSSStyleSheet} cssStyleSheet The CSSRule's parentStyleSheet.
* @param {string} cssText The text for the new CSSRule.
* @param {number=} opt_index The index of the cssRule in its parentStylesheet.
* @throws {Error} If the css rule text appears to be ill-formatted.
* TODO(bowdidge): Inserting at index 0 fails on Firefox 2 and 3 with an
* exception warning "Node cannot be inserted at the specified point in
* the hierarchy."
*/
goog.cssom.addCssRule = function(cssStyleSheet, cssText, opt_index) {
var index = opt_index;
if (index < 0 || index == undefined) {
// If no index specified, insert at the end of the current list
// of rules.
var rules = goog.cssom.getCssRulesFromStyleSheet(cssStyleSheet);
index = rules.length;
}
if (cssStyleSheet.insertRule) {
// W3C (including IE9+).
cssStyleSheet.insertRule(cssText, index);
} else {
// IE, pre 9: We have to parse the cssRule text to get the selector
// separated from the style text.
// aka Everything that isn't a colon, followed by a colon, then
// the rest is the style part.
var matches = /^([^\{]+)\{([^\{]+)\}/.exec(cssText);
if (matches.length == 3) {
var selector = matches[1];
var style = matches[2];
cssStyleSheet.addRule(selector, style, index);
} else {
throw Error('Your CSSRule appears to be ill-formatted.');
}
}
};
/**
* Cross browser function to remove a CSSRule in a CSSStyleSheet at an index.
* @param {CSSStyleSheet} cssStyleSheet The CSSRule's parentStyleSheet.
* @param {number} index The CSSRule's index in the parentStyleSheet.
*/
goog.cssom.removeCssRule = function(cssStyleSheet, index) {
if (cssStyleSheet.deleteRule) {
// W3C.
cssStyleSheet.deleteRule(index);
} else {
// IE.
cssStyleSheet.removeRule(index);
}
};
/**
* Appends a DOM node to HEAD containing the css text that's passed in.
* @param {string} cssText CSS to add to the end of the document.
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper user for
* document interactions.
* @return {!Element} The newly created STYLE element.
*/
goog.cssom.addCssText = function(cssText, opt_domHelper) {
var document = opt_domHelper ? opt_domHelper.getDocument() :
goog.dom.getDocument();
var cssNode = document.createElement('style');
cssNode.type = 'text/css';
var head = document.getElementsByTagName('head')[0];
head.appendChild(cssNode);
if (cssNode.styleSheet) {
// IE.
cssNode.styleSheet.cssText = cssText;
} else {
// W3C.
var cssTextNode = document.createTextNode(cssText);
cssNode.appendChild(cssTextNode);
}
return cssNode;
};
/**
* Cross browser method to get the filename from the StyleSheet's href.
* Explorer only returns the filename in the href, while other agents return
* the full path.
* @param {!StyleSheet} styleSheet Any valid StyleSheet object with an href.
* @throws {Error} When there's no href property found.
* @return {?string} filename The filename, or null if not an external
* styleSheet.
*/
goog.cssom.getFileNameFromStyleSheet = function(styleSheet) {
var href = styleSheet.href;
// Another IE/FF difference. IE returns an empty string, while FF and others
// return null for CSSStyleSheets not from an external file.
if (!href) {
return null;
}
// We need the regexp to ensure we get the filename minus any query params.
var matches = /([^\/\?]+)[^\/]*$/.exec(href);
var filename = matches[1];
return filename;
};
/**
* Recursively gets all CSS text or rules.
* @param {CSSStyleSheet|StyleSheetList} styleSheet The CSSStyleSheet.
* @param {boolean} isTextOutput If true, output is cssText, otherwise cssRules.
* @return {string|!Array<CSSRule>} cssText or cssRules.
* @private
*/
goog.cssom.getAllCss_ = function(styleSheet, isTextOutput) {
var cssOut = [];
var styleSheets = goog.cssom.getAllCssStyleSheets(styleSheet);
for (var i = 0; styleSheet = styleSheets[i]; i++) {
var cssRuleList = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
if (cssRuleList && cssRuleList.length) {
// We're going to track cssRule index if we want rule output.
if (!isTextOutput) {
var ruleIndex = 0;
}
for (var j = 0, n = cssRuleList.length, cssRule; j < n; j++) {
cssRule = cssRuleList[j];
// Gets cssText output, ignoring CSSImportRules.
if (isTextOutput && !cssRule.href) {
var res = goog.cssom.getCssTextFromCssRule(cssRule);
cssOut.push(res);
} else if (!cssRule.href) {
// Gets cssRules output, ignoring CSSImportRules.
if (cssRule.style) {
// This is a fun little hack to get parentStyleSheet into the rule
// object for IE since it failed to implement rule.parentStyleSheet.
// We can later read this property when doing things like hunting
// for indexes in order to delete a given CSSRule.
// Unfortunately we have to use the style object to store these
// pieces of info since the rule object is read-only.
if (!cssRule.parentStyleSheet) {
cssRule.style['-closure-parent-stylesheet'] = styleSheet;
}
// This is a hack to help with possible removal of the rule later,
// where we just append the rule's index in its parentStyleSheet
// onto the style object as a property.
// Unfortunately we have to use the style object to store these
// pieces of info since the rule object is read-only.
cssRule.style['-closure-rule-index'] = ruleIndex;
}
cssOut.push(cssRule);
}
if (!isTextOutput) {
ruleIndex++;
}
}
}
}
return isTextOutput ? cssOut.join(' ') : cssOut;
};
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<!--
Copyright 2008 The Closure Library Authors. All Rights Reserved.
Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<!--
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>
Closure Unit Tests - CSS Object Model helper
</title>
<script src="../base.js">
</script>
<script>
goog.require('goog.cssomTest');
</script>
</head>
<link rel="stylesheet" type="text/css" href="cssom_test_link_1.css">
<style>
/* This will import css_test_import_1 and css_test_import_2 */
@import "cssom_test_import_1.css?cachebust=1";
.css-style-1 {
display: block;
}
.css-style-2 {
display: block;
}
.css-style-3 {
display: block;
}
</style>
<body>
</body>
</html>
@@ -0,0 +1,323 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide('goog.cssomTest');
goog.setTestOnly('goog.cssomTest');
goog.require('goog.array');
goog.require('goog.cssom');
goog.require('goog.cssom.CssRuleType');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
// Since sheet cssom_test1.css's first line is to import
// cssom_test2.css, we should get 2 before one in the string.
var cssText = '.css-link-1 { display: block; } ' +
'.css-import-2 { display: block; } ' +
'.css-import-1 { display: block; } ' +
'.css-style-1 { display: block; } ' +
'.css-style-2 { display: block; } ' +
'.css-style-3 { display: block; }';
var replacementCssText = '.css-repl-1 { display: block; }';
var isIe7 = goog.userAgent.IE &&
(goog.userAgent.compare(goog.userAgent.VERSION, '7.0') == 0);
// We're going to toLowerCase cssText before testing, because IE returns
// CSS property names in UPPERCASE, and the function shouldn't
// "fix" the text as it would be expensive and rarely of use.
// Same goes for the trailing whitespace in IE.
// Same goes for fixing the optimized removal of trailing ; in rules.
// Also needed for Opera.
function fixCssTextForIe(cssText) {
cssText = cssText.toLowerCase().replace(/\s*$/, '');
if (cssText.match(/[^;] \}/)) {
cssText = cssText.replace(/([^;]) \}/g, '$1; }');
}
return cssText;
}
function testGetFileNameFromStyleSheet() {
var styleSheet = {'href': 'http://foo.com/something/filename.css'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
styleSheet = {'href': 'https://foo.com:123/something/filename.css'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
styleSheet = {'href': 'http://foo.com/something/filename.css?bar=bas'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
styleSheet = {'href': 'filename.css?bar=bas'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
styleSheet = {'href': 'filename.css'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
}
function testGetAllCssStyleSheets() {
var styleSheets = goog.cssom.getAllCssStyleSheets();
assertEquals(4, styleSheets.length);
// Makes sure they're in the right cascade order.
assertEquals('cssom_test_link_1.css',
goog.cssom.getFileNameFromStyleSheet(styleSheets[0]));
assertEquals('cssom_test_import_2.css',
goog.cssom.getFileNameFromStyleSheet(styleSheets[1]));
assertEquals('cssom_test_import_1.css',
goog.cssom.getFileNameFromStyleSheet(styleSheets[2]));
// Not an external styleSheet
assertNull(goog.cssom.getFileNameFromStyleSheet(styleSheets[3]));
}
function testGetAllCssText() {
var allCssText = goog.cssom.getAllCssText();
// In IE7, a CSSRule object gets included twice and replaces another
// existing CSSRule object. We aren't using
// goog.testing.ExpectedFailures since it brings in additional CSS
// which breaks a lot of our expectations about the number of rules
// present in a style sheet.
if (!isIe7) {
assertEquals(cssText, fixCssTextForIe(allCssText));
}
}
function testGetAllCssStyleRules() {
var allCssRules = goog.cssom.getAllCssStyleRules();
assertEquals(6, allCssRules.length);
}
function testAddCssText() {
var newCssText = '.css-add-1 { display: block; }';
var newCssNode = goog.cssom.addCssText(newCssText);
assertEquals(document.styleSheets.length, 3);
var allCssText = goog.cssom.getAllCssText();
// In IE7, a CSSRule object gets included twice and replaces another
// existing CSSRule object. We aren't using
// goog.testing.ExpectedFailures since it brings in additional CSS
// which breaks a lot of our expectations about the number of rules
// present in a style sheet.
if (!isIe7) {
// Opera inserts the CSSRule to the first position. And fixCssText
// is also needed to clean up whitespace.
if (goog.userAgent.OPERA) {
assertEquals(newCssText + ' ' + cssText,
fixCssTextForIe(allCssText));
} else {
assertEquals(cssText + ' ' + newCssText,
fixCssTextForIe(allCssText));
}
}
var cssRules = goog.cssom.getAllCssStyleRules();
assertEquals(7, cssRules.length);
// Remove the new stylesheet now so it doesn't interfere with other
// tests.
newCssNode.parentNode.removeChild(newCssNode);
// Sanity check.
cssRules = goog.cssom.getAllCssStyleRules();
assertEquals(6, cssRules.length);
}
function testAddCssRule() {
// test that addCssRule correctly adds the rule to the style
// sheet.
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var newCssRule = '.css-addCssRule { display: block; }';
var rules = styleSheet.rules || styleSheet.cssRules;
var origNumberOfRules = rules.length;
goog.cssom.addCssRule(styleSheet, newCssRule, 1);
rules = styleSheet.rules || styleSheet.cssRules;
var newNumberOfRules = rules.length;
assertEquals(newNumberOfRules, origNumberOfRules + 1);
// Remove the added rule so we don't mess up other tests.
goog.cssom.removeCssRule(styleSheet, 1);
}
function testAddCssRuleAtPos() {
// test that addCssRule correctly adds the rule to the style
// sheet at the specified position.
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var newCssRule = '.css-addCssRulePos { display: block; }';
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var origNumberOfRules = rules.length;
// Firefox croaks if we try to insert a CSSRule at an index that
// contains a CSSImport Rule. Since we deal only with CSSStyleRule
// objects, we find the first CSSStyleRule and return its index.
//
// NOTE(user): We could have unified the code block below for all
// browsers but IE6 horribly mangled up the stylesheet by creating
// duplicate instances of a rule when removeCssRule was invoked
// just after addCssRule with the looping construct in. This is
// perfectly fine since IE's styleSheet.rules does not contain
// references to anything but CSSStyleRules.
var pos = 0;
if (styleSheet.cssRules) {
pos = goog.array.findIndex(rules, function(rule) {
return rule.type == goog.cssom.CssRuleType.STYLE;
});
}
goog.cssom.addCssRule(styleSheet, newCssRule, pos);
rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var newNumberOfRules = rules.length;
assertEquals(newNumberOfRules, origNumberOfRules + 1);
// Remove the added rule so we don't mess up other tests.
goog.cssom.removeCssRule(styleSheet, pos);
rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
assertEquals(origNumberOfRules, rules.length);
}
function testAddCssRuleNoIndex() {
// How well do we handle cases where the optional index is
// not passed in?
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var origNumberOfRules = rules.length;
var newCssRule = '.css-addCssRuleNoIndex { display: block; }';
// Try inserting the rule without specifying an index.
// Make sure we don't throw an exception, and that we added
// the entry.
goog.cssom.addCssRule(styleSheet, newCssRule);
rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var newNumberOfRules = rules.length;
assertEquals(newNumberOfRules, origNumberOfRules + 1);
// Remove the added rule so we don't mess up the other tests.
goog.cssom.removeCssRule(styleSheet, newNumberOfRules - 1);
rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
assertEquals(origNumberOfRules, rules.length);
}
function testGetParentStyleSheetAfterGetAllCssStyleRules() {
var cssRules = goog.cssom.getAllCssStyleRules();
var cssRule = cssRules[4];
var parentStyleSheet = goog.cssom.getParentStyleSheet(cssRule);
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
assertEquals(styleSheet, parentStyleSheet);
}
function testGetCssRuleIndexInParentStyleSheetAfterGetAllCssStyleRules() {
var cssRules = goog.cssom.getAllCssStyleRules();
var cssRule = cssRules[4];
// Note here that this is correct - IE's styleSheet.rules does not
// contain references to anything but CSSStyleRules while FF and others
// include anything that inherits from the CSSRule interface.
// See http://dev.w3.org/csswg/cssom/#cssrule.
var parentStyleSheet = goog.cssom.getParentStyleSheet(cssRule);
var ruleIndex = goog.isDefAndNotNull(parentStyleSheet.cssRules) ? 2 : 1;
assertEquals(ruleIndex,
goog.cssom.getCssRuleIndexInParentStyleSheet(cssRule));
}
function testGetCssRuleIndexInParentStyleSheetNonStyleRule() {
// IE's styleSheet.rules only contain CSSStyleRules.
if (!goog.userAgent.IE) {
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var newCssRule = '@media print { .css-nonStyle { display: block; } }';
goog.cssom.addCssRule(styleSheet, newCssRule);
var rules = styleSheet.rules || styleSheet.cssRules;
var cssRule = rules[rules.length - 1];
assertEquals(goog.cssom.CssRuleType.MEDIA, cssRule.type);
// Make sure we don't throw an exception.
goog.cssom.getCssRuleIndexInParentStyleSheet(cssRule, styleSheet);
// Remove the added rule.
goog.cssom.removeCssRule(styleSheet, rules.length - 1);
}
}
// Tests the scenario where we have a known stylesheet and index.
function testReplaceCssRuleWithStyleSheetAndIndex() {
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var index = 2;
var origCssRule = rules[index];
var origCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(origCssRule));
goog.cssom.replaceCssRule(origCssRule, replacementCssText, styleSheet,
index);
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var newCssRule = rules[index];
var newCssText = goog.cssom.getCssTextFromCssRule(newCssRule);
assertEquals(replacementCssText, fixCssTextForIe(newCssText));
// Now we need to re-replace our rule, to preserve parity for the other
// tests.
goog.cssom.replaceCssRule(newCssRule, origCssText, styleSheet, index);
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var nowCssRule = rules[index];
var nowCssText = goog.cssom.getCssTextFromCssRule(nowCssRule);
assertEquals(origCssText, fixCssTextForIe(nowCssText));
}
function testReplaceCssRuleUsingGetAllCssStyleRules() {
var cssRules = goog.cssom.getAllCssStyleRules();
var origCssRule = cssRules[4];
var origCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(origCssRule));
// notice we don't pass in the stylesheet or index.
goog.cssom.replaceCssRule(origCssRule, replacementCssText);
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var index = goog.isDefAndNotNull(styleSheet.cssRules) ? 2 : 1;
var newCssRule = rules[index];
var newCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(newCssRule));
assertEquals(replacementCssText, newCssText);
// try getting it the other way around too.
var cssRules = goog.cssom.getAllCssStyleRules();
var newCssRule = cssRules[4];
var newCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(newCssRule));
assertEquals(replacementCssText, newCssText);
// Now we need to re-replace our rule, to preserve parity for the other
// tests.
goog.cssom.replaceCssRule(newCssRule, origCssText);
var cssRules = goog.cssom.getAllCssStyleRules();
var nowCssRule = cssRules[4];
var nowCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(nowCssRule));
assertEquals(origCssText, nowCssText);
}
@@ -0,0 +1,11 @@
/*
* Copyright 2010 The Closure Library Authors. All Rights Reserved.
*
* Use of this source code is governed by the Apache License, Version 2.0.
* See the COPYING file for details.
*/
@import "cssom_test_import_2.css";
.css-import-1 {
display: block;
}
@@ -0,0 +1,10 @@
/*
* Copyright 2010 The Closure Library Authors. All Rights Reserved.
*
* Use of this source code is governed by the Apache License, Version 2.0.
* See the COPYING file for details.
*/
.css-import-2 {
display: block;
}
@@ -0,0 +1,10 @@
/*
* Copyright 2010 The Closure Library Authors. All Rights Reserved.
*
* Use of this source code is governed by the Apache License, Version 2.0.
* See the COPYING file for details.
*/
.css-link-1 {
display: block;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,129 @@
<html>
<!--
Copyright 2010 The Closure Library Authors. All Rights Reserved.
Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="../../base.js">
</script>
<script>
goog.require('goog.cssom.iframe.styleTest');
</script>
<style type="text/css">
@import url("style_test_import.css");
body { font-family: Verdana; }
div { background-color: #ffc; margin: 10px 0; }
p { margin: 10px 0; }
.boxy { padding: 5px; background-color: #fa0; }
.special .boxy { padding: 10px; background-color: #abef00; }
div div strong { color: red; }
div { line-height: 1.3; }
.wrapper .inner-wrapper { border: 2px solid pink;}
a { color: red; }
#source4 { background-color: #900; }
#backgroundTest-ancestor-1 {
background-color: rgb(128,0,128);
}
#backgroundTest-ancestor-0 {
background-image: url("../../images/blank.gif");
background-position: 40px 70px;
background-repeat: repeat;
background-color: transparent;
padding: 5px 8px;
}
div#backgroundTest-parent {
border: 1px solid black;
background-color: transparent;
}
div#backgroundTest {
position: relative;
background-color: transparent;
height: 100px;
margin-top: 0;
}
</style>
<style type="text/css">
.goog-presently-theme-monochrome {
background-color: black;
color: #CCC;
}
.goog-presently-theme-monochrome a {
color: #FFF;
}
.goog-presently-theme-monochrome p#source4 {
font-variant: small-caps;
}
.italic {
font-style: italic;
}
</style>
<style type="text/css">
@font-face {
font-family: Cavalier;
}
#cavalier {
font-family: Cavalier;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="inner-wrapper">
<div id="source1" class="italic">
hello world
</div>
<div id="source2">
<div>
Some
<strong>
strong
</strong>
text
</div>
<div class="boxy exciting">
A box
</div>
<div class="inner-wrapper">
A wrapper
</div>
</div>
<div id="source3" class="special">
Some
<strong>
strong
</strong>
text
<div class="boxy">
A box
</div>
</div>
<div id="ancestor" class="goog-presently-theme-monochrome">
<p id="source4" style="background-color: #900">
Here's a link:
<a href="#">
my link
</a>
</p>
</div>
<div id="backgroundTest-ancestor-1">
<div id="backgroundTest-ancestor-0">
<div id="backgroundTest-parent">
<div id="backgroundTest">
hello
</div>
</div>
</div>
</div>
<div id="cavalier">
</div>
</div>
</div>
<br>
</body>
</html>
@@ -0,0 +1,292 @@
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide('goog.cssom.iframe.styleTest');
goog.setTestOnly('goog.cssom.iframe.styleTest');
goog.require('goog.cssom');
goog.require('goog.cssom.iframe.style');
goog.require('goog.dom');
goog.require('goog.dom.DomHelper');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
// unit tests
var propertiesToTest = [
'color',
'font-family',
'font-style',
'font-size',
'font-variant',
'border-top-style',
'border-top-width',
'border-top-color',
'background-color',
'margin-bottom'
];
function crawlDom(startNode, func) {
if (startNode.nodeType != 1) { return; }
func(startNode);
for (var i = 0; i < startNode.childNodes.length; i++) {
crawlDom(startNode.childNodes[i], func);
}
}
function getCurrentCssProperties(node, propList) {
var props = {};
if (node.nodeType != 1) { return; }
for (var i = 0; i < propList.length; i++) {
var prop = propList[i];
if (node.currentStyle) { // IE
var propCamelCase = '';
var propParts = prop.split('-');
for (var j = 0; j < propParts.length; j++) {
propCamelCase += propParts[j].charAt(0).toUpperCase() +
propParts[j].substring(1, propParts[j].length);
}
props[prop] = node.currentStyle[propCamelCase];
} else { // standards-compliant browsers
props[prop] = node.ownerDocument.defaultView.getComputedStyle(
node, '').getPropertyValue(prop);
}
}
return props;
}
function CssPropertyCollector() {
var propsList = [];
this.propsList = propsList;
this.collectProps = function(node) {
var nodeProps = getCurrentCssProperties(node, propertiesToTest);
if (nodeProps) { propsList.push([nodeProps, node]); }
};
}
function recursivelyListCssProperties(el) {
var collector = new CssPropertyCollector();
crawlDom(el, collector.collectProps);
return collector.propsList;
}
function testMatchCssSelector() {
var container = document.createElement('div');
container.className = 'container';
var el = document.createElement('div');
x = el;
el.id = 'mydiv';
el.className = 'colorful foo';
// set some arbirtrary content
el.innerHTML = '<div><ul><li>One</li><li>Two</li></ul></div>';
container.appendChild(el);
document.body.appendChild(container);
var elementAncestry = new goog.cssom.iframe.style.NodeAncestry_(el);
assertEquals(5, elementAncestry.nodes.length);
// list of input/output results. Output is the index of the selector
// that we expect to match - for example, in 'body div div.colorful',
// 'div.colorful' has an index of 2.
var expectedResults = [
['body div', [4, 1]],
['h1', null],
['body div h1', [4, 1]],
['body div.colorful h1', [4, 1]],
['body div div', [4, 2]],
['body div div div', [4, 2]],
['body div div.somethingelse div', [4, 1]],
['body div.somethingelse div', [2, 0]],
['div.container', [3, 0]],
['div.container div', [4, 1]],
['#mydiv', [4, 0]],
['div#mydiv', [4, 0]],
['div.colorful', [4, 0]],
['div#mydiv .colorful', [4, 0]],
['.colorful', [4, 0]],
['body * div', [4, 2]],
['body * *', [4, 2]]
];
for (var i = 0; i < expectedResults.length; i++) {
var input = expectedResults[i][0];
var expectedResult = expectedResults[i][1];
var selector = new goog.cssom.iframe.style.CssSelector_(input);
var result = selector.matchElementAncestry(elementAncestry);
if (expectedResult == null) {
assertEquals('Expected null result', expectedResult, result);
} else {
assertEquals('Expected element index for ' + input,
expectedResult[0],
result.elementIndex);
assertEquals('Expected selector part index for ' + input,
expectedResult[1],
result.selectorPartIndex);
}
}
document.body.removeChild(container);
}
function makeIframeDocument(iframe) {
var doc = goog.dom.getFrameContentDocument(iframe);
doc.open();
doc.write('<html><head>');
doc.write('<style>html,body { background-color: transparent; }</style>');
doc.write('</head><body></body></html>');
doc.close();
return doc;
}
function testCopyCss() {
for (var i = 1; i <= 4; i++) {
var sourceElement = document.getElementById('source' + i);
var newFrame = document.createElement('iframe');
newFrame.allowTransparency = true;
sourceElement.parentNode.insertBefore(newFrame,
sourceElement.nextSibling);
var doc = makeIframeDocument(newFrame);
goog.cssom.addCssText(
goog.cssom.iframe.style.getElementContext(sourceElement),
new goog.dom.DomHelper(doc));
doc.body.innerHTML = sourceElement.innerHTML;
var oldProps = recursivelyListCssProperties(sourceElement);
var newProps = recursivelyListCssProperties(doc.body);
assertEquals(oldProps.length, newProps.length);
for (var j = 0; j < oldProps.length; j++) {
for (var k = 0; k < propertiesToTest.length; k++) {
assertEquals('testing property ' + propertiesToTest[k],
oldProps[j][0][propertiesToTest[k]],
newProps[j][0][propertiesToTest[k]]);
}
}
}
}
function normalizeCssText(cssText) {
// Normalize cssText for testing purposes.
return cssText.replace(/\s/g, '').toLowerCase();
}
function testAImportantInFF2() {
var testDiv = document.getElementById('source1');
var cssText = normalizeCssText(
goog.cssom.iframe.style.getElementContext(testDiv));
var color = standardizeCSSValue('color', 'red');
var NORMAL_RULE = 'a{color:' + color;
var FF_2_RULE = 'a{color:' + color + '!important';
if (goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9a')) {
assertContains(FF_2_RULE, cssText);
} else {
assertContains(NORMAL_RULE, cssText);
assertNotContains(FF_2_RULE, cssText);
}
}
function testCopyBackgroundContext() {
var testDiv = document.getElementById('backgroundTest');
var cssText = goog.cssom.iframe.style.getElementContext(testDiv,
null,
true);
var iframe = document.createElement('iframe');
var ancestor = document.getElementById('backgroundTest-ancestor-1');
ancestor.parentNode.insertBefore(iframe, ancestor.nextSibling);
iframe.style.width = '100%';
iframe.style.height = '100px';
iframe.style.borderWidth = '0px';
var doc = makeIframeDocument(iframe);
goog.cssom.addCssText(cssText, new goog.dom.DomHelper(doc));
doc.body.innerHTML = testDiv.innerHTML;
var normalizedCssText = normalizeCssText(cssText);
assertTrue(
'Background color should be copied from parent element',
/body{[^{]*background-color:(?:rgb\(128,0,128\)|#800080)/.test(
normalizedCssText));
assertTrue(
'Background image should be copied from ancestor element',
/body{[^{]*background-image:url\(/.test(normalizedCssText));
// Background-position can't be calculated in FF2, due to this bug:
// http://bugzilla.mozilla.org/show_bug.cgi?id=316981
if (!(goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9'))) {
// Expected x position is:
// originalBackgroundPositionX - elementOffsetLeft
// 40px - (1px + 8px) == 31px
// Expected y position is:
// originalBackgroundPositionY - elementOffsetLeft
// 70px - (1px + 10px + 5px) == 54px;
assertTrue('Background image position should be adjusted correctly',
/body{[^{]*background-position:31px54px/.test(normalizedCssText));
}
}
function testCopyBackgroundContextFromIframe() {
var testDiv = document.getElementById('backgroundTest');
var iframe = document.createElement('iframe');
iframe.allowTransparency = true;
iframe.style.position = 'absolute';
iframe.style.top = '5px';
iframe.style.left = '5px';
iframe.style.borderWidth = '2px';
iframe.style.borderStyle = 'solid';
testDiv.appendChild(iframe);
var doc = makeIframeDocument(iframe);
doc.body.backgroundColor = 'transparent';
doc.body.style.margin = '0';
doc.body.style.padding = '0';
doc.body.innerHTML = '<p style="margin: 0">I am transparent!</p>';
var normalizedCssText = normalizeCssText(
goog.cssom.iframe.style.getElementContext(
doc.body.firstChild, null, true));
// Background properties should get copied through from the parent
// document since the iframe is transparent
assertTrue(
'Background color should be copied from parent element',
/body{[^{]*background-color:(?:rgb\(128,0,128\)|#800080)/.test(
normalizedCssText));
assertTrue(
'Background image should be copied from ancestor element',
/body{[^{]*background-image:url\(/.test(normalizedCssText));
// Background-position can't be calculated in FF2, due to this bug:
// http://bugzilla.mozilla.org/show_bug.cgi?id=316981
if (!(goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9'))) {
// Image offset should have been calculated to be the same as the
// above example, but adding iframe offset and borderWidth.
// Expected x position is:
// originalBackgroundPositionX - elementOffsetLeft
// 40px - (1px + 8px + 5px + 2px) == 24px
// Expected y position is:
// originalBackgroundPositionY - elementOffsetLeft
// 70px - (1px + 10px + 5px + 5px + 2px) == 47px;
assertTrue('Background image position should be adjusted correctly',
!!/body{[^{]*background-position:24px47px/.exec(
normalizedCssText));
}
iframe.parentNode.removeChild(iframe);
}
function testCopyFontFaceRules() {
var isFontFaceCssomSupported =
goog.userAgent.WEBKIT ||
goog.userAgent.OPERA ||
(goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.1'));
// We cannot use goog.testing.ExpectedFailures since it dynamically
// brings in CSS which causes the background context tests to fail
// in IE6.
if (isFontFaceCssomSupported) {
var cssText = goog.cssom.iframe.style.getElementContext(
document.getElementById('cavalier'));
assertTrue('The font face rule should have been copied correctly',
/@font-face/.test(cssText));
}
}
@@ -0,0 +1,10 @@
/*
* Copyright 2010 The Closure Library Authors. All Rights Reserved.
*
* Use of this source code is governed by the Apache License, Version 2.0.
* See the COPYING file for details.
*/
div div strong {
font-style: italic;
}