forked from ibm-js/delite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathViewport.js
136 lines (123 loc) · 4.47 KB
/
Viewport.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
/**
* Utility singleton to watch for viewport resizes, avoiding duplicate notifications
* which can lead to infinite loops.
*
* Usage:
* ```
* Viewport.on("resize", myCallback)
* Viewport.on("scroll", myOtherCallback)
* ```
*
* myCallback() is called without arguments in case it's Widget.resize(),
* which would interpret the argument as the size to make the widget.
*
* @module delite/Viewport
*/
define([
"decor/Evented",
"decor/sniff", // has("ios")
"requirejs-domready/domReady!"
], function (Evented, has) {
var Viewport = new Evented();
// Get the size of the viewport without size adjustment needed for iOS soft keyboard.
// On android though, this returns the size of the visible area not including the keyboard.
function getBox() {
if (has("ios") < 8) {
// Workaround iOS < 8 problem where window.innerHeight is too low when the document is scrolled so
// much that the document ends before the bottom of the keyboard. Workaround not needed and doesn't work,
// on iOS 8.
var bcr = document.body.getBoundingClientRect();
return {
w: Math.max(bcr.width, window.innerWidth),
h: Math.max(bcr.height, window.innerHeight),
t: window.pageYOffset,
l: window.pageXOffset
};
} else {
return {
w: window.innerWidth,
h: window.innerHeight,
t: window.pageYOffset,
l: window.pageXOffset
};
}
}
/**
* Get the size of the viewport, or on mobile devices, the part of the viewport not obscured by the
* virtual keyboard.
* @function module:delite/Viewport.getEffectiveBox
*/
Viewport.getEffectiveBox = function () {
/* jshint maxcomplexity:12 */
var box = getBox();
// Account for iOS virtual keyboard, if it's being shown. Unfortunately no direct way to check or measure.
var focusedNode = document.activeElement,
tag = focusedNode && focusedNode.tagName && focusedNode.tagName.toLowerCase();
if (has("ios") && focusedNode && !focusedNode.readOnly && (tag === "textarea" || (tag === "input" &&
/^(color|email|number|password|search|tel|text|url)$/.test(focusedNode.type)))) {
// Box represents the size of the viewport. Some of the viewport is likely covered by the keyboard.
// Estimate height of visible viewport assuming viewport goes to bottom of screen,
// but is covered by keyboard.
// By my measurements the effective viewport is the following size (compared to full viewport:
// Portrait / landscape / window.screen.height:
// iPhone 6 / iOS 8: 54% / 26% / 667
// iPhone 5s / iOS 8: 53% / 27% / 568
// iPhone 5s / iOS 7: 53% / 19% / 568
// iPhone 5 / iOS 8: 52% / 27% / 568
// iPhone 4s / iOS 7: 41% / 19% / 480
// iPad 2 / iOS 7.1: 66% / 41%
// iPhone 3s / iOS6: 43% / 29% (but w/hidden address bar because it hides all the time)
if (has("ipad")) {
// Numbers for iPad 2, hopefully it works for other iPads (including iPad mini) too.
box.h *= (window.orientation === 0 || window.orientation === 180 ? 0.65 : 0.38);
} else {
// iPhone varies a lot by model, this should estimate the available space conservatively
if (window.orientation === 0 || window.orientation === 180) {
// portrait
box.h *= (window.screen.height > 500 ? 0.54 : 0.42);
} else {
// landscape
box.h *= (window.screen.height > 500 && has("ios") >= 8 ? 0.26 : 0.19);
}
}
// Account for space taken by auto-completion suggestions.
if (has("ios") >= 8 &&
(!focusedNode.hasAttribute("autocorrect") || focusedNode.getAttribute("autocorrect") === "on") &&
/^(color|number|search|tel|text)$/.test(focusedNode.type)) {
box.h -= 40;
}
}
return box;
};
var oldEffectiveSize = Viewport.getEffectiveBox(),
oldEffectiveScroll = oldEffectiveSize;
function checkForResize() {
var newBox = Viewport.getEffectiveBox();
if (newBox.h !== oldEffectiveSize.h || newBox.w !== oldEffectiveSize.w) {
oldEffectiveSize = newBox;
Viewport.emit("resize", newBox);
return true;
} else {
return false;
}
}
function checkForScroll() {
var newBox = Viewport.getEffectiveBox();
if (newBox.t !== oldEffectiveScroll.t || newBox.l !== oldEffectiveScroll.l) {
oldEffectiveScroll = newBox;
Viewport.emit("scroll", newBox);
return true;
} else {
return false;
}
}
// Poll for viewport resizes due to rotation, browser window size change, or the virtual keyboard
// popping up/down.
function poll() {
var resized = checkForResize(),
scrolled = checkForScroll();
setTimeout(poll, resized || scrolled ? 10 : 50);
}
poll();
return Viewport;
});