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.

explanation

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.

ParameterTypeDescription
wParamnumberAlways 0.
lParamnumberAlways 0.
detail.valuestringThe 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.

ParameterTypeDescription
wParamnumberAlways 0.
lParamnumberAlways 0.
detail.messagestringHuman-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.

ParameterTypeDescription
wParamnumberAlways 0.
lParamnumberAlways 0.
detail.valuestringThe 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;
ParameterTypeDescription
wParamnumberAlways 0.
lParamnumberAlways 0.
detail.valuestringThe 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;
ParameterTypeDescription
wParamnumberAlways 0.
lParamnumberAlways 0.
detail.valuestringThe 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;
ParameterTypeDescription
wParamnumberModifier key bitmask: MK_CONTROL, MK_SHIFT, MK_ALT.
lParamnumberLength of the plain-text clipboard content in characters.
detail['text/plain']stringPlain-text clipboard content.
detail['text/html']stringHTML clipboard content.
detail['text/rtf']stringRTF clipboard content, if available.
detail['text/uri-list']stringRaw URI-list clipboard content, if available.
detail.urisstring[]Parsed URIs from text/uri-list, comments stripped.
detail.filesobject[]File metadata objects { name, size, type } for any files on the clipboard.
detail.typesstring[]All MIME types present on the clipboard.

Focus Gained (MSG_SETFOCUS)

Fired when the editor gains focus.

ParameterTypeDescription
wParamnumberAlways 0.
lParamnumberAlways 0.

Focus Lost (MSG_KILLFOCUS)

Fired when the editor loses focus. Always fires after MSG_INPUT_COMPLETE on blur.

ParameterTypeDescription
wParamnumberAlways 0.
lParamnumberAlways 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.

ParameterTypeDescription
pacIdstringThe data-pac-id of the target component.
Returns string | undefinedCurrent 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.

ParameterTypeDescription
pacIdstringThe data-pac-id of the target component.
htmlstringHTML string to set as the editor content.
Returns void

WakaJodit.focus(pacId)

Moves focus to the editor.

ParameterTypeDescription
pacIdstringThe 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.

ParameterTypeDescription
pacIdstringThe data-pac-id of the target component.
readOnlybooleantrue 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. The Jodit constructor is synchronous, but the 'ready' event that triggers MSG_EDITOR_READY fires asynchronously once the toolbar has fully bootstrapped.
  • Use MSG_INPUT_COMPLETE for validation and autosave: Prefer MSG_INPUT_COMPLETE over MSG_CHANGE for 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 msgProc handles both, make sure the handlers are idempotent or pick one message to act on and ignore the other.
  • Blocking paste: Return false from msgProc when handling MSG_PASTE to cancel the paste. Unlike CKEditor, the full clipboard payload is available across all MIME types, including text/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 your src option (e.g. /assets/jodit/jodit.min.js from a specific release) to avoid unexpected breaking changes.