أنت مهندس معماري خبير في إضافات CKEditor 5.
أحتاج منك تطوير إضافة CKEditor 5 كاملة باسم "NewsletterPlugin".
السياق:
- هذا العمل عبارة عن ترحيل من إضافة قديمة مبنية على CKEditor 4.
- يجب الالتزام الصارم بمعمارية CKEditor 5.
- يجب استخدام إطار واجهة المستخدم الخاص بـ CKEditor 5 ونظام الإضافات Plugin system.
- يجب اتباع التوثيق التالي:
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 (custom build)
- ES6 modules
- يُفضّل TypeScript إن أمكن
- لا يُسمح باستخدام أي واجهات API خاصة بـ CKEditor 4
========================================
متطلبات الميزات
========================================
1) زر في شريط الأدوات:
- أضف زرًا في شريط الأدوات باسم "newsletter"
- الأيقونة: عنصر SVG بسيط كعنصر نائب (placeholder)
- عند الضغط عليه → افتح مربّع حوار (modal dialog)
2) سلوك مربّع الحوار:
يجب أن يحتوي مربّع الحوار على حقول الإدخال التالية:
- title (text input)
- description (textarea)
- tabs (قائمة تبويبات ديناميكية، يستطيع المستخدم إضافة عناصر التبويب أو حذفها)
يحتوي كل عنصر تبويب على:
- 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) السلوك داخل المحرر:
- يكون التبويب الأول نشطًا (active) دائمًا بشكل افتراضي.
- عندما يضغط المستخدم على رابط التبويب <a>:
- أزل الصنف "active" من جميع التبويبات ولوحات المحتوى (panes)
- أضف الصنف "active" إلى التبويب الذي تم الضغط عليه ولوحة المحتوى المرتبطة به
- عند الضغط المزدوج على <a>:
- افتح مربّع الحوار مرة أخرى
- حمّل البيانات الموجودة
- اسمح بالتعديل
- حدّث بنية HTML
5) يجب استخدام:
- GeneralHtmlSupport (GHS) للسماح بالأصناف والسمات المخصّصة (custom classes & attributes)
- محولات upcast / downcast بشكل صحيح
- Widget API مثل toWidget و toWidgetEditable عند الحاجة
- صنف أمر (Command class)
- نظام مكوّنات واجهة المستخدم UI Component system مثل ButtonView و View و InputTextView
- فصل جزء Editing عن جزء UI
- تسجيل الـ Schema بطريقة صحيحة
6) المعمارية المطلوبة:
أنشئ البنية التالية:
- newsletter/
- newsletterplugin.ts
- newsletterediting.ts
- newsletterui.ts
- newslettercommand.ts
7) المتطلبات التقنية:
- سجّل عنصر Schema باسم:
newsletterBlock
- يجب السماح بما يلي:
class
id
href
data attributes
- استخدم:
editor.model.change()
conversion.for('upcast')
conversion.for('downcast')
- تعامل مع حدث النقر عبر مستند الـ editing view
- استخدم editing.view.document.on( 'click', ... )
- اكتشف حدث النقر المزدوج
8) مهم:
لا تستخدم التعامل المباشر مع DOM (raw DOM manipulation) نهائيًا.
يجب أن تتم جميع التحديثات عبر editor.model.
9) المطلوب في المخرجات:
- كود الإضافة كامل
- imports صحيحة
- تعليقات توضّح المعمارية
- شرح فروقات الترحيل من CKEditor 4
- توضيح طريقة تسجيل الإضافة داخل الـ build
10) إضافي:
اشرح طريقة تفعيل إعداد GeneralHtmlSupport داخل إعدادات المحرر.
========================================
قدّم كودًا نظيفًا وجاهزًا للإنتاج.
لا تختصر المنطق.
التزم بدقة بأفضل ممارسات CKEditor 5.