summaryrefslogtreecommitdiffstats
path: root/toolkit/modules/sessionstore/ScrollPosition.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/modules/sessionstore/ScrollPosition.jsm')
-rw-r--r--toolkit/modules/sessionstore/ScrollPosition.jsm103
1 files changed, 103 insertions, 0 deletions
diff --git a/toolkit/modules/sessionstore/ScrollPosition.jsm b/toolkit/modules/sessionstore/ScrollPosition.jsm
new file mode 100644
index 000000000..5267f332a
--- /dev/null
+++ b/toolkit/modules/sessionstore/ScrollPosition.jsm
@@ -0,0 +1,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);
+ }
+ });
+ }
+};