mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-22 20:33:10 +09:00
166 lines
6.2 KiB
JavaScript
166 lines
6.2 KiB
JavaScript
/* 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 file contains helper methods for dealing with XPCOM iterators (arrays
|
|
* and enumerators) in JS-friendly ways.
|
|
*/
|
|
|
|
this.EXPORTED_SYMBOLS = ["fixIterator", "toXPCOMArray", "toArray"];
|
|
|
|
Components.utils.import("resource://gre/modules/Deprecated.jsm");
|
|
|
|
var Ci = Components.interfaces;
|
|
|
|
var JS_HAS_SYMBOLS = typeof Symbol === "function";
|
|
var ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
|
|
|
|
/**
|
|
* This function will take a number of objects and convert them to an array.
|
|
*
|
|
* Currently, we support the following objects:
|
|
* Anything you can for (let x of aObj) on
|
|
* (e.g. toArray(fixIterator(enum))[4],
|
|
* also a NodeList from element.childNodes)
|
|
*
|
|
* @param aObj The object to convert
|
|
*/
|
|
function toArray(aObj) {
|
|
if (ITERATOR_SYMBOL in aObj) {
|
|
return Array.from(aObj);
|
|
}
|
|
|
|
// We got something unexpected, notify the caller loudly.
|
|
throw new Error("An unsupported object sent to toArray: " +
|
|
(("toString" in aObj) ? aObj.toString() : aObj));
|
|
}
|
|
|
|
/**
|
|
* Given a JS array, JS iterator, or one of a variety of XPCOM collections or
|
|
* iterators, return a JS iterator suitable for use in a for...of expression.
|
|
*
|
|
* Currently, we support the following types of XPCOM iterators:
|
|
* nsIArray
|
|
* nsISupportsArray
|
|
* nsISimpleEnumerator
|
|
*
|
|
* This intentionally does not support nsIEnumerator as it is obsolete and
|
|
* no longer used in the base code.
|
|
*
|
|
* Note that old-style JS iterators are explicitly not supported in this
|
|
* method, as they are going away. For a limited time, the resulting iterator
|
|
* can be used in a for...in loop, but this is a legacy compatibility shim that
|
|
* will not work forever. See bug 1098412.
|
|
*
|
|
* @param aEnum the enumerator to convert
|
|
* @param aIface (optional) an interface to QI each object to prior to
|
|
* returning
|
|
*
|
|
* @note This returns an object that can be used in 'for...of' loops.
|
|
* Do not use 'for each...in'. 'for...in' may be used, but only as a
|
|
* legacy feature.
|
|
* This does *not* return an Array object. To create such an array, use
|
|
* let array = toArray(fixIterator(xpcomEnumerator));
|
|
*/
|
|
function fixIterator(aEnum, aIface) {
|
|
// Minor internal details: to support both for (let x of fixIterator()) and
|
|
// for (let x in fixIterator()), we need to add in a __iterator__ kludge
|
|
// property. __iterator__ is to go away in bug 1098412; we could theoretically
|
|
// make it work beyond that by using Proxies, but that's far to go for
|
|
// something we want to get rid of anyways.
|
|
// Note that the new-style iterator uses Symbol.iterator to work, and anything
|
|
// that has Symbol.iterator works with for-of.
|
|
function makeDualIterator(newStyle) {
|
|
newStyle.__iterator__ = function() {
|
|
for (let item of newStyle)
|
|
yield item;
|
|
};
|
|
return newStyle;
|
|
}
|
|
|
|
// If the input is an array or something that sports Symbol.iterator, then
|
|
// the original input is sufficient to directly return. However, if we want
|
|
// to support the aIface parameter, we need to do a lazy version of Array.map.
|
|
if (Array.isArray(aEnum) || ITERATOR_SYMBOL in aEnum) {
|
|
if (!aIface) {
|
|
return makeDualIterator(aEnum);
|
|
} else {
|
|
return makeDualIterator((function*() {
|
|
for (let o of aEnum)
|
|
yield o.QueryInterface(aIface);
|
|
})());
|
|
}
|
|
}
|
|
|
|
let face = aIface || Ci.nsISupports;
|
|
// Figure out which kind of array object we have.
|
|
// First try nsIArray (covers nsIMutableArray too).
|
|
if (aEnum instanceof Ci.nsIArray) {
|
|
return makeDualIterator((function*() {
|
|
let count = aEnum.length;
|
|
for (let i = 0; i < count; i++)
|
|
yield aEnum.queryElementAt(i, face);
|
|
})());
|
|
}
|
|
|
|
// Try an nsISupportsArray.
|
|
// This object is deprecated, but we need to keep supporting it
|
|
// while anything in the base code (including mozilla-central) produces it.
|
|
if (aEnum instanceof Ci.nsISupportsArray) {
|
|
return makeDualIterator((function*() {
|
|
let count = aEnum.Count();
|
|
for (let i = 0; i < count; i++)
|
|
yield aEnum.QueryElementAt(i, face);
|
|
})());
|
|
}
|
|
|
|
// How about nsISimpleEnumerator? This one is nice and simple.
|
|
if (aEnum instanceof Ci.nsISimpleEnumerator) {
|
|
return makeDualIterator((function*() {
|
|
while (aEnum.hasMoreElements())
|
|
yield aEnum.getNext().QueryInterface(face);
|
|
})());
|
|
}
|
|
|
|
// We got something unexpected, notify the caller loudly.
|
|
throw new Error("An unsupported object sent to fixIterator: " +
|
|
(("toString" in aEnum) ? aEnum.toString() : aEnum));
|
|
}
|
|
|
|
/**
|
|
* This function takes an Array object and returns an XPCOM array
|
|
* of the desired type. It will *not* work if you extend Array.prototype.
|
|
*
|
|
* @param aArray the array (anything fixIterator supports) to convert to an XPCOM array
|
|
* @param aInterface the type of XPCOM array to convert
|
|
*
|
|
* @note The returned array is *not* dynamically updated. Changes made to the
|
|
* JS array after a call to this function will not be reflected in the
|
|
* XPCOM array.
|
|
*/
|
|
function toXPCOMArray(aArray, aInterface) {
|
|
if (aInterface.equals(Ci.nsISupportsArray)) {
|
|
Deprecated.warning("nsISupportsArray object is deprecated, avoid creating new ones.",
|
|
"https://developer.mozilla.org/en-US/docs/XPCOM_array_guide");
|
|
let supportsArray = Components.classes["@mozilla.org/supports-array;1"]
|
|
.createInstance(Ci.nsISupportsArray);
|
|
for (let item of fixIterator(aArray)) {
|
|
supportsArray.AppendElement(item);
|
|
}
|
|
return supportsArray;
|
|
}
|
|
|
|
if (aInterface.equals(Ci.nsIMutableArray)) {
|
|
let mutableArray = Components.classes["@mozilla.org/array;1"]
|
|
.createInstance(Ci.nsIMutableArray);
|
|
for (let item of fixIterator(aArray)) {
|
|
mutableArray.appendElement(item, false);
|
|
}
|
|
return mutableArray;
|
|
}
|
|
|
|
// We got something unexpected, notify the caller loudly.
|
|
throw new Error("An unsupported interface requested from toXPCOMArray: " +
|
|
aInterface);
|
|
}
|