Eigene Elemente erstellen.
Jedes DXPR-Builder-Element ist ein JavaScript-Objekt, das auf
window.dxprBuilder.dxpr_elements gepusht wird. Der Editor macht
aus jedem Objekt eine Elementklasse, mit bereits angehängten Tabs Style
und Animation. Diese Seite zeigt, wie die mitgebrachten Elemente in
dxpr_builder/dxpr_elements.js definiert sind, wie ein Modul eine
eigene Definition in den Editor einbringt und wie das Ergebnis-HTML
aussieht. Es gibt keine serverseitigen Twig-Vorlagen pro Element;
Elemente rendern im Browser.
Wie der Editor Elemente registriert
Der Editor lädt sechs Skripte in dieser Reihenfolge, definiert in
dxpr_builder_library_info_build() in dxpr_builder.module als
Bibliothek dxpr_builder/editor.builder:
dxpr_templates.js: clientseitige twig.js-Vorlagen, kompiliert ausdxpr_builder/templates/.dxpr_global.js: geteilte Helfer und die CKEditor-5-Integration.dxpr_events.jsdxpr_param_types.js: pusht je ein Objekt pro Eingabetyp aufwindow.dxprBuilder.dxpr_param_types.dxpr_elements.js: erzeugt das Arraywindow.dxprBuilder.dxpr_elementsund pusht eine Definition pro Element.dxpr_builder.js: der Editor. Wenn diese Datei ausführt, ruft siecreate_dxpr_elements()auf, das überwindow.dxprBuilder.dxpr_elementsloopt und pro Definition:- ruft
register_animated_element(base, is_container, Class)auf, sodass die KlasseAnimatedElementerweitert (Tab Style, Tab Animation, HTML-ID, HTML-Klassen und Platzierungsparameter); - die geerbten Parameter an die
paramsder Definition anhängt; - jeden Parameter durch
make_param_type()wandelt, dasparam.typegegen die registrierten Parametertypen matcht; - die Eigenschaften der Definition in den Klassenprototyp mischt.
- ruft
Eine Definition muss daher nach dxpr_elements.js und vor
dxpr_builder.js auf dem Array liegen. Alle sechs Dateien laden mit
dem defer-Attribut, daher ist die Dokumentreihenfolge der
Skript-Tags die Ausführungsreihenfolge.
Die Elementdefinition
Dies ist das Alert-Element aus dxpr_builder/dxpr_elements.js
(Quelle: dxpr_builder/build/dxpr-elements/elements/az_alert.js),
gestutzt auf die Eigenschaften, die jedes Element braucht. Das Original
setzt außerdem el_class, einen onCancel-Handler und einen
focusout-Listener.
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"));
},
});
| Eigenschaft | Zweck |
|---|---|
base |
Systemname. Er wird als data-azb="az_alert" in das gespeicherte HTML geschrieben und genutzt, um die Klasse zu finden, wenn die Seite erneut geparst wird. Den az_-Präfix behalten. |
name, nameEn |
Bezeichnung in der Elementauswahl und ihre unübersetzte Form. |
icon |
CSS-Klassen für das Auswahl-Icon. Die mitgebrachten Icons sind in dxpr_builder/sass/dxpr-builder-backend/components/_custom-icons.scss definiert; ein eigenes Element braucht eigenes CSS für seine Icon-Klasse. |
category |
Auswahl-Tab. Die Layout-Elemente nutzen Drupal.t("Layout"); Blöcke und Ansichten nutzen "CMS". Weglassen für den Standard-Inhalts-Tab. |
is_container |
true, wenn das Element andere Elemente hält. |
largeSettingsWindow |
Öffnet den Einstellungsdialog in der größeren Größe. |
hidden |
Verbirgt das Element vor der Auswahl, hält es aber renderbar. |
params |
Einstellungen, die im Dialog gezeigt werden. Siehe unten. |
show_settings_on_create |
Öffnet den Einstellungsdialog, sobald das Element abgelegt wird. |
has_content |
Das Element hat einen bearbeitbaren Inhaltsbereich (dom_content_element). |
render(...args) |
Baut this.dom_element aus this.attrs und ruft dann das Basis-render auf. |
save_history() |
Pusht einen Rückgängig-Eintrag mit Bezeichnung. |
parse_attrs_from_dom(element) |
Optional. Liest Parameterwerte aus gespeichertem Markup zurück, genutzt zusammen mit skip_data_azb und skip_params von Elementen wie Image, die Werte in den <img>-Attributen statt data-azat-* speichern. |
Parameter
Jeder Eintrag in params hat:
| Schlüssel | Bedeutung |
|---|---|
type |
Einer der registrierten Parametertypen (nächster Abschnitt). |
heading |
Feldbezeichnung. |
param_name |
Schlüssel in this.attrs und, im gespeicherten HTML, das Attribut data-azat-<param_name>. content ist besonders: Es ist der Element-Body, kein Attribut. |
value |
Standardwert. Für dropdown ist es ein Optionsobjekt mit getText-, getValue- und getDefault-Callbacks. |
description |
Hilfetext unter dem Feld. |
tab |
Gruppiert das Feld in ein benanntes Akkordeon, zum Beispiel Drupal.t("SEO"). |
can_be_empty |
Leere Zeichenkette speichern, statt das Attribut zu droppen. |
safe |
URL-Codierung des gespeicherten Werts überspringen. |
Die Parametertypen sind die type-Werte, die in
dxpr_builder/dxpr_param_types.js auf
window.dxprBuilder.dxpr_param_types gepusht werden: boxmodel, checkbox,
checkboxes, colorpicker, datetime, dropdown, dxb_slider,
html, icon, image, images, link, links, numericfield,
row_layout, saved_datetime, social_links, textarea,
textfield und video. Ein Typ, den Sie nicht registrieren, fällt auf eine
schlichte Texteingabe zurück (BaseParamType).
Nutzen Sie keinen param_name wieder, den jedes Element erbt, etwa
color, background, el_class, hash oder die an_*-Animationsnamen.
Der Tab Style besitzt color bereits, daher wird ein zweiter Parameter
mit diesem Namen nie nach data-azat-color geschrieben.
Was gespeichert wird
update_data() in dxpr_builder.js schreibt das Element nach HTML:
data-azb="<base>"auf dem Wurzelelement;data-azat-<param_name>="<value>"für jeden Parameter, dessen Wert vom Standard abweicht, URL-codiert, außer der Parameter setztsafe: true;- die Style-Tab-Parameter als Inline-
styleund Klassen, nie alsdata-azat-*-Attribute; data-azcnt="true"auf dem Inhaltselement, wennhas_contentgesetzt ist.
Betrachtende, die den Editor nicht erhalten, bekommen dieses HTML ohne seine
data-az*-Attribute: DxprBuilderService::parseDocumentForCleanup()
streift sie, außer einer festen Liste, die es auf animierten Elementen und
auf eingebauten dynamischen Elementen wie Carousel behält. Wenn das
Element JavaScript oder CSS für Besuchende braucht, legen Sie ein
data-dxpr-builder-libraries="<key>"-Attribut auf seine Wurzel:
parseDocumentForTemplateLibrary() hängt
dxpr_builder/elements.<key> für jeden Schlüssel ohne Schrägstrich an. Die
Schlüssel sind die elements.*-Bibliotheken in dxpr_builder.libraries.yml;
ein Schlüssel mit Schrägstrich gilt nur, wenn er die library eines
registrierten Icon-Sets ist.
Minimal lauffähiges Beispiel
Das Beispiel fügt ein „Notice“-Element hinzu, das einen Absatz mit gewählter
Farbe rendert. Es baut sein DOM direkt, weil die kompilierten twig.js-Vorlagen
in dxpr_templates.js Teil des Editor-Bundles sind und von einem anderen
Modul nicht erweitert werden können.
-
Erstellen Sie
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")); }, }); -
Fügen Sie die Datei zwischen
dxpr_elements.js(Gewicht-4) unddxpr_builder.js(Gewicht-3) in die Editor-Bibliothek ein, inmymodule.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: FALSEunddeferpassen zu den Einträgen, die das Modul für seine eigenen Dateien definiert, daher behält die Datei ihren Platz in der Reihenfolge, ob Editor-Assets vom CDN oder aus einem lokalen Build kommen. -
Leeren Sie den Cache und öffnen Sie eine Builder-Seite:
drush cr -
Fügen Sie das Element aus der Auswahl hinzu, setzen Sie Text und Farbe und speichern Sie. Das Feld speichert:
<div class="az-element az-notice" id="..." data-azb="az_notice" data-azat-text="Hallo" data-azat-notice_color="%23198754"> <p style="color: #198754;">Hallo</p> </div>Gäste erhalten dasselbe Markup ohne die
data-az*-Attribute. Der Absatz behält seine Inline-Farbe, daher braucht dieses Element keine Besucherbibliothek.
Zu kennende Grenzen
- Profile listen eigene Elemente nicht. Die Element-Checkliste
in einem Builder-Profil stammt aus einer festen Liste in
src/Form/DxprBuilderProfileForm.phpundsrc/Service/Handler/ProfileHandler.php. Elemente außerhalb dieser Liste verbirgt kein Profil je. - Icons für die Auswahl brauchen CSS aus Ihrem Modul; die
az-custom-icon-Klassen des Builders decken nur die mitgebrachten Elemente ab. DxprBuilderService::getDxprElementsFolders()und seinhook_dxpr_builder_elements_folders_alter()liefern eine Liste vonelements-Ordnern in Themes, aber nichts im Editor liest diese Liste. Es ist keine Registrierungsroute.- Style- und Animation-Tabs werden von
register_animated_element()für Sie hinzugefügt; definieren Sie diese Parameter nicht neu.
Wie geht es weiter?
- Hooks-API für die PHP-Hooks, die Dienstklassen und Icon-Sets hinzufügen.
- Architektur: wie Editor und Feld-Formatierer zusammenpassen.