Bạn là một kiến trúc sư phát triển plugin CKEditor 5 cao cấp.
Tôi cần bạn xây dựng một plugin CKEditor 5 hoàn chỉnh có tên là "NewsletterPlugin".
Bối cảnh:
- Đây là quá trình chuyển đổi (migration) từ một plugin CKEditor 4 cũ.
- Bắt buộc phải tuân thủ nghiêm ngặt kiến trúc của CKEditor 5.
- Bắt buộc phải sử dụng khung giao diện người dùng (UI framework) và hệ thống plugin của CKEditor 5.
- Bắt buộc tuân theo tài liệu chính thức:
https://ckeditor.com/docs/ckeditor5/latest/framework/architecture/ui-components.html
https://ckeditor.com/docs/ckeditor5/latest/features/html/general-html-support.html
Môi trường:
- Bản dựng tùy chỉnh (custom build) CKEditor 5
- Mô-đun ES6 (ES6 modules)
- Ưu tiên sử dụng TypeScript (nếu có thể)
- Không sử dụng bất kỳ API nào của CKEditor 4
========================================
YÊU CẦU TÍNH NĂNG (FEATURE REQUIREMENTS)
========================================
1) Nút trên Thanh công cụ (Toolbar Button):
- Thêm một nút trên thanh công cụ có tên là "newsletter"
- Biểu tượng (Icon): hình giữ chỗ SVG đơn giản
- Khi nhấp vào → mở một hộp thoại (dialog / modal)
2) Hành vi của Hộp thoại (Dialog Behavior):
Hộp thoại phải chứa các trường nhập liệu sau:
- title (ô nhập văn bản text input)
- description (ô nhập văn bản nhiều dòng textarea)
- tabs (danh sách động, người dùng có thể thêm/xóa các mục tab)
Mỗi mục tab bao gồm:
- tabTitle
- tabContent (cho phép nhập mã HTML)
Các nút bấm:
- Cancel (Hủy)
- OK (Đồng ý)
3) Khi nhấn OK:
- Tạo khối HTML có cấu trúc bên trong trình soạn thảo (editor)
- Ví dụ cấu trúc:
<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) Hành vi bên trong trình soạn thảo:
- Tab đầu tiên luôn ở trạng thái active theo mặc định.
- Khi người dùng nhấp vào liên kết tab `<a>`:
- Xóa class "active" khỏi tất cả các tab và khung nội dung (panes)
- Thêm class "active" vào tab vừa nhấp và khung nội dung tương ứng
- Khi người dùng nhấp đúp (double-click) vào thẻ `<a>`:
- Mở lại hộp thoại (dialog)
- Tải dữ liệu hiện có lên hộp thoại
- Cho phép chỉnh sửa
- Cập nhật lại cấu trúc HTML
5) BẮT BUỘC SỬ DỤNG:
- GeneralHtmlSupport (GHS) để cho phép sử dụng các class & thuộc tính tùy chỉnh
- Các bộ chuyển đổi upcast / downcast (converters) chuẩn xác
- Widget API (toWidget, toWidgetEditable nếu cần)
- Lớp Command (Command class)
- Hệ thống UI Component (ButtonView, View, InputTextView)
- Tách biệt rõ phần xử lý dữ liệu (Editing) & phần giao diện (UI)
- Đăng ký Schema đúng quy chuẩn
6) Kiến trúc thư mục yêu cầu:
Tạo cấu trúc tệp như sau:
- newsletter/
- newsletterplugin.ts
- newsletterediting.ts
- newsletterui.ts
- newslettercommand.ts
7) Yêu cầu kỹ thuật:
- Đăng ký phần tử schema:
newsletterBlock
- Phải cho phép các thuộc tính:
class
id
href
các thuộc tính data-* (data attributes)
- Sử dụng:
editor.model.change()
conversion.for('upcast')
conversion.for('downcast')
- Xử lý sự kiện click thông qua tài liệu chế độ xem chỉnh sửa (editing view document)
- Sử dụng `editing.view.document.on( 'click', ... )`
- Phát hiện sự kiện nhấp đúp chuột (double click event)
8) Lưu ý quan trọng:
KHÔNG sử dụng thao tác DOM thô trực tiếp (raw DOM manipulation).
Mọi cập nhật bắt buộc phải đi qua `editor.model`.
9) Đầu ra yêu cầu:
- Toàn bộ mã nguồn đầy đủ của plugin
- Các câu lệnh import chuẩn xác
- Chú thích (comments) giải thích rõ kiến trúc
- Giải thích những điểm khác biệt khi chuyển đổi (migration) từ CKEditor 4 sang
- Hướng dẫn cách đăng ký plugin vào bản dựng (build)
10) Bổ sung:
Giải thích cách bật cấu hình GeneralHtmlSupport trong cấu hình trình soạn thảo (editor config).
========================================
Vui lòng viết mã nguồn sạch, sẵn sàng đưa vào vận hành thực tế (production-ready).
Không tự ý giản lược logic.
Tuân thủ nghiêm ngặt các thực hành tốt nhất (best practices) của CKEditor 5.