All Downloads are FREE. Search and download functionalities are using the official Maven repository.

goog.style.style_test.js Maven / Gradle / Ivy

Go to download

The Google Closure Library is a collection of JavaScript code designed for use with the Google Closure JavaScript Compiler. This non-official distribution was prepared by the ClojureScript team at http://clojure.org/

There is a newer version: 0.0-20230227-c7c0a541
Show newest version
// Copyright 2011 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 Licensegg 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 Shared unit tests for styles.
 */

goog.provide('goog.style_test');

goog.require('goog.array');
goog.require('goog.color');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events.BrowserEvent');
goog.require('goog.html.testing');
goog.require('goog.labs.userAgent.util');
goog.require('goog.math.Box');
goog.require('goog.math.Coordinate');
goog.require('goog.math.Rect');
goog.require('goog.math.Size');
goog.require('goog.object');
goog.require('goog.style');
goog.require('goog.testing.ExpectedFailures');
goog.require('goog.testing.MockUserAgent');
goog.require('goog.testing.TestCase');
goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
goog.require('goog.userAgentTestUtil');
goog.require('goog.userAgentTestUtil.UserAgents');

goog.setTestOnly('goog.style_test');

// IE before version 6 will always be border box in compat mode.
var isBorderBox = goog.dom.isCss1CompatMode() ?
    (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('6')) :
    true;
var EPSILON = 2;
var expectedFailures = new goog.testing.ExpectedFailures();
var $ = goog.dom.getElement;
var mockUserAgent;

function setUpPage() {
  // TODO(b/25875505): Fix unreported assertions (go/failonunreportedasserts).
  goog.testing.TestCase.getActiveTestCase().failOnUnreportedAsserts = false;

  var viewportSize = goog.dom.getViewportSize();
  // When the window is too short or not wide enough, some tests, especially
  // those for off-screen elements, fail.  Oddly, the most reliable
  // indicator is a width of zero (which is of course erroneous), since
  // height sometimes includes a scroll bar.  We can make no assumptions on
  // window size on the Selenium farm.
  if (goog.userAgent.IE && viewportSize.width < 300) {
    // Move to origin, since IE won't resize outside the screen.
    window.moveTo(0, 0);
    window.resizeTo(640, 480);
  }
}

function setUp() {
  window.scrollTo(0, 0);
  goog.userAgentTestUtil.reinitializeUserAgent();
  mockUserAgent = new goog.testing.MockUserAgent();
  mockUserAgent.install();
}

function tearDown() {
  expectedFailures.handleTearDown();
  var testVisibleDiv2 = goog.dom.getElement('test-visible2');
  testVisibleDiv2.setAttribute('style', '');
  goog.dom.removeChildren(testVisibleDiv2);
  var testViewport = goog.dom.getElement('test-viewport');
  testViewport.setAttribute('style', '');
  goog.dom.removeChildren(testViewport);
  goog.dispose(mockUserAgent);

  // Prevent multiple vendor prefixed mock elements from poisoning the cache.
  goog.style.styleNameCache_ = {};
}

function testSetStyle() {
  var el = $('span1');
  goog.style.setStyle(el, 'textDecoration', 'underline');
  assertEquals('Should be underline', 'underline', el.style.textDecoration);
}

function testSetStyleMap() {
  var el = $('span6');

  var styles =
      {'background-color': 'blue', 'font-size': '100px', textAlign: 'center'};

  goog.style.setStyle(el, styles);

  var answers = {
    backgroundColor: 'blue',
    fontSize: '100px',
    textAlign: 'center'
  };

  goog.object.forEach(answers, function(value, style) {
    assertEquals('Should be ' + value, value, el.style[style]);
  });
}

function testSetStyleWithNonCamelizedString() {
  var el = $('span5');
  goog.style.setStyle(el, 'text-decoration', 'underline');
  assertEquals('Should be underline', 'underline', el.style.textDecoration);
}

function testGetStyle() {
  var el = goog.dom.getElement('styleTest3');
  goog.style.setStyle(el, 'width', '80px');
  goog.style.setStyle(el, 'textDecoration', 'underline');

  assertEquals('80px', goog.style.getStyle(el, 'width'));
  assertEquals('underline', goog.style.getStyle(el, 'textDecoration'));
  assertEquals('underline', goog.style.getStyle(el, 'text-decoration'));
  // Non set properties are always empty strings.
  assertEquals('', goog.style.getStyle(el, 'border'));
}

function testGetStyleMsFilter() {
  // Element with -ms-filter style set.
  var e = goog.dom.getElement('msFilter');

  if (goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(8) &&
      !goog.userAgent.isDocumentModeOrHigher(10)) {
    // Only IE8/9 supports -ms-filter and returns it as value for the "filter"
    // property. When in compatibility mode, -ms-filter is not supported
    // and IE8 behaves as IE7 so the other case will apply.
    assertEquals('alpha(opacity=0)', goog.style.getStyle(e, 'filter'));
  } else {
    // Any other browser does not support ms-filter so it returns empty string.
    assertEquals('', goog.style.getStyle(e, 'filter'));
  }
}

function testGetStyleFilter() {
  // Element with filter style set.
  var e = goog.dom.getElement('filter');

  if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) {
    // Filter supported.
    assertEquals('alpha(opacity=0)', goog.style.getStyle(e, 'filter'));
  } else {
    assertEquals('', goog.style.getStyle(e, 'filter'));
  }
}

function testGetComputedStyleMsFilter() {
  // Element with -ms-filter style set.
  var e = goog.dom.getElement('msFilter');

  if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) {
    if (goog.userAgent.isDocumentModeOrHigher(9)) {
      // IE 9 returns the value.
      assertEquals(
          'alpha(opacity=0)', goog.style.getComputedStyle(e, 'filter'));
    } else {
      // Older IE always returns empty string for computed styles.
      assertEquals('', goog.style.getComputedStyle(e, 'filter'));
    }
  } else {
    // Non IE returns 'none' for filter as it is an SVG property
    assertEquals('none', goog.style.getComputedStyle(e, 'filter'));
  }
}

function testGetComputedStyleFilter() {
  // Element with filter style set.
  var e = goog.dom.getElement('filter');

  if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) {
    if (goog.userAgent.isDocumentModeOrHigher(9)) {
      // IE 9 returns the value.
      assertEquals(
          'alpha(opacity=0)', goog.style.getComputedStyle(e, 'filter'));
    } else {
      // Older IE always returns empty string for computed styles.
      assertEquals('', goog.style.getComputedStyle(e, 'filter'));
    }
  } else {
    // Non IE returns 'none' for filter as it is an SVG property
    assertEquals('none', goog.style.getComputedStyle(e, 'filter'));
  }
}

function testGetComputedBoxSizing() {
  if (!goog.userAgent.IE || goog.userAgent.isVersionOrHigher(8)) {
    var defaultBoxSizing =
        goog.dom.isCss1CompatMode() ? 'content-box' : 'border-box';
    var el = goog.dom.getElement('box-sizing-unset');
    assertEquals(defaultBoxSizing, goog.style.getComputedBoxSizing(el));

    el = goog.dom.getElement('box-sizing-border-box');
    assertEquals('border-box', goog.style.getComputedBoxSizing(el));
  } else {
    // IE7 and below don't support box-sizing.
    assertNull(
        goog.style.getComputedBoxSizing(
            goog.dom.getElement('box-sizing-border-box')));
  }
}

function testGetComputedPosition() {
  assertEquals(
      'position not set', 'static',
      goog.style.getComputedPosition($('position-unset')));
  assertEquals(
      'position:relative in style attribute', 'relative',
      goog.style.getComputedPosition($('style-position-relative')));
  if (goog.userAgent.IE && !goog.dom.isCss1CompatMode() &&
      !goog.userAgent.isVersionOrHigher(10)) {
    assertEquals(
        'position:fixed in style attribute', 'static',
        goog.style.getComputedPosition($('style-position-fixed')));
  } else {
    assertEquals(
        'position:fixed in style attribute', 'fixed',
        goog.style.getComputedPosition($('style-position-fixed')));
  }
  assertEquals(
      'position:absolute in css', 'absolute',
      goog.style.getComputedPosition($('css-position-absolute')));
}

function testGetComputedOverflowXAndY() {
  assertEquals(
      'overflow-x:scroll in style attribute', 'scroll',
      goog.style.getComputedOverflowX($('style-overflow-scroll')));
  assertEquals(
      'overflow-y:scroll in style attribute', 'scroll',
      goog.style.getComputedOverflowY($('style-overflow-scroll')));
  assertEquals(
      'overflow-x:hidden in css', 'hidden',
      goog.style.getComputedOverflowX($('css-overflow-hidden')));
  assertEquals(
      'overflow-y:hidden in css', 'hidden',
      goog.style.getComputedOverflowY($('css-overflow-hidden')));
}

function testGetComputedZIndex() {
  assertEquals(
      'z-index:200 in style attribute', '200',
      '' + goog.style.getComputedZIndex($('style-z-index-200')));
  assertEquals(
      'z-index:200 in css', '200',
      '' + goog.style.getComputedZIndex($('css-z-index-200')));
}

function testGetComputedTextAlign() {
  assertEquals(
      'text-align:right in style attribute', 'right',
      goog.style.getComputedTextAlign($('style-text-align-right')));
  assertEquals(
      'text-align:right inherited from parent', 'right',
      goog.style.getComputedTextAlign($('style-text-align-right-inner')));
  assertEquals(
      'text-align:center in css', 'center',
      goog.style.getComputedTextAlign($('css-text-align-center')));
}

function testGetComputedCursor() {
  assertEquals(
      'cursor:move in style attribute', 'move',
      goog.style.getComputedCursor($('style-cursor-move')));
  assertEquals(
      'cursor:move inherited from parent', 'move',
      goog.style.getComputedCursor($('style-cursor-move-inner')));
  assertEquals(
      'cursor:poiner in css', 'pointer',
      goog.style.getComputedCursor($('css-cursor-pointer')));
}

function testGetBackgroundColor() {
  var dest = $('bgcolorDest');

  for (var i = 0; $('bgcolorTest' + i); i++) {
    var src = $('bgcolorTest' + i);
    var bgColor = goog.style.getBackgroundColor(src);

    dest.style.backgroundColor = bgColor;
    assertEquals(
        'Background colors should be equal', goog.style.getBackgroundColor(src),
        goog.style.getBackgroundColor(dest));

    try {
      // goog.color.parse throws a generic exception if handed input it
      // doesn't understand.
      var c = goog.color.parse(bgColor);
      assertEquals('rgb(255,0,0)', goog.color.hexToRgbStyle(c.hex));
    } catch (e) {
      // Internet Explorer is unable to parse colors correctly after test 4.
      // Other browsers may vary, but all should be able to handle straight
      // hex input.
      assertFalse('Should be able to parse color "' + bgColor + '"', i < 5);
    }
  }
}

function testSetPosition() {
  var el = $('testEl');

  goog.style.setPosition(el, 100, 100);
  assertEquals('100px', el.style.left);
  assertEquals('100px', el.style.top);

  goog.style.setPosition(el, '50px', '25px');
  assertEquals('50px', el.style.left);
  assertEquals('25px', el.style.top);

  goog.style.setPosition(el, '10ex', '25px');
  assertEquals('10ex', el.style.left);
  assertEquals('25px', el.style.top);

  goog.style.setPosition(el, '10%', '25%');
  assertEquals('10%', el.style.left);
  assertEquals('25%', el.style.top);

  // ignores stupid units
  goog.style.setPosition(el, 0, 0);
  // TODO(user): IE errors if you set these values.  Should we make setStyle
  // catch these?  Or leave it up to the app.  Fixing the tests for now.
  // goog.style.setPosition(el, '10rainbows', '25rainbows');
  assertEquals('0px', el.style.left);
  assertEquals('0px', el.style.top);


  goog.style.setPosition(el, new goog.math.Coordinate(20, 40));
  assertEquals('20px', el.style.left);
  assertEquals('40px', el.style.top);
}

function testGetClientPositionAbsPositionElement() {
  var div = goog.dom.createDom(goog.dom.TagName.DIV);
  div.style.position = 'absolute';
  div.style.left = '100px';
  div.style.top = '200px';
  document.body.appendChild(div);
  var pos = goog.style.getClientPosition(div);
  assertEquals(100, pos.x);
  assertEquals(200, pos.y);
}

function testGetClientPositionNestedElements() {
  var innerDiv = goog.dom.createDom(goog.dom.TagName.DIV);
  innerDiv.style.position = 'relative';
  innerDiv.style.left = '-10px';
  innerDiv.style.top = '-10px';
  var div = goog.dom.createDom(goog.dom.TagName.DIV);
  div.style.position = 'absolute';
  div.style.left = '150px';
  div.style.top = '250px';
  div.appendChild(innerDiv);
  document.body.appendChild(div);
  var pos = goog.style.getClientPosition(innerDiv);
  assertEquals(140, pos.x);
  assertEquals(240, pos.y);
}

function testGetClientPositionOfOffscreenElement() {
  var div = goog.dom.createDom(goog.dom.TagName.DIV);
  div.style.position = 'absolute';
  div.style.left = '2000px';
  div.style.top = '2000px';
  div.style.width = '10px';
  div.style.height = '10px';
  document.body.appendChild(div);

  try {
    window.scroll(0, 0);
    var pos = goog.style.getClientPosition(div);
    assertEquals(2000, pos.x);
    assertEquals(2000, pos.y);

    // The following tests do not work in Gecko 1.8 and below, due to an
    // obscure off-by-one bug in goog.style.getPageOffset.  Same for IE.
    if (!goog.userAgent.IE &&
        !(goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9'))) {
      window.scroll(1, 1);
      var pos = goog.style.getClientPosition(div);
      assertEquals(1999, pos.x);
      assertRoughlyEquals(1999, pos.y, 0.5);

      window.scroll(2, 2);
      pos = goog.style.getClientPosition(div);
      assertEquals(1998, pos.x);
      assertRoughlyEquals(1998, pos.y, 0.5);

      window.scroll(100, 100);
      pos = goog.style.getClientPosition(div);
      assertEquals(1900, pos.x);
      assertRoughlyEquals(1900, pos.y, 0.5);
    }
  } finally {
    window.scroll(0, 0);
    document.body.removeChild(div);
  }
}

function testGetClientPositionOfOrphanElement() {
  var orphanElem = document.createElement(goog.dom.TagName.DIV);
  var pos = goog.style.getClientPosition(orphanElem);
  assertEquals(0, pos.x);
  assertEquals(0, pos.y);
}

function testGetClientPositionEvent() {
  var mockEvent = {};
  mockEvent.clientX = 100;
  mockEvent.clientY = 200;
  var pos = goog.style.getClientPosition(mockEvent);
  assertEquals(100, pos.x);
  assertEquals(200, pos.y);
}

function testGetClientPositionTouchEvent() {
  var mockTouchEvent = {};
  mockTouchEvent.changedTouches = [{}];
  mockTouchEvent.changedTouches[0].clientX = 100;
  mockTouchEvent.changedTouches[0].clientY = 200;

  var pos = goog.style.getClientPosition(mockTouchEvent);
  assertEquals(100, pos.x);
  assertEquals(200, pos.y);
}

function testGetClientPositionEmptyTouchList() {
  var mockTouchEvent = {};

  mockTouchEvent.touches = [];

  mockTouchEvent.changedTouches = [{}];
  mockTouchEvent.changedTouches[0].clientX = 100;
  mockTouchEvent.changedTouches[0].clientY = 200;

  var pos = goog.style.getClientPosition(mockTouchEvent);
  assertEquals(100, pos.x);
  assertEquals(200, pos.y);
}

function testGetClientPositionAbstractedTouchEvent() {
  var mockTouchEvent = {};
  mockTouchEvent.changedTouches = [{}];
  mockTouchEvent.changedTouches[0].clientX = 100;
  mockTouchEvent.changedTouches[0].clientY = 200;

  var e = new goog.events.BrowserEvent(mockTouchEvent);

  var pos = goog.style.getClientPosition(e);
  assertEquals(100, pos.x);
  assertEquals(200, pos.y);
}

function testGetPageOffsetAbsPositionedElement() {
  var div = goog.dom.createDom(goog.dom.TagName.DIV);
  div.style.position = 'absolute';
  div.style.left = '100px';
  div.style.top = '200px';
  document.body.appendChild(div);
  var pos = goog.style.getPageOffset(div);
  assertEquals(100, pos.x);
  assertEquals(200, pos.y);
}

function testGetPageOffsetNestedElements() {
  var innerDiv = goog.dom.createDom(goog.dom.TagName.DIV);
  innerDiv.style.position = 'relative';
  innerDiv.style.left = '-10px';
  innerDiv.style.top = '-10px';
  var div = goog.dom.createDom(goog.dom.TagName.DIV);
  div.style.position = 'absolute';
  div.style.left = '150px';
  div.style.top = '250px';
  div.appendChild(innerDiv);
  document.body.appendChild(div);
  var pos = goog.style.getPageOffset(innerDiv);
  assertRoughlyEquals(140, pos.x, 0.1);
  assertRoughlyEquals(240, pos.y, 0.1);
}

function testGetPageOffsetWithBodyPadding() {
  document.body.style.margin = '40px';
  document.body.style.padding = '60px';
  document.body.style.borderWidth = '70px';
  try {
    var div = goog.dom.createDom(goog.dom.TagName.DIV);
    div.style.position = 'absolute';
    div.style.left = '100px';
    div.style.top = '200px';
    // Margin will affect position, but padding and borders should not.
    div.style.margin = '1px';
    div.style.padding = '2px';
    div.style.borderWidth = '3px';
    document.body.appendChild(div);
    var pos = goog.style.getPageOffset(div);
    assertRoughlyEquals(101, pos.x, 0.1);
    assertRoughlyEquals(201, pos.y, 0.1);
  } finally {
    document.body.removeChild(div);
    document.body.style.margin = '';
    document.body.style.padding = '';
    document.body.style.borderWidth = '';
  }
}

function testGetPageOffsetWithDocumentElementPadding() {
  document.documentElement.style.margin = '40px';
  document.documentElement.style.padding = '60px';
  document.documentElement.style.borderWidth = '70px';
  try {
    var div = goog.dom.createDom(goog.dom.TagName.DIV);
    div.style.position = 'absolute';
    div.style.left = '100px';
    div.style.top = '200px';
    // Margin will affect position, but padding and borders should not.
    div.style.margin = '1px';
    div.style.padding = '2px';
    div.style.borderWidth = '3px';
    document.body.appendChild(div);
    var pos = goog.style.getPageOffset(div);
    // FF3 (but not beyond) gets confused by document margins.
    if (goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9') &&
        !goog.userAgent.isVersionOrHigher('1.9.1')) {
      assertEquals(141, pos.x);
      assertEquals(241, pos.y);
    } else {
      assertRoughlyEquals(101, pos.x, 0.1);
      assertRoughlyEquals(201, pos.y, 0.1);
    }
  } finally {
    document.body.removeChild(div);
    document.documentElement.style.margin = '';
    document.documentElement.style.padding = '';
    document.documentElement.style.borderWidth = '';
  }
}

function testGetPageOffsetElementOffscreen() {
  var div = goog.dom.createDom(goog.dom.TagName.DIV);
  div.style.position = 'absolute';
  div.style.left = '10000px';
  div.style.top = '20000px';
  document.body.appendChild(div);
  window.scroll(0, 0);
  try {
    var pos = goog.style.getPageOffset(div);
    assertEquals(10000, pos.x);
    assertEquals(20000, pos.y);

    // The following tests do not work in Gecko 1.8 and below, due to an
    // obscure off-by-one bug in goog.style.getPageOffset.  Same for IE.
    if (!(goog.userAgent.IE) &&
        !(goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9'))) {
      window.scroll(1, 1);
      pos = goog.style.getPageOffset(div);
      assertEquals(10000, pos.x);
      assertRoughlyEquals(20000, pos.y, 0.5);

      window.scroll(1000, 2000);
      pos = goog.style.getPageOffset(div);
      assertEquals(10000, pos.x);
      assertRoughlyEquals(20000, pos.y, 1);

      window.scroll(10000, 20000);
      pos = goog.style.getPageOffset(div);
      assertEquals(10000, pos.x);
      assertRoughlyEquals(20000, pos.y, 1);
    }
  }
  // Undo changes.
  finally {
    document.body.removeChild(div);
    window.scroll(0, 0);
  }
}

function testGetPageOffsetFixedPositionElements() {
  // Skip these tests in certain browsers.
  // position:fixed is not supported in IE before version 7
  if (!goog.userAgent.IE || !goog.userAgent.isVersionOrHigher('6')) {
    // Test with a position fixed element
    var div = goog.dom.createDom(goog.dom.TagName.DIV);
    div.style.position = 'fixed';
    div.style.top = '10px';
    div.style.left = '10px';
    document.body.appendChild(div);
    var pos = goog.style.getPageOffset(div);
    assertEquals(10, pos.x);
    assertEquals(10, pos.y);

    // Test with a position fixed element as parent
    var innerDiv = goog.dom.createDom(goog.dom.TagName.DIV);
    div = goog.dom.createDom(goog.dom.TagName.DIV);
    div.style.position = 'fixed';
    div.style.top = '10px';
    div.style.left = '10px';
    div.style.padding = '5px';
    div.appendChild(innerDiv);
    document.body.appendChild(div);
    pos = goog.style.getPageOffset(innerDiv);
    assertEquals(15, pos.x);
    assertEquals(15, pos.y);
  }
}

function testGetPositionTolerantToNoDocumentElementBorder() {
  // In IE, removing the border on the document element undoes the normal
  // 2-pixel offset.  Ensure that we're correctly compensating for both cases.
  try {
    document.documentElement.style.borderWidth = '0';
    var div = goog.dom.createDom(goog.dom.TagName.DIV);
    div.style.position = 'absolute';
    div.style.left = '100px';
    div.style.top = '200px';
    document.body.appendChild(div);

    // Test all major positioning methods.
    // Disabled for IE9 and below - IE8 returns dimensions multiplied by 100.
    // IE9 is flaky. See b/22873770.
    expectedFailures.expectFailureFor(
        goog.userAgent.IE && !goog.userAgent.isVersionOrHigher(10));
    try {
      // Test all major positioning methods.
      var pos = goog.style.getClientPosition(div);
      assertEquals(100, pos.x);
      assertRoughlyEquals(200, pos.y, .1);
      var offset = goog.style.getPageOffset(div);
      assertEquals(100, offset.x);
      assertRoughlyEquals(200, offset.y, .1);
    } catch (e) {
      expectedFailures.handleException(e);
    }
  } finally {
    document.documentElement.style.borderWidth = '';
  }
}

function testSetSize() {
  var el = $('testEl');

  goog.style.setSize(el, 100, 100);
  assertEquals('100px', el.style.width);
  assertEquals('100px', el.style.height);

  goog.style.setSize(el, '50px', '25px');
  assertEquals('should be "50px"', '50px', el.style.width);
  assertEquals('should be "25px"', '25px', el.style.height);

  goog.style.setSize(el, '10ex', '25px');
  assertEquals('10ex', el.style.width);
  assertEquals('25px', el.style.height);

  goog.style.setSize(el, '10%', '25%');
  assertEquals('10%', el.style.width);
  assertEquals('25%', el.style.height);

  // ignores stupid units
  goog.style.setSize(el, 0, 0);
  // TODO(user): IE errors if you set these values.  Should we make setStyle
  // catch these?  Or leave it up to the app.  Fixing the tests for now.
  // goog.style.setSize(el, '10rainbows', '25rainbows');
  assertEquals('0px', el.style.width);
  assertEquals('0px', el.style.height);

  goog.style.setSize(el, new goog.math.Size(20, 40));
  assertEquals('20px', el.style.width);
  assertEquals('40px', el.style.height);
}

function testSetWidthAndHeight() {
  var el = $('testEl');

  // Replicate all of the setSize tests above.

  goog.style.setWidth(el, 100);
  goog.style.setHeight(el, 100);
  assertEquals('100px', el.style.width);
  assertEquals('100px', el.style.height);

  goog.style.setWidth(el, '50px');
  goog.style.setHeight(el, '25px');
  assertEquals('should be "50px"', '50px', el.style.width);
  assertEquals('should be "25px"', '25px', el.style.height);

  goog.style.setWidth(el, '10ex');
  goog.style.setHeight(el, '25px');
  assertEquals('10ex', el.style.width);
  assertEquals('25px', el.style.height);

  goog.style.setWidth(el, '10%');
  goog.style.setHeight(el, '25%');
  assertEquals('10%', el.style.width);
  assertEquals('25%', el.style.height);

  goog.style.setWidth(el, 0);
  goog.style.setHeight(el, 0);
  assertEquals('0px', el.style.width);
  assertEquals('0px', el.style.height);

  goog.style.setWidth(el, 20);
  goog.style.setHeight(el, 40);
  assertEquals('20px', el.style.width);
  assertEquals('40px', el.style.height);

  // Additional tests testing each separately.
  goog.style.setWidth(el, '');
  goog.style.setHeight(el, '');
  assertEquals('', el.style.width);
  assertEquals('', el.style.height);

  goog.style.setHeight(el, 20);
  assertEquals('', el.style.width);
  assertEquals('20px', el.style.height);

  goog.style.setWidth(el, 40);
  assertEquals('40px', el.style.width);
  assertEquals('20px', el.style.height);
}

function testGetSize() {
  var el = $('testEl');
  goog.style.setSize(el, 100, 100);

  var dims = goog.style.getSize(el);
  assertEquals(100, dims.width);
  assertEquals(100, dims.height);

  goog.style.setStyle(el, 'display', 'none');
  dims = goog.style.getSize(el);
  assertEquals(100, dims.width);
  assertEquals(100, dims.height);

  el = $('testEl5');
  goog.style.setSize(el, 100, 100);
  dims = goog.style.getSize(el);
  assertEquals(100, dims.width);
  assertEquals(100, dims.height);

  el = $('span0');
  dims = goog.style.getSize(el);
  assertNotEquals(0, dims.width);
  assertNotEquals(0, dims.height);

  el = $('table1');
  dims = goog.style.getSize(el);
  assertNotEquals(0, dims.width);
  assertNotEquals(0, dims.height);

  el = $('td1');
  dims = goog.style.getSize(el);
  assertNotEquals(0, dims.width);
  assertNotEquals(0, dims.height);

  el = $('li1');
  dims = goog.style.getSize(el);
  assertNotEquals(0, dims.width);
  assertNotEquals(0, dims.height);

  el = goog.dom.getElementsByTagNameAndClass(goog.dom.TagName.HTML)[0];
  dims = goog.style.getSize(el);
  assertNotEquals(0, dims.width);
  assertNotEquals(0, dims.height);

  el = goog.dom.getElementsByTagNameAndClass(goog.dom.TagName.BODY)[0];
  dims = goog.style.getSize(el);
  assertNotEquals(0, dims.width);
  assertNotEquals(0, dims.height);
}

function testGetSizeSvgElements() {
  var svgEl = document.createElementNS &&
      document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  if (!svgEl || svgEl.getAttribute('transform') == '' ||
      (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher(534.8))) {
    // SVG not supported, or getBoundingClientRect not supported on SVG
    // elements.
    return;
  }

  document.body.appendChild(svgEl);
  var el = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
  el.setAttribute('x', 10);
  el.setAttribute('y', 10);
  el.setAttribute('width', 32);
  el.setAttribute('height', 21);
  el.setAttribute('fill', '#000');

  svgEl.appendChild(el);

  // The bounding size in 1 larger than the SVG element in IE.
  var expectedWidth = (goog.userAgent.EDGE_OR_IE) ? 33 : 32;
  var expectedHeight = (goog.userAgent.EDGE_OR_IE) ? 22 : 21;

  var dims = goog.style.getSize(el);
  assertEquals(expectedWidth, dims.width);
  assertRoughlyEquals(expectedHeight, dims.height, 0.01);

  dims = goog.style.getSize(svgEl);
  // The size of the  will be the viewport size on all browsers. This used
  // to not be true for Firefox, but they fixed the glitch in Firefox 33.
  // https://bugzilla.mozilla.org/show_bug.cgi?id=530985
  assertTrue(dims.width >= expectedWidth);
  assertTrue(dims.height >= expectedHeight);

  el.style.visibility = 'none';

  dims = goog.style.getSize(el);
  assertEquals(expectedWidth, dims.width);
  assertRoughlyEquals(expectedHeight, dims.height, 0.01);

  dims = goog.style.getSize(svgEl);
  assertTrue(dims.width >= expectedWidth);
  assertTrue(dims.height >= expectedHeight);
}

function testGetSizeSvgDocument() {
  var svgEl = document.createElementNS &&
      document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  if (!svgEl || svgEl.getAttribute('transform') == '' ||
      (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher(534.8))) {
    // SVG not supported, or getBoundingClientRect not supported on SVG
    // elements.
    return;
  }

  var frame = goog.dom.getElement('svg-frame');
  var doc = goog.dom.getFrameContentDocument(frame);
  var rect = doc.getElementById('rect');
  var dims = goog.style.getSize(rect);
  if (!goog.userAgent.EDGE_OR_IE) {
    assertEquals(50, dims.width);
    assertEquals(50, dims.height);
  } else {
    assertEquals(51, dims.width);
    assertEquals(51, dims.height);
  }
}

function testGetSizeInlineBlock() {
  var el = $('height-test-inner');
  var dims = goog.style.getSize(el);
  assertNotEquals(0, dims.height);
}

function testGetSizeTransformedRotated() {
  if (!hasWebkitTransform()) return;

  var el = $('rotated');
  goog.style.setSize(el, 300, 200);

  var noRotateDims = goog.style.getTransformedSize(el);
  assertEquals(300, noRotateDims.width);
  assertEquals(200, noRotateDims.height);

  el.style.webkitTransform = 'rotate(180deg)';
  var rotate180Dims = goog.style.getTransformedSize(el);
  assertEquals(300, rotate180Dims.width);
  assertEquals(200, rotate180Dims.height);

  el.style.webkitTransform = 'rotate(90deg)';
  var rotate90ClockwiseDims = goog.style.getTransformedSize(el);
  assertEquals(200, rotate90ClockwiseDims.width);
  assertEquals(300, rotate90ClockwiseDims.height);

  el.style.webkitTransform = 'rotate(-90deg)';
  var rotate90CounterClockwiseDims = goog.style.getTransformedSize(el);
  assertEquals(200, rotate90CounterClockwiseDims.width);
  assertEquals(300, rotate90CounterClockwiseDims.height);
}

function testGetSizeTransformedScaled() {
  if (!hasWebkitTransform()) return;

  var el = $('scaled');
  goog.style.setSize(el, 300, 200);

  var noScaleDims = goog.style.getTransformedSize(el);
  assertEquals(300, noScaleDims.width);
  assertEquals(200, noScaleDims.height);

  el.style.webkitTransform = 'scale(2, 0.5)';
  var scaledDims = goog.style.getTransformedSize(el);
  assertEquals(600, scaledDims.width);
  assertEquals(100, scaledDims.height);
}

function hasWebkitTransform() {
  return 'webkitTransform' in document.body.style;
}

function testGetSizeOfOrphanElement() {
  var orphanElem = document.createElement(goog.dom.TagName.DIV);
  var size = goog.style.getSize(orphanElem);
  assertEquals(0, size.width);
  assertEquals(0, size.height);
}

function testGetBounds() {
  var el = $('testEl');

  var dims = goog.style.getSize(el);
  var pos = goog.style.getPageOffset(el);

  var rect = goog.style.getBounds(el);

  // Relies on getSize and getPageOffset being correct.
  assertEquals(dims.width, rect.width);
  assertEquals(dims.height, rect.height);
  assertEquals(pos.x, rect.left);
  assertEquals(pos.y, rect.top);
}

function testInstallStyles() {
  var el = $('installTest0');
  var originalBackground = goog.style.getBackgroundColor(el);

  // Uses background-color because it's easy to get the computed value
  var result = goog.style.installStyles(
      '#installTest0 { background-color: rgb(255, 192, 203); }');

  assertColorRgbEquals('rgb(255,192,203)', goog.style.getBackgroundColor(el));

  goog.style.uninstallStyles(result);
  assertEquals(originalBackground, goog.style.getBackgroundColor(el));
}

function testInstallSafeStyleSheet() {
  var el = $('installTest0');
  var originalBackground = goog.style.getBackgroundColor(el);

  // Uses background-color because it's easy to get the computed value
  var result = goog.style.installSafeStyleSheet(
      goog.html.testing.newSafeStyleSheetForTest(
          '#installTest0 { background-color: rgb(255, 192, 203); }'));

  assertColorRgbEquals('rgb(255,192,203)', goog.style.getBackgroundColor(el));

  goog.style.uninstallStyles(result);
  assertEquals(originalBackground, goog.style.getBackgroundColor(el));
}

function testSetStyles() {
  var el = $('installTest1');

  // Change to pink
  var ss = goog.style.installStyles(
      '#installTest1 { background-color: rgb(255, 192, 203); }');

  assertColorRgbEquals('rgb(255,192,203)', goog.style.getBackgroundColor(el));

  // Now change to orange
  goog.style.setStyles(
      ss, '#installTest1 { background-color: rgb(255, 255, 0); }');
  assertColorRgbEquals('rgb(255,255,0)', goog.style.getBackgroundColor(el));
}

function testSetSafeStyleSheet() {
  var el = $('installTest1');

  // Change to pink
  var ss = goog.style.installSafeStyleSheet(
      goog.html.testing.newSafeStyleSheetForTest(
          '#installTest1 { background-color: rgb(255, 192, 203); }'));

  assertColorRgbEquals('rgb(255,192,203)', goog.style.getBackgroundColor(el));

  // Now change to orange
  goog.style.setSafeStyleSheet(ss,
      goog.html.testing.newSafeStyleSheetForTest(
          '#installTest1 { background-color: rgb(255, 255, 0); }'));
  assertColorRgbEquals('rgb(255,255,0)', goog.style.getBackgroundColor(el));
}

function assertColorRgbEquals(expected, actual) {
  assertEquals(
      expected, goog.color.hexToRgbStyle(goog.color.parse(actual).hex));
}

function testIsRightToLeft() {
  assertFalse(goog.style.isRightToLeft($('rtl1')));
  assertTrue(goog.style.isRightToLeft($('rtl2')));
  assertFalse(goog.style.isRightToLeft($('rtl3')));
  assertFalse(goog.style.isRightToLeft($('rtl4')));
  assertTrue(goog.style.isRightToLeft($('rtl5')));
  assertFalse(goog.style.isRightToLeft($('rtl6')));
  assertTrue(goog.style.isRightToLeft($('rtl7')));
  assertFalse(goog.style.isRightToLeft($('rtl8')));
  assertTrue(goog.style.isRightToLeft($('rtl9')));
  assertFalse(goog.style.isRightToLeft($('rtl10')));
}

function testIsUnselectable() {
  assertEquals(
      goog.userAgent.GECKO, goog.style.isUnselectable($('unselectable-gecko')));
  assertEquals(
      goog.userAgent.IE || goog.userAgent.OPERA,
      goog.style.isUnselectable($('unselectable-ie')));
  assertEquals(
      goog.userAgent.WEBKIT || goog.userAgent.EDGE,
      goog.style.isUnselectable($('unselectable-webkit')));
}

function testSetUnselectable() {
  var el = $('make-unselectable');
  assertFalse(goog.style.isUnselectable(el));

  function assertDescendantsUnselectable(unselectable) {
    goog.array.forEach(el.getElementsByTagName('*'), function(descendant) {
      // Skip MathML or any other elements that do not have a style property.
      if (descendant.style) {
        assertEquals(unselectable, goog.style.isUnselectable(descendant));
      }
    });
  }

  goog.style.setUnselectable(el, true);
  assertTrue(goog.style.isUnselectable(el));
  assertDescendantsUnselectable(true);

  goog.style.setUnselectable(el, false);
  assertFalse(goog.style.isUnselectable(el));
  assertDescendantsUnselectable(false);

  goog.style.setUnselectable(el, true, true);
  assertTrue(goog.style.isUnselectable(el));
  assertDescendantsUnselectable(false);

  goog.style.setUnselectable(el, false, true);
  assertFalse(goog.style.isUnselectable(el));
  assertDescendantsUnselectable(false);
}

function testPosWithAbsoluteAndScroll() {
  var el = $('pos-scroll-abs');
  var el1 = $('pos-scroll-abs-1');
  var el2 = $('pos-scroll-abs-2');

  el1.scrollTop = 200;
  var pos = goog.style.getPageOffset(el2);

  assertEquals(200, pos.x);
  // Don't bother with IE in quirks mode
  if (!goog.userAgent.IE || document.compatMode == 'CSS1Compat') {
    assertRoughlyEquals(300, pos.y, .1);
  }
}

function testPosWithAbsoluteAndWindowScroll() {
  window.scrollBy(0, 200);
  var el = $('abs-upper-left');
  var pos = goog.style.getPageOffset(el);
  assertRoughlyEquals('Top should be about 0', 0, pos.y, 0.1);
}

function testGetBorderBoxSize() {
  // Strict mode
  var getBorderBoxSize = goog.style.getBorderBoxSize;

  var el = $('size-a');
  var rect = getBorderBoxSize(el);
  assertEquals('width:100px', 100, rect.width);
  assertEquals('height:100px', 100, rect.height);

  // with border: 10px
  el = $('size-b');
  rect = getBorderBoxSize(el);
  assertEquals('width:100px;border:10px', isBorderBox ? 100 : 120, rect.width);
  assertEquals(
      'height:100px;border:10px', isBorderBox ? 100 : 120, rect.height);

  // with border: 10px; padding: 10px
  el = $('size-c');
  rect = getBorderBoxSize(el);
  assertEquals(
      'width:100px;border:10px;padding:10px', isBorderBox ? 100 : 140,
      rect.width);
  assertEquals(
      'height:100px;border:10px;padding:10px', isBorderBox ? 100 : 140,
      rect.height);

  // size, padding and borders are all in non pixel units
  // all we test here is that we get a number out
  el = $('size-d');
  rect = getBorderBoxSize(el);
  assertEquals('number', typeof rect.width);
  assertEquals('number', typeof rect.height);
  assertFalse(isNaN(rect.width));
  assertFalse(isNaN(rect.height));
}

function testGetContentBoxSize() {
  // Strict mode
  var getContentBoxSize = goog.style.getContentBoxSize;

  var el = $('size-a');
  var rect = getContentBoxSize(el);
  assertEquals('width:100px', 100, rect.width);
  assertEquals('height:100px', 100, rect.height);

  // with border: 10px
  el = $('size-b');
  rect = getContentBoxSize(el);
  assertEquals('width:100px;border:10px', isBorderBox ? 80 : 100, rect.width);
  assertEquals('height:100px;border:10px', isBorderBox ? 80 : 100, rect.height);

  // with border: 10px; padding: 10px
  el = $('size-c');
  rect = getContentBoxSize(el);
  assertEquals(
      'width:100px;border:10px;padding:10px', isBorderBox ? 60 : 100,
      rect.width);
  assertEquals(
      'height:100px;border:10px;padding:10px', isBorderBox ? 60 : 100,
      rect.height);

  // size, padding and borders are all in non pixel units
  // all we test here is that we get a number out
  el = $('size-d');
  rect = getContentBoxSize(el);
  assertEquals('number', typeof rect.width);
  assertEquals('number', typeof rect.height);
  assertFalse(isNaN(rect.width));
  assertFalse(isNaN(rect.height));

  // test whether getContentBoxSize works when width and height
  // aren't explicitly set, but the default of 'auto'.
  // 'size-f' has no margin, border, or padding, so offsetWidth/Height
  // should match the content box size
  el = $('size-f');
  rect = getContentBoxSize(el);
  assertEquals(el.offsetWidth, rect.width);
  assertEquals(el.offsetHeight, rect.height);
}

function testSetBorderBoxSize() {
  // Strict mode
  var el = $('size-e');
  var Size = goog.math.Size;
  var setBorderBoxSize = goog.style.setBorderBoxSize;

  // Clean up
  // style element has 100x100, no border and no padding
  el.style.padding = '';
  el.style.margin = '';
  el.style.borderWidth = '';
  el.style.width = '';
  el.style.height = '';

  setBorderBoxSize(el, new Size(100, 100));

  assertEquals(100, el.offsetWidth);
  assertEquals(100, el.offsetHeight);

  el.style.borderWidth = '10px';
  setBorderBoxSize(el, new Size(100, 100));

  assertEquals('width:100px;border:10px', 100, el.offsetWidth);
  assertEquals('height:100px;border:10px', 100, el.offsetHeight);

  el.style.padding = '10px';
  setBorderBoxSize(el, new Size(100, 100));
  assertEquals(100, el.offsetWidth);
  assertEquals(100, el.offsetHeight);

  el.style.borderWidth = '0';
  setBorderBoxSize(el, new Size(100, 100));
  assertEquals(100, el.offsetWidth);
  assertEquals(100, el.offsetHeight);

  if (goog.userAgent.GECKO) {
    assertEquals('border-box', el.style.MozBoxSizing);
  } else if (goog.userAgent.WEBKIT) {
    assertEquals('border-box', el.style.WebkitBoxSizing);
  } else if (
      goog.userAgent.OPERA ||
      goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(8)) {
    assertEquals('border-box', el.style.boxSizing);
  }

  // Try a negative width/height.
  setBorderBoxSize(el, new Size(-10, -10));

  // Setting the border box smaller than the borders will just give you
  // a content box of size 0.
  // NOTE(nicksantos): I'm not really sure why IE7 is special here.
  var isIeLt8Quirks = goog.userAgent.IE &&
      !goog.userAgent.isDocumentModeOrHigher(8) && !goog.dom.isCss1CompatMode();
  assertEquals(20, el.offsetWidth);
  assertEquals(isIeLt8Quirks ? 39 : 20, el.offsetHeight);
}

function testSetContentBoxSize() {
  // Strict mode
  var el = $('size-e');
  var Size = goog.math.Size;
  var setContentBoxSize = goog.style.setContentBoxSize;

  // Clean up
  // style element has 100x100, no border and no padding
  el.style.padding = '';
  el.style.margin = '';
  el.style.borderWidth = '';
  el.style.width = '';
  el.style.height = '';

  setContentBoxSize(el, new Size(100, 100));

  assertEquals(100, el.offsetWidth);
  assertEquals(100, el.offsetHeight);

  el.style.borderWidth = '10px';
  setContentBoxSize(el, new Size(100, 100));
  assertEquals('width:100px;border-width:10px', 120, el.offsetWidth);
  assertEquals('height:100px;border-width:10px', 120, el.offsetHeight);

  el.style.padding = '10px';
  setContentBoxSize(el, new Size(100, 100));
  assertEquals(
      'width:100px;border-width:10px;padding:10px', 140, el.offsetWidth);
  assertEquals(
      'height:100px;border-width:10px;padding:10px', 140, el.offsetHeight);

  el.style.borderWidth = '0';
  setContentBoxSize(el, new Size(100, 100));
  assertEquals('width:100px;padding:10px', 120, el.offsetWidth);
  assertEquals('height:100px;padding:10px', 120, el.offsetHeight);

  if (goog.userAgent.GECKO) {
    assertEquals('content-box', el.style.MozBoxSizing);
  } else if (goog.userAgent.WEBKIT) {
    assertEquals('content-box', el.style.WebkitBoxSizing);
  } else if (
      goog.userAgent.OPERA ||
      goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(8)) {
    assertEquals('content-box', el.style.boxSizing);
  }

  // Try a negative width/height.
  setContentBoxSize(el, new Size(-10, -10));

  // NOTE(nicksantos): I'm not really sure why IE7 is special here.
  var isIeLt8Quirks = goog.userAgent.IE &&
      !goog.userAgent.isDocumentModeOrHigher('8') &&
      !goog.dom.isCss1CompatMode();
  assertEquals(20, el.offsetWidth);
  assertEquals(isIeLt8Quirks ? 39 : 20, el.offsetHeight);
}

function testGetPaddingBox() {
  // Strict mode
  var el = $('size-e');
  var Size = goog.math.Size;
  var getPaddingBox = goog.style.getPaddingBox;

  // Clean up
  // style element has 100x100, no border and no padding
  el.style.padding = '';
  el.style.margin = '';
  el.style.borderWidth = '';
  el.style.width = '';
  el.style.height = '';

  el.style.padding = '10px';
  var rect = getPaddingBox(el);
  assertEquals(10, rect.left);
  assertEquals(10, rect.right);
  assertEquals(10, rect.top);
  assertEquals(10, rect.bottom);

  el.style.padding = '0';
  rect = getPaddingBox(el);
  assertEquals(0, rect.left);
  assertEquals(0, rect.right);
  assertEquals(0, rect.top);
  assertEquals(0, rect.bottom);

  el.style.padding = '1px 2px 3px 4px';
  rect = getPaddingBox(el);
  assertEquals(1, rect.top);
  assertEquals(2, rect.right);
  assertEquals(3, rect.bottom);
  assertEquals(4, rect.left);

  el.style.padding = '1mm 2em 3ex 4%';
  rect = getPaddingBox(el);
  assertFalse(isNaN(rect.top));
  assertFalse(isNaN(rect.right));
  assertFalse(isNaN(rect.bottom));
  assertFalse(isNaN(rect.left));
  assertTrue(rect.top >= 0);
  assertTrue(rect.right >= 0);
  assertTrue(rect.bottom >= 0);
  assertTrue(rect.left >= 0);
}

function testGetPaddingBoxUnattached() {
  var el = document.createElement(goog.dom.TagName.DIV);
  var box = goog.style.getPaddingBox(el);
  if (goog.userAgent.WEBKIT) {
    assertTrue(isNaN(box.top));
    assertTrue(isNaN(box.right));
    assertTrue(isNaN(box.bottom));
    assertTrue(isNaN(box.left));
  } else {
    assertObjectEquals(new goog.math.Box(0, 0, 0, 0), box);
  }
}

function testGetMarginBox() {
  // Strict mode
  var el = $('size-e');
  var Size = goog.math.Size;
  var getMarginBox = goog.style.getMarginBox;

  // Clean up
  // style element has 100x100, no border and no padding
  el.style.padding = '';
  el.style.margin = '';
  el.style.borderWidth = '';
  el.style.width = '';
  el.style.height = '';

  el.style.margin = '10px';
  var rect = getMarginBox(el);
  assertEquals(10, rect.left);
  // In webkit the right margin is the calculated distance from right edge and
  // not the computed right margin so it is not reliable.
  // See https://bugs.webkit.org/show_bug.cgi?id=19828
  if (!goog.userAgent.WEBKIT) {
    assertEquals(10, rect.right);
  }
  assertEquals(10, rect.top);
  assertEquals(10, rect.bottom);

  el.style.margin = '0';
  rect = getMarginBox(el);
  assertEquals(0, rect.left);
  // In webkit the right margin is the calculated distance from right edge and
  // not the computed right margin so it is not reliable.
  // See https://bugs.webkit.org/show_bug.cgi?id=19828
  if (!goog.userAgent.WEBKIT) {
    assertEquals(0, rect.right);
  }
  assertEquals(0, rect.top);
  assertEquals(0, rect.bottom);

  el.style.margin = '1px 2px 3px 4px';
  rect = getMarginBox(el);
  assertEquals(1, rect.top);
  // In webkit the right margin is the calculated distance from right edge and
  // not the computed right margin so it is not reliable.
  // See https://bugs.webkit.org/show_bug.cgi?id=19828
  if (!goog.userAgent.WEBKIT) {
    assertEquals(2, rect.right);
  }
  assertEquals(3, rect.bottom);
  assertEquals(4, rect.left);

  el.style.margin = '1mm 2em 3ex 4%';
  rect = getMarginBox(el);
  assertFalse(isNaN(rect.top));
  assertFalse(isNaN(rect.right));
  assertFalse(isNaN(rect.bottom));
  assertFalse(isNaN(rect.left));
  assertTrue(rect.top >= 0);
  // In webkit the right margin is the calculated distance from right edge and
  // not the computed right margin so it is not reliable.
  // See https://bugs.webkit.org/show_bug.cgi?id=19828
  if (!goog.userAgent.WEBKIT) {
    assertTrue(rect.right >= 0);
  }
  assertTrue(rect.bottom >= 0);
  assertTrue(rect.left >= 0);
}

function testGetBorderBox() {
  // Strict mode
  var el = $('size-e');
  var Size = goog.math.Size;
  var getBorderBox = goog.style.getBorderBox;

  // Clean up
  // style element has 100x100, no border and no padding
  el.style.padding = '';
  el.style.margin = '';
  el.style.borderWidth = '';
  el.style.width = '';
  el.style.height = '';

  el.style.borderWidth = '10px';
  var rect = getBorderBox(el);
  assertEquals(10, rect.left);
  assertEquals(10, rect.right);
  assertEquals(10, rect.top);
  assertEquals(10, rect.bottom);

  el.style.borderWidth = '0';
  rect = getBorderBox(el);
  assertEquals(0, rect.left);
  assertEquals(0, rect.right);
  assertEquals(0, rect.top);
  assertEquals(0, rect.bottom);

  el.style.borderWidth = '1px 2px 3px 4px';
  rect = getBorderBox(el);
  assertEquals(1, rect.top);
  assertEquals(2, rect.right);
  assertEquals(3, rect.bottom);
  assertEquals(4, rect.left);

  // % does not work for border widths in IE
  el.style.borderWidth = '1mm 2em 3ex 4pt';
  rect = getBorderBox(el);
  assertFalse(isNaN(rect.top));
  assertFalse(isNaN(rect.right));
  assertFalse(isNaN(rect.bottom));
  assertFalse(isNaN(rect.left));
  assertTrue(rect.top >= 0);
  assertTrue(rect.right >= 0);
  assertTrue(rect.bottom >= 0);
  assertTrue(rect.left >= 0);

  el.style.borderWidth = 'thin medium thick 1px';
  rect = getBorderBox(el);
  assertFalse(isNaN(rect.top));
  assertFalse(isNaN(rect.right));
  assertFalse(isNaN(rect.bottom));
  assertFalse(isNaN(rect.left));
  assertTrue(rect.top >= 0);
  assertTrue(rect.right >= 0);
  assertTrue(rect.bottom >= 0);
  assertTrue(rect.left >= 0);
}

function testGetFontFamily() {
  // I tried to use common fonts for these tests. It's possible the test fails
  // because the testing platform doesn't have one of these fonts installed:
  //   Comic Sans MS or Century Schoolbook L
  //   Times
  //   Helvetica

  var tmpFont = goog.style.getFontFamily($('font-tag'));
  assertTrue(
      'FontFamily should be detectable when set via ',
      'Times' == tmpFont || 'Times New Roman' == tmpFont);
  tmpFont = goog.style.getFontFamily($('small-text'));
  assertTrue(
      'Multiword fonts should be reported with quotes stripped.',
      'Comic Sans MS' == tmpFont || 'Century Schoolbook L' == tmpFont);
  // Firefox fails this test & retuns a generic 'monospace' instead of the
  // actually displayed font (e.g., "Times New").
  // tmpFont = goog.style.getFontFamily($('pre-font'));
  // assertEquals('
 tags should use a fixed-width font',
  //             'Times New',
  //             tmpFont);
  tmpFont = goog.style.getFontFamily($('inherit-font'));
  assertEquals(
      'Explicitly inherited fonts should be detectable', 'Helvetica', tmpFont);
  tmpFont = goog.style.getFontFamily($('times-font-family'));
  assertEquals(
      'Font-family set via style attribute should be detected', 'Times',
      tmpFont);
  tmpFont = goog.style.getFontFamily($('bold-font'));
  assertEquals(
      'Implicitly inherited font should be detected', 'Helvetica', tmpFont);
  tmpFont = goog.style.getFontFamily($('css-html-tag-redefinition'));
  assertEquals('HTML tag CSS rewrites should be detected', 'Times', tmpFont);
  tmpFont = goog.style.getFontFamily($('no-text-font-styles'));
  assertEquals(
      'Font family should exist even with no text', 'Helvetica', tmpFont);
  tmpFont = goog.style.getFontFamily($('icon-font'));
  assertNotEquals(
      'icon is a special font-family value', 'icon', tmpFont.toLowerCase());
  tmpFont = goog.style.getFontFamily($('font-style-badfont'));
  // Firefox fails this test and reports the specified "badFont", which is
  // obviously not displayed.
  // assertEquals('Invalid fonts should not be returned',
  //             'Helvetica',
  //             tmpFont);
  tmpFont = goog.style.getFontFamily($('img-font-test'));
  assertTrue(
      'Even img tags should inherit the document body\'s font', tmpFont != '');
  tmpFont = goog.style.getFontFamily($('nested-font'));
  assertEquals(
      'An element with nested content should be unaffected.', 'Arial', tmpFont);
  // IE raises an 'Invalid Argument' error when using the moveToElementText
  // method from the TextRange object with an element that is not attached to
  // a document.
  var element = goog.dom.createDom(
      goog.dom.TagName.SPAN, {style: 'font-family:Times,sans-serif;'},
      'some text');
  tmpFont = goog.style.getFontFamily(element);
  assertEquals(
      'Font should be correctly retrieved for element not attached' +
          ' to a document',
      'Times', tmpFont);
}

function testGetFontSize() {
  assertEquals(
      'Font size should be determined even without any text', 30,
      goog.style.getFontSize($('no-text-font-styles')));
  assertEquals(
      'A 5em font should be 5x larger than its parent.', 150,
      goog.style.getFontSize($('css-html-tag-redefinition')));
  assertTrue(
      'Setting font size=-1 should result in a positive font size.',
      goog.style.getFontSize($('font-tag')) > 0);
  assertEquals(
      'Inheriting a 50% font-size should have no additional effect',
      goog.style.getFontSize($('font-style-badfont')),
      goog.style.getFontSize($('inherit-50pct-font')));
  assertTrue(
      'In pretty much any display, 3in should be > 8px',
      goog.style.getFontSize($('times-font-family')) >
          goog.style.getFontSize($('no-text-font-styles')));
  assertTrue(
      'With no applied styles, font-size should still be defined.',
      goog.style.getFontSize($('no-font-style')) > 0);
  assertEquals(
      '50% of 30px is 15', 15, goog.style.getFontSize($('font-style-badfont')));
  assertTrue(
      'x-small text should be smaller than small text',
      goog.style.getFontSize($('x-small-text')) <
          goog.style.getFontSize($('small-text')));
  // IE fails this test, the decimal portion of px lengths isn't reported
  // by getCascadedStyle. Firefox passes, but only because it ignores the
  // decimals altogether.
  // assertEquals('12.5px should be the same as 0.5em nested in a 25px node.',
  //             goog.style.getFontSize($('font-size-12-point-5-px')),
  //             goog.style.getFontSize($('font-size-50-pct-of-25-px')));

  assertEquals(
      'Font size should not doubly count em values', 2,
      goog.style.getFontSize($('em-font-size')));
}

function testGetLengthUnits() {
  assertEquals('px', goog.style.getLengthUnits('15px'));
  assertEquals('%', goog.style.getLengthUnits('99%'));
  assertNull(goog.style.getLengthUnits(''));
}

function testParseStyleAttribute() {
  var css = 'left: 0px; text-align: center';
  var expected = {'left': '0px', 'textAlign': 'center'};

  assertObjectEquals(expected, goog.style.parseStyleAttribute(css));
}

function testToStyleAttribute() {
  var object = {'left': '0px', 'textAlign': 'center'};
  var expected = 'left:0px;text-align:center;';

  assertEquals(expected, goog.style.toStyleAttribute(object));
}

function testStyleAttributePassthrough() {
  var object = {'left': '0px', 'textAlign': 'center'};

  assertObjectEquals(
      object,
      goog.style.parseStyleAttribute(goog.style.toStyleAttribute(object)));
}

function testGetFloat() {
  assertEquals('', goog.style.getFloat($('no-float')));
  assertEquals('none', goog.style.getFloat($('float-none')));
  assertEquals('left', goog.style.getFloat($('float-left')));
}

function testSetFloat() {
  var el = $('float-test');

  goog.style.setFloat(el, 'left');
  assertEquals('left', goog.style.getFloat(el));

  goog.style.setFloat(el, 'right');
  assertEquals('right', goog.style.getFloat(el));

  goog.style.setFloat(el, 'none');
  assertEquals('none', goog.style.getFloat(el));

  goog.style.setFloat(el, '');
  assertEquals('', goog.style.getFloat(el));
}

function testIsElementShown() {
  var el = $('testEl');

  goog.style.setElementShown(el, false);
  assertFalse(goog.style.isElementShown(el));

  goog.style.setElementShown(el, true);
  assertTrue(goog.style.isElementShown(el));
}

function testGetOpacity() {
  var el1 = {style: {opacity: '0.3'}};

  var el2 = {style: {MozOpacity: '0.1'}};

  var el3 = {
    style: {filter: 'some:other,filter;alpha(opacity=25.5);alpha(more=100);'}
  };

  assertEquals(0.3, goog.style.getOpacity(el1));
  assertEquals(0.1, goog.style.getOpacity(el2));
  assertEquals(0.255, goog.style.getOpacity(el3));

  el1.style.opacity = '0';
  el2.style.MozOpacity = '0';
  el3.style.filter = 'some:other,filter;alpha(opacity=0);alpha(more=100);';

  assertEquals(0, goog.style.getOpacity(el1));
  assertEquals(0, goog.style.getOpacity(el2));
  assertEquals(0, goog.style.getOpacity(el3));

  el1.style.opacity = '';
  el2.style.MozOpacity = '';
  el3.style.filter = '';

  assertEquals('', goog.style.getOpacity(el1));
  assertEquals('', goog.style.getOpacity(el2));
  assertEquals('', goog.style.getOpacity(el3));

  var el4 = {style: {}};

  assertEquals('', goog.style.getOpacity(el4));
  assertEquals('', goog.style.getOpacity($('test-opacity')));
}

function testSetOpacity() {
  var el1 = {style: {opacity: '0.3'}};
  goog.style.setOpacity(el1, 0.8);

  var el2 = {style: {MozOpacity: '0.1'}};
  goog.style.setOpacity(el2, 0.5);

  var el3 = {style: {filter: 'alpha(opacity=25)'}};
  goog.style.setOpacity(el3, 0.1);

  assertEquals(0.8, Number(el1.style.opacity));
  assertEquals(0.5, Number(el2.style.MozOpacity));
  assertEquals('alpha(opacity=10)', el3.style.filter);

  goog.style.setOpacity(el1, 0);
  goog.style.setOpacity(el2, 0);
  goog.style.setOpacity(el3, 0);

  assertEquals(0, Number(el1.style.opacity));
  assertEquals(0, Number(el2.style.MozOpacity));
  assertEquals('alpha(opacity=0)', el3.style.filter);

  goog.style.setOpacity(el1, '');
  goog.style.setOpacity(el2, '');
  goog.style.setOpacity(el3, '');

  assertEquals('', el1.style.opacity);
  assertEquals('', el2.style.MozOpacity);
  assertEquals('', el3.style.filter);
}

function testFramedPageOffset() {
  // Set up a complicated iframe ancestor chain.
  var iframe = goog.dom.getElement('test-frame-offset');
  var iframeDoc = goog.dom.getFrameContentDocument(iframe);
  var iframeWindow = goog.dom.getWindow(iframeDoc);

  var iframePos = 'style="display:block;position:absolute;' +
      'top:50px;left:50px;width:50px;height:50px;"';
  iframeDoc.write(
      '' +
      '
hi mom!
'); iframeDoc.close(); var iframe2 = iframeDoc.getElementById('test-frame-offset-2'); var testElement2 = iframeDoc.getElementById('test-element-2'); var iframeDoc2 = goog.dom.getFrameContentDocument(iframe2); var iframeWindow2 = goog.dom.getWindow(iframeDoc2); iframeDoc2.write( '
hi mom!
'); iframeDoc2.close(); var testElement3 = iframeDoc2.getElementById('test-element-3'); assertCoordinateApprox(300, 300, 0, goog.style.getPageOffset(testElement2)); assertCoordinateApprox(500, 500, 0, goog.style.getPageOffset(testElement3)); assertCoordinateApprox( 350, 350, 0, goog.style.getFramedPageOffset(testElement2, window)); assertCoordinateApprox( 300, 300, 0, goog.style.getFramedPageOffset(testElement2, iframeWindow)); assertCoordinateApprox( 600, 600, 0, goog.style.getFramedPageOffset(testElement3, window)); assertCoordinateApprox( 550, 550, 0, goog.style.getFramedPageOffset(testElement3, iframeWindow)); assertCoordinateApprox( 500, 500, 0, goog.style.getFramedPageOffset(testElement3, iframeWindow2)); // Scroll the iframes a bit. window.scrollBy(0, 5); iframeWindow.scrollBy(0, 11); iframeWindow2.scrollBy(0, 18); // On Firefox 2, scrolling inner iframes causes off by one errors // in the page position, because we're using screen coords to compute them. assertCoordinateApprox(300, 300, 2, goog.style.getPageOffset(testElement2)); assertCoordinateApprox(500, 500, 2, goog.style.getPageOffset(testElement3)); assertCoordinateApprox( 350, 350 - 11, 2, goog.style.getFramedPageOffset(testElement2, window)); assertCoordinateApprox( 300, 300, 2, goog.style.getFramedPageOffset(testElement2, iframeWindow)); assertCoordinateApprox( 600, 600 - 18 - 11, 2, goog.style.getFramedPageOffset(testElement3, window)); assertCoordinateApprox( 550, 550 - 18, 2, goog.style.getFramedPageOffset(testElement3, iframeWindow)); assertCoordinateApprox( 500, 500, 2, goog.style.getFramedPageOffset(testElement3, iframeWindow2)); // In IE, if the element is in a frame that's been removed from the DOM and // relativeWin is not that frame's contentWindow, the contentWindow's parent // reference points to itself. We want to guarantee that we don't fall into // an infinite loop. var iframeParent = iframe.parentElement; iframeParent.removeChild(iframe); // We don't check the value returned as it differs by browser. 0,0 for Chrome // and FF. IE returns 30000 or 30198 for x in IE8-9 and 300 in IE10-11 goog.style.getFramedPageOffset(testElement2, window); } /** * Asserts that the coordinate is approximately equal to the given * x and y coordinates, give or take delta. */ function assertCoordinateApprox(x, y, delta, coord) { assertTrue( 'Expected x: ' + x + ', actual x: ' + coord.x, coord.x >= x - delta && coord.x <= x + delta); assertTrue( 'Expected y: ' + y + ', actual y: ' + coord.y, coord.y >= y - delta && coord.y <= y + delta); } function testTranslateRectForAnotherFrame() { var rect = new goog.math.Rect(1, 2, 3, 4); var thisDom = goog.dom.getDomHelper(); goog.style.translateRectForAnotherFrame(rect, thisDom, thisDom); assertEquals(1, rect.left); assertEquals(2, rect.top); assertEquals(3, rect.width); assertEquals(4, rect.height); var iframe = $('test-translate-frame-standard'); var iframeDoc = goog.dom.getFrameContentDocument(iframe); var iframeDom = goog.dom.getDomHelper(iframeDoc); // Cannot rely on iframe starting at origin. iframeDom.getWindow().scrollTo(0, 0); // iframe is at (100, 150) and its body is not scrolled. rect = new goog.math.Rect(1, 2, 3, 4); goog.style.translateRectForAnotherFrame(rect, iframeDom, thisDom); assertEquals(1 + 100, rect.left); assertRoughlyEquals(2 + 150, rect.top, .1); assertEquals(3, rect.width); assertEquals(4, rect.height); iframeDom.getWindow().scrollTo(11, 13); rect = new goog.math.Rect(1, 2, 3, 4); goog.style.translateRectForAnotherFrame(rect, iframeDom, thisDom); assertEquals(1 + 100 - 11, rect.left); assertRoughlyEquals(2 + 150 - 13, rect.top, .1); assertEquals(3, rect.width); assertEquals(4, rect.height); iframe = $('test-translate-frame-quirk'); iframeDoc = goog.dom.getFrameContentDocument(iframe); iframeDom = goog.dom.getDomHelper(iframeDoc); // Cannot rely on iframe starting at origin. iframeDom.getWindow().scrollTo(0, 0); // iframe is at (100, 350) and its body is not scrolled. rect = new goog.math.Rect(1, 2, 3, 4); goog.style.translateRectForAnotherFrame(rect, iframeDom, thisDom); assertEquals(1 + 100, rect.left); assertRoughlyEquals(2 + 350, rect.top, .1); assertEquals(3, rect.width); assertEquals(4, rect.height); iframeDom.getWindow().scrollTo(11, 13); rect = new goog.math.Rect(1, 2, 3, 4); goog.style.translateRectForAnotherFrame(rect, iframeDom, thisDom); assertEquals(1 + 100 - 11, rect.left); assertRoughlyEquals(2 + 350 - 13, rect.top, .1); assertEquals(3, rect.width); assertEquals(4, rect.height); } function testGetVisibleRectForElement() { var container = goog.dom.getElement('test-visible'); var el = goog.dom.getElement('test-visible-el'); var dom = goog.dom.getDomHelper(el); var winScroll = dom.getDocumentScroll(); var winSize = dom.getViewportSize(); // Skip this test if the window size is small. Firefox3/Linux in Selenium // sometimes fails without this check. if (winSize.width < 20 || winSize.height < 20) { return; } // Move the container element to the window's viewport. var h = winSize.height < 100 ? winSize.height / 2 : 100; goog.style.setSize(container, winSize.width / 2, h); goog.style.setPosition(container, 8, winScroll.y + winSize.height - h); var visible = goog.style.getVisibleRectForElement(el); var bounds = goog.style.getBounds(container); // VisibleRect == Bounds rect of the offsetParent assertNotNull(visible); assertEquals(bounds.left, visible.left); assertEquals(bounds.top, visible.top); assertEquals(bounds.left + bounds.width, visible.right); assertEquals(bounds.top + bounds.height, visible.bottom); // Move a part of the container element to outside of the viewpoert. goog.style.setPosition(container, 8, winScroll.y + winSize.height - h / 2); visible = goog.style.getVisibleRectForElement(el); bounds = goog.style.getBounds(container); // Confirm VisibleRect == Intersection of the bounds rect of the // offsetParent and the viewport. assertNotNull(visible); assertEquals(bounds.left, visible.left); assertEquals(bounds.top, visible.top); assertEquals(bounds.left + bounds.width, visible.right); assertEquals(winScroll.y + winSize.height, visible.bottom); // Move the container element to outside of the viewpoert. goog.style.setPosition(container, 8, winScroll.y + winSize.height * 2); visible = goog.style.getVisibleRectForElement(el); assertNull(visible); // Test the case with body element of height 0 var iframe = goog.dom.getElement('test-visible-frame'); var iframeDoc = goog.dom.getFrameContentDocument(iframe); el = iframeDoc.getElementById('test-visible'); visible = goog.style.getVisibleRectForElement(el); var iframeViewportSize = goog.dom.getDomHelper(el).getViewportSize(); // NOTE(chrishenry): For iframe, the clipping viewport is always the iframe // viewport, and not the actual browser viewport. assertNotNull(visible); assertEquals(0, visible.top); assertEquals(iframeViewportSize.height, visible.bottom); assertEquals(0, visible.left); assertEquals(iframeViewportSize.width, visible.right); } function testGetVisibleRectForElementWithBodyScrolled() { var container = goog.dom.getElement('test-visible2'); var dom = goog.dom.getDomHelper(container); var el = dom.createDom(goog.dom.TagName.DIV, undefined, 'Test'); el.style.position = 'absolute'; dom.append(container, el); container.style.position = 'absolute'; goog.style.setPosition(container, 20, 500); goog.style.setSize(container, 100, 150); // Scroll body container such that container is exactly at top. window.scrollTo(0, 500); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(500, visibleRect.top, EPSILON); assertRoughlyEquals(20, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(120, visibleRect.right, EPSILON); // Top 100px is clipped by window viewport. window.scrollTo(0, 600); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(600, visibleRect.top, EPSILON); assertRoughlyEquals(20, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(120, visibleRect.right, EPSILON); var winSize = dom.getViewportSize(); // Left 50px is clipped by window viewport. // Right part is clipped by window viewport. goog.style.setSize(container, 10000, 150); window.scrollTo(70, 500); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(500, visibleRect.top, EPSILON); assertRoughlyEquals(70, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(70 + winSize.width, visibleRect.right, EPSILON); // Bottom part is clipped by window viewport. goog.style.setSize(container, 100, 2000); window.scrollTo(0, 500); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(500, visibleRect.top, EPSILON); assertRoughlyEquals(20, visibleRect.left, EPSILON); assertRoughlyEquals(120, visibleRect.right, EPSILON); assertRoughlyEquals(500 + winSize.height, visibleRect.bottom, EPSILON); goog.style.setPosition(container, 10000, 10000); assertNull(goog.style.getVisibleRectForElement(el)); } function testGetVisibleRectForElementWithNestedAreaAndNonOffsetAncestor() { // IE7 quirks mode somehow consider container2 below as offset parent // of the element, which is incorrect. if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(8) && !goog.dom.isCss1CompatMode()) { return; } var container = goog.dom.getElement('test-visible2'); var dom = goog.dom.getDomHelper(container); var container2 = dom.createDom(goog.dom.TagName.DIV); var el = dom.createDom(goog.dom.TagName.DIV, undefined, 'Test'); el.style.position = 'absolute'; dom.append(container, container2); dom.append(container2, el); container.style.position = 'absolute'; goog.style.setPosition(container, 20, 500); goog.style.setSize(container, 100, 150); // container2 is a scrollable container but is not an offsetParent of // the element. It is ignored in the computation. container2.style.overflow = 'hidden'; container2.style.marginTop = '50px'; container2.style.marginLeft = '100px'; goog.style.setSize(container2, 150, 100); // Scroll body container such that container is exactly at top. window.scrollTo(0, 500); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(500, visibleRect.top, EPSILON); assertRoughlyEquals(20, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(120, visibleRect.right, EPSILON); // Top 100px is clipped by window viewport. window.scrollTo(0, 600); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(600, visibleRect.top, EPSILON); assertRoughlyEquals(20, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(120, visibleRect.right, EPSILON); var winSize = dom.getViewportSize(); // Left 50px is clipped by window viewport. // Right part is clipped by window viewport. goog.style.setSize(container, 10000, 150); window.scrollTo(70, 500); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(500, visibleRect.top, EPSILON); assertRoughlyEquals(70, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(70 + winSize.width, visibleRect.right, EPSILON); // Bottom part is clipped by window viewport. goog.style.setSize(container, 100, 2000); window.scrollTo(0, 500); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(500, visibleRect.top, EPSILON); assertRoughlyEquals(20, visibleRect.left, EPSILON); assertRoughlyEquals(120, visibleRect.right, EPSILON); assertRoughlyEquals(500 + winSize.height, visibleRect.bottom, EPSILON); goog.style.setPosition(container, 10000, 10000); assertNull(goog.style.getVisibleRectForElement(el)); } function testGetVisibleRectForElementInsideNestedScrollableArea() { var container = goog.dom.getElement('test-visible2'); var dom = goog.dom.getDomHelper(container); var container2 = dom.createDom(goog.dom.TagName.DIV); var el = dom.createDom(goog.dom.TagName.DIV, undefined, 'Test'); el.style.position = 'absolute'; dom.append(container, container2); dom.append(container2, el); container.style.position = 'absolute'; goog.style.setPosition(container, 100 /* left */, 500 /* top */); goog.style.setSize(container, 300 /* width */, 300 /* height */); container2.style.overflow = 'hidden'; container2.style.position = 'relative'; goog.style.setPosition(container2, 100, 50); goog.style.setSize(container2, 150, 100); // Scroll body container such that container is exactly at top. window.scrollTo(0, 500); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(550, visibleRect.top, EPSILON); assertRoughlyEquals(200, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(350, visibleRect.right, EPSILON); // Left 50px is clipped by container. goog.style.setPosition(container2, -50, 50); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(550, visibleRect.top, EPSILON); assertRoughlyEquals(100, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(200, visibleRect.right, EPSILON); // Right part is clipped by container. goog.style.setPosition(container2, 100, 50); goog.style.setWidth(container2, 1000, 100); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(550, visibleRect.top, EPSILON); assertRoughlyEquals(200, visibleRect.left, EPSILON); assertRoughlyEquals(650, visibleRect.bottom, EPSILON); assertRoughlyEquals(400, visibleRect.right, EPSILON); // Top 50px is clipped by container. goog.style.setStyle(container2, 'width', '150px'); goog.style.setStyle(container2, 'top', '-50px'); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(500, visibleRect.top, EPSILON); assertRoughlyEquals(200, visibleRect.left, EPSILON); assertRoughlyEquals(550, visibleRect.bottom, EPSILON); assertRoughlyEquals(350, visibleRect.right, EPSILON); // Bottom part is clipped by container. goog.style.setStyle(container2, 'top', '50px'); goog.style.setStyle(container2, 'height', '1000px'); var visibleRect = goog.style.getVisibleRectForElement(el); assertNotNull(visibleRect); assertRoughlyEquals(550, visibleRect.top, EPSILON); assertRoughlyEquals(200, visibleRect.left, EPSILON); assertRoughlyEquals(800, visibleRect.bottom, EPSILON); assertRoughlyEquals(350, visibleRect.right, EPSILON); // Outside viewport. goog.style.setStyle(container2, 'top', '10000px'); goog.style.setStyle(container2, 'left', '10000px'); assertNull(goog.style.getVisibleRectForElement(el)); } function testScrollIntoContainerViewQuirks() { if (goog.dom.isCss1CompatMode()) return; var container = goog.dom.getElement('scrollable-container'); // Scroll the minimum amount to make the elements visible. goog.style.scrollIntoContainerView(goog.dom.getElement('item7'), container); assertEquals('scroll to item7', 79, container.scrollTop); goog.style.scrollIntoContainerView(goog.dom.getElement('item8'), container); assertEquals('scroll to item8', 100, container.scrollTop); goog.style.scrollIntoContainerView(goog.dom.getElement('item7'), container); assertEquals('item7 still visible', 100, container.scrollTop); goog.style.scrollIntoContainerView(goog.dom.getElement('item1'), container); assertEquals('scroll to item1', 17, container.scrollTop); // Center the element in the first argument. goog.style.scrollIntoContainerView( goog.dom.getElement('item1'), container, true); assertEquals('center item1', 0, container.scrollTop); goog.style.scrollIntoContainerView( goog.dom.getElement('item4'), container, true); assertEquals('center item4', 48, container.scrollTop); // The element is higher than the container. goog.dom.getElement('item3').style.height = '140px'; goog.style.scrollIntoContainerView(goog.dom.getElement('item3'), container); assertEquals('show item3 with increased height', 59, container.scrollTop); goog.style.scrollIntoContainerView( goog.dom.getElement('item3'), container, true); assertEquals('center item3 with increased height', 87, container.scrollTop); goog.dom.getElement('item3').style.height = ''; // Scroll to non-integer position. goog.dom.getElement('item4').style.height = '21px'; goog.style.scrollIntoContainerView( goog.dom.getElement('item4'), container, true); assertEquals('scroll position is rounded down', 48, container.scrollTop); goog.dom.getElement('item4').style.height = ''; } function testScrollIntoContainerViewStandard() { if (!goog.dom.isCss1CompatMode()) return; var container = goog.dom.getElement('scrollable-container'); // Scroll the minimum amount to make the elements visible. goog.style.scrollIntoContainerView(goog.dom.getElement('item7'), container); assertEquals('scroll to item7', 115, container.scrollTop); goog.style.scrollIntoContainerView(goog.dom.getElement('item8'), container); assertEquals('scroll to item8', 148, container.scrollTop); goog.style.scrollIntoContainerView(goog.dom.getElement('item7'), container); assertEquals('item7 still visible', 148, container.scrollTop); goog.style.scrollIntoContainerView(goog.dom.getElement('item1'), container); assertEquals('scroll to item1', 17, container.scrollTop); // Center the element in the first argument. goog.style.scrollIntoContainerView( goog.dom.getElement('item1'), container, true); assertEquals('center item1', 0, container.scrollTop); goog.style.scrollIntoContainerView( goog.dom.getElement('item4'), container, true); assertEquals('center item4', 66, container.scrollTop); // The element is higher than the container. goog.dom.getElement('item3').style.height = '140px'; goog.style.scrollIntoContainerView(goog.dom.getElement('item3'), container); assertEquals('show item3 with increased height', 83, container.scrollTop); goog.style.scrollIntoContainerView( goog.dom.getElement('item3'), container, true); assertEquals('center item3 with increased height', 93, container.scrollTop); goog.dom.getElement('item3').style.height = ''; // Scroll to non-integer position. goog.dom.getElement('item4').style.height = '21px'; goog.style.scrollIntoContainerView( goog.dom.getElement('item4'), container, true); assertEquals('scroll position is rounded down', 66, container.scrollTop); goog.dom.getElement('item4').style.height = ''; } function testOffsetParent() { var parent = goog.dom.getElement('offset-parent'); var child = goog.dom.getElement('offset-child'); assertEquals(parent, goog.style.getOffsetParent(child)); } function testOverflowOffsetParent() { var parent = goog.dom.getElement('offset-parent-overflow'); var child = goog.dom.getElement('offset-child-overflow'); assertEquals(parent, goog.style.getOffsetParent(child)); } function testShadowDomOffsetParent() { // Ignore browsers that don't support shadowDOM. if (!document.createShadowRoot) { return; } var parent = goog.dom.createDom(goog.dom.TagName.DIV); parent.style.position = 'relative'; var host = goog.dom.createDom(goog.dom.TagName.DIV); goog.dom.appendChild(parent, host); var root = host.createShadowRoot(); var child = goog.dom.createDom(goog.dom.TagName.DIV); goog.dom.appendChild(root, child); assertEquals(parent, goog.style.getOffsetParent(child)); } function testGetViewportPageOffset() { expectedFailures.expectFailureFor( goog.userAgent.IE && !goog.userAgent.isVersionOrHigher(10), 'Test has been flaky for ie9-win7 and ie8-winxp image. Disabling. ' + 'See b/22873770.'); try { var testViewport = goog.dom.getElement('test-viewport'); testViewport.style.height = '5000px'; testViewport.style.width = '5000px'; var offset = goog.style.getViewportPageOffset(document); assertEquals(0, offset.x); assertEquals(0, offset.y); window.scrollTo(0, 100); offset = goog.style.getViewportPageOffset(document); assertEquals(0, offset.x); assertEquals(100, offset.y); window.scrollTo(100, 0); offset = goog.style.getViewportPageOffset(document); assertEquals(100, offset.x); assertEquals(0, offset.y); } catch (e) { expectedFailures.handleException(e); } } function testGetsTranslation() { var element = document.getElementById('translation'); if (goog.userAgent.IE) { if (!goog.userAgent.isDocumentModeOrHigher(9) || (!goog.dom.isCss1CompatMode() && !goog.userAgent.isDocumentModeOrHigher(10))) { // 'CSS transforms were introduced in IE9, but only in standards mode // later browsers support the translations in quirks mode. return; } } // First check the element is actually translated, and we haven't missed // one of the vendor-specific transform properties var position = goog.style.getClientPosition(element); var translation = goog.style.getCssTranslation(element); var expectedTranslation = new goog.math.Coordinate(20, 30); assertEquals(30, position.x); assertRoughlyEquals(40, position.y, .1); assertObjectEquals(expectedTranslation, translation); } /** * Test browser detection for a user agent configuration. * @param {Array} expectedAgents Array of expected userAgents. * @param {string} uaString User agent string. * @param {string=} opt_product Navigator product string. * @param {string=} opt_vendor Navigator vendor string. */ function assertUserAgent(expectedAgents, uaString, opt_product, opt_vendor) { var mockNavigator = {'userAgent': uaString, 'product': opt_product, 'vendor': opt_vendor}; mockUserAgent.setNavigator(mockNavigator); mockUserAgent.setUserAgentString(uaString); // Force User-Agent lib to reread the global userAgent. goog.labs.userAgent.util.setUserAgent(null); goog.userAgentTestUtil.reinitializeUserAgent(); for (var ua in goog.userAgentTestUtil.UserAgents) { var isExpected = goog.array.contains( expectedAgents, goog.userAgentTestUtil.UserAgents[ua]); assertEquals( isExpected, goog.userAgentTestUtil.getUserAgentDetected( goog.userAgentTestUtil.UserAgents[ua])); } } /** * Test for the proper vendor style name for a CSS property * with a vendor prefix for Webkit. */ function testGetVendorStyleNameWebkit() { var mockElement = {'style': {'WebkitTransformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.WEBKIT], 'WebKit'); assertEquals( '-webkit-transform-origin', goog.style.getVendorStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * when it exists without a vendor prefix for Webkit. */ function testGetVendorStyleNameWebkitNoPrefix() { var mockElement = { 'style': {'WebkitTransformOrigin': '', 'transformOrigin': ''} }; assertUserAgent([goog.userAgentTestUtil.UserAgents.WEBKIT], 'WebKit'); assertEquals( 'transform-origin', goog.style.getVendorStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * with a vendor prefix for Gecko. */ function testGetVendorStyleNameGecko() { var mockElement = {'style': {'MozTransformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.GECKO], 'Gecko', 'Gecko'); assertEquals( '-moz-transform-origin', goog.style.getVendorStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * when it exists without a vendor prefix for Gecko. */ function testGetVendorStyleNameGeckoNoPrefix() { var mockElement = { 'style': {'MozTransformOrigin': '', 'transformOrigin': ''} }; assertUserAgent([goog.userAgentTestUtil.UserAgents.GECKO], 'Gecko', 'Gecko'); assertEquals( 'transform-origin', goog.style.getVendorStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * with a vendor prefix for IE. */ function testGetVendorStyleNameIE() { var mockElement = {'style': {'msTransformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.IE], 'MSIE'); assertEquals( '-ms-transform-origin', goog.style.getVendorStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * when it exists without a vendor prefix for IE. */ function testGetVendorStyleNameIENoPrefix() { var mockElement = {'style': {'msTransformOrigin': '', 'transformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.IE], 'MSIE'); assertEquals( 'transform-origin', goog.style.getVendorStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * with a vendor prefix for Opera. */ function testGetVendorStyleNameOpera() { var mockElement = {'style': {'OTransformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.OPERA], 'Opera'); assertEquals( '-o-transform-origin', goog.style.getVendorStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * when it exists without a vendor prefix for Opera. */ function testGetVendorStyleNameOperaNoPrefix() { var mockElement = {'style': {'OTransformOrigin': '', 'transformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.OPERA], 'Opera'); assertEquals( 'transform-origin', goog.style.getVendorStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * with a vendor prefix for Webkit. */ function testGetVendorJsStyleNameWebkit() { var mockElement = {'style': {'WebkitTransformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.WEBKIT], 'WebKit'); assertEquals( 'WebkitTransformOrigin', goog.style.getVendorJsStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * when it exists without a vendor prefix for Webkit. */ function testGetVendorJsStyleNameWebkitNoPrefix() { var mockElement = { 'style': {'WebkitTransformOrigin': '', 'transformOrigin': ''} }; assertUserAgent([goog.userAgentTestUtil.UserAgents.WEBKIT], 'WebKit'); assertEquals( 'transformOrigin', goog.style.getVendorJsStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * with a vendor prefix for Gecko. */ function testGetVendorJsStyleNameGecko() { var mockElement = {'style': {'MozTransformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.GECKO], 'Gecko', 'Gecko'); assertEquals( 'MozTransformOrigin', goog.style.getVendorJsStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * when it exists without a vendor prefix for Gecko. */ function testGetVendorJsStyleNameGeckoNoPrefix() { var mockElement = { 'style': {'MozTransformOrigin': '', 'transformOrigin': ''} }; assertUserAgent([goog.userAgentTestUtil.UserAgents.GECKO], 'Gecko', 'Gecko'); assertEquals( 'transformOrigin', goog.style.getVendorJsStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * with a vendor prefix for IE. */ function testGetVendorJsStyleNameIE() { var mockElement = {'style': {'msTransformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.IE], 'MSIE'); assertEquals( 'msTransformOrigin', goog.style.getVendorJsStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * when it exists without a vendor prefix for IE. */ function testGetVendorJsStyleNameIENoPrefix() { var mockElement = {'style': {'msTransformOrigin': '', 'transformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.IE], 'MSIE'); assertEquals( 'transformOrigin', goog.style.getVendorJsStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * with a vendor prefix for Opera. */ function testGetVendorJsStyleNameOpera() { var mockElement = {'style': {'OTransformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.OPERA], 'Opera'); assertEquals( 'OTransformOrigin', goog.style.getVendorJsStyleName_(mockElement, 'transform-origin')); } /** * Test for the proper vendor style name for a CSS property * when it exists without a vendor prefix for Opera. */ function testGetVendorJsStyleNameOperaNoPrefix() { var mockElement = {'style': {'OTransformOrigin': '', 'transformOrigin': ''}}; assertUserAgent([goog.userAgentTestUtil.UserAgents.OPERA], 'Opera'); assertEquals( 'transformOrigin', goog.style.getVendorJsStyleName_(mockElement, 'transform-origin')); } /** * Test for the setting a style name for a CSS property * with a vendor prefix for Webkit. */ function testSetVendorStyleWebkit() { var mockElement = {'style': {'WebkitTransform': ''}}; var styleValue = 'translate3d(0,0,0)'; assertUserAgent([goog.userAgentTestUtil.UserAgents.WEBKIT], 'WebKit'); goog.style.setStyle(mockElement, 'transform', styleValue); assertEquals(styleValue, mockElement.style.WebkitTransform); } /** * Test for the setting a style name for a CSS property * with a vendor prefix for Mozilla. */ function testSetVendorStyleGecko() { var mockElement = {'style': {'MozTransform': ''}}; var styleValue = 'translate3d(0,0,0)'; assertUserAgent([goog.userAgentTestUtil.UserAgents.GECKO], 'Gecko', 'Gecko'); goog.style.setStyle(mockElement, 'transform', styleValue); assertEquals(styleValue, mockElement.style.MozTransform); } /** * Test for the setting a style name for a CSS property * with a vendor prefix for IE. */ function testSetVendorStyleIE() { var mockElement = {'style': {'msTransform': ''}}; var styleValue = 'translate3d(0,0,0)'; assertUserAgent([goog.userAgentTestUtil.UserAgents.IE], 'MSIE'); goog.style.setStyle(mockElement, 'transform', styleValue); assertEquals(styleValue, mockElement.style.msTransform); } /** * Test for the setting a style name for a CSS property * with a vendor prefix for Opera. */ function testSetVendorStyleOpera() { var mockElement = {'style': {'OTransform': ''}}; var styleValue = 'translate3d(0,0,0)'; assertUserAgent([goog.userAgentTestUtil.UserAgents.OPERA], 'Opera'); goog.style.setStyle(mockElement, 'transform', styleValue); assertEquals(styleValue, mockElement.style.OTransform); } /** * Test for the getting a style name for a CSS property * with a vendor prefix for Webkit. */ function testGetVendorStyleWebkit() { var mockElement = {'style': {'WebkitTransform': ''}}; var styleValue = 'translate3d(0,0,0)'; assertUserAgent([goog.userAgentTestUtil.UserAgents.WEBKIT], 'WebKit'); goog.style.setStyle(mockElement, 'transform', styleValue); assertEquals(styleValue, goog.style.getStyle(mockElement, 'transform')); } /** * Test for the getting a style name for a CSS property * with a vendor prefix for Mozilla. */ function testGetVendorStyleGecko() { var mockElement = {'style': {'MozTransform': ''}}; var styleValue = 'translate3d(0,0,0)'; assertUserAgent([goog.userAgentTestUtil.UserAgents.GECKO], 'Gecko', 'Gecko'); goog.style.setStyle(mockElement, 'transform', styleValue); assertEquals(styleValue, goog.style.getStyle(mockElement, 'transform')); } /** * Test for the getting a style name for a CSS property * with a vendor prefix for IE. */ function testGetVendorStyleIE() { var mockElement = {'style': {'msTransform': ''}}; var styleValue = 'translate3d(0,0,0)'; assertUserAgent([goog.userAgentTestUtil.UserAgents.IE], 'MSIE'); goog.style.setStyle(mockElement, 'transform', styleValue); assertEquals(styleValue, goog.style.getStyle(mockElement, 'transform')); } /** * Test for the getting a style name for a CSS property * with a vendor prefix for Opera. */ function testGetVendorStyleOpera() { var mockElement = {'style': {'OTransform': ''}}; var styleValue = 'translate3d(0,0,0)'; assertUserAgent([goog.userAgentTestUtil.UserAgents.OPERA], 'Opera'); goog.style.setStyle(mockElement, 'transform', styleValue); assertEquals(styleValue, goog.style.getStyle(mockElement, 'transform')); } function testParseStyleAttributeWithColon() { // Regression test for https://github.com/google/closure-library/issues/127. var cssObj = goog.style.parseStyleAttribute( 'left: 0px; text-align: center; background-image: ' + 'url(http://www.google.ca/Test.gif); -ms-filter: ' + 'progid:DXImageTransform.Microsoft.MotionBlur(strength=50), ' + 'progid:DXImageTransform.Microsoft.BasicImage(mirror=1);'); assertEquals('url(http://www.google.ca/Test.gif)', cssObj.backgroundImage); assertEquals( 'progid:DXImageTransform.Microsoft.MotionBlur(strength=50), ' + 'progid:DXImageTransform.Microsoft.BasicImage(mirror=1)', cssObj.MsFilter); }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy