Skip to content
Snippets Groups Projects
Select Git revision
  • 2.0.x
  • 8.x-1.x
  • 2.0.0-beta19
  • 2.0.0-beta18
  • 2.0.0-beta17
  • 2.0.0-beta16
  • 2.0.0-beta15
  • 2.0.0-beta14
  • 2.0.0-beta13
  • 2.0.0-beta12
  • 2.0.0-beta11
  • 2.0.0-beta10
  • 2.0.0-beta9
  • 2.0.0-beta8
  • 2.0.0-beta7
  • 2.0.0-beta6
  • 2.0.0-beta5
  • 2.0.0-beta4
  • 8.x-1.0-alpha16
  • 2.0.0-beta3
  • 8.x-1.0-alpha15
  • 2.0.0-beta2
22 results

CssClassField.php

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    CssClassField.php 2.69 KiB
    <?php
    
    namespace Drupal\toolshed\Element;
    
    use Drupal\Core\Form\FormStateInterface;
    use Drupal\Core\Render\Element\Textfield;
    
    /**
     * Create a form element for entering and validating CSS classes.
     *
     * @FormElement("css_class")
     */
    class CssClassField extends Textfield {
    
      /**
       * {@inheritdoc}
       */
      public function getInfo(): array {
        $info = parent::getInfo();
    
        // We don't need all the extra process method for autocomplete.
        $info['#process'] = [
          static::class . '::processAjaxForm',
          static::class . '::processGroup',
        ];
    
        $info['#element_validate'][] = static::class . '::validateCssClasses';
        unset($info['#maxlength']);
    
        return $info;
      }
    
      /**
       * {@inheritdoc}
       */
      public static function valueCallback(&$element, $input, FormStateInterface $form_state): mixed {
        if ($input !== FALSE && $input !== NULL) {
          return is_string($input) ? preg_split('#\s+#', $input, -1, PREG_SPLIT_NO_EMPTY) : $input;
        }
    
        return NULL;
      }
    
      /**
       * {@inheritdoc}
       */
      public static function preRenderTextfield($element): array {
        if (is_array($element['#value'])) {
          $element['#attributes']['value'] = implode(' ', $element['#value']);
        }
    
        return parent::preRenderTextfield($element);
      }
    
      /**
       * Validate that the CSS classes entered here are in a valid CSS format.
       *
       * @param array $element
       *   Array definition of this css class element.
       * @param \Drupal\Core\Form\FormStateInterface $form_state
       *   The form state object, containing the build, info and values of the
       *   current form.
       */
      public static function validateCssClasses(array $element, FormStateInterface $form_state): void {
        // If the class names were entered, ensure that they are valid CSS classes.
        $classStr = implode(' ', $element['#value']);
        preg_match_all('/(?<=^| )[\w\-_][\w\-_\[\]:\/]*(?: +|$)/i', $classStr, $matches, PREG_PATTERN_ORDER);
    
        // If the valid class names match the sequences seperated by spaces, then
        // all the class names were valid. Otherwise the naming violations are
        // excluded from the $matches variable.
        if (count($matches[0]) !== count($element['#value'])) {
          $cssErrors = array_diff($element['#value'], array_map('trim', $matches[0]));
          $form_state->setError($element, t(
            'All class values must be valid CSS names. This means they must start with a letter, and can only contain alphanumeric characters, dashes, underscores and brackets. These classes violate these rules: "%cssErrors"',
            ['%cssErrors' => implode(', ', $cssErrors)]
          ));
        }
        else {
          $classes = preg_split('#\s+#', $classStr, -1, PREG_SPLIT_NO_EMPTY);
          $form_state->setValue($element['#parents'], $classes);
        }
      }
    
    }