mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 07:17:30 +09:00
Add Pale Moon
This commit is contained in:
parent
dcd9973243
commit
fe8028fa2e
1173 changed files with 143053 additions and 934 deletions
230
application/palemoon/components/sessionstore/DocumentUtils.jsm
Normal file
230
application/palemoon/components/sessionstore/DocumentUtils.jsm
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/* 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/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "DocumentUtils" ];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/sessionstore/XPathGenerator.jsm");
|
||||
|
||||
this.DocumentUtils = {
|
||||
/**
|
||||
* Obtain form data for a DOMDocument instance.
|
||||
*
|
||||
* The returned object has 2 keys, "id" and "xpath". Each key holds an object
|
||||
* which further defines form data.
|
||||
*
|
||||
* The "id" object maps element IDs to values. The "xpath" object maps the
|
||||
* XPath of an element to its value.
|
||||
*
|
||||
* @param aDocument
|
||||
* DOMDocument instance to obtain form data for.
|
||||
* @return object
|
||||
* Form data encoded in an object.
|
||||
*/
|
||||
getFormData: function DocumentUtils_getFormData(aDocument) {
|
||||
let formNodes = aDocument.evaluate(
|
||||
XPathGenerator.restorableFormNodes,
|
||||
aDocument,
|
||||
XPathGenerator.resolveNS,
|
||||
Ci.nsIDOMXPathResult.UNORDERED_NODE_ITERATOR_TYPE, null
|
||||
);
|
||||
|
||||
let node;
|
||||
let ret = {id: {}, xpath: {}};
|
||||
|
||||
// Limit the number of XPath expressions for performance reasons. See
|
||||
// bug 477564.
|
||||
const MAX_TRAVERSED_XPATHS = 100;
|
||||
let generatedCount = 0;
|
||||
|
||||
while (node = formNodes.iterateNext()) {
|
||||
let nId = node.id;
|
||||
let hasDefaultValue = true;
|
||||
let value;
|
||||
|
||||
// Only generate a limited number of XPath expressions for perf reasons
|
||||
// (cf. bug 477564)
|
||||
if (!nId && generatedCount > MAX_TRAVERSED_XPATHS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node instanceof Ci.nsIDOMHTMLInputElement ||
|
||||
node instanceof Ci.nsIDOMHTMLTextAreaElement) {
|
||||
switch (node.type) {
|
||||
case "checkbox":
|
||||
case "radio":
|
||||
value = node.checked;
|
||||
hasDefaultValue = value == node.defaultChecked;
|
||||
break;
|
||||
case "file":
|
||||
value = { type: "file", fileList: node.mozGetFileNameArray() };
|
||||
hasDefaultValue = !value.fileList.length;
|
||||
break;
|
||||
default: // text, textarea
|
||||
value = node.value;
|
||||
hasDefaultValue = value == node.defaultValue;
|
||||
break;
|
||||
}
|
||||
} else if (!node.multiple) {
|
||||
// <select>s without the multiple attribute are hard to determine the
|
||||
// default value, so assume we don't have the default.
|
||||
hasDefaultValue = false;
|
||||
value = { selectedIndex: node.selectedIndex, value: node.value };
|
||||
} else {
|
||||
// <select>s with the multiple attribute are easier to determine the
|
||||
// default value since each <option> has a defaultSelected
|
||||
let options = Array.map(node.options, function(aOpt, aIx) {
|
||||
let oSelected = aOpt.selected;
|
||||
hasDefaultValue = hasDefaultValue && (oSelected == aOpt.defaultSelected);
|
||||
return oSelected ? aOpt.value : -1;
|
||||
});
|
||||
value = options.filter(function(aIx) aIx !== -1);
|
||||
}
|
||||
|
||||
// In order to reduce XPath generation (which is slow), we only save data
|
||||
// for form fields that have been changed. (cf. bug 537289)
|
||||
if (!hasDefaultValue) {
|
||||
if (nId) {
|
||||
ret.id[nId] = value;
|
||||
} else {
|
||||
generatedCount++;
|
||||
ret.xpath[XPathGenerator.generate(node)] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Merges form data on a document from previously obtained data.
|
||||
*
|
||||
* This is the inverse of getFormData(). The data argument is the same object
|
||||
* type which is returned by getFormData(): an object containing the keys
|
||||
* "id" and "xpath" which are each objects mapping element identifiers to
|
||||
* form values.
|
||||
*
|
||||
* Where the document has existing form data for an element, the value
|
||||
* will be replaced. Where the document has a form element but no matching
|
||||
* data in the passed object, the element is untouched.
|
||||
*
|
||||
* @param aDocument
|
||||
* DOMDocument instance to which to restore form data.
|
||||
* @param aData
|
||||
* Object defining form data.
|
||||
*/
|
||||
mergeFormData: function DocumentUtils_mergeFormData(aDocument, aData) {
|
||||
if ("xpath" in aData) {
|
||||
for each (let [xpath, value] in Iterator(aData.xpath)) {
|
||||
let node = XPathGenerator.resolve(aDocument, xpath);
|
||||
|
||||
if (node) {
|
||||
this.restoreFormValue(node, value, aDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("id" in aData) {
|
||||
for each (let [id, value] in Iterator(aData.id)) {
|
||||
let node = aDocument.getElementById(id);
|
||||
|
||||
if (node) {
|
||||
this.restoreFormValue(node, value, aDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Low-level function to restore a form value to a DOMNode.
|
||||
*
|
||||
* If you want a higher-level interface, see mergeFormData().
|
||||
*
|
||||
* When the value is changed, the function will fire the appropriate DOM
|
||||
* events.
|
||||
*
|
||||
* @param aNode
|
||||
* DOMNode to set form value on.
|
||||
* @param aValue
|
||||
* Value to set form element to.
|
||||
* @param aDocument [optional]
|
||||
* DOMDocument node belongs to. If not defined, node.ownerDocument
|
||||
* is used.
|
||||
*/
|
||||
restoreFormValue: function DocumentUtils_restoreFormValue(aNode, aValue, aDocument) {
|
||||
aDocument = aDocument || aNode.ownerDocument;
|
||||
|
||||
let eventType;
|
||||
|
||||
if (typeof aValue == "string" && aNode.type != "file") {
|
||||
// Don't dispatch an input event if there is no change.
|
||||
if (aNode.value == aValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
aNode.value = aValue;
|
||||
eventType = "input";
|
||||
} else if (typeof aValue == "boolean") {
|
||||
// Don't dispatch a change event for no change.
|
||||
if (aNode.checked == aValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
aNode.checked = aValue;
|
||||
eventType = "change";
|
||||
} else if (typeof aValue == "number") {
|
||||
// handle select backwards compatibility, example { "#id" : index }
|
||||
// We saved the value blindly since selects take more work to determine
|
||||
// default values. So now we should check to avoid unnecessary events.
|
||||
if (aNode.selectedIndex == aValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aValue < aNode.options.length) {
|
||||
aNode.selectedIndex = aValue;
|
||||
eventType = "change";
|
||||
}
|
||||
} else if (aValue && aValue.selectedIndex >= 0 && aValue.value) {
|
||||
// handle select new format
|
||||
|
||||
// Don't dispatch a change event for no change
|
||||
if (aNode.options[aNode.selectedIndex].value == aValue.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find first option with matching aValue if possible
|
||||
for (let i = 0; i < aNode.options.length; i++) {
|
||||
if (aNode.options[i].value == aValue.value) {
|
||||
aNode.selectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
eventType = "change";
|
||||
} else if (aValue && aValue.fileList && aValue.type == "file" &&
|
||||
aNode.type == "file") {
|
||||
aNode.mozSetFileNameArray(aValue.fileList, aValue.fileList.length);
|
||||
eventType = "input";
|
||||
} else if (aValue && typeof aValue.indexOf == "function" && aNode.options) {
|
||||
Array.forEach(aNode.options, function(opt, index) {
|
||||
// don't worry about malformed options with same values
|
||||
opt.selected = aValue.indexOf(opt.value) > -1;
|
||||
|
||||
// Only fire the event here if this wasn't selected by default
|
||||
if (!opt.defaultSelected) {
|
||||
eventType = "change";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fire events for this node if applicable
|
||||
if (eventType) {
|
||||
let event = aDocument.createEvent("UIEvents");
|
||||
event.initUIEvent(eventType, true, true, aDocument.defaultView, 0);
|
||||
aNode.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue