@oix1987/yjd 1.0.1 → 1.0.3

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 +9 -1
  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 +13 -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/ui/color-picker.js +0 -296
  43. package/lib/ui/customselect.js +0 -319
  44. package/lib/ui/emoji-picker.js +0 -196
  45. package/lib/ui/icons.js +0 -413
  46. package/lib/ui/image-popup.js +0 -444
  47. package/lib/ui/import-popup.js +0 -288
  48. package/lib/ui/link-popup.js +0 -191
  49. package/lib/ui/list-picker.js +0 -307
  50. package/lib/ui/select-button.js +0 -61
  51. package/lib/ui/table-popup.js +0 -171
  52. package/lib/ui/tag-popup.js +0 -249
  53. package/lib/ui/text-align-picker.js +0 -281
  54. package/lib/ui/video-popup.js +0 -422
  55. package/lib/utils/history-helper.js +0 -50
  56. package/lib/utils/popup-helper.js +0 -219
  57. package/lib/utils/popup-positioning.js +0 -231
  58. /package/{lib → dist}/styles.css +0 -0
@@ -1,288 +0,0 @@
1
- /**
2
- * Import Popup Component - Popup for importing various file types
3
- */
4
- import { appendPopup, calculatePopupPosition, setPopupPosition } from '../utils/popup-helper.js';
5
-
6
- class ImportPopup {
7
- constructor(options = {}) {
8
- this.options = {
9
- onImport: null,
10
- ...options
11
- };
12
-
13
- this.popup = null;
14
- this.isVisible = false;
15
- this.clickOutsideHandler = null;
16
- this.selectedFile = null;
17
- this.fileType = null;
18
-
19
- this.createImportPopup();
20
- }
21
-
22
- createImportPopup() {
23
- this.popup = document.createElement('div');
24
- this.popup.className = 'import-popup';
25
-
26
- const content = document.createElement('div');
27
- content.className = 'import-popup-content';
28
-
29
- // Title
30
- const title = document.createElement('h3');
31
- title.textContent = 'Import File';
32
- title.className = 'import-popup-title';
33
- content.appendChild(title);
34
-
35
- // File type selector
36
- const typeContainer = document.createElement('div');
37
- typeContainer.className = 'import-type-container';
38
-
39
- const typeLabel = document.createElement('label');
40
- typeLabel.textContent = 'File Type:';
41
- typeLabel.className = 'import-input-label';
42
-
43
- this.typeSelect = document.createElement('select');
44
- this.typeSelect.className = 'import-type-select';
45
- this.typeSelect.innerHTML = `
46
- <option value="">Select file type...</option>
47
- <option value="html">HTML (.html, .htm)</option>
48
- <option value="excel">Excel/CSV (.csv, .xlsx, .xls)</option>
49
- <option value="pdf">PDF (.pdf)</option>
50
- <option value="word">Word (.doc, .docx)</option>
51
- `;
52
- this.typeSelect.addEventListener('change', () => this.updateFileInput());
53
-
54
- typeContainer.appendChild(typeLabel);
55
- typeContainer.appendChild(this.typeSelect);
56
- content.appendChild(typeContainer);
57
-
58
- // File input
59
- this.fileInput = document.createElement('input');
60
- this.fileInput.type = 'file';
61
- this.fileInput.className = 'import-file-input';
62
- this.fileInput.disabled = true;
63
- this.fileInput.addEventListener('change', (e) => this.handleFileSelect(e));
64
-
65
- content.appendChild(this.fileInput);
66
-
67
- // File info
68
- this.fileInfo = document.createElement('div');
69
- this.fileInfo.className = 'import-file-info';
70
- this.fileInfo.style.display = 'none';
71
- content.appendChild(this.fileInfo);
72
-
73
- // Buttons
74
- const buttonContainer = document.createElement('div');
75
- buttonContainer.className = 'import-button-container';
76
-
77
- const cancelButton = document.createElement('button');
78
- cancelButton.type = 'button';
79
- cancelButton.className = 'import-button cancel-button';
80
- cancelButton.textContent = 'Cancel';
81
- cancelButton.addEventListener('click', () => this.hide());
82
-
83
- this.importButton = document.createElement('button');
84
- this.importButton.type = 'button';
85
- this.importButton.className = 'import-button import-button-main';
86
- this.importButton.textContent = 'Import';
87
- this.importButton.disabled = true;
88
- this.importButton.addEventListener('click', () => this.processImport());
89
-
90
- buttonContainer.appendChild(cancelButton);
91
- buttonContainer.appendChild(this.importButton);
92
- content.appendChild(buttonContainer);
93
-
94
- this.popup.appendChild(content);
95
- appendPopup(this.popup);
96
- }
97
-
98
- updateFileInput() {
99
- const selectedType = this.typeSelect.value;
100
-
101
- if (selectedType) {
102
- this.fileType = selectedType;
103
- this.fileInput.disabled = false;
104
-
105
- const acceptTypes = this.getAcceptTypes(selectedType);
106
- this.fileInput.accept = acceptTypes;
107
- } else {
108
- this.fileType = null;
109
- this.fileInput.disabled = true;
110
- this.fileInput.accept = '';
111
- }
112
-
113
- this.updateImportButton();
114
- }
115
-
116
- getAcceptTypes(fileType) {
117
- const types = {
118
- html: '.html,.htm,text/html',
119
- excel: '.csv,.xlsx,.xls,text/csv',
120
- pdf: '.pdf,application/pdf',
121
- word: '.doc,.docx'
122
- };
123
-
124
- return types[fileType] || '';
125
- }
126
-
127
- handleFileSelect(e) {
128
- const file = e.target.files[0];
129
- if (file) {
130
- this.setSelectedFile(file);
131
- }
132
- }
133
-
134
- setSelectedFile(file) {
135
- this.selectedFile = file;
136
-
137
- this.fileInfo.style.display = 'block';
138
- this.fileInfo.innerHTML = `
139
- <div><strong>Name:</strong> ${file.name}</div>
140
- <div><strong>Size:</strong> ${this.formatFileSize(file.size)}</div>
141
- <div><strong>Type:</strong> ${file.type || 'Unknown'}</div>
142
- `;
143
-
144
- this.updateImportButton();
145
- }
146
-
147
- formatFileSize(bytes) {
148
- if (bytes === 0) return '0 Bytes';
149
-
150
- const k = 1024;
151
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
152
- const i = Math.floor(Math.log(bytes) / Math.log(k));
153
-
154
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
155
- }
156
-
157
- updateImportButton() {
158
- this.importButton.disabled = !this.selectedFile || !this.fileType;
159
- }
160
-
161
- async processImport() {
162
- if (!this.selectedFile || !this.fileType) return;
163
-
164
- try {
165
- let content;
166
-
167
- if (this.fileType === 'html') {
168
- content = await this.readAsText(this.selectedFile);
169
- } else if (this.fileType === 'excel') {
170
- if (this.selectedFile.name.toLowerCase().endsWith('.csv')) {
171
- const csvContent = await this.readAsText(this.selectedFile);
172
- content = this.parseCSV(csvContent);
173
- } else {
174
- alert('Excel files (.xlsx/.xls) require additional libraries. Please use CSV format.');
175
- return;
176
- }
177
- } else if (this.fileType === 'pdf') {
178
- alert('PDF import requires additional libraries. Feature coming soon.');
179
- return;
180
- } else if (this.fileType === 'word') {
181
- alert('Word document import requires additional libraries. Feature coming soon.');
182
- return;
183
- }
184
-
185
- if (this.options.onImport) {
186
- this.options.onImport(content, this.fileType);
187
- }
188
-
189
- this.hide();
190
- this.reset();
191
-
192
- } catch (error) {
193
- console.error('Import error:', error);
194
- alert('Error importing file: ' + error.message);
195
- }
196
- }
197
-
198
- parseCSV(csvContent) {
199
- const lines = csvContent.split('\n');
200
- const result = [];
201
-
202
- lines.forEach(line => {
203
- if (line.trim()) {
204
- const cells = line.split(',').map(cell => cell.trim().replace(/^["']|["']$/g, ''));
205
- result.push(cells);
206
- }
207
- });
208
-
209
- return result;
210
- }
211
-
212
- readAsText(file) {
213
- return new Promise((resolve, reject) => {
214
- const reader = new FileReader();
215
- reader.onload = (e) => resolve(e.target.result);
216
- reader.onerror = () => reject(new Error('Failed to read file'));
217
- reader.readAsText(file);
218
- });
219
- }
220
-
221
- reset() {
222
- this.selectedFile = null;
223
- this.fileType = null;
224
- this.typeSelect.value = '';
225
- this.fileInput.value = '';
226
- this.fileInput.disabled = true;
227
- this.fileInfo.style.display = 'none';
228
- this.updateImportButton();
229
- }
230
-
231
- setupClickOutside() {
232
- if (this.clickOutsideHandler) {
233
- document.removeEventListener('click', this.clickOutsideHandler);
234
- }
235
-
236
- this.clickOutsideHandler = (e) => {
237
- if (!this.popup.contains(e.target)) {
238
- this.hide();
239
- }
240
- };
241
-
242
- setTimeout(() => {
243
- document.addEventListener('click', this.clickOutsideHandler);
244
- }, 100);
245
- }
246
-
247
- removeClickOutside() {
248
- if (this.clickOutsideHandler) {
249
- document.removeEventListener('click', this.clickOutsideHandler);
250
- this.clickOutsideHandler = null;
251
- }
252
- }
253
-
254
- show(anchor) {
255
- if (!anchor) return;
256
-
257
- // Calculate and set popup position
258
- const position = calculatePopupPosition(anchor, this.popup, {
259
- offsetY: 5,
260
- offsetX: 0
261
- });
262
- setPopupPosition(this.popup, position);
263
-
264
- this.popup.classList.add('visible');
265
- this.isVisible = true;
266
-
267
- this.setupClickOutside();
268
- }
269
-
270
- hide() {
271
- this.popup.classList.remove('visible');
272
- this.isVisible = false;
273
- this.removeClickOutside();
274
- }
275
-
276
- destroy() {
277
- this.removeClickOutside();
278
-
279
- if (this.popup && this.popup.parentNode) {
280
- this.popup.parentNode.removeChild(this.popup);
281
- }
282
-
283
- this.popup = null;
284
- this.isVisible = false;
285
- }
286
- }
287
-
288
- export default ImportPopup;
@@ -1,191 +0,0 @@
1
- /**
2
- * Link Popup Component - Simple link popup
3
- */
4
- import { appendPopup, calculatePopupPosition, setPopupPosition } from '../utils/popup-helper.js';
5
-
6
- class LinkPopup {
7
- constructor(options = {}) {
8
- this.options = {
9
- onLinkSelect: null,
10
- editor: null,
11
- ...options
12
- };
13
-
14
- this.popup = null;
15
- this.isVisible = false;
16
- this.urlInput = null;
17
- this.textInput = null;
18
-
19
- this.createPopup();
20
- }
21
-
22
- createPopup() {
23
- this.popup = document.createElement('div');
24
- this.popup.className = 'link-popup';
25
-
26
- const content = document.createElement('div');
27
- content.className = 'link-popup-content';
28
-
29
- // title
30
- const linkTitle = document.createElement('h2');
31
- linkTitle.textContent = 'Upload link';
32
- linkTitle.className = 'yjd-input-title';
33
- //text label 1
34
- const inputgroup1 = document.createElement('div');
35
- inputgroup1.className = 'yjd-input-group';
36
- const textLabel = document.createElement('p');
37
- textLabel.textContent = 'Your URL';
38
- textLabel.className = 'yjd-input-label';
39
-
40
- this.urlInput = document.createElement('input');
41
- this.urlInput.type = 'url';
42
- this.urlInput.className = 'yjd-input';
43
- this.urlInput.placeholder = 'Please enter your URL';
44
- inputgroup1.appendChild(textLabel);
45
- inputgroup1.appendChild(this.urlInput);
46
-
47
- // Text label 2
48
- const inputgroup2 = document.createElement('div');
49
- inputgroup2.className = 'yjd-input-group';
50
- const urlLabel = document.createElement('p');
51
- urlLabel.textContent = 'Your display text';
52
- urlLabel.className = 'yjd-input-label';
53
-
54
- this.textInput = document.createElement('input');
55
- this.textInput.type = 'text';
56
- this.textInput.className = 'yjd-input';
57
- this.textInput.placeholder = 'Please enter display text';
58
- inputgroup2.appendChild(urlLabel);
59
- inputgroup2.appendChild(this.textInput);
60
-
61
- // Buttons
62
- const buttonContainer = document.createElement('div');
63
- buttonContainer.className = 'yjd-button-container';
64
-
65
- const okButton = document.createElement('button');
66
- okButton.type = 'button';
67
- okButton.className = 'yjd-button-confirm';
68
- okButton.textContent = 'Add link';
69
- okButton.onclick = () => {
70
- this.handleOk();
71
- // Maintain editor focus after action
72
- if (this.options.editor) {
73
- setTimeout(() => this.options.editor.focus(), 0);
74
- }
75
- };
76
-
77
- const cancelButton = document.createElement('button');
78
- cancelButton.type = 'button';
79
- cancelButton.className = 'yjd-button-cancel';
80
- cancelButton.textContent = 'Cancel';
81
- cancelButton.onclick = () => {
82
- this.hide();
83
- // Maintain editor focus after popup close
84
- if (this.options.editor) {
85
- setTimeout(() => this.options.editor.focus(), 0);
86
- }
87
- };
88
-
89
- // Enter key to submit
90
- this.urlInput.onkeydown = (e) => {
91
- if (e.key === 'Enter') this.handleOk();
92
- if (e.key === 'Escape') this.hide();
93
- };
94
-
95
- this.textInput.onkeydown = (e) => {
96
- if (e.key === 'Enter') this.handleOk();
97
- if (e.key === 'Escape') this.hide();
98
- };
99
-
100
- buttonContainer.appendChild(cancelButton);
101
- buttonContainer.appendChild(okButton);
102
-
103
- content.appendChild(linkTitle);
104
- content.appendChild(inputgroup1);
105
- content.appendChild(inputgroup2);
106
- content.appendChild(buttonContainer);
107
-
108
- this.popup.appendChild(content);
109
- appendPopup(this.popup);
110
-
111
- // Prevent focus loss when clicking on popup
112
- if (this.options.editor && typeof this.options.editor.preventFocusLoss === 'function') {
113
- this.options.editor.preventFocusLoss(this.popup);
114
- }
115
- }
116
-
117
- handleOk() {
118
- const url = this.urlInput.value.trim();
119
- // Kiểm tra rỗng
120
- if (!url) {
121
- alert('Please enter a URL');
122
- this.urlInput.focus();
123
- return;
124
- }
125
- // Kiểm tra định dạng URL
126
- try {
127
- new URL(url); // Nếu sai format, sẽ throw
128
- } catch (e) {
129
- alert('Please enter a valid URL');
130
- this.urlInput.focus();
131
- return;
132
- }
133
-
134
- const text = this.textInput.value.trim();
135
-
136
- if (this.options.onLinkSelect) {
137
- this.options.onLinkSelect({ url, text });
138
- }
139
-
140
- this.hide();
141
- }
142
-
143
- show(anchor, existingLink = null, selectedText = '') {
144
- if (!anchor) return;
145
-
146
- // Populate fields
147
- this.urlInput.value = existingLink ? existingLink.url : '';
148
- // Use selected text if available, otherwise use existing link text or empty
149
- this.textInput.value = selectedText || (existingLink ? existingLink.text : '');
150
-
151
- // Calculate and set popup position
152
- const position = calculatePopupPosition(anchor, this.popup, {
153
- offsetY: 5,
154
- offsetX: 0
155
- });
156
- setPopupPosition(this.popup, position);
157
-
158
- // Show popup
159
- this.popup.classList.add('visible');
160
- this.isVisible = true;
161
-
162
- // Focus URL input
163
- setTimeout(() => this.urlInput.focus(), 100);
164
-
165
- // Click outside to close
166
- setTimeout(() => {
167
- document.addEventListener('click', this.closeOnClickOutside);
168
- }, 100);
169
- }
170
-
171
- hide() {
172
- this.popup.classList.remove('visible');
173
- this.isVisible = false;
174
- document.removeEventListener('click', this.closeOnClickOutside);
175
- }
176
-
177
- closeOnClickOutside = (e) => {
178
- if (!this.popup.contains(e.target)) {
179
- this.hide();
180
- }
181
- }
182
-
183
- destroy() {
184
- document.removeEventListener('click', this.closeOnClickOutside);
185
- if (this.popup && this.popup.parentNode) {
186
- this.popup.parentNode.removeChild(this.popup);
187
- }
188
- }
189
- }
190
-
191
- export default LinkPopup;