ThorAILabs commited on
Commit
1310834
·
verified ·
1 Parent(s): a22420b

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +539 -93
index.html CHANGED
@@ -3,109 +3,555 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>DocX Editor</title>
7
-
8
- <!-- Tailwind CSS -->
9
  <script src="https://cdn.tailwindcss.com"></script>
10
-
11
- <!-- Font Awesome -->
12
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
13
-
14
- <!-- DOCX Libraries -->
15
- <script src="https://unpkg.com/mammoth@1.4.8/mammoth.browser.min.js"></script>
16
- <script src="https://cdn.jsdelivr.net/npm/html-docx-js@1.1.1/dist/html-docx.min.js"></script>
17
-
18
- <!-- Cookie Library -->
19
- <script src="https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  </head>
21
- <body class="bg-gray-100">
22
- <div class="container mx-auto px-4">
23
- <!-- Toolbar -->
24
- <div class="bg-white shadow-md sticky top-0 p-4 mb-4 flex gap-4">
25
- <input type="file" id="importFile" class="hidden" accept=".docx">
26
- <button onclick="document.getElementById('importFile').click()"
27
- class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded flex items-center gap-2">
28
- <i class="fas fa-file-import"></i>
29
- Import DOCX
30
- </button>
31
-
32
- <button onclick="exportDOCX()"
33
- class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded flex items-center gap-2">
34
- <i class="fas fa-file-export"></i>
35
- Export DOCX
36
- </button>
37
-
38
- <div class="flex items-center ml-auto text-gray-500">
39
- <i class="fas fa-save mr-2"></i>
40
- <span id="saveStatus">Auto-saved</span>
 
 
 
 
 
41
  </div>
42
  </div>
 
43
 
44
- <!-- Editor -->
45
- <div id="editor"
46
- class="bg-white shadow-lg min-h-[calc(100vh-150px)] p-8 text-lg focus:outline-none"
47
- contenteditable="true"
48
- oninput="scheduleSave()"></div>
49
- </div>
50
-
51
- <script>
52
- let timeoutId;
53
- const COOKIE_NAME = 'documentContent';
54
- const EDITOR = document.getElementById('editor');
55
-
56
- // Load saved content
57
- window.onload = () => {
58
- const savedContent = Cookies.get(COOKIE_NAME);
59
- if(savedContent) EDITOR.innerHTML = savedContent;
60
- };
61
 
62
- // Auto-save functionality
63
- function scheduleSave() {
64
- clearTimeout(timeoutId);
65
- timeoutId = setTimeout(() => {
66
- Cookies.set(COOKIE_NAME, EDITOR.innerHTML, { expires: 7 });
67
- document.getElementById('saveStatus').textContent = 'Auto-saved just now';
68
- }, 2000);
69
- }
70
 
71
- // DOCX Import
72
- document.getElementById('importFile').addEventListener('change', function(e) {
73
- const file = e.target.files[0];
74
- const reader = new FileReader();
75
-
76
- reader.onload = function() {
77
- mammoth.convertToHtml({ arrayBuffer: reader.result })
78
- .then(result => EDITOR.innerHTML = result.value)
79
- .catch(err => console.error(err));
80
- };
81
-
82
- reader.readAsArrayBuffer(file);
83
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- // DOCX Export
86
- function exportDOCX() {
87
- const content = `
88
- <html>
89
- <head><meta charset="UTF-8"></head>
90
- <body>${EDITOR.innerHTML}</body>
91
- </html>
92
- `;
93
-
94
- const converted = htmlDocx.asBlob(content);
95
- const url = URL.createObjectURL(converted);
96
-
97
- const a = document.createElement('a');
98
- a.href = url;
99
- a.download = 'document.docx';
100
- a.click();
101
- URL.revokeObjectURL(url);
102
- }
103
 
104
- // Handle paste to remove formatting
105
- EDITOR.addEventListener('paste', e => {
106
- e.preventDefault();
107
- const text = (e.clipboardData || window.clipboardData).getData('text');
108
- document.execCommand('insertText', false, text);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  });
110
  </script>
111
  </body>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>DocClone - Google Docs Clone</title>
 
 
7
  <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/docx/7.1.0/docx.min.js"></script>
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
10
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
+ <style>
12
+ .editor {
13
+ min-height: calc(100vh - 120px);
14
+ }
15
+ .document-item:hover {
16
+ background-color: #f3f4f6;
17
+ }
18
+ .document-item.active {
19
+ background-color: #e5e7eb;
20
+ }
21
+ #sidebar {
22
+ transition: all 0.3s ease;
23
+ }
24
+ @media (max-width: 768px) {
25
+ #sidebar {
26
+ position: fixed;
27
+ left: -100%;
28
+ top: 0;
29
+ z-index: 50;
30
+ height: 100vh;
31
+ width: 80%;
32
+ }
33
+ #sidebar.open {
34
+ left: 0;
35
+ }
36
+ #overlay {
37
+ display: none;
38
+ position: fixed;
39
+ top: 0;
40
+ left: 0;
41
+ right: 0;
42
+ bottom: 0;
43
+ background-color: rgba(0,0,0,0.5);
44
+ z-index: 40;
45
+ }
46
+ #overlay.open {
47
+ display: block;
48
+ }
49
+ }
50
+ </style>
51
  </head>
52
+ <body class="bg-gray-50">
53
+ <!-- Header -->
54
+ <header class="bg-white shadow-sm">
55
+ <div class="flex items-center justify-between px-4 py-2">
56
+ <div class="flex items-center space-x-4">
57
+ <button id="menu-btn" class="md:hidden text-gray-600">
58
+ <i class="fas fa-bars text-xl"></i>
59
+ </button>
60
+ <div class="flex items-center">
61
+ <i class="fas fa-file-word text-blue-500 text-2xl mr-2"></i>
62
+ <h1 class="text-xl font-bold text-gray-800">DocClone</h1>
63
+ </div>
64
+ </div>
65
+ <div class="flex items-center space-x-4">
66
+ <button id="save-btn" class="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition">
67
+ <i class="fas fa-save mr-1"></i> Save
68
+ </button>
69
+ <button id="export-btn" class="px-3 py-1 bg-green-500 text-white rounded hover:bg-green-600 transition">
70
+ <i class="fas fa-file-export mr-1"></i> Export DOCX
71
+ </button>
72
+ <div class="relative">
73
+ <button id="new-doc-btn" class="px-3 py-1 bg-purple-500 text-white rounded hover:bg-purple-600 transition">
74
+ <i class="fas fa-plus mr-1"></i> New
75
+ </button>
76
+ </div>
77
  </div>
78
  </div>
79
+ </header>
80
 
81
+ <!-- Main Content -->
82
+ <div class="flex">
83
+ <!-- Sidebar -->
84
+ <div id="sidebar" class="bg-white w-64 h-screen shadow-md overflow-y-auto">
85
+ <div class="p-4 border-b">
86
+ <h2 class="text-lg font-semibold text-gray-700">My Documents</h2>
87
+ </div>
88
+ <div id="documents-list" class="p-2">
89
+ <!-- Documents will be loaded here -->
90
+ </div>
91
+ </div>
 
 
 
 
 
 
92
 
93
+ <!-- Overlay for mobile -->
94
+ <div id="overlay" class=""></div>
 
 
 
 
 
 
95
 
96
+ <!-- Editor -->
97
+ <div class="flex-1">
98
+ <div class="bg-white shadow-sm p-4">
99
+ <div class="flex items-center space-x-4 overflow-x-auto">
100
+ <select id="font-family" class="px-2 py-1 border rounded">
101
+ <option value="Arial">Arial</option>
102
+ <option value="Times New Roman">Times New Roman</option>
103
+ <option value="Courier New">Courier New</option>
104
+ <option value="Georgia">Georgia</option>
105
+ <option value="Verdana">Verdana</option>
106
+ </select>
107
+ <select id="font-size" class="px-2 py-1 border rounded">
108
+ <option value="1">8pt</option>
109
+ <option value="2">10pt</option>
110
+ <option value="3">12pt</option>
111
+ <option value="4">14pt</option>
112
+ <option value="5">18pt</option>
113
+ <option value="6">24pt</option>
114
+ <option value="7">36pt</option>
115
+ </select>
116
+ <button id="bold-btn" class="p-1 rounded hover:bg-gray-100">
117
+ <i class="fas fa-bold"></i>
118
+ </button>
119
+ <button id="italic-btn" class="p-1 rounded hover:bg-gray-100">
120
+ <i class="fas fa-italic"></i>
121
+ </button>
122
+ <button id="underline-btn" class="p-1 rounded hover:bg-gray-100">
123
+ <i class="fas fa-underline"></i>
124
+ </button>
125
+ <div class="border-l h-6 mx-2"></div>
126
+ <button id="align-left-btn" class="p-1 rounded hover:bg-gray-100">
127
+ <i class="fas fa-align-left"></i>
128
+ </button>
129
+ <button id="align-center-btn" class="p-1 rounded hover:bg-gray-100">
130
+ <i class="fas fa-align-center"></i>
131
+ </button>
132
+ <button id="align-right-btn" class="p-1 rounded hover:bg-gray-100">
133
+ <i class="fas fa-align-right"></i>
134
+ </button>
135
+ <div class="border-l h-6 mx-2"></div>
136
+ <button id="list-ul-btn" class="p-1 rounded hover:bg-gray-100">
137
+ <i class="fas fa-list-ul"></i>
138
+ </button>
139
+ <button id="list-ol-btn" class="p-1 rounded hover:bg-gray-100">
140
+ <i class="fas fa-list-ol"></i>
141
+ </button>
142
+ </div>
143
+ </div>
144
+ <div class="p-4">
145
+ <div id="editor" class="editor bg-white border rounded p-6 shadow-inner focus:outline-none" contenteditable="true"></div>
146
+ </div>
147
+ </div>
148
+ </div>
149
 
150
+ <!-- Document Name Modal -->
151
+ <div id="doc-name-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
152
+ <div class="bg-white rounded-lg p-6 w-96">
153
+ <h3 class="text-lg font-semibold mb-4">Name your document</h3>
154
+ <input type="text" id="doc-name-input" class="w-full px-3 py-2 border rounded mb-4" placeholder="Document name">
155
+ <div class="flex justify-end space-x-2">
156
+ <button id="cancel-doc-btn" class="px-4 py-2 border rounded hover:bg-gray-100">Cancel</button>
157
+ <button id="confirm-doc-btn" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">Create</button>
158
+ </div>
159
+ </div>
160
+ </div>
 
 
 
 
 
 
 
161
 
162
+ <script>
163
+ document.addEventListener('DOMContentLoaded', function() {
164
+ // DOM Elements
165
+ const editor = document.getElementById('editor');
166
+ const documentsList = document.getElementById('documents-list');
167
+ const saveBtn = document.getElementById('save-btn');
168
+ const exportBtn = document.getElementById('export-btn');
169
+ const newDocBtn = document.getElementById('new-doc-btn');
170
+ const menuBtn = document.getElementById('menu-btn');
171
+ const sidebar = document.getElementById('sidebar');
172
+ const overlay = document.getElementById('overlay');
173
+ const docNameModal = document.getElementById('doc-name-modal');
174
+ const docNameInput = document.getElementById('doc-name-input');
175
+ const confirmDocBtn = document.getElementById('confirm-doc-btn');
176
+ const cancelDocBtn = document.getElementById('cancel-doc-btn');
177
+
178
+ // Formatting buttons
179
+ const boldBtn = document.getElementById('bold-btn');
180
+ const italicBtn = document.getElementById('italic-btn');
181
+ const underlineBtn = document.getElementById('underline-btn');
182
+ const alignLeftBtn = document.getElementById('align-left-btn');
183
+ const alignCenterBtn = document.getElementById('align-center-btn');
184
+ const alignRightBtn = document.getElementById('align-right-btn');
185
+ const listUlBtn = document.getElementById('list-ul-btn');
186
+ const listOlBtn = document.getElementById('list-ol-btn');
187
+ const fontFamily = document.getElementById('font-family');
188
+ const fontSize = document.getElementById('font-size');
189
+
190
+ // State
191
+ let currentDocId = null;
192
+ let documents = [];
193
+
194
+ // Initialize
195
+ loadDocuments();
196
+ if (documents.length > 0) {
197
+ loadDocument(documents[0].id);
198
+ } else {
199
+ createNewDocument();
200
+ }
201
+
202
+ // Event Listeners
203
+ menuBtn.addEventListener('click', toggleSidebar);
204
+ overlay.addEventListener('click', toggleSidebar);
205
+
206
+ saveBtn.addEventListener('click', saveCurrentDocument);
207
+ exportBtn.addEventListener('click', exportToDocx);
208
+ newDocBtn.addEventListener('click', showNewDocModal);
209
+
210
+ confirmDocBtn.addEventListener('click', createNewDocumentWithName);
211
+ cancelDocBtn.addEventListener('click', hideNewDocModal);
212
+
213
+ // Formatting event listeners
214
+ boldBtn.addEventListener('click', () => document.execCommand('bold', false, null));
215
+ italicBtn.addEventListener('click', () => document.execCommand('italic', false, null));
216
+ underlineBtn.addEventListener('click', () => document.execCommand('underline', false, null));
217
+ alignLeftBtn.addEventListener('click', () => document.execCommand('justifyLeft', false, null));
218
+ alignCenterBtn.addEventListener('click', () => document.execCommand('justifyCenter', false, null));
219
+ alignRightBtn.addEventListener('click', () => document.execCommand('justifyRight', false, null));
220
+ listUlBtn.addEventListener('click', () => document.execCommand('insertUnorderedList', false, null));
221
+ listOlBtn.addEventListener('click', () => document.execCommand('insertOrderedList', false, null));
222
+
223
+ fontFamily.addEventListener('change', () => {
224
+ document.execCommand('fontName', false, fontFamily.value);
225
+ });
226
+
227
+ fontSize.addEventListener('change', () => {
228
+ const sizes = ['8pt', '10pt', '12pt', '14pt', '18pt', '24pt', '36pt'];
229
+ document.execCommand('fontSize', false, fontSize.value);
230
+ // Fix the actual size (execCommand only sets the font size tag)
231
+ const selection = window.getSelection();
232
+ if (selection.rangeCount > 0) {
233
+ const range = selection.getRangeAt(0);
234
+ const span = document.createElement('span');
235
+ span.style.fontSize = sizes[fontSize.value - 1];
236
+ range.surroundContents(span);
237
+ }
238
+ });
239
+
240
+ // Functions
241
+ function toggleSidebar() {
242
+ sidebar.classList.toggle('open');
243
+ overlay.classList.toggle('open');
244
+ }
245
+
246
+ function showNewDocModal() {
247
+ docNameModal.classList.remove('hidden');
248
+ docNameInput.focus();
249
+ }
250
+
251
+ function hideNewDocModal() {
252
+ docNameModal.classList.add('hidden');
253
+ docNameInput.value = '';
254
+ }
255
+
256
+ function createNewDocumentWithName() {
257
+ const name = docNameInput.value.trim() || 'Untitled Document';
258
+ createNewDocument(name);
259
+ hideNewDocModal();
260
+ }
261
+
262
+ function createNewDocument(name = 'Untitled Document') {
263
+ const newDoc = {
264
+ id: Date.now().toString(),
265
+ name: name,
266
+ content: '<p><br></p>',
267
+ createdAt: new Date().toISOString(),
268
+ updatedAt: new Date().toISOString()
269
+ };
270
+
271
+ documents.unshift(newDoc);
272
+ saveDocumentsToCookies();
273
+ renderDocumentsList();
274
+ loadDocument(newDoc.id);
275
+ }
276
+
277
+ function loadDocuments() {
278
+ const docsCookie = getCookie('documents');
279
+ if (docsCookie) {
280
+ documents = JSON.parse(docsCookie);
281
+ renderDocumentsList();
282
+ }
283
+ }
284
+
285
+ function saveDocumentsToCookies() {
286
+ setCookie('documents', JSON.stringify(documents), 365);
287
+ }
288
+
289
+ function renderDocumentsList() {
290
+ documentsList.innerHTML = '';
291
+
292
+ if (documents.length === 0) {
293
+ documentsList.innerHTML = '<p class="text-gray-500 p-2">No documents yet</p>';
294
+ return;
295
+ }
296
+
297
+ documents.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt));
298
+
299
+ documents.forEach(doc => {
300
+ const docElement = document.createElement('div');
301
+ docElement.className = `document-item p-3 cursor-pointer rounded flex items-center justify-between ${currentDocId === doc.id ? 'active' : ''}`;
302
+ docElement.innerHTML = `
303
+ <div class="flex items-center">
304
+ <i class="fas fa-file-word text-blue-500 mr-2"></i>
305
+ <span class="truncate">${doc.name}</span>
306
+ </div>
307
+ <button class="delete-doc text-red-500 hover:text-red-700 p-1" data-id="${doc.id}">
308
+ <i class="fas fa-trash"></i>
309
+ </button>
310
+ `;
311
+
312
+ docElement.addEventListener('click', () => loadDocument(doc.id));
313
+
314
+ const deleteBtn = docElement.querySelector('.delete-doc');
315
+ deleteBtn.addEventListener('click', (e) => {
316
+ e.stopPropagation();
317
+ deleteDocument(doc.id);
318
+ });
319
+
320
+ documentsList.appendChild(docElement);
321
+ });
322
+ }
323
+
324
+ function loadDocument(docId) {
325
+ const doc = documents.find(d => d.id === docId);
326
+ if (doc) {
327
+ currentDocId = docId;
328
+ editor.innerHTML = doc.content;
329
+ renderDocumentsList();
330
+
331
+ // Set focus to editor
332
+ editor.focus();
333
+
334
+ // Move cursor to end
335
+ const range = document.createRange();
336
+ range.selectNodeContents(editor);
337
+ range.collapse(false);
338
+ const selection = window.getSelection();
339
+ selection.removeAllRanges();
340
+ selection.addRange(range);
341
+ }
342
+ }
343
+
344
+ function saveCurrentDocument() {
345
+ if (!currentDocId) return;
346
+
347
+ const docIndex = documents.findIndex(d => d.id === currentDocId);
348
+ if (docIndex !== -1) {
349
+ documents[docIndex].content = editor.innerHTML;
350
+ documents[docIndex].updatedAt = new Date().toISOString();
351
+ saveDocumentsToCookies();
352
+ renderDocumentsList();
353
+
354
+ // Show save notification
355
+ showNotification('Document saved successfully');
356
+ }
357
+ }
358
+
359
+ function deleteDocument(docId) {
360
+ if (confirm('Are you sure you want to delete this document?')) {
361
+ documents = documents.filter(d => d.id !== docId);
362
+ saveDocumentsToCookies();
363
+
364
+ if (currentDocId === docId) {
365
+ if (documents.length > 0) {
366
+ loadDocument(documents[0].id);
367
+ } else {
368
+ createNewDocument();
369
+ }
370
+ } else {
371
+ renderDocumentsList();
372
+ }
373
+ }
374
+ }
375
+
376
+ function exportToDocx() {
377
+ if (!currentDocId) return;
378
+
379
+ const doc = documents.find(d => d.id === currentDocId);
380
+ if (!doc) return;
381
+
382
+ // Create a temporary div to parse the HTML content
383
+ const tempDiv = document.createElement('div');
384
+ tempDiv.innerHTML = doc.content;
385
+
386
+ // Initialize DOCX
387
+ const { Document, Paragraph, TextRun, HeadingLevel, AlignmentType } = docx;
388
+
389
+ const children = [];
390
+
391
+ // Process each node in the content
392
+ const nodes = tempDiv.childNodes;
393
+ for (let i = 0; i < nodes.length; i++) {
394
+ const node = nodes[i];
395
+
396
+ if (node.nodeType === Node.TEXT_NODE) {
397
+ if (node.textContent.trim() !== '') {
398
+ children.push(
399
+ new Paragraph({
400
+ children: [new TextRun(node.textContent)],
401
+ })
402
+ );
403
+ }
404
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
405
+ if (node.tagName === 'P') {
406
+ const paragraphChildren = [];
407
+ const textRuns = [];
408
+
409
+ // Process child nodes of the paragraph
410
+ processNode(node, textRuns);
411
+
412
+ if (textRuns.length > 0) {
413
+ paragraphChildren.push(...textRuns);
414
+ }
415
+
416
+ children.push(
417
+ new Paragraph({
418
+ children: paragraphChildren,
419
+ })
420
+ );
421
+ } else if (node.tagName === 'H1') {
422
+ children.push(
423
+ new Paragraph({
424
+ text: node.textContent,
425
+ heading: HeadingLevel.HEADING_1,
426
+ })
427
+ );
428
+ } else if (node.tagName === 'H2') {
429
+ children.push(
430
+ new Paragraph({
431
+ text: node.textContent,
432
+ heading: HeadingLevel.HEADING_2,
433
+ })
434
+ );
435
+ } else if (node.tagName === 'UL' || node.tagName === 'OL') {
436
+ const listItems = node.querySelectorAll('li');
437
+ listItems.forEach(li => {
438
+ children.push(
439
+ new Paragraph({
440
+ text: li.textContent,
441
+ bullet: {
442
+ level: 0
443
+ },
444
+ })
445
+ );
446
+ });
447
+ } else if (node.tagName === 'DIV') {
448
+ // Handle divs (often used for line breaks)
449
+ if (node.textContent.trim() !== '') {
450
+ children.push(
451
+ new Paragraph({
452
+ children: [new TextRun(node.textContent)],
453
+ })
454
+ );
455
+ }
456
+ }
457
+ }
458
+ }
459
+
460
+ // Create the document
461
+ const docxDoc = new Document({
462
+ title: doc.name,
463
+ description: "Exported from DocClone",
464
+ creator: "DocClone",
465
+ children: children,
466
+ });
467
+
468
+ // Generate and download the DOCX file
469
+ docx.Packer.toBlob(docxDoc).then(blob => {
470
+ saveAs(blob, `${doc.name}.docx`);
471
+ });
472
+
473
+ function processNode(element, textRuns) {
474
+ for (let j = 0; j < element.childNodes.length; j++) {
475
+ const child = element.childNodes[j];
476
+
477
+ if (child.nodeType === Node.TEXT_NODE) {
478
+ if (child.textContent.trim() !== '') {
479
+ textRuns.push(
480
+ new TextRun({
481
+ text: child.textContent,
482
+ bold: element.style.fontWeight === 'bold' || element.tagName === 'STRONG' || element.tagName === 'B',
483
+ italics: element.style.fontStyle === 'italic' || element.tagName === 'EM' || element.tagName === 'I',
484
+ underline: element.style.textDecoration === 'underline' || element.tagName === 'U',
485
+ size: element.style.fontSize ? parseInt(element.style.fontSize) * 2 : undefined,
486
+ font: element.style.fontFamily || undefined,
487
+ })
488
+ );
489
+ }
490
+ } else if (child.nodeType === Node.ELEMENT_NODE) {
491
+ // Recursively process child elements
492
+ processNode(child, textRuns);
493
+ }
494
+ }
495
+ }
496
+ }
497
+
498
+ function showNotification(message) {
499
+ const notification = document.createElement('div');
500
+ notification.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded shadow-lg';
501
+ notification.textContent = message;
502
+ document.body.appendChild(notification);
503
+
504
+ setTimeout(() => {
505
+ notification.classList.add('opacity-0', 'transition-opacity', 'duration-300');
506
+ setTimeout(() => notification.remove(), 300);
507
+ }, 3000);
508
+ }
509
+
510
+ // Cookie helper functions
511
+ function setCookie(name, value, days) {
512
+ let expires = "";
513
+ if (days) {
514
+ const date = new Date();
515
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
516
+ expires = "; expires=" + date.toUTCString();
517
+ }
518
+ document.cookie = name + "=" + (value || "") + expires + "; path=/";
519
+ }
520
+
521
+ function getCookie(name) {
522
+ const nameEQ = name + "=";
523
+ const ca = document.cookie.split(';');
524
+ for (let i = 0; i < ca.length; i++) {
525
+ let c = ca[i];
526
+ while (c.charAt(0) === ' ') c = c.substring(1, c.length);
527
+ if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
528
+ }
529
+ return null;
530
+ }
531
+
532
+ // Auto-save functionality
533
+ let saveTimeout;
534
+ editor.addEventListener('input', () => {
535
+ clearTimeout(saveTimeout);
536
+ saveTimeout = setTimeout(() => {
537
+ saveCurrentDocument();
538
+ }, 2000);
539
+ });
540
+
541
+ // Keyboard shortcuts
542
+ document.addEventListener('keydown', (e) => {
543
+ // Ctrl+S or Cmd+S to save
544
+ if ((e.ctrlKey || e.metaKey) && e.key === 's') {
545
+ e.preventDefault();
546
+ saveCurrentDocument();
547
+ }
548
+
549
+ // Ctrl+N or Cmd+N to create new document
550
+ if ((e.ctrlKey || e.metaKey) && e.key === 'n') {
551
+ e.preventDefault();
552
+ showNewDocModal();
553
+ }
554
+ });
555
  });
556
  </script>
557
  </body>