إنشاء عناصر مخصصة.
كل عنصر في DXPR Builder كائن JavaScript مدفوع إلى
window.dxprBuilder.dxpr_elements. فيحوّل المحرّر كل كائن
إلى صنف عنصر مع تبويبي النمط والحركة مرفقين أصلًا.
توضح هذه الصفحة كيفية تعريف العناصر المشحونة في
dxpr_builder/dxpr_elements.js، وكيف تضيف الوحدة تعريفها الخاص
إلى المحرّر، وكيف يبدو HTML الناتج.
لا توجد قوالب Twig من جهة الخادم لكل عنصر؛ فالعناصر تُعرض
في المتصفح.
كيف يسجّل المحرّر العناصر
يحمّل المحرّر ستة نصوص بهذا الترتيب، معرّفة في
dxpr_builder_library_info_build() في dxpr_builder.module كمكتبة
dxpr_builder/editor.builder:
dxpr_templates.js: قوالب twig.js من جهة العميل مُجمَّعة منdxpr_builder/templates/.dxpr_global.js: مساعدات مشتركة وتكامل CKEditor 5.dxpr_events.jsdxpr_param_types.js: يدفع كائنًا واحدًا لكل نوع إدخال إلىwindow.dxprBuilder.dxpr_param_types.dxpr_elements.js: ينشئ المصفوفةwindow.dxprBuilder.dxpr_elementsويدفع تعريفًا واحدًا لكل عنصر.dxpr_builder.js: المحرّر. عندما يُنفَّذ هذا الملف يستدعيcreate_dxpr_elements()التي تحلّق فوقwindow.dxprBuilder.dxpr_elementsولكل تعريف:- تستدعي
register_animated_element(base, is_container, Class)، فيوسّع الصنفAnimatedElement(تبويب النمط وتبويب الحركة ومعرّف HTML وفئات HTML ومعاملات الموضع)؛ - تُلحق المعاملات الموروثة بـ
paramsالخاصة بالتعريف؛ - تحوّل كل معامل عبر
make_param_type()التي تطابقparam.typeمع أنواع المعاملات المسجلة؛ - تمزج خصائص التعريف في نموذج الصنف الأولي.
- تستدعي
يجب لذلك أن يكون التعريف على المصفوفة بعد عمل
dxpr_elements.js وقبل عمل dxpr_builder.js. وتُحمَّل الملفات
الستة كلها مع السمة defer، فترتيب وسوم النصوص في المستند هو
ترتيب التنفيذ.
تعريف العنصر
هذا عنصر التنبيه من dxpr_builder/dxpr_elements.js
(المصدر: dxpr_builder/build/dxpr-elements/elements/az_alert.js)،
مختصرًا إلى الخصائص التي يحتاجها كل عنصر. ويضبط الأصل أيضًا
el_class ومعالج onCancel ومستمع focusout.
window.dxprBuilder.dxpr_elements.push({
base: "az_alert",
name: Drupal.t("Alert"),
nameEn: "Alert",
icon: "az-custom-icon az-alert-icon",
largeSettingsWindow: true,
hidden: false,
params: [
{
type: "textarea",
heading: Drupal.t("Message"),
param_name: "content",
value: Drupal.t(
"This is a placeholder text. Your actual content will go here. Edit this to include your own information.",
),
},
{
type: "dropdown",
heading: Drupal.t("Type"),
param_name: "type",
description: Drupal.t("Select message type."),
getText: (opt) => opt.text,
getValue: (opt) => opt.value,
getDefault: (param) => param.value["alert-success"].value,
value: {
"alert-success": { text: Drupal.t("Success"), value: "alert-success" },
"alert-info": { text: Drupal.t("Info"), value: "alert-info" },
"alert-warning": { text: Drupal.t("Warning"), value: "alert-warning" },
"alert-danger": { text: Drupal.t("Danger"), value: "alert-danger" },
},
passthrough: true,
},
],
show_settings_on_create: true,
has_content: true,
render(...args) {
const state = {
class: `az-element az-alert alert ${this.attrs.type} ${this.get_el_classes()} ${this.get_content_classes()}`,
style: this.attrs.style,
message: this.attrs.content,
};
this.dom_element = this.baseclass.prototype.render_template(
"elements/alert/alert",
state,
);
this.baseclass.prototype.render.apply(this, args);
},
save_history() {
const container = this.get_my_container();
container.save_container_history(Drupal.t("Edit alert"));
},
});
| الخاصية | الغرض |
|---|---|
base |
الاسم الآلي. يُكتَب في HTML المحفوظ كـ data-azb="az_alert" ويُستخدَم للعثور على الصنف عند تحليل الصفحة مجددًا. حافظوا على البادئة az_. |
name، nameEn |
التسمية في منتقي العناصر وصيغتها غير المترجمة. |
icon |
فئات CSS لأيقونة المنتقي. والأيقونات المشحونة معرّفة في dxpr_builder/sass/dxpr-builder-backend/components/_custom-icons.scss؛ ويحتاج العنصر المخصص CSS الخاص به لفئة أيقونته. |
category |
تبويب المنتقي. تستخدم عناصر التخطيط Drupal.t("Layout")؛ وتستخدم الكتل وطرق العرض "CMS". أهملوها لتبويب المحتوى الافتراضي. |
is_container |
true عندما يحمل العنصر عناصر أخرى. |
largeSettingsWindow |
يفتح مربع حوار الإعدادات بالحجم الأكبر. |
hidden |
يخفي العنصر عن المنتقي مع إبقائه قابلًا للعرض. |
params |
الإعدادات المعروضة في مربع الحوار. انظر أدناه. |
show_settings_on_create |
يفتح مربع حوار الإعدادات فور إفلات العنصر. |
has_content |
يحمل العنصر منطقة محتوى قابلة للتحرير (dom_content_element). |
render(...args) |
يبني this.dom_element من this.attrs، ثم يستدعي render الأساسية. |
save_history() |
يدفع مدخل تراجع مع تسمية. |
parse_attrs_from_dom(element) |
اختياري. يقرأ قيم المعاملات مجددًا من الوسوم المحفوظة، ويُستخدَم مع skip_data_azb وskip_params من عناصر مثل الصورة التي تخزّن القيم في سمات <img> بدل data-azat-*. |
المعاملات
يحمل كل مدخل في params:
| المفتاح | المعنى |
|---|---|
type |
أحد أنواع المعاملات المسجلة (القسم التالي). |
heading |
تسمية الحقل. |
param_name |
المفتاح في this.attrs، وفي HTML المحفوظ السمة data-azat-<param_name>. وcontent خاصة: فهي متن العنصر، لا سمة. |
value |
القيمة الافتراضية. فلـ dropdown هي كائن خيارات مع دوال getText وgetValue وgetDefault. |
description |
نص مساعدة تحت الحقل. |
tab |
يجمّع الحقل في أكورديون مُسمّى، مثلًا Drupal.t("SEO"). |
can_be_empty |
يخزّن سلسلة فارغة بدل إسقاط السمة. |
safe |
يتجاوز ترميز URL للقيمة المخزّنة. |
أنواع المعاملات هي قيم type المدفوعة إلى
window.dxprBuilder.dxpr_param_types في
dxpr_builder/dxpr_param_types.js: boxmodel وcheckbox و
checkboxes وcolorpicker وdatetime وdropdown وdxb_slider و
html وicon وimage وimages وlink وlinks وnumericfield و
row_layout وsaved_datetime وsocial_links وtextarea و
textfield وvideo. والنوع الذي لا تسجّلونه يرتد إلى
حقل إدخال نص عادي (BaseParamType).
لا تعيدوا استخدام param_name يرثه كل عنصر، مثل
color أو background أو el_class أو hash أو أسماء an_* الخاصة
بالحركة. فتبويب النمط يملك color أصلًا، فلا يُكتَب معامل ثانٍ
بهذا الاسم أبدًا في data-azat-color.
ما يُحفَظ
update_data() في dxpr_builder.js تكتب العنصر إلى HTML:
data-azb="<base>"على العنصر الجذري؛data-azat-<param_name>="<value>"لكل معامل تختلف قيمته عن الافتراضي، مرمّزة بترميز URL ما لم يضبط المعاملsafe: true؛- معاملات تبويب النمط كـ
styleمضمّنة وفئات، أبدًا كسماتdata-azat-*؛ data-azcnt="true"على عنصر المحتوى عندما يُضبَطhas_content.
يستقبل المشاهِدون الذين لا يحصلون على المحرّر HTML هذا دون سماته
data-az*: فيجرّدها DxprBuilderService::parseDocumentForCleanup()،
عدا قائمة ثابتة يُبقيها على العناصر المتحركة وعلى
العناصر الديناميكية المدمجة مثل الدوّار. وإذا احتاج العنصر JavaScript أو CSS
للزوار، ضعوا سمة
data-dxpr-builder-libraries="<key>" على جذره:
فيرفق parseDocumentForTemplateLibrary()
dxpr_builder/elements.<key> لكل مفتاح دون شرطة. والمفاتيح هي مكتبات
elements.* في dxpr_builder.libraries.yml؛
والمفتاح ذو الشرطة لا يُكرَّم إلا عندما يكون library الخاصة
بمجموعة أيقونات مسجلة.
مثال عملي أدنى
يضيف المثال عنصر "Notice" الذي يعرض فقرة بلون
مختار. وهو يبني DOM الخاصة به مباشرة لأن قوالب twig.js
المُجمَّعة في dxpr_templates.js جزء من حزمة المحرّر ولا
تستطيع وحدة أخرى توسيعها.
-
أنشئوا
mymodule/js/notice-element.js:window.dxprBuilder.dxpr_elements.push({ base: "az_notice", name: Drupal.t("Notice"), nameEn: "Notice", icon: "az-custom-icon az-alert-icon", params: [ { type: "textfield", heading: Drupal.t("Text"), param_name: "text", value: Drupal.t("Notice text"), }, { type: "colorpicker", heading: Drupal.t("Colour"), param_name: "notice_color", value: "#0d6efd", }, ], show_settings_on_create: true, render(...args) { const el = document.createElement("div"); el.className = `az-element az-notice ${this.get_el_classes()}`; if (this.attrs.style) { el.setAttribute("style", this.attrs.style); } const p = document.createElement("p"); p.style.color = this.attrs.notice_color; p.textContent = this.attrs.text; el.appendChild(p); this.dom_element = el; this.baseclass.prototype.render.apply(this, args); }, save_history() { this.get_my_container().save_container_history(Drupal.t("Edit notice")); }, }); -
أدخلوا الملف في مكتبة المحرّر بين
dxpr_elements.js(الوزن-4) وdxpr_builder.js(الوزن-3) فيmymodule.module:/** * Implements hook_library_info_alter(). */ function mymodule_library_info_alter(array &$libraries, string $extension): void { if ($extension === 'dxpr_builder' && isset($libraries['editor.builder'])) { $path = '/' . \Drupal::service('extension.list.module')->getPath('mymodule'); $libraries['editor.builder']['js'][$path . '/js/notice-element.js'] = [ 'weight' => -3.5, 'preprocess' => FALSE, 'attributes' => ['defer' => TRUE], ]; } }preprocess: FALSEوdeferيطابقان المدخلات التي تعرّفها الوحدة لملفاتها الخاصة، فيحافظ الملف على مكانه في التسلسل سواء أتت أصول المحرّر من CDN أم من بناء محلي. -
امسحوا ذاكرة التخزين المؤقت وافتحوا صفحة منشئ:
drush cr -
أضيفوا العنصر من المنتقي واضبطوا نصّه ولونه واحفظوا. فيخزّن الحقل:
<div class="az-element az-notice" id="..." data-azb="az_notice" data-azat-text="Hello" data-azat-notice_color="%23198754"> <p style="color: #198754;">Hello</p> </div>يحصل الزائر على الوسوم نفسها دون سمات
data-az*. فتحتفظ الفقرة بلونها المضمّن، فلا حاجة لمكتبة زوار لهذا العنصر.
قيود يجب معرفتها
- الملفات لا تسرد العناصر المخصصة. فقائمة العناصر في
ملف المنشئ تأتي من قائمة ثابتة في
src/Form/DxprBuilderProfileForm.phpوsrc/Service/Handler/ProfileHandler.php. والعناصر خارج تلك القائمة لا يخفيها ملف أبدًا. - أيقونات المنتقي تحتاج CSS من وحدتكم؛ ففئات
az-custom-iconالمشحونة مع المنشئ تغطي العناصر المشحونة فقط. DxprBuilderService::getDxprElementsFolders()وخطافhook_dxpr_builder_elements_folders_alter()الخاص بها يعيدان قائمة مجلداتelementsفي القوالب، لكن لا شيء في المحرّر يقرأ تلك القائمة. فليست مسار تسجيل.- تبويبا النمط والحركة يُضافان لكم عبر
register_animated_element()؛ فلا تعيدوا تعريف تلك المعاملات.
ما الخطوة التالية؟
- واجهة الخطافات لخطافات PHP التي تضيف فئات الأدوات ومجموعات الأيقونات.
- البنية لكيفية تلاؤم المحرّر ومُنسِّق الحقل معًا.