isic-arabic / script.js
stat2025's picture
Update script.js
64d386f verified
Raw History Blame Contribute Delete
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);
});
})();