зеркало из https://github.com/mozilla/gecko-dev.git
454 строки
12 KiB
JavaScript
454 строки
12 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
|
* 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/. */
|
|
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
|
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
SessionStore: "resource:///modules/sessionstore/SessionStore.jsm",
|
|
});
|
|
|
|
function UpdateSessionStore(
|
|
aBrowser,
|
|
aFlushId,
|
|
aIsFinal,
|
|
aEpoch,
|
|
aData,
|
|
aCollectSHistory
|
|
) {
|
|
return SessionStoreFuncInternal.updateSessionStore(
|
|
aBrowser,
|
|
aFlushId,
|
|
aIsFinal,
|
|
aEpoch,
|
|
aData,
|
|
aCollectSHistory
|
|
);
|
|
}
|
|
|
|
var EXPORTED_SYMBOLS = ["UpdateSessionStore"];
|
|
|
|
var SessionStoreFuncInternal = {
|
|
// form data which is waiting to be updated
|
|
_formDataId: [],
|
|
_formDataIdValue: [],
|
|
_formDataXPath: [],
|
|
_formDataXPathValue: [],
|
|
|
|
/**
|
|
* The data will be stored in the arrays:
|
|
* "_formDataId, _formDataIdValue" for the elements with id.
|
|
* "_formDataXPath, _formDataXPathValue" for the elements with XPath.
|
|
*/
|
|
updateFormData: function SSF_updateFormData(aType, aData) {
|
|
let idArray = this._formDataId;
|
|
let valueArray = this._formDataIdValue;
|
|
|
|
if (aType == "XPath") {
|
|
idArray = this._formDataXPath;
|
|
valueArray = this._formDataXPathValue;
|
|
}
|
|
|
|
let valueIdx = aData.valueIdx;
|
|
for (let i = 0; i < aData.id.length; i++) {
|
|
idArray.push(aData.id[i]);
|
|
|
|
if (aData.type[i] == "singleSelect") {
|
|
valueArray.push({
|
|
selectedIndex: aData.selectedIndex[valueIdx[i]],
|
|
value: aData.selectVal[valueIdx[i]],
|
|
});
|
|
} else if (aData.type[i] == "file") {
|
|
valueArray.push({
|
|
type: "file",
|
|
fileList: aData.strVal.slice(valueIdx[i], valueIdx[++i]),
|
|
});
|
|
} else if (aData.type[i] == "multipleSelect") {
|
|
valueArray.push(aData.strVal.slice(valueIdx[i], valueIdx[++i]));
|
|
} else if (aData.type[i] == "string") {
|
|
valueArray.push(aData.strVal[valueIdx[i]]);
|
|
} else if (aData.type[i] == "bool") {
|
|
valueArray.push(aData.boolVal[valueIdx[i]]);
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Return the array of formdata for this._sessionData.formdata.children
|
|
*
|
|
* aStartIndex: Current index for aInnerHTML/aUrl/aNumId/aNumXPath/aDescendants.
|
|
* (aStartIndex means the index of current root frame)
|
|
* aInnerHTML: Array for innerHTML.
|
|
* aUrl: Array for url.
|
|
* aNumId: Array for number of containing elements with id
|
|
* aNumXPath: Array for number of containing elements with XPath
|
|
* aDescendants: Array for number of descendants.
|
|
*
|
|
* aCurrentIdIdx: Current index for this._formDataId and this._formDataIdValue
|
|
* aCurrentXPathIdx: Current index for this._formDataXPath and this._formDataXPathValue
|
|
* aNumberOfDescendants: The number of descendants for current frame
|
|
*
|
|
* The returned array includes "aNumberOfDescendants" formdata objects.
|
|
*/
|
|
composeInputChildren: function SSF_composeInputChildren(
|
|
aInnerHTML,
|
|
aUrl,
|
|
aCurrentIdIdx,
|
|
aNumId,
|
|
aCurrentXpathIdx,
|
|
aNumXPath,
|
|
aDescendants,
|
|
aStartIndex,
|
|
aNumberOfDescendants
|
|
) {
|
|
let children = [];
|
|
let lastIndexOfNonNullbject = -1;
|
|
for (let i = 0; i < aNumberOfDescendants; i++) {
|
|
let currentIndex = aStartIndex + i;
|
|
let obj = {};
|
|
let objWithData = false;
|
|
|
|
// set url/id/xpath
|
|
if (aUrl[currentIndex]) {
|
|
obj.url = aUrl[currentIndex];
|
|
objWithData = true;
|
|
|
|
if (aInnerHTML[currentIndex]) {
|
|
// eslint-disable-next-line no-unsanitized/property
|
|
obj.innerHTML = aInnerHTML[currentIndex];
|
|
}
|
|
if (aNumId[currentIndex]) {
|
|
let idObj = {};
|
|
for (let idx = 0; idx < aNumId[currentIndex]; idx++) {
|
|
idObj[
|
|
this._formDataId[aCurrentIdIdx + idx]
|
|
] = this._formDataIdValue[aCurrentIdIdx + idx];
|
|
}
|
|
obj.id = idObj;
|
|
}
|
|
|
|
// We want to avoid saving data for about:sessionrestore as a string.
|
|
// Since it's stored in the form as stringified JSON, stringifying further
|
|
// causes an explosion of escape characters. cf. bug 467409
|
|
if (
|
|
obj.url == "about:sessionrestore" ||
|
|
obj.url == "about:welcomeback"
|
|
) {
|
|
obj.id.sessionData = JSON.parse(obj.id.sessionData);
|
|
}
|
|
|
|
if (aNumXPath[currentIndex]) {
|
|
let xpathObj = {};
|
|
for (let idx = 0; idx < aNumXPath[currentIndex]; idx++) {
|
|
xpathObj[
|
|
this._formDataXPath[aCurrentXpathIdx + idx]
|
|
] = this._formDataXPathValue[aCurrentXpathIdx + idx];
|
|
}
|
|
obj.xpath = xpathObj;
|
|
}
|
|
}
|
|
|
|
// compose the descendantsTree which will be pushed into children array
|
|
if (aDescendants[currentIndex]) {
|
|
let descendantsTree = this.composeInputChildren(
|
|
aInnerHTML,
|
|
aUrl,
|
|
aCurrentIdIdx + aNumId[currentIndex],
|
|
aNumId,
|
|
aCurrentXpathIdx + aNumXPath[currentIndex],
|
|
aNumXPath,
|
|
aDescendants,
|
|
currentIndex + 1,
|
|
aDescendants[currentIndex]
|
|
);
|
|
i += aDescendants[currentIndex];
|
|
if (descendantsTree) {
|
|
obj.children = descendantsTree;
|
|
}
|
|
}
|
|
|
|
if (objWithData) {
|
|
lastIndexOfNonNullbject = children.length;
|
|
children.push(obj);
|
|
} else {
|
|
children.push(null);
|
|
}
|
|
}
|
|
|
|
if (lastIndexOfNonNullbject == -1) {
|
|
return null;
|
|
}
|
|
|
|
return children.slice(0, lastIndexOfNonNullbject + 1);
|
|
},
|
|
|
|
/**
|
|
* Update the object for this._sessionData.formdata.
|
|
* The object contains the formdata for all reachable frames.
|
|
*
|
|
* "object.children" is an array with one entry per frame,
|
|
* containing formdata as a nested data structure according
|
|
* to the layout of the frame tree, or null if no formdata.
|
|
*
|
|
* Example:
|
|
* {
|
|
* url: "http://mozilla.org/",
|
|
* id: {input_id: "input value"},
|
|
* xpath: {input_xpath: "input value"},
|
|
* children: [
|
|
* null,
|
|
* {url: "http://sub.mozilla.org/", id: {input_id: "input value 2"}}
|
|
* ]
|
|
* }
|
|
*
|
|
* Each index of the following array is corresponging to each frame.
|
|
* aDescendants: Array for number of descendants
|
|
* aInnerHTML: Array for innerHTML
|
|
* aUrl: Array for url
|
|
* aNumId: Array for number of containing elements with id
|
|
* aNumXPath: Array for number of containing elements with XPath
|
|
*
|
|
* Here we use [index 0] to compose the formdata object of root frame.
|
|
* Besides, we use composeInputChildren() to get array of "object.children".
|
|
*/
|
|
updateInput: function SSF_updateInput(
|
|
aSessionData,
|
|
aDescendants,
|
|
aInnerHTML,
|
|
aUrl,
|
|
aNumId,
|
|
aNumXPath
|
|
) {
|
|
let obj = {};
|
|
let objWithData = false;
|
|
|
|
if (aUrl[0]) {
|
|
obj.url = aUrl[0];
|
|
|
|
if (aInnerHTML[0]) {
|
|
// eslint-disable-next-line no-unsanitized/property
|
|
obj.innerHTML = aInnerHTML[0];
|
|
objWithData = true;
|
|
}
|
|
|
|
if (aNumId[0]) {
|
|
let idObj = {};
|
|
for (let i = 0; i < aNumId[0]; i++) {
|
|
idObj[this._formDataId[i]] = this._formDataIdValue[i];
|
|
}
|
|
obj.id = idObj;
|
|
objWithData = true;
|
|
}
|
|
|
|
// We want to avoid saving data for about:sessionrestore as a string.
|
|
// Since it's stored in the form as stringified JSON, stringifying further
|
|
// causes an explosion of escape characters. cf. bug 467409
|
|
if (obj.url == "about:sessionrestore" || obj.url == "about:welcomeback") {
|
|
obj.id.sessionData = JSON.parse(obj.id.sessionData);
|
|
}
|
|
|
|
if (aNumXPath[0]) {
|
|
let xpathObj = {};
|
|
for (let i = 0; i < aNumXPath[0]; i++) {
|
|
xpathObj[this._formDataXPath[i]] = this._formDataXPathValue[i];
|
|
}
|
|
obj.xpath = xpathObj;
|
|
objWithData = true;
|
|
}
|
|
}
|
|
|
|
if (aDescendants.length > 1) {
|
|
let descendantsTree = this.composeInputChildren(
|
|
aInnerHTML,
|
|
aUrl,
|
|
aNumId[0],
|
|
aNumId,
|
|
aNumXPath[0],
|
|
aNumXPath,
|
|
aDescendants,
|
|
1,
|
|
aDescendants[0]
|
|
);
|
|
if (descendantsTree) {
|
|
obj.children = descendantsTree;
|
|
objWithData = true;
|
|
}
|
|
}
|
|
|
|
if (objWithData) {
|
|
aSessionData.formdata = obj;
|
|
} else {
|
|
aSessionData.formdata = null;
|
|
}
|
|
},
|
|
|
|
composeChildren: function SSF_composeScrollPositionsData(
|
|
aPositions,
|
|
aDescendants,
|
|
aStartIndex,
|
|
aNumberOfDescendants
|
|
) {
|
|
let children = [];
|
|
let lastIndexOfNonNullbject = -1;
|
|
for (let i = 0; i < aNumberOfDescendants; i++) {
|
|
let currentIndex = aStartIndex + i;
|
|
let obj = {};
|
|
let objWithData = false;
|
|
if (aPositions[currentIndex]) {
|
|
obj.scroll = aPositions[currentIndex];
|
|
objWithData = true;
|
|
}
|
|
if (aDescendants[currentIndex]) {
|
|
let descendantsTree = this.composeChildren(
|
|
aPositions,
|
|
aDescendants,
|
|
currentIndex + 1,
|
|
aDescendants[currentIndex]
|
|
);
|
|
i += aDescendants[currentIndex];
|
|
if (descendantsTree) {
|
|
obj.children = descendantsTree;
|
|
objWithData = true;
|
|
}
|
|
}
|
|
|
|
if (objWithData) {
|
|
lastIndexOfNonNullbject = children.length;
|
|
children.push(obj);
|
|
} else {
|
|
children.push(null);
|
|
}
|
|
}
|
|
|
|
if (lastIndexOfNonNullbject == -1) {
|
|
return null;
|
|
}
|
|
|
|
return children.slice(0, lastIndexOfNonNullbject + 1);
|
|
},
|
|
|
|
updateScrollPositions: function SSF_updateScrollPositions(
|
|
aPositions,
|
|
aDescendants
|
|
) {
|
|
let obj = {};
|
|
let objWithData = false;
|
|
|
|
if (aPositions[0]) {
|
|
obj.scroll = aPositions[0];
|
|
objWithData = true;
|
|
}
|
|
|
|
if (aPositions.length > 1) {
|
|
let children = this.composeChildren(
|
|
aPositions,
|
|
aDescendants,
|
|
1,
|
|
aDescendants[0]
|
|
);
|
|
if (children) {
|
|
obj.children = children;
|
|
objWithData = true;
|
|
}
|
|
}
|
|
if (objWithData) {
|
|
return obj;
|
|
}
|
|
return null;
|
|
},
|
|
|
|
updateStorage: function SSF_updateStorage(aOrigins, aKeys, aValues) {
|
|
let data = {};
|
|
for (let i = 0; i < aOrigins.length; i++) {
|
|
// If the key isn't defined, then .clear() was called, and we send
|
|
// up null for this domain to indicate that storage has been cleared
|
|
// for it.
|
|
if (aKeys[i] == "") {
|
|
while (aOrigins[i + 1] == aOrigins[i]) {
|
|
i++;
|
|
}
|
|
data[aOrigins[i]] = null;
|
|
} else {
|
|
let hostData = {};
|
|
hostData[aKeys[i]] = aValues[i];
|
|
while (aOrigins[i + 1] == aOrigins[i]) {
|
|
i++;
|
|
hostData[aKeys[i]] = aValues[i];
|
|
}
|
|
data[aOrigins[i]] = hostData;
|
|
}
|
|
}
|
|
if (aOrigins.length) {
|
|
return data;
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
updateSessionStore: function SSF_updateSessionStore(
|
|
aBrowser,
|
|
aFlushId,
|
|
aIsFinal,
|
|
aEpoch,
|
|
aData,
|
|
aCollectSHistory
|
|
) {
|
|
let currentData = {};
|
|
if (aData.docShellCaps != undefined) {
|
|
currentData.disallow = aData.docShellCaps ? aData.docShellCaps : null;
|
|
}
|
|
if (aData.isPrivate != undefined) {
|
|
currentData.isPrivate = aData.isPrivate;
|
|
}
|
|
if (
|
|
aData.positions != undefined &&
|
|
aData.positionDescendants != undefined
|
|
) {
|
|
currentData.scroll = this.updateScrollPositions(
|
|
aData.positions,
|
|
aData.positionDescendants
|
|
);
|
|
}
|
|
if (aData.id != undefined) {
|
|
this.updateFormData("id", aData.id);
|
|
}
|
|
if (aData.xpath != undefined) {
|
|
this.updateFormData("XPath", aData.xpath);
|
|
}
|
|
if (aData.inputDescendants != undefined) {
|
|
this.updateInput(
|
|
currentData,
|
|
aData.inputDescendants,
|
|
aData.innerHTML,
|
|
aData.url,
|
|
aData.numId,
|
|
aData.numXPath
|
|
);
|
|
}
|
|
if (aData.isFullStorage != undefined) {
|
|
let storage = this.updateStorage(
|
|
aData.storageOrigins,
|
|
aData.storageKeys,
|
|
aData.storageValues
|
|
);
|
|
if (aData.isFullStorage) {
|
|
currentData.storage = storage;
|
|
} else {
|
|
currentData.storagechange = storage;
|
|
}
|
|
}
|
|
|
|
SessionStore.updateSessionStoreFromTablistener(aBrowser, {
|
|
data: currentData,
|
|
flushID: aFlushId,
|
|
isFinal: aIsFinal,
|
|
epoch: aEpoch,
|
|
sHistoryNeeded: aCollectSHistory,
|
|
});
|
|
this._formDataId = [];
|
|
this._formDataIdValue = [];
|
|
this._formDataXPath = [];
|
|
this._formDataXPathValue = [];
|
|
},
|
|
};
|