Skip to content
Snippets Groups Projects
Select Git revision
  • 5.1.x
  • 3495887-fields-challenge-inline
  • 5.0.x
  • 4.0.x
  • 1.0.x
  • previous/3495887-fields-challenge-inline/2025-01-11-1
  • previous/3495887-fields-challenge-inline/2025-01-11
  • 5.1.0-alpha3
  • 5.1.0-alpha2
  • 5.0.0-beta2
  • 5.1.0-alpha1
  • 5.0.0-beta1
  • 5.0.0-alpha16
  • 5.0.0-alpha15
  • 5.0.0-alpha14
  • 5.0.0-alpha13
  • 5.0.0-alpha12
  • 4.0.0-alpha4
  • 5.0.0-alpha11
  • 5.0.0-alpha10
  • 5.0.0-alpha9
  • 5.0.0-alpha8
  • 5.0.0-alpha7
  • 5.0.0-alpha6
  • 5.0.0-alpha5
25 results

README.md

Blame
  • Forked from project / ui_suite_bootstrap
    Source project has a limited visibility.
    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);
        }
      }
    
    }