visualn-8.x-1.x-dev/modules/visualn_basic_drawers/src/Plugin/VisualN/Drawer/LinechartBasicDrawer.php

modules/visualn_basic_drawers/src/Plugin/VisualN/Drawer/LinechartBasicDrawer.php
<?php

namespace Drupal\visualn_basic_drawers\Plugin\VisualN\Drawer;

use Drupal\visualn\Core\DrawerWithJsBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\visualn\ResourceInterface;
use Drupal\Component\Utility\NestedArray;

/**
 * Provides a 'Line Chart' VisualN drawer.
 *
 * @ingroup drawer_plugins
 *
 * @VisualNDrawer(
 *  id = "visualn_linechart_basic",
 *  label = @Translation("Linechart Basic"),
 * )
 */
class LinechartBasicDrawer extends DrawerWithJsBase {

  /**
   * {@inheritdoc}
   */
  public function getDescription() {
    return t('Basic linechart with variable number of series');
  }

  /**
   * @inheritdoc
   */
  public function defaultConfiguration() {
    $default_config = [
      'series_number' => 1,
      'series_labels' => [],
    ];

    return $default_config;
  }

  /**
   * @inheritdoc
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    // ajax wrapper id must be unique
    $ajax_wrapper_id = !empty($form['#array_parents'])
      ? implode('-', $form['#array_parents']) . '--linechart-ajax-wrapper'
      : 'linechart-ajax-wrapper';
    // @todo: check for other special chars
    // the "|" character is added to visualn_style list on visualn style config page
    $ajax_wrapper_id = str_replace('|', '-', $ajax_wrapper_id);

    $form['series_number'] = [
      '#type' => 'number',
      '#title' => t('Number of series'),
      '#default_value' => $this->configuration['series_number'],
      '#min' => 1,
      '#max' => 10,
      '#required' => TRUE,
    ];

    // @todo: also validation should check if update_series was triggered (if number changed)
    $form['update_series'] = [
      // @todo: add a more concise comment
      // use 'button' instead of 'submit' to avoid calling submit handler
      // also #limit_validation_errors setting and views Drawing display style settings
      // do not work (independently) if used 'submit' type
      '#type' => 'button',
      '#value' => t('Update series'),
      //'#prefix' => '<div class="form-item">',
      //'#suffix' => '</div>',
      '#ajax' => [
        'callback' => [get_called_class(), 'ajaxCallback'],
        'wrapper' => $ajax_wrapper_id,
      ],
      '#limit_validation_errors' => [],
    ];

    if (!empty($form['#parents'])) {
      // Submits must have different names in case multiple instances of the drawer config
      // are shown on a page, otherwise all submits would have an 'op' name with the same 'value'
      // which would cause wrong triggering element at submit.
      $form_parents = $form['#parents'];
      $name = array_shift($form_parents);
      $name .= '[' . implode('][', $form['#parents']) . '][update_series]';
      $form['update_series']['#name'] = $name;
    }

    $form['ajax_container'] = [
      '#type' => 'details',
      '#open' => TRUE,
      '#title' => t('Series labels'),
      '#description' => t('Enter label for each series, leave empty to use defaults.'),
      '#prefix' => '<div id="' . $ajax_wrapper_id . '">',
      '#suffix' => '</div>',
      '#process' => [[get_called_class(), 'processConfigurationFormSectionsUpdate']],
    ];
    $form['ajax_container']['#configuration'] = $this->configuration;

    return $form;
  }

  /**
   * Attach series labels subform.
   */
  public static function processConfigurationFormSectionsUpdate(array $element, FormStateInterface $form_state, $form) {
    $configuration = $element['#configuration'];
    // Generally $element['#parents'] could be used directly here since 'series_number' element triggers ajax request
    // but leave it as it is for clarity.
    $element_parents = array_slice($element['#parents'], 0, -1);
    $series_number = $form_state->getValue(array_merge($element_parents, ['series_number']));
    for ($i = 1; $i <= $series_number; $i++) {
      $element['series_labels'][$i] = [
        '#type' => 'textfield',
        '#title' => t('Data series @series', ['@series' => $i]),
        '#attributes' => ['placeholder' => '#' . $i],
      ];
      if (isset($configuration['series_labels'][$i])) {
        $element['series_labels'][$i]['#default_value'] = $configuration['series_labels'][$i];
      }
    }

    return $element;
  }

  /**
   * @inheritdoc
   */
  public static function ajaxCallback(array $form, FormStateInterface $form_state) {
    $triggering_element = $form_state->getTriggeringElement();
    $visualn_style_id = $form_state->getValue($form_state->getTriggeringElement()['#parents']);
    $triggering_element_parents = array_slice($triggering_element['#array_parents'], 0, -1);
    $element = NestedArray::getValue($form, $triggering_element_parents);

    return $element['ajax_container'];
  }

  /**
   * @inheritdoc
   */
  public function prepareJsConfig(array &$drawer_config) {
    $series_number = $drawer_config['series_number'];
    for ($i = 1; $i <= $series_number; $i++) {
      if (empty($drawer_config['series_labels'][$i])) {
        $drawer_config['series_labels'][$i] = '#' . $i;
      }
    }

    // @todo: 'update_series' should be already removed here, check it
    unset($drawer_config['update_series']);
    unset($drawer_config['ajax_container']);
  }

  /**
   * @inheritdoc
   */
  public function extractFormValues($form, FormStateInterface $form_state) {
    // Since it is supposed to be subform_state, get all the values without limiting the scope.
    $clean_values = $form_state->cleanValues()->getValues();

    // the element may be not set, e.g. when called before values mapping,
    // see VisualNFormsHelper::processDrawerFields() for example
    if (isset($clean_values['ajax_container'])) {
      $clean_values['series_labels'] = $clean_values['ajax_container']['series_labels'];
      foreach ($clean_values['series_labels'] as $k => $label) {
        // trim series labels
        $clean_values['series_labels'][$k] = trim($label);
      }
      unset($clean_values['ajax_container']);
    }

    return $clean_values;
  }

  /**
   * @inheritdoc
   */
  public function prepareBuild(array &$build, $vuid, ResourceInterface $resource) {
    // Attach drawer config to js settings
    parent::prepareBuild($build, $vuid, $resource);
    // @todo: $resource = parent::prepareBuild($build, $vuid, $resource); (?)

    // Attach visualn style libraries
    $build['#attached']['library'][] = 'visualn_basic_drawers/linechart-basic-drawer';

    return $resource;
  }

  /**
   * @inheritdoc
   */
  public function jsId() {
    return 'visualnLinechartBasicDrawer';
  }

  /**
   * @inheritdoc
   */
  public function dataKeys() {
    $data_keys = ['x'];

    // add data key for each series
    for ($i = 1; $i <= $this->configuration['series_number']; $i++) {
      $data_keys[] = 'data' . $i;
    }

    return $data_keys;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc