Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save slejnej/b0dfad183d7aec0bd76e3c31832d12b4 to your computer and use it in GitHub Desktop.
Save slejnej/b0dfad183d7aec0bd76e3c31832d12b4 to your computer and use it in GitHub Desktop.
Drupal 8 - entity_reference_tree (new inline display support)
diff --git a/css/entity-reference-tree.css b/css/entity-reference-tree.css
index 7dff60d..5b19f09 100644
--- a/css/entity-reference-tree.css
+++ b/css/entity-reference-tree.css
@@ -1,4 +1,9 @@
-#entity-reference-tree-selected-text {
+.entity-reference-tree-selected-text {
font-weight: 600;
margin-top: 1em;
}
+
+/* Hide the actual entity reference autocomplete field */
+.field--widget-inline-entity-reference-tree-widget .form-autocomplete {
+ display: none;
+}
diff --git a/js/entity_reference_tree.js b/js/entity_reference_tree.js
index 950c136..af1e948 100644
--- a/js/entity_reference_tree.js
+++ b/js/entity_reference_tree.js
@@ -8,144 +8,158 @@
(function($, Drupal) {
Drupal.behaviors.entityReferenceTree = {
attach: function(context, settings) {
- $("#entity-reference-tree-wrapper", context)
- .once("jstreeBehavior")
- .each(function() {
- const treeContainer = $(this);
- const fieldEditName = $("#entity-reference-tree-widget-field").val();
- const widgetElement = $("#" + fieldEditName);
- const theme = treeContainer.attr("theme");
- const dots = treeContainer.attr("dots");
- // Avoid ajax callback from running following codes again.
- if (widgetElement.length) {
- const entityType = $("#entity-reference-tree-entity-type").val();
- const bundle = $("#entity-reference-tree-entity-bundle").val();
- const token = settings["entity_tree_token_" + fieldEditName];
- const idIsString = bundle === "*";
- const limit = parseInt(settings["tree_limit_" + fieldEditName]);
- let selectedNodes;
- // Selected nodes.
- if (idIsString) {
- selectedNodes = widgetElement.val().match(/\([a-z 0-9 _]+\)/g);
- } else {
- selectedNodes = widgetElement.val().match(/\((\d+)\)/g);
- }
+ $(".entity-reference-tree-wrapper", context)
+ .each(function() {
+ const treeContainer = $(this);
+ const treeJs = treeContainer.find('.entity-reference-tree');
+ const fieldEditName = treeContainer.find(".entity-reference-tree-widget-field").val();
+ const widgetElement = $("#" + fieldEditName);
+ const theme = treeJs.attr("theme");
+ const dots = treeJs.attr("dots");
+ const widgetType = settings['widget_type'];
+ // Avoid ajax callback from running following codes again.
+ if (widgetElement.length) {
+ const entityType = treeContainer.find(".entity-reference-tree-entity-type").val();
+ const bundle = treeContainer.find(".entity-reference-tree-entity-bundle").val();
+ const token = settings["entity_tree_token_" + fieldEditName];
+ const idIsString = bundle === "*";
+ const limit = parseInt(settings["tree_limit_" + fieldEditName]);
+ let selectedNodes;
+ // Selected nodes.
+ if (idIsString) {
+ selectedNodes = widgetElement.val().match(/\([a-z 0-9 _]+\)/g);
+ } else {
+ selectedNodes = widgetElement.val().match(/\((\d+)\)/g);
+ }
- if (selectedNodes) {
- // Pick up nodes id.
- for (let i = 0; i < selectedNodes.length; i++) {
- // Remove the round brackets.
- if (idIsString) {
- selectedNodes[i] = selectedNodes[i].slice(
- 1,
- selectedNodes[i].length - 1
- );
- } else {
- selectedNodes[i] = parseInt(
- selectedNodes[i].slice(1, selectedNodes[i].length - 1),
- 10
- );
+ if (selectedNodes) {
+ // Pick up nodes id.
+ for (let i = 0; i < selectedNodes.length; i++) {
+ // Remove the round brackets.
+ if (idIsString) {
+ selectedNodes[i] = selectedNodes[i].slice(
+ 1,
+ selectedNodes[i].length - 1
+ );
+ } else {
+ selectedNodes[i] = parseInt(
+ selectedNodes[i].slice(1, selectedNodes[i].length - 1),
+ 10
+ );
+ }
}
+ } else {
+ selectedNodes = [];
}
- } else {
- selectedNodes = [];
- }
- // Populate the selected entities text.
- $("#entity-reference-tree-selected-node").val(widgetElement.val());
- $("#entity-reference-tree-selected-text").text(
- Drupal.t("Selected entities") + ": " + widgetElement.val()
- );
- // Build the tree.
- treeContainer.jstree({
- core: {
- data: {
- url: function(node) {
- return Drupal.url(
- "admin/entity_reference_tree/json/" +
- entityType +
- "/" +
- bundle +
- "?token=" +
- token
- );
+ // Populate the selected entities text.
+ if (widgetType == 'inline') {
+ $(widgetElement).val(widgetElement.val())
+ }
+ else {
+ treeContainer.find(".entity-reference-tree-selected-node").val(widgetElement.val());
+ treeContainer.find(".entity-reference-tree-selected-text").text(
+ Drupal.t("Selected entities") + ": " + widgetElement.val()
+ );
+ }
+
+ // Build the tree.
+ treeJs.jstree({
+ core: {
+ data: {
+ url: function(node) {
+ return Drupal.url(
+ "admin/entity_reference_tree/json/" +
+ entityType +
+ "/" +
+ bundle +
+ "?token=" +
+ token
+ );
+ },
+ data: function(node) {
+ return {
+ id: node.id,
+ text: node.text,
+ parent: node.parent
+ };
+ }
},
- data: function(node) {
- return {
- id: node.id,
- text: node.text,
- parent: node.parent
- };
+ themes: {
+ dots: dots === "1",
+ name: theme
+ }
+ },
+ checkbox: {
+ three_state: false
+ },
+ search: {
+ show_only_matches: true
+ },
+ conditionalselect : function (node, event) {
+ if (limit > 0) {
+ return this.get_selected().length < limit || node.state.selected;
+ }
+ else {
+ // No limit.
+ return true;
}
+
},
- themes: {
- dots: dots === "1",
- name: theme
+ plugins: ["search", "changed", "checkbox", "conditionalselect"]
+ });
+ // Initialize the selected node.
+ treeJs.on("ready.jstree", function(e, data) {
+ data.instance.select_node(selectedNodes);
+ if (widgetType == "modal") {
+ // Make modal window height scaled automatically.
+ $("#drupal-modal").dialog("option", { height: 'auto' });
}
- },
- checkbox: {
- three_state: false
- },
- search: {
- show_only_matches: true
- },
- conditionalselect : function (node, event) {
- if (limit > 0) {
- return this.get_selected().length < limit || node.state.selected;
- }
- else {
- // No limit.
- return true;
- }
-
- },
- plugins: ["search", "changed", "checkbox", "conditionalselect"]
- });
- // Initialize the selected node.
- treeContainer.on("ready.jstree", function(e, data) {
- data.instance.select_node(selectedNodes);
- // Make modal window height scaled automatically.
- $("#drupal-modal").dialog( "option", { height: 'auto' } );
- });
- // Selected event.
- treeContainer.on("changed.jstree", function(evt, data) {
- // selected node objects;
- const choosedNodes = data.selected;
- const r = [];
+ });
+ // Selected event.
+ treeJs.on("changed.jstree", function(evt, data) {
+ // selected node objects;
+ const choosedNodes = data.selected;
+ const r = [];
- for (let i = 0; i < choosedNodes.length; i++) {
- const node = data.instance.get_node(choosedNodes[i]);
- // node text escaping double quote.
- let nodeText =
- node.text.replace(/"/g, '""') + " (" + node.id + ")";
- // Comma is a special character for autocomplete widge.
- if (
- nodeText.indexOf(",") !== -1 ||
- nodeText.indexOf("'") !== -1
- ) {
- nodeText = '"' + nodeText + '"';
+ for (let i = 0; i < choosedNodes.length; i++) {
+ const node = data.instance.get_node(choosedNodes[i]);
+ // node text escaping double quote.
+ let nodeText =
+ node.text.replace(/"/g, '""') + " (" + node.id + ")";
+ // Comma is a special character for autocomplete widge.
+ if (
+ nodeText.indexOf(",") !== -1 ||
+ nodeText.indexOf("'") !== -1
+ ) {
+ nodeText = '"' + nodeText + '"';
+ }
+ r.push(nodeText);
}
- r.push(nodeText);
- }
- const selectedText = r.join(", ");
- $("#entity-reference-tree-selected-node").val(selectedText);
- $("#entity-reference-tree-selected-text").text(
- Drupal.t("Selected entities") + ": " + selectedText
- );
- });
- // Search filter box.
- let to = false;
- $("#entity-reference-tree-search").keyup(function() {
- const searchInput = $(this);
- if (to) {
- clearTimeout(to);
- }
- to = setTimeout(function() {
- const v = searchInput.val();
- treeContainer.jstree(true).search(v);
- }, 250);
- });
- }
- });
+ const selectedText = r.join(", ");
+ if (widgetType == "inline") {
+ $(widgetElement).val(selectedText);
+ }
+ else {
+ treeContainer.find(".entity-reference-tree-selected-node").val(selectedText);
+ treeContainer.find(".entity-reference-tree-selected-text").text(
+ Drupal.t("Selected entities") + ": " + selectedText
+ );
+ }
+ });
+ // Search filter box.
+ let to = false;
+ treeContainer.find(".entity-reference-tree-search").keyup(function() {
+ const searchInput = $(this);
+ if (to) {
+ clearTimeout(to);
+ }
+ to = setTimeout(function() {
+ const v = searchInput.val();
+ treeJs.jstree(true).search(v);
+ }, 250);
+ });
+ }
+ });
}
};
})(jQuery, Drupal);
@@ -153,7 +167,7 @@
// Codes just run once the DOM has loaded.
// @See https://www.drupal.org/docs/8/api/javascript-api/javascript-api-overview
(function($) {
- // Search form sumbit function.
+ // Search form sumbit function.
// Argument passed from InvokeCommand defined in Drupal\entity_reference_tree\Form\SearchForm
$.fn.entitySearchDialogAjaxCallback = function(fieldEditID, selectedEntites) {
if ($("#" + fieldEditID).length) {
diff --git a/src/Form/SearchForm.php b/src/Form/SearchForm.php
index 5c62467..6fdb358 100644
--- a/src/Form/SearchForm.php
+++ b/src/Form/SearchForm.php
@@ -37,7 +37,7 @@ class SearchForm extends FormBase {
/**
* {@inheritdoc}
*/
- public function buildForm(array $form, FormStateInterface $form_state, $field_edit_id = '', $bundles = '', $entity_type = '', $theme = 'default', $dots = false) {
+ public function buildForm(array $form, FormStateInterface $form_state, $field_edit_id = '', $bundles = '', $entity_type = '', $theme = 'default', $dots = FALSE) {
// Do nothing after the form is submitted.
if (!empty($form_state->getValues())) {
return [];
@@ -45,64 +45,77 @@ class SearchForm extends FormBase {
// Limit number of selected nodes of tree.
$limit = $this->getRequest()->get('limit');
+ // All around wrapper.
+ $form['tree_container'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'div',
+ '#attributes' => [
+ 'class' => [
+ 'entity-reference-tree-wrapper',
+ ],
+ ],
+ ];
+
// The status messages that will contain any form errors.
- $form['status_messages'] = [
+ $form['tree_container']['status_messages'] = [
'#type' => 'status_messages',
'#weight' => -10,
];
// Selectd entity text.
- $form['selected_text'] = [
- '#type' => 'html_tag',
- '#tag' => 'div',
- '#value' => $this
+ $form['tree_container']['selected_text'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'div',
+ '#value' => $this
->t('Selected Entities'),
- '#weight' => 1000,
- '#attributes' => [
- 'class' => [
- 'selected-entities-text',
- ],
- 'id' => [
- 'entity-reference-tree-selected-text',
- ],
+ '#weight' => 1000,
+ '#attributes' => [
+ 'class' => [
+ 'selected-entities-text',
+ 'entity-reference-tree-selected-text',
],
+ ],
];
+
// Hidden field for submitting selected entity IDs.
- $form['selected_node'] = [
+ $form['tree_container']['selected_node'] = [
'#type' => 'hidden',
'#attributes' => [
- 'id' => [
+ 'class' => [
'entity-reference-tree-selected-node',
],
],
];
+
// Search filter box.
- $form['tree_search'] = [
+ $form['tree_container']['tree_search'] = [
'#type' => 'textfield',
'#title' => $this
->t('Search'),
'#size' => 60,
'#attributes' => [
- 'id' => [
+ 'class' => [
'entity-reference-tree-search',
],
],
];
+
// JsTree container.
- $form['tree_container'] = [
+ $form['tree_container']['js_tree'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#attributes' => [
- 'id' => [
- 'entity-reference-tree-wrapper',
+ 'class' => [
+ 'entity-reference-tree',
],
'theme' => $theme,
- 'dots' => $dots,
+ 'dots' => $dots,
],
];
+
// Submit button.
- $form['actions'] = ['#type' => 'actions'];
- $form['actions']['send'] = [
+ $form['tree_container']['actions'] = ['#type' => 'actions'];
+ $form['tree_container']['actions']['send'] = [
'#type' => 'submit',
'#value' => $this->t('Save'),
'#attributes' => [
@@ -116,55 +129,59 @@ class SearchForm extends FormBase {
],
];
- $form['#attached']['library'][] = 'entity_reference_tree/jstree';
- $form['#attached']['library'][] = 'entity_reference_tree/entity_tree';
- $form['#attached']['library'][] = 'entity_reference_tree/jstree_' . $theme . '_theme';
-
- // Disable the cache for this form.
- $form_state->setCached(FALSE);
- $form['#cache'] = ['max-age' => 0];
- $form['#attributes']['data-user-info-from-browser'] = FALSE;
// Field element id.
- $form['field_id'] = [
+ $form['tree_container']['field_id'] = [
'#name' => 'field_id',
'#type' => 'hidden',
'#weight' => 80,
'#value' => $field_edit_id,
'#attributes' => [
- 'id' => [
+ 'class' => [
'entity-reference-tree-widget-field',
],
],
];
+
// Entity type.
- $form['entity_type'] = [
+ $form['tree_container']['entity_type'] = [
'#name' => 'entity_type',
'#type' => 'hidden',
'#weight' => 80,
'#value' => $entity_type,
'#attributes' => [
- 'id' => [
+ 'class' => [
'entity-reference-tree-entity-type',
],
],
];
+
// Entity bundle.
- $form['entity_bundle'] = [
+ $form['tree_container']['entity_bundle'] = [
'#name' => 'entity_bundle',
'#type' => 'hidden',
'#weight' => 80,
'#value' => $bundles,
'#attributes' => [
- 'id' => [
+ 'class' => [
'entity-reference-tree-entity-bundle',
],
],
];
-
+
+ // Disable the cache for this form.
+ $form_state->setCached(FALSE);
+ $form['#cache'] = ['max-age' => 0];
+ $form['#attributes']['data-user-info-from-browser'] = FALSE;
+
+ $form['#attached']['library'][] = 'entity_reference_tree/jstree';
+ $form['#attached']['library'][] = 'entity_reference_tree/entity_tree';
+ $form['#attached']['library'][] = 'entity_reference_tree/jstree_' . $theme . '_theme';
+
// Pass data to js file.
$form['#attached']['drupalSettings'] = [
- 'entity_tree_token_' . $field_edit_id => \Drupal::csrfToken()->get($bundles),
- 'tree_limit_' . $field_edit_id => empty($limit) ? -1 : $limit,
+ 'entity_tree_token_' . $field_edit_id => \Drupal::csrfToken()->get($bundles),
+ 'tree_limit_' . $field_edit_id => empty($limit) ? -1 : $limit,
+ 'widget_type' => 'modal',
];
return $form;
@@ -178,7 +195,7 @@ class SearchForm extends FormBase {
// If there are any form errors, re-display the form.
if ($form_state->hasAnyErrors()) {
- $response->addCommand(new ReplaceCommand('#entity_reference_tree_wrapper', $form));
+ $response->addCommand(new ReplaceCommand('.entity_reference_tree_wrapper', $form));
}
else {
$response->addCommand(new InvokeCommand(NULL, 'entitySearchDialogAjaxCallback', [$form_state->getValue('field_id'), $form_state->getValue('selected_node')]));
diff --git a/src/Plugin/Field/FieldWidget/EntityReferenceTreeWidgetBase.php b/src/Plugin/Field/FieldWidget/EntityReferenceTreeWidgetBase.php
new file mode 100644
index 0000000..7b017bc
--- /dev/null
+++ b/src/Plugin/Field/FieldWidget/EntityReferenceTreeWidgetBase.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace Drupal\entity_reference_tree\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget;
+
+/**
+ * Base class for 'Entity reference tree' widget plugin implementations.
+ */
+abstract class EntityReferenceTreeWidgetBase extends EntityReferenceAutocompleteWidget {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function defaultSettings() {
+ return [
+ // JsTree theme.
+ 'theme' => 'default',
+ // Using dot line.
+ 'dots' => 0,
+ ] + parent::defaultSettings();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function settingsForm(array $form, FormStateInterface $form_state) {
+ $element = [];
+
+ // JsTRee theme.
+ $element['theme'] = [
+ '#type' => 'radios',
+ '#title' => $this->t('JsTree theme'),
+ '#default_value' => $this->getSetting('theme'),
+ '#required' => TRUE,
+ '#options' => [
+ 'default' => $this->t('Default'),
+ 'default-dark' => $this->t('Default Dark'),
+ ],
+ ];
+
+ // Tree dot.
+ $element['dots'] = [
+ '#type' => 'radios',
+ '#title' => $this->t('Dot line'),
+ '#default_value' => $this->getSetting('dots'),
+ '#options' => [
+ 0 => $this->t('No'),
+ 1 => $this->t('Yes'),
+ ],
+ ];
+
+ return $element;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function settingsSummary() {
+ $summary = [];
+
+ // JsTree theme.
+ $summary[] = $this->t('JsTree theme: @theme', ['@theme' => $this->getSetting('theme')]);
+
+ return $summary;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
+ $element = parent::formElement($items, $delta, $element, $form, $form_state);
+
+ // The id of autocomple text field.
+ $edit_id = 'edit-' . str_replace('_', '-', $items->getName()) . '-target-id';
+
+ $element['target_id']['#id'] = $edit_id;
+ $element['target_id']['#tags'] = TRUE;
+ $element['target_id']['#default_value'] = $items->referencedEntities();
+
+ return $element;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
+ return $values['target_id'];
+ }
+
+}
diff --git a/src/Plugin/Field/FieldWidget/InlineEntityReferenceTreeWidget.php b/src/Plugin/Field/FieldWidget/InlineEntityReferenceTreeWidget.php
new file mode 100644
index 0000000..d10e47f
--- /dev/null
+++ b/src/Plugin/Field/FieldWidget/InlineEntityReferenceTreeWidget.php
@@ -0,0 +1,134 @@
+<?php
+
+namespace Drupal\entity_reference_tree\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Field\FieldItemListInterface;
+
+/**
+ * Plugin implementation of the 'inline_entity_reference_tree_widget' widget.
+ *
+ * @FieldWidget(
+ * id = "inline_entity_reference_tree_widget",
+ * module = "dd_tree_builder",
+ * label = @Translation("Inline entity reference tree widget"),
+ * field_types = {
+ * "entity_reference"
+ * },
+ * multiple_values = TRUE
+ * )
+ */
+class InlineEntityReferenceTreeWidget extends EntityReferenceTreeWidgetBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
+ $element = parent::formElement($items, $delta, $element, $form, $form_state);
+
+ $theme = $this->getSetting('theme');
+ $dots = $this->getSetting('dots');
+ $field_edit_id = $element['target_id']['#id'];
+ $entity_type = $element['target_id']['#target_type'];
+ $arr_target = $element['target_id']['#selection_settings']['target_bundles'];
+ $bundles = empty($arr_target) ? '*' : implode(',', $arr_target);
+
+ // All around wrapper.
+ $element['tree_container'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'div',
+ '#attributes' => [
+ 'class' => [
+ 'entity-reference-tree-wrapper',
+ ],
+ ],
+ ];
+
+ // The status messages that will contain any form errors.
+ $element['tree_container']['status_messages'] = [
+ '#type' => 'status_messages',
+ '#weight' => -10,
+ ];
+
+ // Search filter box.
+ $element['tree_container']['tree_search'] = [
+ '#type' => 'textfield',
+ '#title' => $this
+ ->t('Search'),
+ '#size' => 60,
+ '#attributes' => [
+ 'class' => [
+ 'entity-reference-tree-search',
+ ],
+ ],
+ ];
+
+ // Field element id.
+ $element['tree_container']['field_id'] = [
+ '#name' => 'field_id',
+ '#type' => 'hidden',
+ '#weight' => 80,
+ '#value' => $field_edit_id,
+ '#attributes' => [
+ 'class' => [
+ 'entity-reference-tree-widget-field',
+ ],
+ ],
+ ];
+
+ // Entity type.
+ $element['tree_container']['entity_type'] = [
+ '#name' => 'entity_type',
+ '#type' => 'hidden',
+ '#weight' => 80,
+ '#value' => $entity_type,
+ '#attributes' => [
+ 'class' => [
+ 'entity-reference-tree-entity-type',
+ ],
+ ],
+ ];
+
+ // Entity bundle.
+ $element['tree_container']['entity_bundle'] = [
+ '#name' => 'entity_bundle',
+ '#type' => 'hidden',
+ '#weight' => 80,
+ '#value' => $bundles,
+ '#attributes' => [
+ 'class' => [
+ 'entity-reference-tree-entity-bundle',
+ ],
+ ],
+ ];
+
+ // JsTree container.
+ $element['tree_container']['js_tree'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'div',
+ '#attributes' => [
+ 'class' => [
+ 'entity-reference-tree',
+ ],
+ 'theme' => $theme,
+ 'dots' => $dots,
+ ],
+ ];
+
+ // Attach libraries.
+ $form['#attached']['library'][] = 'entity_reference_tree/jstree';
+ $form['#attached']['library'][] = 'entity_reference_tree/jstree_' . $theme . '_theme';
+ $form['#attached']['library'][] = 'entity_reference_tree/entity_tree';
+ $form['#attached']['library'][] = 'entity_reference_tree/widget';
+
+ // Pass data to js file.
+ $element['#attached']['drupalSettings'] = [
+ 'entity_tree_token_' . $field_edit_id => \Drupal::csrfToken()->get($bundles),
+ 'tree_limit_' . $field_edit_id => -1,
+ 'widget_type' => 'inline',
+ ];
+
+ return $element;
+ }
+
+}
diff --git a/src/Plugin/Field/FieldWidget/ModalEntityReferenceTreeWidget.php b/src/Plugin/Field/FieldWidget/ModalEntityReferenceTreeWidget.php
new file mode 100644
index 0000000..daeb1ea
--- /dev/null
+++ b/src/Plugin/Field/FieldWidget/ModalEntityReferenceTreeWidget.php
@@ -0,0 +1,110 @@
+<?php
+
+namespace Drupal\entity_reference_tree\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
+
+/**
+ * A entity reference tree widget.
+ *
+ * @FieldWidget(
+ * id = "entity_reference_tree",
+ * label = @Translation("Entity reference tree widget"),
+ * field_types = {
+ * "entity_reference",
+ * },
+ * multiple_values = TRUE
+ * )
+ */
+class ModalEntityReferenceTreeWidget extends EntityReferenceTreeWidgetBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function defaultSettings() {
+ return [
+ // Button label.
+ 'label' => '',
+ ] + parent::defaultSettings();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function settingsForm(array $form, FormStateInterface $form_state) {
+ $element = parent::settingsForm($form, $form_state);
+
+ // Button label.
+ $element['label'] = [
+ '#type' => 'textfield',
+ '#title' => $this->t('Button label'),
+ '#default_value' => $this->getSetting('label'),
+ ];
+
+ return $element;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function settingsSummary() {
+ $summary = parent::settingsSummary();
+
+ // Button label.
+ if ($label = $this->getSetting('label')) {
+ $summary[] = t('Button label: @label', ['@label' => $label]);
+ }
+
+ return $summary;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state)
+ {
+
+ $arr_element = parent::formElement($items, $delta, $element, $form, $form_state);
+ $arr_target = empty($arr_element['target_id']['#selection_settings']['target_bundles']) ? [] : $arr_element['target_id']['#selection_settings']['target_bundles'];
+ $str_target_type = $arr_element['target_id']['#target_type'];
+
+ $edit_id = $arr_element['target_id']['#id'];
+
+ $label = $this->getSetting('label');
+ if (!$label) {
+ $label = $this->t('@label tree', [
+ '@label' => ucfirst(str_replace('_', ' ', $str_target_type)),
+ ]);
+ } else {
+ $label = $this->t('@label', ['@label' => $label]);
+ }
+
+ $arr_element['dialog_link'] = [
+ '#type' => 'link',
+ '#title' => $label,
+ '#url' => Url::fromRoute(
+ 'entity_reference_tree.widget_form',
+ [
+ 'field_edit_id' => $edit_id,
+ 'bundle' => empty($arr_target) ? '*' : implode(',', $arr_target),
+ 'entity_type' => $str_target_type,
+ 'theme' => $this->getSetting('theme'),
+ 'dots' => $this->getSetting('dots'),
+ 'limit' => $this->fieldDefinition->getFieldStorageDefinition()->getCardinality(),
+ ]),
+ '#attributes' => [
+ 'class' => [
+ 'use-ajax',
+ 'button',
+ ],
+ ],
+ ];
+
+ // Attach libraries.
+ $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
+ $form['#attached']['library'][] = 'entity_reference_tree/widget';
+ return $arr_element;
+ }
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment