summaryrefslogtreecommitdiffstats
path: root/browser/components/payments/res/components/address-option.js
blob: 2661f3e2319e6b779dee338d69cc1b2d7cbd8c6c (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
/* 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/. */

/* import-globals-from ../../../../../browser/extensions/formautofill/content/autofillEditForms.js*/
import ObservedPropertiesMixin from "../mixins/ObservedPropertiesMixin.js";
import RichOption from "./rich-option.js";
/* import-globals-from ../unprivileged-fallbacks.js */

/**
 * Up to two-line address display. After bug 1475684 this will also be used for
 * the single-line <option> substitute too.
 *
 * <rich-select>
 *  <address-option guid="98hgvnbmytfc"
 *                  address-level1="MI"
 *                  address-level2="Some City"
 *                  email="foo@example.com"
 *                  country="USA"
 *                  name="Jared Wein"
 *                  postal-code="90210"
 *                  street-address="1234 Anywhere St"
 *                  tel="+1 650 555-5555"></address-option>
 * </rich-select>
 *
 * Attribute names follow FormAutofillStorage.jsm.
 */

export default class AddressOption extends ObservedPropertiesMixin(RichOption) {
  static get recordAttributes() {
    return [
      "address-level1",
      "address-level2",
      "address-level3",
      "country",
      "email",
      "guid",
      "name",
      "organization",
      "postal-code",
      "street-address",
      "tel",
    ];
  }

  static get observedAttributes() {
    return RichOption.observedAttributes.concat(
      AddressOption.recordAttributes,
      "address-fields",
      "break-after-nth-field",
      "data-field-separator"
    );
  }

  constructor() {
    super();

    this._line1 = document.createElement("div");
    this._line1.classList.add("line");
    this._line2 = document.createElement("div");
    this._line2.classList.add("line");

    for (let name of AddressOption.recordAttributes) {
      this[`_${name}`] = document.createElement("span");
      this[`_${name}`].classList.add(name);
      // XXX Bug 1490816: Use appropriate strings
      let missingValueString =
        name.replace(/(-|^)([a-z])/g, ($0, $1, $2) => {
          return $1.replace("-", " ") + $2.toUpperCase();
        }) + " Missing";
      this[`_${name}`].dataset.missingString = missingValueString;
    }
  }

  connectedCallback() {
    this.appendChild(this._line1);
    this.appendChild(this._line2);
    super.connectedCallback();
  }

  static formatSingleLineLabel(address, addressFields) {
    return PaymentDialogUtils.getAddressLabel(address, addressFields);
  }

  get requiredFields() {
    if (this.hasAttribute("address-fields")) {
      let names = this.getAttribute("address-fields")
        .trim()
        .split(/\s+/);
      if (names.length) {
        return names;
      }
    }

    return [
      // "address-level1", // TODO: bug 1481481 - not required for some countries e.g. DE
      "address-level2",
      "country",
      "name",
      "postal-code",
      "street-address",
    ];
  }

  render() {
    // Clear the lines of the fields so we can append only the ones still
    // visible in the correct order below.
    this._line1.textContent = "";
    this._line2.textContent = "";

    // Fill the fields with their text/strings.
    // Fall back to empty strings to prevent 'null' from appearing.
    for (let name of AddressOption.recordAttributes) {
      let camelCaseName = super.constructor.kebabToCamelCase(name);
      let fieldEl = this[`_${name}`];
      fieldEl.textContent = this[camelCaseName] || "";
    }

    let { fieldsOrder } = PaymentDialogUtils.getFormFormat(this.country);
    // A subset of the requested fields may be returned if the fields don't apply to the country.
    let requestedVisibleFields = this.addressFields || "mailing-address";
    let visibleFields = EditAddress.computeVisibleFields(
      fieldsOrder,
      requestedVisibleFields
    );
    let visibleFieldCount = 0;
    let requiredFields = this.requiredFields;
    // Start by populating line 1
    let lineEl = this._line1;
    // Which field number to start line 2 after.
    let breakAfterNthField = this.breakAfterNthField || 2;

    // Now actually place the fields in the proper place on the lines.
    for (let field of visibleFields) {
      let fieldEl = this[`_${field.fieldId}`];
      if (!fieldEl) {
        log.warn(`address-option render: '${field.fieldId}' doesn't exist`);
        continue;
      }

      if (!fieldEl.textContent && !requiredFields.includes(field.fieldId)) {
        // The field is empty and we don't need to show "Missing …" so don't append.
        continue;
      }

      if (lineEl.children.length) {
        lineEl.append(this.dataset.fieldSeparator);
      }
      lineEl.appendChild(fieldEl);

      // Add a break after this field, if requested.
      if (++visibleFieldCount == breakAfterNthField) {
        lineEl = this._line2;
      }
    }
  }
}

customElements.define("address-option", AddressOption);