### Install KaTeX Source: https://github.com/jihong88/suneditor/blob/master/guide/external-libraries.md Install KaTeX using npm for rendering LaTeX math formulas. ```bash npm install katex ``` -------------------------------- ### Install MathJax Source: https://github.com/jihong88/suneditor/blob/master/guide/external-libraries.md Install the MathJax library using npm. This is the first step to enable MathJax support in the editor. ```bash npm install mathjax-full ``` -------------------------------- ### Install CodeMirror Source: https://github.com/jihong88/suneditor/blob/master/guide/external-libraries.md Install CodeMirror using npm for syntax highlighting in code view. ```bash npm install codemirror ``` -------------------------------- ### Start Local Development Server Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Use this command to start a local development server. It's useful for making and previewing changes during development. ```bash npm run dev # Start local dev server (http://localhost:8088) npm start # Alias for npm run dev ``` -------------------------------- ### Example Changes Log Entry Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md An example of a security-related change entry in the `changes.md` file. ```markdown ## Security - 2026-03-29 - **html:** Block obfuscated `javascript:` protocol in href/src attributes (entity/URL-encoded whitespace bypass) ``` -------------------------------- ### Example Conventional Commit Source: https://github.com/jihong88/suneditor/blob/master/CONTRIBUTING.md A comprehensive example demonstrating a 'feat' commit with a detailed body explaining the changes and linking to a closed issue. ```text feat(#1541): add table cell merge functionality - Implement horizontal and vertical merge - Add merge/unmerge buttons to table controller - Update table serialization logic Closes #1541 ``` -------------------------------- ### JavaScript Plugin Example Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Create a custom command plugin in JavaScript. This example defines a 'helloWorld' plugin that inserts 'Hello, World!' into the editor. ```javascript import { PluginCommand } from 'suneditor/src/interfaces'; import { dom } from 'suneditor/src/helper'; class HelloWorld extends PluginCommand { static key = 'helloWorld'; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance */ constructor(kernel) { super(kernel); this.title = 'Hello World'; this.icon = 'HW'; } /** * @override * @type {PluginCommand['action']} */ action() { this.$.html.insert('

Hello, World!

'); this.$.history.push(false); } } export default HelloWorld; ``` -------------------------------- ### SunEditor Initialization and Hooks Example Source: https://github.com/jihong88/suneditor/blob/master/guide/typedef-guide.md Demonstrates how to initialize SunEditor with options and define a keydown hook. Requires SunEditor instance and type imports. ```typescript import type { SunEditor } from 'suneditor'; // Editor instance const editor: SunEditor.Instance = suneditor.init({ ... }); // Options const options: SunEditor.InitOptions = { width: '100%', height: '400px', buttonList: [['bold', 'italic', '|', 'underline']] }; // Hook parameters function onKeyDown(params: SunEditor.HookParams.KeyEvent): void { const { event, frameContext } = params; // ... } // Component info function handleComponent(info: SunEditor.ComponentInfo): void { console.log(info.pluginName, info.target); } ``` -------------------------------- ### Install SunEditor via NPM Source: https://github.com/jihong88/suneditor/blob/master/README.md Install the SunEditor package using NPM. This is the recommended method for most projects. ```bash npm install suneditor --save ``` -------------------------------- ### TypeScript Plugin Example Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Create a custom command plugin in TypeScript. This example defines a 'helloWorld' plugin that inserts 'Hello, World!' into the editor, including type annotations. ```typescript import { PluginCommand } from 'suneditor/src/interfaces'; import type { SunEditor } from 'suneditor/types'; class HelloWorld extends PluginCommand { static key = 'helloWorld'; constructor(kernel: SunEditor.Kernel) { super(kernel); this.title = 'Hello World'; this.icon = 'HW'; } action(): void { this.$.html.insert('

Hello, World!

'); this.$.history.push(false); } } export default HelloWorld; ``` -------------------------------- ### Cross-Plugin-Type Composition Example Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Demonstrates how a plugin can implement multiple plugin types to offer various interaction modes, such as input, command, and dropdown functionalities. ```plaintext FontSize extends PluginInput ← base type (toolbar input) @implements {PluginCommand} ← provides action() for inc/dec buttons @implements {PluginDropdown} ← provides on() for dropdown menu ``` -------------------------------- ### Plugin Base Type Examples Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Illustrates the different base classes a plugin can extend to define its primary type and lifecycle methods. ```plaintext extends PluginModal → type: 'modal' (required: open()) extends PluginCommand → type: 'command' (required: action()) extends PluginInput → type: 'input' (optional: toolbarInputKeyDown/Change) extends PluginDropdown → type: 'dropdown' (required: action()) ``` -------------------------------- ### Example: Active Hook for Blockquote Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Demonstrates the `active` hook for the `Editor.EventManager`. This example updates the toolbar button's active state based on the selected element's node name. ```javascript /** * @hook Editor.EventManager * @type {SunEditor.Hook.Event.Active} */ active(element, target) { if (/^BLOCKQUOTE$/i.test(element?.nodeName)) { dom.utils.addClass(target, 'active'); return true; } dom.utils.removeClass(target, 'active'); return false; } ``` -------------------------------- ### Plugin Dependency Access Example Source: https://github.com/jihong88/suneditor/blob/master/ARCHITECTURE.md Demonstrates how a PluginCommand accesses the dependency bag ('$') via the KernelInjector in its constructor and uses it to retrieve language strings and format nodes. ```javascript import { PluginCommand } from '../../interfaces'; class Blockquote extends PluginCommand { static key = 'blockquote'; constructor(kernel) { super(kernel); // KernelInjector → this.$ = kernel.$ (Deps bag) this.title = this.$.lang.tag_blockquote; } action() { const node = this.$.selection.getNode(); this.$.format.applyBlock(this.quoteTag.cloneNode(false)); } } ``` -------------------------------- ### Example Security Report Email Subjects Source: https://github.com/jihong88/suneditor/blob/master/SECURITY.md These are examples of how to format the subject line for security vulnerability reports. ```text [Security] XSS vulnerability in editor preview ``` ```text [Security] Possible HTML injection via paste handler ``` -------------------------------- ### Enter Key Event Flow Example Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Traces the sequence of events and function calls when a user presses the Enter key in the editor, from event capture to DOM update. ```text 1. User presses Enter ↓ 2. handler_ww_key.js captures keydown event ↓ 3. keydown.reducer.js analyzes the event with current editor state ↓ 4. Reducer delegates to keydown.rule.enter.js for Enter-specific logic ↓ 5. Returns action list: [{t: 'enter.line.addDefault', p: {...}}, {t: 'history.push', p: {...}}] ↓ 6. executor.js dispatches actions through effect registries (common + keydown) ↓ 7. Effects execute: - 'enter.line.addDefault' → calls format.addLine() - 'history.push' → calls history.push() ↓ 8. DOM updated, selection adjusted, onChange event triggered ``` -------------------------------- ### Implement a PluginBrowser for SunEditor Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Create a custom plugin that opens a gallery or browser interface. This example shows how to integrate with the Browser module for selecting items. ```javascript import { PluginBrowser } from 'suneditor/src/interfaces'; import Browser from 'suneditor/src/modules/contract/Browser'; class MyGallery extends PluginBrowser { static key = 'myGallery'; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance */ constructor(kernel) { super(kernel); this.title = 'My Gallery'; this.icon = 'image'; this.browser = new Browser(this, this.$ /* browser config */); } open(onSelectFunction) { this.browser.open(onSelectFunction); } close() { this.browser.close(); } } ``` -------------------------------- ### Implement PluginCommand for Toggling Strikethrough Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Use PluginCommand for simple actions triggered by a button click. This example shows how to create a strikethrough toggle plugin. ```javascript import { PluginCommand } from 'suneditor/src/interfaces'; import { dom } from 'suneditor/src/helper'; class ToggleStrikethrough extends PluginCommand { static key = 'toggleStrikethrough'; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance */ constructor(kernel) { super(kernel); this.title = 'Strikethrough'; this.icon = 'strikethrough'; // built-in icon key, or raw SVG/HTML } /** * @hook Editor.EventManager * @type {SunEditor.Hook.Event.Active} */ active(element, target) { if (/^S$/i.test(element?.nodeName)) { dom.utils.addClass(target, 'active'); return true; } dom.utils.removeClass(target, 'active'); return false; } /** * @override * @type {PluginCommand['action']} */ action() { const node = dom.utils.createElement('S'); this.$.inline.apply(node, { stylesToModify: null, nodesToRemove: null }); } } ``` -------------------------------- ### Module Dependency Access Example Source: https://github.com/jihong88/suneditor/blob/master/ARCHITECTURE.md Illustrates a Module ('Modal') receiving the dependency bag ('$') directly in its constructor and using it to add event listeners. ```javascript class Modal { #$; constructor(inst, $, element) { this.#$ = $; // Deps bag passed directly, no inheritance this.inst = inst; this.#$.eventManager.addEvent(element, 'submit', ...); } } ``` -------------------------------- ### SunEditor Initialization with Custom Options (JavaScript) Source: https://github.com/jihong88/suneditor/blob/master/test/dev/cdn_test.html Initializes a SunEditor instance with a specific toolbar configuration and various plugin-specific options. This example demonstrates how to set up the editor for features like math, file uploads, image galleries, and autocomplete. ```javascript const editorInstance = SUNEDITOR.create(document.querySelector('#editor_classic'), { plugins: SUNEDITOR.plugins, // allowedClassName: '.+', // attributeWhitelist: { '*': 'class|data-.+' }, // statusbar_container: '#root_statusbar_container', // shortcutsHint: false, // codeMirror: { // EditorView: EditorView, // extensions: [ // basicSetup, // html({ // matchClosingTags: true, // autoCloseTags: true // }), // javascript() // ], // minimalSetup: minimalSetup // }, iframe: false, // defaultLine: 'div', toolbar_sticky: 0, lineAttrReset: 'id', buttonList: bl, subToolbar: { buttonList: [['bold', 'dir', 'dir_ltr', 'dir_rtl', 'save']], width: 'auto', mode: 'balloon' // balloon, balloon-always, balloon-block }, math: { fontSizeList: [ { text: '1', value: '1em' }, { text: '1.5', value: '1.5em' } ] }, fileUpload: { uploadUrl: 'http://localhost:3000/editor/files/upload' }, imageGallery: { url: 'https://etyswjpn79.execute-api.ap-northeast-1.amazonaws.com/suneditor-demo' }, image: { uploadUrl: 'http://localhost:3000/editor/upload' }, autocomplete: { delayTime: 150, limitSize: 8, searchStartLength: 0, useCachingData: true, useCachingFieldData: true, triggers: { // ── @ Mention (API) ── '@': { limitSize: 5, apiUrl: 'https://74iuojmw16.execute-api.ap-northeast-1.amazonaws.com/suneditor-demo/SunEditor-sample-mention/{key}?limit={limitSize}', // apiHeaders: { Authorization: 'Bearer ...' }, // transformResponse: (json, xhr) => json.data, renderItem: (item) => '
' + '@' + item.key + '' + '' + item.name + '' + '
', onSelect: (item, t) => ({ tag: 'a', attrs: { 'data-se-autocomplete': t + item.key, href: item.url, title: item.name, target: '_blank' }, text: t + item.key }) }, // ── : Emoji (static data) ── ':': { searchStartLength: 2, limitSize: 10, useCachingFieldData: false, data: [ { key: 'smile', value: '😊' }, { key: 'laugh', value: '😂' }, { key: 'heart', value: '❤️' }, { key: 'thumbsup', value: '👍' }, { key: 'fire', value: '🔥' }, { key: 'star', value: '⭐' }, { key: 'rocket', va ] } } } }); ``` -------------------------------- ### Example HTML Structure with Inline Component Source: https://github.com/jihong88/suneditor/blob/master/ARCHITECTURE.md Illustrates the DOM structure of SunEditor content, showing how inline components like math formulas are embedded within lines. ```html

Line 1: text with E=mc^2 formula

Line 2: quoted text

``` -------------------------------- ### SunEditor Plugin Access Pattern Example Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Demonstrates how plugins access dependencies through the 'this.$' (Deps bag) and extend base plugin classes like PluginModal. ```javascript import { PluginModal } from '../../interfaces'; class MyPlugin extends PluginModal { static key = 'myPlugin'; static className = 'se-btn-my-plugin'; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance */ constructor(kernel, pluginOptions) { super(kernel); // KernelInjector → this.$ = kernel.$ (Deps bag) this.title = this.$.lang.myPlugin; // access via Deps this.icon = 'myPlugin'; } open(target) { const range = this.$.selection.get(); const wysiwyg = this.$.frameContext.get('wysiwyg'); const height = this.$.frameOptions.get('height'); this.$.html.insert('

content

'); this.$.history.push(false); } } ``` -------------------------------- ### Core Logic Class Dependency Access Example Source: https://github.com/jihong88/suneditor/blob/master/ARCHITECTURE.md Shows a Core Logic class ('Component') receiving the Kernel in its constructor and accessing the dependency bag ('$'), store, options, and event manager. ```javascript class Component { #kernel; #$; #store; constructor(kernel) { this.#kernel = kernel; // Kernel (runtime container) this.#$ = kernel.$; // Deps bag (shared dependency object) this.#store = kernel.store; // Store (runtime state) // Cache frequently used services from Deps this.#options = this.#$.options; this.#frameContext = this.#$.frameContext; this.#eventManager = this.#$.eventManager; } } ``` -------------------------------- ### Register Custom Plugin Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Register a custom plugin with SunEditor. This example shows how to import the plugin and include it in the editor's options. ```javascript import SUNEDITOR from 'suneditor'; import plugins from 'suneditor/src/plugins'; import HelloWorld from './plugins/helloWorld'; SUNEDITOR.create('editor', { plugins: [...plugins, HelloWorld], buttonList: [['bold', 'italic', 'helloWorld']], }); ``` -------------------------------- ### TypeScript Plugin with Implements Keyword Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Shows a TypeScript example of a plugin implementing multiple interfaces using the 'implements' keyword. This approach leverages TypeScript's static typing for better code maintainability. ```typescript import { interfaces } from 'suneditor'; import type { SunEditor } from 'suneditor/types'; class FontSize extends interfaces.PluginInput implements interfaces.PluginCommand, interfaces.PluginDropdown { static key = 'fontSize'; toolbarInputKeyDown(params: SunEditor.HookParams.ToolbarInputKeyDown): void { ... } toolbarInputChange(params: SunEditor.HookParams.ToolbarInputChange): void { ... } action(target: HTMLElement): void { ... } on(target: HTMLElement): void { ... } } ``` -------------------------------- ### Develop a PluginModal for SunEditor Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Create a custom plugin that opens a modal dialog for user input. This example demonstrates how to build and manage a modal for inserting code. ```javascript import { PluginModal } from 'suneditor/src/interfaces'; import Modal from 'suneditor/src/modules/contract/Modal'; import { dom } from 'suneditor/src/helper'; class InsertCode extends PluginModal { static key = 'insertCode'; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance */ constructor(kernel) { super(kernel); this.title = 'Insert Code'; this.icon = 'code'; // Build modal HTML const modalEl = dom.utils.createElement( 'div', null, `
Insert Code
`, ); this.modal = new Modal(this, this.$, modalEl); this.textarea = modalEl.querySelector('textarea'); } /** * @override * @type {PluginModal['open']} */ open() { this.modal.open(); } /** * @hook Modules.Modal * @type {SunEditor.Hook.Modal.Action} */ async modalAction() { const code = this.textarea.value; if (!code) return false; // close loading only const pre = dom.utils.createElement('PRE'); const codeEl = dom.utils.createElement('CODE'); codeEl.textContent = code; pre.appendChild(codeEl); this.$.html.insert(pre.outerHTML); this.$.history.push(false); return true; // close modal + loading } /** * @hook Modules.Modal * @type {SunEditor.Hook.Modal.On} */ modalOn(isUpdate) { if (!isUpdate) this.textarea.value = ''; this.textarea.focus(); } /** * @hook Modules.Modal * @type {SunEditor.Hook.Modal.Off} */ modalOff() { this.textarea.value = ''; } } ``` -------------------------------- ### JavaScript Plugin with JSDoc Implements Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Provides a JavaScript example of a plugin implementing multiple interfaces using JSDoc tags for type hints. This pattern is useful for composing different interaction modes. ```javascript import { PluginCommand, PluginDropdown, PluginInput } from 'suneditor/src/interfaces'; void PluginCommand; void PluginDropdown; /** * @implements {PluginCommand} * @implements {PluginDropdown} */ class FontSize extends PluginInput { static key = 'fontSize'; // PluginInput base toolbarInputKeyDown(params) { /* handle arrow keys, enter */ } toolbarInputChange(params) { /* apply typed value */ } // PluginCommand (implements) — inc/dec button clicks action(target) { /* adjust font size */ } // PluginDropdown (implements) — dropdown open on(target) { /* highlight active size in list */ } } ``` -------------------------------- ### Define Mouse Event Handler with JSDoc Source: https://github.com/jihong88/suneditor/blob/master/guide/typedef-guide.md Use JSDoc to type hint parameters for event handlers. This example shows how to define the expected structure for mouse event parameters. ```javascript /** * @param {SunEditor.HookParams.MouseEvent} params */ function onMouseDown(params) { const { event, frameContext, target } = params; // } ``` -------------------------------- ### Implement Custom Plugin with Event Hooks Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Example of a custom plugin that intercepts the `onKeyDown` event to handle the Tab key, preventing default behavior and inserting spaces. Returning `false` stops further event processing. ```javascript class MyPlugin extends PluginField { static options = { eventIndex: 100, // Default priority (lower = earlier) eventIndex_onKeyDown: 50, // Override: run onKeyDown earlier eventIndex_onInput: 200, // Override: run onInput later }; /** * @hook Editor.EventManager * @type {SunEditor.Hook.Event.OnKeyDown} */ onKeyDown({ event, range }) { if (event.key === 'Tab') { event.preventDefault(); this.$.html.insert(' '); return false; // Stop further processing } } } ``` -------------------------------- ### SunEditor State Management API Source: https://github.com/jihong88/suneditor/blob/master/ARCHITECTURE.md Demonstrates how to read, write, and subscribe to state changes within the SunEditor's store. Use 'get' to read values, 'set' to update and notify subscribers, and 'subscribe' for reactive updates. ```javascript const rootKey = store.get('rootKey'); const hasFocus = store.get('hasFocus'); // Write (notifies subscribers) store.set('hasFocus', true); store.set('_preventBlur', false); // Subscribe const unsubscribe = store.subscribe('hasFocus', (newVal, oldVal) => { ... }); unsubscribe(); // cleanup ``` -------------------------------- ### Correct Plugin Instantiation Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Demonstrates the correct way to pass plugin class references to the options. This ensures the Kernel can manage the plugin's lifecycle. ```javascript // Correct plugins: [MyPlugin]; ``` -------------------------------- ### Build Project for Production Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Builds a minified version of the project, optimized for production deployment. ```bash npm run build:prod # Build for production (minified) ``` -------------------------------- ### Initialize SunEditor with NPM Source: https://github.com/jihong88/suneditor/blob/master/README.md Import necessary CSS and the SunEditor library, then create an editor instance. Ensure you have an HTML element with the ID 'editor' or a textarea with the same ID. ```javascript import 'suneditor/css/editor'; // Editor UI import 'suneditor/css/contents'; // For displaying HTML import suneditor from 'suneditor'; // HTML:
or suneditor.create(document.querySelector('#editor'), { // options }); ``` -------------------------------- ### Build Project for Development Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Builds the project with source maps included, suitable for debugging during development. ```bash npm run build:dev # Build for development (with source maps) ``` -------------------------------- ### Plugin Registration Options Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Illustrates the two ways to register plugins: as an array of class references or as an object mapping names to class references. ```javascript options.plugins: [ImagePlugin, VideoPlugin, ...] // or { image: ImagePlugin, video: VideoPlugin, ... } ``` -------------------------------- ### Run Playwright End-to-End Tests Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Executes Playwright end-to-end tests. The web server will start or reuse an existing instance on localhost:8088. ```bash npm run test:e2e # Run Playwright E2E tests (webServer starts/reuses localhost:8088) ``` -------------------------------- ### SunEditor Plugin Inheritance Chain Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Illustrates the inheritance hierarchy for SunEditor plugins, starting from KernelInjector and extending to specific plugin types. ```text KernelInjector → Base → PluginCommand/PluginModal/PluginDropdown/... ↓ constructor(kernel) → super(kernel) → this.$ = kernel.$ ``` -------------------------------- ### Create SunEditor Instance with Plugins and Button List Source: https://github.com/jihong88/suneditor/blob/master/test/e2e/test.html Initializes a SunEditor instance with a comprehensive set of plugins and a custom button list. Exposes the editor instance globally for testing. ```javascript import suneditor from '../../src/suneditor.js'; import plugins from '../../src/plugins/index.js'; const editor = suneditor.create('editor', { plugins: plugins, buttonList: [ ['undo', 'redo'], ['font', 'fontSize', 'blockStyle'], ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript'], ['fontColor', 'hiliteColor'], ['removeFormat'], ['outdent', 'indent'], ['align', 'horizontalRule', 'list', 'lineHeight'], ['table', 'link', 'image', 'video', 'audio'], ['fullScreen', 'showBlocks', 'codeView'], ['preview', 'print'] ], width: '100%', height: 'auto', minHeight: '400px' }); // Expose editor globally for Playwright tests window.suneditor = editor; ``` -------------------------------- ### SunEditor Initialization Order Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md The sequence of steps involved in creating and initializing a SunEditor instance, from the initial create call to the final onload event. ```text 1. suneditor.create() → Validates target, merges options 2. new Editor() → Creates editor instance 3. Constructor() → Builds DOM (toolbar, statusbar, wysiwyg frames) 4. new CoreKernel() → Kernel (runtime container) a. L1: Store (state management) b. Deps Phase 1: Config deps added to $ (L2) c. L3: Logic instances created (dom, shell, panel) d. Deps Phase 2: Logic deps added to $ (Deps bag complete) e. L3 Init Pass: _init() called on L3 instances that need post-Phase 2 setup f. L4: EventOrchestrator 5. editor.#Create() → Plugin registration, event setup 6. editor.#editorInit() → Frame init, triggers onload event ``` -------------------------------- ### Configure KaTeX with SunEditor Source: https://github.com/jihong88/suneditor/blob/master/guide/external-libraries.md Configure SunEditor to use KaTeX for math formula rendering. Ensure KaTeX library and CSS are imported. ```javascript import katex from 'katex'; import 'katex/dist/katex.css'; import SUNEDITOR from 'suneditor'; import plugins from 'suneditor/src/plugins'; const editor = SUNEDITOR.create('editor', { plugins: plugins, buttonList: [['math']], externalLibs: { katex: { src: katex, options: { // Optional: KaTeX render options throwOnError: false, displayMode: true, }, }, }); ``` -------------------------------- ### Auto-fix Formatting Issues with ESLint Source: https://github.com/jihong88/suneditor/blob/master/CONTRIBUTING.md Run this command to automatically fix code formatting issues according to the project's ESLint configuration. Ensure you have Node.js v14+ installed. ```bash npm run lint:fix-all ``` -------------------------------- ### KaTeX CDN Usage (JavaScript) Source: https://github.com/jihong88/suneditor/blob/master/guide/external-libraries.md Initialize SunEditor with KaTeX using global variables when loaded via CDN. ```javascript // katex is available as global variable SUNEDITOR.create('editor', { externalLibs: { katex: { src: katex, }, }); ``` -------------------------------- ### Implement PluginDropdown for Custom Text Alignment Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Use PluginDropdown to create plugins with dropdown menus. This example implements a custom text alignment plugin with predefined alignment options. ```javascript import { PluginDropdown } from 'suneditor/src/interfaces'; import { dom } from 'suneditor/src/helper'; /** * @typedef {Object} CustomAlignPluginOptions * @property {Array.<"right"|"center"|"left"|"justify">} [items] - Align items */ class CustomAlign extends PluginDropdown { static key = 'customAlign'; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance * @param {CustomAlignPluginOptions} pluginOptions */ constructor(kernel, pluginOptions) { super(kernel); this.title = this.$.lang.align; this.icon = 'align_left'; // Build dropdown HTML const menu = dom.utils.createElement( 'div', { class: 'se-dropdown se-list-layer' }, `
`, ); // Register dropdown target this.$.menu.initDropdownTarget(CustomAlign, menu); } /** * @override * @type {PluginDropdown['on']} */ on(target) { // Called when dropdown opens. Update active states. } /** * @override * @type {PluginDropdown['action']} */ action(target) { const value = target.getAttribute('data-command'); if (!value) return; const lines = this.$.format.getLines(); for (const line of lines) { dom.utils.setStyle(line, 'textAlign', value); } this.$.menu.dropdownOff(); this.$.focusManager.focus(); this.$.history.push(false); } } ``` -------------------------------- ### SunEditor Factory Entry Point and Editor Facade Source: https://github.com/jihong88/suneditor/blob/master/ARCHITECTURE.md The public entry point `suneditor.js` validates options and creates the editor instance. `editor.js` acts as the Facade, orchestrating initialization and exposing minimal public methods. ```javascript /** * @description Factory Entry Point * @param {Element | string} target - Target element or selector * @param {object} options - Editor initialization options * @returns {Editor} - SunEditor instance */ function create(target, options) { // ... implementation details ... return new Editor(target, options); } /** * @description Initializes the editor with options. * @param {object} options - Editor initialization options * @returns {{create: function(Element|string, object): Editor}} - Object with create function */ function init(options) { // ... implementation details ... return { create: function(target, options) { return create(target, options); } }; } ``` ```javascript /** * @description Main Editor Class - Facade */ class Editor { constructor(target, options) { // ... initialization logic ... } /** * @description Checks if the editor is empty. * @returns {boolean} - True if empty, false otherwise. */ isEmpty() { // ... implementation details ... } /** * @description Resets editor options. * @param {object} options - New options to reset with. */ resetOptions(options) { // ... implementation details ... } /** * @description Changes the frame context of the editor. * @param {string} context - The new frame context. */ changeFrameContext(context) { // ... implementation details ... } /** * @description Destroys the editor instance. */ destroy() { // ... implementation details ... } // Internal properties and methods // Plugin lifecycle, multi-root, frame init // $ (Deps) object for full API access } ``` -------------------------------- ### Create a PluginField for Input Event Detection in SunEditor Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Develop a custom plugin that responds to editor input events. This example demonstrates detecting hashtags using the `onInput` hook and debouncing. ```javascript import { PluginField } from 'suneditor/src/interfaces'; import { converter } from 'suneditor/src/helper'; class HashtagDetector extends PluginField { static key = 'hashtagDetector'; static className = ''; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance */ constructor(kernel) { super(kernel); this.onInput = converter.debounce(this.onInput.bind(this), 200); } /** * @hook Editor.EventManager * @type {SunEditor.Hook.Event.OnInput} */ onInput({ frameContext }) { const sel = this.$.selection.get(); const text = sel.anchorNode?.textContent || ''; const before = text.substring(0, sel.anchorOffset); const match = before.match(/#(\w+)$/); if (match) { // Handle hashtag detection console.log('Detected hashtag:', match[1]); } } } ``` -------------------------------- ### Sync Language Files Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Synchronizes language files. This command requires Google API credentials to function correctly. ```bash npm run check:langs # Sync language files (requires Google API credentials) ``` -------------------------------- ### Import DOM Helpers Source: https://github.com/jihong88/suneditor/blob/master/prompts/coding-rules.md Import DOM utility functions once at the top of your file. This includes helpers for general utilities, querying, and checking node types. ```javascript import { dom, numbers, unicode, converter, env, keyCodeMap } from '../../helper'; ``` -------------------------------- ### Module Contracts Implementation Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Shows how a plugin can implement module contracts to hook into specific editor lifecycles and methods. ```typescript class Image extends PluginModal implements ModuleModal, ModuleController, EditorComponent { ... } ``` -------------------------------- ### Run Tests with Coverage Report Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Executes tests and generates a coverage report, showing which parts of the codebase are exercised by the tests. ```bash npm run test:coverage # Run tests with coverage report ``` -------------------------------- ### Line Formatting Application Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md For line-level formatting, use wrappers such as `this.$.format.setLine` which manage history push internally. ```javascript this.$.format.setLine ``` -------------------------------- ### Instantiate SunEditor Modules Source: https://github.com/jihong88/suneditor/blob/master/prompts/coding-rules.md Instantiate core modules like Modal, Controller, and Figure within a plugin. The first argument is the host plugin instance (`this`), and the second is `$`. Order is crucial for lifecycle hooks. ```javascript this.modal = new Modal(this, this.$, modalElement); this.controller = new Controller(this, this.$, controllerElement, { position: 'bottom', disabled: false, parents: [], isWWTarget: true, }); this.figure = new Figure(this, this.$, imgElement, { controls: [['mirror_h', 'mirror_v'], ['caption'], ['remove']], }); ``` -------------------------------- ### Event Handling in onKeyDown Source: https://github.com/jihong88/suneditor/blob/master/ARCHITECTURE.md Demonstrates the three stages of event processing for 'onKeyDown' events, including user-registered callbacks, plugin events, and core processing. ```javascript // Stage 1: User event if ((await this.$.eventManager.triggerEvent('onKeyDown', { frameContext, event })) === false) return; // Stage 2: Plugin event if ((await this._callPluginEventAsync('onKeyDown', { frameContext, event, range, line })) === false) return; // Stage 3: Core processing (reducer → actions → effects) ``` -------------------------------- ### Convert Changes to Release Note Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Converts the content of 'changes.md' into a release note format. ```bash /release-note ``` -------------------------------- ### Configure SunEditor with External Libraries and Autocomplete Source: https://github.com/jihong88/suneditor/blob/master/test/dev/cdn_test.html This snippet shows the configuration for SunEditor, including external libraries like KaTeX and custom autocomplete options for emojis and hashtags. Use this to extend SunEditor's functionality. ```javascript externalLibs: { // codeMirror: { // src: Codemirror5 // }, katex: { src: katex } } }); ``` -------------------------------- ### Register Plugin Class Reference Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Always pass class references to the `plugins` array. The kernel manages instantiation and lifecycle, so avoid passing instances like `new MyPlugin()`. ```javascript // Correct plugins: [MyPlugin]; ``` ```javascript // Wrong — kernel cannot manage lifecycle plugins: [new MyPlugin()]; ``` -------------------------------- ### Configure Math Plugin Options Source: https://github.com/jihong88/suneditor/blob/master/guide/external-libraries.md Customize the math plugin's behavior and appearance using various options. This includes setting font sizes, form dimensions, and resize capabilities. ```javascript SUNEDITOR.create('editor', { externalLibs: { katex: { src: katex }, }, math: { fontSizeList: [ { text: '1', value: '1em' }, { text: '1.5', value: '1.5em' }, { text: '2', value: '2em', default: true }, { text: '2.5', value: '2.5em' }, ], formSize: { width: '460px', height: '14em', minWidth: '400px', minHeight: '40px', maxWidth: '800px', maxHeight: '400px', }, canResize: true, autoHeight: false, onPaste: function (event) { // Custom paste handler for math input }, }, }); ``` -------------------------------- ### Allowed Imports in SunEditor Helpers Source: https://github.com/jihong88/suneditor/blob/master/prompts/coding-rules.md Demonstrates correct import paths for helper modules in SunEditor, showing how to access other layers via the constructor. ```javascript import { PluginCommand } from '../../interfaces'; import { Modal, Controller, Figure } from '../../modules/contract'; import { dom, numbers } from '../../helper'; // inside the class, reach other L3 modules through $: this.$.format.setLine(...); this.$.selection.getRange(); ``` -------------------------------- ### Incorrect Plugin Instantiation Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Shows the incorrect method of passing plugin instances directly. This prevents the Kernel from managing the plugin's lifecycle. ```javascript // Wrong - Kernel cannot manage lifecycle plugins: [new MyPlugin()]; ``` -------------------------------- ### KaTeX CDN Usage (HTML) Source: https://github.com/jihong88/suneditor/blob/master/guide/external-libraries.md Include KaTeX CSS and JavaScript files from a CDN for use in HTML. ```html ``` -------------------------------- ### Create a Word Count Command Plugin Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Implement a command plugin to display the current word count in the editor. This plugin extends `PluginCommand` and uses the kernel instance to access editor content and display a toast notification. ```javascript import { PluginCommand } from 'suneditor/src/interfaces'; class WordCount extends PluginCommand { static key = 'wordCount'; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance */ constructor(kernel) { super(kernel); this.title = 'Word Count'; this.icon = 'WC'; } /** * @override * @type {PluginCommand['action']} */ action() { const text = this.$.html.get({ format: 'text' }); const words = text.trim().split(/\s+/).filter(Boolean).length; this.$.ui.showToast(`Words: ${words}`, 2000); } } export default WordCount; ``` -------------------------------- ### SunEditor Plugin Constructor with Options and Dependencies Source: https://github.com/jihong88/suneditor/blob/master/guide/custom-plugin.md Standard constructor pattern for SunEditor plugins, accepting kernel and plugin-specific options. Manages plugin metadata, UI elements, and internal state. ```javascript /** * @typedef {Object} MyPluginOptions * @property {boolean} [canResize=true] - Whether the element can be resized. * @property {string} [defaultWidth="auto"] - The default width. */ /** * @class * @description MyPlugin description. */ class MyPlugin extends PluginModal { static key = 'myPlugin'; static className = 'se-btn-my-plugin'; /** * @constructor * @param {SunEditor.Kernel} kernel - The Kernel instance * @param {MyPluginOptions} pluginOptions */ constructor(kernel, pluginOptions) { super(kernel); // KernelInjector → this.$ = kernel.$ (Deps bag) // Plugin metadata (used by toolbar button) this.title = this.$.lang.myPlugin || 'My Plugin'; this.icon = 'myPlugin'; // icon key from this.$.icons, or raw HTML/SVG // Optional: toolbar button content and layout this.inner = null; // string (HTML) | HTMLElement | false (hide) | null (use icon) this.beforeItem = null; // HTMLElement to insert before the button this.afterItem = null; // HTMLElement to insert after the button this.replaceButton = null; // HTMLElement to replace the entire default button // Plugin members this.myState = {}; // Module instances (if using Modal, Controller, etc.) this.modal = new Modal(this, this.$, modalElement); this.controller = new Controller(this, this.$, controllerElement, { position: 'bottom' }); } } ``` -------------------------------- ### Check Architecture Dependencies Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Uses dependency-cruiser to check architecture dependencies, helping to enforce project structure rules. ```bash npm run check:arch # Check architecture dependencies with dependency-cruiser ``` -------------------------------- ### Enable Plugins in SunEditor Source: https://github.com/jihong88/suneditor/blob/master/README.md Configure the SunEditor instance to include specific plugins like 'font', 'image', and 'video'. Set the image upload URL for the image plugin. ```js suneditor.create('#editor', { plugins: ['font', 'image', 'video'], image: { uploadUrl: 'https://upload.image', }, }); ``` -------------------------------- ### Format for Changes Log Entries Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Use this markdown format to add entries to the `changes.md` file. New entries should be added at the top. ```markdown ## [Category] - YYYY-MM-DD - **tag:** Short description of the change ``` -------------------------------- ### Migrate tagStyles options Source: https://github.com/jihong88/suneditor/blob/master/release-note.md Before: Separate spanStyles, lineStyles, and tagStyles. After: Unified into tagStyles with category defaults like @text and @line. ```javascript // Before { spanStyles: 'color|font-size', lineStyles: 'text-align|margin', tagStyles: { div: 'color' } } // After { tagStyles: { '@text': 'color|font-size', '@line': 'text-align|margin', div: 'color' } } ``` -------------------------------- ### Build TypeScript Definitions Source: https://github.com/jihong88/suneditor/blob/master/GUIDE.md Builds TypeScript definition files from JSDoc comments. Essential for improving TypeScript integration. ```bash npm run ts-build # Build TypeScript definitions from JSDoc ```