(function attachPhoneCountryUtils(root, factory) { root.MultiPagePhoneCountryUtils = factory(); })(typeof self !== 'undefined' ? self : globalThis, function createPhoneCountryUtils() { const KNOWN_DIAL_CODES = Object.freeze([ '1246', '1264', '1268', '1284', '1340', '1345', '1441', '1473', '1649', '1664', '1670', '1671', '1684', '1721', '1758', '1767', '1784', '1809', '1829', '1849', '1868', '1869', '1876', '971', '962', '886', '880', '856', '855', '852', '853', '673', '672', '670', '599', '598', '597', '596', '595', '594', '593', '592', '591', '590', '509', '508', '507', '506', '505', '504', '503', '502', '501', '423', '421', '420', '389', '387', '386', '385', '383', '382', '381', '380', '379', '378', '377', '376', '375', '374', '373', '372', '371', '370', '359', '358', '357', '356', '355', '354', '353', '352', '351', '350', '299', '298', '297', '291', '290', '269', '268', '267', '266', '265', '264', '263', '262', '261', '260', '258', '257', '256', '255', '254', '253', '252', '251', '250', '249', '248', '247', '246', '245', '244', '243', '242', '241', '240', '239', '238', '237', '236', '235', '234', '233', '232', '231', '230', '229', '228', '227', '226', '225', '224', '223', '222', '221', '220', '218', '216', '213', '212', '211', '98', '95', '94', '93', '92', '91', '90', '89', '88', '86', '84', '82', '81', '66', '65', '64', '63', '62', '61', '60', '58', '57', '56', '55', '54', '53', '52', '51', '49', '48', '47', '46', '45', '44', '43', '41', '40', '39', '36', '34', '33', '32', '31', '30', '27', '20', '7', '1', ]); function normalizePhoneDigits(value) { let digits = String(value || '').replace(/\D+/g, ''); if (digits.startsWith('00')) { digits = digits.slice(2); } return digits; } function extractDialCodeFromText(value) { const match = String(value || '').match(/\(\+\s*(\d{1,4})\s*\)|\+\s*\(\s*(\d{1,4})\s*\)|\+\s*(\d{1,4})\b/); return String(match?.[1] || match?.[2] || match?.[3] || '').trim(); } function normalizeCountryLabel(value) { return String(value || '') .normalize('NFKD') .replace(/[\u0300-\u036f]/g, '') .replace(/&/g, ' and ') .replace(/[^\p{L}\p{N}\s]/gu, ' ') .replace(/\s+/g, ' ') .trim() .toLowerCase(); } function normalizeCountryOptionValue(value) { return String(value || '').trim().toUpperCase(); } function getCountryLabelAliases(value) { const aliases = new Set(); const addAlias = (alias) => { const normalized = normalizeCountryLabel(alias); if (normalized) { aliases.add(normalized); } }; const raw = String(value || '').trim(); addAlias(raw); const normalized = normalizeCountryLabel(raw); const compact = normalized.replace(/\s+/g, ''); if ( /(?:^|\s)(?:gb|uk)(?:\s|$)/i.test(raw) || /england|united\s*kingdom|great\s*britain|\bbritain\b/i.test(raw) || /英国|英格兰|大不列颠/.test(raw) || ['gb', 'uk', 'england', 'unitedkingdom', 'greatbritain', 'britain'].includes(compact) ) { [ 'GB', 'UK', 'United Kingdom', 'Great Britain', 'Britain', 'England', '英国', '英格兰', '大不列颠', ].forEach(addAlias); } return Array.from(aliases); } function getRegionDisplayName(regionCode, locale) { const normalizedRegionCode = normalizeCountryOptionValue(regionCode); const normalizedLocale = String(locale || '').trim(); if (!/^[A-Z]{2}$/.test(normalizedRegionCode) || !normalizedLocale || typeof Intl?.DisplayNames !== 'function') { return ''; } try { return String( new Intl.DisplayNames([normalizedLocale], { type: 'region' }).of(normalizedRegionCode) || '' ).trim(); } catch { return ''; } } function getOptionLabel(option) { return String(option?.textContent || option?.label || '') .replace(/\s+/g, ' ') .trim(); } function getOptionMatchLabels(option, options = {}) { const labels = new Set(); const pushLabel = (value) => { const label = String(value || '').replace(/\s+/g, ' ').trim(); if (label) { labels.add(label); } }; const getLabel = typeof options.getOptionLabel === 'function' ? options.getOptionLabel : getOptionLabel; pushLabel(getLabel(option)); const regionCode = normalizeCountryOptionValue(option?.value); if (/^[A-Z]{2}$/.test(regionCode)) { pushLabel(regionCode); pushLabel(getRegionDisplayName(regionCode, 'en')); const pageLocale = String( options.pageLocale || options.document?.documentElement?.lang || options.document?.documentElement?.getAttribute?.('lang') || options.navigator?.language || '' ).trim(); if (pageLocale && !/^en(?:[-_]|$)/i.test(pageLocale)) { pushLabel(getRegionDisplayName(regionCode, pageLocale)); } } return Array.from(labels); } function resolveDialCodeFromPhoneNumber(phoneNumber = '', texts = []) { const digits = normalizePhoneDigits(phoneNumber); if (!digits) { return ''; } const textDialCodes = texts .map((text) => normalizePhoneDigits(extractDialCodeFromText(text))) .filter((dialCode) => dialCode && digits.startsWith(dialCode) && digits.length > dialCode.length) .sort((left, right) => right.length - left.length); if (textDialCodes[0]) { return textDialCodes[0]; } return KNOWN_DIAL_CODES.find((code) => digits.startsWith(code) && digits.length > code.length) || ''; } function findOptionByCountryLabel(options, countryLabel, config = {}) { const source = Array.from(options || []); const normalizedTargets = getCountryLabelAliases(countryLabel); if (source.length === 0 || normalizedTargets.length === 0) { return null; } return source.find((option) => ( getOptionMatchLabels(option, config).some((label) => normalizedTargets.includes(normalizeCountryLabel(label))) )) || source.find((option) => { const normalizedLabels = getOptionMatchLabels(option, config) .map((label) => normalizeCountryLabel(label)) .filter(Boolean); return normalizedLabels.some((optionLabel) => normalizedTargets.some((normalizedTarget) => ( optionLabel.length > 2 && normalizedTarget.length > 2 && (optionLabel.includes(normalizedTarget) || normalizedTarget.includes(optionLabel)) ))); }) || null; } function findOptionByPhoneNumber(options, phoneNumber, config = {}) { const source = Array.from(options || []); const digits = normalizePhoneDigits(phoneNumber); if (source.length === 0 || !digits) { return null; } const getLabel = typeof config.getOptionLabel === 'function' ? config.getOptionLabel : getOptionLabel; let bestMatch = null; let bestDialCodeLength = 0; for (const option of source) { const dialCode = normalizePhoneDigits(extractDialCodeFromText(getLabel(option))); if (!dialCode || !digits.startsWith(dialCode) || dialCode.length <= bestDialCodeLength) { continue; } bestMatch = option; bestDialCodeLength = dialCode.length; } return bestMatch; } function findElementByDialCode(elements, phoneNumber, config = {}) { const source = Array.from(elements || []); const digits = normalizePhoneDigits(phoneNumber); if (source.length === 0 || !digits) { return null; } const getText = typeof config.getText === 'function' ? config.getText : getOptionLabel; let bestMatch = null; let bestDialCodeLength = 0; for (const element of source) { const dialCode = normalizePhoneDigits(extractDialCodeFromText(getText(element))); if (!dialCode || !digits.startsWith(dialCode) || dialCode.length <= bestDialCodeLength) { continue; } bestMatch = element; bestDialCodeLength = dialCode.length; } return bestMatch; } return { extractDialCodeFromText, findElementByDialCode, findOptionByCountryLabel, findOptionByPhoneNumber, getCountryLabelAliases, getOptionLabel, getOptionMatchLabels, getRegionDisplayName, normalizeCountryLabel, normalizeCountryOptionValue, normalizePhoneDigits, resolveDialCodeFromPhoneNumber, }; });