WakaJodit
WakaJodit integrates with WakaPAC as a plugin, bridging Jodit into the WakaPAC message model. Editor events — content changes, focus, blur, paste — all arrive in msgProc as messages, the same dispatch table as clicks, keypresses, and timers.
Getting Started
Register WakaJodit with WakaPAC once, before creating any components. The plugin activates automatically for components whose root element is either a <waka-jodit> custom element, or a <textarea> carrying a data-jodit attribute.
Custom element
Use <waka-jodit> as the container element. The plugin detects the tag name and activates automatically — no extra attribute is needed. Add a name attribute to participate in form submission:
<waka-jodit id="editor1" name="body"></waka-jodit>
<script>
wakaPAC.use(WakaJodit);
wakaPAC('#editor1', {
msgProc(event) { }
});
</script>
Attribute-based (classic)
<script src="https://cdn.jsdelivr.net/gh/quellabs/wakapac@main/wakapac.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/quellabs/wakapac@main/plugins/wakajodit.min.js"></script>
<textarea id="editor1" data-jodit name="body"></textarea>
<script>
wakaPAC.use(WakaJodit);
wakaPAC('#editor1', {
msgProc(event) { }
});
</script>
Loading Jodit
The plugin injects the Jodit script and its companion stylesheet automatically on first use and shares them across all instances. Components created before the script finishes loading are queued and initialized once it is available. You can also load Jodit yourself before WakaPAC initializes any components — the plugin will detect the existing window.Jodit global and skip injection.
CDN (default) — loads the latest Jodit build from jsDelivr, including the companion stylesheet. No license key is required:
wakaPAC.use(WakaJodit);
Self-hosted — point the plugin at your own Jodit build. Pass css to load a companion stylesheet, or null if the styles are already on the page:
// Self-hosted bundle with explicit CSS path
wakaPAC.use(WakaJodit, {
src: '/assets/jodit/jodit.min.js',
css: '/assets/jodit/jodit.min.css'
});
// Self-hosted bundle whose styles are already on the page
wakaPAC.use(WakaJodit, {
src: '/assets/jodit/jodit.min.js',
css: null
});
CDN script, custom or suppressed CSS — use the CDN script but manage the stylesheet yourself:
// Suppress auto-injection entirely (stylesheet already on page)
wakaPAC.use(WakaJodit, { css: null });
// CDN script with a custom stylesheet path
wakaPAC.use(WakaJodit, { css: '/assets/jodit/custom-jodit.css' });
The plugin expects a UMD/IIFE build that exposes window.Jodit. ESM-only builds are not supported.
The Basics
Once registered, editor events arrive in msgProc. The current HTML content is always available through WakaJodit.getValue().
wakaPAC('#editor1', {
msgProc(event) {
switch (event.message) {
case WakaJodit.MSG_EDITOR_READY:
console.log('Editor ready, initial content:', event.detail.value);
break;
case wakaPAC.MSG_CHANGE:
console.log('Content changed:', event.detail.value);
break;
case wakaPAC.MSG_INPUT_COMPLETE:
// Validate or save on blur / after paste
this.validate(event.detail.value);
break;
case wakaPAC.MSG_PASTE:
// Return false to block the paste
if (event.detail['text/html'].includes('<script')) {
return false;
}
break;
case WakaJodit.MSG_EDITOR_ERROR:
console.error('Editor failed to load:', event.detail.message);
break;
}
}
});
Per-Instance Configuration
Jodit config can be passed per-component as the third argument to wakaPAC(), under the jodit key. Any valid Jodit config option is accepted and will be merged with the plugin-level defaults.
wakaPAC('#editor1', { msgProc }, {
jodit: {
toolbar: true,
height: 400,
language: 'nl'
}
});
Plugin-level defaults can also be set when registering, and they apply to all instances unless overridden per-component:
wakaPAC.use(WakaJodit, {
toolbar: true,
height: 300,
language: 'nl'
});
Messages
WakaJodit dispatches two plugin-specific message types. All other events use standard WakaPAC message constants available on the wakaPAC object.
Editor Ready (MSG_EDITOR_READY)
Fired once when Jodit has fully initialized and is ready to accept input. The 'ready' event inside Jodit is used rather than the moment of construction, because the toolbar may still be bootstrapping at that point. Do not call WakaJodit.setValue() before this message fires.
| Parameter | Type | Description |
|---|---|---|
wParam | number | Always 0. |
lParam | number | Always 0. |
detail.value | string | The initial HTML content of the editor, sourced from the textarea's value at the time of initialization. |
Editor Load Error (MSG_EDITOR_ERROR)
Fired when the Jodit script fails to load (network error, Content Security Policy block, or a missing window.Jodit global after load), or when the Jodit constructor throws. Components waiting for the script are notified and will not initialize.
| Parameter | Type | Description |
|---|---|---|
wParam | number | Always 0. |
lParam | number | Always 0. |
detail.message | string | Human-readable error description. |
Content Changed (MSG_CHANGE)
Fired when the editor content changes. Jodit fires its 'change' event after every content mutation — typing, toolbar actions, and programmatic setValue() calls — so MSG_CHANGE arrives on every mutation. MSG_INPUT also fires alongside it from the same event, so both messages arrive together on each change.
| Parameter | Type | Description |
|---|---|---|
wParam | number | Always 0. |
lParam | number | Always 0. |
detail.value | string | The current HTML content of the editor. |
Keystroke / Mutation (MSG_INPUT)
Fired on every content mutation alongside MSG_CHANGE. Both messages are dispatched from Jodit's single 'change' event, so there is no distinction between in-progress keystrokes and committed changes. Use this for live counters or previews that need to stay in sync with every edit. If your msgProc handles both messages and you only want to react once per mutation, handle MSG_CHANGE and ignore MSG_INPUT, or vice versa.
case wakaPAC.MSG_INPUT:
this.charCount = event.detail.value.replace(/<[^>]+>/g, '').length;
break;
| Parameter | Type | Description |
|---|---|---|
wParam | number | Always 0. |
lParam | number | Always 0. |
detail.value | string | The current HTML content of the editor. |
Input Complete (MSG_INPUT_COMPLETE)
Fired when an editing interaction is considered complete — on blur, and immediately after a paste has been processed (via Jodit's 'afterPaste' event). Use this to trigger validation or autosave without reacting to every intermediate change.
case wakaPAC.MSG_INPUT_COMPLETE:
this.save(event.detail.value);
break;
| Parameter | Type | Description |
|---|---|---|
wParam | number | Always 0. |
lParam | number | Always 0. |
detail.value | string | The current HTML content of the editor. |
Paste (MSG_PASTE)
Fired before the pasted content is inserted into the editor, giving msgProc the opportunity to inspect or block it. Return false from msgProc to cancel the paste. Jodit fires its 'beforePaste' event with the native ClipboardEvent, so the full clipboard payload is available across all MIME types. If the paste proceeds, MSG_INPUT_COMPLETE fires afterward via 'afterPaste', followed by MSG_CHANGE and MSG_INPUT from the resulting content mutation.
case wakaPAC.MSG_PASTE:
// Block pastes containing script tags
if (event.detail['text/html'].includes('<script')) {
return false;
}
break;
| Parameter | Type | Description |
|---|---|---|
wParam | number | Modifier key bitmask: MK_CONTROL, MK_SHIFT, MK_ALT. |
lParam | number | Length of the plain-text clipboard content in characters. |
detail['text/plain'] | string | Plain-text clipboard content. |
detail['text/html'] | string | HTML clipboard content. |
detail['text/rtf'] | string | RTF clipboard content, if available. |
detail['text/uri-list'] | string | Raw URI-list clipboard content, if available. |
detail.uris | string[] | Parsed URIs from text/uri-list, comments stripped. |
detail.files | object[] | File metadata objects { name, size, type } for any files on the clipboard. |
detail.types | string[] | All MIME types present on the clipboard. |
Focus Gained (MSG_SETFOCUS)
Fired when the editor gains focus.
| Parameter | Type | Description |
|---|---|---|
wParam | number | Always 0. |
lParam | number | Always 0. |
Focus Lost (MSG_KILLFOCUS)
Fired when the editor loses focus. Always fires after MSG_INPUT_COMPLETE on blur.
| Parameter | Type | Description |
|---|---|---|
wParam | number | Always 0. |
lParam | number | Always 0. |
API
All API methods take pacId as their first argument. Methods targeting a pacId not registered as a Jodit component are silently ignored.
WakaJodit.getValue(pacId)
Returns the current HTML content of the editor.
| Parameter | Type | Description |
|---|---|---|
pacId | string | The data-pac-id of the target component. |
Returns string | undefined | Current HTML content, or undefined if the component is not registered. | |
WakaJodit.setValue(pacId, html)
Sets the editor content programmatically. Jodit fires its 'change' event on assignment, which dispatches MSG_INPUT and MSG_CHANGE as normal.
| Parameter | Type | Description |
|---|---|---|
pacId | string | The data-pac-id of the target component. |
html | string | HTML string to set as the editor content. |
Returns void | ||
WakaJodit.focus(pacId)
Moves focus to the editor.
| Parameter | Type | Description |
|---|---|---|
pacId | string | The data-pac-id of the target component. |
Returns void | ||
WakaJodit.setReadOnly(pacId, readOnly)
Toggles read-only mode. In read-only mode the editor content is visible but cannot be edited. Delegates to Jodit's setReadOnly(bool) method — no lock ID is required.
| Parameter | Type | Description |
|---|---|---|
pacId | string | The data-pac-id of the target component. |
readOnly | boolean | true to enable read-only mode, false to restore editing. |
Returns void | ||
Form Submission
Jodit retains the original <textarea> in the DOM and keeps it synchronized automatically on every change. No proxy element or extra handling is needed — native form posts work without any additional setup.
When using the <waka-jodit> custom element, the plugin creates a hidden <textarea> inside it and initializes Jodit on that element. The proxy textarea inherits the name attribute from the custom element, so form submission works identically to the attribute-based pattern.
Best Practices
- Register once: Call
wakaPAC.use(WakaJodit)once before creating any components. The Jodit script is shared across all instances on the page. - No license key required: Jodit is MIT-licensed. The CDN build from jsDelivr is free to use without registration or an API key.
- Wait for MSG_EDITOR_READY: Do not call
WakaJodit.setValue()programmatically before this message fires. TheJoditconstructor is synchronous, but the'ready'event that triggersMSG_EDITOR_READYfires asynchronously once the toolbar has fully bootstrapped. - Use MSG_INPUT_COMPLETE for validation and autosave: Prefer
MSG_INPUT_COMPLETEoverMSG_CHANGEfor expensive operations. It fires on blur and after paste — not on every mutation. - Handling MSG_INPUT and MSG_CHANGE together: Both messages fire together on every mutation. If your
msgProchandles both, make sure the handlers are idempotent or pick one message to act on and ignore the other. - Blocking paste: Return
falsefrommsgProcwhen handlingMSG_PASTEto cancel the paste. Unlike CKEditor, the full clipboard payload is available across all MIME types, includingtext/html, before Jodit's own processing runs. - No manual cleanup needed: The plugin calls
editor.destruct()automatically when the component is destroyed. Jodit removes its editor UI and restores the original textarea to its pre-init state. - Pin a Jodit version in production: The default CDN URL uses
jodit@latest, which will pick up new major versions automatically. For production use, pin a specific version in yoursrcoption (e.g./assets/jodit/jodit.min.jsfrom a specific release) to avoid unexpected breaking changes.