summaryrefslogtreecommitdiffstats
path: root/toolkit/components/xulstore/new/XULStore.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/xulstore/new/XULStore.jsm')
-rw-r--r--toolkit/components/xulstore/new/XULStore.jsm107
1 files changed, 107 insertions, 0 deletions
diff --git a/toolkit/components/xulstore/new/XULStore.jsm b/toolkit/components/xulstore/new/XULStore.jsm
new file mode 100644
index 0000000000..16108eeb8b
--- /dev/null
+++ b/toolkit/components/xulstore/new/XULStore.jsm
@@ -0,0 +1,107 @@
+/* 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 JS module wraps the nsIXULStore XPCOM service with useful abstractions.
+// In particular, it wraps the enumerators returned by getIDsEnumerator()
+// and getAttributeEnumerator() in JS objects that implement the iterable
+// protocol. It also implements the persist() method. JS consumers should use
+// this module rather than accessing nsIXULStore directly.
+
+const EXPORTED_SYMBOLS = ["XULStore", "getXULStore"];
+
+// Services.xulStore loads this module and returns its `XULStore` symbol
+// when this implementation of XULStore is enabled, so using it here
+// would loop infinitely. But the mozilla/use-services rule is a good
+// requiremnt for every other consumer of XULStore.
+// eslint-disable-next-line mozilla/use-services
+const xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
+
+// Enables logging.
+const debugMode = false;
+
+// Internal function for logging debug messages to the Error Console window
+function log(message) {
+ if (!debugMode) {
+ return;
+ }
+ console.log("XULStore: " + message);
+}
+
+const XULStore = {
+ setValue: xulStore.setValue,
+ hasValue: xulStore.hasValue,
+ getValue: xulStore.getValue,
+ removeValue: xulStore.removeValue,
+ removeDocument: xulStore.removeDocument,
+
+ /**
+ * Sets a value for a specified node's attribute, except in
+ * the case below:
+ * If the value is empty and if calling `hasValue` with the node's
+ * document and ID and `attr` would return true, then the
+ * value instead gets removed from the store (see Bug 1476680).
+ *
+ * @param node - DOM node
+ * @param attr - attribute to store
+ */
+ persist(node, attr) {
+ if (!node.id) {
+ throw new Error("Node without ID passed into persist()");
+ }
+
+ const uri = node.ownerDocument.documentURI;
+ const value = node.getAttribute(attr);
+
+ if (node.localName == "window") {
+ log("Persisting attributes to windows is handled by AppWindow.");
+ return;
+ }
+
+ // See Bug 1476680 - we could drop the `hasValue` check so that
+ // any time there's an empty attribute it gets removed from the
+ // store. Since this is copying behavior from document.persist,
+ // callers would need to be updated with that change.
+ if (!value && xulStore.hasValue(uri, node.id, attr)) {
+ xulStore.removeValue(uri, node.id, attr);
+ } else {
+ xulStore.setValue(uri, node.id, attr, value);
+ }
+ },
+
+ getIDsEnumerator(docURI) {
+ return new XULStoreEnumerator(xulStore.getIDsEnumerator(docURI));
+ },
+
+ getAttributeEnumerator(docURI, id) {
+ return new XULStoreEnumerator(xulStore.getAttributeEnumerator(docURI, id));
+ },
+};
+
+class XULStoreEnumerator {
+ constructor(enumerator) {
+ this.enumerator = enumerator;
+ }
+
+ hasMore() {
+ return this.enumerator.hasMore();
+ }
+
+ getNext() {
+ return this.enumerator.getNext();
+ }
+
+ *[Symbol.iterator]() {
+ while (this.enumerator.hasMore()) {
+ yield this.enumerator.getNext();
+ }
+ }
+}
+
+// Only here for the sake of component registration, which requires a
+// callable function.
+function getXULStore() {
+ return XULStore;
+}