diff options
Diffstat (limited to 'toolkit/modules/sessionstore/ScrollPosition.jsm')
-rw-r--r-- | toolkit/modules/sessionstore/ScrollPosition.jsm | 103 |
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); + } + }); + } +}; |