comunidad

Creando un componente personalizado con el módulo JFU

 

Para crear un componente personalizado, primero tenemos que crear un módulo personalizado.
Para este ejemplo el nombre de nuestro módulo será “example_jfu” y de nuestro componente será "text_multiple ". 

Creamos el archivo example_jfu.info.yml con la siguiente información.

name: Example JFU
type: module
description: Add custom JFU components.
core_version_requirement: ^9 || ^10
package: Custom
dependencies:
  - jfu

Instalar el módulo personalizado.

Paso siguiente crearemos un campo en cualquiera de las entidades donde se puede agregar campos, en nuestro caso será un nodo.
El tipo de campo puede ser uno de estos.

  • JSON (raw)
  • JSON (text)
  • JSONB/JSON (raw)

En el widget del campo escogemos la opción de “Component”.

Lo mismo hacemos en el format.

Hasta este punto ya tenemos los recursos necesarios para nuestro componente, solo faltaría crearlo.

Configuración del componente

Para definir la configuración del componente usaremos el hook “hook_jfu_add_components”. Nuestro archivo “example_jfu.module” estaría quedando de la siguiente forma.

/**
* Implements hook_jfu_add_components().
*/

function example_jfu_jfu_add_components(array &$added_components) {
  $added_components['text_multiple'] = [
    'image' => TRUE,
    'allow_classes' => 0,
    'allow_select_class' => 0,
    'class_list' => '',
    'module_name' => 'example_jfu'
  ];
}

A partir de este paso ya tenemos disponible el componente, si vamos al widget del campo podemos ver el componente y sus configuraciones.

Configuramos las opciones necesarias y guardamos.

Modelo

Una vez agregado el componente, este aún no hace nada, para ello se debe de crear un modelo.
Este modelo se define en una carpeta  “component_models”, dentro de esta definimos una carpeta con el nombre del componente y dentro de ello un archivo de tipo Json con el nombre del componente “component_models/texto_multiple/texto_multiple.json”.
En este archivo Json definiremos los modelos para cada uno de nuestros campos. El archivo estaría quedando así.

{
  "type": "text_multiple",
  "label": "text multiple",
  "title": "",
  "subtitle": "",
  "body": {
    "type": "text",
    "value": "",
    "format": "basic_html"
  },
  "image": {
    "type": "image",
    "fid": "",
    "alt": "",
    "title": "",
    "value": "",
    "width": "",
    "height": ""
  },
  "options": {
    "full_width": false,
    "custom_classes": "",
    "selected_class": ""
  }
}

Luego de crear el modelo definiremos un archivo “assets/js/index.js” donde estará la funcionalidad de nuestro componente.
El archivo “example_jfu.libraries.yml”  quedaría de la siguiente manera.

example_jfu.jfu_widget:
  js:
    assets/js/index.js: {}
  dependencies:
    - jfu/json_widget_utils

Ya creada la librería tenemos que usar el hook “hook_jfu_attached”. Estaría quedando de la siguiente forma.

/**
* Implements hook_jfu_attached().
*/

function example_jfu_jfu_attached(&$jfu_attached) {
  $jfu_attached = 'example_jfu/example_jfu.jfu_widget';
}

Ahora solo queda ir a nuestro archivo “index.js” e implementar lo siguiente.


Creando la visualización del componente
// Define component display text_multiple
Vue.component('display-text_multiple', {
  props: ['o_data', 'index', 'field_name', 'is_load', 'cardinality', 'options'],
  data: function () {
    return {
      isActive: true
    };
  },
  methods: {
    activeToggle: function() {
      this.isActive = !this.isActive;
    }
  },
  template: `
    <div class="component-item--wrapper" draggable="true" v-on:dragstart="dragStart($event, index)" v-on:dragend="dragEnd($event, field_name)">
      <a v-show="cardinality != 1" class="tabledrag-handle" title="Drag to re-order">
        <div class="handle">&nbsp;</div>
      </a>
      <div class="jfu-toggle" v-on:click="activeToggle">
        <span>{{ o_data.label }}</span>
        <span class="jfu-toggle-trigger-icon" v-bind:class="{'is-active' :isActive}"></span>
      </div>
      <div class="accordion-item--content" v-bind:class="{'is-active' :isActive}">
        <display-content-text_multiple v-bind:o_data="o_data" v-bind:options="options"></display-content-text_multiple>
        <display-operations v-bind:index="index" v-bind:field_name="field_name" v-bind:is_load="is_load" v-bind:type="o_data.type"></display-operations>
      </div>
    </div>
  `
});

// Define component display content text_multiple
Vue.component('display-content-text_multiple', {
  props: ['o_data', 'options'],
  template: `
    <div class="component-item">
      <div v-if="o_data.title" class="tm-item--title">
        <h3>{{ o_data.title }}</h3>
      </div>
      <display-text v-bind:content="o_data.subtitle"></display-text>
      <display-text v-bind:content="o_data.body.value"></display-text>
      <display-image v-bind:o_image="o_data.image" v-bind:options="options"></display-image>
    </div>
  `
});
Creando el formulario del componente
// Define component form text_multiple'
Vue.component('form-text_multiple', {
  props: ['o_json', 'edit_index', 'index', 'field_name', 'components', 'options'],
  template: `
    <form v-on:submit.prevent="edit_index === '' ? addToJfu($event) : updateToJfu($event, o_json.type, edit_index)">
      <form-elements-text_multiple v-bind:o_json="o_json" v-bind:field_name="field_name" v-bind:index="0" v-bind:options="options"></form-elements-text_multiple>
      <div class="error-messages" style="display: none;">
        <span>Image field is required.</span>
      </div>
      <input class="link-to link-to-add" type="submit" value="Save" />
    </form>
  `
});

// Define component form elements text_multiple
Vue.component('form-elements-text_multiple', {
  props: ['o_json', 'index', 'field_name', 'options'],
  template: `
    <div class="form-component">
      <form-classes v-bind:o_json="o_json" v-bind:index="index" v-bind:field_name="field_name" v-bind:options="options"></form-classes>
      <p>
        <label>{{ options.defaultLabels.title }}
          <input type="text" name="tm_title" size="60" maxlength="255" placeholder="Title" v-model="o_json.title" />
        </label>
      </p>
      <p>
        <label>{{ options.defaultLabels.subtitle }}
          <input type="text" name="tm_subtitle" size="60" maxlength="255" placeholder="Subtitle" v-model="o_json.subtitle" />
        </label>
      </p>
      <form-text v-bind:o_json="o_json.body" v-bind:field_name="field_name" v-bind:options="options" v-bind:index="index"></form-text>
      <form-image v-bind:o_image="o_json.image" v-bind:field_name="field_name" v-bind:index="index" v-bind:component="'quote'" v-bind:options="options"></form-image>
      <p>
        <label>{{ options.defaultLabels.full_width }}
          <label><input type="checkbox" id="full_width" v-model="o_json.options.full_width">{{ options.defaultLabels.activate_full_width }}</label>
        </label>
      </p>
    </div>
  `
});

Ahora vamos a llenar contenido, en nuestro campo aparece el botón “Add component”, damos click en este botón y nos muestra un listado de los componentes disponibles, seleccionar nuestro componente, se estaría viendo de la siguiente forma.

img

 

Visualización

Ya llegado a este punto ya estamos a un paso de terminar. Ahora solo nos queda armar una plantilla para nuestro componente.
La plantilla se debe definir de la siguiente forma.

La plantilla principal puede tener cualquier nombre, quedaría de la siguiente manera “templates/example-jfu-component-templates.html.twig”.

<div class="jfu--component jfu-type--{{ json_array.type}}">
  {% if json_array.type %}
    {% include '@example_jfu/components/' ~ json_array.type ~ '.html.twig' with { 'json_array': json_array, 'components_config': components_config } %}
  {% endif %}
</div>

Luego crearemos una carpeta llamada “components” dentro de la carpeta “templates”.
Dentro de la carpeta “components” crearemos una plantilla con el nombre del componente “templates/components/text_multiple.html.twig”, aquí podemos armar nuestro marcado deseado.

<div class="tm-wrapper{{ classes }}">
  <div class="tm-item {{ json_array.options.full_width ? 'container-full-width' : 'container' }}">
    {% if json_array.title is not empty %}
      <h3 class="tm--title">{{ json_array.title }}</h3>
    {% endif %}
    {% if json_array.subtitle is not empty %}
      <h4 class="tm--subtitle">{{ json_array.subtitle }}</h4>
    {% endif %}
    {% if json_array.body.value is not empty %}
      {% include '@jfu/components/jfu_' ~ json_array.body.type ~ '.html.twig' with {'json_array': json_array.body } %}
    {% endif %}
    {% if json_array.image.value is not empty %}
      {% include '@jfu/components/jfu_' ~ json_array.image.type ~ '.html.twig' with {'json_array': json_array.image } %}
    {% endif %}
  </div>
</div>

Finalmente usaremos los siguientes hooks “hook_theme” y “hook_jfu_add_template”.

/**
* Implements hook_theme().
*/

function example_jfu_theme($existing, $type, $theme, $path) {
  return [
    'example_jfu_component_templates' => [
      'template' => 'example-jfu-component-templates',
      'variables' => [
        'values' => NULL,
        'json_array' => NULL,
        'components_config' => NULL,
        'classes' => NULL,
      ],
    ],
  ];
}
/**
 * Implements hook_jfu_add_template().
 */

 function example_jfu_jfu_add_template(&$template) {
  $template = 'example_jfu_component_templates';
}

 

Me pareció interesante el artículo

Deseo más información

O también puedes comunicarte con nosotros.

por whatsapp por whatsapp

Añadir nuevo comentario

Me gustaría más información sobre:

CAPTCHA