stat2025 commited on
Commit
94f42cc
·
verified ·
1 Parent(s): c8f1631

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +227 -24
index.html CHANGED
@@ -29,10 +29,10 @@
29
 
30
  <!-- تعريف بسيط -->
31
  <section class="hero">
32
- <h1>ادمج ملفاتك بسهولة في PDF واحد منسّق.</h1>
33
  <p>
34
- اختر مجموعة من الصور أو ملفات PDF، وسيتم إنشاء ملف PDF واحد مرتب حسب أسماء الملفات،
35
- للاستخدام الداخلي ضمن مجموعتك.
36
  </p>
37
  </section>
38
 
@@ -40,15 +40,15 @@
40
  <section class="steps">
41
  <div class="step">
42
  <span class="step-number">1</span>
43
- <span class="step-text">اضغط لاختيار الملفات، ويمكن الإضافة على دفعات.</span>
44
  </div>
45
  <div class="step">
46
  <span class="step-number">2</span>
47
- <span class="step-text">استخدم إما صورًا فقط أو ملفات PDF فقط في كل عملية.</span>
48
  </div>
49
  <div class="step">
50
  <span class="step-number">3</span>
51
- <span class="step-text">احصل على ملف PDF واحد جاهز للتحميل.</span>
52
  </div>
53
  </section>
54
 
@@ -57,13 +57,13 @@
57
 
58
  <!-- اختيار الملفات -->
59
  <div class="card-row">
60
- <h2 class="card-title">اختر الملفات المراد دمجها</h2>
61
  <p class="hint">
62
  يدعم:
63
  <strong>دمج عدة ملفات PDF</strong> في ملف واحد،
64
  أو
65
  <strong>تحويل عدة صور (JPG / PNG)</strong> إلى ملف PDF واحد.
66
- لا تخلط بين الصور وملفات PDF في نفس العملية.
67
  </p>
68
 
69
  <label class="file-picker">
@@ -87,11 +87,10 @@
87
  />
88
  </div>
89
 
90
- <!-- زر الدمج -->
91
  <div class="actions">
92
- <button id="mergeBtn" class="btn-main">
93
- دمج وإنشاء ملف PDF واحد
94
- </button>
95
  </div>
96
 
97
  <!-- حالة العملية -->
@@ -101,19 +100,223 @@
101
  </div>
102
 
103
  <script>
104
- .delete-btn {
105
- background: none;
106
- border: none;
107
- cursor: pointer;
108
- font-size: 14px;
109
- transition: 0.2s;
110
- }
111
-
112
- .delete-btn:hover {
113
- color: #b91c1c;
114
- transform: scale(1.1);
115
- }
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  </script>
118
  </body>
119
  </html>
 
29
 
30
  <!-- تعريف بسيط -->
31
  <section class="hero">
32
+ <h1>ادمج ملفاتك بسهولة في ملف PDF واحد منسّق.</h1>
33
  <p>
34
+ اختر مجموعة من الصور أو ملفات PDF، وستقوم الأداة بإنشاء ملف PDF واحد مرتب حسب أسماء الملفات،
35
+ ليسهل حفظه ومشاركته بين أعضاء المجموعة.
36
  </p>
37
  </section>
38
 
 
40
  <section class="steps">
41
  <div class="step">
42
  <span class="step-number">1</span>
43
+ <span class="step-text">اختر ملفاتك (يمكن الإضافة على دفعات من الجوال أو الكمبيوتر).</span>
44
  </div>
45
  <div class="step">
46
  <span class="step-number">2</span>
47
+ <span class="step-text">تأكد أن الملفات: صور فقط أو PDF فقط في نفس العملية.</span>
48
  </div>
49
  <div class="step">
50
  <span class="step-number">3</span>
51
+ <span class="step-text">اضغط "دمج" لتحميل ملف PDF النهائي مباشرة.</span>
52
  </div>
53
  </section>
54
 
 
57
 
58
  <!-- اختيار الملفات -->
59
  <div class="card-row">
60
+ <h2 class="card-title">اختيار الملفات</h2>
61
  <p class="hint">
62
  يدعم:
63
  <strong>دمج عدة ملفات PDF</strong> في ملف واحد،
64
  أو
65
  <strong>تحويل عدة صور (JPG / PNG)</strong> إلى ملف PDF واحد.
66
+ لا تخلط بين الصور وملفات PDF في عملية واحدة لتفادي الخطأ.
67
  </p>
68
 
69
  <label class="file-picker">
 
87
  />
88
  </div>
89
 
90
+ <!-- الأزرار -->
91
  <div class="actions">
92
+ <button id="mergeBtn" class="btn-main">دمج وإنشاء ملف PDF واحد</button>
93
+ <button id="clearBtn" class="btn-secondary" type="button">مسح جميع الملفات</button>
 
94
  </div>
95
 
96
  <!-- حالة العملية -->
 
100
  </div>
101
 
102
  <script>
103
+ const filesInput = document.getElementById("files");
104
+ const mergeBtn = document.getElementById("mergeBtn");
105
+ const clearBtn = document.getElementById("clearBtn");
106
+ const statusDiv = document.getElementById("status");
107
+ const fileListDiv = document.getElementById("fileList");
108
+ const outputNameInput = document.getElementById("outputName");
 
 
 
 
 
 
109
 
110
+ // مصفوفة للاحتفاظ بكل الملفات المختارة (من عدة مرات اختيار)
111
+ let selectedFiles = [];
112
+
113
+ function setStatus(msg, type = "") {
114
+ statusDiv.textContent = msg;
115
+ statusDiv.className = "status" + (type ? " " + type : "");
116
+ if (!msg) statusDiv.className = "status";
117
+ }
118
+
119
+ function renderFileList(files) {
120
+ if (!files.length) {
121
+ fileListDiv.classList.add("hidden");
122
+ fileListDiv.innerHTML = "";
123
+ return;
124
+ }
125
+
126
+ fileListDiv.classList.remove("hidden");
127
+ fileListDiv.innerHTML = `
128
+ <div class="file-list-header">
129
+ <span>الملفات المختارة: ${files.length}</span>
130
+ <span class="file-note">يمكنك حذف أي ملف قبل الدمج أو مسح الكل.</span>
131
+ </div>
132
+ <ul class="file-list-ul">
133
+ ${files
134
+ .map(
135
+ (f, i) => `
136
+ <li>
137
+ <span class="index">${i + 1}</span>
138
+ <span class="name" title="${f.name}">${f.name}</span>
139
+ <span class="size">${(f.size / 1024).toFixed(1)} كيلوبايت</span>
140
+ <button class="delete-btn" data-index="${i}" title="حذف هذا الملف">🗑️</button>
141
+ </li>`
142
+ )
143
+ .join("")}
144
+ </ul>
145
+ `;
146
+
147
+ // أزرار الحذف لكل ملف
148
+ fileListDiv.querySelectorAll(".delete-btn").forEach((btn) => {
149
+ btn.addEventListener("click", (e) => {
150
+ const index = parseInt(e.currentTarget.dataset.index, 10);
151
+ if (!isNaN(index)) {
152
+ selectedFiles.splice(index, 1);
153
+ renderFileList(selectedFiles);
154
+ setStatus("");
155
+ }
156
+ });
157
+ });
158
+ }
159
+
160
+ function detectMode(files) {
161
+ if (!files.length) return null;
162
+ const allImages = files.every((f) => f.type.startsWith("image/"));
163
+ const allPDFs = files.every(
164
+ (f) =>
165
+ f.type === "application/pdf" ||
166
+ f.name.toLowerCase().endsWith(".pdf")
167
+ );
168
+ if (allImages) return "images";
169
+ if (allPDFs) return "pdfs";
170
+ return null;
171
+ }
172
+
173
+ function downloadPdf(bytes, filename) {
174
+ const blob = new Blob([bytes], { type: "application/pdf" });
175
+ const url = URL.createObjectURL(blob);
176
+ const a = document.createElement("a");
177
+ a.href = url;
178
+ a.download = filename;
179
+ document.body.appendChild(a);
180
+ a.click();
181
+ a.remove();
182
+ URL.revokeObjectURL(url);
183
+ }
184
+
185
+ // إضافة ملفات على دفعات (مهم للجوال)
186
+ filesInput.addEventListener("change", () => {
187
+ const newFiles = Array.from(filesInput.files || []);
188
+ if (!newFiles.length) return;
189
+
190
+ // دمج بدون تكرار (اسم + حجم + وقت تعديل)
191
+ const map = new Map();
192
+ [...selectedFiles, ...newFiles].forEach((f) => {
193
+ const key = `${f.name}|${f.size}|${f.lastModified}`;
194
+ if (!map.has(key)) map.set(key, f);
195
+ });
196
+
197
+ selectedFiles = Array.from(map.values()).sort((a, b) =>
198
+ a.name.localeCompare(b.name, undefined, { numeric: true })
199
+ );
200
+
201
+ renderFileList(selectedFiles);
202
+ setStatus("");
203
+ filesInput.value = ""; // للسماح باختيار دفعات جديدة
204
+ });
205
+
206
+ // زر مسح جميع الملفات
207
+ clearBtn.addEventListener("click", () => {
208
+ selectedFiles = [];
209
+ renderFileList([]);
210
+ setStatus("تم مسح جميع الملفات المختارة.", "ok");
211
+ filesInput.value = "";
212
+ outputNameInput.value = "";
213
+ });
214
+
215
+ // تنفيذ الدمج
216
+ mergeBtn.addEventListener("click", async () => {
217
+ let files = [...selectedFiles];
218
+
219
+ if (!files.length) {
220
+ setStatus("الرجاء اختيار الملفات أولاً.", "error");
221
+ return;
222
+ }
223
+
224
+ const mode = detectMode(files);
225
+ if (!mode) {
226
+ setStatus(
227
+ "تنبيه: يجب أن تكون جميع الملفات صورًا فقط أو جميعها PDF فقط في العملية الواحدة.",
228
+ "error"
229
+ );
230
+ return;
231
+ }
232
+
233
+ // ترتيب حسب الاسم
234
+ files.sort((a, b) =>
235
+ a.name.localeCompare(b.name, undefined, { numeric: true })
236
+ );
237
+ renderFileList(files);
238
+
239
+ try {
240
+ setStatus("جاري معالجة الملفات...", "loading");
241
+ mergeBtn.disabled = true;
242
+ mergeBtn.classList.add("disabled");
243
+
244
+ if (mode === "images") {
245
+ const pdfDoc = await PDFLib.PDFDocument.create();
246
+
247
+ for (const file of files) {
248
+ const bytes = await file.arrayBuffer();
249
+ const lower = file.name.toLowerCase();
250
+
251
+ let image;
252
+ if (
253
+ file.type === "image/jpeg" ||
254
+ file.type === "image/jpg" ||
255
+ lower.endsWith(".jpg") ||
256
+ lower.endsWith(".jpeg")
257
+ ) {
258
+ image = await pdfDoc.embedJpg(bytes);
259
+ } else {
260
+ image = await pdfDoc.embedPng(bytes);
261
+ }
262
+
263
+ const imgWidth = image.width;
264
+ const imgHeight = image.height;
265
+ const pageWidth = 595.28; // A4
266
+ const pageHeight = 841.89; // A4
267
+
268
+ const page = pdfDoc.addPage([pageWidth, pageHeight]);
269
+ const scale = Math.min(pageWidth / imgWidth, pageHeight / imgHeight);
270
+ const drawWidth = imgWidth * scale;
271
+ const drawHeight = imgHeight * scale;
272
+ const x = (pageWidth - drawWidth) / 2;
273
+ const y = (pageHeight - drawHeight) / 2;
274
+
275
+ page.drawImage(image, { x, y, width: drawWidth, height: drawHeight });
276
+ }
277
+
278
+ const pdfBytes = await pdfDoc.save();
279
+ const outName =
280
+ (outputNameInput.value || "merged-images.pdf").trim() ||
281
+ "merged-images.pdf";
282
+ downloadPdf(pdfBytes, outName);
283
+ setStatus("تم إنشاء ملف PDF من الصور بنجاح.", "ok");
284
+ }
285
+
286
+ if (mode === "pdfs") {
287
+ const pdfDoc = await PDFLib.PDFDocument.create();
288
+
289
+ for (const file of files) {
290
+ const bytes = await file.arrayBuffer();
291
+ const donorPdf = await PDFLib.PDFDocument.load(bytes);
292
+ const pages = await pdfDoc.copyPages(
293
+ donorPdf,
294
+ donorPdf.getPageIndices()
295
+ );
296
+ pages.forEach((p) => pdfDoc.addPage(p));
297
+ }
298
+
299
+ const pdfBytes = await pdfDoc.save();
300
+ const outName =
301
+ (outputNameInput.value || "merged-pdfs.pdf").trim() ||
302
+ "merged-pdfs.pdf";
303
+ downloadPdf(pdfBytes, outName);
304
+ setStatus("تم دمج ملفات PDF بنجاح.", "ok");
305
+ }
306
+
307
+ // تنظيف بعد الدمج
308
+ selectedFiles = [];
309
+ renderFileList([]);
310
+ filesInput.value = "";
311
+ // لا نمسح اسم الملف؛ يمكن استخدامه مرة أخرى لو أحب
312
+ } catch (err) {
313
+ console.error(err);
314
+ setStatus("حدث خطأ أثناء المعالجة. تأكد من الملفات وحاول مرة أخرى.", "error");
315
+ } finally {
316
+ mergeBtn.disabled = false;
317
+ mergeBtn.classList.remove("disabled");
318
+ }
319
+ });
320
  </script>
321
  </body>
322
  </html>