@oix1987/yjd 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +73 -22
  2. package/dist/rich-editor.esm.js +2 -0
  3. package/dist/rich-editor.esm.js.map +1 -0
  4. package/dist/rich-editor.min.js +2 -0
  5. package/dist/rich-editor.min.js.map +1 -0
  6. package/package.json +12 -7
  7. package/index.js +0 -221
  8. package/lib/core/editor.js +0 -1175
  9. package/lib/core/format.js +0 -542
  10. package/lib/core/module.js +0 -81
  11. package/lib/core/registry.js +0 -152
  12. package/lib/formats/background.js +0 -212
  13. package/lib/formats/bold.js +0 -67
  14. package/lib/formats/capitalization.js +0 -563
  15. package/lib/formats/color.js +0 -165
  16. package/lib/formats/emoji.js +0 -282
  17. package/lib/formats/font-family.js +0 -547
  18. package/lib/formats/heading.js +0 -502
  19. package/lib/formats/image.js +0 -344
  20. package/lib/formats/import.js +0 -385
  21. package/lib/formats/indent.js +0 -297
  22. package/lib/formats/italic.js +0 -27
  23. package/lib/formats/line-height.js +0 -558
  24. package/lib/formats/link.js +0 -251
  25. package/lib/formats/list.js +0 -635
  26. package/lib/formats/strike.js +0 -31
  27. package/lib/formats/subscript.js +0 -36
  28. package/lib/formats/superscript.js +0 -35
  29. package/lib/formats/table.js +0 -288
  30. package/lib/formats/tag.js +0 -304
  31. package/lib/formats/text-align.js +0 -421
  32. package/lib/formats/text-size.js +0 -497
  33. package/lib/formats/underline.js +0 -30
  34. package/lib/formats/video.js +0 -372
  35. package/lib/modules/block-toolbar.js +0 -628
  36. package/lib/modules/code-view.js +0 -434
  37. package/lib/modules/history.js +0 -410
  38. package/lib/modules/resize-handles.js +0 -677
  39. package/lib/modules/table-toolbar.js +0 -618
  40. package/lib/modules/toolbar.js +0 -424
  41. package/lib/styles-loader.js +0 -144
  42. package/lib/styles.css +0 -2123
  43. package/lib/ui/color-picker.js +0 -296
  44. package/lib/ui/customselect.js +0 -319
  45. package/lib/ui/emoji-picker.js +0 -196
  46. package/lib/ui/icons.js +0 -413
  47. package/lib/ui/image-popup.js +0 -444
  48. package/lib/ui/import-popup.js +0 -288
  49. package/lib/ui/link-popup.js +0 -191
  50. package/lib/ui/list-picker.js +0 -307
  51. package/lib/ui/select-button.js +0 -61
  52. package/lib/ui/table-popup.js +0 -171
  53. package/lib/ui/tag-popup.js +0 -249
  54. package/lib/ui/text-align-picker.js +0 -281
  55. package/lib/ui/video-popup.js +0 -422
  56. package/lib/utils/history-helper.js +0 -50
  57. package/lib/utils/popup-helper.js +0 -219
  58. package/lib/utils/popup-positioning.js +0 -231
@@ -1,434 +0,0 @@
1
- import Module from '../core/module.js';
2
-
3
- /**
4
- * Code View Module - Toggles between normal editor view and HTML source code view
5
- */
6
- class CodeView extends Module {
7
- constructor(editor, options = {}) {
8
- super(editor, options);
9
-
10
- this.isCodeView = false;
11
- this.originalContent = '';
12
- this.codeTextarea = null;
13
- this.disabledModules = new Set(); // Track disabled modules
14
-
15
- this.init();
16
- }
17
-
18
- init() {
19
-
20
- // Listen for code view toggle events
21
- this.editor.on('toolbar-click', (data) => {
22
- if (data.command === 'code-view') {
23
- this.toggleCodeView();
24
- }
25
- });
26
- }
27
-
28
- /**
29
- * Toggle between normal editor view and code view
30
- */
31
- toggleCodeView() {
32
-
33
- if (this.isCodeView) {
34
- this.showNormalView();
35
- } else {
36
- this.showCodeView();
37
- }
38
-
39
- this.updateToolbarButton();
40
- }
41
-
42
- /**
43
- * Show code view - display HTML source
44
- */
45
- showCodeView() {
46
- const editorArea = this.editor.editor;
47
- if (!editorArea) return;
48
-
49
- // Store original content
50
- this.originalContent = editorArea.innerHTML;
51
-
52
- // Create textarea for code editing
53
- this.codeTextarea = document.createElement('textarea');
54
- this.codeTextarea.className = 'code-view-textarea';
55
- this.codeTextarea.value = this.formatHTML(this.originalContent);
56
-
57
- // Replace editor content with textarea
58
- editorArea.style.display = 'none';
59
- editorArea.parentNode.insertBefore(this.codeTextarea, editorArea);
60
-
61
- // Add CSS class to wrapper for styling
62
- const wrapper = this.editor.wrapper;
63
- if (wrapper) {
64
- wrapper.classList.add('code-view-active');
65
- }
66
-
67
- // Focus on textarea
68
- this.codeTextarea.focus();
69
-
70
- // Set flag
71
- this.isCodeView = true;
72
-
73
- // Disable other features
74
- this.disableOtherFeatures();
75
-
76
- // Add event listener for real-time updates
77
- this.codeTextarea.addEventListener('input', () => {
78
- this.updateOriginalContent();
79
- });
80
-
81
- }
82
-
83
- /**
84
- * Show normal editor view - restore visual editor
85
- */
86
- showNormalView() {
87
- const editorArea = this.editor.editor;
88
- if (!editorArea || !this.codeTextarea) return;
89
-
90
- // Get updated content from textarea
91
- const updatedHTML = this.codeTextarea.value;
92
-
93
- // Remove textarea
94
- this.codeTextarea.parentNode.removeChild(this.codeTextarea);
95
- this.codeTextarea = null;
96
-
97
- // Remove CSS class from wrapper
98
- const wrapper = this.editor.wrapper;
99
- if (wrapper) {
100
- wrapper.classList.remove('code-view-active');
101
- }
102
-
103
- // Show editor area
104
- editorArea.style.display = '';
105
-
106
- // Update editor content
107
- editorArea.innerHTML = updatedHTML;
108
-
109
- // Focus on editor
110
- editorArea.focus();
111
-
112
- // Set flag
113
- this.isCodeView = false;
114
-
115
- // Enable other features
116
- this.enableOtherFeatures();
117
-
118
- // Trigger content change event
119
- this.editor.onContentChange();
120
-
121
- }
122
-
123
- /**
124
- * Disable other features when in code view
125
- */
126
- disableOtherFeatures() {
127
- // Disable toolbar buttons (except code-view and theme)
128
- const toolbar = this.editor.getModule('toolbar');
129
- if (toolbar) {
130
- const allCommands = [
131
- 'bold', 'italic', 'underline', 'strike', 'subscript', 'superscript',
132
- 'color', 'background', 'link', 'table', 'heading',
133
- 'font-family', 'line-height', 'capitalization', 'text-align', 'list',
134
- 'indent-increase', 'indent-decrease', 'text-size', 'emoji', 'image',
135
- 'video', 'tag', 'import', 'undo', 'redo'
136
- ];
137
-
138
- allCommands.forEach(command => {
139
- toolbar.setButtonDisabled(command, true);
140
- });
141
-
142
- // Keep code-view and theme enabled
143
- toolbar.setButtonDisabled('code-view', false);
144
- toolbar.setButtonDisabled('theme', false);
145
- }
146
-
147
- // Disable editor events
148
- this.disableEditorEvents();
149
-
150
- // Disable other modules
151
- this.disableOtherModules();
152
-
153
- // Hide any open popups
154
- this.hideAllPopups();
155
- }
156
-
157
- /**
158
- * Enable other features when returning to normal view
159
- */
160
- enableOtherFeatures() {
161
- // Enable toolbar buttons
162
- const toolbar = this.editor.getModule('toolbar');
163
- if (toolbar) {
164
- const allCommands = [
165
- 'bold', 'italic', 'underline', 'strike', 'subscript', 'superscript',
166
- 'color', 'background', 'link', 'table', 'heading',
167
- 'font-family', 'line-height', 'capitalization', 'text-align', 'list',
168
- 'indent-increase', 'indent-decrease', 'text-size', 'emoji', 'image',
169
- 'video', 'tag', 'import', 'undo', 'redo'
170
- ];
171
-
172
- allCommands.forEach(command => {
173
- toolbar.setButtonDisabled(command, false);
174
- });
175
- }
176
-
177
- // Enable editor events
178
- this.enableEditorEvents();
179
-
180
- // Enable other modules
181
- this.enableOtherModules();
182
- }
183
-
184
- /**
185
- * Disable editor events when in code view
186
- */
187
- disableEditorEvents() {
188
- const editorArea = this.editor.editor;
189
- if (!editorArea) return;
190
-
191
- // Make editor non-editable to disable all editing functionality
192
- editorArea.contentEditable = false;
193
-
194
- // Add a visual indicator that editor is disabled
195
- editorArea.style.opacity = '0.5';
196
- editorArea.style.pointerEvents = 'none';
197
- editorArea.style.cursor = 'not-allowed';
198
-
199
- // Add a title to indicate the editor is disabled
200
- editorArea.title = 'Editor is disabled in code view mode. Click "Switch to Visual Editor" to return to normal editing.';
201
- }
202
-
203
- /**
204
- * Enable editor events when returning to normal view
205
- */
206
- enableEditorEvents() {
207
- const editorArea = this.editor.editor;
208
- if (!editorArea) return;
209
-
210
- // Restore editor functionality
211
- editorArea.contentEditable = true;
212
- editorArea.style.opacity = '';
213
- editorArea.style.pointerEvents = '';
214
- editorArea.style.cursor = '';
215
- editorArea.title = '';
216
- }
217
-
218
- /**
219
- * Disable other modules when in code view
220
- */
221
- disableOtherModules() {
222
- const modulesToDisable = ['history', 'block-toolbar', 'table-toolbar', 'resize-handles'];
223
-
224
- modulesToDisable.forEach(moduleName => {
225
- const module = this.editor.getModule(moduleName);
226
- if (module) {
227
- // Try to disable module if it has disable method
228
- if (typeof module.disable === 'function') {
229
- module.disable();
230
- this.disabledModules.add(moduleName);
231
- }
232
- // For modules without disable method, we can hide their UI elements
233
- else if (module.getContainer && typeof module.getContainer === 'function') {
234
- const container = module.getContainer();
235
- if (container) {
236
- container.style.display = 'none';
237
- this.disabledModules.add(moduleName);
238
- }
239
- }
240
- }
241
- });
242
- }
243
-
244
- /**
245
- * Enable other modules when returning to normal view
246
- */
247
- enableOtherModules() {
248
- this.disabledModules.forEach(moduleName => {
249
- const module = this.editor.getModule(moduleName);
250
- if (module) {
251
- // Try to enable module if it has enable method
252
- if (typeof module.enable === 'function') {
253
- module.enable();
254
- }
255
- // For modules without enable method, show their UI elements
256
- else if (module.getContainer && typeof module.getContainer === 'function') {
257
- const container = module.getContainer();
258
- if (container) {
259
- container.style.display = '';
260
- }
261
- }
262
- }
263
- });
264
-
265
- this.disabledModules.clear();
266
- }
267
-
268
- /**
269
- * Update original content when user types in textarea
270
- */
271
- updateOriginalContent() {
272
- if (this.codeTextarea) {
273
- this.originalContent = this.codeTextarea.value;
274
-
275
- // Trigger content change event to call onChange callback
276
- // Get the HTML content from textarea
277
- const content = this.codeTextarea.value;
278
-
279
- // Call onChange callback if provided
280
- if (this.editor.options.onChange && typeof this.editor.options.onChange === 'function') {
281
- this.editor.options.onChange(content);
282
- }
283
-
284
- // Emit text-change event
285
- this.editor.emit('text-change', content);
286
- }
287
- }
288
-
289
- /**
290
- * Format HTML for better readability
291
- */
292
- formatHTML(html) {
293
- let formatted = html;
294
-
295
- // Tách thẻ mở và đóng thành dòng riêng biệt
296
- formatted = formatted.replace(/></g, '>\n<');
297
-
298
- // Tách nội dung giữa thẻ mở và đóng thành dòng riêng
299
- formatted = formatted.replace(/>([^<>\s][^<]*)</g, '>\n$1\n<');
300
-
301
- const lines = formatted.split('\n');
302
- const indentSize = 4;
303
- const formattedLines = [];
304
- const tagStack = []; // Stack để theo dõi thẻ mở
305
-
306
- for (let line of lines) {
307
- const trimmed = line.trim();
308
- if (!trimmed) continue;
309
-
310
- // Check for closing tag - xử lý trước khi in
311
- if (/^<\/(\w+)/.test(trimmed)) {
312
- const closeTagMatch = trimmed.match(/^<\/(\w+)/);
313
- if (closeTagMatch) {
314
- const tagName = closeTagMatch[1];
315
- // Tìm và loại bỏ thẻ mở tương ứng từ stack
316
- for (let i = tagStack.length - 1; i >= 0; i--) {
317
- if (tagStack[i] === tagName) {
318
- tagStack.splice(i, 1);
319
- break;
320
- }
321
- }
322
- }
323
- }
324
-
325
- // Apply indentation based on current stack level
326
- let currentLevel = tagStack.length;
327
-
328
- // Nếu là nội dung text (không phải thẻ), nó nằm bên trong thẻ cha nên cần thụt lề thêm
329
- if (!trimmed.startsWith('<')) {
330
- currentLevel = tagStack.length;
331
- }
332
-
333
- formattedLines.push(' '.repeat(currentLevel * indentSize) + trimmed);
334
-
335
- // Check for opening tag (not self-closing) - xử lý sau khi in
336
- const openTagMatch = trimmed.match(/^<(\w+)/);
337
- if (
338
- openTagMatch &&
339
- !trimmed.startsWith('</') &&
340
- !trimmed.endsWith('/>') &&
341
- !['area','base','br','col','embed','hr','img','input','link','meta','param','source','track','wbr'].includes(openTagMatch[1].toLowerCase())
342
- ) {
343
- const tagName = openTagMatch[1];
344
- tagStack.push(tagName);
345
- }
346
- }
347
-
348
- return formattedLines.join('\n');
349
- }
350
-
351
- /**
352
- * Update toolbar button state
353
- */
354
- updateToolbarButton() {
355
-
356
- const toolbar = this.editor.getModule('toolbar');
357
- if (toolbar) {
358
- toolbar.setButtonActive('code-view', this.isCodeView);
359
-
360
- // Update button title
361
- const buttonTitle = this.isCodeView ? 'Switch to Visual Editor' : 'Switch to HTML Editor';
362
- toolbar.setButtonTitle('code-view', buttonTitle);
363
-
364
- } else {
365
- }
366
- }
367
-
368
- /**
369
- * Check if currently in code view
370
- */
371
- isInCodeView() {
372
- return this.isCodeView;
373
- }
374
-
375
- /**
376
- * Get current content (from textarea if in code view, otherwise from editor)
377
- */
378
- getCurrentContent() {
379
- if (this.isCodeView && this.codeTextarea) {
380
- return this.codeTextarea.value;
381
- }
382
- return this.editor.editor.innerHTML;
383
- }
384
-
385
- /**
386
- * Set content programmatically
387
- */
388
- setContent(html) {
389
- if (this.isCodeView && this.codeTextarea) {
390
- this.codeTextarea.value = this.formatHTML(html);
391
- this.updateOriginalContent();
392
- } else {
393
- this.editor.editor.innerHTML = html;
394
- }
395
- }
396
-
397
- /**
398
- * Hide all popups when entering code view
399
- */
400
- hideAllPopups() {
401
- // Remove all popup elements from the DOM
402
- const popups = document.querySelectorAll('.rich-editor-popup, .color-picker-popup, .emoji-picker-popup, .link-popup, .image-popup, .video-popup, .table-popup, .tag-popup, .import-popup');
403
- popups.forEach(popup => {
404
- if (popup.parentNode) {
405
- popup.parentNode.removeChild(popup);
406
- }
407
- });
408
-
409
- // Clear any popup instances from the editor
410
- if (this.editor.popupInstances) {
411
- this.editor.popupInstances.clear();
412
- }
413
- }
414
-
415
- /**
416
- * Clean up when module is destroyed
417
- */
418
- destroy() {
419
- if (this.isCodeView) {
420
- this.showNormalView();
421
- }
422
-
423
- if (this.codeTextarea && this.codeTextarea.parentNode) {
424
- this.codeTextarea.parentNode.removeChild(this.codeTextarea);
425
- }
426
-
427
- this.codeTextarea = null;
428
- this.originalContent = '';
429
- this.isCodeView = false;
430
- this.disabledModules.clear();
431
- }
432
- }
433
-
434
- export default CodeView;