| const FIELD_MAP = { |
| name: "إسم المنشأة", |
| phone: "رقم التواصل", |
| email: "البريد الالكتروني", |
| city: "المدينة الصناعية", |
| commercialRegister: "السجل التجاري من الاطار", |
| activityCode: "كود النشاط", |
| activity: "النشاط" |
| };
|
|
|
| const ICONS = {
|
| phone: `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2a1.3 1.3 0 0 1 1.34-.31c1.47.49 3.04.75 4.65.75.72 0 1.3.58 1.3 1.3v3.48c0 .72-.58 1.3-1.3 1.3C10.52 21.7 1.8 12.98 1.8 2.1 1.8 1.38 2.38.8 3.1.8h3.5c.72 0 1.3.58 1.3 1.3 0 1.62.26 3.18.75 4.65.14.47.03.99-.32 1.33l-1.71 1.71Z" /></svg>`,
|
| whatsapp: `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12.04 2.2a9.7 9.7 0 0 0-8.39 14.56L2.6 21.8l5.17-1.23a9.67 9.67 0 0 0 4.27.99h.01a9.68 9.68 0 0 0 0-19.36Zm5.7 13.65c-.24.68-1.39 1.3-1.95 1.38-.5.08-1.14.12-1.84-.12-.43-.14-.98-.32-1.68-.63-2.96-1.28-4.88-4.26-5.03-4.46-.15-.2-1.2-1.59-1.2-3.04s.76-2.16 1.03-2.45c.27-.3.58-.37.78-.37h.56c.18.01.42-.07.66.5.24.58.82 2 .89 2.15.07.15.12.32.02.52-.1.2-.15.32-.3.49-.15.17-.32.38-.45.51-.15.15-.3.31-.13.61.17.3.75 1.24 1.61 2.01 1.1.98 2.03 1.28 2.33 1.43.3.15.47.13.64-.08.17-.2.74-.86.94-1.15.2-.3.4-.25.66-.15.27.1 1.72.81 2.01.96.3.15.5.22.57.35.07.12.07.72-.17 1.4Z" /></svg>`
|
| };
|
|
|
| const queryInput = document.getElementById("query");
|
| const resultsEl = document.getElementById("results");
|
| const clearButton = document.getElementById("clearButton"); |
| const emptyTemplate = document.getElementById("emptyTemplate");
|
|
|
| function escapeHtml(value) {
|
| return String(value ?? "")
|
| .replaceAll("&", "&")
|
| .replaceAll("<", "<")
|
| .replaceAll(">", ">")
|
| .replaceAll('"', """)
|
| .replaceAll("'", "'");
|
| }
|
|
|
| function normalizeArabic(value) {
|
| return String(value || "")
|
| .toLowerCase() |
| .replace(/[إأآا]/g, "ا") |
| .replace(/ى/g, "ي") |
| .replace(/ة/g, "ه") |
| .replace(/ؤ/g, "و") |
| .replace(/ئ/g, "ي") |
| .replace(/[ً-ٰٟ]/g, "")
|
| .replace(/\s+/g, " ")
|
| .trim();
|
| }
|
|
|
| function digitsOnly(value) {
|
| return String(value || "").replace(/\D/g, "");
|
| }
|
|
|
| function formatPhoneDisplay(value) { |
| const digits = digitsOnly(value); |
| if (!digits || digits === "0") return "غير متاح"; |
| if (digits.length === 9 && digits.startsWith("5")) return `0${digits}`; |
| return digits; |
| } |
|
|
| function hasUsefulValue(value) { |
| const text = String(value ?? "").trim(); |
| if (!text) return false; |
| const normalized = text.replace(/\s+/g, "").replace(/[ـ-]/g, ""); |
| if (!normalized) return false; |
| if (/^0+$/.test(digitsOnly(normalized)) && !/[^\d\s+()-]/.test(normalized)) return false; |
| return !["غيرمتاح", "لايوجد", "لاينطبق", "nan", "null", "undefined"].includes(normalizeArabic(normalized)); |
| } |
|
|
| function toSaudiInternational(value) {
|
| let digits = digitsOnly(value);
|
| if (!digits || digits === "0") return "";
|
| if (digits.startsWith("00")) digits = digits.slice(2);
|
| if (digits.startsWith("+")) digits = digits.slice(1);
|
| if (digits.startsWith("966")) return digits;
|
| if (digits.startsWith("0") && digits.length >= 9) return `966${digits.slice(1)}`;
|
| if (digits.startsWith("5") && digits.length === 9) return `966${digits}`;
|
| return digits.length >= 7 ? digits : "";
|
| }
|
|
|
| function highlightName(name, query) {
|
| const original = String(name || "");
|
| const q = String(query || "").trim();
|
| if (!original || !q) return escapeHtml(original || "-");
|
|
|
| const index = original.toLowerCase().indexOf(q.toLowerCase());
|
| if (index === -1) return escapeHtml(original);
|
|
|
| const before = escapeHtml(original.slice(0, index));
|
| const match = escapeHtml(original.slice(index, index + q.length));
|
| const after = escapeHtml(original.slice(index + q.length));
|
| return `${before}<mark>${match}</mark>${after}`;
|
| }
|
|
|
| function field(label, value, options = {}) { |
| if (!hasUsefulValue(value)) return ""; |
|
|
| const display = value && String(value).trim() ? value : "-"; |
| const content = options.html || escapeHtml(display); |
| const classes = ["info-field", options.full ? "full" : ""].filter(Boolean).join(" "); |
| const valueClasses = ["value", options.ltr ? "ltr" : ""].filter(Boolean).join(" "); |
| const action = options.action || ""; |
|
|
| return ` |
| <div class="${classes}"> |
| <span class="label">${escapeHtml(label)}</span> |
| <div class="field-line"> |
| <div class="${valueClasses}">${content}</div> |
| ${action} |
| </div> |
| </div> |
| `; |
| } |
|
|
| function whatsappAction(phone) { |
| const normalized = toSaudiInternational(phone); |
| if (!normalized) return ""; |
| const disabled = !normalized; |
| const whatsHref = disabled ? "#" : `https://wa.me/${normalized}`; |
| const disabledClass = disabled ? " disabled" : ""; |
|
|
| return ` |
| <a class="inline-whatsapp${disabledClass}" href="${whatsHref}" target="_blank" rel="noopener" title="واتساب" aria-label="واتساب">${ICONS.whatsapp}</a> |
| `; |
| } |
|
|
| function renderEmpty() { |
| const node = emptyTemplate.content.cloneNode(true); |
| resultsEl.replaceChildren(node); |
| } |
|
|
| function renderResults(items, query) {
|
| if (!query.trim()) {
|
| renderEmpty();
|
| return;
|
| }
|
|
|
| if (!items.length) { |
| renderEmpty(); |
| return; |
| } |
|
|
| resultsEl.innerHTML = items.map((item) => {
|
| const name = item[FIELD_MAP.name] || "-"; |
| const phone = item[FIELD_MAP.phone] || ""; |
| const email = item[FIELD_MAP.email] || ""; |
| const city = item[FIELD_MAP.city] || ""; |
| const emailHtml = hasUsefulValue(email) ? `<a href="mailto:${escapeHtml(email)}">${escapeHtml(email)}</a>` : ""; |
|
|
| return ` |
| <article class="result-card"> |
| <div class="card-head"> |
| <div> |
| <h2 class="entity-title">${highlightName(name, query)}</h2> |
| ${hasUsefulValue(city) ? `<p class="entity-meta">${escapeHtml(city)}</p>` : ""} |
| </div> |
| </div> |
| <div class="card-body"> |
| ${field("رقم التواصل", phone, { html: escapeHtml(formatPhoneDisplay(phone)), ltr: true, action: whatsappAction(phone) })} |
| ${field("البريد الالكتروني", email, { html: emailHtml, ltr: true })} |
| ${field("السجل التجاري", item[FIELD_MAP.commercialRegister], { ltr: true })} |
| ${field("كود النشاط", item[FIELD_MAP.activityCode], { ltr: true })} |
| ${field("المدينة الصناعية", city)} |
| ${field("النشاط", item[FIELD_MAP.activity], { full: true })} |
| </div>
|
| </article>
|
| `;
|
| }).join("");
|
| }
|
|
|
| function search() {
|
| const query = queryInput.value.trim();
|
| const normalizedQuery = normalizeArabic(query);
|
|
|
| const matches = DATA.filter((item) => {
|
| const name = normalizeArabic(item[FIELD_MAP.name]);
|
| return normalizedQuery && name.includes(normalizedQuery);
|
| }).sort((a, b) => String(a[FIELD_MAP.name] || "").localeCompare(String(b[FIELD_MAP.name] || ""), "ar"));
|
|
|
| renderResults(matches, query);
|
| }
|
|
|
| queryInput.addEventListener("input", search); |
| queryInput.addEventListener("keydown", (event) => {
|
| if (event.key === "Enter") search();
|
| });
|
| clearButton.addEventListener("click", () => {
|
| queryInput.value = "";
|
| queryInput.focus();
|
| renderEmpty();
|
| });
|
|
|
| renderEmpty();
|
|
|