Would "Deep dives" into the Wappler .js components be useful for those looking to extend or interface directly from .js? (yes, it's AI generated). Sorry, some sections repeated, it's just a concept demo! (been cleaned up)
Something like:
Component Overview
This defines a custom Wappler component called summernote, which wraps the Summernote WYSIWYG editor with reactive bindings, configuration options, and event handling.
Initial State & Attributes
Initial Data
initialData: {
disabled: false,
value: ""
}
Supported Attributes
These are the props you can pass to the component:
| Attribute | Type | Default | Description |
|---|---|---|---|
value |
String | "" |
Initial content of the editor |
disabled |
Boolean | false |
Whether the editor is disabled |
config |
Object | {} |
Custom Summernote config |
height, minHeight, maxHeight |
Number | null |
Editor height settings |
autofocus |
Boolean | false |
Auto-focus on load |
lang |
String | "en-US" |
Language setting |
airMode |
Boolean | false |
Enables Air Mode (inline editing) |
toolbar, toolbarImage, toolbarLink, toolbarTable, toolbarAir |
Array | null |
Toolbar configurations |
blockquoteBreakingLevel |
Number | 2 |
Controls blockquote behavior |
styleTags, fontNames, fontNamesIgnoreCheck, fontSizeUnits, lineHeights |
Array | null |
Styling options |
placeholder |
String | null |
Placeholder text |
dialogsInBody, dialogsFade |
Boolean | false |
Dialog behavior |
disableDrop, disableShortcuts, disableTab, disableSpellcheck, disableGrammar |
Boolean | false |
Feature toggles |
codeviewFilter, codeviewIframeFilter |
Boolean | true |
Security filters |
plugins, buttons |
Object | {} |
Custom plugins and buttons |
Methods
These are exposed methods you can call on the component:
enable()/disable()β toggle editor stateempty()β clear contentinsertText(text)β insert plain textpasteHTML(html)β insert HTMLundo()/redo()/reset()β history actionssetValue(value)β set content programmaticallystatus(msg)/info(msg)/success(msg)/warning(msg)/danger(msg)β show status messagesinvoke(method, args)β call any Summernote method directly
Events
These are dispatched by the component:
init,focus,blur,enter,change,changed,input,updatedbuttonclickβ when a custom button is clickedmediadeleteβ when media is removed
Lifecycle Hooks
init()β sets up debounce handlers and Summernote callbacksrender(el)β sets initial content and initializes the editorperformUpdate(changes)β reacts to prop changesdestroy()β cleans up the editor
Internal Logic Highlights
- Toolbar Filtering: Only includes non-empty toolbar groups.
- Popover Setup: Dynamically configures popovers for image, link, table, and air toolbars.
- Language Check: Logs an error if the specified language file isnβt loaded.
- Custom Buttons & Plugins: Watches for
pluginandbuttonattributes and dynamically registers them using Summernoteβs UI API.
Utility Functions
_toCamelCase(str)β converts kebab-case to camelCase$parseAttributes(el)β parses dynamic attributes likepluginandbuttonand wires them into the editor
Visual Flow: Component Lifecycle & Interaction
[Attributes] βββΆ [Initialization] βββΆ [Editor Setup] βββΆ [User Interaction]
β β β β
βΌ βΌ βΌ βΌ
Props like: init() binds render() sets Events like:
value, config callbacks & initial value focus, blur,
toolbar, etc. debounce logic & calls _initEditor change, input
β β β β
βΌ βΌ βΌ βΌ
performUpdate() βββΆ _initEditor() βββΆ Summernote API βββΆ dispatchEvent()
Modular Breakdown
1. Initialization
init() {
this._initEditor = debounce(this._initEditor.bind(this));
this._callbacks = {
callbacks: {
onBlur: this._blurHandler,
onChange: this._changeHandler,
...
}
};
}
2. Editor Setup
render(el) {
if (this.props.value) {
el.tagName === "TEXTAREA" ? el.value = this.props.value : el.innerHTML = this.props.value;
}
this._initEditor();
}
3. Dynamic Updates
performUpdate(changes) {
if (changes.has("value")) this._setValue(this.props.value);
if (changes.has("disabled")) this._editor.invoke(this.props.disabled ? "disable" : "enable");
}
4. Custom Buttons & Plugins
$parseAttributes(el) {
watch("plugin", value => {
this.props.plugins[camelCase(arg)] = { ...defaults, ...value };
});
watch("button", value => {
this.props.buttons[camelCase(arg)] = () => createButton(value);
});
}