author | Nicolai Kasper <nicolai@thunderbird.net> |
Mon, 27 Jun 2022 09:05:15 +0000 | |
changeset 119333 | 91683740f55d3af8b8ce405434d7ca797e3665cc |
parent 119328 | 40b247165baa05a2bb80f4624d8f9c9ef4878bc3 |
child 119334 | 2523b1259978b75c7ebe7397d6a1e9469943cba2 |
push id | 16219 |
push user | nicolai@thunderbird.net |
push date | Mon, 04 Jul 2022 13:28:23 +0000 |
treeherder | try-comm-central@2523b1259978 [default view] [failures only] |
reviewers | darktrojan |
bugs | 1776214 |
--- a/mail/components/addrbook/content/vcard-edit/adr.js +++ b/mail/components/addrbook/content/vcard-edit/adr.js @@ -13,19 +13,16 @@ ChromeUtils.defineModuleGetter( /** * @implements {VCardPropertyEntryView} * @see RFC6350 ADR */ class VCardAdrComponent extends HTMLElement { /** @type {VCardPropertyEntry} */ vCardPropertyEntry; - /** @type {HTMLSelectElement} */ - selectEl; - static newVCardPropertyEntry() { return new VCardPropertyEntry("adr", {}, "text", [ "", "", "", "", "", "", @@ -68,28 +65,28 @@ class VCardAdrComponent extends HTMLElem this.assignIds(this.regionEl, this.querySelector('label[for="code"]')); this.countryEl = this.querySelector('input[name="country"]'); this.assignIds( this.countryEl, this.querySelector('label[for="country"]') ); - this.selectEl = this.querySelector("select"); - let selectId = vCardIdGen.next().value; - this.selectEl.id = selectId; - this.querySelector('label[for="select"]').htmlFor = selectId; + // Adjust the adr type selection. + this.vCardType = this.querySelector("vcard-type"); + this.vCardType.vCardPropertyEntry = this.vCardPropertyEntry; + this.vCardType.createLabel = true; this.fromVCardPropertyEntryToUI(); } } disconnectedCallback() { if (!this.isConnected) { - this.selectEl = null; + this.vCardType = null; this.vCardPropertyEntry = null; this.poboxEl = null; this.extEl = null; this.streetEl = null; this.localityEl = null; this.regionEl = null; this.codeEl = null; this.countryEl = null; @@ -106,37 +103,19 @@ class VCardAdrComponent extends HTMLElem } else { this.streetEl.value = this.vCardPropertyEntry.value[2] || ""; } this.resizeStreetEl(); this.localityEl.value = this.vCardPropertyEntry.value[3] || ""; this.regionEl.value = this.vCardPropertyEntry.value[4] || ""; this.codeEl.value = this.vCardPropertyEntry.value[5] || ""; this.countryEl.value = this.vCardPropertyEntry.value[6] || ""; - - /** - * @TODO - * Create an element for type selection of home, work, ... - */ - let paramsType = this.vCardPropertyEntry.params.type; - if (paramsType && !Array.isArray(paramsType)) { - this.selectEl.value = this.vCardPropertyEntry.params.type; - } } fromUIToVCardPropertyEntry() { - /** - * @TODO - * Create an element for type selection of home, work, ... - */ - let paramsType = this.selectEl.value; - if (paramsType) { - this.vCardPropertyEntry.params.type = paramsType; - } - let streetValue = this.streetEl.value || ""; streetValue = streetValue.trim(); if (streetValue.includes("\n")) { streetValue = streetValue.replaceAll("\r", ""); streetValue = streetValue.split("\n"); } this.vCardPropertyEntry.value = [
--- a/mail/components/addrbook/content/vcard-edit/edit.js +++ b/mail/components/addrbook/content/vcard-edit/edit.js @@ -754,16 +754,94 @@ function* vCardHtmlIdGen() { let internalId = 0; while (true) { yield `vcard-id-${internalId++}`; } } let vCardIdGen = vCardHtmlIdGen(); +class VCardTypeSelection extends HTMLElement { + /** @type {HTMLSelectElement} */ + selectEl; + + constructor() { + super(); + } + + connectedCallback() { + if (this.isConnected) { + if (!this.vCardPropertyEntry) { + return; + } + + let template; + let types; + if (this.tel) { + types = ["work", "home", "cell", "fax", "pager"]; + template = document.getElementById("template-vcard-edit-type-tel"); + } else { + types = ["work", "home"]; + template = document.getElementById("template-vcard-edit-type"); + } + let clonedTemplate = template.content.cloneNode(true); + this.appendChild(clonedTemplate); + + this.selectEl = this.querySelector("select"); + let selectId = vCardIdGen.next().value; + this.selectEl.id = selectId; + + // Just abandon any values we don't have UI for. We don't have any way to + // know whether to keep them or not, and they're very rarely used. + // let types = ["work", "home", "cell", "fax", "pager"]; + let paramsType = this.vCardPropertyEntry.params.type; + if (paramsType && Array.isArray(paramsType)) { + this.selectEl.value = paramsType.find(t => types.includes(t)) || ""; + } else if (types.includes(paramsType)) { + this.selectEl.value = this.vCardPropertyEntry.params.type; + } + + // Change the value on the vCardPropertyEntry. + this.selectEl.addEventListener("change", e => { + if (this.selectEl.value) { + this.vCardPropertyEntry.params.type = this.selectEl.value; + } else { + delete this.vCardPropertyEntry.params.type; + } + }); + + // Set an aria-labelledyby on the select. + if (this.setAriaLabelledBy) { + this.querySelector("select").setAttribute( + "aria-labelledby", + this.setAriaLabelledBy + ); + } + + // Create a label element for the select. + if (this.createLabel) { + let labelEl = document.createElement("label"); + labelEl.htmlFor = selectId; + labelEl.setAttribute("data-l10n-id", "vcard-entry-type-label"); + labelEl.classList.add("screen-reader-only"); + this.appendChild(labelEl); + } + } + } + + disconnectedCallback() { + if (!this.isConnected) { + this.selectEl = null; + this.vCardPropertyEntry = null; + } + } +} + +customElements.define("vcard-type", VCardTypeSelection); + /** * Interface for vCard Fields in the edit view. * * @interface VCardPropertyEntryView */ /** * Getter/Setter for rich data do not use HTMLAttributes for this.
--- a/mail/components/addrbook/content/vcard-edit/email.js +++ b/mail/components/addrbook/content/vcard-edit/email.js @@ -13,18 +13,16 @@ ChromeUtils.defineModuleGetter( /** * @implements {VCardPropertyEntryView} * @see RFC6350 EMAIL */ class VCardEmailComponent extends HTMLTableRowElement { /** @type {VCardPropertyEntry} */ vCardPropertyEntry; - /** @type {HTMLSelectElement} */ - selectEl; /** @type {HTMLInputElement} */ emailEl; /** @type {HTMLInputElement} */ checkboxEl; static newVCardPropertyEntry() { return new VCardPropertyEntry("email", {}, "text", ""); } @@ -52,61 +50,46 @@ class VCardEmailComponent extends HTMLTa // Uncheck the checkbox of other VCardEmailComponents if this one is // checked. this.checkboxEl.addEventListener("change", event => { if (event.target.checked === true) { this.dispatchEvent(VCardEmailComponent.CheckboxEvent()); } }); + + // Adjust the email type selection. + this.vCardType = this.querySelector("vcard-type"); + this.vCardType.vCardPropertyEntry = this.vCardPropertyEntry; + this.vCardType.setAriaLabelledBy = "addr-book-edit-email-type"; + this.fromVCardPropertyEntryToUI(); } } disconnectedCallback() { if (!this.isConnected) { this.checkboxEl = null; this.emailEl = null; - this.selectEl = null; + this.vCardType = null; this.vCardPropertyEntry = null; } } fromVCardPropertyEntryToUI() { this.emailEl.value = this.vCardPropertyEntry.value; - /** - * @TODO - * Create an element for type selection of home, work, ... - */ - let paramsType = this.vCardPropertyEntry.params.type; - if (paramsType && !Array.isArray(paramsType)) { - this.selectEl.value = this.vCardPropertyEntry.params.type; - } + let pref = this.vCardPropertyEntry.params.pref; if (pref === "1") { this.checkboxEl.checked = true; } } fromUIToVCardPropertyEntry() { this.vCardPropertyEntry.value = this.emailEl.value; - /** - * @TODO - * Create an element for type selection of home, work, ... - */ - let paramsType = this.selectEl.value; - if (paramsType && paramsType !== "") { - this.vCardPropertyEntry.params.type = this.selectEl.value; - } else if (paramsType && !Array.isArray(paramsType)) { - /** - * @TODO params.type is string | Array<string> | falsy. - * Right now the case is only handled for string. - */ - delete this.vCardPropertyEntry.params.type; - } if (this.checkboxEl.checked) { this.vCardPropertyEntry.params.pref = "1"; } else if ( this.vCardPropertyEntry.params.pref && this.vCardPropertyEntry.params.pref === "1" ) { // Only delete the pref if a pref of 1 is set and the checkbox is not
--- a/mail/components/addrbook/content/vcard-edit/tel.js +++ b/mail/components/addrbook/content/vcard-edit/tel.js @@ -16,18 +16,16 @@ ChromeUtils.defineModuleGetter( * * @TODO missing type-param-tel support. * "text, voice, fax, cell, video, pager, textphone" */ class VCardTelComponent extends HTMLElement { /** @type {VCardPropertyEntry} */ vCardPropertyEntry; - /** @type {HTMLSelectElement} */ - selectEl; /** @type {HTMLInputElement} */ inputElement; static newVCardPropertyEntry() { return new VCardPropertyEntry("tel", {}, "text", ""); } constructor() { @@ -42,55 +40,40 @@ class VCardTelComponent extends HTMLElem this.inputElement = this.querySelector('input[type="text"]'); let urlId = vCardIdGen.next().value; this.inputElement.id = urlId; let urlLabel = this.querySelector('label[for="text"]'); urlLabel.htmlFor = urlId; document.l10n.setAttributes(urlLabel, "vcard-tel-label"); this.inputElement.type = "tel"; - this.selectEl = this.querySelector("select"); - let selectId = vCardIdGen.next().value; - this.selectEl.id = selectId; - this.querySelector('label[for="select"]').htmlFor = selectId; + // Adjust the tel type selection. + this.vCardType = this.querySelector("vcard-type"); + this.vCardType.vCardPropertyEntry = this.vCardPropertyEntry; + this.vCardType.createLabel = true; + this.vCardType.tel = true; this.fromVCardPropertyEntryToUI(); } } disconnectedCallback() { if (!this.isConnected) { this.inputElement = null; - this.selectEl = null; + this.vCardType = null; this.vCardPropertyEntry = null; } } fromVCardPropertyEntryToUI() { this.inputElement.value = this.vCardPropertyEntry.value; - - // Just abandon any values we don't have UI for. We don't have any way to - // know whether to keep them or not, and they're very rarely used. - let types = ["work", "home", "cell", "fax", "pager"]; - let paramsType = this.vCardPropertyEntry.params.type; - if (paramsType && Array.isArray(paramsType)) { - this.selectEl.value = paramsType.find(t => types.includes(t)) || ""; - } else if (types.includes(paramsType)) { - this.selectEl.value = this.vCardPropertyEntry.params.type; - } } fromUIToVCardPropertyEntry() { this.vCardPropertyEntry.value = this.inputElement.value; - - if (this.selectEl.value) { - this.vCardPropertyEntry.params.type = this.selectEl.value; - } else { - delete this.vCardPropertyEntry.params.type; - } } valueIsEmpty() { return this.vCardPropertyEntry.value === ""; } } customElements.define("vcard-tel", VCardTelComponent);
--- a/mail/components/addrbook/content/vcard-edit/url.js +++ b/mail/components/addrbook/content/vcard-edit/url.js @@ -13,18 +13,16 @@ ChromeUtils.defineModuleGetter( /** * @implements {VCardPropertyEntryView} * @see RFC6350 URL */ class VCardURLComponent extends HTMLElement { /** @type {VCardPropertyEntry} */ vCardPropertyEntry; - /** @type {HTMLSelectElement} */ - selectEl; /** @type {HTMLInputElement} */ urlEl; static newVCardPropertyEntry() { return new VCardPropertyEntry("url", {}, "uri", ""); } constructor() { @@ -49,67 +47,45 @@ class VCardURLComponent extends HTMLElem if ( this.urlEl.value.length > "https://".length && !/^https?:\/\//.test(this.urlEl.value) ) { this.urlEl.value = "https://" + this.urlEl.value; } }); - this.selectEl = this.querySelector("select"); - let selectId = vCardIdGen.next().value; - this.selectEl.id = selectId; - this.querySelector('label[for="select"]').htmlFor = selectId; + // Adjust the url type selection. + this.vCardType = this.querySelector("vcard-type"); + this.vCardType.vCardPropertyEntry = this.vCardPropertyEntry; + this.vCardType.createLabel = true; this.fromVCardPropertyEntryToUI(); } } disconnectedCallback() { if (!this.isConnected) { this.urlEl = null; - this.selectEl = null; + this.vCardType = null; this.vCardPropertyEntry = null; } } fromVCardPropertyEntryToUI() { let value = this.vCardPropertyEntry.value; if (/^https?\\:/.test(value)) { // Google escapes some characters in violation of RFC6350. A backslash // wouldn't be expected in a URL so removing them shouldn't be a problem. value = value.replace(/\\(.)/g, "$1"); } this.urlEl.value = value; - /** - * @TODO - * Create an element for type selection of home, work, ... - */ - let paramsType = this.vCardPropertyEntry.params.type; - if (paramsType && !Array.isArray(paramsType)) { - this.selectEl.value = this.vCardPropertyEntry.params.type; - } } fromUIToVCardPropertyEntry() { this.vCardPropertyEntry.value = this.urlEl.value; - /** - * @TODO - * Create an element for type selection of home, work, ... - */ - let paramsType = this.selectEl.value; - if (paramsType && !Array.isArray(paramsType) && paramsType !== "") { - this.vCardPropertyEntry.params.type = this.selectEl.value; - } else if (paramsType && !Array.isArray(paramsType)) { - /** - * @TODO params.type is string | Array<string> | falsy. - * Right now the case is only handled for string. - */ - delete this.vCardPropertyEntry.params.type; - } } valueIsEmpty() { return this.vCardPropertyEntry.value === ""; } } customElements.define("vcard-url", VCardURLComponent);
--- a/mail/components/addrbook/content/vcard-edit/vCardTemplates.inc.xhtml +++ b/mail/components/addrbook/content/vcard-edit/vCardTemplates.inc.xhtml @@ -196,65 +196,38 @@ <!-- FIXME: Replace this DTD string with a fluent ID after 102. --> <label for="vCardNickName">&NickName.label;</label> <input id="vCardNickName" type="text"/> </template> <!-- Email --> <template id="template-vcard-edit-email"> <td> - <!-- The type selection is repeated boilerplate and will be reduced --> - <select class="vcard-type-selection" - aria-labelledby="addr-book-edit-email-type"> - <option value="work" data-l10n-id="vcard-entry-type-work" /> - <option value="home" data-l10n-id="vcard-entry-type-home" /> - <option value="" data-l10n-id="vcard-entry-type-none" selected="selected" /> - </select> + <vcard-type></vcard-type> </td> <td class="email-column"> <input type="email" aria-labelledby="addr-book-edit-email-label" /> </td> <td class="default-column"> <input type="checkbox" aria-labelledby="addr-book-edit-email-default" /> </td> </template> <!-- Phone --> <template id="template-vcard-edit-tel"> - <label class="screen-reader-only" - for="select" - data-l10n-id="vcard-entry-type-label"/> - <!-- The type selection is repeated boilerplate and will be reduced --> - <select class="vcard-type-selection"> - <option value="work" data-l10n-id="vcard-entry-type-work"/> - <option value="home" data-l10n-id="vcard-entry-type-home"/> - <!-- FIXME: Replace these strings and remove aboutAddressBook.ftl from - AccountManager.xhtml. --> - <option value="cell" data-l10n-id="about-addressbook-entry-type-cell"/> - <option value="fax" data-l10n-id="about-addressbook-entry-type-fax"/> - <option value="pager" data-l10n-id="about-addressbook-entry-type-pager"/> - <option value="" data-l10n-id="vcard-entry-type-none" selected="selected"/> - </select> + <vcard-type></vcard-type> <label class="screen-reader-only" for="text"/> <input type="text"/> </template> <!-- Field with type and text --> <template id="template-vcard-edit-type-text"> - <label class="screen-reader-only" - for="select" - data-l10n-id="vcard-entry-type-label"/> - <!-- The type selection is repeated boilerplate and will be reduced --> - <select class="vcard-type-selection"> - <option value="work" data-l10n-id="vcard-entry-type-work"/> - <option value="home" data-l10n-id="vcard-entry-type-home"/> - <option value="" data-l10n-id="vcard-entry-type-none" selected="selected"/> - </select> + <vcard-type></vcard-type> <label class="screen-reader-only" for="text"/> <input type="text"/> </template> <!-- Time Zone --> <template id="template-vcard-edit-tz"> <select> <option value=""></option> @@ -289,25 +262,17 @@ </div> </fieldset> </template> <!-- Address --> <template id="template-vcard-edit-adr"> <fieldset class="fieldset-grid fieldset-reset"> <legend class="screen-reader-only" data-l10n-id="vcard-adr-label"/> - <label class="screen-reader-only" - for="select" - data-l10n-id="vcard-entry-type-label"/> - <!-- The type selection is repeated boilerplate and will be reduced --> - <select class="vcard-type-selection"> - <option value="work" data-l10n-id="vcard-entry-type-work"/> - <option value="home" data-l10n-id="vcard-entry-type-home"/> - <option value="" data-l10n-id="vcard-entry-type-none" selected="selected"/> - </select> + <vcard-type></vcard-type> <div class="vcard-adr-inputs"> <label for="pobox" data-l10n-id="vcard-adr-pobox"/> <input type="text" name="pobox"/> </div> <div class="vcard-adr-inputs"> <label for="ext" data-l10n-id="vcard-adr-ext"/> <input type="text" name="ext"/> </div> @@ -353,8 +318,29 @@ </div> </template> <template id="template-vcard-edit-org"> <div class="vcard-adr-inputs"> <label for="org" data-l10n-id="vcard-org-org"/> <textarea name="org"></textarea> </div> </template> + +<template id="template-vcard-edit-type"> + <select class="vcard-type-selection"> + <option value="work" data-l10n-id="vcard-entry-type-work"/> + <option value="home" data-l10n-id="vcard-entry-type-home"/> + <option value="" data-l10n-id="vcard-entry-type-none" selected="selected"/> + </select> +</template> + +<template id="template-vcard-edit-type-tel"> + <select class="vcard-type-selection"> + <option value="work" data-l10n-id="vcard-entry-type-work"/> + <option value="home" data-l10n-id="vcard-entry-type-home"/> + <!-- FIXME: Replace these strings and remove aboutAddressBook.ftl from + AccountManager.xhtml. --> + <option value="cell" data-l10n-id="about-addressbook-entry-type-cell"/> + <option value="fax" data-l10n-id="about-addressbook-entry-type-fax"/> + <option value="pager" data-l10n-id="about-addressbook-entry-type-pager"/> + <option value="" data-l10n-id="vcard-entry-type-none" selected="selected"/> + </select> +</template>
--- a/mail/components/addrbook/test/browser/browser_edit_card.js +++ b/mail/components/addrbook/test/browser/browser_edit_card.js @@ -1,15 +1,17 @@ /* 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/. */ // TODO: Fix the UI so that we don't have to do this. window.maximize(); +requestLongerTimeout(2); + async function inEditingMode() { let abWindow = getAddressBookWindow(); let abDocument = abWindow.document; await TestUtils.waitForCondition( () => abWindow.detailsPane.isEditing, "entering editing mode" ); @@ -242,28 +244,28 @@ function checkVCardInputValues(expected) for (let [index, field] of fields.entries()) { let expectedEntry = expectedEntries[index]; let valueField; let typeField; switch (key) { case "email": valueField = field.emailEl; - typeField = field.selectEl; + typeField = field.vCardType.selectEl; break; case "impp": valueField = field.imppEl; break; case "url": valueField = field.urlEl; - typeField = field.selectEl; + typeField = field.vCardType.selectEl; break; case "tel": valueField = field.inputElement; - typeField = field.selectEl; + typeField = field.vCardType.selectEl; break; case "note": valueField = field.textAreaEl; break; } // Check the input value of the field. Assert.equal( @@ -364,66 +366,101 @@ function setInputValues(changes) { } else { EventUtils.synthesizeKey("VK_BACK_SPACE", {}, abWindow); } } } EventUtils.synthesizeKey("VK_TAB", {}, abWindow); } -function setVCardInputValues(changes) { +/** + * Uses EventUtils.synthesizeMouseAtCenter and XULPopup.activateItem to + * activate optionValue from the select element typeField. + * + * @param {HTMLSelectElement} typeField Select element. + * @param {string} optionValue The value attribute of the option element from + * typeField. + */ +async function activateTypeSelect(typeField, optionValue) { + let abWindow = getAddressBookWindow(); + // Ensure that the select field is inside the viewport. + typeField.scrollIntoView(); + EventUtils.synthesizeMouseAtCenter(typeField, {}, abWindow); + let selectPopup = await BrowserTestUtils.waitForSelectPopupShown(window); + + // Get the index of the optionValue from typeField + let index = Array.from(typeField.children).findIndex( + child => child.value === optionValue + ); + Assert.ok(index >= 0, "Type in select field found"); + + // No change event is fired if the same option is activated. + if (index === typeField.selectedIndex) { + let popupHidden = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden"); + selectPopup.hidePopup(); + await popupHidden; + return; + } + + // The change event saves the vCard value. + let changeEvent = BrowserTestUtils.waitForEvent(typeField, "change"); + selectPopup.activateItem(selectPopup.children[index]); + await changeEvent; +} + +async function setVCardInputValues(changes) { let abWindow = getAddressBookWindow(); for (let [key, entries] of Object.entries(changes)) { let fields = getFields(key, true, entries.length); for (let [index, field] of fields.entries()) { let changeEntry = entries[index]; let valueField; let typeField; switch (key) { case "email": valueField = field.emailEl; - typeField = field.selectEl; + typeField = field.vCardType.selectEl; if ( (field.checkboxEl.checked && changeEntry && !changeEntry.pref) || (!field.checkboxEl.checked && changeEntry && changeEntry.pref == "1") ) { EventUtils.synthesizeMouseAtCenter(field.checkboxEl, {}, abWindow); } break; case "impp": valueField = field.imppEl; break; case "url": valueField = field.urlEl; - typeField = field.selectEl; + typeField = field.vCardType.selectEl; break; case "tel": valueField = field.inputElement; - typeField = field.selectEl; + typeField = field.vCardType.selectEl; break; case "note": valueField = field.textAreaEl; break; } valueField.select(); if (changeEntry && changeEntry.value) { EventUtils.sendString(changeEntry.value); } else { EventUtils.synthesizeKey("VK_BACK_SPACE", {}, abWindow); } if (typeField && changeEntry && changeEntry.type) { - field.selectEl.value = changeEntry.type; + await activateTypeSelect(typeField, changeEntry.type); } else if (typeField) { - field.selectEl.value = ""; + await activateTypeSelect(typeField, ""); } } } EventUtils.synthesizeKey("VK_TAB", {}, abWindow); } /** * Open the contact at the given index in the #cards element. @@ -1781,17 +1818,17 @@ add_task(async function test_email_field checkVCardValues(book.childCards[0], { email: [{ value: "contact1.lastname1@invalid", pref: "1" }], }); // Edit contact1 set type. await editContactAtIndex(0, { useMouse: true, useActivate: true }); - setVCardInputValues({ + await setVCardInputValues({ email: [{ value: "contact1.lastname1@invalid", type: "work" }], }); await checkDefaultEmailChoice(false, 0); EventUtils.synthesizeMouseAtCenter(saveEditButton, {}, abWindow); await notInEditingMode(cardsList); @@ -1825,17 +1862,17 @@ add_task(async function test_email_field await editContactAtIndex(0, { useMouse: true }); checkVCardInputValues({ email: [{ value: "contact1.lastname1@invalid", type: "work" }], }); await checkDefaultEmailChoice(false, 0); - setVCardInputValues({ + await setVCardInputValues({ email: [ { value: "contact1.lastname1@invalid", pref: "1", type: "work" }, { value: "another.contact1@invalid", type: "home" }, ], }); await checkDefaultEmailChoice(true, 0); @@ -1860,17 +1897,17 @@ add_task(async function test_email_field email: [ { value: "contact1.lastname1@invalid", type: "work" }, { value: "another.contact1@invalid", type: "home" }, ], }); await checkDefaultEmailChoice(true, 0); - setVCardInputValues({ + await setVCardInputValues({ email: [ { value: "contact1.lastname1@invalid", type: "work" }, { value: "another.contact1@invalid", type: "home", pref: "1" }, ], }); await checkDefaultEmailChoice(true, 1); @@ -1895,17 +1932,17 @@ add_task(async function test_email_field email: [ { value: "contact1.lastname1@invalid", type: "work" }, { value: "another.contact1@invalid", type: "home" }, ], }); await checkDefaultEmailChoice(true, 1); - setVCardInputValues({ + await setVCardInputValues({ email: [{}, { value: "another.contact1@invalid", type: "home", pref: "1" }], }); // The default email choosing is still visible until the contact is saved. await checkDefaultEmailChoice(true, 1); EventUtils.synthesizeMouseAtCenter(saveEditButton, {}, abWindow); await notInEditingMode(editButton); @@ -1924,36 +1961,36 @@ add_task(async function test_email_field await editContactAtIndex(1, {}); checkVCardInputValues({ email: [{ value: "contact2.lastname2@invalid" }], }); await checkDefaultEmailChoice(false, 0); - setVCardInputValues({ + await setVCardInputValues({ email: [ { value: "home.contact2@invalid", type: "home", pref: "1" }, { value: "work.contact2@invalid", type: "work", pref: "1" }, ], }); await checkDefaultEmailChoice(true, 1); - setVCardInputValues({ + await setVCardInputValues({ email: [ { value: "home.contact2@invalid", type: "home", pref: "1" }, { value: "work.contact2@invalid", type: "work", pref: "1" }, { value: "some.contact2@invalid" }, ], }); await checkDefaultEmailChoice(true, 1); - setVCardInputValues({ + await setVCardInputValues({ email: [ { value: "home.contact2@invalid", type: "home", pref: "1" }, { value: "work.contact2@invalid", type: "work", pref: "1" }, { value: "some.contact2@invalid", pref: "1" }, { value: "default.email.contact2@invalid", type: "home", pref: "1" }, ], }); @@ -1984,17 +2021,17 @@ add_task(async function test_email_field { value: "work.contact2@invalid", type: "work" }, { value: "some.contact2@invalid" }, { value: "default.email.contact2@invalid", type: "home" }, ], }); await checkDefaultEmailChoice(true, 3); - setVCardInputValues({ + await setVCardInputValues({ email: [{ value: "home.contact2@invalid", type: "home" }], }); // The default email choosing is still visible until the contact is saved. // For this case the default email is left on an empty field which will be // removed. await checkDefaultEmailChoice(true, 3); @@ -2014,17 +2051,17 @@ add_task(async function test_email_field await editContactAtIndex(1, { useActivate: true }); checkVCardInputValues({ email: [{ value: "home.contact2@invalid", type: "home" }], }); await checkDefaultEmailChoice(false, 0); - setVCardInputValues({ + await setVCardInputValues({ email: [ { value: "home.contact2@invalid", type: "home", pref: "1" }, { value: "work.contact2@invalid", type: "work", pref: "1" }, { value: "some.contact2@invalid", pref: "1" }, { value: "default.email.contact2@invalid", type: "home", pref: "1" }, ], }); @@ -2115,17 +2152,17 @@ add_task(async function test_vCard_field // Cancel the new contact creation. EventUtils.synthesizeMouseAtCenter(cancelEditButton, {}, abWindow); await notInEditingMode(searchInput); // Set values for contact1 with one entry for each field. await editContactAtIndex(0, { useMouse: true, useActivate: true }); - setVCardInputValues({ + await setVCardInputValues({ impp: [{ value: "matrix:u/contact1:example.com" }], url: [{ value: "http://www.example.com" }], tel: [{ value: "+123456 789" }], note: [{ value: "A note to this contact" }], }); EventUtils.synthesizeMouseAtCenter(saveEditButton, {}, abWindow); await notInEditingMode(cardsList); @@ -2150,17 +2187,17 @@ add_task(async function test_vCard_field checkVCardInputValues({ impp: [{ value: "matrix:u/contact1:example.com" }], url: [{ value: "http://www.example.com" }], tel: [{ value: "+123456 789" }], note: [{ value: "A note to this contact" }], }); - setVCardInputValues({ + await setVCardInputValues({ impp: [ { value: "matrix:u/contact1:example.com" }, { value: "irc:irc.example.com/contact1,isuser" }, { value: "xmpp:test@example.com" }, ], url: [ { value: "http://example.com" }, { value: "https://hello", type: "home" }, @@ -2204,17 +2241,17 @@ add_task(async function test_vCard_field }); // Switch from contact1 to contact2 and set some entries. // Ensure that no fields from contact1 are leaked. await editContactAtIndex(1, { useMouse: true }); checkVCardInputValues({ impp: [], url: [], tel: [], note: [] }); - setVCardInputValues({ + await setVCardInputValues({ impp: [{ value: "invalid:example.com" }], url: [{ value: "http://www.thunderbird.net" }], tel: [{ value: "650-903-0800" }], note: [{ value: "Another note\nfor contact 2" }], }); EventUtils.synthesizeMouseAtCenter(saveEditButton, {}, abWindow); await notInEditingMode(editButton); @@ -2263,17 +2300,17 @@ add_task(async function test_vCard_field tel: [ { value: "+123456 789", type: "home" }, { value: "809 77 666 8" }, { value: "+1113456789", type: "work" }, ], note: [{ value: "Another note contact1\n\n\n" }], }); - setVCardInputValues({ + await setVCardInputValues({ impp: [{ value: "" }, { value: "" }, { value: "" }], url: [{ value: "" }, { value: "" }, { value: "" }], tel: [{ value: "" }, { value: "" }, { value: "" }], note: [{ value: "" }], }); EventUtils.synthesizeMouseAtCenter(saveEditButton, {}, abWindow); await notInEditingMode(editButton); @@ -2297,17 +2334,17 @@ add_task(async function test_vCard_field checkVCardInputValues({ impp: [{ value: "invalid:example.com" }], url: [{ value: "http://www.thunderbird.net" }], tel: [{ value: "650-903-0800" }], note: [{ value: "Another note\nfor contact 2" }], }); - setVCardInputValues({ + await setVCardInputValues({ impp: [{ value: "" }], url: [ { value: "http://www.thunderbird.net" }, { value: "www.another.url", type: "work" }, ], tel: [{ value: "650-903-0800" }, { value: "+123 456 789", type: "home" }], note: [], }); @@ -2362,8 +2399,147 @@ add_task(async function test_vCard_field // Check that no values from contact2 are leaked to contact1 when cancelling. await editContactAtIndex(0, {}); checkVCardInputValues({ impp: [], url: [], tel: [], note: [] }); await closeAddressBookWindow(); await promiseDirectoryRemoved(book.URI); }); + +/** + * Switches to different types to verify that all works accordingly. + */ +add_task(async function test_type_selection() { + let abWindow = await openAddressBookWindow(); + let abDocument = abWindow.document; + let book = createAddressBook("Test Book Type Selection"); + + let contact1 = createContact("contact1", "lastname"); + book.addCard(contact1); + + openDirectory(book); + + let editButton = abDocument.getElementById("editButton"); + let saveEditButton = abDocument.getElementById("saveEditButton"); + + await editContactAtIndex(0, {}); + + await setVCardInputValues({ + email: [ + { value: "contact1@invalid" }, + { value: "home.contact1@invalid", type: "home" }, + { value: "work.contact1@invalid", type: "work" }, + ], + url: [ + { value: "http://none.example.com" }, + { value: "https://home.example.com", type: "home" }, + { value: "https://work.example.com", type: "work" }, + ], + tel: [ + { value: "+123456 789" }, + { value: "809 HOME 77 666 8", type: "home" }, + { value: "+111 WORK 3456789", type: "work" }, + { value: "+123 CELL 456 789", type: "cell" }, + { value: "809 FAX 77 666 8", type: "fax" }, + { value: "+111 PAGER 3456789", type: "pager" }, + ], + }); + + EventUtils.synthesizeMouseAtCenter(saveEditButton, {}, abWindow); + await notInEditingMode(editButton); + + checkVCardValues(book.childCards[0], { + email: [ + { value: "contact1@invalid", pref: "1" }, + { value: "home.contact1@invalid", type: "home" }, + { value: "work.contact1@invalid", type: "work" }, + ], + url: [ + { value: "http://none.example.com" }, + { value: "https://home.example.com", type: "home" }, + { value: "https://work.example.com", type: "work" }, + ], + tel: [ + { value: "+123456 789" }, + { value: "809 HOME 77 666 8", type: "home" }, + { value: "+111 WORK 3456789", type: "work" }, + { value: "+123 CELL 456 789", type: "cell" }, + { value: "809 FAX 77 666 8", type: "fax" }, + { value: "+111 PAGER 3456789", type: "pager" }, + ], + }); + + EventUtils.synthesizeMouseAtCenter(editButton, {}, abWindow); + await inEditingMode(); + + checkVCardInputValues({ + email: [ + { value: "contact1@invalid", pref: "1" }, + { value: "home.contact1@invalid", type: "home" }, + { value: "work.contact1@invalid", type: "work" }, + ], + url: [ + { value: "http://none.example.com" }, + { value: "https://home.example.com", type: "home" }, + { value: "https://work.example.com", type: "work" }, + ], + tel: [ + { value: "+123456 789" }, + { value: "809 HOME 77 666 8", type: "home" }, + { value: "+111 WORK 3456789", type: "work" }, + { value: "+123 CELL 456 789", type: "cell" }, + { value: "809 FAX 77 666 8", type: "fax" }, + { value: "+111 PAGER 3456789", type: "pager" }, + ], + }); + + await setVCardInputValues({ + email: [ + { value: "contact1@invalid", type: "work" }, + { value: "home.contact1@invalid" }, + { value: "work.contact1@invalid", type: "home" }, + ], + url: [ + { value: "http://none.example.com", type: "work" }, + { value: "https://home.example.com" }, + { value: "https://work.example.com", type: "home" }, + ], + tel: [ + { value: "+123456 789", type: "pager" }, + { value: "809 HOME 77 666 8" }, + { value: "+111 WORK 3456789", type: "home" }, + { value: "+123 CELL 456 789" }, + { value: "809 FAX 77 666 8", type: "fax" }, + { value: "+111 PAGER 3456789", type: "cell" }, + ], + }); + + EventUtils.synthesizeMouseAtCenter(saveEditButton, {}, abWindow); + await notInEditingMode(editButton); + + checkVCardValues(book.childCards[0], { + email: [ + { value: "contact1@invalid", type: "work", pref: "1" }, + { value: "home.contact1@invalid" }, + { value: "work.contact1@invalid", type: "home" }, + ], + url: [ + { value: "http://none.example.com", type: "work" }, + { value: "https://home.example.com" }, + { value: "https://work.example.com", type: "home" }, + ], + tel: [ + { value: "+123456 789", type: "pager" }, + { value: "809 HOME 77 666 8" }, + { value: "+111 WORK 3456789", type: "home" }, + { value: "+123 CELL 456 789" }, + { value: "809 FAX 77 666 8", type: "fax" }, + { value: "+111 PAGER 3456789", type: "cell" }, + ], + }); + + EventUtils.synthesizeMouseAtCenter(saveEditButton, {}, abWindow); + await notInEditingMode(editButton); + + await closeAddressBookWindow(); + await promiseDirectoryRemoved(book.URI); +});