quixote
Version:
CSS unit and integration testing
182 lines (155 loc) • 8.25 kB
JavaScript
// Copyright (c) 2014 Titanium I.T. LLC. All rights reserved. For license, see "README" or "LICENSE" file.
;
var ensure = require("../util/ensure.js");
var PositionDescriptor = require("./position_descriptor.js");
var Position = require("../values/position.js");
var TOP = "top";
var RIGHT = "right";
var BOTTOM = "bottom";
var LEFT = "left";
var Me = module.exports = function PageEdge(edge, browsingContext) {
var BrowsingContext = require("../browsing_context.js"); // break circular dependency
ensure.signature(arguments, [ String, BrowsingContext ]);
this.should = this.createShould();
if (edge === LEFT || edge === RIGHT) PositionDescriptor.x(this);
else if (edge === TOP || edge === BOTTOM) PositionDescriptor.y(this);
else ensure.unreachable("Unknown edge: " + edge);
this._edge = edge;
this._browsingContext = browsingContext;
};
PositionDescriptor.extend(Me);
Me.top = factoryFn(TOP);
Me.right = factoryFn(RIGHT);
Me.bottom = factoryFn(BOTTOM);
Me.left = factoryFn(LEFT);
Me.prototype.value = function value() {
ensure.signature(arguments, []);
var size = pageSize(this._browsingContext.contentDocument);
switch(this._edge) {
case TOP: return Position.y(0);
case RIGHT: return Position.x(size.width);
case BOTTOM: return Position.y(size.height);
case LEFT: return Position.x(0);
default: ensure.unreachable();
}
};
Me.prototype.toString = function toString() {
ensure.signature(arguments, []);
switch(this._edge) {
case TOP: return "top of page";
case RIGHT: return "right side of page";
case BOTTOM: return "bottom of page";
case LEFT: return "left side of page";
default: ensure.unreachable();
}
};
function factoryFn(edge) {
return function factory(browsingContext) {
return new Me(edge, browsingContext);
};
}
// USEFUL READING: http://www.quirksmode.org/mobile/viewports.html
// and http://www.quirksmode.org/mobile/viewports2.html
// API SEMANTICS.
// Ref https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements
// getBoundingClientRect().width: sum of bounding boxes of element (the displayed width of the element,
// including padding and border). Fractional. Applies transformations.
// clientWidth: visible width of element including padding (but not border). EXCEPT on root element (html), where
// it is the width of the viewport. Rounds to an integer. Doesn't apply transformations.
// offsetWidth: visible width of element including padding, border, and scrollbars (if any). Rounds to an integer.
// Doesn't apply transformations.
// scrollWidth: entire width of element, including any part that's not visible due to scrollbars. Rounds to
// an integer. Doesn't apply transformations. Not clear if it includes scrollbars, but I think not. Also
// not clear if it includes borders or padding. (But from tests, apparently not borders. Except on root
// element and body element, which have special results that vary by browser.)
// TEST RESULTS: WIDTH
// ✔ = correct answer
// ✘ = incorrect answer and diverges from spec
// ~ = incorrect answer, but matches spec
// BROWSERS TESTED: Safari 6.2.0 (Mac OS X 10.8.5); Mobile Safari 7.0.0 (iOS 7.1); Firefox 32.0.0 (Mac OS X 10.8);
// Firefox 33.0.0 (Windows 7); Chrome 38.0.2125 (Mac OS X 10.8.5); Chrome 38.0.2125 (Windows 7); IE 8, 9, 10, 11
// html width style smaller than viewport width; body width style smaller than html width style
// NOTE: These tests were conducted when correct result was width of border. That has been changed
// to "width of viewport."
// html.getBoundingClientRect().width
// ✘ IE 8, 9, 10: width of viewport
// ✔ Safari, Mobile Safari, Chrome, Firefox, IE 11: width of html, including border
// html.clientWidth
// ~ Safari, Mobile Safari, Chrome, Firefox, IE 8, 9, 10, 11: width of viewport
// html.offsetWidth
// ✘ IE 8, 9, 10: width of viewport
// ✔ Safari, Mobile Safari, Chrome, Firefox, IE 11: width of html, including border
// html.scrollWidth
// ✘ IE 8, 9, 10, 11, Firefox: width of viewport
// ~ Safari, Mobile Safari, Chrome: width of html, excluding border
// body.getBoundingClientRect().width
// ~ Safari, Mobile Safari, Chrome, Firefox, IE 8, 9, 10, 11: width of body, including border
// body.clientWidth
// ~ Safari, Mobile Safari, Chrome, Firefox, IE 8, 9, 10, 11: width of body, excluding border
// body.offsetWidth
// ~ Safari, Mobile Safari, Chrome, Firefox, IE 8, 9, 10, 11: width of body, including border
// body.scrollWidth
// ✘ Safari, Mobile Safari, Chrome: width of viewport
// ~ Firefox, IE 8, 9, 10, 11: width of body, excluding border
// element width style wider than viewport; body and html width styles at default
// BROWSER BEHAVIOR: html and body border extend to width of viewport and not beyond (except on Mobile Safari)
// Correct result is element width + body border-left + html border-left (except on Mobile Safari)
// Mobile Safari uses a layout viewport, so it's expected to include body border-right and html border-right.
// html.getBoundingClientRect().width
// ✔ Mobile Safari: element width + body border + html border
// ~ Safari, Chrome, Firefox, IE 8, 9, 10, 11: viewport width
// html.clientWidth
// ✔ Mobile Safari: element width + body border + html border
// ~ Safari, Chrome, Firefox, IE 8, 9, 10, 11: viewport width
// html.offsetWidth
// ✔ Mobile Safari: element width + body border + html border
// ~ Safari, Chrome, Firefox, IE 8, 9, 10, 11: viewport width
// html.scrollWidth
// ✔ Mobile Safari: element width + body border + html border
// ✘ Safari, Chrome: element width + body border-left (BUT NOT html border-left)
// ✔ Firefox, IE 8, 9, 10, 11: element width + body border-left + html border-left
// body.getBoundingClientRect().width
// ~ Mobile Safari: element width + body border
// ~ Safari, Chrome, Firefox, IE 8, 9, 10, 11: viewport width - html border
// body.clientWidth
// ~ Mobile Safari: element width
// ~ Safari, Chrome, Firefox, IE 8, 9, 10, 11: viewport width - html border - body border
// body.offsetWidth
// ~ Mobile Safari: element width + body border
// ~ Safari, Chrome, Firefox, IE 8, 9, 10, 11: viewport width - html border
// body.scrollWidth
// ✔ Mobile Safari: element width + body border + html border
// ✔ Safari, Chrome: element width + body border-left + html border-left (matches actual browser)
// ~ Firefox, IE 8, 9, 10, 11: element width
// TEST RESULTS: HEIGHT
// ✔ = correct answer
// ✘ = incorrect answer and diverges from spec
// ~ = incorrect answer, but matches spec
// html height style smaller than viewport height; body height style smaller than html height style
// NOTE: These tests were conducted when correct result was height of viewport.
// html.clientHeight
// ✔ Safari, Mobile Safari, Chrome, Firefox, IE 8, 9, 10, 11: height of viewport
// element height style taller than viewport; body and html width styles at default
// BROWSER BEHAVIOR: html and body border enclose entire element
// Correct result is element width + body border-top + html border-top + body border-bottom + html border-bottom
// html.clientHeight
// ✔ Mobile Safari: element height + all borders
// ~ Safari, Chrome, Firefox, IE 8, 9, 10, 11: height of viewport
// html.scrollHeight
// ✔ Firefox, IE 8, 9, 10, 11: element height + all borders
// ✘ Safari, Mobile Safari, Chrome: element height + html border-bottom
// body.scrollHeight
// ✔ Safari, Mobile Safari, Chrome: element height + all borders
// ~ Firefox, IE 8, 9, 10, 11: element height (body height - body border)
function pageSize(document) {
var html = document.documentElement;
var body = document.body;
// BEST WIDTH ANSWER SO FAR (ASSUMING VIEWPORT IS MINIMUM ANSWER):
var width = Math.max(body.scrollWidth, html.scrollWidth);
// BEST HEIGHT ANSWER SO FAR (ASSUMING VIEWPORT IS MINIMUM ANSWER):
var height = Math.max(body.scrollHeight, html.scrollHeight);
return {
width: width,
height: height
};
}