293 lines
11 KiB
JavaScript
293 lines
11 KiB
JavaScript
// 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));
|
|
}
|
|
}
|