From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../shared/AddressMetaDataLoader.sys.mjs | 168 +++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 toolkit/components/formautofill/shared/AddressMetaDataLoader.sys.mjs (limited to 'toolkit/components/formautofill/shared/AddressMetaDataLoader.sys.mjs') diff --git a/toolkit/components/formautofill/shared/AddressMetaDataLoader.sys.mjs b/toolkit/components/formautofill/shared/AddressMetaDataLoader.sys.mjs new file mode 100644 index 0000000000..a7be227921 --- /dev/null +++ b/toolkit/components/formautofill/shared/AddressMetaDataLoader.sys.mjs @@ -0,0 +1,168 @@ +/* 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/. */ + +const lazy = {}; +ChromeUtils.defineESModuleGetters(lazy, { + AddressMetaData: "resource://gre/modules/shared/AddressMetaData.sys.mjs", + AddressMetaDataExtension: + "resource://gre/modules/shared/AddressMetaDataExtension.sys.mjs", +}); + +export class AddressMetaDataLoader { + // Status of address data loading. We'll load all the countries with basic level 1 + // information while requesting conutry information, and set country to true. + // Level 1 Set is for recording which country's level 1/level 2 data is loaded, + // since we only load this when getCountryAddressData called with level 1 parameter. + static dataLoaded = { + country: false, + level1: new Set(), + }; + + static addressData = {}; + + static DATA_PREFIX = "data/"; + + /** + * Load address meta data and extension into one object. + * + * @returns {object} + * An object containing address data object with properties from extension. + */ + static loadAddressMetaData() { + const addressMetaData = lazy.AddressMetaData; + + for (const key in lazy.AddressMetaDataExtension) { + let addressDataForKey = addressMetaData[key]; + if (!addressDataForKey) { + addressDataForKey = addressMetaData[key] = {}; + } + + Object.assign(addressDataForKey, lazy.AddressMetaDataExtension[key]); + } + return addressMetaData; + } + + /** + * Convert certain properties' string value into array. We should make sure + * the cached data is parsed. + * + * @param {object} data Original metadata from addressReferences. + * @returns {object} parsed metadata with property value that converts to array. + */ + static #parse(data) { + if (!data) { + return null; + } + + const properties = [ + "languages", + "sub_keys", + "sub_isoids", + "sub_names", + "sub_lnames", + ]; + for (const key of properties) { + if (!data[key]) { + continue; + } + // No need to normalize data if the value is array already. + if (Array.isArray(data[key])) { + return data; + } + + data[key] = data[key].split("~"); + } + return data; + } + + /** + * We'll cache addressData in the loader once the data loaded from scripts. + * It'll become the example below after loading addressReferences with extension: + * addressData: { + * "data/US": {"lang": ["en"], ...// Data defined in libaddressinput metadata + * "alternative_names": ... // Data defined in extension } + * "data/CA": {} // Other supported country metadata + * "data/TW": {} // Other supported country metadata + * "data/TW/台北市": {} // Other supported country level 1 metadata + * } + * + * @param {string} country + * @param {string?} level1 + * @returns {object} Default locale metadata + */ + static #loadData(country, level1 = null) { + // Load the addressData if needed + if (!this.dataLoaded.country) { + this.addressData = this.loadAddressMetaData(); + this.dataLoaded.country = true; + } + if (!level1) { + return this.#parse(this.addressData[`${this.DATA_PREFIX}${country}`]); + } + // If level1 is set, load addressReferences under country folder with specific + // country/level 1 for level 2 information. + if (!this.dataLoaded.level1.has(country)) { + Object.assign(this.addressData, this.loadAddressMetaData()); + this.dataLoaded.level1.add(country); + } + return this.#parse( + this.addressData[`${this.DATA_PREFIX}${country}/${level1}`] + ); + } + + /** + * Return the region metadata with default locale and other locales (if exists). + * + * @param {string} country + * @param {string?} level1 + * @returns {object} Return default locale and other locales metadata. + */ + static getData(country, level1 = null) { + const defaultLocale = this.#loadData(country, level1); + if (!defaultLocale) { + return null; + } + + const countryData = this.#parse( + this.addressData[`${this.DATA_PREFIX}${country}`] + ); + let locales = []; + // TODO: Should be able to support multi-locale level 1/ level 2 metadata query + // in Bug 1421886 + if (countryData.languages) { + const list = countryData.languages.filter( + key => key !== countryData.lang + ); + locales = list.map(key => + this.#parse(this.addressData[`${defaultLocale.id}--${key}`]) + ); + } + return { defaultLocale, locales }; + } + + /** + * Return an array containing countries alpha2 codes. + * + * @returns {Array} Return an array containing countries alpha2 codes. + */ + static get #countryCodes() { + return Object.keys(lazy.AddressMetaDataExtension).map(dataKey => + dataKey.replace(this.DATA_PREFIX, "") + ); + } + + static getCountries(locales = []) { + const displayNames = new Intl.DisplayNames(locales, { + type: "region", + fallback: "none", + }); + const countriesMap = new Map(); + for (const countryCode of this.#countryCodes) { + countriesMap.set(countryCode, displayNames.of(countryCode)); + } + return countriesMap; + } +} + +export default AddressMetaDataLoader; -- cgit v1.2.3