Asks for a complete CKEditor 5 plugin, NewsletterPlugin, migrated from a CKEditor 4 plugin while following CKEditor 5 architecture and UI framework.
You are a senior CKEditor 5 plugin architect.
I need you to build a complete CKEditor 5 plugin called "NewsletterPlugin".
Context:
- This is a migration from a legacy CKEditor 4 plugin.
- Must follow CKEditor 5 architecture strictly.
- Must use CKEditor 5 UI framework and plugin system.
- Must follow documentation:
https://ckeditor.com/docs/ckeditor5/latest/framework/architecture/ui-components.html
https://ckeditor.com/docs/ckeditor5/latest/features/html/general-html-support.html
Environment:
- CKEditor 5 custom build
- ES6 modules
- Typescript preferred (if possible)
- No usage of CKEditor 4 APIs
========================================
FEATURE REQUIREMENTS
========================================
1) Toolbar Button:
- Add a toolbar button named "newsletter"
- Icon: simple SVG placeholder
- When clicked → open a dialog (modal)
2) Dialog Behavior:
The dialog must contain input fields:
- title (text input)
- description (textarea)
- tabs (dynamic list, user can add/remove tab items)
Each tab item:
- tabTitle
- tabContent (HTML allowed)
Buttons:
- Cancel
- OK
3) On OK:
- Generate structured HTML block inside editor
- Structure example:
<div class="newsletter">
<ul class="newsletter-tabs">
<li class="active">
<a href="#tab-1" class="active">Tab 1</a>
</li>
<li>
<a href="#tab-2">Tab 2</a>
</li>
</ul>
<div class="newsletter-content">
<div id="tab-1" class="tab-pane active">
Content 1
</div>
<div id="tab-2" class="tab-pane">
Content 2
</div>
</div>
</div>
4) Behavior inside editor:
- First tab always active by default.
- When user clicks <a> tab link:
- Remove class "active" from all tabs and panes
- Add class "active" to clicked tab and corresponding pane
- When user double-clicks <a>:
- Open dialog again
- Load existing data
- Allow editing
- Update HTML structure
5) MUST USE:
- GeneralHtmlSupport (GHS) for allowing custom classes & attributes
- Proper upcast / downcast converters
- Widget API (toWidget, toWidgetEditable if needed)
- Command class
- UI Component system (ButtonView, View, InputTextView)
- Editing & UI part separated
- Schema registration properly
6) Architecture required:
Create structure:
- newsletter/
- newsletterplugin.ts
- newsletterediting.ts
- newsletterui.ts
- newslettercommand.ts
7) Technical requirements:
- Register schema element:
newsletterBlock
- Must allow:
class
id
href
data attributes
- Use:
editor.model.change()
conversion.for('upcast')
conversion.for('downcast')
- Handle click event via editing view document
- Use editing.view.document.on( 'click', ... )
- Detect double click event
8) Important:
Do NOT use raw DOM manipulation.
All updates must go through editor.model.
9) Output required:
- Full plugin code
- Proper imports
- Comments explaining architecture
- Explain migration differences from CKEditor 4
- Show how to register plugin in build
10) Extra:
Explain how to enable GeneralHtmlSupport configuration in editor config.
========================================
Please produce clean production-ready code.
Do not simplify logic.
Follow CKEditor 5 best practices strictly.你是一位资深 CKEditor 5 插件架构师。
我需要你构建一个完整的 CKEditor 5 插件,名为 "NewsletterPlugin"。
上下文:
- 这是从旧版 CKEditor 4 插件迁移而来。
- 必须严格遵循 CKEditor 5 架构。
- 必须使用 CKEditor 5 UI 框架和插件系统。
- 必须遵循文档:
https://ckeditor.com/docs/ckeditor5/latest/framework/architecture/ui-components.html
https://ckeditor.com/docs/ckeditor5/latest/features/html/general-html-support.html
环境:
- CKEditor 5 自定义构建
- ES6 模块
- 推荐使用 Typescript(如可能)
- 不得使用 CKEditor 4 API
========================================
功能需求
========================================
1) 工具栏按钮:
- 添加一个名为 "newsletter" 的工具栏按钮
- 图标:简单的 SVG 占位符
- 点击时 → 打开一个对话框(模态)
2) 对话框行为:
对话框必须包含以下输入字段:
- title(文本输入)
- description(多行文本)
- tabs(动态列表,用户可添加/删除 tab 项)
每个 tab 项:
- tabTitle
- tabContent(允许 HTML)
按钮:
- Cancel
- OK
3) 点击 OK 时:
- 在编辑器内生成结构化 HTML 块
- 结构示例:
<div class="newsletter">
<ul class="newsletter-tabs">
<li class="active">
<a href="#tab-1" class="active">Tab 1</a>
</li>
<li>
<a href="#tab-2">Tab 2</a>
</li>
</ul>
<div class="newsletter-content">
<div id="tab-1" class="tab-pane active">
Content 1
</div>
<div id="tab-2" class="tab-pane">
Content 2
</div>
</div>
</div>
4) 编辑器内的行为:
- 默认第一个 tab 始终处于激活状态。
- 当用户点击 `<a>` tab 链接时:
- 移除所有 tab 和 pane 的 "active" 类
- 为被点击的 tab 及其对应的 pane 添加 "active" 类
- 当用户双击 `<a>` 时:
- 再次打开对话框
- 加载现有数据
- 允许编辑
- 更新 HTML 结构
5) 必须使用:
- GeneralHtmlSupport (GHS) 以允许自定义类和属性
- 正确的上行转换(upcast)/下行转换(downcast)转换器
- Widget API(如需要,使用 toWidget, toWidgetEditable)
- Command 类
- UI 组件系统(ButtonView, View, InputTextView)
- 编辑(Editing)与 UI 部分分离
- 正确注册 Schema
6) 所需架构:
创建以下结构:
- newsletter/
- newsletterplugin.ts
- newsletterediting.ts
- newsletterui.ts
- newslettercommand.ts
7) 技术要求:
- 注册 schema 元素:
newsletterBlock
- 必须允许:
class
id
href
data 属性
- 使用:
editor.model.change()
conversion.for('upcast')
conversion.for('downcast')
- 通过 editing view document 处理点击事件
- 使用 editing.view.document.on( 'click', ... )
- 检测双击事件
8) 重要:
不得使用原始 DOM 操作。
所有更新必须通过 editor.model 进行。
9) 输出要求:
- 完整的插件代码
- 正确的导入语句
- 注释说明架构
- 解释从 CKEditor 4 迁移的差异
- 展示如何在构建中注册插件
10) 额外:
解释如何在编辑器配置中启用 GeneralHtmlSupport 配置。
========================================
请生成干净、可用于生产的代码。
不要简化逻辑。
严格遵循 CKEditor 5 最佳实践。