summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/addrbook/content/map-list.js
blob: 102cb09522896369e9a9d49f9abb6c9c15aff257 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/* 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";

/* global MozElements */

// Wrap in a block to prevent leaking to window scope.
{
  /**
   * The MozMapList widget behaves as a popup menu showing available map options
   * for an address. It is a part of the card view in the addressbook.
   *
   * @augments {MozElements.MozMenuPopup}
   */
  class MozMapList extends MozElements.MozMenuPopup {
    connectedCallback() {
      if (this.delayConnectedCallback() || this.hasConnected) {
        return;
      }
      this.setAttribute("is", "map-list");

      this.addEventListener("command", event => {
        this._chooseMapService(event.target);
        event.stopPropagation();
      });

      this.addEventListener("popupshowing", event => {
        this._listMapServices();
      });

      this._setWidgetDisabled(true);
    }

    get mapURL() {
      return this._createMapItURL();
    }

    /**
     * Initializes the necessary address data from an addressbook card.
     *
     * @param {nsIAbCard} card - The card to get the address data from.
     * @param {string} addrPrefix - Card property prefix: "Home" or "Work",
     *    to make the map use either HomeAddress or WorkAddress.
     */
    initMapAddressFromCard(card, addrPrefix) {
      let mapItURLFormat = this._getMapURLPref();
      let doNotShowMap = !mapItURLFormat || !addrPrefix || !card;
      this._setWidgetDisabled(doNotShowMap);
      if (doNotShowMap) {
        return;
      }

      this.address1 = card.getProperty(addrPrefix + "Address");
      this.address2 = card.getProperty(addrPrefix + "Address2");
      this.city = card.getProperty(addrPrefix + "City");
      this._state = card.getProperty(addrPrefix + "State");
      this.zip = card.getProperty(addrPrefix + "ZipCode");
      this.country = card.getProperty(addrPrefix + "Country");
    }

    /**
     * Sets the disabled/enabled state of the parent widget (e.g. a button).
     */
    _setWidgetDisabled(disabled) {
      this.parentNode.disabled = disabled;
    }

    /**
     * Returns the Map service URL from localized pref. Returns null if there
     * is none at the given index.
     *
     * @param {integer} [index=0] - The index of the service to return.
     *   0 is the default service.
     */
    _getMapURLPref(index = 0) {
      let url = null;
      if (!index) {
        url = Services.prefs.getComplexValue(
          "mail.addr_book.mapit_url.format",
          Ci.nsIPrefLocalizedString
        ).data;
      } else {
        try {
          url = Services.prefs.getComplexValue(
            "mail.addr_book.mapit_url." + index + ".format",
            Ci.nsIPrefLocalizedString
          ).data;
        } catch (e) {}
      }

      return url;
    }

    /**
     * Builds menuitem elements representing map services defined in prefs
     * and attaches them to the specified button.
     */
    _listMapServices() {
      let index = 1;
      let itemFound = true;
      let defaultFound = false;
      const kUserIndex = 100;
      let mapList = this;
      while (mapList.hasChildNodes()) {
        mapList.lastChild.remove();
      }

      let defaultUrl = this._getMapURLPref();

      // Creates the menuitem with supplied data.
      function addMapService(url, name) {
        let item = document.createXULElement("menuitem");
        item.setAttribute("url", url);
        item.setAttribute("label", name);
        item.setAttribute("type", "radio");
        item.setAttribute("name", "mapit_service");
        if (url == defaultUrl) {
          item.setAttribute("checked", "true");
        }
        mapList.appendChild(item);
      }

      // Generates a useful generic name by cutting out only the host address.
      function generateName(url) {
        return new URL(url).hostname;
      }

      // Add all defined map services as menuitems.
      while (itemFound) {
        let urlName;
        let urlTemplate = this._getMapURLPref(index);
        if (!urlTemplate) {
          itemFound = false;
        } else {
          // Name is not mandatory, generate one if not found.
          try {
            urlName = Services.prefs.getComplexValue(
              "mail.addr_book.mapit_url." + index + ".name",
              Ci.nsIPrefLocalizedString
            ).data;
          } catch (e) {
            urlName = generateName(urlTemplate);
          }
        }
        if (itemFound) {
          addMapService(urlTemplate, urlName);
          index++;
          if (urlTemplate == defaultUrl) {
            defaultFound = true;
          }
        } else if (index < kUserIndex) {
          // After iterating the base region provided urls, check for user defined ones.
          index = kUserIndex;
          itemFound = true;
        }
      }
      if (!defaultFound) {
        // If user had put a customized map URL into mail.addr_book.mapit_url.format
        // preserve it as a new map service named with the URL.
        // 'index' now points to the first unused entry in prefs.
        let defaultName = generateName(defaultUrl);
        addMapService(defaultUrl, defaultName);
        Services.prefs.setCharPref(
          "mail.addr_book.mapit_url." + index + ".format",
          defaultUrl
        );
        Services.prefs.setCharPref(
          "mail.addr_book.mapit_url." + index + ".name",
          defaultName
        );
      }
    }

    /**
     * Save user selected mapping service.
     *
     * @param {Element} item - The chosen menuitem with map service.
     */
    _chooseMapService(item) {
      // Save selected URL as the default.
      let defaultUrl = Cc["@mozilla.org/pref-localizedstring;1"].createInstance(
        Ci.nsIPrefLocalizedString
      );
      defaultUrl.data = item.getAttribute("url");
      Services.prefs.setComplexValue(
        "mail.addr_book.mapit_url.format",
        Ci.nsIPrefLocalizedString,
        defaultUrl
      );
    }

    /**
     * Generate the map URL used to open the link on clicking the menulist button.
     *
     * @returns {urlFormat} - the map url generated from the address.
     */
    _createMapItURL() {
      let urlFormat = this._getMapURLPref();
      if (!urlFormat) {
        return null;
      }

      urlFormat = urlFormat.replace("@A1", encodeURIComponent(this.address1));
      urlFormat = urlFormat.replace("@A2", encodeURIComponent(this.address2));
      urlFormat = urlFormat.replace("@CI", encodeURIComponent(this.city));
      urlFormat = urlFormat.replace("@ST", encodeURIComponent(this._state));
      urlFormat = urlFormat.replace("@ZI", encodeURIComponent(this.zip));
      urlFormat = urlFormat.replace("@CO", encodeURIComponent(this.country));

      return urlFormat;
    }
  }

  customElements.define("map-list", MozMapList, { extends: "menupopup" });
}