-
Notifications
You must be signed in to change notification settings - Fork 45
/
Copy pathpage_edge.js
181 lines (155 loc) · 8.05 KB
/
page_edge.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright (c) 2014 Titanium I.T. LLC. All rights reserved. For license, see "README" or "LICENSE" file.
"use strict";
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
};
}