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
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["ScrollPosition"];
const Ci = Components.interfaces;
/**
* It provides methods to collect scroll positions from single frames and to
* restore scroll positions for frame trees.
*
* This is a child process module.
*/
this.ScrollPosition = Object.freeze({
collect(frame) {
return ScrollPositionInternal.collect(frame);
},
restoreTree(root, data) {
ScrollPositionInternal.restoreTree(root, data);
}
});
/**
* This module's internal API.
*/
var ScrollPositionInternal = {
/**
* Collects scroll position data for any given |frame| in the frame hierarchy.
*
* @param frame (DOMWindow)
*
* @return {scroll: "x,y"} e.g. {scroll: "100,200"}
* Returns null when there is no scroll data we want to store for the
* given |frame|.
*/
collect: function (frame) {
let ifreq = frame.QueryInterface(Ci.nsIInterfaceRequestor);
let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
let scrollX = {}, scrollY = {};
utils.getScrollXY(false /* no layout flush */, scrollX, scrollY);
if (scrollX.value || scrollY.value) {
return {scroll: scrollX.value + "," + scrollY.value};
}
return null;
},
/**
* Restores scroll position data for any given |frame| in the frame hierarchy.
*
* @param frame (DOMWindow)
* @param value (object, see collect())
*/
restore: function (frame, value) {
let match;
if (value && (match = /(\d+),(\d+)/.exec(value))) {
frame.scrollTo(match[1], match[2]);
}
},
/**
* Restores scroll position data for the current frame hierarchy starting at
* |root| using the given scroll position |data|.
*
* If the given |root| frame's hierarchy doesn't match that of the given
* |data| object we will silently discard data for unreachable frames. We
* may as well assign scroll positions to the wrong frames if some were
* reordered or removed.
*
* @param root (DOMWindow)
* @param data (object)
* {
* scroll: "100,200",
* children: [
* {scroll: "100,200"},
* null,
* {scroll: "200,300", children: [ ... ]}
* ]
* }
*/
restoreTree: function (root, data) {
if (data.hasOwnProperty("scroll")) {
this.restore(root, data.scroll);
}
if (!data.hasOwnProperty("children")) {
return;
}
let frames = root.frames;
data.children.forEach((child, index) => {
if (child && index < frames.length) {
this.restoreTree(frames[index], child);
}
});
}
};
|