1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5"use strict"; 6 7// This JS module wraps the nsIXULStore XPCOM service with useful abstractions. 8// In particular, it wraps the enumerators returned by getIDsEnumerator() 9// and getAttributeEnumerator() in JS objects that implement the iterable 10// protocol. It also implements the persist() method. JS consumers should use 11// this module rather than accessing nsIXULStore directly. 12 13const EXPORTED_SYMBOLS = ["XULStore", "getXULStore"]; 14 15// Services.xulStore loads this module and returns its `XULStore` symbol 16// when this implementation of XULStore is enabled, so using it here 17// would loop infinitely. But the mozilla/use-services rule is a good 18// requiremnt for every other consumer of XULStore. 19// eslint-disable-next-line mozilla/use-services 20const xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore); 21 22// Enables logging. 23const debugMode = false; 24 25// Internal function for logging debug messages to the Error Console window 26function log(message) { 27 if (!debugMode) { 28 return; 29 } 30 console.log("XULStore: " + message); 31} 32 33const XULStore = { 34 setValue: xulStore.setValue, 35 hasValue: xulStore.hasValue, 36 getValue: xulStore.getValue, 37 removeValue: xulStore.removeValue, 38 removeDocument: xulStore.removeDocument, 39 40 /** 41 * Sets a value for a specified node's attribute, except in 42 * the case below: 43 * If the value is empty and if calling `hasValue` with the node's 44 * document and ID and `attr` would return true, then the 45 * value instead gets removed from the store (see Bug 1476680). 46 * 47 * @param node - DOM node 48 * @param attr - attribute to store 49 */ 50 persist(node, attr) { 51 if (!node.id) { 52 throw new Error("Node without ID passed into persist()"); 53 } 54 55 const uri = node.ownerDocument.documentURI; 56 const value = node.getAttribute(attr); 57 58 if (node.localName == "window") { 59 log("Persisting attributes to windows is handled by AppWindow."); 60 return; 61 } 62 63 // See Bug 1476680 - we could drop the `hasValue` check so that 64 // any time there's an empty attribute it gets removed from the 65 // store. Since this is copying behavior from document.persist, 66 // callers would need to be updated with that change. 67 if (!value && xulStore.hasValue(uri, node.id, attr)) { 68 xulStore.removeValue(uri, node.id, attr); 69 } else { 70 xulStore.setValue(uri, node.id, attr, value); 71 } 72 }, 73 74 getIDsEnumerator(docURI) { 75 return new XULStoreEnumerator(xulStore.getIDsEnumerator(docURI)); 76 }, 77 78 getAttributeEnumerator(docURI, id) { 79 return new XULStoreEnumerator(xulStore.getAttributeEnumerator(docURI, id)); 80 }, 81}; 82 83class XULStoreEnumerator { 84 constructor(enumerator) { 85 this.enumerator = enumerator; 86 } 87 88 hasMore() { 89 return this.enumerator.hasMore(); 90 } 91 92 getNext() { 93 return this.enumerator.getNext(); 94 } 95 96 *[Symbol.iterator]() { 97 while (this.enumerator.hasMore()) { 98 yield this.enumerator.getNext(); 99 } 100 } 101} 102 103// Only here for the sake of component registration, which requires a 104// callable function. 105function getXULStore() { 106 return XULStore; 107} 108