カスタムエレメントの作成.

Learn DXPR BuilderExtendBouw erop voort

すべてのDXPR Builderエレメントはwindow.dxprBuilder.dxpr_elementsにプッシュされるJavaScriptオブジェクトです。エディターは各オブジェクトをStyle・Animationタブ付きのエレメントクラスに変換します。このページでは出荷エレメントがdxpr_builder/dxpr_elements.jsで定義される方法、モジュールが独自定義をエディターに追加する方法、結果のHTMLを示します。エレメントごとのサーバー側Twigテンプレートはありません。エレメントはブラウザーでレンダーされます。

エディターのエレメント登録方法

この順序で読み込まれ、dxpr_builder_library_info_build()(dxpr_builder.module内)でdxpr_builder/editor.builderライブラリーとして定義される6つのスクリプトです。

  1. dxpr_templates.js:dxpr_builder/templates/からコンパイルされたクライアント側twig.jsテンプレート。
  2. dxpr_global.js:共有ヘルパーとCKEditor 5統合。
  3. dxpr_events.js
  4. dxpr_param_types.js:入力タイプごとに1オブジェクトをwindow.dxprBuilder.dxpr_param_typesにプッシュ。
  5. dxpr_elements.js:window.dxprBuilder.dxpr_elements配列を作り、エレメントごとに1定義をプッシュ。
  6. dxpr_builder.js:エディター。このファイルの実行時にcreate_dxpr_elements()を呼び出し、window.dxprBuilder.dxpr_elementsをループして各定義で以下を実行します。
    • 呼び出すのはregister_animated_element(base, is_container, Class)で、クラスがAnimatedElementを拡張します(Styleタブ、Animationタブ、HTML ID、HTMLクラス、配置パラメーター)。
    • 継承パラメーターを定義のparamsに追加します。
    • 全パラメーターをmake_param_type()で変換します。param.typeを登録済みパラメータータイプと照合します。
    • 定義のプロパティをクラスのプロトタイプに混ぜ込みます。

定義はdxpr_elements.jsの実行後、dxpr_builder.jsの実行前に配列にある必要があります。6ファイルはすべてdefer属性で読み込まれるため、scriptタグの文書順序が実行順序です。

エレメント定義

例はdxpr_builder/dxpr_elements.jsのAlertエレメントです(ソース: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-*を使わないImageなどのエレメント向けです。

パラメーター

各項目は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_*アニメーション名。Styleタブがcolorを所有済みのため、その名の2つ目のパラメーターがdata-azat-colorに書き込まれることはありません。

保存内容

update_data()(dxpr_builder.js内)はエレメントをHTMLに書き込みます。

  • data-azb="<base>"はルートエレメントに。
  • data-azat-<param_name>="<value>"は初期値と異なる値の全パラメーターに。パラメーターがsafe: trueを設定しない限りURLエンコードされます。
  • Styleタブのパラメーターはインラインstyleとクラスとして。data-azat-*属性にはなりません。
  • data-azcnt="true"はhas_content設定時にコンテンツエレメントに。

エディターを受け取らない閲覧者はこのHTMLをdata-az*属性なしで受け取ります。DxprBuilderService::parseDocumentForCleanup()が除去します。アニメーション付きエレメントとCarouselなどの組み込み動的エレメントに保持する固定リストを除きます。エレメントが訪問者向けJavaScriptやCSSを要する場合、ルートにdata-dxpr-builder-libraries="<key>"属性を付けます。parseDocumentForTemplateLibrary()はスラッシュなしの全キーにdxpr_builder/elements.<key>を添付します。キーはdxpr_builder.libraries.ymlのelements.*ライブラリーです。スラッシュ付きキーは登録済みアイコンセットのlibraryである場合のみ有効です。

最小動作例

例では選択色で段落をレンダーする「Notice」エレメントを追加します。dxpr_templates.jsのコンパイル済みtwig.jsテンプレートはエディターバンドルの一部で他モジュールから拡張できないため、DOMを直接構築します。

  1. 作るのは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"));
      },
    });
    
  2. ファイルをエディターライブラリーに挿入します。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由来でもローカルビルド由来でもファイルの順序位置を保ちます。

  3. キャッシュをクリアしてBuilderページを開きます。

    drush cr
    
  4. ピッカーからエレメントを追加し、テキストと色を設定して保存します。フィールドの保存内容です。

    <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*属性なしで同じマークアップを受け取ります。段落はインライン色を保つため、このエレメントに訪問者用ライブラリーは不要です。

把握すべき制限

  • プロフィールはカスタムエレメントを列挙しません。Builderプロフィールのエレメントチェックリストはsrc/Form/DxprBuilderProfileForm.phpとsrc/Service/Handler/ProfileHandler.phpの固定リストから来ます。その外のエレメントはプロフィールで隠れません。
  • ピッカーのアイコンはモジュールからのCSSが必要です。Builder出荷のaz-custom-iconクラスは出荷エレメントのみを対象とします。
  • DxprBuilderService::getDxprElementsFolders()とhook_dxpr_builder_elements_folders_alter()はテーマ内のelementsフォルダーの一覧を返しますが、エディターは何も読み取りません。登録ルートではありません。
  • StyleとAnimationタブはregister_animated_element()が追加します。そのパラメーターを再定義しません。

次のステップ

  • フックAPI:ユーティリティークラスとアイコンセットを追加するPHPフックに。
  • アーキテクチャー:エディターとフィールドフォーマッターの連携に。