summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/addrbook/content/menulist-addrbooks.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/addrbook/content/menulist-addrbooks.js')
-rw-r--r--comm/mail/components/addrbook/content/menulist-addrbooks.js271
1 files changed, 271 insertions, 0 deletions
diff --git a/comm/mail/components/addrbook/content/menulist-addrbooks.js b/comm/mail/components/addrbook/content/menulist-addrbooks.js
new file mode 100644
index 0000000000..6d919d98ad
--- /dev/null
+++ b/comm/mail/components/addrbook/content/menulist-addrbooks.js
@@ -0,0 +1,271 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+// The menulist CE is defined lazily. Create one now to get menulist defined,
+// allowing us to inherit from it.
+if (!customElements.get("menulist")) {
+ delete document.createXULElement("menulist");
+}
+
+// Wrap in a block to prevent leaking to window scope.
+{
+ const { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+ );
+ /**
+ * MozMenulistAddrbooks is a menulist widget that is automatically
+ * populated with the complete address book list.
+ *
+ * @augments {MozMenuList}
+ */
+ class MozMenulistAddrbooks extends customElements.get("menulist") {
+ connectedCallback() {
+ super.connectedCallback();
+ if (this.delayConnectedCallback()) {
+ return;
+ }
+
+ if (this.menupopup) {
+ return;
+ }
+
+ this._directories = [];
+
+ this._rebuild();
+
+ // Store as a member of `this` so there's a strong reference.
+ this._addressBookListener = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIObserver",
+ "nsISupportsWeakReference",
+ ]),
+
+ _notifications: [
+ "addrbook-directory-created",
+ "addrbook-directory-updated",
+ "addrbook-directory-deleted",
+ "addrbook-reloaded",
+ ],
+
+ init() {
+ for (let topic of this._notifications) {
+ Services.obs.addObserver(this, topic, true);
+ }
+ window.addEventListener("unload", this);
+ },
+
+ cleanUp() {
+ for (let topic of this._notifications) {
+ Services.obs.removeObserver(this, topic);
+ }
+ window.removeEventListener("unload", this);
+ },
+
+ handleEvent(event) {
+ this.cleanUp();
+ },
+
+ observe: (subject, topic, data) => {
+ // Test-only reload of the address book manager.
+ if (topic == "addrbook-reloaded") {
+ this._rebuild();
+ return;
+ }
+
+ subject.QueryInterface(Ci.nsIAbDirectory);
+
+ switch (topic) {
+ case "addrbook-directory-created": {
+ if (this._matches(subject)) {
+ this._rebuild();
+ }
+ break;
+ }
+ case "addrbook-directory-updated": {
+ // Find the item in the list to rename.
+ // We can't use indexOf here because we need loose equality.
+ let len = this._directories.length;
+ for (var oldIndex = len - 1; oldIndex >= 0; oldIndex--) {
+ if (this._directories[oldIndex] == subject) {
+ break;
+ }
+ }
+ if (oldIndex != -1) {
+ this._rebuild();
+ }
+ break;
+ }
+ case "addrbook-directory-deleted": {
+ // Find the item in the list to remove.
+ // We can't use indexOf here because we need loose equality.
+ let len = this._directories.length;
+ for (var index = len - 1; index >= 0; index--) {
+ if (this._directories[index] == subject) {
+ break;
+ }
+ }
+ if (index != -1) {
+ this._directories.splice(index, 1);
+ // Are we removing the selected directory?
+ if (
+ this.selectedItem ==
+ this.menupopup.removeChild(this.menupopup.children[index])
+ ) {
+ // If so, try to select the first directory, if available.
+ if (this.menupopup.hasChildNodes()) {
+ this.menupopup.firstElementChild.doCommand();
+ } else {
+ this.selectedItem = null;
+ }
+ }
+ }
+ break;
+ }
+ }
+ },
+ };
+
+ this._addressBookListener.init();
+ }
+
+ /**
+ * Returns the address book type based on the remoteonly attribute
+ * of the menulist.
+ *
+ * "URI" Local Address Book
+ * "dirPrefId" Remote LDAP Directory
+ */
+ get _type() {
+ return this.getAttribute("remoteonly") ? "dirPrefId" : "URI";
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ this._addressBookListener.cleanUp();
+ this._teardown();
+ }
+
+ _rebuild() {
+ // Init the address book cache.
+ this._directories.length = 0;
+
+ for (let ab of MailServices.ab.directories) {
+ if (this._matches(ab)) {
+ this._directories.push(ab);
+
+ if (this.getAttribute("mailinglists") == "true") {
+ // Also append contained mailinglists.
+ for (let list of ab.childNodes) {
+ if (this._matches(list)) {
+ this._directories.push(list);
+ }
+ }
+ }
+ }
+ }
+
+ this._teardown();
+
+ if (this.hasAttribute("none")) {
+ // Create a dummy menuitem representing no selection.
+ this._directories.unshift(null);
+ let listItem = this.appendItem(this.getAttribute("none"), "");
+ listItem.setAttribute("class", "menuitem-iconic abMenuItem");
+ }
+
+ if (this.hasAttribute("alladdressbooks")) {
+ // Insert a menuitem representing All Addressbooks.
+ let allABLabel = this.getAttribute("alladdressbooks");
+ if (allABLabel == "true") {
+ let bundle = Services.strings.createBundle(
+ "chrome://messenger/locale/addressbook/addressBook.properties"
+ );
+ allABLabel = bundle.GetStringFromName("allAddressBooks");
+ }
+
+ this._directories.unshift(null);
+ let listItem = this.appendItem(allABLabel, "moz-abdirectory://?");
+ listItem.setAttribute("class", "menuitem-iconic abMenuItem");
+ listItem.setAttribute(
+ "image",
+ "chrome://messenger/skin/icons/new/compact/address-book.svg"
+ );
+ }
+
+ // Now create menuitems for all displayed directories.
+ let type = this._type;
+ for (let ab of this._directories) {
+ if (!ab) {
+ // Skip the empty members added above.
+ continue;
+ }
+
+ let listItem = this.appendItem(ab.dirName, ab[type]);
+ listItem.setAttribute("class", "menuitem-iconic abMenuItem");
+
+ // Style the items by type.
+ if (ab.isMailList) {
+ listItem.setAttribute(
+ "image",
+ "chrome://messenger/skin/icons/new/compact/user-list.svg"
+ );
+ } else if (ab.isRemote && ab.isSecure) {
+ listItem.setAttribute(
+ "image",
+ "chrome://messenger/skin/icons/new/compact/globe-secure.svg"
+ );
+ } else if (ab.isRemote) {
+ listItem.setAttribute(
+ "image",
+ "chrome://messenger/skin/icons/new/compact/globe.svg"
+ );
+ } else {
+ listItem.setAttribute(
+ "image",
+ "chrome://messenger/skin/icons/new/compact/address-book.svg"
+ );
+ }
+ }
+
+ // Attempt to select the persisted or otherwise first directory.
+ this.selectedIndex = this._directories.findIndex(d => {
+ return d && d[type] == this.value;
+ });
+
+ if (!this.selectedItem && this.menupopup.hasChildNodes()) {
+ this.selectedIndex = 0;
+ }
+ }
+
+ _teardown() {
+ // Empty out anything in the list.
+ while (this.menupopup && this.menupopup.hasChildNodes()) {
+ this.menupopup.lastChild.remove();
+ }
+ }
+
+ _matches(ab) {
+ // This condition is used for instance when creating cards
+ if (this.getAttribute("writable") == "true" && ab.readOnly) {
+ return false;
+ }
+
+ // This condition is used for instance when creating mailing lists
+ if (
+ this.getAttribute("supportsmaillists") == "true" &&
+ !ab.supportsMailingLists
+ ) {
+ return false;
+ }
+
+ return (
+ this.getAttribute(ab.isRemote ? "localonly" : "remoteonly") != "true"
+ );
+ }
+ }
+
+ customElements.define("menulist-addrbooks", MozMenulistAddrbooks, {
+ extends: "menulist",
+ });
+}