autumnnote 1.0.8 → 1.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/README.md +401 -628
- package/dist/autumnnote.css +169 -0
- package/dist/autumnnote.es.js +3669 -179
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +3668 -178
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +3 -2
- package/src/js/Context.js +18 -2
- package/src/js/core/func.js +5 -5
- package/src/js/i18n/de.js +320 -0
- package/src/js/i18n/en.js +328 -0
- package/src/js/i18n/es.js +320 -0
- package/src/js/i18n/fr.js +321 -0
- package/src/js/i18n/index.js +59 -0
- package/src/js/i18n/ja.js +321 -0
- package/src/js/i18n/ko.js +320 -0
- package/src/js/i18n/vi.js +321 -0
- package/src/js/i18n/zh.js +321 -0
- package/src/js/index.js +2 -1
- package/src/js/module/AutoSaveRestore.js +126 -0
- package/src/js/module/BubbleToolbar.js +243 -0
- package/src/js/module/CodeTooltip.js +12 -9
- package/src/js/module/ContextMenu.js +41 -37
- package/src/js/module/EmojiDialog.js +8 -7
- package/src/js/module/FindReplace.js +14 -13
- package/src/js/module/IconDialog.js +14 -13
- package/src/js/module/ImageDialog.js +17 -16
- package/src/js/module/ImageTooltip.js +13 -12
- package/src/js/module/LinkDialog.js +10 -9
- package/src/js/module/LinkTooltip.js +6 -5
- package/src/js/module/MarkdownShortcuts.js +253 -0
- package/src/js/module/Mention.js +337 -0
- package/src/js/module/ShortcutsDialog.js +5 -4
- package/src/js/module/Statusbar.js +6 -5
- package/src/js/module/TableTooltip.js +22 -19
- package/src/js/module/Toolbar.js +21 -15
- package/src/js/module/VideoDialog.js +10 -9
- package/src/js/module/VideoTooltip.js +12 -11
- package/src/js/settings.js +23 -0
- package/src/styles/autumnnote.scss +191 -0
- package/types/index.d.ts +114 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Autumn Note
|
|
2
2
|
|
|
3
3
|
<p align="center"><img src="image/banner.png" width="120" alt="AutumnNote Banner"/></p>
|
|
4
4
|
|
|
5
|
-
[](#)
|
|
6
6
|
[](https://github.com/cmm-cmm/Autumn-Note/actions/workflows/pages.yml)
|
|
7
7
|
[](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
|
8
8
|
[](https://vitejs.dev/)
|
|
@@ -11,37 +11,60 @@
|
|
|
11
11
|
[](#)
|
|
12
12
|
[](https://fontawesome.com/)
|
|
13
13
|
|
|
14
|
-
A modern, lightweight WYSIWYG rich-text editor with vanilla JavaScript (ES2022+)
|
|
14
|
+
A modern, lightweight WYSIWYG rich-text editor built with vanilla JavaScript (ES2022+) — no jQuery, no heavy dependencies.
|
|
15
15
|
|
|
16
|
-
>
|
|
16
|
+
> Write rich text. No dependencies. No drama.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
[Live Demo](https://cmm-cmm.github.io/Autumn-Note/)
|
|
19
19
|
|
|
20
20
|
<p align="center"><img src="demo/Screenshot.png" alt="AutumnNote Screenshot"/></p>
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
1. [Features](#features)
|
|
27
|
+
2. [Installation](#installation)
|
|
28
|
+
3. [Quick Start](#quick-start)
|
|
29
|
+
4. [API](#api)
|
|
30
|
+
5. [Options](#options)
|
|
31
|
+
6. [Toolbar Customisation](#toolbar-customisation)
|
|
32
|
+
7. [Keyboard Shortcuts](#keyboard-shortcuts)
|
|
33
|
+
8. [Mentions](#mentions)
|
|
34
|
+
9. [Project Structure](#project-structure)
|
|
35
|
+
10. [Comparison](#comparison)
|
|
36
|
+
11. [License](#license)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
24
40
|
## Features
|
|
25
41
|
|
|
26
42
|
### Editing
|
|
27
43
|
- **Text formatting** — bold, italic, underline, strikethrough, superscript, subscript
|
|
28
44
|
- **Paragraph styles** — Normal, H1–H6, Blockquote, Code block
|
|
29
45
|
- **Font family** — customisable dropdown (10 families by default)
|
|
46
|
+
- **Font size** — configurable default via `defaultFontSize`; applied to new content
|
|
30
47
|
- **Line height** — dropdown from 1.0 to 3.0
|
|
31
|
-
- **Text
|
|
48
|
+
- **Text and highlight colour** — native colour picker with last-used colour memory; custom brand swatches via `colorSwatches`
|
|
32
49
|
- **Alignment** — left, center, right, justify
|
|
33
50
|
- **Lists** — unordered and ordered, with indent / outdent; Tab/Shift+Tab in list context
|
|
34
|
-
- **
|
|
51
|
+
- **Checklist** — interactive checkbox list; toggle items by clicking; converts to/from plain paragraphs on outdent
|
|
52
|
+
- **Undo / redo** — built-in history stack (configurable depth via `historyLimit`, `Ctrl+Z` / `Ctrl+Y`)
|
|
35
53
|
- **Tab key** — configurable spaces-per-tab; smart list indentation inside `<li>`
|
|
54
|
+
- **RTL support** — set `direction: 'rtl'` to flip the editor layout and text direction
|
|
36
55
|
|
|
37
56
|
### Insert
|
|
38
57
|
- **Horizontal rule** — inserts an `<hr>` at the current caret position
|
|
39
58
|
- **Link dialog** — URL, display text (auto-filled from selection), "Open in new tab" checkbox; edits existing links when caret is inside an `<a>`
|
|
40
|
-
- **Image dialog** — insert by URL with alt text, or file upload (base64 embed); enforces `maxImageSize`; supports custom `onImageUpload` handler for server-side upload
|
|
59
|
+
- **Image dialog** — insert by URL with alt text, or file upload (base64 embed); enforces `maxImageSize`; file input restricted to browser-renderable MIME types; supports custom `onImageUpload` handler for server-side upload
|
|
60
|
+
- **Image crop overlay** — inline interactive crop tool triggered from the image tooltip; corner and edge drag handles; canvas-based crop export; CORS fallback warning
|
|
41
61
|
- **Video dialog** — paste a YouTube watch/short URL, Vimeo URL, or direct `.mp4 / .webm / .ogg` URL; configurable width; renders as responsive `<iframe>` or `<video>`
|
|
42
|
-
- **Table** — interactive grid picker (up to
|
|
43
|
-
- **Emoji picker** —
|
|
44
|
-
- **FA Icon picker** — FontAwesome 6 Free Solid icons across 8 categories
|
|
62
|
+
- **Table** — interactive grid picker (up to 10x10); optional header row (`tableHeaderRow`); floating tooltip for full row/column/cell management
|
|
63
|
+
- **Emoji picker** — approximately 380 Unicode emoji across 7 categories (Smileys, People, Animals, Food, Travel, Objects, Symbols); keyword search; click to insert as plain UTF-8 character
|
|
64
|
+
- **FA Icon picker** — FontAwesome 6 Free Solid icons across 8 categories; keyword search; configurable style, size, and colour; inserts as `<i>` element; auto-injects FA CDN if not on the page
|
|
65
|
+
|
|
66
|
+
### Search
|
|
67
|
+
- **Find and Replace** — `Ctrl+F` to find, `Ctrl+H` for find-and-replace; TreeWalker text matching; `<mark>` highlighting; case-sensitive toggle; Prev/Next navigation; single and replace-all modes
|
|
45
68
|
|
|
46
69
|
### Inline tooltips
|
|
47
70
|
Floating toolbars appear automatically when the user clicks on an editable element:
|
|
@@ -49,34 +72,53 @@ Floating toolbars appear automatically when the user clicks on an editable eleme
|
|
|
49
72
|
| Element | Actions |
|
|
50
73
|
|---|---|
|
|
51
74
|
| **Link** | Open in new tab, Edit (reopens dialog), Unlink |
|
|
52
|
-
| **Image** | Edit alt/URL (reopens dialog), Delete |
|
|
75
|
+
| **Image** | Edit alt/URL (reopens dialog), Crop, Delete |
|
|
53
76
|
| **Video** | Edit (reopens dialog), Delete |
|
|
54
77
|
| **Table cell** | Row above/below, Delete row, Column left/right, Delete column, Merge cells, Unmerge cells, Cell selection mode, Column width, Row height, Border width, Delete table |
|
|
55
|
-
| **Code block**
|
|
78
|
+
| **Code block** | Copy code, Delete block |
|
|
56
79
|
|
|
57
80
|
### Context menu
|
|
58
|
-
Right-click inside the editor opens a context menu with: **Undo**, **Redo**, **Cut**, **Copy**, **Paste**, **Bold**, **Italic**, **Underline**, **Copy Format**, **Paste Format**, **Remove Format
|
|
81
|
+
Right-click inside the editor opens a context menu with: **Undo**, **Redo**, **Cut**, **Copy**, **Paste**, **Bold**, **Italic**, **Underline**, **Copy Format**, **Paste Format**, **Remove Format**, and a **colour palette** for quick text/highlight colour changes.
|
|
82
|
+
|
|
83
|
+
### Internationalisation
|
|
84
|
+
- **Built-in locales** — English (`en`), Vietnamese (`vi`), Japanese (`ja`), Simplified Chinese (`zh`), French (`fr`), German (`de`), Spanish (`es`), Korean (`ko`)
|
|
85
|
+
- **Custom locale** — pass any partial locale object to override individual strings
|
|
86
|
+
- **Per-instance language** — set a different `lang` per editor instance on the same page
|
|
87
|
+
- **Auto-fallback** — unknown codes or missing keys fall back to English
|
|
59
88
|
|
|
60
89
|
### UI
|
|
61
|
-
- **Toolbar** — fully configurable button groups;
|
|
90
|
+
- **Toolbar** — fully configurable button groups; overflow strategy: `wrap` (default) or `scroll`; FontAwesome icons with built-in SVG fallback
|
|
91
|
+
- **Sticky toolbar** — `stickyToolbar: true` pins the toolbar to the viewport top; configurable offset for fixed nav bars
|
|
92
|
+
- **Dark / light theme** — `theme: 'dark'` or `theme: 'light'` (default); full SCSS variable coverage
|
|
62
93
|
- **Image resizer** — drag handle on selected image to resize proportionally
|
|
63
94
|
- **Video resizer** — drag handle on selected video embed to resize
|
|
64
|
-
- **Statusbar** — live word and character count; drag handle to resize editor height
|
|
95
|
+
- **Statusbar** — live word and character count; drag handle to resize editor height; limit warnings when `maxChars` or `maxWords` is reached
|
|
65
96
|
- **Code view** — toggle raw HTML; sanitised before applying back to the editor
|
|
66
97
|
- **Fullscreen** — expands the editor to fill the viewport
|
|
67
98
|
- **Placeholder** — CSS `::before` pseudo-element, zero DOM node cost
|
|
99
|
+
- **Read-only mode** — `readOnly: true` renders a non-editable preview with toolbar hidden; toggle at runtime via `editor.setDisabled()`
|
|
100
|
+
- **Auto-save** — `autoSave: true` persists content to `localStorage` on every change; key configurable via `autoSaveKey`
|
|
101
|
+
- **Auto-save restore** — when `autoSave` and `autoSaveRestore` are both `true`, a dismissible banner prompts the user to restore or discard a previously saved draft on load; configurable age window via `autoSaveRestoreTimeout`
|
|
102
|
+
- **Bubble toolbar** — `bubbleToolbar: true` shows a compact floating toolbar above selected text with quick-access buttons (bold, italic, underline, strikethrough, link, text colour, remove format, inline code); button set configurable via `bubbleToolbarItems`
|
|
103
|
+
- **Markdown shortcuts** — `markdownShortcuts: true` (default) converts Markdown syntax typed in the editor into HTML in real time: `# ` → H1–H3, `> ` → blockquote, `- ` / `* ` → unordered list, `1. ` → ordered list, `[ ] ` → checklist, `---` → HR, ` ``` ` → code block; inline: `**bold**`, `*italic*`, `~~strikethrough~~`, `` `code` ``
|
|
104
|
+
- **Custom focus ring** — `focusColor` accepts any CSS colour string to override the default blue focus ring
|
|
105
|
+
- **Spellcheck** — browser spellcheck enabled by default (`spellcheck: true`)
|
|
68
106
|
|
|
69
107
|
### Integration
|
|
70
108
|
- **No jQuery** — pure vanilla ES2022, zero runtime dependencies
|
|
71
|
-
- **Bootstrap friendly** — optional Bootstrap 4/5 styling
|
|
109
|
+
- **Bootstrap friendly** — optional Bootstrap 4/5 styling (`useBootstrap: true`)
|
|
72
110
|
- **FontAwesome ready** — auto-detects FA on the page; falls back to built-in SVG icons
|
|
73
111
|
- **Plugin-ready** — register custom modules via `AutumnNote.defaults`
|
|
74
|
-
- **Tree-shakeable** — ES module build; all core utilities
|
|
112
|
+
- **Tree-shakeable** — ES module build; all core utilities individually exported
|
|
113
|
+
- **TypeScript definitions** — bundled `types/index.d.ts` with full JSDoc coverage
|
|
114
|
+
- **@mention autocomplete** — type `@` (or any custom trigger) to open a floating dropdown backed by a user-supplied `onSearch` function; inserts a non-editable mention chip; customisable chip HTML via `onInsert`
|
|
75
115
|
|
|
76
116
|
### Security
|
|
77
|
-
- All HTML (pasted content, `setHTML()`, or code-view output)
|
|
117
|
+
- All HTML (pasted content, `setHTML()`, or code-view output) passes through a DOM-based sanitiser that strips `<script>`, `<object>`, `<embed>`, and all `on*` event handler attributes
|
|
118
|
+
- `<iframe>` elements are permitted in `setHTML()` with src restricted to trusted CDN hosts; `srcdoc` is stripped
|
|
78
119
|
- `javascript:` and `data:` URLs are rejected in links and images
|
|
79
120
|
- Clipboard paste sanitises rich content to remove XSS vectors before inserting
|
|
121
|
+
- `pasteStripAttributes` option strips `class`, `style`, and `data-*` from pasted HTML
|
|
80
122
|
|
|
81
123
|
---
|
|
82
124
|
|
|
@@ -85,14 +127,32 @@ Right-click inside the editor opens a context menu with: **Undo**, **Redo**, **C
|
|
|
85
127
|
### npm / pnpm / yarn
|
|
86
128
|
|
|
87
129
|
```bash
|
|
88
|
-
npm install
|
|
130
|
+
npm install autumnnote
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
import AutumnNote from 'autumnnote';
|
|
135
|
+
import 'autumnnote/dist/autumnnote.css';
|
|
89
136
|
```
|
|
90
137
|
|
|
91
138
|
### CDN
|
|
92
139
|
|
|
140
|
+
**jsDelivr** (Recommended):
|
|
141
|
+
|
|
93
142
|
```html
|
|
94
|
-
<
|
|
95
|
-
|
|
143
|
+
<script src="https://cdn.jsdelivr.net/npm/autumnnote"></script>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**unpkg:**
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<script src="https://unpkg.com/autumnnote"></script>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<link rel="stylesheet" href="dist/autumnnote.css" />
|
|
155
|
+
<script src="dist/autumnnote.umd.js"></script>
|
|
96
156
|
```
|
|
97
157
|
|
|
98
158
|
> **FontAwesome icons** — the editor auto-detects FontAwesome on the page and falls back to built-in SVG icons when absent. To enable FA icons, include the FA stylesheet:
|
|
@@ -101,8 +161,6 @@ npm install AutumnNote
|
|
|
101
161
|
> <!-- FontAwesome 6 Free (recommended) -->
|
|
102
162
|
> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
|
|
103
163
|
> ```
|
|
104
|
-
>
|
|
105
|
-
> If FA is not on the page but the **FA Icon picker** is used, the editor will automatically inject the FontAwesome CDN stylesheet on first open.
|
|
106
164
|
|
|
107
165
|
---
|
|
108
166
|
|
|
@@ -111,7 +169,7 @@ npm install AutumnNote
|
|
|
111
169
|
### ES Module
|
|
112
170
|
|
|
113
171
|
```js
|
|
114
|
-
import AutumnNote from '
|
|
172
|
+
import AutumnNote from 'autumnnote';
|
|
115
173
|
|
|
116
174
|
const editor = AutumnNote.create('#my-editor', {
|
|
117
175
|
placeholder: 'Start typing…',
|
|
@@ -126,7 +184,7 @@ const editor = AutumnNote.create('#my-editor', {
|
|
|
126
184
|
|
|
127
185
|
```html
|
|
128
186
|
<div id="my-editor"><p>Hello!</p></div>
|
|
129
|
-
<script src="dist/
|
|
187
|
+
<script src="dist/autumnnote.umd.js"></script>
|
|
130
188
|
<script>
|
|
131
189
|
const editor = AutumnNote.create('#my-editor');
|
|
132
190
|
</script>
|
|
@@ -142,527 +200,69 @@ const editor = AutumnNote.create('#my-editor', {
|
|
|
142
200
|
});
|
|
143
201
|
```
|
|
144
202
|
|
|
145
|
-
###
|
|
146
|
-
|
|
147
|
-
```js
|
|
148
|
-
const editor = AutumnNote.create('#my-editor', {
|
|
149
|
-
useFontAwesome: true,
|
|
150
|
-
fontAwesomeClass: 'fa-solid', // FA 6 prefix
|
|
151
|
-
});
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## Usage
|
|
157
|
-
|
|
158
|
-
### Read content on demand
|
|
159
|
-
|
|
160
|
-
The most common pattern — attach a button that reads back the current HTML:
|
|
161
|
-
|
|
162
|
-
```html
|
|
163
|
-
<link rel="stylesheet" href="dist/autumnnote.css" />
|
|
164
|
-
|
|
165
|
-
<div id="editor"><p>Hello, <strong>AutumnNote</strong>!</p></div>
|
|
166
|
-
|
|
167
|
-
<button onclick="getHTML()">Get HTML</button>
|
|
168
|
-
<pre id="output"></pre>
|
|
169
|
-
|
|
170
|
-
<script src="dist/autumnnote.umd.js"></script>
|
|
171
|
-
<script>
|
|
172
|
-
const editor = AutumnNote.create('#editor', { height: 300 });
|
|
173
|
-
|
|
174
|
-
function getHTML() {
|
|
175
|
-
document.getElementById('output').innerText = editor.getHTML();
|
|
176
|
-
}
|
|
177
|
-
</script>
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### React to every change
|
|
181
|
-
|
|
182
|
-
Use `onChange` (or `editor.on('change', fn)`) to update a live preview automatically:
|
|
183
|
-
|
|
184
|
-
```html
|
|
185
|
-
<div id="editor"><p>Start typing…</p></div>
|
|
186
|
-
<pre id="preview"></pre>
|
|
187
|
-
|
|
188
|
-
<script src="dist/autumnnote.umd.js"></script>
|
|
189
|
-
<script>
|
|
190
|
-
const editor = AutumnNote.create('#editor', {
|
|
191
|
-
height: 300,
|
|
192
|
-
onChange(html) {
|
|
193
|
-
document.getElementById('preview').innerText = html;
|
|
194
|
-
},
|
|
195
|
-
});
|
|
196
|
-
</script>
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Set and clear content programmatically
|
|
200
|
-
|
|
201
|
-
```js
|
|
202
|
-
editor.setHTML('<p>New <em>content</em></p>'); // set
|
|
203
|
-
editor.clear(); // clear to empty <p>
|
|
204
|
-
console.log(editor.getText()); // plain text, no markup
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## API
|
|
210
|
-
|
|
211
|
-
### Factory
|
|
212
|
-
|
|
213
|
-
| Method | Description |
|
|
214
|
-
|---|---|
|
|
215
|
-
| `AutumnNote.create(selector, options?)` | Creates editor instance(s). `selector` can be a CSS string, `Element`, `NodeList`, or `Element[]`. Returns a `Context` for a single match, or `Context[]` for multiple. |
|
|
216
|
-
| `AutumnNote.destroy(selector)` | Destroys editor(s) matching the selector and restores the original element. |
|
|
217
|
-
| `AutumnNote.getInstance(selector)` | Returns the `Context` for a given element, or `null` if not initialised. |
|
|
218
|
-
| `AutumnNote.defaults` | Global default options object. Mutate before calling `create()` to apply project-wide settings. |
|
|
219
|
-
|
|
220
|
-
### Context (editor instance)
|
|
221
|
-
|
|
222
|
-
| Method | Description |
|
|
223
|
-
|---|---|
|
|
224
|
-
| `editor.getHTML()` | Returns the current HTML content. Zero-width spaces inserted by the icon picker are stripped automatically. |
|
|
225
|
-
| `editor.setHTML(html)` | Sets HTML content. Input is sanitised before rendering. |
|
|
226
|
-
| `editor.getText()` | Returns plain text with no markup. |
|
|
227
|
-
| `editor.clear()` | Clears all content, resets to an empty `<p>`. |
|
|
228
|
-
| `editor.setDisabled(bool)` | Disables (`true`) or re-enables (`false`) the editor and toolbar. |
|
|
229
|
-
| `editor.destroy()` | Removes the editor, disposes all modules, and restores the original element. |
|
|
230
|
-
| `editor.on(event, fn)` | Subscribes to an editor event. Returns an unsubscribe function — call it to remove the listener. |
|
|
231
|
-
| `editor.invoke('module.method', ...args)` | Calls any registered module method by dot-separated name. Returns the method's return value. |
|
|
232
|
-
|
|
233
|
-
### Events
|
|
234
|
-
|
|
235
|
-
| Name | Payload | Description |
|
|
236
|
-
|---|---|---|
|
|
237
|
-
| `change` | `html: string` | Fired after every content mutation. Debounced internally. |
|
|
238
|
-
| `focus` | — | Editor's editable area gained focus. |
|
|
239
|
-
| `blur` | — | Editor's editable area lost focus. |
|
|
240
|
-
|
|
241
|
-
#### Subscribing to events
|
|
242
|
-
|
|
243
|
-
```js
|
|
244
|
-
const editor = AutumnNote.create('#editor');
|
|
245
|
-
|
|
246
|
-
// Subscribe
|
|
247
|
-
const unsub = editor.on('change', (html) => {
|
|
248
|
-
document.getElementById('output').innerHTML = html;
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// Unsubscribe later
|
|
252
|
-
unsub();
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### `invoke()` examples
|
|
203
|
+
### Dark mode
|
|
256
204
|
|
|
257
205
|
```js
|
|
258
|
-
|
|
259
|
-
editor.invoke('linkDialog.show');
|
|
260
|
-
editor.invoke('imageDialog.show');
|
|
261
|
-
editor.invoke('emojiDialog.show');
|
|
262
|
-
editor.invoke('iconDialog.show');
|
|
263
|
-
|
|
264
|
-
// Undo / redo
|
|
265
|
-
editor.invoke('editor.undo');
|
|
266
|
-
editor.invoke('editor.redo');
|
|
267
|
-
|
|
268
|
-
// Toggle views
|
|
269
|
-
editor.invoke('codeview.toggle');
|
|
270
|
-
editor.invoke('fullscreen.toggle');
|
|
271
|
-
|
|
272
|
-
// Query state
|
|
273
|
-
const isCodeview = editor.invoke('codeview.isActive'); // boolean
|
|
274
|
-
const isFullscreen = editor.invoke('fullscreen.isActive'); // boolean
|
|
206
|
+
const editor = AutumnNote.create('#my-editor', { theme: 'dark' });
|
|
275
207
|
```
|
|
276
208
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
## Options
|
|
280
|
-
|
|
281
|
-
| Option | Type | Default | Description |
|
|
282
|
-
|---|---|---|---|
|
|
283
|
-
| `placeholder` | `string` | `''` | Placeholder text shown when the editor is empty. |
|
|
284
|
-
| `height` | `number` | `200` | Initial / minimum editor height in px. |
|
|
285
|
-
| `minHeight` | `number` | `100` | Hard minimum height in px (enforced during resize). |
|
|
286
|
-
| `maxHeight` | `number` | `0` | Maximum height in px. `0` = unlimited. |
|
|
287
|
-
| `focus` | `boolean` | `false` | Auto-focus the editor on initialisation. |
|
|
288
|
-
| `resizeable` | `boolean` | `true` | Show the drag-to-resize handle in the statusbar. |
|
|
289
|
-
| `toolbar` | `Array` | default | Array of button group arrays. See [Toolbar customisation](#toolbar-customisation). |
|
|
290
|
-
| `useBootstrap` | `boolean` | `false` | Apply Bootstrap button classes to toolbar buttons. |
|
|
291
|
-
| `bootstrapVersion` | `number` | `5` | Bootstrap major version to target (`4` or `5`). |
|
|
292
|
-
| `toolbarButtonClass` | `string` | `'btn btn-sm btn-light'` | CSS classes applied to toolbar buttons when `useBootstrap` is `true`. |
|
|
293
|
-
| `useFontAwesome` | `boolean` | `true` | Render toolbar icons via FontAwesome when FA is detected on the page. |
|
|
294
|
-
| `fontAwesomeClass` | `string` | `'fas'` | FontAwesome prefix class. Use `'fas'` for FA 5, `'fa-solid'` for FA 6. |
|
|
295
|
-
| `pasteAsPlainText` | `boolean` | `false` | Force all pasted content to plain text, stripping all formatting. |
|
|
296
|
-
| `pasteCleanHTML` | `boolean` | `true` | Sanitise HTML on paste — strips scripts and dangerous attributes. |
|
|
297
|
-
| `allowImageUpload` | `boolean` | `true` | Show the file upload input in the image dialog. |
|
|
298
|
-
| `maxImageSize` | `number` | `5` | Maximum image upload file size in MB. Files exceeding this are rejected with an alert. |
|
|
299
|
-
| `onImageUpload` | `Function` | `null` | `(files: FileList) => void` — custom upload handler. When provided, overrides the default base64 embed behaviour. Insert the resulting URL yourself via `editor.invoke('editor.insertImage', url, alt)`. |
|
|
300
|
-
| `tabSize` | `number` | `0` | Number of spaces inserted per Tab key press outside of lists. `0` = browser default Tab behaviour. |
|
|
301
|
-
| `defaultFontFamily` | `string` | `'Arial'` | Font family applied as the default style for the editable area. |
|
|
302
|
-
| `fontFamilies` | `string[]` | (10 fonts) | Font families listed in the Font Family dropdown. Default: Arial, Arial Black, Comic Sans MS, Courier New, Georgia, Impact, Tahoma, Times New Roman, Trebuchet MS, Verdana. |
|
|
303
|
-
| `onChange` | `Function` | `null` | `(html: string) => void` — shorthand for `editor.on('change', fn)`. |
|
|
304
|
-
| `onFocus` | `Function` | `null` | `(context: Context) => void` — shorthand for `editor.on('focus', fn)`. |
|
|
305
|
-
| `onBlur` | `Function` | `null` | `(context: Context) => void` — shorthand for `editor.on('blur', fn)`. |
|
|
306
|
-
| `stickyToolbar` | `boolean` | `false` | Stick the toolbar to the viewport top when the page is scrolled. |
|
|
307
|
-
| `stickyToolbarOffset` | `number` | `0` | Top offset in px for the sticky toolbar (e.g. height of a fixed navigation bar). |
|
|
308
|
-
| `theme` | `string` | `'light'` | Colour theme: `'light'` or `'dark'`. |
|
|
309
|
-
| `codeHighlight` | `boolean` | `false` | Auto-load Prism.js for syntax highlighting inside `<pre><code>` blocks. |
|
|
310
|
-
| `codeHighlightCDN` | `string` | cdnjs Prism 1.29.0 | Base CDN URL used when auto-loading Prism assets. |
|
|
311
|
-
| `markdownPaste` | `boolean` | `true` | Convert pasted Markdown text to HTML when no HTML is present in the clipboard. |
|
|
312
|
-
| `readOnly` | `boolean` | `false` | Start the editor in read-only (non-editable) mode. The toolbar is hidden and the content area is non-interactive. Toggle programmatically with `editor.setDisabled(bool)`. |
|
|
313
|
-
| `focusColor` | `string` | `null` | Custom CSS colour for the editor focus ring, e.g. `'#f97316'`. Overrides the default blue when set. |
|
|
314
|
-
|
|
315
|
-
---
|
|
316
|
-
|
|
317
|
-
## Dialogs
|
|
318
|
-
|
|
319
|
-
### Link dialog
|
|
320
|
-
Fields: **URL** (type=url, required), **Display text** (auto-populated from the current selection), **Open in new tab** checkbox.
|
|
321
|
-
When the caret is inside an existing `<a>` element, the dialog pre-fills with the current link's values and updates in-place on confirm.
|
|
322
|
-
|
|
323
|
-
### Image dialog
|
|
324
|
-
Fields: **Image URL** (type=url), **Alt text**, and — when `allowImageUpload` is `true` — a **file picker** (accepts `image/*`). Selecting a file embeds it as a base64 data URI unless `onImageUpload` is provided.
|
|
325
|
-
|
|
326
|
-
### Video dialog
|
|
327
|
-
Fields: **Video URL** (YouTube / Vimeo / direct file), **Width** (px, default 560). Supported URL formats:
|
|
328
|
-
- `https://www.youtube.com/watch?v=…` → `<iframe>` embed
|
|
329
|
-
- `https://youtu.be/…` → `<iframe>` embed
|
|
330
|
-
- `https://vimeo.com/…` → `<iframe>` embed
|
|
331
|
-
- Direct `.mp4`, `.webm`, `.ogg` URL → `<video controls>` element
|
|
332
|
-
|
|
333
|
-
### Emoji picker
|
|
334
|
-
Displays ~380 Unicode emoji in a scrollable grid grouped into 7 categories. Filter by category tab or keyword search. Clicking an emoji inserts it immediately as a plain Unicode character — no extra "Insert" step. All characters are UTF-8 / utf8mb4 compatible.
|
|
335
|
-
|
|
336
|
-
### FA Icon picker
|
|
337
|
-
Displays FontAwesome 6 Free Solid icons grouped into 8 categories: **Popular**, **Interface**, **Navigation**, **Media**, **Communication**, **Files**, **People**, **Objects**. Filter by category or keyword search. Before inserting, configure:
|
|
338
|
-
- **Style** — Solid, Regular, or Light (Pro)
|
|
339
|
-
- **Size** — Inherit, 0.75em, 1em, 1.25em, 1.5em, 2em, 3em
|
|
340
|
-
- **Colour** — colour picker + "Use colour" toggle
|
|
341
|
-
|
|
342
|
-
The icon is inserted as `<i class="fa-solid fa-{name}" style="…">`. If FontAwesome is not loaded on the page, the dialog automatically injects the FA 6 CDN stylesheet on first open.
|
|
343
|
-
|
|
344
|
-
---
|
|
345
|
-
|
|
346
|
-
## Table tooltip
|
|
347
|
-
|
|
348
|
-
Clicking inside any table opens a floating tooltip with the following actions:
|
|
349
|
-
|
|
350
|
-
| Group | Actions |
|
|
351
|
-
|---|---|
|
|
352
|
-
| Rows | Add Row Above, Add Row Below, Delete Row |
|
|
353
|
-
| Columns | Add Column Left, Add Column Right, Delete Column |
|
|
354
|
-
| Cells | Merge Cells |
|
|
355
|
-
| Resize | Column Width (px / %), Row Height (px) |
|
|
356
|
-
| Danger | Delete Table |
|
|
357
|
-
|
|
358
|
-
---
|
|
359
|
-
|
|
360
|
-
## Toolbar Customisation
|
|
361
|
-
|
|
362
|
-
The `toolbar` option accepts an array of button groups. Each group is a sub-array of button definition objects:
|
|
209
|
+
### Read-only preview
|
|
363
210
|
|
|
364
211
|
```js
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
boldBtn, italicBtn, underlineBtn, strikeBtn,
|
|
368
|
-
foreColorBtn, backColorBtn,
|
|
369
|
-
linkBtn, imageBtn, videoBtn, tableBtn,
|
|
370
|
-
emojiBtn, iconBtn,
|
|
371
|
-
codeviewBtn, fullscreenBtn,
|
|
372
|
-
} from 'AutumnNote/src/js/module/Buttons.js';
|
|
373
|
-
|
|
374
|
-
AutumnNote.create('#editor', {
|
|
375
|
-
toolbar: [
|
|
376
|
-
[boldBtn, italicBtn, underlineBtn, strikeBtn],
|
|
377
|
-
[foreColorBtn, backColorBtn],
|
|
378
|
-
[linkBtn, imageBtn, videoBtn, tableBtn],
|
|
379
|
-
[emojiBtn, iconBtn],
|
|
380
|
-
[codeviewBtn, fullscreenBtn],
|
|
381
|
-
],
|
|
382
|
-
});
|
|
212
|
+
const preview = AutumnNote.create('#preview', { readOnly: true });
|
|
213
|
+
preview.setHTML(savedHtml);
|
|
383
214
|
```
|
|
384
215
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
| Export | Type | Tooltip |
|
|
388
|
-
|---|---|---|
|
|
389
|
-
| `paragraphStyleBtn` | dropdown | Paragraph Style |
|
|
390
|
-
| `fontFamilyBtn` | dropdown | Font Family |
|
|
391
|
-
| `lineHeightBtn` | dropdown | Line Height |
|
|
392
|
-
| `undoBtn` / `redoBtn` | button | Undo / Redo |
|
|
393
|
-
| `boldBtn` / `italicBtn` / `underlineBtn` / `strikeBtn` | button | Text style |
|
|
394
|
-
| `superscriptBtn` / `subscriptBtn` | button | Super / Subscript |
|
|
395
|
-
| `foreColorBtn` / `backColorBtn` | color picker | Text colour / Highlight colour |
|
|
396
|
-
| `alignLeftBtn` / `alignCenterBtn` / `alignRightBtn` / `alignJustifyBtn` | button | Alignment |
|
|
397
|
-
| `ulBtn` / `olBtn` / `indentBtn` / `outdentBtn` | button | Lists & indentation |
|
|
398
|
-
| `hrBtn` | button | Horizontal Rule |
|
|
399
|
-
| `linkBtn` | button | Insert Link |
|
|
400
|
-
| `imageBtn` | button | Insert Image |
|
|
401
|
-
| `videoBtn` | button | Insert Video |
|
|
402
|
-
| `tableBtn` | grid picker | Insert Table |
|
|
403
|
-
| `emojiBtn` | button | Insert Emoji |
|
|
404
|
-
| `iconBtn` | button | Insert FA Icon |
|
|
405
|
-
| `codeviewBtn` | button | HTML Code View |
|
|
406
|
-
| `fullscreenBtn` | button | Fullscreen |
|
|
407
|
-
|
|
408
|
-
### Setting global defaults
|
|
216
|
+
### Auto-save draft
|
|
409
217
|
|
|
410
218
|
```js
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
Object.assign(AutumnNote.defaults, {
|
|
415
|
-
height: 400,
|
|
416
|
-
placeholder: 'Write something…',
|
|
417
|
-
fontAwesomeClass: 'fa-solid',
|
|
418
|
-
fontFamilies: ['Inter', 'Roboto', 'Georgia', 'Courier New'],
|
|
219
|
+
const editor = AutumnNote.create('#my-editor', {
|
|
220
|
+
autoSave: true,
|
|
221
|
+
autoSaveKey: 'my-draft',
|
|
419
222
|
});
|
|
420
223
|
```
|
|
421
224
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
## Custom Image Upload
|
|
225
|
+
### Custom image upload
|
|
425
226
|
|
|
426
227
|
```js
|
|
427
|
-
AutumnNote.create('#editor', {
|
|
428
|
-
allowImageUpload: true,
|
|
228
|
+
const editor = AutumnNote.create('#my-editor', {
|
|
429
229
|
onImageUpload(files) {
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
fetch('/api/upload', { method: 'POST', body: formData })
|
|
230
|
+
const fd = new FormData();
|
|
231
|
+
fd.append('file', files[0]);
|
|
232
|
+
fetch('/api/upload', { method: 'POST', body: fd })
|
|
434
233
|
.then(r => r.json())
|
|
435
|
-
.then(({ url }) =>
|
|
436
|
-
// Insert the returned URL into the editor
|
|
437
|
-
this.invoke('editor.insertImage', url, files[0].name);
|
|
438
|
-
});
|
|
234
|
+
.then(({ url }) => editor.insertImage(url, files[0].name));
|
|
439
235
|
},
|
|
440
236
|
});
|
|
441
237
|
```
|
|
442
238
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
## Multiple Instances
|
|
239
|
+
### Bubble toolbar
|
|
446
240
|
|
|
447
241
|
```js
|
|
448
|
-
const editors = AutumnNote.create('.rich-editor', { height: 250 });
|
|
449
|
-
// editors is Context[] when selector matches multiple elements
|
|
450
|
-
|
|
451
|
-
// Iterate all instances
|
|
452
|
-
document.querySelectorAll('.rich-editor').forEach((el) => {
|
|
453
|
-
const editor = AutumnNote.getInstance(el);
|
|
454
|
-
console.log(editor.getHTML());
|
|
455
|
-
});
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
---
|
|
459
|
-
|
|
460
|
-
## Project Structure
|
|
461
|
-
|
|
462
|
-
```
|
|
463
|
-
src/
|
|
464
|
-
├── js/
|
|
465
|
-
│ ├── core/
|
|
466
|
-
│ │ ├── dom.js DOM utilities (createElement, on, closest, …)
|
|
467
|
-
│ │ ├── range.js Selection / Range API helpers (withSavedRange, …)
|
|
468
|
-
│ │ ├── func.js General helpers (mergeDeep, debounce, …)
|
|
469
|
-
│ │ ├── key.js Keyboard key constants
|
|
470
|
-
│ │ ├── lists.js Array helpers
|
|
471
|
-
│ │ ├── env.js Browser / platform detection
|
|
472
|
-
│ │ ├── markdown.js Lightweight Markdown → HTML converter (paste handling)
|
|
473
|
-
│ │ └── sanitise.js DOM-based HTML and URL sanitiser (shared by all modules)
|
|
474
|
-
│ ├── editing/
|
|
475
|
-
│ │ ├── History.js Undo / redo stack (100 levels)
|
|
476
|
-
│ │ ├── Style.js execCommand style wrappers
|
|
477
|
-
│ │ ├── Table.js Table creation and cell manipulation
|
|
478
|
-
│ │ └── Typing.js Tab / Enter key behaviour
|
|
479
|
-
│ ├── module/
|
|
480
|
-
│ │ ├── Editor.js Core editing commands + getHTML / setHTML + sanitiser
|
|
481
|
-
│ │ ├── Toolbar.js Toolbar UI, button rendering (SVG + FA), dropdowns, colour picker
|
|
482
|
-
│ │ ├── Buttons.js Button / dropdown / colorpicker definitions and defaultToolbar
|
|
483
|
-
│ │ ├── Statusbar.js Word & character count + drag-to-resize
|
|
484
|
-
│ │ ├── Clipboard.js Paste sanitisation (HTML clean + plain-text mode)
|
|
485
|
-
│ │ ├── ContextMenu.js Right-click context menu (cut, copy, paste, format tools)
|
|
486
|
-
│ │ ├── Placeholder.js CSS-based placeholder
|
|
487
|
-
│ │ ├── Codeview.js HTML source view toggle
|
|
488
|
-
│ │ ├── Fullscreen.js Fullscreen mode
|
|
489
|
-
│ │ ├── LinkDialog.js Link insert / edit dialog
|
|
490
|
-
│ │ ├── LinkTooltip.js Floating toolbar for links (open / edit / unlink)
|
|
491
|
-
│ │ ├── ImageDialog.js Image insert dialog (URL + optional file upload)
|
|
492
|
-
│ │ ├── ImageTooltip.js Floating toolbar for images (edit / delete)
|
|
493
|
-
│ │ ├── ImageResizer.js Drag handle to resize images
|
|
494
|
-
│ │ ├── VideoDialog.js Video embed dialog (YouTube, Vimeo, direct file)
|
|
495
|
-
│ │ ├── VideoTooltip.js Floating toolbar for video embeds (edit / delete)
|
|
496
|
-
│ │ ├── VideoResizer.js Drag handle to resize video embeds
|
|
497
|
-
│ │ ├── TableTooltip.js Floating toolbar for tables (row/col/cell management)
|
|
498
|
-
│ │ ├── CodeTooltip.js Floating toolbar for code blocks (copy / delete)
|
|
499
|
-
│ │ ├── EmojiDialog.js Unicode emoji picker (~380 emoji, 7 categories)
|
|
500
|
-
│ │ ├── IconDialog.js FontAwesome icon picker (FA 6 Free Solid, 8 categories)
|
|
501
|
-
│ │ └── ShortcutsDialog.js Keyboard shortcuts reference dialog (Shift+?)
|
|
502
|
-
│ ├── Context.js Editor instance hub — module registry and event bus
|
|
503
|
-
│ ├── settings.js Default options (AsnOptions)
|
|
504
|
-
│ ├── renderer.js DOM layout builder
|
|
505
|
-
│ └── index.js Public entry point + AutumnNote factory
|
|
506
|
-
└── styles/
|
|
507
|
-
├── _variables.scss SCSS design tokens (colours, spacing, radii, transitions)
|
|
508
|
-
└── AutumnNote.scss Main stylesheet
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
---
|
|
512
|
-
|
|
513
|
-
## Development
|
|
514
|
-
|
|
515
|
-
```bash
|
|
516
|
-
# Install dependencies
|
|
517
|
-
npm install
|
|
518
|
-
|
|
519
|
-
# Start dev server with HMR (Vite)
|
|
520
|
-
npm run dev
|
|
521
|
-
|
|
522
|
-
# Build library (ES module + UMD + CSS)
|
|
523
|
-
npm run build
|
|
524
|
-
|
|
525
|
-
# Run unit tests (Vitest)
|
|
526
|
-
npm test
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
Build output in `dist/`:
|
|
530
|
-
- `AutumnNote.es.js` — ES module (tree-shakeable)
|
|
531
|
-
- `AutumnNote.umd.js` — UMD bundle (script tag / CommonJS)
|
|
532
|
-
- `AutumnNote.css` — compiled stylesheet
|
|
533
|
-
|
|
534
|
-
---
|
|
535
|
-
|
|
536
|
-
## Comparison with Summernote
|
|
537
|
-
|
|
538
|
-
| Feature | Summernote | AutumnNote |
|
|
539
|
-
|---|---|---|
|
|
540
|
-
| jQuery required | Yes | No |
|
|
541
|
-
| Bootstrap required | Optional | No |
|
|
542
|
-
| Build system | Grunt | Vite |
|
|
543
|
-
| Module format | IIFE | ES module + UMD |
|
|
544
|
-
| Written in | ES5 / ES6 mix | ES2022 |
|
|
545
|
-
| HTML sanitisation | Basic | DOM-based (strips scripts, XSS vectors) |
|
|
546
|
-
| Emoji picker | No | Yes (~380 Unicode emoji, 7 categories) |
|
|
547
|
-
| FA icon picker | No | Yes (FA 6 Free Solid, 8 categories, searchable) |
|
|
548
|
-
| Video embeds | No | Yes (YouTube, Vimeo, direct file) |
|
|
549
|
-
| Image / video resize | No | Yes (drag handles) |
|
|
550
|
-
| Inline tooltips | No | Yes (link, image, video, table, code) |
|
|
551
|
-
| Context menu | No | Yes (with format copy/paste) |
|
|
552
|
-
| Right-click context menu | No | Yes |
|
|
553
|
-
|
|
554
|
-
---
|
|
555
|
-
|
|
556
|
-
## License
|
|
557
|
-
|
|
558
|
-
MIT
|
|
559
|
-
|
|
560
|
-
---
|
|
561
|
-
|
|
562
|
-
## Features
|
|
563
|
-
|
|
564
|
-
### Editing
|
|
565
|
-
- **Text formatting** — bold, italic, underline, strikethrough, superscript, subscript
|
|
566
|
-
- **Paragraph styles** — Normal, H1–H6, Blockquote, Code block
|
|
567
|
-
- **Font family** — customisable dropdown (10 families by default)
|
|
568
|
-
- **Line height** — dropdown from 1.0 to 3.0
|
|
569
|
-
- **Text & highlight colour** — native colour picker with last-used colour
|
|
570
|
-
- **Alignment** — left, center, right, justify
|
|
571
|
-
- **Lists** — unordered and ordered, with indent / outdent
|
|
572
|
-
- **Undo / redo** — built-in history stack (100 levels, `Ctrl+Z` / `Ctrl+Y`)
|
|
573
|
-
- **Tab key** — configurable spaces-per-tab, smart list indentation
|
|
574
|
-
|
|
575
|
-
### Insert
|
|
576
|
-
- **Horizontal rule**
|
|
577
|
-
- **Link dialog** — insert / edit hyperlinks with text and target options
|
|
578
|
-
- **Image dialog** — insert by URL or file upload (base64 embed); configurable max size
|
|
579
|
-
- **Video dialog** — insert YouTube / Vimeo / direct video URLs as responsive embeds
|
|
580
|
-
- **Table** — interactive grid picker (up to 10×10), context-menu actions (add/delete row/col, merge, split)
|
|
581
|
-
- **Emoji picker** — ~380 Unicode emoji across 7 categories (Smileys, People, Animals, Food, Travel, Objects, Symbols) with keyword search; click to insert instantly
|
|
582
|
-
- **FA Icon picker** — browse FontAwesome 6 Free Solid icons by category with keyword search; configurable style, size, and colour
|
|
583
|
-
|
|
584
|
-
### UI
|
|
585
|
-
- **Toolbar** — fully configurable button groups; auto-renders with SVG fallback or FontAwesome icons
|
|
586
|
-
- **Inline tooltips** — link, image, video, table, and code-block context tooltips with edit/delete actions
|
|
587
|
-
- **Image resizer** — drag handle to resize inserted images
|
|
588
|
-
- **Video resizer** — drag handle to resize inserted video embeds
|
|
589
|
-
- **Statusbar** — word and character count + drag-to-resize editor height
|
|
590
|
-
- **Code view** — toggle raw HTML source editor with sanitisation on apply
|
|
591
|
-
- **Fullscreen** — expand to fill the viewport
|
|
592
|
-
- **Placeholder** — CSS-based, zero DOM pollution
|
|
593
|
-
- **Context menu** — right-click menu for common actions
|
|
594
|
-
|
|
595
|
-
### Integration
|
|
596
|
-
- **No jQuery** — pure vanilla ES2022, zero runtime dependencies
|
|
597
|
-
- **Bootstrap friendly** — optional Bootstrap 4/5 styling for toolbar buttons (`useBootstrap: true`)
|
|
598
|
-
- **FontAwesome ready** — auto-detects FA on the page; falls back to inline SVG icons
|
|
599
|
-
- **Plugin-ready** — register custom modules via `AutumnNote.defaults`
|
|
600
|
-
- **Tree-shakeable** — ES module build; all core utilities are individually exported
|
|
601
|
-
|
|
602
|
-
### Security
|
|
603
|
-
- All HTML (pasted, loaded via `setHTML`, or applied from code view) is sanitised through a DOM-based parser — strips `<script>`, `<iframe>`, `<object>`, all `on*` attributes
|
|
604
|
-
- `javascript:` URLs are rejected in links and images
|
|
605
|
-
- Clipboard paste sanitises and removes XSS vectors before inserting
|
|
606
|
-
|
|
607
|
-
---
|
|
608
|
-
|
|
609
|
-
## Installation
|
|
610
|
-
|
|
611
|
-
### npm / pnpm / yarn
|
|
612
|
-
|
|
613
|
-
```bash
|
|
614
|
-
npm install AutumnNote
|
|
615
|
-
```
|
|
616
|
-
|
|
617
|
-
### CDN
|
|
618
|
-
|
|
619
|
-
```html
|
|
620
|
-
<link rel="stylesheet" href="dist/AutumnNote.css" />
|
|
621
|
-
<script src="dist/AutumnNote.umd.js"></script>
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
> To use FontAwesome toolbar icons, include the FA stylesheet on your page. The editor auto-detects it and falls back to built-in SVG icons when FA is absent.
|
|
625
|
-
>
|
|
626
|
-
> ```html
|
|
627
|
-
> <!-- FontAwesome 6 Free -->
|
|
628
|
-
> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
|
|
629
|
-
> ```
|
|
630
|
-
|
|
631
|
-
---
|
|
632
|
-
|
|
633
|
-
## Quick Start
|
|
634
|
-
|
|
635
|
-
### ES Module
|
|
636
|
-
|
|
637
|
-
```js
|
|
638
|
-
import AutumnNote from 'AutumnNote';
|
|
639
|
-
|
|
640
242
|
const editor = AutumnNote.create('#my-editor', {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
onChange(html) {
|
|
644
|
-
console.log(html);
|
|
645
|
-
},
|
|
243
|
+
bubbleToolbar: true,
|
|
244
|
+
bubbleToolbarItems: ['bold', 'italic', 'underline', 'strikethrough', 'link', 'removeFormat'],
|
|
646
245
|
});
|
|
647
246
|
```
|
|
648
247
|
|
|
649
|
-
###
|
|
650
|
-
|
|
651
|
-
```html
|
|
652
|
-
<div id="my-editor"><p>Hello!</p></div>
|
|
653
|
-
<script src="dist/AutumnNote.umd.js"></script>
|
|
654
|
-
<script>
|
|
655
|
-
const editor = AutumnNote.create('#my-editor');
|
|
656
|
-
</script>
|
|
657
|
-
```
|
|
658
|
-
|
|
659
|
-
### With Bootstrap 5
|
|
248
|
+
### @mention autocomplete
|
|
660
249
|
|
|
661
250
|
```js
|
|
662
251
|
const editor = AutumnNote.create('#my-editor', {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
252
|
+
mention: {
|
|
253
|
+
onSearch(query, callback) {
|
|
254
|
+
const users = [
|
|
255
|
+
{ id: 1, label: 'Alice' },
|
|
256
|
+
{ id: 2, label: 'Bob' },
|
|
257
|
+
{ id: 3, label: 'Charlie' },
|
|
258
|
+
];
|
|
259
|
+
callback(users.filter(u => u.label.toLowerCase().includes(query.toLowerCase())));
|
|
260
|
+
},
|
|
261
|
+
onInsert(item) {
|
|
262
|
+
// optional: return custom HTML for the mention chip
|
|
263
|
+
return `<span class="mention" data-id="${item.id}">@${item.label}</span>`;
|
|
264
|
+
},
|
|
265
|
+
},
|
|
666
266
|
});
|
|
667
267
|
```
|
|
668
268
|
|
|
@@ -674,31 +274,40 @@ const editor = AutumnNote.create('#my-editor', {
|
|
|
674
274
|
|
|
675
275
|
| Method | Description |
|
|
676
276
|
|---|---|
|
|
677
|
-
| `AutumnNote.create(selector, options?)` | Creates editor instance(s).
|
|
277
|
+
| `AutumnNote.create(selector, options?)` | Creates editor instance(s). `selector` can be a CSS string, `Element`, `NodeList`, or `Element[]`. Returns a `Context` or `Context[]`. |
|
|
678
278
|
| `AutumnNote.destroy(selector)` | Destroys editor(s) and restores the original element. |
|
|
679
279
|
| `AutumnNote.getInstance(selector)` | Returns the `Context` for a given element, or `null`. |
|
|
680
|
-
| `AutumnNote.defaults` | Global default options — mutate before calling `create()` to
|
|
280
|
+
| `AutumnNote.defaults` | Global default options object — mutate before calling `create()` to apply project-wide settings. |
|
|
681
281
|
|
|
682
|
-
### Context (
|
|
282
|
+
### Context (instance methods)
|
|
683
283
|
|
|
684
284
|
| Method | Description |
|
|
685
285
|
|---|---|
|
|
686
|
-
| `editor.getHTML()` | Returns the current HTML
|
|
687
|
-
| `editor.setHTML(html)` | Sets HTML content (sanitised). |
|
|
688
|
-
| `editor.getText()` | Returns plain text
|
|
689
|
-
| `editor.clear()` | Clears all content
|
|
690
|
-
| `editor.setDisabled(bool)` |
|
|
691
|
-
| `editor.destroy()` | Removes the editor and restores the original element. |
|
|
286
|
+
| `editor.getHTML()` | Returns the current HTML. Zero-width spaces from the icon picker are stripped automatically. |
|
|
287
|
+
| `editor.setHTML(html)` | Sets HTML content (sanitised). `<iframe>` elements are preserved. |
|
|
288
|
+
| `editor.getText()` | Returns plain text with no markup. |
|
|
289
|
+
| `editor.clear()` | Clears all content, resets to an empty `<p>`. |
|
|
290
|
+
| `editor.setDisabled(bool)` | Disables (`true`) or re-enables (`false`) the editor and toolbar. |
|
|
291
|
+
| `editor.destroy()` | Removes the editor, disposes all modules, and restores the original element. |
|
|
692
292
|
| `editor.on(event, fn)` | Subscribes to an editor event. Returns an unsubscribe function. |
|
|
693
|
-
| `editor.
|
|
293
|
+
| `editor.off(event, fn)` | Removes a previously registered listener. |
|
|
294
|
+
| `editor.invoke('module.method', ...args)` | Calls any registered module method by dot-separated name. |
|
|
694
295
|
|
|
695
296
|
### Events
|
|
696
297
|
|
|
697
298
|
| Name | Payload | Description |
|
|
698
299
|
|---|---|---|
|
|
699
|
-
| `change` | `html: string` | Fired after every content mutation. |
|
|
700
|
-
| `focus` |
|
|
701
|
-
| `blur` |
|
|
300
|
+
| `change` | `html: string` | Fired after every content mutation. Debounced internally. |
|
|
301
|
+
| `focus` | `context` | Editor gained focus. |
|
|
302
|
+
| `blur` | `context` | Editor lost focus. |
|
|
303
|
+
| `init` | `context` | Fired once after the editor has fully initialised. |
|
|
304
|
+
| `imageUpload` | `files: FileList` | Fired when images are dropped or pasted (when `onImageUpload` is provided). |
|
|
305
|
+
| `imageError` | `{ file, message }` | Fired when an image is rejected (e.g. over `maxImageSize`). |
|
|
306
|
+
| `paste` | `{ text, html }` | Fired after every paste event. |
|
|
307
|
+
| `selectionChange` | `context` | Fired when the cursor or selection changes. |
|
|
308
|
+
| `destroy` | `context` | Fired just before the editor is destroyed. |
|
|
309
|
+
| `charLimitReached` | `context` | Fired when `maxChars` is hit. |
|
|
310
|
+
| `wordLimitReached` | `context` | Fired when `maxWords` is hit. |
|
|
702
311
|
|
|
703
312
|
---
|
|
704
313
|
|
|
@@ -707,59 +316,125 @@ const editor = AutumnNote.create('#my-editor', {
|
|
|
707
316
|
| Option | Type | Default | Description |
|
|
708
317
|
|---|---|---|---|
|
|
709
318
|
| `placeholder` | `string` | `''` | Placeholder text shown when the editor is empty. |
|
|
710
|
-
| `height` | `number` | `200` | Initial
|
|
711
|
-
| `minHeight` | `number` | `100` |
|
|
712
|
-
| `maxHeight` | `number` | `0` | Maximum height in
|
|
713
|
-
| `focus` | `boolean` | `false` |
|
|
714
|
-
| `
|
|
715
|
-
| `toolbar` | `Array` |
|
|
716
|
-
| `
|
|
319
|
+
| `height` | `number` | `200` | Initial editor height in pixels. |
|
|
320
|
+
| `minHeight` | `number` | `100` | Minimum resizable height in pixels. |
|
|
321
|
+
| `maxHeight` | `number` | `0` | Maximum resizable height in pixels. `0` = unlimited. |
|
|
322
|
+
| `focus` | `boolean` | `false` | Automatically focus the editor on creation. |
|
|
323
|
+
| `resizable` | `boolean` | `true` | Show the resize handle at the bottom of the editor. |
|
|
324
|
+
| `toolbar` | `Array[]` | all buttons | Toolbar layout. See [Toolbar Customisation](#toolbar-customisation). |
|
|
325
|
+
| `toolbarOverflow` | `string` | `'wrap'` | Toolbar overflow strategy: `'wrap'` or `'scroll'`. |
|
|
326
|
+
| `useBootstrap` | `boolean` | `false` | Apply Bootstrap CSS classes to toolbar buttons. |
|
|
717
327
|
| `bootstrapVersion` | `number` | `5` | Bootstrap major version (`4` or `5`). |
|
|
718
328
|
| `toolbarButtonClass` | `string` | `'btn btn-sm btn-light'` | CSS classes for toolbar buttons when `useBootstrap` is `true`. |
|
|
719
329
|
| `useFontAwesome` | `boolean` | `true` | Use FA icons when FontAwesome is detected on the page. |
|
|
720
|
-
| `fontAwesomeClass` | `string` | `'fas'` | FA prefix
|
|
721
|
-
| `pasteAsPlainText` | `boolean` | `false` | Strip all formatting
|
|
330
|
+
| `fontAwesomeClass` | `string` | `'fas'` | FA prefix: `'fas'` for FA 5, `'fa-solid'` for FA 6. |
|
|
331
|
+
| `pasteAsPlainText` | `boolean` | `false` | Strip all formatting when pasting. |
|
|
722
332
|
| `pasteCleanHTML` | `boolean` | `true` | Sanitise HTML on paste. |
|
|
723
|
-
| `
|
|
724
|
-
| `
|
|
725
|
-
| `
|
|
726
|
-
| `
|
|
727
|
-
| `
|
|
728
|
-
| `
|
|
729
|
-
| `
|
|
730
|
-
| `
|
|
731
|
-
| `
|
|
732
|
-
| `stickyToolbar` | `boolean` | `false` |
|
|
733
|
-
| `stickyToolbarOffset` | `number` | `0` | Top offset in
|
|
333
|
+
| `pasteStripAttributes` | `boolean` | `false` | Strip `class`, `style`, and `data-*` attributes from pasted HTML. |
|
|
334
|
+
| `markdownPaste` | `boolean` | `true` | Convert pasted Markdown shortcuts to HTML as you type. |
|
|
335
|
+
| `allowImageUpload` | `boolean` | `true` | Allow drag/paste/file upload in the image dialog. |
|
|
336
|
+
| `maxImageSize` | `number` | `5` | Maximum image file size in megabytes. |
|
|
337
|
+
| `tabSize` | `number` | `4` | Number of spaces inserted when Tab is pressed. |
|
|
338
|
+
| `historyLimit` | `number` | `100` | Maximum undo steps to retain. |
|
|
339
|
+
| `defaultFontFamily` | `string` | `'Arial'` | Font shown by default in the font-family dropdown. |
|
|
340
|
+
| `defaultFontSize` | `string` | `'14px'` | Default font size applied to new content. |
|
|
341
|
+
| `fontFamilies` | `string[]` | 10 fonts | Font families available in the font-family dropdown. |
|
|
342
|
+
| `stickyToolbar` | `boolean` | `false` | Pin the toolbar to the viewport top when the page is scrolled. |
|
|
343
|
+
| `stickyToolbarOffset` | `number` | `0` | Top offset in pixels for the sticky toolbar (e.g. height of a fixed nav bar). |
|
|
734
344
|
| `theme` | `string` | `'light'` | Colour theme: `'light'` or `'dark'`. |
|
|
735
|
-
| `
|
|
736
|
-
| `
|
|
737
|
-
| `
|
|
345
|
+
| `readOnly` | `boolean` | `false` | Start the editor in non-editable (read-only) mode with toolbar hidden. |
|
|
346
|
+
| `spellcheck` | `boolean` | `true` | Enable browser spellcheck in the editable area. |
|
|
347
|
+
| `direction` | `string` | `'ltr'` | Text direction: `'ltr'` or `'rtl'`. |
|
|
348
|
+
| `autoSave` | `boolean` | `false` | Persist content to `localStorage` on every change. |
|
|
349
|
+
| `autoSaveKey` | `string` | `'autumnnote-autosave'` | `localStorage` key used when `autoSave` is enabled. |
|
|
350
|
+
| `maxChars` | `number` | `0` | Maximum character count. `0` = unlimited. Shows warning in statusbar. |
|
|
351
|
+
| `maxWords` | `number` | `0` | Maximum word count. `0` = unlimited. Shows warning in statusbar. |
|
|
352
|
+
| `tableHeaderRow` | `boolean` | `false` | Insert a `<thead>` header row when creating new tables. |
|
|
353
|
+
| `codeHighlight` | `boolean` | `true` | Auto-load Prism.js for syntax highlighting inside `<pre><code>` blocks. |
|
|
354
|
+
| `codeHighlightCDN` | `string` | cdnjs Prism 1.29.0 | Base CDN URL for Prism assets. |
|
|
355
|
+
| `colorSwatches` | `string[]` | `[]` | Custom brand colour swatches prepended to the colour picker palette. |
|
|
356
|
+
| `focusColor` | `string` | `null` | Custom focus ring colour (any valid CSS colour). Overrides the default blue. |
|
|
357
|
+
| `lang` | `string \| object` | `'en'` | UI display language. Built-in codes: `'en'`, `'vi'`, `'ja'`, `'zh'`, `'fr'`, `'de'`, `'es'`, `'ko'`. Pass a partial locale object for custom overrides. |
|
|
358
|
+
| `markdownShortcuts` | `boolean` | `true` | Convert Markdown-style syntax typed in the editor to HTML in real time (block and inline rules). |
|
|
359
|
+
| `bubbleToolbar` | `boolean` | `false` | Show a mini floating toolbar above the text selection for quick formatting. |
|
|
360
|
+
| `bubbleToolbarItems` | `string[]` | `['bold','italic','underline','link','foreColor','removeFormat']` | Buttons shown in the bubble toolbar. Available names: `'bold'`, `'italic'`, `'underline'`, `'strikethrough'`, `'link'`, `'foreColor'`, `'removeFormat'`, `'inlineCode'`. |
|
|
361
|
+
| `autoSaveRestore` | `boolean` | `false` | When `autoSave` is also `true`, show a restore banner on load if a draft exists. |
|
|
362
|
+
| `autoSaveRestoreTimeout` | `number` | `7` | Max draft age in days before it is auto-discarded. `0` = no expiry. |
|
|
363
|
+
| `onAutoSaveRestore` | `Function` | `null` | `(html, context) => void` — called after the user restores a draft. |
|
|
364
|
+
| `mention` | `object` | `null` | @mention configuration object. Set `mention.onSearch` to activate. See [Mentions](#mentions). |
|
|
365
|
+
| `onChange` | `Function` | `null` | `(html: string) => void` — called on every content change. |
|
|
366
|
+
| `onFocus` | `Function` | `null` | `(context) => void` — called when the editor gains focus. |
|
|
367
|
+
| `onBlur` | `Function` | `null` | `(context) => void` — called when the editor loses focus. |
|
|
368
|
+
| `onInit` | `Function` | `null` | `(context) => void` — called once after the editor is initialised. |
|
|
369
|
+
| `onImageUpload` | `Function` | `null` | `(files: FileList) => void` — custom upload handler. Overrides base64 embed. |
|
|
370
|
+
| `onImageError` | `Function` | `null` | `({ file, message }) => void` — called when an image is rejected. |
|
|
371
|
+
| `onPaste` | `Function` | `null` | `({ text, html }) => void` — called after every paste event. |
|
|
372
|
+
| `onSelectionChange` | `Function` | `null` | `(context) => void` — called when cursor or selection changes. |
|
|
373
|
+
| `onDestroy` | `Function` | `null` | `(context) => void` — called just before the editor is destroyed. |
|
|
374
|
+
| `onCharLimitReached` | `Function` | `null` | `(context) => void` — called when `maxChars` is hit. |
|
|
375
|
+
| `onWordLimitReached` | `Function` | `null` | `(context) => void` — called when `maxWords` is hit. |
|
|
738
376
|
|
|
739
377
|
---
|
|
740
378
|
|
|
741
379
|
## Toolbar Customisation
|
|
742
380
|
|
|
743
|
-
The `toolbar` option accepts an array of
|
|
381
|
+
The `toolbar` option accepts an array of **groups**. Each group is an array of button definition objects exported from the package:
|
|
744
382
|
|
|
745
383
|
```js
|
|
746
|
-
import AutumnNote
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
384
|
+
import AutumnNote, {
|
|
385
|
+
boldBtn, italicBtn, underlineBtn, strikeBtn,
|
|
386
|
+
superscriptBtn, subscriptBtn,
|
|
387
|
+
alignLeftBtn, alignCenterBtn, alignRightBtn, alignJustifyBtn,
|
|
388
|
+
ulBtn, olBtn, checklistBtn, indentBtn, outdentBtn,
|
|
389
|
+
undoBtn, redoBtn,
|
|
390
|
+
hrBtn, linkBtn, imageBtn, videoBtn,
|
|
391
|
+
emojiBtn, iconBtn, tableBtn,
|
|
392
|
+
fontFamilyBtn, paragraphStyleBtn, lineHeightBtn,
|
|
393
|
+
foreColorBtn, backColorBtn,
|
|
394
|
+
findBtn, findReplaceBtn,
|
|
395
|
+
codeviewBtn, fullscreenBtn, shortcutsBtn,
|
|
396
|
+
} from 'autumnnote';
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Default toolbar layout
|
|
400
|
+
|
|
401
|
+
```js
|
|
402
|
+
[
|
|
403
|
+
[paragraphStyleBtn, fontFamilyBtn, lineHeightBtn],
|
|
404
|
+
[undoBtn, redoBtn],
|
|
405
|
+
[boldBtn, italicBtn, underlineBtn, strikeBtn],
|
|
406
|
+
[superscriptBtn, subscriptBtn],
|
|
407
|
+
[foreColorBtn, backColorBtn],
|
|
408
|
+
[alignLeftBtn, alignCenterBtn, alignRightBtn, alignJustifyBtn],
|
|
409
|
+
[ulBtn, olBtn, checklistBtn, indentBtn, outdentBtn],
|
|
410
|
+
[hrBtn, linkBtn, imageBtn, videoBtn, tableBtn, emojiBtn, iconBtn],
|
|
411
|
+
[codeviewBtn, fullscreenBtn, shortcutsBtn],
|
|
412
|
+
]
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Custom toolbar example
|
|
752
416
|
|
|
417
|
+
```js
|
|
753
418
|
AutumnNote.create('#editor', {
|
|
754
419
|
toolbar: [
|
|
420
|
+
[undoBtn, redoBtn],
|
|
755
421
|
[boldBtn, italicBtn, underlineBtn],
|
|
756
|
-
[
|
|
757
|
-
[
|
|
422
|
+
[ulBtn, olBtn, checklistBtn],
|
|
423
|
+
[linkBtn, imageBtn],
|
|
424
|
+
[findBtn, findReplaceBtn],
|
|
758
425
|
],
|
|
759
426
|
});
|
|
760
427
|
```
|
|
761
428
|
|
|
762
|
-
|
|
429
|
+
### Hiding the toolbar
|
|
430
|
+
|
|
431
|
+
Pass an empty array for a toolbar-less editor (keyboard shortcuts still work):
|
|
432
|
+
|
|
433
|
+
```js
|
|
434
|
+
AutumnNote.create('#editor', { toolbar: [] });
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### All available buttons
|
|
763
438
|
|
|
764
439
|
| Export | Tooltip |
|
|
765
440
|
|---|---|
|
|
@@ -771,16 +446,84 @@ AutumnNote.create('#editor', {
|
|
|
771
446
|
| `superscriptBtn` / `subscriptBtn` | Super / Subscript |
|
|
772
447
|
| `foreColorBtn` / `backColorBtn` | Text colour / Highlight colour |
|
|
773
448
|
| `alignLeftBtn` / `alignCenterBtn` / `alignRightBtn` / `alignJustifyBtn` | Alignment |
|
|
774
|
-
| `ulBtn` / `olBtn` / `
|
|
449
|
+
| `ulBtn` / `olBtn` / `checklistBtn` | Lists |
|
|
450
|
+
| `indentBtn` / `outdentBtn` | Indentation |
|
|
775
451
|
| `hrBtn` | Horizontal Rule |
|
|
776
|
-
| `linkBtn` | Insert Link |
|
|
452
|
+
| `linkBtn` | Insert / Edit Link |
|
|
777
453
|
| `imageBtn` | Insert Image |
|
|
778
454
|
| `videoBtn` | Insert Video |
|
|
779
455
|
| `tableBtn` | Insert Table (grid picker) |
|
|
780
456
|
| `emojiBtn` | Insert Emoji |
|
|
781
457
|
| `iconBtn` | Insert FA Icon |
|
|
458
|
+
| `findBtn` | Find (Ctrl+F) |
|
|
459
|
+
| `findReplaceBtn` | Find & Replace (Ctrl+H) |
|
|
782
460
|
| `codeviewBtn` | HTML Code View |
|
|
783
461
|
| `fullscreenBtn` | Fullscreen |
|
|
462
|
+
| `shortcutsBtn` | Keyboard Shortcuts dialog |
|
|
463
|
+
|
|
464
|
+
### Setting global defaults
|
|
465
|
+
|
|
466
|
+
```js
|
|
467
|
+
Object.assign(AutumnNote.defaults, {
|
|
468
|
+
height: 400,
|
|
469
|
+
theme: 'dark',
|
|
470
|
+
fontFamilies: ['Inter', 'Roboto', 'Georgia', 'Courier New'],
|
|
471
|
+
colorSwatches: ['#e74c3c', '#f39c12', '#2ecc71', '#3498db'],
|
|
472
|
+
});
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Keyboard Shortcuts
|
|
478
|
+
|
|
479
|
+
| Keys | Action |
|
|
480
|
+
|---|---|
|
|
481
|
+
| `Ctrl + Z` | Undo |
|
|
482
|
+
| `Ctrl + Shift + Z` / `Ctrl + Y` | Redo |
|
|
483
|
+
| `Ctrl + B` | Bold |
|
|
484
|
+
| `Ctrl + I` | Italic |
|
|
485
|
+
| `Ctrl + U` | Underline |
|
|
486
|
+
| `Ctrl + F` | Open Find dialog |
|
|
487
|
+
| `Ctrl + H` | Open Find & Replace dialog |
|
|
488
|
+
| `Shift + Enter` | Insert line break |
|
|
489
|
+
| `Tab` | Insert spaces / indent list item |
|
|
490
|
+
| `Shift + Tab` | Outdent list item |
|
|
491
|
+
| `Shift + ?` | Open Keyboard Shortcuts dialog |
|
|
492
|
+
|
|
493
|
+
> The number of spaces inserted by `Tab` is controlled by the `tabSize` option.
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## Mentions
|
|
498
|
+
|
|
499
|
+
The `mention` option object activates `@mention` autocomplete. Only `onSearch` is required; all other fields are optional.
|
|
500
|
+
|
|
501
|
+
| Field | Type | Default | Description |
|
|
502
|
+
|---|---|---|---|
|
|
503
|
+
| `onSearch` | `Function` | — | `(query, callback) => void` — called when the user types after the trigger character. Pass an array of `{ id, label, avatar? }` to the callback. |
|
|
504
|
+
| `onInsert` | `Function` | `null` | `(item) => string \| null` — return custom HTML for the inserted mention chip. Return `null` to use the built-in chip. |
|
|
505
|
+
| `trigger` | `string` | `'@'` | Character that opens the dropdown. |
|
|
506
|
+
| `minChars` | `number` | `0` | Minimum characters after the trigger before `onSearch` is called. `0` = open immediately. |
|
|
507
|
+
| `maxResults` | `number` | `8` | Maximum items shown in the dropdown. |
|
|
508
|
+
| `debounce` | `number` | `200` | Debounce delay in milliseconds for `onSearch` calls. |
|
|
509
|
+
| `mentionClass` | `string` | `'an-mention'` | CSS class applied to the inserted mention chip. |
|
|
510
|
+
| `allowSpaces` | `boolean` | `false` | Allow spaces in the query string before the dropdown closes. |
|
|
511
|
+
|
|
512
|
+
### Example
|
|
513
|
+
|
|
514
|
+
```js
|
|
515
|
+
AutumnNote.create('#editor', {
|
|
516
|
+
mention: {
|
|
517
|
+
trigger: '@',
|
|
518
|
+
minChars: 1,
|
|
519
|
+
onSearch(query, callback) {
|
|
520
|
+
fetch(`/api/users?q=${encodeURIComponent(query)}`)
|
|
521
|
+
.then(r => r.json())
|
|
522
|
+
.then(users => callback(users)); // [{ id, label, avatar? }]
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
});
|
|
526
|
+
```
|
|
784
527
|
|
|
785
528
|
---
|
|
786
529
|
|
|
@@ -790,89 +533,119 @@ AutumnNote.create('#editor', {
|
|
|
790
533
|
src/
|
|
791
534
|
├── js/
|
|
792
535
|
│ ├── core/
|
|
793
|
-
│ │ ├── dom.js DOM utilities
|
|
794
|
-
│ │ ├── range.js Selection
|
|
795
|
-
│ │ ├── func.js General
|
|
536
|
+
│ │ ├── dom.js DOM utilities (createElement, on, closest, ...)
|
|
537
|
+
│ │ ├── range.js Selection and Range API helpers
|
|
538
|
+
│ │ ├── func.js General helpers (mergeDeep, debounce, ...)
|
|
796
539
|
│ │ ├── key.js Keyboard key constants
|
|
797
540
|
│ │ ├── lists.js Array helpers
|
|
798
|
-
│ │ ├── env.js Browser
|
|
799
|
-
│ │ ├── markdown.js Markdown
|
|
541
|
+
│ │ ├── env.js Browser/platform detection
|
|
542
|
+
│ │ ├── markdown.js Lightweight Markdown to HTML converter
|
|
800
543
|
│ │ └── sanitise.js DOM-based HTML and URL sanitiser
|
|
801
544
|
│ ├── editing/
|
|
802
|
-
│ │ ├── History.js Undo
|
|
545
|
+
│ │ ├── History.js Undo/redo stack (configurable depth)
|
|
803
546
|
│ │ ├── Style.js execCommand style wrappers
|
|
804
|
-
│ │ ├── Table.js Table creation and manipulation
|
|
805
|
-
│ │ └── Typing.js Tab
|
|
547
|
+
│ │ ├── Table.js Table creation and cell manipulation
|
|
548
|
+
│ │ └── Typing.js Tab/Enter/ArrowKey behaviour and FA icon caret handling
|
|
806
549
|
│ ├── module/
|
|
807
|
-
│ │ ├── Editor.js Core editing commands
|
|
808
|
-
│ │ ├── Toolbar.js Toolbar UI
|
|
809
|
-
│ │ ├── Buttons.js Button and
|
|
810
|
-
│ │ ├── Statusbar.js
|
|
811
|
-
│ │ ├── Clipboard.js Paste sanitisation
|
|
812
|
-
│ │ ├── ContextMenu.js Right-click context menu
|
|
813
|
-
│ │ ├── Placeholder.js
|
|
814
|
-
│ │ ├── Codeview.js HTML source view
|
|
550
|
+
│ │ ├── Editor.js Core editing commands, getHTML/setHTML, sanitiser
|
|
551
|
+
│ │ ├── Toolbar.js Toolbar UI, button rendering (SVG + FA), dropdowns, colour picker
|
|
552
|
+
│ │ ├── Buttons.js Button/dropdown/colorpicker definitions and defaultToolbar
|
|
553
|
+
│ │ ├── Statusbar.js Word and character count, drag-to-resize, limit warnings
|
|
554
|
+
│ │ ├── Clipboard.js Paste sanitisation (HTML clean, plain-text, Markdown modes)
|
|
555
|
+
│ │ ├── ContextMenu.js Right-click context menu with colour palette
|
|
556
|
+
│ │ ├── Placeholder.js CSS-based placeholder
|
|
557
|
+
│ │ ├── Codeview.js HTML source view toggle
|
|
815
558
|
│ │ ├── Fullscreen.js Fullscreen mode
|
|
816
|
-
│ │ ├──
|
|
817
|
-
│ │ ├──
|
|
818
|
-
│ │ ├──
|
|
819
|
-
│ │ ├──
|
|
820
|
-
│ │ ├──
|
|
821
|
-
│ │ ├──
|
|
822
|
-
│ │ ├──
|
|
823
|
-
│ │ ├──
|
|
824
|
-
│ │ ├──
|
|
825
|
-
│ │ ├──
|
|
826
|
-
│ │ ├──
|
|
827
|
-
│ │ ├──
|
|
828
|
-
│ │
|
|
829
|
-
│ ├──
|
|
830
|
-
│ ├──
|
|
559
|
+
│ │ ├── FindReplace.js Find and Replace dialog (Ctrl+F / Ctrl+H)
|
|
560
|
+
│ │ ├── LinkDialog.js Link insert/edit dialog
|
|
561
|
+
│ │ ├── LinkTooltip.js Floating toolbar for links (open/edit/unlink)
|
|
562
|
+
│ │ ├── ImageDialog.js Image insert dialog (URL + file upload with MIME filtering)
|
|
563
|
+
│ │ ├── ImageTooltip.js Floating toolbar for images (edit/crop/delete)
|
|
564
|
+
│ │ ├── ImageResizer.js rAF-based drag handle to resize images
|
|
565
|
+
│ │ ├── ImageCropOverlay.js Inline crop tool (corner/edge handles, canvas export)
|
|
566
|
+
│ │ ├── VideoDialog.js Video embed dialog (YouTube, Vimeo, direct file)
|
|
567
|
+
│ │ ├── VideoTooltip.js Floating toolbar for video embeds (edit/delete)
|
|
568
|
+
│ │ ├── VideoResizer.js rAF-based drag handle to resize video embeds
|
|
569
|
+
│ │ ├── TableTooltip.js Floating toolbar for tables (row/col/merge/unmerge/select mode)
|
|
570
|
+
│ │ ├── CodeTooltip.js Floating toolbar for code blocks (copy/delete)
|
|
571
|
+
│ │ ├── EmojiDialog.js Unicode emoji picker (~380 emoji, 7 categories)
|
|
572
|
+
│ │ ├── IconDialog.js FontAwesome icon picker (FA 6 Free Solid, 8 categories)
|
|
573
|
+
│ │ ├── ShortcutsDialog.js Keyboard shortcuts reference dialog (Shift+?)
|
|
574
|
+
│ │ ├── BubbleToolbar.js Mini floating toolbar above text selection
|
|
575
|
+
│ │ ├── MarkdownShortcuts.js Inline Markdown-to-HTML input rules
|
|
576
|
+
│ │ ├── AutoSaveRestore.js Draft restore banner for localStorage drafts
|
|
577
|
+
│ │ └── Mention.js @mention autocomplete with floating dropdown
|
|
578
|
+
│ ├── Context.js Editor instance hub: module registry and event bus
|
|
579
|
+
│ ├── settings.js Default options (AsnOptions)
|
|
831
580
|
│ ├── renderer.js DOM layout builder
|
|
832
|
-
│ └── index.js Public entry point
|
|
581
|
+
│ └── index.js Public entry point + AutumnNote factory
|
|
833
582
|
└── styles/
|
|
834
|
-
├── _variables.scss SCSS design tokens
|
|
835
|
-
└──
|
|
583
|
+
├── _variables.scss SCSS design tokens (colours, spacing, radii, transitions)
|
|
584
|
+
└── autumnnote.scss Main stylesheet
|
|
836
585
|
```
|
|
837
586
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
## Development
|
|
587
|
+
### Development commands
|
|
841
588
|
|
|
842
589
|
```bash
|
|
843
|
-
#
|
|
844
|
-
npm
|
|
845
|
-
|
|
846
|
-
#
|
|
847
|
-
npm run
|
|
590
|
+
npm install # install dependencies
|
|
591
|
+
npm run dev # start Vite dev server with HMR
|
|
592
|
+
npm run build # build ES + UMD + CSS to dist/
|
|
593
|
+
npm test # run Vitest test suite once
|
|
594
|
+
npm run test:watch # run tests in watch mode
|
|
595
|
+
npm run lint # ESLint
|
|
596
|
+
npm run typecheck # TypeScript type check (tsconfig.json)
|
|
597
|
+
```
|
|
848
598
|
|
|
849
|
-
|
|
850
|
-
npm run build
|
|
599
|
+
Build output in `dist/`:
|
|
851
600
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
601
|
+
| File | Format | Use |
|
|
602
|
+
|---|---|---|
|
|
603
|
+
| `autumnnote.es.js` | ES Module | `import` in bundlers (tree-shakeable) |
|
|
604
|
+
| `autumnnote.umd.js` | UMD | `<script>` tag / CommonJS |
|
|
605
|
+
| `autumnnote.css` | CSS | Styles for both builds |
|
|
855
606
|
|
|
856
607
|
---
|
|
857
608
|
|
|
858
|
-
## Comparison
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
|
863
|
-
|
|
864
|
-
|
|
|
865
|
-
|
|
|
866
|
-
|
|
|
867
|
-
|
|
|
868
|
-
|
|
|
869
|
-
|
|
|
870
|
-
|
|
|
871
|
-
|
|
|
872
|
-
|
|
|
609
|
+
## Comparison
|
|
610
|
+
|
|
611
|
+
The table below compares AutumnNote against editors commonly used in this category. Specific library names are omitted to avoid bias.
|
|
612
|
+
|
|
613
|
+
| Feature | Editor A | Editor B | Editor C | **AutumnNote** |
|
|
614
|
+
|---|---|---|---|---|
|
|
615
|
+
| jQuery dependency | Required | Required | Optional | **None** |
|
|
616
|
+
| Runtime dependencies | Several | Several | 1–2 | **Zero** |
|
|
617
|
+
| JavaScript standard | ES5 / legacy | ES6 mix | ES6 | **ES2022** |
|
|
618
|
+
| Module format | IIFE / AMD | IIFE | CommonJS + IIFE | **ES Module + UMD** |
|
|
619
|
+
| Build tool | Grunt | Gulp | Rollup | **Vite** |
|
|
620
|
+
| TypeScript definitions | External / partial | Partial | Yes | **Yes (bundled)** |
|
|
621
|
+
| HTML sanitisation | Basic | Whitelist-only | Moderate | **DOM-based (XSS-safe)** |
|
|
622
|
+
| Iframe support in setHTML | No | No | Restricted | **Yes (host-trusted)** |
|
|
623
|
+
| Dark theme | No | No | Yes | **Yes (built-in)** |
|
|
624
|
+
| RTL text direction | No | Partial | No | **Yes** |
|
|
625
|
+
| Built-in i18n locales | No | No | Partial | **Yes (8 languages)** |
|
|
626
|
+
| Custom locale object | No | No | No | **Yes** |
|
|
627
|
+
| Checklist (todo list) | No | No | No | **Yes** |
|
|
628
|
+
| Find and Replace | No | No | No | **Yes (Ctrl+F / Ctrl+H)** |
|
|
629
|
+
| Emoji picker | No | No | No | **Yes (~380 emoji)** |
|
|
630
|
+
| FA icon picker | No | No | No | **Yes (FA 6, searchable)** |
|
|
631
|
+
| Video embeds | No | No | No | **Yes (YouTube, Vimeo, direct)** |
|
|
632
|
+
| Image crop tool | No | No | No | **Yes (inline)** |
|
|
633
|
+
| Image / video resize | No | No | No | **Yes (drag handles)** |
|
|
634
|
+
| Inline tooltips | No | No | Partial | **Yes (link, image, video, table, code)** |
|
|
635
|
+
| Table cell merge/unmerge | No | No | Yes | **Yes** |
|
|
636
|
+
| Table cell selection mode | No | No | No | **Yes** |
|
|
637
|
+
| Context menu | No | No | No | **Yes (with colour palette)** |
|
|
638
|
+
| Sticky toolbar | No | No | No | **Yes** |
|
|
639
|
+
| Auto-save to localStorage | No | No | No | **Yes** |
|
|
640
|
+
| Character / word limits | No | No | No | **Yes** |
|
|
641
|
+
| Custom focus ring colour | No | No | No | **Yes** |
|
|
642
|
+
| Read-only mode | No | Partial | Yes | **Yes** |
|
|
643
|
+
| Custom colour swatches | No | No | No | **Yes** |
|
|
644
|
+
| Code view (HTML source) | No | Yes | Yes | **Yes (sanitised)** |
|
|
645
|
+
| Syntax highlighting | No | No | Partial | **Yes (Prism.js via CDN)** |
|
|
873
646
|
|
|
874
647
|
---
|
|
875
648
|
|
|
876
649
|
## License
|
|
877
650
|
|
|
878
|
-
MIT
|
|
651
|
+
[MIT](LICENSE)
|