Criar elementos personalizados.
Cada elemento do DXPR Builder é um objeto JavaScript empurrado para
window.dxprBuilder.dxpr_elements. O editor transforma cada objeto
numa classe de elemento com os separadores Style e Animation já
anexados. Esta página mostra como os elementos incluídos se definem em
dxpr_builder/dxpr_elements.js, como um módulo adiciona a própria
definição ao editor, e como fica o HTML resultante.
Não há modelos Twig de servidor por elemento; os elementos
apresentam-se no navegador.
Como o editor regista elementos
O editor carrega seis scripts por esta ordem, definidos em
dxpr_builder_library_info_build() em dxpr_builder.module como a
biblioteca dxpr_builder/editor.builder:
dxpr_templates.js: modelos twig.js do lado do cliente compilados dedxpr_builder/templates/.dxpr_global.js: auxiliares partilhados e a integração com CKEditor 5.dxpr_events.jsdxpr_param_types.js: empurra um objeto por tipo de entrada parawindow.dxprBuilder.dxpr_param_types.dxpr_elements.js: cria o arraywindow.dxprBuilder.dxpr_elementse empurra uma definição por elemento.dxpr_builder.js: o editor. Quando este ficheiro executa, chamacreate_dxpr_elements(), que percorrewindow.dxprBuilder.dxpr_elementse para cada definição:- chama
register_animated_element(base, is_container, Class), para a classe estenderAnimatedElement(separador Style, separador Animation, HTML ID, classes HTML e parâmetros de colocação); - anexa os parâmetros herdados aos
paramsda definição; - converte cada parâmetro através de
make_param_type(), que comparaparam.typecom os tipos de parâmetro registados; - mistura as propriedades da definição no protótipo da classe.
- chama
Uma definição tem por isso de estar no array depois de
dxpr_elements.js correr e antes de dxpr_builder.js correr. Os seis
ficheiros carregam com o atributo defer, por isso a ordem dos
script tags no documento é a ordem de execução.
A definição de elemento
Este é o elemento Alert de dxpr_builder/dxpr_elements.js
(origem: dxpr_builder/build/dxpr-elements/elements/az_alert.js),
reduzido às propriedades de que cada elemento precisa. O original também
define el_class, um manipulador onCancel e um ouvinte 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"));
},
});
| Property | Purpose |
|---|---|
base |
Nome de sistema. Escreve-se no HTML guardado como data-azb="az_alert" e usa-se para encontrar a classe quando a página é analisada outra vez. Mantenha o prefixo az_. |
name, nameEn |
Etiqueta no seletor de elementos e a forma não traduzida. |
icon |
Classes CSS para o ícone do seletor. Os ícones incluídos definem-se em dxpr_builder/sass/dxpr-builder-backend/components/_custom-icons.scss; um elemento personalizado precisa do próprio CSS para a classe de ícone. |
category |
Separador do seletor. Os elementos de esquema usam Drupal.t("Layout"); blocos e vistas usam "CMS". Omita para o separador de conteúdo predefinido. |
is_container |
true quando o elemento contém outros elementos. |
largeSettingsWindow |
Abre o diálogo de definições no tamanho maior. |
hidden |
Esconde o elemento do seletor mantendo-o apresentável. |
params |
Definições mostradas no diálogo. Ver abaixo. |
show_settings_on_create |
Abre o diálogo de definições assim que o elemento é largado. |
has_content |
O elemento tem uma área de conteúdo editável (dom_content_element). |
render(...args) |
Constrói this.dom_element a partir de this.attrs e depois chama o render base. |
save_history() |
Empurra uma entrada de anulação com etiqueta. |
parse_attrs_from_dom(element) |
Opcional. Lê valores de parâmetro de volta da marcação guardada, usado com skip_data_azb e skip_params por elementos como Image que guardam valores nos atributos <img> em vez de data-azat-*. |
Parâmetros
Cada entrada em params tem:
| Key | Meaning |
|---|---|
type |
Um dos tipos de parâmetro registados (próxima secção). |
heading |
Etiqueta do campo. |
param_name |
Chave em this.attrs e, no HTML guardado, o atributo data-azat-<param_name>. content é especial: é o corpo do elemento, não um atributo. |
value |
Valor predefinido. Para dropdown é um objeto de opções com retornos getText, getValue e getDefault. |
description |
Texto de ajuda sob o campo. |
tab |
Agrupa o campo num acordeão nomeado, por exemplo Drupal.t("SEO"). |
can_be_empty |
Guarda uma cadeia vazia em vez de largar o atributo. |
safe |
Omite a codificação de URL do valor guardado. |
Os tipos de parâmetro são os valores type empurrados para
window.dxprBuilder.dxpr_param_types em
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 e video. Um tipo sem registo recua para uma
entrada de texto simples (BaseParamType).
Não reutilize um param_name que cada elemento herda, como
color, background, el_class, hash ou os nomes de animação an_*.
O separador Style já detém color, por isso um segundo parâmetro
com esse nome nunca é escrito em data-azat-color.
O que fica guardado
update_data() em dxpr_builder.js escreve o elemento em HTML:
data-azb="<base>"no elemento raiz;data-azat-<param_name>="<value>"para cada parâmetro cujo valor difere da predefinição, codificado para URL salvo se o parâmetro definesafe: true;- os parâmetros do separador Style como
styleem linha e classes, nunca como atributosdata-azat-*; data-azcnt="true"no elemento de conteúdo quandohas_contentestá definido.
Os visitantes sem editor recebem este HTML sem os
atributos data-az*: DxprBuilderService::parseDocumentForCleanup()
remove-os, exceto uma lista fixa que mantém em elementos animados e
em elementos dinâmicos incluídos como Carousel. Se o
elemento precisa de JavaScript ou CSS para visitantes, ponha um
atributo data-dxpr-builder-libraries="<key>" na raiz:
parseDocumentForTemplateLibrary() anexa
dxpr_builder/elements.<key> para cada chave sem barra. As
chaves são as bibliotecas elements.* em dxpr_builder.libraries.yml;
uma chave com barra só é aceite quando é a library de um
conjunto de ícones do registo.
Exemplo mínimo funcional
O exemplo adiciona um elemento "Notice" que apresenta um parágrafo com uma
cor escolhida. Constrói o DOM diretamente porque os modelos twig.js
compilados em dxpr_templates.js fazem parte do pacote do editor e
não podem ser estendidos por outro módulo.
-
Crie
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")); }, }); -
Insira o ficheiro na biblioteca do editor entre
dxpr_elements.js(peso-4) edxpr_builder.js(peso-3) emmymodule.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: FALSEedefercorrespondem às entradas que o módulo define para os próprios ficheiros, por isso o ficheiro mantém o lugar na sequência quer os recursos do editor venham da CDN ou de uma compilação local. -
Limpe a cache e abra uma página do construtor:
drush cr -
Adicione o elemento a partir do seletor, defina o texto e a cor, e guarde. O 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>Um visitante recebe a mesma marcação sem os atributos
data-az*. O parágrafo mantém a cor em linha, por isso não é precisa biblioteca de visitantes para este elemento.
Limites a conhecer
- Profiles do not list custom elements. A lista de verificação de elementos
num perfil do construtor vem de uma lista fixa em
src/Form/DxprBuilderProfileForm.phpesrc/Service/Handler/ProfileHandler.php. Elementos fora dessa lista nunca são escondidos por um perfil. - Icons for the picker precisam de CSS do módulo; as
classes
az-custom-iconincluídas no construtor abrangem apenas os elementos incluídos. DxprBuilderService::getDxprElementsFolders()e ohook_dxpr_builder_elements_folders_alter()devolvem uma lista de pastaselementsem temas, mas nada no editor lê essa lista. Não é uma rota de registo.- Style and Animation tabs são adicionados por
register_animated_element(); não redefina esses parâmetros.
O que se segue?
- API de hooks para os hooks PHP que adicionam classes utilitárias e conjuntos de ícones.
- Arquitetura para saber como o editor e o formatador de campo combinam.