| |
| |
| |
| |
|
|
|
|
| (global => {
|
| 'use strict';
|
|
|
| const PhoneResolverEngine = {
|
| |
| |
| |
|
|
| normalize: function(phone) {
|
| if (!phone) return '';
|
| let cleaned = String(phone).trim().replace(/[^0-9+]/g, '');
|
|
|
| if (cleaned.startsWith('00')) {
|
| cleaned = '+' + cleaned.slice(2);
|
| }
|
|
|
| if (!cleaned.startsWith('+') && cleaned.length >= 10) {
|
| if (cleaned.startsWith('01') && cleaned.length === 11) {
|
| cleaned = '+20' + cleaned.slice(1);
|
| } else if (!cleaned.startsWith('+')) {
|
| cleaned = '+' + cleaned;
|
| }
|
| }
|
|
|
| return cleaned;
|
| },
|
|
|
| |
| |
| |
|
|
| validatePhoneFormat: function(phone) {
|
| const norm = this.normalize(phone);
|
| const digits = norm.replace(/[^0-9]/g, '');
|
|
|
| return {
|
| isValid: digits.length >= 8 && digits.length <= 16,
|
| normalized: norm,
|
| digitsCount: digits.length
|
| };
|
| },
|
|
|
| |
| |
| |
| |
|
|
| lookupByPhone: function(rawPhone, contactsList = []) {
|
| if (!rawPhone) return null;
|
| const normTarget = this.normalize(rawPhone);
|
| if (!normTarget) return null;
|
|
|
| const exactMatch = contactsList.find(c => {
|
| const normC = this.normalize(c.phone);
|
| if (normC === normTarget) return true;
|
|
|
| if (c.altPhones && Array.isArray(c.altPhones)) {
|
| return c.altPhones.some(ap => {
|
| const pVal = typeof ap === 'object' ? ap.phone : ap;
|
| return this.normalize(pVal) === normTarget;
|
| });
|
| }
|
| return false;
|
| });
|
|
|
| if (exactMatch) return exactMatch;
|
|
|
| const digitsOnly = normTarget.replace(/[^0-9]/g, '');
|
| if (digitsOnly.length >= 8) {
|
| const partialMatch = contactsList.find(c => {
|
| const cDigits = (c.phone || '').replace(/[^0-9]/g, '');
|
| return cDigits.endsWith(digitsOnly) || digitsOnly.endsWith(cDigits);
|
| });
|
| if (partialMatch) return partialMatch;
|
| }
|
|
|
| return null;
|
| },
|
|
|
| bindGlobalAutoResolution: function() {
|
| if (window.__fritreeGlobalPhoneAutoResBound) return;
|
| window.__fritreeGlobalPhoneAutoResBound = true;
|
|
|
| document.addEventListener('input', (e) => {
|
| const target = e.target;
|
| if (!target || (target.tagName !== 'INPUT' && target.tagName !== 'TEXTAREA')) return;
|
| if (target.classList.contains('kljqnbvx11')) return;
|
|
|
| const val = target.value;
|
| if (!val || val.length < 8) return;
|
|
|
| const cleaned = this.normalize(val);
|
| if (cleaned && cleaned.length >= 8) {
|
| const contacts = global.FritreeContacts ? global.FritreeContacts.getContacts() : [];
|
| const match = this.lookupByPhone(cleaned, contacts);
|
|
|
| if (match && match.name) {
|
| const parentForm = target.closest('div, form, section') || target.parentNode;
|
| if (parentForm) {
|
| const nameInputs = parentForm.querySelectorAll('input[type="text"]:not([readonly]), input[id*="name"], input[placeholder*="اسم"]');
|
| nameInputs.forEach(input => {
|
| if (input !== target && !input.value) {
|
| input.value = match.name;
|
| input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
|
| const originalBg = input.style.backgroundColor;
|
| input.style.backgroundColor = '#dcfce7';
|
| input.style.transition = 'background-color 0.3s ease';
|
| setTimeout(() => {
|
| input.style.backgroundColor = originalBg || '';
|
| }, 1600);
|
| }
|
| });
|
| }
|
| }
|
| }
|
| });
|
| }
|
| };
|
|
|
| global.FritreeContactsResolver = PhoneResolverEngine;
|
|
|
| })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this); |