@oix1987/yjd 1.0.3 → 2.1.0
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/LICENSE +15 -0
- package/README.md +223 -142
- package/core.js +82 -0
- package/dist/core.esm.js +2 -0
- package/dist/core.esm.js.map +1 -0
- package/dist/rich-editor.esm.js +1 -1
- package/dist/rich-editor.esm.js.map +1 -1
- package/dist/rich-editor.min.js +1 -1
- package/dist/rich-editor.min.js.map +1 -1
- package/index.d.ts +230 -103
- package/index.js +297 -0
- package/lib/core/editor.js +1885 -0
- package/lib/core/format.js +540 -0
- package/lib/core/module.js +81 -0
- package/lib/core/registry.js +158 -0
- package/lib/formats/background.js +213 -0
- package/lib/formats/bold.js +49 -0
- package/lib/formats/capitalization.js +579 -0
- package/lib/formats/color.js +183 -0
- package/lib/formats/emoji.js +282 -0
- package/lib/formats/font-family.js +548 -0
- package/lib/formats/heading.js +502 -0
- package/lib/formats/image.js +341 -0
- package/lib/formats/import.js +385 -0
- package/lib/formats/indent.js +297 -0
- package/lib/formats/italic.js +27 -0
- package/lib/formats/line-height.js +562 -0
- package/lib/formats/link.js +251 -0
- package/lib/formats/list.js +635 -0
- package/lib/formats/strike.js +31 -0
- package/lib/formats/subscript.js +40 -0
- package/lib/formats/superscript.js +39 -0
- package/lib/formats/table.js +293 -0
- package/lib/formats/tag.js +304 -0
- package/lib/formats/text-align.js +422 -0
- package/lib/formats/text-size.js +498 -0
- package/lib/formats/underline.js +30 -0
- package/lib/formats/video.js +381 -0
- package/lib/modules/block-toolbar.js +639 -0
- package/lib/modules/code-view.js +447 -0
- package/lib/modules/find-replace.js +273 -0
- package/lib/modules/history.js +425 -0
- package/lib/modules/mention.js +200 -0
- package/lib/modules/resize-handles.js +701 -0
- package/lib/modules/slash-menu.js +183 -0
- package/lib/modules/table-toolbar.js +635 -0
- package/lib/modules/toolbar.js +607 -0
- package/lib/serialize.js +241 -0
- package/lib/static.js +28 -0
- package/lib/styles-loader.js +142 -0
- package/{dist → lib}/styles.css +1392 -35
- package/lib/styles.css.js +2 -0
- package/lib/styles.min.css +1 -0
- package/lib/ui/color-picker.js +296 -0
- package/lib/ui/customselect.js +351 -0
- package/lib/ui/emoji-picker.js +196 -0
- package/lib/ui/icons.js +145 -0
- package/lib/ui/image-popup.js +435 -0
- package/lib/ui/import-popup.js +288 -0
- package/lib/ui/link-popup.js +139 -0
- package/lib/ui/list-picker.js +307 -0
- package/lib/ui/select-button.js +68 -0
- package/lib/ui/table-popup.js +171 -0
- package/lib/ui/tag-popup.js +249 -0
- package/lib/ui/text-align-picker.js +278 -0
- package/lib/ui/video-popup.js +413 -0
- package/lib/utils/exec-command.js +72 -0
- package/lib/utils/history-helper.js +50 -0
- package/lib/utils/popup-helper.js +219 -0
- package/lib/utils/popup-positioning.js +234 -0
- package/lib/utils/sanitize.js +164 -0
- package/package.json +51 -32
- package/umd-entry.js +19 -0
package/index.d.ts
CHANGED
|
@@ -1,103 +1,230 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
1
|
+
// Type definitions for @oix1987/yjd
|
|
2
|
+
// These declarations are the package entry types (referenced via "types" in package.json),
|
|
3
|
+
// so they are declared at top level rather than wrapped in `declare module`.
|
|
4
|
+
|
|
5
|
+
/** A person/task suggestion returned by a mention source. */
|
|
6
|
+
export interface MentionItem {
|
|
7
|
+
id: string | number;
|
|
8
|
+
name?: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
avatar_url?: string;
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Config for a single mention trigger character. */
|
|
15
|
+
export interface MentionTrigger {
|
|
16
|
+
/** Trigger character, e.g. '#'. */
|
|
17
|
+
char: string;
|
|
18
|
+
/** Async (or sync) lookup of suggestions for the typed query. */
|
|
19
|
+
source: (query: string) => MentionItem[] | Promise<MentionItem[]>;
|
|
20
|
+
/** Custom HTML for a suggestion row. Defaults to avatar + name. */
|
|
21
|
+
renderItem?: (item: MentionItem) => string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** @mention configuration. The token inserted carries `data-id`. */
|
|
25
|
+
export interface MentionOptions {
|
|
26
|
+
/** Primary trigger character (default '@'). */
|
|
27
|
+
trigger?: string;
|
|
28
|
+
source?: (query: string) => MentionItem[] | Promise<MentionItem[]>;
|
|
29
|
+
renderItem?: (item: MentionItem) => string;
|
|
30
|
+
/** Additional triggers, e.g. '#' for task references. */
|
|
31
|
+
triggers?: MentionTrigger[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Image upload hook configuration. */
|
|
35
|
+
export interface ImageOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Upload the chosen file and resolve to its URL. While pending, a placeholder
|
|
38
|
+
* is shown; on resolve the src is swapped, on reject the image is removed.
|
|
39
|
+
* Omit to fall back to inline base64 (data URLs).
|
|
40
|
+
*/
|
|
41
|
+
upload?: (file: File) => string | Promise<string>;
|
|
42
|
+
/** `accept` attribute for the file picker (default 'image/*'). */
|
|
43
|
+
accept?: string;
|
|
44
|
+
/** Maximum file size in bytes; larger files emit 'image:error'. */
|
|
45
|
+
maxSize?: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A JSON document node produced by getJSON()/domToJson. */
|
|
49
|
+
export interface JsonNode {
|
|
50
|
+
tag?: string;
|
|
51
|
+
text?: string;
|
|
52
|
+
attrs?: Record<string, string>;
|
|
53
|
+
content?: JsonNode[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Root JSON document. */
|
|
57
|
+
export interface JsonDoc {
|
|
58
|
+
type: 'doc';
|
|
59
|
+
content: JsonNode[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Editor options interface
|
|
63
|
+
export interface EditorOptions {
|
|
64
|
+
placeholder?: string;
|
|
65
|
+
theme?: string;
|
|
66
|
+
height?: number;
|
|
67
|
+
width?: number;
|
|
68
|
+
maxWidth?: number;
|
|
69
|
+
maxHeight?: number;
|
|
70
|
+
content?: string | null;
|
|
71
|
+
onChange?: (content: string) => void;
|
|
72
|
+
/** When true, paste always inserts plain text (default: false). */
|
|
73
|
+
pasteAsPlainText?: boolean;
|
|
74
|
+
/** Accessible label for the editable region (defaults to placeholder). */
|
|
75
|
+
ariaLabel?: string;
|
|
76
|
+
/** Maximum number of characters allowed. */
|
|
77
|
+
maxLength?: number;
|
|
78
|
+
/** Initial text direction. */
|
|
79
|
+
direction?: 'ltr' | 'rtl';
|
|
80
|
+
/** Enable markdown shortcuts (default: true). Set false to disable. */
|
|
81
|
+
markdown?: boolean;
|
|
82
|
+
/** Autosave drafts to localStorage. true, or { key, debounce(ms) }. */
|
|
83
|
+
autosave?: boolean | { key?: string; debounce?: number };
|
|
84
|
+
/** Image upload hook (replaces inline base64 when `upload` is provided). */
|
|
85
|
+
image?: ImageOptions | boolean;
|
|
86
|
+
/** @mention / #task autocomplete. Inert until a `source` is given. */
|
|
87
|
+
mention?: MentionOptions;
|
|
88
|
+
features?: {
|
|
89
|
+
emoji?: boolean;
|
|
90
|
+
image?: boolean;
|
|
91
|
+
table?: boolean;
|
|
92
|
+
wordCount?: boolean;
|
|
93
|
+
breadcrumb?: boolean;
|
|
94
|
+
};
|
|
95
|
+
toolbar1?: Array<{
|
|
96
|
+
group: string;
|
|
97
|
+
items: string[];
|
|
98
|
+
}>;
|
|
99
|
+
toolbar2?: Array<{
|
|
100
|
+
group: string;
|
|
101
|
+
items: string[];
|
|
102
|
+
}>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export class Editor {
|
|
106
|
+
constructor(selector: string | Element, options?: EditorOptions);
|
|
107
|
+
on(event: string, handler: (data: any) => void): void;
|
|
108
|
+
off(event: string, handler: (data: any) => void): void;
|
|
109
|
+
emit(event: string, data: any): void;
|
|
110
|
+
getContent(): string;
|
|
111
|
+
setContent(content: string): void;
|
|
112
|
+
/** Alias of getContent() / setContent(). */
|
|
113
|
+
getHTML(): string;
|
|
114
|
+
setHTML(html: string): void;
|
|
115
|
+
/** Export/import the document as a JSON tree. */
|
|
116
|
+
getJSON(): JsonDoc;
|
|
117
|
+
setJSON(json: JsonDoc | JsonNode[]): void;
|
|
118
|
+
/** Export/import the document as Markdown (mention ids preserved). */
|
|
119
|
+
getMarkdown(): string;
|
|
120
|
+
setMarkdown(markdown: string): void;
|
|
121
|
+
getText(): string;
|
|
122
|
+
isEmpty(): boolean;
|
|
123
|
+
clear(): void;
|
|
124
|
+
insertText(text: string): void;
|
|
125
|
+
insertHTML(html: string): void;
|
|
126
|
+
clearFormatting(): void;
|
|
127
|
+
insertHorizontalRule(): void;
|
|
128
|
+
insertImageFile(file: File): void;
|
|
129
|
+
setReadOnly(readOnly: boolean): void;
|
|
130
|
+
isReadOnly(): boolean;
|
|
131
|
+
setDirection(dir: 'ltr' | 'rtl'): void;
|
|
132
|
+
getDirection(): 'ltr' | 'rtl';
|
|
133
|
+
toggleDirection(): void;
|
|
134
|
+
clearAutosave(): void;
|
|
135
|
+
focus(): void;
|
|
136
|
+
destroy(): void;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export class Module {}
|
|
140
|
+
export class Format {}
|
|
141
|
+
export class InlineFormat extends Format {}
|
|
142
|
+
export class BlockFormat extends Format {}
|
|
143
|
+
export const registry: any;
|
|
144
|
+
|
|
145
|
+
export class RichEditor extends Editor {
|
|
146
|
+
static register(path: string, definition: any, suppressWarning?: boolean): void;
|
|
147
|
+
static get(path: string): any;
|
|
148
|
+
static create(selector: string | Element, options?: EditorOptions): RichEditor;
|
|
149
|
+
/**
|
|
150
|
+
* Progressive-enhance a <textarea> into an editor, keeping textarea.value
|
|
151
|
+
* in sync (and dispatching native input/change events) on every edit.
|
|
152
|
+
*/
|
|
153
|
+
static fromTextarea(
|
|
154
|
+
textarea: HTMLTextAreaElement | string,
|
|
155
|
+
options?: EditorOptions & { format?: 'html' | 'markdown' }
|
|
156
|
+
): RichEditor;
|
|
157
|
+
/** The original textarea, when created via fromTextarea(). */
|
|
158
|
+
textarea?: HTMLTextAreaElement;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Brand-aligned alias of {@link RichEditor}. */
|
|
162
|
+
export { RichEditor as yjd };
|
|
163
|
+
|
|
164
|
+
export function createEditor(selector: string | Element, options?: EditorOptions): RichEditor;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Render stored HTML into a read-only view that matches the editor's styling.
|
|
168
|
+
* Sanitizes the HTML and tags the host element with `.yjd-content`.
|
|
169
|
+
*/
|
|
170
|
+
export function renderStatic(html: string, target?: Element): Element;
|
|
171
|
+
|
|
172
|
+
// Serialization helpers (also available on the editor as get/set methods)
|
|
173
|
+
export function htmlToMarkdown(html: string): string;
|
|
174
|
+
export function markdownToHtml(markdown: string): string;
|
|
175
|
+
export function domToJson(html: string): JsonDoc;
|
|
176
|
+
export function jsonToHtml(json: JsonDoc | JsonNode[]): string;
|
|
177
|
+
|
|
178
|
+
// Formats
|
|
179
|
+
export const Bold: any;
|
|
180
|
+
export const Italic: any;
|
|
181
|
+
export const Underline: any;
|
|
182
|
+
export const Strike: any;
|
|
183
|
+
export const Subscript: any;
|
|
184
|
+
export const Superscript: any;
|
|
185
|
+
export const Color: any;
|
|
186
|
+
export const Background: any;
|
|
187
|
+
export const Link: any;
|
|
188
|
+
export const Table: any;
|
|
189
|
+
export const Heading: any;
|
|
190
|
+
export const FontFamily: any;
|
|
191
|
+
export const LineHeight: any;
|
|
192
|
+
export const Capitalization: any;
|
|
193
|
+
export const TextAlign: any;
|
|
194
|
+
export const List: any;
|
|
195
|
+
export const Indent: any;
|
|
196
|
+
export const IndentIncrease: any;
|
|
197
|
+
export const IndentDecrease: any;
|
|
198
|
+
export const Emoji: any;
|
|
199
|
+
export const Image: any;
|
|
200
|
+
export const Video: any;
|
|
201
|
+
export const Tag: any;
|
|
202
|
+
export const TextSize: any;
|
|
203
|
+
export const Import: any;
|
|
204
|
+
|
|
205
|
+
// Modules
|
|
206
|
+
export const Toolbar: any;
|
|
207
|
+
export const History: any;
|
|
208
|
+
export const BlockToolbar: any;
|
|
209
|
+
export const TableToolbar: any;
|
|
210
|
+
export const CodeView: any;
|
|
211
|
+
export const FindReplace: any;
|
|
212
|
+
export const SlashMenu: any;
|
|
213
|
+
export const Mention: any;
|
|
214
|
+
export const ResizeHandles: any;
|
|
215
|
+
|
|
216
|
+
// UI components
|
|
217
|
+
export const ColorPicker: any;
|
|
218
|
+
export const IconUtils: any;
|
|
219
|
+
export const LinkPopup: any;
|
|
220
|
+
export const TablePopup: any;
|
|
221
|
+
export const TextAlignPicker: any;
|
|
222
|
+
export const ListPicker: any;
|
|
223
|
+
export const EmojiPicker: any;
|
|
224
|
+
export const ImagePopup: any;
|
|
225
|
+
export const VideoPopup: any;
|
|
226
|
+
export const TagPopup: any;
|
|
227
|
+
|
|
228
|
+
export const createCustomButton: any;
|
|
229
|
+
|
|
230
|
+
export default RichEditor;
|
package/index.js
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import Editor from './lib/core/editor.js';
|
|
2
|
+
import registry from './lib/core/registry.js';
|
|
3
|
+
import Module from './lib/core/module.js';
|
|
4
|
+
import { Format, InlineFormat, BlockFormat } from './lib/core/format.js';
|
|
5
|
+
import StylesLoader from './lib/styles-loader.js';
|
|
6
|
+
import { renderStatic } from './lib/static.js';
|
|
7
|
+
import { htmlToMarkdown, markdownToHtml, domToJson, jsonToHtml } from './lib/serialize.js';
|
|
8
|
+
|
|
9
|
+
// Import formats
|
|
10
|
+
import Bold from './lib/formats/bold.js';
|
|
11
|
+
import Italic from './lib/formats/italic.js';
|
|
12
|
+
import Underline from './lib/formats/underline.js';
|
|
13
|
+
import Strike from './lib/formats/strike.js';
|
|
14
|
+
import Subscript from './lib/formats/subscript.js';
|
|
15
|
+
import Superscript from './lib/formats/superscript.js';
|
|
16
|
+
import Color from './lib/formats/color.js';
|
|
17
|
+
import Background from './lib/formats/background.js';
|
|
18
|
+
import Link from './lib/formats/link.js';
|
|
19
|
+
import Table from './lib/formats/table.js';
|
|
20
|
+
import Heading from './lib/formats/heading.js';
|
|
21
|
+
import FontFamily from './lib/formats/font-family.js';
|
|
22
|
+
import LineHeight from './lib/formats/line-height.js';
|
|
23
|
+
import Capitalization from './lib/formats/capitalization.js';
|
|
24
|
+
import TextAlign from './lib/formats/text-align.js';
|
|
25
|
+
import List from './lib/formats/list.js';
|
|
26
|
+
import Indent, { IndentIncrease, IndentDecrease } from './lib/formats/indent.js';
|
|
27
|
+
import Emoji from './lib/formats/emoji.js';
|
|
28
|
+
import Image from './lib/formats/image.js';
|
|
29
|
+
import Video from './lib/formats/video.js';
|
|
30
|
+
import Tag from './lib/formats/tag.js';
|
|
31
|
+
import TextSize from './lib/formats/text-size.js';
|
|
32
|
+
|
|
33
|
+
import Import from './lib/formats/import.js';
|
|
34
|
+
|
|
35
|
+
// Import modules
|
|
36
|
+
import Toolbar from './lib/modules/toolbar.js';
|
|
37
|
+
import History from './lib/modules/history.js';
|
|
38
|
+
import BlockToolbar from './lib/modules/block-toolbar.js';
|
|
39
|
+
import TableToolbar from './lib/modules/table-toolbar.js';
|
|
40
|
+
import CodeView from './lib/modules/code-view.js';
|
|
41
|
+
import FindReplace from './lib/modules/find-replace.js';
|
|
42
|
+
import SlashMenu from './lib/modules/slash-menu.js';
|
|
43
|
+
import Mention from './lib/modules/mention.js';
|
|
44
|
+
|
|
45
|
+
import ResizeHandles from './lib/modules/resize-handles.js';
|
|
46
|
+
|
|
47
|
+
// Import UI components
|
|
48
|
+
import ColorPicker from './lib/ui/color-picker.js';
|
|
49
|
+
import IconUtils from './lib/ui/icons.js';
|
|
50
|
+
import LinkPopup from './lib/ui/link-popup.js';
|
|
51
|
+
import TablePopup from './lib/ui/table-popup.js';
|
|
52
|
+
import TextAlignPicker from './lib/ui/text-align-picker.js';
|
|
53
|
+
import ListPicker from './lib/ui/list-picker.js';
|
|
54
|
+
import EmojiPicker from './lib/ui/emoji-picker.js';
|
|
55
|
+
import ImagePopup from './lib/ui/image-popup.js';
|
|
56
|
+
import VideoPopup from './lib/ui/video-popup.js';
|
|
57
|
+
import TagPopup from './lib/ui/tag-popup.js';
|
|
58
|
+
|
|
59
|
+
import createCustomButton from './lib/ui/select-button.js';
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
// Register default formats
|
|
64
|
+
registry.register('formats/bold', Bold, true);
|
|
65
|
+
registry.register('formats/italic', Italic, true);
|
|
66
|
+
registry.register('formats/underline', Underline, true);
|
|
67
|
+
registry.register('formats/strike', Strike, true);
|
|
68
|
+
registry.register('formats/subscript', Subscript, true);
|
|
69
|
+
registry.register('formats/superscript', Superscript, true);
|
|
70
|
+
registry.register('formats/color', Color, true);
|
|
71
|
+
registry.register('formats/background', Background, true);
|
|
72
|
+
registry.register('formats/link', Link, true);
|
|
73
|
+
registry.register('formats/table', Table, true);
|
|
74
|
+
registry.register('formats/heading', Heading, true);
|
|
75
|
+
registry.register('formats/font-family', FontFamily, true);
|
|
76
|
+
registry.register('formats/line-height', LineHeight, true);
|
|
77
|
+
registry.register('formats/capitalization', Capitalization, true);
|
|
78
|
+
registry.register('formats/text-align', TextAlign, true);
|
|
79
|
+
registry.register('formats/list', List, true);
|
|
80
|
+
registry.register('formats/indent', Indent, true);
|
|
81
|
+
registry.register('formats/indent-increase', IndentIncrease, true);
|
|
82
|
+
registry.register('formats/indent-decrease', IndentDecrease, true);
|
|
83
|
+
registry.register('formats/emoji', Emoji, true);
|
|
84
|
+
registry.register('formats/image', Image, true);
|
|
85
|
+
registry.register('formats/video', Video, true);
|
|
86
|
+
registry.register('formats/tag', Tag, true);
|
|
87
|
+
registry.register('formats/text-size', TextSize, true);
|
|
88
|
+
|
|
89
|
+
registry.register('formats/import', Import, true);
|
|
90
|
+
|
|
91
|
+
// Register default modules
|
|
92
|
+
registry.register('modules/toolbar', Toolbar, true);
|
|
93
|
+
registry.register('modules/history', History, true);
|
|
94
|
+
registry.register('modules/block-toolbar', BlockToolbar, true);
|
|
95
|
+
registry.register('modules/table-toolbar', TableToolbar, true);
|
|
96
|
+
registry.register('modules/code-view', CodeView, true);
|
|
97
|
+
registry.register('modules/find-replace', FindReplace, true);
|
|
98
|
+
registry.register('modules/slash-menu', SlashMenu, true);
|
|
99
|
+
registry.register('modules/mention', Mention, true);
|
|
100
|
+
|
|
101
|
+
registry.register('modules/resize-handles', ResizeHandles, true);
|
|
102
|
+
|
|
103
|
+
// Register UI components
|
|
104
|
+
registry.register('ui/color-picker', ColorPicker, true);
|
|
105
|
+
registry.register('ui/text-align-picker', TextAlignPicker, true);
|
|
106
|
+
registry.register('ui/list-picker', ListPicker, true);
|
|
107
|
+
registry.register('ui/emoji-picker', EmojiPicker, true);
|
|
108
|
+
registry.register('ui/image-popup', ImagePopup, true);
|
|
109
|
+
registry.register('ui/video-popup', VideoPopup, true);
|
|
110
|
+
registry.register('ui/tag-popup', TagPopup, true);
|
|
111
|
+
|
|
112
|
+
registry.register('ui/custom-button', createCustomButton, true);
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
// Load CSS styles
|
|
117
|
+
StylesLoader.loadStyles().catch(error => {
|
|
118
|
+
console.warn('Could not load Rich Editor styles:', error);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Main Editor class with registration system
|
|
122
|
+
class RichEditor extends Editor {
|
|
123
|
+
/**
|
|
124
|
+
* Register a module, format, or theme
|
|
125
|
+
* @param {string|object} path - Registration path
|
|
126
|
+
* @param {*} definition - Class definition
|
|
127
|
+
* @param {boolean} suppressWarning - Suppress overwrite warnings
|
|
128
|
+
*/
|
|
129
|
+
static register(path, definition, suppressWarning = false) {
|
|
130
|
+
registry.register(path, definition, suppressWarning);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get registered item
|
|
135
|
+
* @param {string} path - Registration path
|
|
136
|
+
*/
|
|
137
|
+
static get(path) {
|
|
138
|
+
return registry.get(path);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Create new editor instance
|
|
143
|
+
* @param {string|Element} selector - DOM selector or element
|
|
144
|
+
* @param {object} options - Editor options
|
|
145
|
+
*/
|
|
146
|
+
static create(selector, options = {}) {
|
|
147
|
+
return new RichEditor(selector, options);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Progressive-enhance a <textarea>: hide it, mount an editor in its place,
|
|
152
|
+
* and keep the textarea's value in sync so existing form submits keep working.
|
|
153
|
+
*
|
|
154
|
+
* const ed = RichEditor.fromTextarea(document.querySelector('#body'), {
|
|
155
|
+
* // any editor option; `format` chooses how the textarea is read/written:
|
|
156
|
+
* format: 'html' | 'markdown', // default 'html'
|
|
157
|
+
* });
|
|
158
|
+
*
|
|
159
|
+
* The textarea's current value seeds the editor (parsed as HTML or Markdown
|
|
160
|
+
* per `format`). On every change the textarea is updated and a native 'input'
|
|
161
|
+
* event is dispatched, so framework bindings / validation keep firing.
|
|
162
|
+
*
|
|
163
|
+
* @param {HTMLTextAreaElement|string} textarea Element or selector.
|
|
164
|
+
* @param {object} [options] Editor options + optional `format`.
|
|
165
|
+
* @returns {RichEditor}
|
|
166
|
+
*/
|
|
167
|
+
static fromTextarea(textarea, options = {}) {
|
|
168
|
+
const ta = typeof textarea === 'string' ? document.querySelector(textarea) : textarea;
|
|
169
|
+
if (!ta) throw new Error('RichEditor.fromTextarea: textarea not found');
|
|
170
|
+
|
|
171
|
+
const format = options.format === 'markdown' ? 'markdown' : 'html';
|
|
172
|
+
const readEditor = (ed) => (format === 'markdown' ? ed.getMarkdown() : ed.getContent());
|
|
173
|
+
|
|
174
|
+
// Mount point right after the textarea; hide the original.
|
|
175
|
+
const mount = document.createElement('div');
|
|
176
|
+
ta.after(mount);
|
|
177
|
+
ta.style.display = 'none';
|
|
178
|
+
ta.setAttribute('aria-hidden', 'true');
|
|
179
|
+
|
|
180
|
+
const initial = ta.value || '';
|
|
181
|
+
const editor = new RichEditor(mount, {
|
|
182
|
+
width: '100%',
|
|
183
|
+
...options,
|
|
184
|
+
// Seed content from the textarea (skip if caller passed explicit content).
|
|
185
|
+
content: options.content != null ? options.content
|
|
186
|
+
: (format === 'markdown' ? markdownToHtml(initial) : initial),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const sync = () => {
|
|
190
|
+
const next = readEditor(editor);
|
|
191
|
+
if (ta.value === next) return;
|
|
192
|
+
ta.value = next;
|
|
193
|
+
ta.dispatchEvent(new Event('input', { bubbles: true }));
|
|
194
|
+
ta.dispatchEvent(new Event('change', { bubbles: true }));
|
|
195
|
+
};
|
|
196
|
+
editor.on('change', sync);
|
|
197
|
+
sync(); // normalise the textarea to the editor's serialization up front.
|
|
198
|
+
|
|
199
|
+
editor.textarea = ta;
|
|
200
|
+
return editor;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Export classes for extension. `yjd` is the brand-aligned name; `RichEditor`
|
|
205
|
+
// is kept as an alias for backward compatibility.
|
|
206
|
+
export {
|
|
207
|
+
RichEditor as default,
|
|
208
|
+
RichEditor,
|
|
209
|
+
RichEditor as yjd,
|
|
210
|
+
Editor,
|
|
211
|
+
Module,
|
|
212
|
+
Format,
|
|
213
|
+
InlineFormat,
|
|
214
|
+
BlockFormat,
|
|
215
|
+
registry
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Export formats
|
|
219
|
+
export {
|
|
220
|
+
Bold,
|
|
221
|
+
Italic,
|
|
222
|
+
Underline,
|
|
223
|
+
Strike,
|
|
224
|
+
Subscript,
|
|
225
|
+
Superscript,
|
|
226
|
+
Color,
|
|
227
|
+
Background,
|
|
228
|
+
Link,
|
|
229
|
+
Table,
|
|
230
|
+
Heading,
|
|
231
|
+
FontFamily,
|
|
232
|
+
LineHeight,
|
|
233
|
+
Capitalization,
|
|
234
|
+
TextAlign,
|
|
235
|
+
List,
|
|
236
|
+
Indent,
|
|
237
|
+
IndentIncrease,
|
|
238
|
+
IndentDecrease,
|
|
239
|
+
Emoji,
|
|
240
|
+
Image,
|
|
241
|
+
Video,
|
|
242
|
+
Tag,
|
|
243
|
+
TextSize,
|
|
244
|
+
|
|
245
|
+
Import
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// Export modules
|
|
249
|
+
export {
|
|
250
|
+
Toolbar,
|
|
251
|
+
History,
|
|
252
|
+
BlockToolbar,
|
|
253
|
+
TableToolbar,
|
|
254
|
+
CodeView,
|
|
255
|
+
FindReplace,
|
|
256
|
+
SlashMenu,
|
|
257
|
+
Mention,
|
|
258
|
+
|
|
259
|
+
ResizeHandles
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Export UI components
|
|
263
|
+
export {
|
|
264
|
+
ColorPicker,
|
|
265
|
+
IconUtils,
|
|
266
|
+
LinkPopup,
|
|
267
|
+
TablePopup,
|
|
268
|
+
TextAlignPicker,
|
|
269
|
+
ListPicker,
|
|
270
|
+
EmojiPicker,
|
|
271
|
+
ImagePopup,
|
|
272
|
+
VideoPopup,
|
|
273
|
+
TagPopup,
|
|
274
|
+
|
|
275
|
+
createCustomButton
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// Static rendering + serialization helpers
|
|
279
|
+
export {
|
|
280
|
+
renderStatic,
|
|
281
|
+
htmlToMarkdown,
|
|
282
|
+
markdownToHtml,
|
|
283
|
+
domToJson,
|
|
284
|
+
jsonToHtml
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Utility function to create editor instance
|
|
292
|
+
* @param {string|Element} selector - DOM selector or element
|
|
293
|
+
* @param {object} options - Editor options
|
|
294
|
+
*/
|
|
295
|
+
export function createEditor(selector, options = {}) {
|
|
296
|
+
return new RichEditor(selector, options);
|
|
297
|
+
}
|