autumnnote 1.0.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 +21 -0
- package/README.md +874 -0
- package/dist/autumnnote.css +1 -0
- package/dist/autumnnote.es.js +5888 -0
- package/dist/autumnnote.es.js.map +1 -0
- package/dist/autumnnote.umd.js +74 -0
- package/dist/autumnnote.umd.js.map +1 -0
- package/package.json +55 -0
- package/src/js/Context.js +497 -0
- package/src/js/core/dom.js +315 -0
- package/src/js/core/env.js +25 -0
- package/src/js/core/func.js +153 -0
- package/src/js/core/key.js +66 -0
- package/src/js/core/lists.js +121 -0
- package/src/js/core/markdown.js +294 -0
- package/src/js/core/range.js +194 -0
- package/src/js/core/sanitise.js +78 -0
- package/src/js/editing/History.js +205 -0
- package/src/js/editing/Style.js +329 -0
- package/src/js/editing/Table.js +59 -0
- package/src/js/editing/Typing.js +142 -0
- package/src/js/index.js +126 -0
- package/src/js/module/Buttons.js +300 -0
- package/src/js/module/Clipboard.js +460 -0
- package/src/js/module/CodeTooltip.js +428 -0
- package/src/js/module/Codeview.js +122 -0
- package/src/js/module/ContextMenu.js +470 -0
- package/src/js/module/Editor.js +528 -0
- package/src/js/module/EmojiDialog.js +726 -0
- package/src/js/module/FindReplace.js +440 -0
- package/src/js/module/Fullscreen.js +80 -0
- package/src/js/module/IconDialog.js +620 -0
- package/src/js/module/ImageDialog.js +208 -0
- package/src/js/module/ImageResizer.js +216 -0
- package/src/js/module/ImageTooltip.js +286 -0
- package/src/js/module/LinkDialog.js +204 -0
- package/src/js/module/LinkTooltip.js +242 -0
- package/src/js/module/Placeholder.js +44 -0
- package/src/js/module/ShortcutsDialog.js +141 -0
- package/src/js/module/Statusbar.js +238 -0
- package/src/js/module/TableTooltip.js +568 -0
- package/src/js/module/Toolbar.js +562 -0
- package/src/js/module/VideoDialog.js +263 -0
- package/src/js/module/VideoResizer.js +227 -0
- package/src/js/module/VideoTooltip.js +252 -0
- package/src/js/renderer.js +107 -0
- package/src/js/settings.js +134 -0
- package/src/styles/_variables.scss +48 -0
- package/src/styles/autumnnote.scss +1740 -0
- package/types/index.d.ts +324 -0
package/README.md
ADDED
|
@@ -0,0 +1,874 @@
|
|
|
1
|
+
# AutumnNote
|
|
2
|
+
|
|
3
|
+
[](#)
|
|
4
|
+
[](https://github.com/cmm-cmm/Autumn-Note/actions/workflows/pages.yml)
|
|
5
|
+
[](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
|
6
|
+
[](https://vitejs.dev/)
|
|
7
|
+
[](https://vitest.dev/)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](#)
|
|
10
|
+
[](https://fontawesome.com/)
|
|
11
|
+
|
|
12
|
+
A modern, lightweight WYSIWYG rich-text editor with vanilla JavaScript (ES2022+), no jQuery dependency.
|
|
13
|
+
|
|
14
|
+
> ✍️ *Write rich text. No dependencies. No drama.*
|
|
15
|
+
|
|
16
|
+
🔗 **[Live Demo](https://cmm-cmm.github.io/Autumn-Note/)**
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
### Editing
|
|
25
|
+
- **Text formatting** — bold, italic, underline, strikethrough, superscript, subscript
|
|
26
|
+
- **Paragraph styles** — Normal, H1–H6, Blockquote, Code block
|
|
27
|
+
- **Font family** — customisable dropdown (10 families by default)
|
|
28
|
+
- **Line height** — dropdown from 1.0 to 3.0
|
|
29
|
+
- **Text & highlight colour** — native colour picker with last-used colour memory
|
|
30
|
+
- **Alignment** — left, center, right, justify
|
|
31
|
+
- **Lists** — unordered and ordered, with indent / outdent; Tab/Shift+Tab in list context
|
|
32
|
+
- **Undo / redo** — built-in history stack (100 levels, `Ctrl+Z` / `Ctrl+Y`)
|
|
33
|
+
- **Tab key** — configurable spaces-per-tab; smart list indentation inside `<li>`
|
|
34
|
+
|
|
35
|
+
### Insert
|
|
36
|
+
- **Horizontal rule** — inserts an `<hr>` at the current caret position
|
|
37
|
+
- **Link dialog** — URL, display text (auto-filled from selection), "Open in new tab" checkbox; edits existing links when caret is inside an `<a>`
|
|
38
|
+
- **Image dialog** — insert by URL with alt text, or file upload (base64 embed); enforces `maxImageSize`; supports custom `onImageUpload` handler for server-side upload
|
|
39
|
+
- **Video dialog** — paste a YouTube watch/short URL, Vimeo URL, or direct `.mp4 / .webm / .ogg` URL; configurable width; renders as responsive `<iframe>` or `<video>`
|
|
40
|
+
- **Table** — interactive grid picker (up to 10×10); floating tooltip on table click for full row/column/cell management (see [Table tooltip](#table-tooltip))
|
|
41
|
+
- **Emoji picker** — ~380 Unicode emoji across 7 categories (Smileys, People, Animals, Food, Travel, Objects, Symbols); keyword search; click to insert instantly as a plain text character (UTF-8 / utf8mb4 safe)
|
|
42
|
+
- **FA Icon picker** — FontAwesome 6 Free Solid icons across 8 categories (Popular, Interface, Navigation, Media, Communication, Files, People, Objects); keyword search; configurable style (Solid / Regular / Light), size, and colour; inserts as `<i>` element; auto-injects FA CDN if not detected on the page
|
|
43
|
+
|
|
44
|
+
### Inline tooltips
|
|
45
|
+
Floating toolbars appear automatically when the user clicks on an editable element:
|
|
46
|
+
|
|
47
|
+
| Element | Actions |
|
|
48
|
+
|---|---|
|
|
49
|
+
| **Link** | Open in new tab, Edit (reopens dialog), Unlink |
|
|
50
|
+
| **Image** | Edit alt/URL (reopens dialog), Delete |
|
|
51
|
+
| **Video** | Edit (reopens dialog), Delete |
|
|
52
|
+
| **Table cell** | Row above/below, Delete row, Column left/right, Delete column, Merge cells, Column width, Row height, Delete table |
|
|
53
|
+
| **Code block** (`<pre>`) | Copy code, Delete block |
|
|
54
|
+
|
|
55
|
+
### Context menu
|
|
56
|
+
Right-click inside the editor opens a context menu with: **Undo**, **Redo**, **Cut**, **Copy**, **Paste**, **Bold**, **Italic**, **Underline**, **Copy Format**, **Paste Format**, **Remove Format**.
|
|
57
|
+
|
|
58
|
+
### UI
|
|
59
|
+
- **Toolbar** — fully configurable button groups; renders with FontAwesome icons when detected, falls back to inline SVG icons
|
|
60
|
+
- **Image resizer** — drag handle on selected image to resize proportionally
|
|
61
|
+
- **Video resizer** — drag handle on selected video embed to resize
|
|
62
|
+
- **Statusbar** — live word and character count; drag handle to resize editor height
|
|
63
|
+
- **Code view** — toggle raw HTML; sanitised before applying back to the editor
|
|
64
|
+
- **Fullscreen** — expands the editor to fill the viewport
|
|
65
|
+
- **Placeholder** — CSS `::before` pseudo-element, zero DOM node cost
|
|
66
|
+
|
|
67
|
+
### Integration
|
|
68
|
+
- **No jQuery** — pure vanilla ES2022, zero runtime dependencies
|
|
69
|
+
- **Bootstrap friendly** — optional Bootstrap 4/5 styling for toolbar buttons (`useBootstrap: true`)
|
|
70
|
+
- **FontAwesome ready** — auto-detects FA on the page; falls back to built-in SVG icons
|
|
71
|
+
- **Plugin-ready** — register custom modules via `AutumnNote.defaults`
|
|
72
|
+
- **Tree-shakeable** — ES module build; all core utilities are individually exported
|
|
73
|
+
|
|
74
|
+
### Security
|
|
75
|
+
- All HTML (pasted content, `setHTML()`, or code-view output) is passed through a DOM-based sanitiser that strips `<script>`, `<iframe>`, `<object>`, `<embed>`, and all `on*` event handler attributes
|
|
76
|
+
- `javascript:` and `data:` URLs are rejected in links and images
|
|
77
|
+
- Clipboard paste sanitises rich content to remove XSS vectors before inserting
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
### npm / pnpm / yarn
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install AutumnNote
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### CDN
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<link rel="stylesheet" href="dist/AutumnNote.css" />
|
|
93
|
+
<script src="dist/AutumnNote.umd.js"></script>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> **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:
|
|
97
|
+
>
|
|
98
|
+
> ```html
|
|
99
|
+
> <!-- FontAwesome 6 Free (recommended) -->
|
|
100
|
+
> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
|
|
101
|
+
> ```
|
|
102
|
+
>
|
|
103
|
+
> 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.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Quick Start
|
|
108
|
+
|
|
109
|
+
### ES Module
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import AutumnNote from 'AutumnNote';
|
|
113
|
+
|
|
114
|
+
const editor = AutumnNote.create('#my-editor', {
|
|
115
|
+
placeholder: 'Start typing…',
|
|
116
|
+
height: 300,
|
|
117
|
+
onChange(html) {
|
|
118
|
+
console.log(html);
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Script tag (UMD)
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<div id="my-editor"><p>Hello!</p></div>
|
|
127
|
+
<script src="dist/AutumnNote.umd.js"></script>
|
|
128
|
+
<script>
|
|
129
|
+
const editor = AutumnNote.create('#my-editor');
|
|
130
|
+
</script>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### With Bootstrap 5
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
const editor = AutumnNote.create('#my-editor', {
|
|
137
|
+
useBootstrap: true,
|
|
138
|
+
bootstrapVersion: 5,
|
|
139
|
+
toolbarButtonClass: 'btn btn-sm btn-light',
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### With FontAwesome 6
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
const editor = AutumnNote.create('#my-editor', {
|
|
147
|
+
useFontAwesome: true,
|
|
148
|
+
fontAwesomeClass: 'fa-solid', // FA 6 prefix
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Usage
|
|
155
|
+
|
|
156
|
+
### Read content on demand
|
|
157
|
+
|
|
158
|
+
The most common pattern — attach a button that reads back the current HTML:
|
|
159
|
+
|
|
160
|
+
```html
|
|
161
|
+
<link rel="stylesheet" href="dist/autumnnote.css" />
|
|
162
|
+
|
|
163
|
+
<div id="editor"><p>Hello, <strong>AutumnNote</strong>!</p></div>
|
|
164
|
+
|
|
165
|
+
<button onclick="getHTML()">Get HTML</button>
|
|
166
|
+
<pre id="output"></pre>
|
|
167
|
+
|
|
168
|
+
<script src="dist/autumnnote.umd.js"></script>
|
|
169
|
+
<script>
|
|
170
|
+
const editor = AutumnNote.create('#editor', { height: 300 });
|
|
171
|
+
|
|
172
|
+
function getHTML() {
|
|
173
|
+
document.getElementById('output').innerText = editor.getHTML();
|
|
174
|
+
}
|
|
175
|
+
</script>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### React to every change
|
|
179
|
+
|
|
180
|
+
Use `onChange` (or `editor.on('change', fn)`) to update a live preview automatically:
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<div id="editor"><p>Start typing…</p></div>
|
|
184
|
+
<pre id="preview"></pre>
|
|
185
|
+
|
|
186
|
+
<script src="dist/autumnnote.umd.js"></script>
|
|
187
|
+
<script>
|
|
188
|
+
const editor = AutumnNote.create('#editor', {
|
|
189
|
+
height: 300,
|
|
190
|
+
onChange(html) {
|
|
191
|
+
document.getElementById('preview').innerText = html;
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
</script>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Set and clear content programmatically
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
editor.setHTML('<p>New <em>content</em></p>'); // set
|
|
201
|
+
editor.clear(); // clear to empty <p>
|
|
202
|
+
console.log(editor.getText()); // plain text, no markup
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## API
|
|
208
|
+
|
|
209
|
+
### Factory
|
|
210
|
+
|
|
211
|
+
| Method | Description |
|
|
212
|
+
|---|---|
|
|
213
|
+
| `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. |
|
|
214
|
+
| `AutumnNote.destroy(selector)` | Destroys editor(s) matching the selector and restores the original element. |
|
|
215
|
+
| `AutumnNote.getInstance(selector)` | Returns the `Context` for a given element, or `null` if not initialised. |
|
|
216
|
+
| `AutumnNote.defaults` | Global default options object. Mutate before calling `create()` to apply project-wide settings. |
|
|
217
|
+
|
|
218
|
+
### Context (editor instance)
|
|
219
|
+
|
|
220
|
+
| Method | Description |
|
|
221
|
+
|---|---|
|
|
222
|
+
| `editor.getHTML()` | Returns the current HTML content. Zero-width spaces inserted by the icon picker are stripped automatically. |
|
|
223
|
+
| `editor.setHTML(html)` | Sets HTML content. Input is sanitised before rendering. |
|
|
224
|
+
| `editor.getText()` | Returns plain text with no markup. |
|
|
225
|
+
| `editor.clear()` | Clears all content, resets to an empty `<p>`. |
|
|
226
|
+
| `editor.setDisabled(bool)` | Disables (`true`) or re-enables (`false`) the editor and toolbar. |
|
|
227
|
+
| `editor.destroy()` | Removes the editor, disposes all modules, and restores the original element. |
|
|
228
|
+
| `editor.on(event, fn)` | Subscribes to an editor event. Returns an unsubscribe function — call it to remove the listener. |
|
|
229
|
+
| `editor.invoke('module.method', ...args)` | Calls any registered module method by dot-separated name. Returns the method's return value. |
|
|
230
|
+
|
|
231
|
+
### Events
|
|
232
|
+
|
|
233
|
+
| Name | Payload | Description |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| `change` | `html: string` | Fired after every content mutation. Debounced internally. |
|
|
236
|
+
| `focus` | — | Editor's editable area gained focus. |
|
|
237
|
+
| `blur` | — | Editor's editable area lost focus. |
|
|
238
|
+
|
|
239
|
+
#### Subscribing to events
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
const editor = AutumnNote.create('#editor');
|
|
243
|
+
|
|
244
|
+
// Subscribe
|
|
245
|
+
const unsub = editor.on('change', (html) => {
|
|
246
|
+
document.getElementById('output').innerHTML = html;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Unsubscribe later
|
|
250
|
+
unsub();
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### `invoke()` examples
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
// Programmatically open a dialog
|
|
257
|
+
editor.invoke('linkDialog.show');
|
|
258
|
+
editor.invoke('imageDialog.show');
|
|
259
|
+
editor.invoke('emojiDialog.show');
|
|
260
|
+
editor.invoke('iconDialog.show');
|
|
261
|
+
|
|
262
|
+
// Undo / redo
|
|
263
|
+
editor.invoke('editor.undo');
|
|
264
|
+
editor.invoke('editor.redo');
|
|
265
|
+
|
|
266
|
+
// Toggle views
|
|
267
|
+
editor.invoke('codeview.toggle');
|
|
268
|
+
editor.invoke('fullscreen.toggle');
|
|
269
|
+
|
|
270
|
+
// Query state
|
|
271
|
+
const isCodeview = editor.invoke('codeview.isActive'); // boolean
|
|
272
|
+
const isFullscreen = editor.invoke('fullscreen.isActive'); // boolean
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Options
|
|
278
|
+
|
|
279
|
+
| Option | Type | Default | Description |
|
|
280
|
+
|---|---|---|---|
|
|
281
|
+
| `placeholder` | `string` | `''` | Placeholder text shown when the editor is empty. |
|
|
282
|
+
| `height` | `number` | `200` | Initial / minimum editor height in px. |
|
|
283
|
+
| `minHeight` | `number` | `100` | Hard minimum height in px (enforced during resize). |
|
|
284
|
+
| `maxHeight` | `number` | `0` | Maximum height in px. `0` = unlimited. |
|
|
285
|
+
| `focus` | `boolean` | `false` | Auto-focus the editor on initialisation. |
|
|
286
|
+
| `resizeable` | `boolean` | `true` | Show the drag-to-resize handle in the statusbar. |
|
|
287
|
+
| `toolbar` | `Array` | default | Array of button group arrays. See [Toolbar customisation](#toolbar-customisation). |
|
|
288
|
+
| `useBootstrap` | `boolean` | `false` | Apply Bootstrap button classes to toolbar buttons. |
|
|
289
|
+
| `bootstrapVersion` | `number` | `5` | Bootstrap major version to target (`4` or `5`). |
|
|
290
|
+
| `toolbarButtonClass` | `string` | `'btn btn-sm btn-light'` | CSS classes applied to toolbar buttons when `useBootstrap` is `true`. |
|
|
291
|
+
| `useFontAwesome` | `boolean` | `true` | Render toolbar icons via FontAwesome when FA is detected on the page. |
|
|
292
|
+
| `fontAwesomeClass` | `string` | `'fas'` | FontAwesome prefix class. Use `'fas'` for FA 5, `'fa-solid'` for FA 6. |
|
|
293
|
+
| `pasteAsPlainText` | `boolean` | `false` | Force all pasted content to plain text, stripping all formatting. |
|
|
294
|
+
| `pasteCleanHTML` | `boolean` | `true` | Sanitise HTML on paste — strips scripts and dangerous attributes. |
|
|
295
|
+
| `allowImageUpload` | `boolean` | `true` | Show the file upload input in the image dialog. |
|
|
296
|
+
| `maxImageSize` | `number` | `5` | Maximum image upload file size in MB. Files exceeding this are rejected with an alert. |
|
|
297
|
+
| `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)`. |
|
|
298
|
+
| `tabSize` | `number` | `0` | Number of spaces inserted per Tab key press outside of lists. `0` = browser default Tab behaviour. |
|
|
299
|
+
| `defaultFontFamily` | `string` | `'Arial'` | Font family applied as the default style for the editable area. |
|
|
300
|
+
| `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. |
|
|
301
|
+
| `onChange` | `Function` | `null` | `(html: string) => void` — shorthand for `editor.on('change', fn)`. |
|
|
302
|
+
| `onFocus` | `Function` | `null` | `(context: Context) => void` — shorthand for `editor.on('focus', fn)`. |
|
|
303
|
+
| `onBlur` | `Function` | `null` | `(context: Context) => void` — shorthand for `editor.on('blur', fn)`. |
|
|
304
|
+
| `stickyToolbar` | `boolean` | `false` | Stick the toolbar to the viewport top when the page is scrolled. |
|
|
305
|
+
| `stickyToolbarOffset` | `number` | `0` | Top offset in px for the sticky toolbar (e.g. height of a fixed navigation bar). |
|
|
306
|
+
| `theme` | `string` | `'light'` | Colour theme: `'light'` or `'dark'`. |
|
|
307
|
+
| `codeHighlight` | `boolean` | `false` | Auto-load Prism.js for syntax highlighting inside `<pre><code>` blocks. |
|
|
308
|
+
| `codeHighlightCDN` | `string` | cdnjs Prism 1.29.0 | Base CDN URL used when auto-loading Prism assets. |
|
|
309
|
+
| `markdownPaste` | `boolean` | `true` | Convert pasted Markdown text to HTML when no HTML is present in the clipboard. |
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Dialogs
|
|
314
|
+
|
|
315
|
+
### Link dialog
|
|
316
|
+
Fields: **URL** (type=url, required), **Display text** (auto-populated from the current selection), **Open in new tab** checkbox.
|
|
317
|
+
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.
|
|
318
|
+
|
|
319
|
+
### Image dialog
|
|
320
|
+
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.
|
|
321
|
+
|
|
322
|
+
### Video dialog
|
|
323
|
+
Fields: **Video URL** (YouTube / Vimeo / direct file), **Width** (px, default 560). Supported URL formats:
|
|
324
|
+
- `https://www.youtube.com/watch?v=…` → `<iframe>` embed
|
|
325
|
+
- `https://youtu.be/…` → `<iframe>` embed
|
|
326
|
+
- `https://vimeo.com/…` → `<iframe>` embed
|
|
327
|
+
- Direct `.mp4`, `.webm`, `.ogg` URL → `<video controls>` element
|
|
328
|
+
|
|
329
|
+
### Emoji picker
|
|
330
|
+
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.
|
|
331
|
+
|
|
332
|
+
### FA Icon picker
|
|
333
|
+
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:
|
|
334
|
+
- **Style** — Solid, Regular, or Light (Pro)
|
|
335
|
+
- **Size** — Inherit, 0.75em, 1em, 1.25em, 1.5em, 2em, 3em
|
|
336
|
+
- **Colour** — colour picker + "Use colour" toggle
|
|
337
|
+
|
|
338
|
+
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.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Table tooltip
|
|
343
|
+
|
|
344
|
+
Clicking inside any table opens a floating tooltip with the following actions:
|
|
345
|
+
|
|
346
|
+
| Group | Actions |
|
|
347
|
+
|---|---|
|
|
348
|
+
| Rows | Add Row Above, Add Row Below, Delete Row |
|
|
349
|
+
| Columns | Add Column Left, Add Column Right, Delete Column |
|
|
350
|
+
| Cells | Merge Cells |
|
|
351
|
+
| Resize | Column Width (px / %), Row Height (px) |
|
|
352
|
+
| Danger | Delete Table |
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Toolbar Customisation
|
|
357
|
+
|
|
358
|
+
The `toolbar` option accepts an array of button groups. Each group is a sub-array of button definition objects:
|
|
359
|
+
|
|
360
|
+
```js
|
|
361
|
+
import AutumnNote from 'AutumnNote';
|
|
362
|
+
import {
|
|
363
|
+
boldBtn, italicBtn, underlineBtn, strikeBtn,
|
|
364
|
+
foreColorBtn, backColorBtn,
|
|
365
|
+
linkBtn, imageBtn, videoBtn, tableBtn,
|
|
366
|
+
emojiBtn, iconBtn,
|
|
367
|
+
codeviewBtn, fullscreenBtn,
|
|
368
|
+
} from 'AutumnNote/src/js/module/Buttons.js';
|
|
369
|
+
|
|
370
|
+
AutumnNote.create('#editor', {
|
|
371
|
+
toolbar: [
|
|
372
|
+
[boldBtn, italicBtn, underlineBtn, strikeBtn],
|
|
373
|
+
[foreColorBtn, backColorBtn],
|
|
374
|
+
[linkBtn, imageBtn, videoBtn, tableBtn],
|
|
375
|
+
[emojiBtn, iconBtn],
|
|
376
|
+
[codeviewBtn, fullscreenBtn],
|
|
377
|
+
],
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Available buttons**
|
|
382
|
+
|
|
383
|
+
| Export | Type | Tooltip |
|
|
384
|
+
|---|---|---|
|
|
385
|
+
| `paragraphStyleBtn` | dropdown | Paragraph Style |
|
|
386
|
+
| `fontFamilyBtn` | dropdown | Font Family |
|
|
387
|
+
| `lineHeightBtn` | dropdown | Line Height |
|
|
388
|
+
| `undoBtn` / `redoBtn` | button | Undo / Redo |
|
|
389
|
+
| `boldBtn` / `italicBtn` / `underlineBtn` / `strikeBtn` | button | Text style |
|
|
390
|
+
| `superscriptBtn` / `subscriptBtn` | button | Super / Subscript |
|
|
391
|
+
| `foreColorBtn` / `backColorBtn` | color picker | Text colour / Highlight colour |
|
|
392
|
+
| `alignLeftBtn` / `alignCenterBtn` / `alignRightBtn` / `alignJustifyBtn` | button | Alignment |
|
|
393
|
+
| `ulBtn` / `olBtn` / `indentBtn` / `outdentBtn` | button | Lists & indentation |
|
|
394
|
+
| `hrBtn` | button | Horizontal Rule |
|
|
395
|
+
| `linkBtn` | button | Insert Link |
|
|
396
|
+
| `imageBtn` | button | Insert Image |
|
|
397
|
+
| `videoBtn` | button | Insert Video |
|
|
398
|
+
| `tableBtn` | grid picker | Insert Table |
|
|
399
|
+
| `emojiBtn` | button | Insert Emoji |
|
|
400
|
+
| `iconBtn` | button | Insert FA Icon |
|
|
401
|
+
| `codeviewBtn` | button | HTML Code View |
|
|
402
|
+
| `fullscreenBtn` | button | Fullscreen |
|
|
403
|
+
|
|
404
|
+
### Setting global defaults
|
|
405
|
+
|
|
406
|
+
```js
|
|
407
|
+
import AutumnNote from 'AutumnNote';
|
|
408
|
+
|
|
409
|
+
// Apply once before any create() calls
|
|
410
|
+
Object.assign(AutumnNote.defaults, {
|
|
411
|
+
height: 400,
|
|
412
|
+
placeholder: 'Write something…',
|
|
413
|
+
fontAwesomeClass: 'fa-solid',
|
|
414
|
+
fontFamilies: ['Inter', 'Roboto', 'Georgia', 'Courier New'],
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Custom Image Upload
|
|
421
|
+
|
|
422
|
+
```js
|
|
423
|
+
AutumnNote.create('#editor', {
|
|
424
|
+
allowImageUpload: true,
|
|
425
|
+
onImageUpload(files) {
|
|
426
|
+
const formData = new FormData();
|
|
427
|
+
formData.append('file', files[0]);
|
|
428
|
+
|
|
429
|
+
fetch('/api/upload', { method: 'POST', body: formData })
|
|
430
|
+
.then(r => r.json())
|
|
431
|
+
.then(({ url }) => {
|
|
432
|
+
// Insert the returned URL into the editor
|
|
433
|
+
this.invoke('editor.insertImage', url, files[0].name);
|
|
434
|
+
});
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Multiple Instances
|
|
442
|
+
|
|
443
|
+
```js
|
|
444
|
+
const editors = AutumnNote.create('.rich-editor', { height: 250 });
|
|
445
|
+
// editors is Context[] when selector matches multiple elements
|
|
446
|
+
|
|
447
|
+
// Iterate all instances
|
|
448
|
+
document.querySelectorAll('.rich-editor').forEach((el) => {
|
|
449
|
+
const editor = AutumnNote.getInstance(el);
|
|
450
|
+
console.log(editor.getHTML());
|
|
451
|
+
});
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## Project Structure
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
src/
|
|
460
|
+
├── js/
|
|
461
|
+
│ ├── core/
|
|
462
|
+
│ │ ├── dom.js DOM utilities (createElement, on, closest, …)
|
|
463
|
+
│ │ ├── range.js Selection / Range API helpers (withSavedRange, …)
|
|
464
|
+
│ │ ├── func.js General helpers (mergeDeep, debounce, …)
|
|
465
|
+
│ │ ├── key.js Keyboard key constants
|
|
466
|
+
│ │ ├── lists.js Array helpers
|
|
467
|
+
│ │ ├── env.js Browser / platform detection
|
|
468
|
+
│ │ ├── markdown.js Lightweight Markdown → HTML converter (paste handling)
|
|
469
|
+
│ │ └── sanitise.js DOM-based HTML and URL sanitiser (shared by all modules)
|
|
470
|
+
│ ├── editing/
|
|
471
|
+
│ │ ├── History.js Undo / redo stack (100 levels)
|
|
472
|
+
│ │ ├── Style.js execCommand style wrappers
|
|
473
|
+
│ │ ├── Table.js Table creation and cell manipulation
|
|
474
|
+
│ │ └── Typing.js Tab / Enter key behaviour
|
|
475
|
+
│ ├── module/
|
|
476
|
+
│ │ ├── Editor.js Core editing commands + getHTML / setHTML + sanitiser
|
|
477
|
+
│ │ ├── Toolbar.js Toolbar UI, button rendering (SVG + FA), dropdowns, colour picker
|
|
478
|
+
│ │ ├── Buttons.js Button / dropdown / colorpicker definitions and defaultToolbar
|
|
479
|
+
│ │ ├── Statusbar.js Word & character count + drag-to-resize
|
|
480
|
+
│ │ ├── Clipboard.js Paste sanitisation (HTML clean + plain-text mode)
|
|
481
|
+
│ │ ├── ContextMenu.js Right-click context menu (cut, copy, paste, format tools)
|
|
482
|
+
│ │ ├── Placeholder.js CSS-based placeholder
|
|
483
|
+
│ │ ├── Codeview.js HTML source view toggle
|
|
484
|
+
│ │ ├── Fullscreen.js Fullscreen mode
|
|
485
|
+
│ │ ├── LinkDialog.js Link insert / edit dialog
|
|
486
|
+
│ │ ├── LinkTooltip.js Floating toolbar for links (open / edit / unlink)
|
|
487
|
+
│ │ ├── ImageDialog.js Image insert dialog (URL + optional file upload)
|
|
488
|
+
│ │ ├── ImageTooltip.js Floating toolbar for images (edit / delete)
|
|
489
|
+
│ │ ├── ImageResizer.js Drag handle to resize images
|
|
490
|
+
│ │ ├── VideoDialog.js Video embed dialog (YouTube, Vimeo, direct file)
|
|
491
|
+
│ │ ├── VideoTooltip.js Floating toolbar for video embeds (edit / delete)
|
|
492
|
+
│ │ ├── VideoResizer.js Drag handle to resize video embeds
|
|
493
|
+
│ │ ├── TableTooltip.js Floating toolbar for tables (row/col/cell management)
|
|
494
|
+
│ │ ├── CodeTooltip.js Floating toolbar for code blocks (copy / delete)
|
|
495
|
+
│ │ ├── EmojiDialog.js Unicode emoji picker (~380 emoji, 7 categories)
|
|
496
|
+
│ │ ├── IconDialog.js FontAwesome icon picker (FA 6 Free Solid, 8 categories)
|
|
497
|
+
│ │ └── ShortcutsDialog.js Keyboard shortcuts reference dialog (Shift+?)
|
|
498
|
+
│ ├── Context.js Editor instance hub — module registry and event bus
|
|
499
|
+
│ ├── settings.js Default options (AsnOptions)
|
|
500
|
+
│ ├── renderer.js DOM layout builder
|
|
501
|
+
│ └── index.js Public entry point + AutumnNote factory
|
|
502
|
+
└── styles/
|
|
503
|
+
├── _variables.scss SCSS design tokens (colours, spacing, radii, transitions)
|
|
504
|
+
└── AutumnNote.scss Main stylesheet
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Development
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
# Install dependencies
|
|
513
|
+
npm install
|
|
514
|
+
|
|
515
|
+
# Start dev server with HMR (Vite)
|
|
516
|
+
npm run dev
|
|
517
|
+
|
|
518
|
+
# Build library (ES module + UMD + CSS)
|
|
519
|
+
npm run build
|
|
520
|
+
|
|
521
|
+
# Run unit tests (Vitest)
|
|
522
|
+
npm test
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Build output in `dist/`:
|
|
526
|
+
- `AutumnNote.es.js` — ES module (tree-shakeable)
|
|
527
|
+
- `AutumnNote.umd.js` — UMD bundle (script tag / CommonJS)
|
|
528
|
+
- `AutumnNote.css` — compiled stylesheet
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Comparison with Summernote
|
|
533
|
+
|
|
534
|
+
| Feature | Summernote | AutumnNote |
|
|
535
|
+
|---|---|---|
|
|
536
|
+
| jQuery required | Yes | No |
|
|
537
|
+
| Bootstrap required | Optional | No |
|
|
538
|
+
| Build system | Grunt | Vite |
|
|
539
|
+
| Module format | IIFE | ES module + UMD |
|
|
540
|
+
| Written in | ES5 / ES6 mix | ES2022 |
|
|
541
|
+
| HTML sanitisation | Basic | DOM-based (strips scripts, XSS vectors) |
|
|
542
|
+
| Emoji picker | No | Yes (~380 Unicode emoji, 7 categories) |
|
|
543
|
+
| FA icon picker | No | Yes (FA 6 Free Solid, 8 categories, searchable) |
|
|
544
|
+
| Video embeds | No | Yes (YouTube, Vimeo, direct file) |
|
|
545
|
+
| Image / video resize | No | Yes (drag handles) |
|
|
546
|
+
| Inline tooltips | No | Yes (link, image, video, table, code) |
|
|
547
|
+
| Context menu | No | Yes (with format copy/paste) |
|
|
548
|
+
| Right-click context menu | No | Yes |
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## License
|
|
553
|
+
|
|
554
|
+
MIT
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## Features
|
|
559
|
+
|
|
560
|
+
### Editing
|
|
561
|
+
- **Text formatting** — bold, italic, underline, strikethrough, superscript, subscript
|
|
562
|
+
- **Paragraph styles** — Normal, H1–H6, Blockquote, Code block
|
|
563
|
+
- **Font family** — customisable dropdown (10 families by default)
|
|
564
|
+
- **Line height** — dropdown from 1.0 to 3.0
|
|
565
|
+
- **Text & highlight colour** — native colour picker with last-used colour
|
|
566
|
+
- **Alignment** — left, center, right, justify
|
|
567
|
+
- **Lists** — unordered and ordered, with indent / outdent
|
|
568
|
+
- **Undo / redo** — built-in history stack (100 levels, `Ctrl+Z` / `Ctrl+Y`)
|
|
569
|
+
- **Tab key** — configurable spaces-per-tab, smart list indentation
|
|
570
|
+
|
|
571
|
+
### Insert
|
|
572
|
+
- **Horizontal rule**
|
|
573
|
+
- **Link dialog** — insert / edit hyperlinks with text and target options
|
|
574
|
+
- **Image dialog** — insert by URL or file upload (base64 embed); configurable max size
|
|
575
|
+
- **Video dialog** — insert YouTube / Vimeo / direct video URLs as responsive embeds
|
|
576
|
+
- **Table** — interactive grid picker (up to 10×10), context-menu actions (add/delete row/col, merge, split)
|
|
577
|
+
- **Emoji picker** — ~380 Unicode emoji across 7 categories (Smileys, People, Animals, Food, Travel, Objects, Symbols) with keyword search; click to insert instantly
|
|
578
|
+
- **FA Icon picker** — browse FontAwesome 6 Free Solid icons by category with keyword search; configurable style, size, and colour
|
|
579
|
+
|
|
580
|
+
### UI
|
|
581
|
+
- **Toolbar** — fully configurable button groups; auto-renders with SVG fallback or FontAwesome icons
|
|
582
|
+
- **Inline tooltips** — link, image, video, table, and code-block context tooltips with edit/delete actions
|
|
583
|
+
- **Image resizer** — drag handle to resize inserted images
|
|
584
|
+
- **Video resizer** — drag handle to resize inserted video embeds
|
|
585
|
+
- **Statusbar** — word and character count + drag-to-resize editor height
|
|
586
|
+
- **Code view** — toggle raw HTML source editor with sanitisation on apply
|
|
587
|
+
- **Fullscreen** — expand to fill the viewport
|
|
588
|
+
- **Placeholder** — CSS-based, zero DOM pollution
|
|
589
|
+
- **Context menu** — right-click menu for common actions
|
|
590
|
+
|
|
591
|
+
### Integration
|
|
592
|
+
- **No jQuery** — pure vanilla ES2022, zero runtime dependencies
|
|
593
|
+
- **Bootstrap friendly** — optional Bootstrap 4/5 styling for toolbar buttons (`useBootstrap: true`)
|
|
594
|
+
- **FontAwesome ready** — auto-detects FA on the page; falls back to inline SVG icons
|
|
595
|
+
- **Plugin-ready** — register custom modules via `AutumnNote.defaults`
|
|
596
|
+
- **Tree-shakeable** — ES module build; all core utilities are individually exported
|
|
597
|
+
|
|
598
|
+
### Security
|
|
599
|
+
- 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
|
|
600
|
+
- `javascript:` URLs are rejected in links and images
|
|
601
|
+
- Clipboard paste sanitises and removes XSS vectors before inserting
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## Installation
|
|
606
|
+
|
|
607
|
+
### npm / pnpm / yarn
|
|
608
|
+
|
|
609
|
+
```bash
|
|
610
|
+
npm install AutumnNote
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### CDN
|
|
614
|
+
|
|
615
|
+
```html
|
|
616
|
+
<link rel="stylesheet" href="dist/AutumnNote.css" />
|
|
617
|
+
<script src="dist/AutumnNote.umd.js"></script>
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
> 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.
|
|
621
|
+
>
|
|
622
|
+
> ```html
|
|
623
|
+
> <!-- FontAwesome 6 Free -->
|
|
624
|
+
> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
|
|
625
|
+
> ```
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
## Quick Start
|
|
630
|
+
|
|
631
|
+
### ES Module
|
|
632
|
+
|
|
633
|
+
```js
|
|
634
|
+
import AutumnNote from 'AutumnNote';
|
|
635
|
+
|
|
636
|
+
const editor = AutumnNote.create('#my-editor', {
|
|
637
|
+
placeholder: 'Start typing…',
|
|
638
|
+
height: 300,
|
|
639
|
+
onChange(html) {
|
|
640
|
+
console.log(html);
|
|
641
|
+
},
|
|
642
|
+
});
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### Script tag (UMD)
|
|
646
|
+
|
|
647
|
+
```html
|
|
648
|
+
<div id="my-editor"><p>Hello!</p></div>
|
|
649
|
+
<script src="dist/AutumnNote.umd.js"></script>
|
|
650
|
+
<script>
|
|
651
|
+
const editor = AutumnNote.create('#my-editor');
|
|
652
|
+
</script>
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### With Bootstrap 5
|
|
656
|
+
|
|
657
|
+
```js
|
|
658
|
+
const editor = AutumnNote.create('#my-editor', {
|
|
659
|
+
useBootstrap: true,
|
|
660
|
+
bootstrapVersion: 5,
|
|
661
|
+
toolbarButtonClass: 'btn btn-sm btn-light',
|
|
662
|
+
});
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
---
|
|
666
|
+
|
|
667
|
+
## API
|
|
668
|
+
|
|
669
|
+
### Factory
|
|
670
|
+
|
|
671
|
+
| Method | Description |
|
|
672
|
+
|---|---|
|
|
673
|
+
| `AutumnNote.create(selector, options?)` | Creates editor instance(s). Returns a `Context` (or array of `Context`). |
|
|
674
|
+
| `AutumnNote.destroy(selector)` | Destroys editor(s) and restores the original element. |
|
|
675
|
+
| `AutumnNote.getInstance(selector)` | Returns the `Context` for a given element, or `null`. |
|
|
676
|
+
| `AutumnNote.defaults` | Global default options — mutate before calling `create()` to set project-wide defaults. |
|
|
677
|
+
|
|
678
|
+
### Context (editor instance)
|
|
679
|
+
|
|
680
|
+
| Method | Description |
|
|
681
|
+
|---|---|
|
|
682
|
+
| `editor.getHTML()` | Returns the current HTML content (sanitised). |
|
|
683
|
+
| `editor.setHTML(html)` | Sets HTML content (sanitised). |
|
|
684
|
+
| `editor.getText()` | Returns plain text (no markup). |
|
|
685
|
+
| `editor.clear()` | Clears all content. |
|
|
686
|
+
| `editor.setDisabled(bool)` | Enables or disables the editor. |
|
|
687
|
+
| `editor.destroy()` | Removes the editor and restores the original element. |
|
|
688
|
+
| `editor.on(event, fn)` | Subscribes to an editor event. Returns an unsubscribe function. |
|
|
689
|
+
| `editor.invoke('module.method', ...args)` | Calls any registered module method by name. |
|
|
690
|
+
|
|
691
|
+
### Events
|
|
692
|
+
|
|
693
|
+
| Name | Payload | Description |
|
|
694
|
+
|---|---|---|
|
|
695
|
+
| `change` | `html: string` | Fired after every content mutation. |
|
|
696
|
+
| `focus` | — | Editor gained focus. |
|
|
697
|
+
| `blur` | — | Editor lost focus. |
|
|
698
|
+
|
|
699
|
+
---
|
|
700
|
+
|
|
701
|
+
## Options
|
|
702
|
+
|
|
703
|
+
| Option | Type | Default | Description |
|
|
704
|
+
|---|---|---|---|
|
|
705
|
+
| `placeholder` | `string` | `''` | Placeholder text shown when the editor is empty. |
|
|
706
|
+
| `height` | `number` | `200` | Initial / minimum editor height in px. |
|
|
707
|
+
| `minHeight` | `number` | `100` | Hard minimum height in px. |
|
|
708
|
+
| `maxHeight` | `number` | `0` | Maximum height in px. `0` = unlimited. |
|
|
709
|
+
| `focus` | `boolean` | `false` | Auto-focus the editor on initialisation. |
|
|
710
|
+
| `resizeable` | `boolean` | `true` | Show the drag-to-resize handle in the statusbar. |
|
|
711
|
+
| `toolbar` | `Array` | default | Array of button group arrays. See [Toolbar customisation](#toolbar-customisation). |
|
|
712
|
+
| `useBootstrap` | `boolean` | `false` | Apply Bootstrap classes to toolbar buttons. |
|
|
713
|
+
| `bootstrapVersion` | `number` | `5` | Bootstrap major version (`4` or `5`). |
|
|
714
|
+
| `toolbarButtonClass` | `string` | `'btn btn-sm btn-light'` | CSS classes for toolbar buttons when `useBootstrap` is `true`. |
|
|
715
|
+
| `useFontAwesome` | `boolean` | `true` | Use FA icons when FontAwesome is detected on the page. |
|
|
716
|
+
| `fontAwesomeClass` | `string` | `'fas'` | FA prefix — `'fas'` for FA 5, `'fa-solid'` for FA 6. |
|
|
717
|
+
| `pasteAsPlainText` | `boolean` | `false` | Strip all formatting on paste. |
|
|
718
|
+
| `pasteCleanHTML` | `boolean` | `true` | Sanitise HTML on paste. |
|
|
719
|
+
| `allowImageUpload` | `boolean` | `true` | Allow file upload in the image dialog. |
|
|
720
|
+
| `maxImageSize` | `number` | `5` | Maximum image upload size in MB. |
|
|
721
|
+
| `onImageUpload` | `Function` | `null` | Custom upload handler `(files: FileList) => void`. Overrides base64 embed. |
|
|
722
|
+
| `tabSize` | `number` | `0` | Spaces inserted per Tab key press. `0` = browser default. |
|
|
723
|
+
| `defaultFontFamily` | `string` | `'Arial'` | Font applied to the editable area. |
|
|
724
|
+
| `fontFamilies` | `string[]` | (10 fonts) | Font families listed in the font-family dropdown. |
|
|
725
|
+
| `onChange` | `Function` | `null` | `(html: string) => void` — called on every change. |
|
|
726
|
+
| `onFocus` | `Function` | `null` | `(context: Context) => void` |
|
|
727
|
+
| `onBlur` | `Function` | `null` | `(context: Context) => void` |
|
|
728
|
+
| `stickyToolbar` | `boolean` | `false` | Stick the toolbar to the viewport top when the page is scrolled. |
|
|
729
|
+
| `stickyToolbarOffset` | `number` | `0` | Top offset in px for the sticky toolbar (e.g. height of a fixed navigation bar). |
|
|
730
|
+
| `theme` | `string` | `'light'` | Colour theme: `'light'` or `'dark'`. |
|
|
731
|
+
| `codeHighlight` | `boolean` | `false` | Auto-load Prism.js for syntax highlighting inside `<pre><code>` blocks. |
|
|
732
|
+
| `codeHighlightCDN` | `string` | cdnjs Prism 1.29.0 | Base CDN URL used when auto-loading Prism assets. |
|
|
733
|
+
| `markdownPaste` | `boolean` | `true` | Convert pasted Markdown text to HTML when no HTML is present in the clipboard. |
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## Toolbar Customisation
|
|
738
|
+
|
|
739
|
+
The `toolbar` option accepts an array of button groups. Each group is an array of button definition objects imported from `Buttons.js`:
|
|
740
|
+
|
|
741
|
+
```js
|
|
742
|
+
import AutumnNote from 'AutumnNote';
|
|
743
|
+
import {
|
|
744
|
+
boldBtn, italicBtn, underlineBtn,
|
|
745
|
+
linkBtn, imageBtn, emojiBtn, iconBtn,
|
|
746
|
+
codeviewBtn, fullscreenBtn,
|
|
747
|
+
} from 'AutumnNote/src/js/module/Buttons.js';
|
|
748
|
+
|
|
749
|
+
AutumnNote.create('#editor', {
|
|
750
|
+
toolbar: [
|
|
751
|
+
[boldBtn, italicBtn, underlineBtn],
|
|
752
|
+
[linkBtn, imageBtn, emojiBtn, iconBtn],
|
|
753
|
+
[codeviewBtn, fullscreenBtn],
|
|
754
|
+
],
|
|
755
|
+
});
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
**Available buttons**
|
|
759
|
+
|
|
760
|
+
| Export | Tooltip |
|
|
761
|
+
|---|---|
|
|
762
|
+
| `paragraphStyleBtn` | Paragraph Style (dropdown) |
|
|
763
|
+
| `fontFamilyBtn` | Font Family (dropdown) |
|
|
764
|
+
| `lineHeightBtn` | Line Height (dropdown) |
|
|
765
|
+
| `undoBtn` / `redoBtn` | Undo / Redo |
|
|
766
|
+
| `boldBtn` / `italicBtn` / `underlineBtn` / `strikeBtn` | Text style |
|
|
767
|
+
| `superscriptBtn` / `subscriptBtn` | Super / Subscript |
|
|
768
|
+
| `foreColorBtn` / `backColorBtn` | Text colour / Highlight colour |
|
|
769
|
+
| `alignLeftBtn` / `alignCenterBtn` / `alignRightBtn` / `alignJustifyBtn` | Alignment |
|
|
770
|
+
| `ulBtn` / `olBtn` / `indentBtn` / `outdentBtn` | Lists & indentation |
|
|
771
|
+
| `hrBtn` | Horizontal Rule |
|
|
772
|
+
| `linkBtn` | Insert Link |
|
|
773
|
+
| `imageBtn` | Insert Image |
|
|
774
|
+
| `videoBtn` | Insert Video |
|
|
775
|
+
| `tableBtn` | Insert Table (grid picker) |
|
|
776
|
+
| `emojiBtn` | Insert Emoji |
|
|
777
|
+
| `iconBtn` | Insert FA Icon |
|
|
778
|
+
| `codeviewBtn` | HTML Code View |
|
|
779
|
+
| `fullscreenBtn` | Fullscreen |
|
|
780
|
+
|
|
781
|
+
---
|
|
782
|
+
|
|
783
|
+
## Project Structure
|
|
784
|
+
|
|
785
|
+
```
|
|
786
|
+
src/
|
|
787
|
+
├── js/
|
|
788
|
+
│ ├── core/
|
|
789
|
+
│ │ ├── dom.js DOM utilities
|
|
790
|
+
│ │ ├── range.js Selection / Range API helpers
|
|
791
|
+
│ │ ├── func.js General utility helpers
|
|
792
|
+
│ │ ├── key.js Keyboard key constants
|
|
793
|
+
│ │ ├── lists.js Array helpers
|
|
794
|
+
│ │ ├── env.js Browser / platform detection
|
|
795
|
+
│ │ ├── markdown.js Markdown → HTML converter
|
|
796
|
+
│ │ └── sanitise.js DOM-based HTML and URL sanitiser
|
|
797
|
+
│ ├── editing/
|
|
798
|
+
│ │ ├── History.js Undo / redo stack
|
|
799
|
+
│ │ ├── Style.js execCommand style wrappers
|
|
800
|
+
│ │ ├── Table.js Table creation and manipulation
|
|
801
|
+
│ │ └── Typing.js Tab / Enter key behaviour
|
|
802
|
+
│ ├── module/
|
|
803
|
+
│ │ ├── Editor.js Core editing commands + getHTML / setHTML
|
|
804
|
+
│ │ ├── Toolbar.js Toolbar UI and button rendering
|
|
805
|
+
│ │ ├── Buttons.js Button and dropdown definitions
|
|
806
|
+
│ │ ├── Statusbar.js Status bar + drag-to-resize
|
|
807
|
+
│ │ ├── Clipboard.js Paste sanitisation
|
|
808
|
+
│ │ ├── ContextMenu.js Right-click context menu
|
|
809
|
+
│ │ ├── Placeholder.js Placeholder text
|
|
810
|
+
│ │ ├── Codeview.js HTML source view
|
|
811
|
+
│ │ ├── Fullscreen.js Fullscreen mode
|
|
812
|
+
│ │ ├── LinkDialog.js Link insert / edit dialog
|
|
813
|
+
│ │ ├── LinkTooltip.js Inline link tooltip
|
|
814
|
+
│ │ ├── ImageDialog.js Image insert dialog (URL + upload)
|
|
815
|
+
│ │ ├── ImageTooltip.js Inline image tooltip
|
|
816
|
+
│ │ ├── ImageResizer.js Drag-to-resize for images
|
|
817
|
+
│ │ ├── VideoDialog.js Video embed dialog
|
|
818
|
+
│ │ ├── VideoTooltip.js Inline video tooltip
|
|
819
|
+
│ │ ├── VideoResizer.js Drag-to-resize for video embeds
|
|
820
|
+
│ │ ├── TableTooltip.js Table context tooltip
|
|
821
|
+
│ │ ├── CodeTooltip.js Code block context tooltip
|
|
822
|
+
│ │ ├── EmojiDialog.js Unicode emoji picker
|
|
823
|
+
│ │ ├── IconDialog.js FontAwesome icon picker
|
|
824
|
+
│ │ └── ShortcutsDialog.js Keyboard shortcuts dialog
|
|
825
|
+
│ ├── Context.js Editor instance hub
|
|
826
|
+
│ ├── settings.js Default options
|
|
827
|
+
│ ├── renderer.js DOM layout builder
|
|
828
|
+
│ └── index.js Public entry point
|
|
829
|
+
└── styles/
|
|
830
|
+
├── _variables.scss SCSS design tokens
|
|
831
|
+
└── AutumnNote.scss Main stylesheet
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
---
|
|
835
|
+
|
|
836
|
+
## Development
|
|
837
|
+
|
|
838
|
+
```bash
|
|
839
|
+
# Install dependencies
|
|
840
|
+
npm install
|
|
841
|
+
|
|
842
|
+
# Start dev server (Vite)
|
|
843
|
+
npm run dev
|
|
844
|
+
|
|
845
|
+
# Build library
|
|
846
|
+
npm run build
|
|
847
|
+
|
|
848
|
+
# Run tests
|
|
849
|
+
npm test
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
## Comparison with Summernote
|
|
855
|
+
|
|
856
|
+
| Feature | Summernote | AutumnNote |
|
|
857
|
+
|---|---|---|
|
|
858
|
+
| jQuery required | Yes | No |
|
|
859
|
+
| Bootstrap required | Optional | No |
|
|
860
|
+
| Build system | Grunt | Vite |
|
|
861
|
+
| Module format | IIFE | ES module + UMD |
|
|
862
|
+
| Written in | ES5 / ES6 mix | ES2022 |
|
|
863
|
+
| HTML sanitisation | Basic | DOM-based (strips scripts, XSS vectors) |
|
|
864
|
+
| Emoji picker | No | Yes (~380 Unicode emoji) |
|
|
865
|
+
| FA icon picker | No | Yes (FA 6 Free Solid, searchable) |
|
|
866
|
+
| Video embeds | No | Yes (YouTube, Vimeo, direct) |
|
|
867
|
+
| Image / video resize | No | Yes (drag handles) |
|
|
868
|
+
| Inline tooltips | No | Yes (link, image, video, table, code) |
|
|
869
|
+
|
|
870
|
+
---
|
|
871
|
+
|
|
872
|
+
## License
|
|
873
|
+
|
|
874
|
+
MIT
|