<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recent changes to Configuration</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>Recent changes to Configuration</description><atom:link href="https://sourceforge.net/p/neiki-editor/wiki/Configuration/feed" rel="self"/><language>en</language><lastBuildDate>Tue, 09 Jun 2026 08:08:51 -0000</lastBuildDate><atom:link href="https://sourceforge.net/p/neiki-editor/wiki/Configuration/feed" rel="self" type="application/rss+xml"/><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v18
+++ v19
@@ -281,13 +281,13 @@

 | | |
 |---|---|
-| [🔧 Toolbar Reference](Toolbar-Reference) | All available toolbar button identifiers |
-| [🔌 Plugin API](Plugin-API) | Add custom buttons via plugins |
-| [🧩 Advanced Features](Advanced-Features) | Autosave, themes, i18n deep dives |
-| [🎨 Themes &amp;amp; Styling](Themes-and-Styling) | CSS customization guide |
+| [🔧 Toolbar Reference](/p/neiki-editor/wiki/Toolbar%20Reference) | All available toolbar button identifiers |
+| [🔌 Plugin API](/p/neiki-editor/wiki/Plugin%20API) | Add custom buttons via plugins |
+| [🧩 Advanced Features](/p/neiki-editor/wiki/Advanced%20Features) | Autosave, themes, i18n deep dives |
+| [🎨 Themes &amp;amp; Styling](/p/neiki-editor/wiki/Themes%20and%20Styling) | CSS customization guide |

 ---

 &lt;div align="center"&gt;

-  &lt;sub&gt;&lt;a href="./Home"&gt;← Back to Home&lt;/a&gt;&lt;/sub&gt;
+  &lt;sub&gt;&lt;a href="/p/neiki-editor/wiki/Home"&gt;← Back to Home&lt;/a&gt;&lt;/sub&gt;
 &lt;/div&gt;
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 08:08:51 -0000</pubDate><guid>https://sourceforge.net34c6a532c5a48db55d12cb9891dfdfac9e50f974</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v17
+++ v18
@@ -1,6 +1,6 @@
 # ⚙️ Configuration

-Neiki's Editor is fully configurable. Pass an options object as the second argument to customize behavior, appearance, and toolbar layout.
+&amp;gt; All configuration options for Neiki's Editor, with types, defaults, and examples.

 ---

@@ -8,215 +8,174 @@

     :::javascript
     const editor = new NeikiEditor('#editor', {

-        // your options here
+        // options here
     });

 &amp;gt; [!NOTE]
-&amp;gt; All options are optional. The editor works with **zero configuration** out of the box.
+&amp;gt; All options are **optional**. The editor works with zero configuration out of the box.

 ---

 ## 📊 Options Reference

 | Option | Type | Default | Description |
-|--------|------|---------|-------------|
-| `placeholder` | `string` | `'Start typing...'` | Placeholder text shown when editor is empty |
+|---|---|---|---|
+| `placeholder` | `string` | `'Start typing...'` | Ghost text shown when the editor is empty |
 | `minHeight` | `number` | `300` | Minimum editor height in pixels |
-| `maxHeight` | `number\|null` | `null` | Maximum height in pixels (enables scroll when exceeded). When `null`, the toolbar uses `position: sticky` to stay visible while scrolling. |
+| `maxHeight` | `number\|null` | `null` | Maximum height in pixels; enables scroll when exceeded. When `null`, the toolbar uses `position: sticky`. |
 | `autofocus` | `boolean` | `false` | Automatically focus the editor on initialization |
 | `spellcheck` | `boolean` | `true` | Enable browser spellcheck |
-| `readonly` | `boolean` | `false` | Make editor read-only (content is visible but not editable) |
-| `theme` | `string` | `'light'` | Initial theme — `'light'`, `'dark'`, `'blue'`, or `'dark-blue'` |
-| `language` | `string` | `'en'` | UI language — `en`, `cs`, `zh`, `es`, `de`, `fr`, `pt`, `ja` |
-| `autosaveKey` | `string\|null` | `null` | Custom `localStorage` scope for autosave content and enabled state |
-| `toolbar` | `array` | *(see below)* | Array of toolbar button identifiers |
+| `readonly` | `boolean` | `false` | Make editor read-only (visible but not editable) |
+| `theme` | `string` | `'light'` | Initial theme: `'light'`, `'dark'`, `'blue'`, `'dark-blue'` |
+| `language` | `string` | `'en'` | UI language: `en`, `cs`, `zh`, `es`, `de`, `fr`, `pt`, `ja` |
+| `autosaveKey` | `string\|null` | `null` | Custom `localStorage` scope for autosave isolation |
+| `toolbar` | `array` | *(default set)* | Array of toolbar button identifiers |
+| `customClass` | `string\|null` | `null` | Extra CSS class appended to the content area |
+| `showHelp` | `boolean` | `true` | Show Help button in the More menu (⋯) |
+| `imageUploadHandler` | `function\|null` | `null` | Async `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for server image uploads |
+| `videoUploadHandler` | `function\|null` | `null` | Async `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for server video uploads |
+| `translations` | `object` | `{}` | Custom/override translation strings |
 | `onChange` | `function\|null` | `null` | Callback fired on every content change |
-| `onSave` | `function\|null` | `null` | Callback fired on save (Ctrl+S or More menu → Save) |
+| `onSave` | `function\|null` | `null` | Callback fired on save (`Ctrl+S` or More → Save) |
 | `onFocus` | `function\|null` | `null` | Callback fired when editor gains focus |
 | `onBlur` | `function\|null` | `null` | Callback fired when editor loses focus |
 | `onReady` | `function\|null` | `null` | Callback fired once the editor is fully initialized |
-| `showHelp` | `boolean` | `true` | Show Help button in More menu (⋯) |
-| `imageUploadHandler` | `function\|null` | `null` | Async callback `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for uploading images to a server/CDN instead of base64 |
-| `videoUploadHandler` | `function\|null` | `null` | Async callback `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for uploading videos to a server/CDN instead of base64 |
-| `customClass` | `string\|null` | `null` | Custom CSS class appended to the editor content area alongside `neiki-content` |
+
+---
+
+## 🔧 Option Details
+
+### `placeholder`
+
+Shown as ghost text when the editor is empty. Disappears when the user starts typing.
+

+    :::javascript
+    new NeikiEditor('#editor', {
+        placeholder: 'Write your article here...'
+    });
+
+---
+
+### `minHeight` / `maxHeight`
+
+Control the vertical size of the editor:
+
+    :::javascript
+    new NeikiEditor('#editor', {
+        minHeight: 200,
+        maxHeight: 600    // content scrolls after 600px
+    });
+
+&amp;gt; [!TIP]
+&amp;gt; With `maxHeight: null` (default), the editor grows with content and the toolbar becomes sticky — it stays visible while the user scrolls through long documents.
+
+---
+
+### `theme`
+
+Set the initial color theme. The user can change themes at runtime via the More menu.
+
+    :::javascript
+    new NeikiEditor('#editor', {
+        theme: 'dark'   // 'light' | 'dark' | 'blue' | 'dark-blue'
+    });
+
+&amp;gt; [!IMPORTANT]
+&amp;gt; If the user has previously toggled the theme, the persisted `localStorage` value overrides this config option. User preference is always respected. See [Themes &amp;amp; Styling](Themes-and-Styling) for details.
+
+---
+
+### `language`
+
+Set the UI language. Affects all tooltips, modals, status bar text, and system messages.
+
+    :::javascript
+    new NeikiEditor('#editor', {
+        language: 'cs'   // Czech UI
+    });
+
+**Available languages:**
+
+| Code | Language |
+|---|---|
+| `en` | English (default) |
+| `cs` | Czech |
+| `zh` | Chinese |
+| `es` | Spanish |
+| `de` | German |
+| `fr` | French |
+| `pt` | Portuguese |
+| `ja` | Japanese |
+
+&amp;gt; [!NOTE]
+&amp;gt; Language must be set at initialization. Changing it at runtime requires re-initializing the editor.
+
+---
+
+### `autosaveKey`
+
+By default, autosave is scoped to the page URL + editor identity. When your app edits different records at the same URL, use `autosaveKey` to isolate drafts:
+
+    :::javascript
+    new NeikiEditor('#editor', {
+        autosaveKey: 'article-42'
+    });
+
+See [Advanced Features — Autosave](Advanced-Features#-autosave) for full details.

 ---

 ### `customClass`

-Appends a custom CSS class to the editor content area element. The default `neiki-content` class is always present; your class is added alongside it.
-
-&amp;gt; **Note:** The old `custom_class` name is still accepted for backward compatibility.
-

-    :::javascript
-    new NeikiEditor('#editor', {
-        customClass: 'custom-content'
-    });
-
-This renders as:
+Appends an extra CSS class to the content area alongside the default `neiki-content` class:
+
+    :::javascript
+    new NeikiEditor('#editor', {
+        customClass: 'my-custom-content'
+    });
+
+Renders as:

     :::html

-    &lt;div class="" contenteditable="true"&gt;&lt;/div&gt;
-
-This makes it easy to apply custom styles without overriding the default `.neiki-content` class:
+    &lt;div class="" contenteditable="true"&gt;&lt;/div&gt;
+
+Use it to apply custom typography without touching the default styles:

     :::css

-    .custom-content {
-      font-family: 'Georgia', serif;
-      font-size: 18px;
+    .my-custom-content {
+        font-family: 'Georgia', serif;
+        font-size: 18px;
+        line-height: 1.8;
     }

----
-
-## 🔧 Detailed Option Descriptions
-
-### `placeholder`
-
-Displayed as ghost text when the editor is empty. Disappears as soon as the user starts typing.
-

-    :::javascript
-    new NeikiEditor('#editor', {
-        placeholder: 'Write your article here...'
-    });
-
----
-
-### `minHeight` / `maxHeight`
-
-Control the editor's vertical size. When `maxHeight` is set, the content area becomes scrollable.
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        minHeight: 200,
-        maxHeight: 600
-    });
-
-&amp;gt; [!TIP]
-&amp;gt; Set `maxHeight: null` (default) for an editor that grows with its content without a scroll limit. In this mode, the toolbar uses `position: sticky` to remain visible at the top of the viewport while scrolling long content.
-
----
-
-### `theme`
-
-Set the initial color theme. The user can change themes at runtime using the Change theme select in the More menu, or by adding `themeToggle` as a standalone toolbar select.
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        theme: 'dark'
-    });
-
-Available themes are `light`, `dark`, `blue`, and `dark-blue`.
-
-The chosen theme persists across page reloads via `localStorage`.
-
-&amp;gt; [!IMPORTANT]
-&amp;gt; If the user has previously toggled the theme, the persisted value overrides the `theme` config option. This ensures user preference is always respected.
-
----
-
-### `language`
-
-Set the UI language for all toolbar tooltips, modal dialogs, status bar texts, and system messages.
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        language: 'cs'  // Czech UI
-    });
-
-Built-in languages:
-- `'en'` — English (default)
-- `'cs'` — Czech
-- `'zh'` — Chinese
-- `'es'` — Spanish
-- `'de'` — German
-- `'fr'` — French
-- `'pt'` — Portuguese
-- `'ja'` — Japanese
-
----
-
-### `translations`
-
-Pass custom translations directly in config. Keys you provide are merged with built-in ones — you only need to override what you want.
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        language: 'de',
-        translations: {
-            de: {
-                'toolbar.bold': 'Fett (Strg+B)',
-                'toolbar.italic': 'Kursiv (Strg+I)',
-                // English is used as fallback for missing keys
-            }
-        }
-    });
-
-You can also register translations globally using the static method:
-
-    :::javascript
-    NeikiEditor.addTranslation('de', {
-        'toolbar.bold': 'Fett (Strg+B)',
-        'toolbar.italic': 'Kursiv (Strg+I)',
-    });
-    
-    const editor = new NeikiEditor('#editor', { language: 'de' });
-
----
-
-### `autosaveKey`
-
-Autosave uses `localStorage` keys scoped by the current page URL and the editor element identity by default. This prevents multiple editors on the same origin from overwriting each other's local drafts.
-
-Use `autosaveKey` when your app edits different records under the same URL or when you need a custom stable scope:
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        autosaveKey: 'article-42'
-    });
-
-You can also set the same value in markup with `data-neiki-autosave-key`.
+&amp;gt; [!NOTE]
+&amp;gt; The old name `custom_class` is still accepted for backward compatibility.

 ---

 ### `imageUploadHandler`

-An async function that receives a `File` object and returns a `Promise&amp;lt;string&amp;gt;` resolving to the image URL. When provided, **all image insertions** (file upload dialog, drag &amp;amp; drop, clipboard paste) use this handler instead of embedding base64 data.
+An async callback for uploading images to your server instead of embedding them as base64. Applies to file picker, drag &amp;amp; drop, and clipboard paste.

     :::javascript
     new NeikiEditor('#editor', {
         imageUploadHandler: async (file) =&amp;gt; {
             const formData = new FormData();
             formData.append('image', file);

-    
-            const response = await fetch('/api/upload', {
-                method: 'POST',
-                body: formData
-            });
-    
-            const data = await response.json();
-            return data.url; // e.g. 'https://cdn.example.com/images/photo.jpg'
-        }
-    });
-
-When `imageUploadHandler` is set:
-- The image dialog accepts **multiple files** — each file is uploaded sequentially via the handler
-- **Drag &amp;amp; drop** images are uploaded via the handler instead of being converted to base64
-- **Clipboard paste** images are uploaded via the handler
-- The dialog hint text changes to "Will be uploaded via handler"
-
-When `imageUploadHandler` is `null` (default):
-- Single file uploads are converted to base64 (existing behavior)
-- Multiple file uploads are each converted to base64 and inserted sequentially
-- Clipboard pasted images are converted to base64
+            const res = await fetch('/api/upload', { method: 'POST', body: formData });
+            const data = await res.json();
+            return data.url;  // must return the final image URL
+        }
+    });

 &amp;gt; [!TIP]
-&amp;gt; Using `imageUploadHandler` is strongly recommended for production. It keeps the HTML content lightweight and allows browsers to cache images efficiently.
+&amp;gt; Using `imageUploadHandler` is strongly recommended for production. It prevents bloated base64 content and lets browsers cache images properly.

 ---

 ### `videoUploadHandler`

-An async function that receives a video `File` object and returns a `Promise&amp;lt;string&amp;gt;` resolving to the video URL. When provided, Insert &amp;gt; Video file uploads use this handler instead of embedding base64 data.
+Same as `imageUploadHandler` but for videos. Without it, video files are embedded as base64.

     :::javascript
     new NeikiEditor('#editor', {
@@ -229,29 +188,82 @@
         }
     });

-When `videoUploadHandler` is `null` (default), selected videos are converted to base64 and inserted as `&lt;video controls=""&gt;`.
-
----
-
-### `toolbar`
-
-An array defining which buttons appear in the toolbar and in what order. Use `'|'` as a visual separator.
+---
+
+### `translations`
+
+Override or extend any built-in translation string. Keys you provide are merged with the built-in ones — you only need to supply what you want to change.
+

+    :::javascript
+    new NeikiEditor('#editor', {
+        language: 'en',
+        translations: {
+            'toolbar.bold': 'Make it bold',
+            'placeholder': 'Start your story...'
+        }
+    });
+
+---
+
+### Callbacks
+
+All callbacks receive the editor instance or relevant data:
+
+    :::javascript
+    new NeikiEditor('#editor', {
+        onReady: function(editor) {
+            console.log('Editor ready!', editor);
+        },
+    
+        onChange: function(content) {
+            // fires on every keystroke / change
+            console.log('New content:', content);
+        },
+    
+        onSave: function(content) {
+            // fires on Ctrl+S or More → Save
+            fetch('/api/save', {
+                method: 'POST',
+                headers: { 'Content-Type': 'application/json' },
+                body: JSON.stringify({ content })
+            });
+        },
+    
+        onFocus: function() {
+            document.title = '✏️ Editing...';
+        },
+    
+        onBlur: function() {
+            document.title = 'My Page';
+        }
+    });
+
+---
+
+## 🏗️ Toolbar Configuration
+
+Customize the toolbar by passing an array of button identifiers:

     :::javascript
     new NeikiEditor('#editor', {
         toolbar: [

-            'viewCode', 'undo', 'redo', 'findReplace', '|',
             'bold', 'italic', 'underline', '|',
             'heading', 'fontSize', '|',
+            'bulletList', 'numberedList', '|',
             'insertDropdown', '|',
             'moreMenu'
         ]
     });

-#### Default Toolbar
-

-    :::javascript
-    [
+- Use `'|'` as a separator between groups. Groups wrap as whole units on narrow screens.
+- Plugin buttons are referenced by their registered `name`.
+
+For the full list of available buttons, see the [Toolbar Reference](Toolbar-Reference).
+
+**Default toolbar** (all features):
+
+    :::javascript
+    toolbar: [
         'viewCode', 'undo', 'redo', 'findReplace', '|',
         'bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'code', 'removeFormat', '|',
         'heading', 'fontFamily', 'fontSize', '|',
@@ -263,140 +275,16 @@
         'moreMenu'
     ]

-The `insertDropdown` item consolidates Link, Image, Video, Table, Emoji, and Symbol into a single dropdown button. The `moreMenu` item provides Save, Preview, Download, Print, Autosave, Clear all, Change theme, Fullscreen, and Help in a dropdown pushed to the right edge of the toolbar.
-
-&amp;gt; [!NOTE]
-&amp;gt; You can still use standalone toolbar items like `link`, `image`, `video`, `table`, `emoji`, `specialChars`, `fullscreen`, `themeToggle`, `autosave`, `print` directly in the toolbar array if you prefer individual buttons.
-
-For a complete list of all buttons, see **[Toolbar Reference](Toolbar-Reference)**.
-
----
-
-### `onChange`
-
-Called every time the editor content changes. Receives the HTML content string and the editor instance.
-

-    :::javascript
-    new NeikiEditor('#editor', {
-        onChange: function(content, editor) {
-            console.log('New content:', content);
-            document.getElementById('preview').innerHTML = content;
-        }
-    });
-
-&amp;gt; [!TIP]
-&amp;gt; For auto-saving to a server, wrap your save logic in a debounce function to avoid excessive requests:
-&amp;gt; ```javascript
-&amp;gt; onChange: debounce(function(content) {
-&amp;gt;     fetch('/api/save', {
-&amp;gt;         method: 'POST',
-&amp;gt;         body: JSON.stringify({ content })
-&amp;gt;     });
-&amp;gt; }, 2000)
-&amp;gt; ```
-
----
-
-### `onSave`
-
-Called when the user presses **Ctrl+S** or clicks **Save** in the More menu (⋯). Receives the HTML content string and the editor instance.
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        onSave: function(content, editor) {
-            fetch('/api/save', {
-                method: 'POST',
-                headers: { 'Content-Type': 'application/json' },
-                body: JSON.stringify({ content })
-            });
-        }
-    });
-
-&amp;gt; [!TIP]
-&amp;gt; Unlike `onChange`, `onSave` is triggered only on explicit user action (keyboard shortcut or menu), making it ideal for save-to-server logic without needing debounce.
-
----
-
-### `onReady`
-
-Called once when the editor has finished initializing. Useful for setup tasks that depend on the editor being ready.
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        onReady: function(editor) {
-            console.log('Editor is ready!');
-            editor.focus();
-        }
-    });
-
----
-
-### `readonly`
-
-When `true`, the editor displays content in the styled editor UI but prevents any editing.
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        readonly: true
-    });
-
----
-
-### `showHelp`
-
-Controls whether the **Help** button appears in the More menu (⋯). When clicked, it opens a modal with logo, author, version, and links to GitHub and documentation.
-
-    :::javascript
-    new NeikiEditor('#editor', {
-        showHelp: false  // hide Help from More menu
-    });
-
----
-
-## 🏗️ Full Configuration Example
-
-    :::javascript
-    const editor = new NeikiEditor('#editor', {
-        placeholder: 'Start writing your blog post...',
-        minHeight: 400,
-        maxHeight: 800,
-        autofocus: true,
-        spellcheck: true,
-        readonly: false,
-        theme: 'light',
-        toolbar: [
-            'viewCode', 'undo', 'redo', 'findReplace', '|',
-            'bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'removeFormat', '|',
-            'heading', 'fontFamily', 'fontSize', '|',
-            'foreColor', 'backColor', '|',
-            'alignLeft', 'alignCenter', 'alignRight', 'alignJustify', '|',
-            'indent', 'outdent', '|',
-            'bulletList', 'numberedList', 'blockquote', 'horizontalRule', '|',
-            'insertDropdown', '|',
-            'moreMenu'
-        ],
-        onChange: function(content, editor) {
-            console.log('Content length:', content.length);
-        },
-        onSave: function(content, editor) {
-            console.log('Save triggered');
-        },
-        onReady: function(editor) {
-            console.log("Neiki's Editor v3.0.1 initialized");
-        },
-        showHelp: true,
-        imageUploadHandler: null, // set to async (file) =&amp;gt; url for server uploads
-        videoUploadHandler: null, // set to async (file) =&amp;gt; url for video uploads
-        custom_class: null // optional custom CSS class for the content area
-    });
-
 ---

 ## 🔗 Related Pages

-- **[🔧 Toolbar Reference](Toolbar-Reference)** — All available toolbar buttons
-- **[🔌 Plugin API](Plugin-API)** — Extend the editor with custom functionality
-- **[🧩 Advanced Features](Advanced-Features)** — Themes, autosave, tables, and more
+| | |
+|---|---|
+| [🔧 Toolbar Reference](Toolbar-Reference) | All available toolbar button identifiers |
+| [🔌 Plugin API](Plugin-API) | Add custom buttons via plugins |
+| [🧩 Advanced Features](Advanced-Features) | Autosave, themes, i18n deep dives |
+| [🎨 Themes &amp;amp; Styling](Themes-and-Styling) | CSS customization guide |

 ---

&lt;/video&gt;&amp;lt;/string&amp;gt;&amp;lt;/string&amp;gt;&amp;lt;/url&amp;gt;&amp;lt;/url&amp;gt;&amp;lt;/url&amp;gt;&amp;lt;/url&amp;gt;&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:52 -0000</pubDate><guid>https://sourceforge.netd9c5b9a00c17e007c82634319ce889820a6209d6</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v16
+++ v17
@@ -26,7 +26,7 @@
 | `autofocus` | `boolean` | `false` | Automatically focus the editor on initialization |
 | `spellcheck` | `boolean` | `true` | Enable browser spellcheck |
 | `readonly` | `boolean` | `false` | Make editor read-only (content is visible but not editable) |
-| `theme` | `string` | `'light'` | Initial theme — `'light'` or `'dark'` |
+| `theme` | `string` | `'light'` | Initial theme — `'light'`, `'dark'`, `'blue'`, or `'dark-blue'` |
 | `language` | `string` | `'en'` | UI language — `en`, `cs`, `zh`, `es`, `de`, `fr`, `pt`, `ja` |
 | `autosaveKey` | `string\|null` | `null` | Custom `localStorage` scope for autosave content and enabled state |
 | `toolbar` | `array` | *(see below)* | Array of toolbar button identifiers |
@@ -37,6 +37,7 @@
 | `onReady` | `function\|null` | `null` | Callback fired once the editor is fully initialized |
 | `showHelp` | `boolean` | `true` | Show Help button in More menu (⋯) |
 | `imageUploadHandler` | `function\|null` | `null` | Async callback `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for uploading images to a server/CDN instead of base64 |
+| `videoUploadHandler` | `function\|null` | `null` | Async callback `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for uploading videos to a server/CDN instead of base64 |
 | `customClass` | `string\|null` | `null` | Custom CSS class appended to the editor content area alongside `neiki-content` |

 ---
@@ -97,12 +98,14 @@

 ### `theme`

-Set the initial color theme. The user can toggle themes at runtime using the `themeToggle` toolbar button.
+Set the initial color theme. The user can change themes at runtime using the Change theme select in the More menu, or by adding `themeToggle` as a standalone toolbar select.

     :::javascript
     new NeikiEditor('#editor', {
         theme: 'dark'
     });
+
+Available themes are `light`, `dark`, `blue`, and `dark-blue`.

 The chosen theme persists across page reloads via `localStorage`.

@@ -211,6 +214,25 @@

 ---

+### `videoUploadHandler`
+
+An async function that receives a video `File` object and returns a `Promise&amp;lt;string&amp;gt;` resolving to the video URL. When provided, Insert &amp;gt; Video file uploads use this handler instead of embedding base64 data.
+

+    :::javascript
+    new NeikiEditor('#editor', {
+        videoUploadHandler: async (file) =&amp;gt; {
+            const formData = new FormData();
+            formData.append('video', file);
+            const response = await fetch('/api/upload-video', { method: 'POST', body: formData });
+            const data = await response.json();
+            return data.url;
+        }
+    });
+
+When `videoUploadHandler` is `null` (default), selected videos are converted to base64 and inserted as `&lt;video controls=""&gt;`.
+
+---
+
 ### `toolbar`

 An array defining which buttons appear in the toolbar and in what order. Use `'|'` as a visual separator.
@@ -241,10 +263,10 @@
         'moreMenu'
     ]

-The `insertDropdown` item consolidates Link, Image, Table, Emoji, and Symbol into a single dropdown button. The `moreMenu` item provides Save, Preview, Download, Print, Autosave, Clear all, Toggle Theme, Fullscreen, and Help in a dropdown pushed to the right edge of the toolbar.
+The `insertDropdown` item consolidates Link, Image, Video, Table, Emoji, and Symbol into a single dropdown button. The `moreMenu` item provides Save, Preview, Download, Print, Autosave, Clear all, Change theme, Fullscreen, and Help in a dropdown pushed to the right edge of the toolbar.

 &amp;gt; [!NOTE]
-&amp;gt; You can still use standalone toolbar items like `link`, `image`, `table`, `emoji`, `specialChars`, `fullscreen`, `themeToggle`, `autosave`, `print` directly in the toolbar array if you prefer individual buttons.
+&amp;gt; You can still use standalone toolbar items like `link`, `image`, `video`, `table`, `emoji`, `specialChars`, `fullscreen`, `themeToggle`, `autosave`, `print` directly in the toolbar array if you prefer individual buttons.

 For a complete list of all buttons, see **[Toolbar Reference](Toolbar-Reference)**.

@@ -360,10 +382,11 @@
             console.log('Save triggered');
         },
         onReady: function(editor) {

-            console.log("Neiki's Editor v2.10.1 initialized");
+            console.log("Neiki's Editor v3.0.1 initialized");
         },
         showHelp: true,
         imageUploadHandler: null, // set to async (file) =&amp;gt; url for server uploads
+        videoUploadHandler: null, // set to async (file) =&amp;gt; url for video uploads
         custom_class: null // optional custom CSS class for the content area
     });

&lt;/video&gt;&amp;lt;/string&amp;gt;&amp;lt;/url&amp;gt;&amp;lt;/url&amp;gt;&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:52 -0000</pubDate><guid>https://sourceforge.net034a2a28dfd16ae2d23b3b10c068442cd1fd0eaf</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v15
+++ v16
@@ -37,17 +37,19 @@
 | `onReady` | `function\|null` | `null` | Callback fired once the editor is fully initialized |
 | `showHelp` | `boolean` | `true` | Show Help button in More menu (⋯) |
 | `imageUploadHandler` | `function\|null` | `null` | Async callback `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for uploading images to a server/CDN instead of base64 |
-| `custom_class` | `string\|null` | `null` | Custom CSS class appended to the editor content area alongside `neiki-content` |
-
----
-
-### `custom_class`
+| `customClass` | `string\|null` | `null` | Custom CSS class appended to the editor content area alongside `neiki-content` |
+
+---
+
+### `customClass`

 Appends a custom CSS class to the editor content area element. The default `neiki-content` class is always present; your class is added alongside it.


-    :::javascript
-    new NeikiEditor('#editor', {
-        custom_class: 'custom-content'
+&amp;gt; **Note:** The old `custom_class` name is still accepted for backward compatibility.
+
+    :::javascript
+    new NeikiEditor('#editor', {
+        customClass: 'custom-content'
     });

 This renders as:
@@ -229,7 +231,7 @@
     :::javascript
     [
         'viewCode', 'undo', 'redo', 'findReplace', '|',

-        'bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'removeFormat', '|',
+        'bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'code', 'removeFormat', '|',
         'heading', 'fontFamily', 'fontSize', '|',
         'foreColor', 'backColor', '|',
         'alignLeft', 'alignCenter', 'alignRight', 'alignJustify', '|',
@@ -358,7 +360,7 @@
             console.log('Save triggered');
         },
         onReady: function(editor) {
-            console.log("Neiki's Editor v2.9.5 initialized");
+            console.log("Neiki's Editor v2.10.1 initialized");
         },
         showHelp: true,
         imageUploadHandler: null, // set to async (file) =&amp;gt; url for server uploads
&amp;lt;/url&amp;gt;&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:51 -0000</pubDate><guid>https://sourceforge.net939d2962024c90e7ee47387c92a57883978bc68b</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v14
+++ v15
@@ -37,6 +37,31 @@
 | `onReady` | `function\|null` | `null` | Callback fired once the editor is fully initialized |
 | `showHelp` | `boolean` | `true` | Show Help button in More menu (⋯) |
 | `imageUploadHandler` | `function\|null` | `null` | Async callback `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for uploading images to a server/CDN instead of base64 |
+| `custom_class` | `string\|null` | `null` | Custom CSS class appended to the editor content area alongside `neiki-content` |
+
+---
+
+### `custom_class`
+
+Appends a custom CSS class to the editor content area element. The default `neiki-content` class is always present; your class is added alongside it.
+

+    :::javascript
+    new NeikiEditor('#editor', {
+        custom_class: 'custom-content'
+    });
+
+This renders as:
+
+    :::html
+    &lt;div class="" contenteditable="true"&gt;&lt;/div&gt;
+
+This makes it easy to apply custom styles without overriding the default `.neiki-content` class:
+
+    :::css
+    .custom-content {
+      font-family: 'Georgia', serif;
+      font-size: 18px;
+    }

 ---

@@ -333,10 +358,11 @@
             console.log('Save triggered');
         },
         onReady: function(editor) {

-            console.log("Neiki's Editor v2.9.4 initialized");
+            console.log("Neiki's Editor v2.9.5 initialized");
         },
         showHelp: true,
-        imageUploadHandler: null // set to async (file) =&amp;gt; url for server uploads
+        imageUploadHandler: null, // set to async (file) =&amp;gt; url for server uploads
+        custom_class: null // optional custom CSS class for the content area
     });

 ---
&amp;lt;/url&amp;gt;&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:51 -0000</pubDate><guid>https://sourceforge.netfe966cb06bb985f64907b07de637acc591eb5592</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v13
+++ v14
@@ -28,6 +28,7 @@
 | `readonly` | `boolean` | `false` | Make editor read-only (content is visible but not editable) |
 | `theme` | `string` | `'light'` | Initial theme — `'light'` or `'dark'` |
 | `language` | `string` | `'en'` | UI language — `en`, `cs`, `zh`, `es`, `de`, `fr`, `pt`, `ja` |
+| `autosaveKey` | `string\|null` | `null` | Custom `localStorage` scope for autosave content and enabled state |
 | `toolbar` | `array` | *(see below)* | Array of toolbar button identifiers |
 | `onChange` | `function\|null` | `null` | Callback fired on every content change |
 | `onSave` | `function\|null` | `null` | Callback fired on save (Ctrl+S or More menu → Save) |
@@ -129,6 +130,21 @@
     });

     const editor = new NeikiEditor('#editor', { language: 'de' });
+
+---
+
+### `autosaveKey`
+
+Autosave uses `localStorage` keys scoped by the current page URL and the editor element identity by default. This prevents multiple editors on the same origin from overwriting each other's local drafts.
+
+Use `autosaveKey` when your app edits different records under the same URL or when you need a custom stable scope:
+

+    :::javascript
+    new NeikiEditor('#editor', {
+        autosaveKey: 'article-42'
+    });
+
+You can also set the same value in markup with `data-neiki-autosave-key`.

 ---

@@ -317,7 +333,7 @@
             console.log('Save triggered');
         },
         onReady: function(editor) {

-            console.log("Neiki's Editor v2.9.2 initialized");
+            console.log("Neiki's Editor v2.9.4 initialized");
         },
         showHelp: true,
         imageUploadHandler: null // set to async (file) =&amp;gt; url for server uploads
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:51 -0000</pubDate><guid>https://sourceforge.net4025e226c0ad37320a811f35fca271802184ee55</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v12
+++ v13
@@ -317,7 +317,7 @@
             console.log('Save triggered');
         },
         onReady: function(editor) {

-            console.log('Neiki's Editor v2.9.2 initialized');
+            console.log("Neiki's Editor v2.9.2 initialized");
         },
         showHelp: true,
         imageUploadHandler: null // set to async (file) =&amp;gt; url for server uploads
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:51 -0000</pubDate><guid>https://sourceforge.netc4531f9a05c76d439e27e6b95185c3e5366a0631</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v11
+++ v12
@@ -22,7 +22,7 @@
 |--------|------|---------|-------------|
 | `placeholder` | `string` | `'Start typing...'` | Placeholder text shown when editor is empty |
 | `minHeight` | `number` | `300` | Minimum editor height in pixels |
-| `maxHeight` | `number\|null` | `null` | Maximum height in pixels (enables scroll when exceeded) |
+| `maxHeight` | `number\|null` | `null` | Maximum height in pixels (enables scroll when exceeded). When `null`, the toolbar uses `position: sticky` to stay visible while scrolling. |
 | `autofocus` | `boolean` | `false` | Automatically focus the editor on initialization |
 | `spellcheck` | `boolean` | `true` | Enable browser spellcheck |
 | `readonly` | `boolean` | `false` | Make editor read-only (content is visible but not editable) |
@@ -63,7 +63,7 @@
     });

 &amp;gt; [!TIP]
-&amp;gt; Set `maxHeight: null` (default) for an editor that grows with its content without a scroll limit.
+&amp;gt; Set `maxHeight: null` (default) for an editor that grows with its content without a scroll limit. In this mode, the toolbar uses `position: sticky` to remain visible at the top of the viewport while scrolling long content.

 ---

@@ -317,7 +317,7 @@
             console.log('Save triggered');
         },
         onReady: function(editor) {

-            console.log('Neiki's Editor v2.9.1 initialized');
+            console.log('Neiki's Editor v2.9.2 initialized');
         },
         showHelp: true,
         imageUploadHandler: null // set to async (file) =&amp;gt; url for server uploads
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:50 -0000</pubDate><guid>https://sourceforge.net5be99b25a9519930549b03b121531a1a236c1510</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v10
+++ v11
@@ -317,7 +317,7 @@
             console.log('Save triggered');
         },
         onReady: function(editor) {

-            console.log('Neiki's Editor v2.9.0 initialized');
+            console.log('Neiki's Editor v2.9.1 initialized');
         },
         showHelp: true,
         imageUploadHandler: null // set to async (file) =&amp;gt; url for server uploads
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:50 -0000</pubDate><guid>https://sourceforge.netbc8ad3a30bb5c1ec9d807cea8d7b1bc17dbc7867</guid></item><item><title>Configuration modified by neikiri</title><link>https://sourceforge.net/p/neiki-editor/wiki/Configuration/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v9
+++ v10
@@ -1,6 +1,6 @@
 # ⚙️ Configuration

-Neiki Editor is fully configurable. Pass an options object as the second argument to customize behavior, appearance, and toolbar layout.
+Neiki's Editor is fully configurable. Pass an options object as the second argument to customize behavior, appearance, and toolbar layout.

 ---

@@ -35,6 +35,7 @@
 | `onBlur` | `function\|null` | `null` | Callback fired when editor loses focus |
 | `onReady` | `function\|null` | `null` | Callback fired once the editor is fully initialized |
 | `showHelp` | `boolean` | `true` | Show Help button in More menu (⋯) |
+| `imageUploadHandler` | `function\|null` | `null` | Async callback `(file) =&amp;gt; Promise&amp;lt;url&amp;gt;` for uploading images to a server/CDN instead of base64 |

 ---

@@ -128,6 +129,42 @@
     });

     const editor = new NeikiEditor('#editor', { language: 'de' });
+
+---
+
+### `imageUploadHandler`
+
+An async function that receives a `File` object and returns a `Promise&amp;lt;string&amp;gt;` resolving to the image URL. When provided, **all image insertions** (file upload dialog, drag &amp;amp; drop, clipboard paste) use this handler instead of embedding base64 data.
+

+    :::javascript
+    new NeikiEditor('#editor', {
+        imageUploadHandler: async (file) =&amp;gt; {
+            const formData = new FormData();
+            formData.append('image', file);
+    
+            const response = await fetch('/api/upload', {
+                method: 'POST',
+                body: formData
+            });
+    
+            const data = await response.json();
+            return data.url; // e.g. 'https://cdn.example.com/images/photo.jpg'
+        }
+    });
+
+When `imageUploadHandler` is set:
+- The image dialog accepts **multiple files** — each file is uploaded sequentially via the handler
+- **Drag &amp;amp; drop** images are uploaded via the handler instead of being converted to base64
+- **Clipboard paste** images are uploaded via the handler
+- The dialog hint text changes to "Will be uploaded via handler"
+
+When `imageUploadHandler` is `null` (default):
+- Single file uploads are converted to base64 (existing behavior)
+- Multiple file uploads are each converted to base64 and inserted sequentially
+- Clipboard pasted images are converted to base64
+
+&amp;gt; [!TIP]
+&amp;gt; Using `imageUploadHandler` is strongly recommended for production. It keeps the HTML content lightweight and allows browsers to cache images efficiently.

 ---

@@ -280,9 +317,10 @@
             console.log('Save triggered');
         },
         onReady: function(editor) {

-            console.log('Neiki Editor v2.8.0 initialized');
+            console.log('Neiki's Editor v2.9.0 initialized');
         },
-        showHelp: true
+        showHelp: true,
+        imageUploadHandler: null // set to async (file) =&amp;gt; url for server uploads
     });

 ---
&amp;lt;/string&amp;gt;&amp;lt;/url&amp;gt;&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">neikiri</dc:creator><pubDate>Tue, 09 Jun 2026 06:07:50 -0000</pubDate><guid>https://sourceforge.nete3ba33614c5a9d8007f3df76c14fd6e3cf66d44d</guid></item></channel></rss>