Spaces:
Running
Running
Download script.js from stat2025/isic-arabic: direct link, hf CLI and curl.
- Browser
- Download file 7.01 kB
-
https://huggingface.co/spaces/stat2025/isic-arabic/resolve/main/script.js
- Command line
-
hf download hf://spaces/stat2025/isic-arabic/script.js
-
curl -L -o script.js https://huggingface.co/spaces/stat2025/isic-arabic/resolve/main/script.js
7.01 kB
| const searchBox = document.getElementById("searchBox"); | |
| const clearSearch = document.getElementById("clearSearch"); | |
| const pageSizeEl = document.getElementById("pageSize"); | |
| const themeBtn = document.getElementById("themeToggle"); | |
| const tableBody = document.getElementById("tableBody"); | |
| const pagination = document.getElementById("pagination"); | |
| const counter = document.getElementById("counter"); | |
| const loading = document.getElementById("loading"); | |
| let data = []; | |
| let filtered = []; | |
| let currentPage = 1; | |
| const DEFAULT_PAGE_SIZE = 10; | |
| let rowsPerPage = DEFAULT_PAGE_SIZE; | |
| if (pageSizeEl) pageSizeEl.value = String(DEFAULT_PAGE_SIZE); | |
| const colors = [ | |
| "#00bcd4", "#4caf50", "#f44336", "#ff9800", "#9c27b0", | |
| "#e91e63", "#009688", "#3f51b5", "#607d8b", "#795548" | |
| ]; | |
| function normalizeArabic(str = "") { | |
| return str | |
| .replace(/[\u064B-\u0652]/g, "") | |
| .replace(/[أإآا]/g, "ا") | |
| .replace(/ى/g, "ي") | |
| .replace(/ؤ/g, "و") | |
| .replace(/ئ/g, "ي") | |
| .replace(/ة/g, "ه") | |
| .toLowerCase(); | |
| } | |
| function matches(text, q) { | |
| if (!q) return true; | |
| return normalizeArabic(String(text ?? "")).includes(normalizeArabic(q)); | |
| } | |
| function highlight(text, q) { | |
| if (!q) return String(text ?? ""); | |
| const esc = q.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); | |
| return String(text ?? "").replace( | |
| new RegExp(esc, "gi"), | |
| m => `<mark class="hl">${m}</mark>` | |
| ); | |
| } | |
| function renderPagination() { | |
| const pages = Math.ceil(filtered.length / rowsPerPage); | |
| pagination.innerHTML = ""; | |
| if (pages <= 1) return; | |
| const makeBtn = (label, page, opts = {}) => { | |
| const b = document.createElement("button"); | |
| b.textContent = label; | |
| b.className = "page-btn" + (opts.ghost ? " ghost" : ""); | |
| b.disabled = !!opts.disabled; | |
| b.addEventListener("click", () => { | |
| currentPage = page; | |
| updateView(); | |
| window.scrollTo({ top: 0, behavior: "smooth" }); | |
| }); | |
| return b; | |
| }; | |
| pagination.appendChild( | |
| makeBtn("‹", Math.max(1, currentPage - 1), { | |
| ghost: true, | |
| disabled: currentPage === 1 | |
| }) | |
| ); | |
| const windowSize = 5; | |
| let total = pages; | |
| let start = Math.max(1, currentPage - Math.floor(windowSize / 2)); | |
| let end = Math.min(total, start + windowSize - 1); | |
| if (end - start + 1 < windowSize) { | |
| start = Math.max(1, end - windowSize + 1); | |
| } | |
| if (start > 1) { | |
| pagination.appendChild(makeBtn("1", 1, { ghost: currentPage !== 1 })); | |
| } | |
| if (start > 2) { | |
| pagination.appendChild( | |
| Object.assign(document.createElement("span"), { | |
| className: "dots", | |
| textContent: "..." | |
| }) | |
| ); | |
| } | |
| for (let p = start; p <= end; p++) { | |
| const btn = makeBtn(String(p), p); | |
| if (p === currentPage) btn.classList.add("active"); | |
| pagination.appendChild(btn); | |
| } | |
| if (end < total - 1) { | |
| pagination.appendChild( | |
| Object.assign(document.createElement("span"), { | |
| className: "dots", | |
| textContent: "..." | |
| }) | |
| ); | |
| } | |
| if (end < total) { | |
| pagination.appendChild( | |
| makeBtn(String(total), total, { ghost: currentPage !== total }) | |
| ); | |
| } | |
| pagination.appendChild( | |
| makeBtn("›", Math.min(total, currentPage + 1), { | |
| ghost: true, | |
| disabled: currentPage === total | |
| }) | |
| ); | |
| } | |
| function renderTable() { | |
| const q = searchBox.value.trim(); | |
| tableBody.innerHTML = ""; | |
| const start = (currentPage - 1) * rowsPerPage; | |
| const pageItems = filtered.slice(start, start + rowsPerPage); | |
| if (pageItems.length === 0) { | |
| const tr = document.createElement("tr"); | |
| const td = document.createElement("td"); | |
| td.colSpan = 3; | |
| td.className = "no-results"; | |
| td.textContent = "🤔 لا توجد نتائج مطابقة"; | |
| tr.appendChild(td); | |
| tableBody.appendChild(tr); | |
| return; | |
| } | |
| pageItems.forEach((it, i) => { | |
| const tr = document.createElement("tr"); | |
| const code = it.code ?? ""; | |
| const act = it.activity ?? it.name ?? ""; | |
| const codeTd = document.createElement("td"); | |
| codeTd.innerHTML = highlight(code, q); | |
| const actTd = document.createElement("td"); | |
| actTd.innerHTML = highlight(act, q); | |
| const colorTd = document.createElement("td"); | |
| const colorBar = document.createElement("div"); | |
| colorBar.className = "color-bar"; | |
| colorBar.style.backgroundColor = colors[i % colors.length]; | |
| colorTd.appendChild(colorBar); | |
| tr.appendChild(codeTd); | |
| tr.appendChild(actTd); | |
| tr.appendChild(colorTd); | |
| tableBody.appendChild(tr); | |
| }); | |
| } | |
| function updateView() { | |
| const q = searchBox.value.trim(); | |
| filtered = data.filter( | |
| it => matches(it.code, q) || matches(it.activity ?? it.name, q) | |
| ); | |
| if (!q) { | |
| counter.textContent = `📊 إجمالي الأنشطة: ${data.length.toLocaleString()}`; | |
| } else { | |
| counter.textContent = filtered.length | |
| ? `✅ عدد النتائج: ${filtered.length.toLocaleString()}` | |
| : "🤔 لا توجد نتائج مطابقة"; | |
| } | |
| if (loading) loading.style.display = "none"; | |
| renderTable(); | |
| renderPagination(); | |
| } | |
| function debounce(fn, delay = 200) { | |
| let t; | |
| return (...a) => { | |
| clearTimeout(t); | |
| t = setTimeout(() => fn(...a), delay); | |
| }; | |
| } | |
| searchBox.addEventListener( | |
| "input", | |
| debounce(() => { | |
| currentPage = 1; | |
| updateView(); | |
| }, 180) | |
| ); | |
| clearSearch.addEventListener("click", () => { | |
| searchBox.value = ""; | |
| searchBox.focus(); | |
| currentPage = 1; | |
| updateView(); | |
| }); | |
| pageSizeEl.addEventListener("change", () => { | |
| rowsPerPage = parseInt(pageSizeEl.value, 10); | |
| currentPage = 1; | |
| updateView(); | |
| }); | |
| document.addEventListener("keydown", (e) => { | |
| if (e.key === "/") { | |
| e.preventDefault(); | |
| searchBox.focus(); | |
| } | |
| }); | |
| (function initTheme() { | |
| const saved = localStorage.getItem("theme") || "light"; | |
| document.documentElement.classList.toggle("dark", saved === "dark"); | |
| themeBtn.textContent = saved === "dark" ? "☀️ فاتح" : "🌙 ليلي"; | |
| themeBtn.addEventListener("click", () => { | |
| const isDark = document.documentElement.classList.toggle("dark"); | |
| localStorage.setItem("theme", isDark ? "dark" : "light"); | |
| themeBtn.textContent = isDark ? "☀️ فاتح" : "🌙 ليلي"; | |
| }); | |
| })(); | |
| fetch("data.json", { cache: "no-cache" }) | |
| .then(r => r.json()) | |
| .then(json => { | |
| data = Array.isArray(json) | |
| ? json.map(row => { | |
| const rawCode = String( | |
| row.code ?? row.Code ?? row["رمز"] ?? "" | |
| ).trim(); | |
| return { | |
| code: rawCode.slice(0, 4), | |
| activity: row.activity ?? row.Activity ?? row.name ?? row["النشاط"] ?? "" | |
| }; | |
| }) | |
| : []; | |
| updateView(); | |
| }) | |
| .catch(err => { | |
| console.error(err); | |
| if (loading) loading.textContent = "تعذر تحميل البيانات ❌"; | |
| }); | |
| (function () { | |
| const tw = document.querySelector(".table-wrap"); | |
| if (!tw) return; | |
| let t; | |
| tw.addEventListener("scroll", () => { | |
| tw.classList.add("scrolling"); | |
| clearTimeout(t); | |
| t = setTimeout(() => tw.classList.remove("scrolling"), 180); | |
| }); | |
| })(); |