stat2025 commited on
Commit
8ecf0f5
·
verified ·
1 Parent(s): 7eeb134

Update script.js

Browse files
Files changed (1) hide show
  1. script.js +155 -46
script.js CHANGED
@@ -1,65 +1,174 @@
1
- const tableBody = document.getElementById("tableBody");
2
- const searchBox = document.getElementById("searchBox");
3
- const counter = document.getElementById("counter");
4
- const noResults = document.getElementById("noResults");
5
- const themeToggle = document.getElementById("themeToggle");
 
 
 
 
6
 
 
7
  let data = [];
 
 
 
8
 
9
- // تحميل البيانات من ملف JSON أو API
10
- fetch("data.json")
11
- .then(res => res.json())
12
- .then(json => {
13
- data = json;
14
- renderTable(data);
15
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
- // رسم الجدول
18
- function renderTable(list) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  tableBody.innerHTML = "";
20
 
21
- if (list.length === 0) {
22
- noResults.classList.remove("hidden");
23
- counter.textContent = "📊 إجمالي الأنشطة: 0";
 
 
 
 
 
 
 
24
  return;
25
- } else {
26
- noResults.classList.add("hidden");
27
  }
28
 
29
- list.forEach(item => {
30
  const tr = document.createElement("tr");
 
 
 
 
 
31
 
32
- const tdAct = document.createElement("td");
33
- tdAct.textContent = item.activity;
34
- tr.appendChild(tdAct);
35
 
36
- const tdCode = document.createElement("td");
37
- tdCode.textContent = item.code;
38
- tr.appendChild(tdCode);
 
 
39
 
 
40
  tableBody.appendChild(tr);
41
  });
42
-
43
- counter.textContent = `📊 إجمالي الأنشطة: ${list.length.toLocaleString()}`;
44
  }
45
 
46
- // البحث المباشر
47
- searchBox.addEventListener("input", e => {
48
- const q = e.target.value.trim();
49
- const filtered = data.filter(
50
- item =>
51
- item.code.toString().includes(q) ||
52
- item.activity.includes(q)
53
- );
54
- renderTable(filtered);
55
- });
56
-
57
- // زر الوضع الليلي
58
- themeToggle.addEventListener("click", () => {
59
- document.body.classList.toggle("dark");
60
- if (document.body.classList.contains("dark")) {
61
- themeToggle.textContent = "☀️ نهاري";
62
  } else {
63
- themeToggle.textContent = "🌙 ليلي";
 
 
64
  }
65
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // عناصر الواجهة
2
+ const searchBox = document.getElementById("searchBox");
3
+ const clearSearch = document.getElementById("clearSearch");
4
+ const pageSizeEl = document.getElementById("pageSize");
5
+ const themeBtn = document.getElementById("themeToggle");
6
+ const tableBody = document.getElementById("tableBody");
7
+ const pagination = document.getElementById("pagination");
8
+ const counter = document.getElementById("counter");
9
+ const loading = document.getElementById("loading");
10
 
11
+ // حالة
12
  let data = [];
13
+ let filtered = [];
14
+ let currentPage = 1;
15
+ let rowsPerPage = parseInt(pageSizeEl.value, 10);
16
 
17
+ // ألوان جانبية
18
+ const colors = ["#00bcd4","#4caf50","#f44336","#ff9800","#9c27b0","#e91e63","#009688","#3f51b5","#607d8b","#795548"];
19
+
20
+ /* ========= أدوات بحث عربية ========= */
21
+ function normalizeArabic(str=""){
22
+ return str
23
+ .replace(/[\u064B-\u0652]/g, "")
24
+ .replace(/[أإآا]/g,"ا").replace(/ى/g,"ي")
25
+ .replace(/ؤ/g,"و").replace(/ئ/g,"ي").replace(/ة/g,"ه")
26
+ .toLowerCase();
27
+ }
28
+ function matches(text, q){
29
+ if(!q) return true;
30
+ return normalizeArabic(String(text ?? "")).includes(normalizeArabic(q));
31
+ }
32
+ function highlight(text, q){
33
+ if(!q) return String(text ?? "");
34
+ const esc = q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
35
+ return String(text ?? "").replace(new RegExp(esc, 'gi'), m => `<mark class="hl">${m}</mark>`);
36
+ }
37
+
38
+ /* ========= ترقيم الصفحات ========= */
39
+ function renderPagination(){
40
+ const pages = Math.ceil(filtered.length / rowsPerPage);
41
+ pagination.innerHTML = "";
42
+ if (pages <= 1) return;
43
+
44
+ const makeBtn = (label, page, opts={})=>{
45
+ const b = document.createElement("button");
46
+ b.textContent = label;
47
+ b.className = "page-btn" + (opts.ghost ? " ghost" : "");
48
+ b.disabled = !!opts.disabled;
49
+ b.addEventListener("click", ()=>{
50
+ currentPage = page;
51
+ updateView();
52
+ window.scrollTo({top:0, behavior:"smooth"});
53
+ });
54
+ return b;
55
+ };
56
+
57
+ pagination.appendChild(makeBtn("‹", Math.max(1, currentPage-1), {ghost:true, disabled: currentPage===1}));
58
 
59
+ const windowSize = 5;
60
+ let total = pages;
61
+ let start = Math.max(1, currentPage - Math.floor(windowSize/2));
62
+ let end = Math.min(total, start + windowSize - 1);
63
+ if (end - start + 1 < windowSize) start = Math.max(1, end - windowSize + 1);
64
+
65
+ if (start > 1) pagination.appendChild(makeBtn("1", 1, {ghost: currentPage!==1}));
66
+ if (start > 2) pagination.appendChild(Object.assign(document.createElement("span"), {className:"dots", textContent:"..."}));
67
+
68
+ for (let p=start; p<=end; p++){
69
+ const btn = makeBtn(String(p), p);
70
+ if (p === currentPage) btn.classList.add("active");
71
+ pagination.appendChild(btn);
72
+ }
73
+
74
+ if (end < total - 1) pagination.appendChild(Object.assign(document.createElement("span"), {className:"dots", textContent:"..."}));
75
+ if (end < total) pagination.appendChild(makeBtn(String(total), total, {ghost: currentPage!==total}));
76
+
77
+ pagination.appendChild(makeBtn("›", Math.min(total, currentPage+1), {ghost:true, disabled: currentPage===total}));
78
+ }
79
+
80
+ /* ========= عرض الجدول ========= */
81
+ function renderTable(){
82
+ const q = searchBox.value.trim();
83
  tableBody.innerHTML = "";
84
 
85
+ const start = (currentPage - 1) * rowsPerPage;
86
+ const pageItems = filtered.slice(start, start + rowsPerPage);
87
+
88
+ if (pageItems.length === 0) {
89
+ const tr = document.createElement("tr");
90
+ const td = document.createElement("td");
91
+ td.colSpan = 3; td.className = "no-results";
92
+ td.textContent = "🤔 لا توجد نتائج مطابقة";
93
+ tr.appendChild(td);
94
+ tableBody.appendChild(tr);
95
  return;
 
 
96
  }
97
 
98
+ pageItems.forEach((it, i)=>{
99
  const tr = document.createElement("tr");
100
+ const code = it.code ?? "";
101
+ const act = it.activity ?? it.name ?? "";
102
+
103
+ const codeTd = document.createElement("td");
104
+ codeTd.innerHTML = highlight(code, q);
105
 
106
+ const actTd = document.createElement("td");
107
+ actTd.innerHTML = highlight(act, q);
 
108
 
109
+ const colorTd = document.createElement("td");
110
+ const colorBar = document.createElement("div");
111
+ colorBar.className = "color-bar";
112
+ colorBar.style.backgroundColor = colors[i % colors.length];
113
+ colorTd.appendChild(colorBar);
114
 
115
+ tr.appendChild(codeTd); tr.appendChild(actTd); tr.appendChild(colorTd);
116
  tableBody.appendChild(tr);
117
  });
 
 
118
  }
119
 
120
+ /* ========= تحديث العرض ========= */
121
+ function updateView(){
122
+ const q = searchBox.value.trim();
123
+ filtered = data.filter(it => matches(it.code, q) || matches(it.activity ?? it.name, q));
124
+
125
+ // عدّاد مباشر بالرموز
126
+ if (!q) {
127
+ counter.textContent = `📊 إجمالي الأنشطة: ${data.length.toLocaleString()}`;
 
 
 
 
 
 
 
 
128
  } else {
129
+ counter.textContent = filtered.length
130
+ ? `✅ عدد النتائج: ${filtered.length.toLocaleString()}`
131
+ : "🤔 لا توجد نتائج مطابقة";
132
  }
133
+
134
+ if (loading) loading.style.display = "none";
135
+ renderTable();
136
+ renderPagination();
137
+ }
138
+
139
+ /* ========= أحداث ========= */
140
+ function debounce(fn, delay=200){ let t; return (...a)=>{ clearTimeout(t); t=setTimeout(()=>fn(...a), delay); }; }
141
+
142
+ searchBox.addEventListener("input", debounce(()=>{ currentPage=1; updateView(); }, 180));
143
+ clearSearch.addEventListener("click", ()=>{ searchBox.value=""; searchBox.focus(); currentPage=1; updateView(); });
144
+ pageSizeEl.addEventListener("change", ()=>{ rowsPerPage = parseInt(pageSizeEl.value, 10); currentPage=1; updateView(); });
145
+
146
+ // اختصار للانتقال للبحث
147
+ document.addEventListener("keydown", (e)=>{ if(e.key==="/"){ e.preventDefault(); searchBox.focus(); } });
148
+
149
+ /* ========= وضع ليلي ========= */
150
+ (function initTheme(){
151
+ const saved = localStorage.getItem("theme") || "light";
152
+ document.documentElement.classList.toggle("dark", saved === "dark");
153
+ themeBtn.textContent = saved === "dark" ? "☀️ فاتح" : "🌙 ليلي";
154
+ themeBtn.addEventListener("click", ()=>{
155
+ const isDark = document.documentElement.classList.toggle("dark");
156
+ localStorage.setItem("theme", isDark ? "dark" : "light");
157
+ themeBtn.textContent = isDark ? "☀️ فاتح" : "🌙 ليلي";
158
+ });
159
+ })();
160
+
161
+ /* ========= تحميل البيانات ========= */
162
+ fetch("data.json", { cache: "no-cache" })
163
+ .then(r=> r.json())
164
+ .then(json=>{
165
+ data = Array.isArray(json) ? json.map(row=>({
166
+ code: row.code ?? row.Code ?? row["رمز"] ?? "",
167
+ activity: row.activity ?? row.Activity ?? row.name ?? row["النشاط"] ?? ""
168
+ })) : [];
169
+ updateView();
170
+ })
171
+ .catch(err=>{
172
+ console.error(err);
173
+ if (loading) loading.textContent = "تعذر تحميل البيانات ❌";
174
+ });