Creación de elementos personalizados.
Cada elemento de DXPR Builder es un objeto JavaScript puesto en
window.dxprBuilder.dxpr_elements. El editor convierte cada objeto
en una clase de elemento con las pestañas Style y Animation ya
adjuntas. Esta página muestra cómo se definen los elementos incluidos en
dxpr_builder/dxpr_elements.js, cómo un módulo añade su propia
definición al editor y cómo es el HTML resultante.
No hay plantillas Twig de servidor por elemento; los elementos
se renderizan en el navegador.
Cómo el editor registra elementos
El editor carga seis scripts en este orden, definidos en
dxpr_builder_library_info_build() en dxpr_builder.module como la
biblioteca dxpr_builder/editor.builder:
dxpr_templates.js: plantillas twig.js de cliente compiladas desdedxpr_builder/templates/.dxpr_global.js: ayudas compartidas y la integración CKEditor 5.dxpr_events.jsdxpr_param_types.js: pone un objeto por tipo de entrada enwindow.dxprBuilder.dxpr_param_types.dxpr_elements.js: crea el arraywindow.dxprBuilder.dxpr_elementsy pone una definición por elemento.dxpr_builder.js: el editor. Cuando este archivo se ejecuta llama acreate_dxpr_elements(), que recorrewindow.dxprBuilder.dxpr_elementsy para cada definición:- llama a
register_animated_element(base, is_container, Class), así que la clase extiendeAnimatedElement(pestaña Style, pestaña Animation, HTML ID, HTML classes y parámetros de colocación); - añade los parámetros heredados a los
paramsde la definición; - convierte cada parámetro con
make_param_type(), que cruzaparam.typecon los tipos de parámetro registrados; - mezcla las propiedades de la definición en el prototipo de la clase.
- llama a
Una definición tiene que estar en el array después de que
dxpr_elements.js se ejecutó y antes de que dxpr_builder.js se ejecute. Los
seis archivos se cargan con el atributo defer, así que el orden de documento de
las etiquetas de script es el orden de ejecución.
La definición de elemento
Este es el elemento Alert de dxpr_builder/dxpr_elements.js
(fuente: dxpr_builder/build/dxpr-elements/elements/az_alert.js),
recortado a las propiedades que cada elemento necesita. El original también
fija el_class, un manejador onCancel y un listener 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"));
},
});
| Propiedad | Propósito |
|---|---|
base |
Nombre de máquina. Se escribe en el HTML guardado como data-azb="az_alert" y se usa para encontrar la clase cuando la página se analiza de nuevo. Conserva el prefijo az_. |
name, nameEn |
Etiqueta en el selector de elementos y su forma sin traducir. |
icon |
Clases CSS para el icono del selector. Los iconos incluidos se definen en dxpr_builder/sass/dxpr-builder-backend/components/_custom-icons.scss; un elemento personalizado necesita su propio CSS para su clase de icono. |
category |
Pestaña del selector. Los elementos de diseño usan Drupal.t("Layout"); bloques y vistas usan "CMS". Omítelo para la pestaña de contenido predeterminada. |
is_container |
true cuando el elemento contiene otros elementos. |
largeSettingsWindow |
Abre el diálogo de ajustes en el tamaño grande. |
hidden |
Oculta el elemento del selector manteniéndolo renderizable. |
params |
Ajustes mostrados en el diálogo. Ver abajo. |
show_settings_on_create |
Abre el diálogo de ajustes en cuanto el elemento se suelta. |
has_content |
El elemento tiene un área de contenido editable (dom_content_element). |
render(...args) |
Construye this.dom_element desde this.attrs, y luego llama al render base. |
save_history() |
Pone una entrada de deshacer con etiqueta. |
parse_attrs_from_dom(element) |
Opcional. Lee valores de parámetros de vuelta desde el marcado guardado, usado junto con skip_data_azb y skip_params por elementos como Image que guardan valores en los atributos <img> en lugar de data-azat-*. |
Parámetros
Cada entrada en params tiene:
| Clave | Significado |
|---|---|
type |
Uno de los tipos de parámetro registrados (siguiente sección). |
heading |
Etiqueta del campo. |
param_name |
Clave en this.attrs y, en el HTML guardado, el atributo data-azat-<param_name>. content es especial: es el cuerpo del elemento, no un atributo. |
value |
Valor predeterminado. Para dropdown es un objeto de opciones con callbacks getText, getValue y getDefault. |
description |
Texto de ayuda bajo el campo. |
tab |
Agrupa el campo en un acordeón con nombre, por ejemplo Drupal.t("SEO"). |
can_be_empty |
Guarda una cadena vacía en lugar de quitar el atributo. |
safe |
Omite la codificación URL del valor guardado. |
Los tipos de parámetro son los valores type puestos en
window.dxprBuilder.dxpr_param_types en
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 y video. Un tipo que no registras vuelve a una
entrada de texto simple (BaseParamType).
No reutilices un param_name que cada elemento hereda, como
color, background, el_class, hash o los nombres de animación
an_*. La pestaña Style ya posee color, así que un segundo parámetro
con ese nombre nunca se escribe en data-azat-color.
Qué se guarda
update_data() en dxpr_builder.js escribe el elemento a HTML:
data-azb="<base>"en el elemento raíz;data-azat-<param_name>="<value>"para cada parámetro cuyo valor difiere de su predeterminado, codificado en URL salvo que el parámetro fijasafe: true;- los parámetros de la pestaña Style como
styleen línea y clases, nunca como atributosdata-azat-*; data-azcnt="true"en el elemento de contenido cuandohas_contentestá fijado.
Quienes no reciben el editor reciben este HTML sin sus
atributos data-az*: DxprBuilderService::parseDocumentForCleanup()
los quita, salvo una lista fija que conserva en elementos animados y
en elementos dinámicos integrados como Carousel. Si el
elemento necesita JavaScript o CSS para visitas, pon un
atributo data-dxpr-builder-libraries="<key>" en su raíz:
parseDocumentForTemplateLibrary() adjunta
dxpr_builder/elements.<key> por cada clave sin barra. Las
claves son las bibliotecas elements.* en dxpr_builder.libraries.yml;
una clave con barra solo se respeta cuando es el library de un
conjunto de iconos registrado.
Ejemplo mínimo funcional
El ejemplo añade un elemento "Notice" que renderiza un párrafo con un
color elegido. Crea su DOM directamente porque las plantillas twig.js
compiladas en dxpr_templates.js son parte del paquete del editor y
otro módulo no puede extenderlas.
-
Crea
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")); }, }); -
Inserta el archivo en la biblioteca del editor entre
dxpr_elements.js(peso-4) ydxpr_builder.js(peso-3) enmymodule.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: FALSEydefercoinciden con las entradas que el módulo define para sus propios archivos, así que el archivo conserva su lugar en la secuencia vengan los recursos del editor de la CDN o de una compilación local. -
Limpia la caché y abre una página del constructor:
drush cr -
Añade el elemento desde el selector, fija su texto y color, y guarda. El campo guarda:
<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>Una visita recibe el mismo marcado sin los atributos
data-az*. El párrafo conserva su color en línea, así que este elemento no necesita biblioteca de visitas.
Límites que debes conocer
- Los perfiles no enumeran elementos personalizados. La lista de elementos
en un perfil del constructor viene de una lista fija en
src/Form/DxprBuilderProfileForm.phpysrc/Service/Handler/ProfileHandler.php. Los elementos fuera de esa lista nunca los oculta un perfil. - Icons for the picker: los iconos del selector necesitan CSS de tu módulo. Las clases
az-custom-iconincluidas solo cubren los elementos incluidos. DxprBuilderService::getDxprElementsFolders()y suhook_dxpr_builder_elements_folders_alter()devuelven una lista de carpetaselementsen temas, pero nada en el editor lee esa lista. No es una ruta de registro.- Style and Animation tabs las añade por ti
register_animated_element(); no redefinas esos parámetros.
¿Qué sigue?
- API de hooks para los hooks PHP que añaden clases de utilidades y conjuntos de iconos.
- Arquitectura para ver cómo encajan el editor y el formato de campo.