@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.
- package/README.md +73 -22
- package/dist/rich-editor.esm.js +2 -0
- package/dist/rich-editor.esm.js.map +1 -0
- package/dist/rich-editor.min.js +2 -0
- package/dist/rich-editor.min.js.map +1 -0
- package/package.json +12 -7
- package/index.js +0 -221
- package/lib/core/editor.js +0 -1175
- package/lib/core/format.js +0 -542
- package/lib/core/module.js +0 -81
- package/lib/core/registry.js +0 -152
- package/lib/formats/background.js +0 -212
- package/lib/formats/bold.js +0 -67
- package/lib/formats/capitalization.js +0 -563
- package/lib/formats/color.js +0 -165
- package/lib/formats/emoji.js +0 -282
- package/lib/formats/font-family.js +0 -547
- package/lib/formats/heading.js +0 -502
- package/lib/formats/image.js +0 -344
- package/lib/formats/import.js +0 -385
- package/lib/formats/indent.js +0 -297
- package/lib/formats/italic.js +0 -27
- package/lib/formats/line-height.js +0 -558
- package/lib/formats/link.js +0 -251
- package/lib/formats/list.js +0 -635
- package/lib/formats/strike.js +0 -31
- package/lib/formats/subscript.js +0 -36
- package/lib/formats/superscript.js +0 -35
- package/lib/formats/table.js +0 -288
- package/lib/formats/tag.js +0 -304
- package/lib/formats/text-align.js +0 -421
- package/lib/formats/text-size.js +0 -497
- package/lib/formats/underline.js +0 -30
- package/lib/formats/video.js +0 -372
- package/lib/modules/block-toolbar.js +0 -628
- package/lib/modules/code-view.js +0 -434
- package/lib/modules/history.js +0 -410
- package/lib/modules/resize-handles.js +0 -677
- package/lib/modules/table-toolbar.js +0 -618
- package/lib/modules/toolbar.js +0 -424
- package/lib/styles-loader.js +0 -144
- package/lib/styles.css +0 -2123
- package/lib/ui/color-picker.js +0 -296
- package/lib/ui/customselect.js +0 -319
- package/lib/ui/emoji-picker.js +0 -196
- package/lib/ui/icons.js +0 -413
- package/lib/ui/image-popup.js +0 -444
- package/lib/ui/import-popup.js +0 -288
- package/lib/ui/link-popup.js +0 -191
- package/lib/ui/list-picker.js +0 -307
- package/lib/ui/select-button.js +0 -61
- package/lib/ui/table-popup.js +0 -171
- package/lib/ui/tag-popup.js +0 -249
- package/lib/ui/text-align-picker.js +0 -281
- package/lib/ui/video-popup.js +0 -422
- package/lib/utils/history-helper.js +0 -50
- package/lib/utils/popup-helper.js +0 -219
- package/lib/utils/popup-positioning.js +0 -231
package/lib/formats/link.js
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import { InlineFormat } from '../core/format.js';
|
|
2
|
-
import LinkPopup from '../ui/link-popup.js';
|
|
3
|
-
import Editor from '../core/editor.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Link Format - Simple link insertion
|
|
7
|
-
* Now supports multiple editor instances with separate popup instances
|
|
8
|
-
*/
|
|
9
|
-
class Link extends InlineFormat {
|
|
10
|
-
static formatName = 'link';
|
|
11
|
-
static tagName = 'A';
|
|
12
|
-
|
|
13
|
-
// Map to store saved ranges for each editor instance
|
|
14
|
-
static savedRanges = new Map();
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
super();
|
|
18
|
-
|
|
19
|
-
// Get current editor instance
|
|
20
|
-
const currentEditor = Editor.getCurrentInstance();
|
|
21
|
-
if (!currentEditor) {
|
|
22
|
-
console.warn('No editor instance found for Link format');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
this.editorId = currentEditor.instanceId;
|
|
27
|
-
|
|
28
|
-
// Check if this editor already has a link popup instance
|
|
29
|
-
let linkPopup = currentEditor.getPopupInstance('link');
|
|
30
|
-
|
|
31
|
-
if (!linkPopup) {
|
|
32
|
-
// Create new popup instance for this editor
|
|
33
|
-
linkPopup = new LinkPopup({
|
|
34
|
-
onLinkSelect: (linkData) => {
|
|
35
|
-
Link.insertLink(linkData, this.editorId);
|
|
36
|
-
},
|
|
37
|
-
editor: currentEditor,
|
|
38
|
-
editorId: this.editorId
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// Store popup instance in editor
|
|
42
|
-
currentEditor.setPopupInstance('link', linkPopup);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
this.linkPopup = linkPopup;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Create a new Link format instance for a specific editor
|
|
50
|
-
* @param {string} editorId - Editor instance ID
|
|
51
|
-
* @returns {Link} Link format instance
|
|
52
|
-
*/
|
|
53
|
-
static createForEditor(editorId) {
|
|
54
|
-
const editor = Editor.getInstanceById(editorId);
|
|
55
|
-
if (!editor) {
|
|
56
|
-
console.warn('No editor instance found for ID:', editorId);
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Temporarily set as current instance
|
|
61
|
-
const originalCurrent = Editor.currentInstance;
|
|
62
|
-
Editor.currentInstance = editor;
|
|
63
|
-
|
|
64
|
-
// Create format instance
|
|
65
|
-
const format = new Link();
|
|
66
|
-
|
|
67
|
-
// Restore original current instance
|
|
68
|
-
Editor.currentInstance = originalCurrent;
|
|
69
|
-
|
|
70
|
-
return format;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Insert link at saved cursor position
|
|
75
|
-
* @param {Object} linkData - Link data with url and text
|
|
76
|
-
* @param {string} editorId - Editor instance ID
|
|
77
|
-
*/
|
|
78
|
-
static insertLink(linkData, editorId = null) {
|
|
79
|
-
// Get the correct editor instance
|
|
80
|
-
let editor = null;
|
|
81
|
-
if (editorId) {
|
|
82
|
-
editor = Editor.getInstanceById(editorId);
|
|
83
|
-
} else {
|
|
84
|
-
editor = Editor.getCurrentInstance();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (!editor) {
|
|
88
|
-
console.warn('No editor instance found for link insertion');
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Get saved range for this specific editor
|
|
93
|
-
const savedRange = Link.savedRanges.get(editorId);
|
|
94
|
-
if (!savedRange) {
|
|
95
|
-
console.warn('No saved range found for editor:', editorId);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const selection = window.getSelection();
|
|
100
|
-
selection.removeAllRanges();
|
|
101
|
-
selection.addRange(savedRange);
|
|
102
|
-
|
|
103
|
-
const range = selection.getRangeAt(0);
|
|
104
|
-
|
|
105
|
-
if (range.collapsed) {
|
|
106
|
-
// No selection - insert link at cursor
|
|
107
|
-
const linkElement = document.createElement('A');
|
|
108
|
-
linkElement.href = linkData.url;
|
|
109
|
-
linkElement.target = '_blank';
|
|
110
|
-
linkElement.rel = 'noopener noreferrer';
|
|
111
|
-
linkElement.textContent = linkData.text || linkData.url;
|
|
112
|
-
range.insertNode(linkElement);
|
|
113
|
-
} else {
|
|
114
|
-
// Has selection - wrap existing content with link while preserving styles
|
|
115
|
-
const fragment = range.extractContents();
|
|
116
|
-
const linkElement = document.createElement('A');
|
|
117
|
-
linkElement.href = linkData.url;
|
|
118
|
-
linkElement.target = '_blank';
|
|
119
|
-
linkElement.rel = 'noopener noreferrer';
|
|
120
|
-
|
|
121
|
-
// Move all nodes from fragment to link element
|
|
122
|
-
while (fragment.firstChild) {
|
|
123
|
-
linkElement.appendChild(fragment.firstChild);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
range.insertNode(linkElement);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Position cursor after link
|
|
130
|
-
const newRange = document.createRange();
|
|
131
|
-
newRange.setStartAfter(range.endContainer);
|
|
132
|
-
newRange.collapse(true);
|
|
133
|
-
selection.removeAllRanges();
|
|
134
|
-
selection.addRange(newRange);
|
|
135
|
-
|
|
136
|
-
// Trigger content change after applying format
|
|
137
|
-
setTimeout(() => {
|
|
138
|
-
if (editor && typeof editor.onContentChange === 'function') {
|
|
139
|
-
editor.onContentChange();
|
|
140
|
-
}
|
|
141
|
-
}, 0);
|
|
142
|
-
|
|
143
|
-
// Clear saved range for this editor
|
|
144
|
-
Link.savedRanges.delete(editorId);
|
|
145
|
-
|
|
146
|
-
// Trigger content change event
|
|
147
|
-
if (editor && typeof editor.onContentChange === 'function') {
|
|
148
|
-
editor.onContentChange();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Toggle link popup
|
|
154
|
-
*/
|
|
155
|
-
toggle() {
|
|
156
|
-
if (this.linkPopup.isVisible) {
|
|
157
|
-
this.linkPopup.hide();
|
|
158
|
-
} else {
|
|
159
|
-
this.showPopup();
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Show link popup
|
|
165
|
-
*/
|
|
166
|
-
showPopup() {
|
|
167
|
-
// Lưu vị trí con trỏ hiện tại cho editor này
|
|
168
|
-
const selection = window.getSelection();
|
|
169
|
-
if (selection && selection.rangeCount > 0) {
|
|
170
|
-
const range = selection.getRangeAt(0).cloneRange();
|
|
171
|
-
Link.savedRanges.set(this.editorId, range);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Find link button in the current editor's toolbar
|
|
175
|
-
const editor = Editor.getInstanceById(this.editorId);
|
|
176
|
-
if (!editor) {
|
|
177
|
-
console.warn('No editor found for ID:', this.editorId);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const toolbar = editor.getModule('toolbar');
|
|
182
|
-
if (!toolbar) {
|
|
183
|
-
console.warn('No toolbar module found for editor:', this.editorId);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Try to get link button from toolbar
|
|
188
|
-
let linkButton = toolbar.getButton('link');
|
|
189
|
-
|
|
190
|
-
// Fallback: find button by class in the current editor's toolbar
|
|
191
|
-
if (!linkButton) {
|
|
192
|
-
const toolbarContainer = toolbar.getContainer();
|
|
193
|
-
if (toolbarContainer) {
|
|
194
|
-
linkButton = toolbarContainer.querySelector('.rich-editor-toolbar-btn[data-command="link"]');
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Final fallback: find any link button in the current editor's wrapper
|
|
199
|
-
if (!linkButton) {
|
|
200
|
-
linkButton = editor.wrapper.querySelector('.rich-editor-toolbar-btn[data-command="link"]');
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (!linkButton) {
|
|
204
|
-
console.warn('Link button not found for editor:', this.editorId);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Check if cursor is in existing link
|
|
209
|
-
const existingLink = this.getCurrentLink();
|
|
210
|
-
|
|
211
|
-
// Get selected text for display
|
|
212
|
-
let selectedText = '';
|
|
213
|
-
if (selection && !selection.isCollapsed) {
|
|
214
|
-
selectedText = selection.toString().trim();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
this.linkPopup.show(linkButton, existingLink, selectedText);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Get current link if cursor is in one
|
|
222
|
-
*/
|
|
223
|
-
getCurrentLink() {
|
|
224
|
-
const selection = window.getSelection();
|
|
225
|
-
if (!selection || !selection.rangeCount) return null;
|
|
226
|
-
|
|
227
|
-
let node = selection.getRangeAt(0).startContainer;
|
|
228
|
-
|
|
229
|
-
// Find parent link element
|
|
230
|
-
while (node && node !== document.body) {
|
|
231
|
-
if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'A') {
|
|
232
|
-
return {
|
|
233
|
-
url: node.href || '',
|
|
234
|
-
text: node.textContent || ''
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
node = node.parentNode;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Check if cursor is in a link
|
|
245
|
-
*/
|
|
246
|
-
isActive() {
|
|
247
|
-
return this.getCurrentLink() !== null;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
export default Link;
|