/**
  * Provides markup for associating a tray trigger with a tray element.
  *
  * A tray is a responsive container that wraps renderable content. Trays
  * present content well on small and large screens alike.
  *
  * @param array $element
  *   A renderable array.
  *
  * @return array
  *   A renderable array.
  */
 public static function preRenderToolbarItem($element)
 {
     // Assign each item a unique ID.
     $id = Html::getUniqueId('toolbar-item');
     // Provide attributes for a toolbar item.
     $attributes = array('id' => $id);
     // If tray content is present, markup the tray and its associated trigger.
     if (!empty($element['tray'])) {
         // Provide attributes necessary for trays.
         $attributes += array('data-toolbar-tray' => $id . '-tray', 'aria-owns' => $id, 'role' => 'button', 'aria-pressed' => 'false');
         // Merge in module-provided attributes.
         $element['tab'] += array('#attributes' => array());
         $element['tab']['#attributes'] += $attributes;
         $element['tab']['#attributes']['class'][] = 'trigger';
         // Provide attributes for the tray theme wrapper.
         $attributes = array('id' => $id . '-tray', 'data-toolbar-tray' => $id . '-tray', 'aria-owned-by' => $id);
         // Merge in module-provided attributes.
         if (!isset($element['tray']['#wrapper_attributes'])) {
             $element['tray']['#wrapper_attributes'] = array();
         }
         $element['tray']['#wrapper_attributes'] += $attributes;
         $element['tray']['#wrapper_attributes']['class'][] = 'toolbar-tray';
     }
     $element['tab']['#attributes']['class'][] = 'toolbar-item';
     return $element;
 }
Esempio n. 2
0
 /**
  * Pre-render callback: Renders a link into #markup.
  *
  * Doing so during pre_render gives modules a chance to alter the link parts.
  *
  * @param array $element
  *   A structured array whose keys form the arguments to _l():
  *   - #title: The link text to pass as argument to _l().
  *   - #url: The URL info either pointing to a route or a non routed path.
  *   - #options: (optional) An array of options to pass to _l() or the link
  *     generator.
  *
  * @return array
  *   The passed-in element containing a rendered link in '#markup'.
  */
 public static function preRenderLink($element)
 {
     // By default, link options to pass to _l() are normally set in #options.
     $element += array('#options' => array());
     // However, within the scope of renderable elements, #attributes is a valid
     // way to specify attributes, too. Take them into account, but do not override
     // attributes from #options.
     if (isset($element['#attributes'])) {
         $element['#options'] += array('attributes' => array());
         $element['#options']['attributes'] += $element['#attributes'];
     }
     // This #pre_render callback can be invoked from inside or outside of a Form
     // API context, and depending on that, a HTML ID may be already set in
     // different locations. #options should have precedence over Form API's #id.
     // #attributes have been taken over into #options above already.
     if (isset($element['#options']['attributes']['id'])) {
         $element['#id'] = $element['#options']['attributes']['id'];
     } elseif (isset($element['#id'])) {
         $element['#options']['attributes']['id'] = $element['#id'];
     }
     // Conditionally invoke self::preRenderAjaxForm(), if #ajax is set.
     if (isset($element['#ajax']) && !isset($element['#ajax_processed'])) {
         // If no HTML ID was found above, automatically create one.
         if (!isset($element['#id'])) {
             $element['#id'] = $element['#options']['attributes']['id'] = HtmlUtility::getUniqueId('ajax-link');
         }
         $element = static::preRenderAjaxForm($element);
     }
     if (!empty($element['#url'])) {
         $options = NestedArray::mergeDeep($element['#url']->getOptions(), $element['#options']);
         $element['#markup'] = \Drupal::l($element['#title'], $element['#url']->setOptions($options));
     }
     return $element;
 }
Esempio n. 3
0
 /**
  * {@inheritdoc}
  */
 protected function preprocessVariables(Variables $variables, $hook, array $info)
 {
     // Retrieve the ID, generating one if needed.
     $id = $variables->getAttribute('id', Html::getUniqueId($variables->offsetGet('id', 'bootstrap-carousel')));
     unset($variables['id']);
     // Build slides.
     foreach ($variables->slides as $key => &$slide) {
         if (!isset($slide['attributes'])) {
             $slide['attributes'] = [];
         }
         $slide['attributes'] = new Attribute($slide['attributes']);
     }
     // Build controls.
     if ($variables->controls) {
         $left_icon = Bootstrap::glyphicon('chevron-left');
         $right_icon = Bootstrap::glyphicon('chevron-right');
         $url = Url::fromUserInput("#{$id}");
         $variables->controls = ['left' => ['#type' => 'link', '#title' => new FormattableMarkup(Element::create($left_icon)->render() . '<span class="sr-only">@text</span>', ['@text' => t('Previous')]), '#url' => $url, '#attributes' => ['class' => ['left', 'carousel-control'], 'role' => 'button', 'data-slide' => 'prev']], 'right' => ['#type' => 'link', '#title' => new FormattableMarkup(Element::create($right_icon)->render() . '<span class="sr-only">@text</span>', ['@text' => t('Next')]), '#url' => $url, '#attributes' => ['class' => ['right', 'carousel-control'], 'role' => 'button', 'data-slide' => 'next']]];
     }
     // Build indicators.
     if ($variables->indicators) {
         $variables->indicators = ['#theme' => 'item_list__bootstrap_carousel_indicators', '#list_type' => 'ol', '#items' => array_keys($variables->slides), '#target' => "#{$id}", '#start_index' => $variables->start_index];
     }
     // Ensure all attributes are proper objects.
     $this->preprocessAttributes($variables, $hook, $info);
 }
Esempio n. 4
0
  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state) {
    $form = parent::form($form, $form_state);

    $form['#title'] = $this->t('Edit subqueue %label', ['%label' => $this->entity->label()]);

    // Since the form has ajax buttons, the $wrapper_id will change each time
    // one of those buttons is clicked. Therefore the whole form has to be
    // replaced, otherwise the buttons will have the old $wrapper_id and will
    // only work on the first click.
    if ($form_state->has('subqueue_form_wrapper_id')) {
      $wrapper_id = $form_state->get('subqueue_form_wrapper_id');
    }
    else {
      $wrapper_id = Html::getUniqueId($this->getFormId() . '-wrapper');
    }

    $form_state->set('subqueue_form_wrapper_id', $wrapper_id);
    $form['#prefix'] = '<div id="' . $wrapper_id . '">';
    $form['#suffix'] = '</div>';

    // @todo Consider creating a 'Machine name' field widget.
    $form['name'] = [
      '#type' => 'machine_name',
      '#default_value' => $this->entity->id(),
      '#machine_name' => array(
        'exists' => '\Drupal\entityqueue\Entity\EntitySubqueue::load',
        'source' => ['title', 'widget', 0, 'value'],
      ),
      '#disabled' => !$this->entity->isNew(),
      '#weight' => -5,
      '#access' => !$this->entity->getQueue()->getHandlerPlugin()->hasAutomatedSubqueues(),
    ];

    return $form;
  }
Esempio n. 5
0
 /**
  * {@inheritdoc}
  */
 protected function preprocessVariables(Variables $variables, $hook, array $info)
 {
     // Retrieve the ID, generating one if needed.
     $id = $variables->getAttribute('id', Html::getUniqueId($variables->offsetGet('id', 'bootstrap-panel')));
     unset($variables['id']);
     // Handle collapsible state.
     if ($variables['heading'] && $variables['collapsible']) {
         // Retrieve the body ID attribute.
         if ($body_id = $variables->getAttribute('id', "{$id}--content", 'body_attributes')) {
             // Ensure the target is set.
             if ($variables['target'] = $variables->offsetGet('target', "#{$body_id}")) {
                 // Set additional necessary attributes to the heading.
                 $variables->setAttributes(['aria-controls' => preg_replace('/^#/', '', $variables['target']), 'aria-expanded' => !$variables['collapsed'] ? 'true' : 'false', 'aria-pressed' => !$variables['collapsed'] ? 'true' : 'false', 'data-toggle' => 'collapse', 'role' => 'button'], 'heading_attributes');
             }
         }
     }
     // Ensure there is a valid panel state.
     if (!$variables->offsetGet('panel_type')) {
         $variables->offsetSet('panel_type', 'default');
     }
     // Convert the description variable.
     $this->preprocessDescription($variables, $hook, $info);
     // Ensure all attributes are proper objects.
     $this->preprocessAttributes($variables, $hook, $info);
 }
/**
 * Submit Mobile Blocks settings.
 * @param $values
 * @param $theme
 * @param $generated_files_path
 */
function at_core_submit_mobile_blocks($values, $theme, $generated_files_path)
{
    $mobile_blocks_css = array();
    // TODO entityManager() is deprecated, but how to replace?
    $theme_blocks = \Drupal::entityManager()->getStorage('block')->loadByProperties(['theme' => $theme]);
    if (!empty($theme_blocks)) {
        foreach ($theme_blocks as $block_key => $block_values) {
            $block_id = $block_values->id();
            if (isset($values['settings_mobile_block_show_' . $block_id]) && $values['settings_mobile_block_show_' . $block_id] == 1) {
                $block_selector = '#' . Html::getUniqueId('block-' . $block_id);
                $mobile_blocks_css[] = $block_selector . ' {display:none}' . "\n";
                $mobile_blocks_css[] = '.is-mobile ' . $block_selector . ' {display:block}' . "\n";
            }
            if (isset($values['settings_mobile_block_hide_' . $block_id]) && $values['settings_mobile_block_hide_' . $block_id] == 1) {
                $block_selector = '#' . Html::getUniqueId('block-' . $block_id);
                $mobile_blocks_css[] = '.is-mobile ' . $block_selector . ' {display:none}' . "\n";
                $mobile_blocks_css[] = $block_selector . ' {display:block}' . "\n";
            }
        }
    }
    if (!empty($mobile_blocks_css)) {
        $file_name = 'mobile-blocks.css';
        $filepath = $generated_files_path . '/' . $file_name;
        file_unmanaged_save_data($mobile_blocks_css, $filepath, FILE_EXISTS_REPLACE);
    }
}
Esempio n. 7
0
/**
 * @file
 * Save Breadcrumb CSS to file
 */
function at_core_submit_mobile_blocks($values, $theme, $generated_files_path) {
  $mobile_blocks_css = array();
  $theme_blocks = entity_load_multiple_by_properties('block', ['theme' => $theme]);

  if (!empty($theme_blocks)) {
    foreach ($theme_blocks as $block_key => $block_values) {
      $block_id = $block_values->id();
      if (isset($values['settings_mobile_block_show_' . $block_id]) && $values['settings_mobile_block_show_' . $block_id] == 1) {
        $block_selector = '#' . Html::getUniqueId('block-' . $block_id);
        $mobile_blocks_css[] = $block_selector . ' {display:none}' . "\n";
        $mobile_blocks_css[] = '.is-mobile ' . $block_selector . ' {display:block}' . "\n";
      }
      if (isset($values['settings_mobile_block_hide_' . $block_id]) && $values['settings_mobile_block_hide_' . $block_id] == 1) {
        $block_selector = '#' . Html::getUniqueId('block-' . $block_id);
        $mobile_blocks_css[] = '.is-mobile ' . $block_selector . ' {display:none}' . "\n";
        $mobile_blocks_css[] = $block_selector . ' {display:block}' . "\n";
      }
    }
  }

  if (!empty($mobile_blocks_css)) {
    $file_name = 'mobile-blocks.css';
    $filepath = $generated_files_path . '/' . $file_name;
    file_unmanaged_save_data($mobile_blocks_css, $filepath, FILE_EXISTS_REPLACE);
  }
}
 /**
  * {@inheritdoc}
  */
 public function getFormId()
 {
     /* @var $transition WorkflowTransitionInterface */
     $transition = $this->entity;
     $field_name = $transition->getFieldName();
     /* @var $entity EntityInterface */
     // Entity may be empty on VBO bulk form.
     // $entity = $transition->getTargetEntity();
     // Compose Form Id from string + Entity Id + Field name.
     // Field ID contains entity_type, bundle, field_name.
     // The Form Id is unique, to allow for multiple forms per page.
     // $workflow_type_id = $transition->getWorkflowId();
     // Field name contains implicit entity_type & bundle (since 1 field per entity)
     // $entity_type = $transition->getTargetEntityTypeId();
     // $entity_id = $transition->getTargetEntityId();;
     // Emulate nodeForm convention.
     if ($transition->id()) {
         $suffix = 'edit_form';
     } else {
         $suffix = 'form';
     }
     $form_id = implode('_', array('workflow_transition', $field_name, $suffix));
     $form_id = Html::getUniqueId($form_id);
     return $form_id;
 }
Esempio n. 9
0
 /**
  * Overrides \Drupal\views\Plugin\views\display\PathPluginBase::render().
  */
 public function render()
 {
     if (!empty($this->options['geolocation_field'])) {
         $geo_field = $this->options['geolocation_field'];
         $this->view->field[$geo_field]->options['exclude'] = TRUE;
     } else {
         // TODO: Throw some exception here, we're done.
         return [];
     }
     if (!empty($this->options['title_field'])) {
         $title_field = $this->options['title_field'];
         $this->view->field[$title_field]->options['exclude'] = TRUE;
     }
     $id = \Drupal\Component\Utility\Html::getUniqueId($this->pluginId);
     $build = ['#theme' => 'geolocation_common_map_display', '#id' => $id, '#attached' => ['library' => ['geolocation/geolocation.commonmap'], 'drupalSettings' => ['geolocation' => ['commonMap' => ['id' => $id]]]]];
     foreach ($this->view->result as $row) {
         if (!empty($title_field)) {
             $title_field_handler = $this->view->field[$title_field];
             $title_build = array('#theme' => $title_field_handler->themeFunctions(), '#view' => $title_field_handler->view, '#field' => $title_field_handler, '#row' => $row);
         }
         $geo_items = $this->view->field[$geo_field]->getItems($row);
         foreach ($geo_items as $delta => $item) {
             $geolocation = $item['raw'];
             $position = ['lat' => $geolocation->lat, 'lng' => $geolocation->lng];
             $build['#locations'][] = ['#theme' => 'geolocation_common_map_location', '#content' => $this->view->rowPlugin->render($row), '#title' => empty($title_build) ? '' : $title_build, '#position' => $position];
         }
     }
     $centre = NULL;
     foreach ($this->options['centre'] as $id => $option) {
         if (empty($option['enable'])) {
             continue;
         }
         switch ($id) {
             case 'fixed_value':
                 $centre = ['lat' => (double) $option['settings']['latitude'], 'lng' => (double) $option['settings']['longitude']];
                 break;
             case preg_match('/proximity_filter_*/', $id) ? true : false:
                 $filter_id = substr($id, 17);
                 $handler = $this->displayHandler->getHandler('filter', $filter_id);
                 if ($handler->value['lat'] && $handler->value['lng']) {
                     $centre = ['lat' => (double) $handler->value['lat'], 'lng' => (double) $handler->value['lng']];
                 }
                 break;
             case 'first_row':
                 if (!empty($build['#locations'][0]['#position'])) {
                     $centre = $build['#locations'][0]['#position'];
                 }
                 break;
         }
         if (!empty($centre['lat']) || !empty($centre['lng']) || !empty($centre['locate'])) {
             // We're done, no need for further options.
             break;
         }
     }
     if (!empty($centre)) {
         $build['#centre'] = $centre;
     }
     return $build;
 }
Esempio n. 10
0
 /**
  * Processes a container element.
  *
  * @param array $element
  *   An associative array containing the properties and children of the
  *   container.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  * @param array $complete_form
  *   The complete form structure.
  *
  * @return array
  *   The processed element.
  */
 public static function processContainer(&$element, FormStateInterface $form_state, &$complete_form)
 {
     // Generate the ID of the element if it's not explicitly given.
     if (!isset($element['#id'])) {
         $element['#id'] = HtmlUtility::getUniqueId(implode('-', $element['#parents']) . '-wrapper');
     }
     return $element;
 }
Esempio n. 11
0
 /**
  * Returns a ID that is guaranteed uniqueness.
  *
  * @return string
  *   A unique id to be used to generate aria attributes.
  */
 public function getAriaId()
 {
     static $id;
     if (!isset($id)) {
         $id = Html::getUniqueId($this->get('id'));
     }
     return $id;
 }
Esempio n. 12
0
 /**
  * {@inheritdoc}
  */
 public function preprocessVariables(Variables $variables)
 {
     // Ensure a unique ID, generating one if needed.
     $id = $variables->getAttribute('id', Html::getUniqueId($variables->offsetGet('id', 'progress-bar')));
     $variables->setAttribute('id', $id);
     unset($variables['id']);
     // Preprocess attributes.
     $this->preprocessAttributes();
 }
Esempio n. 13
0
/**
 * Pre-processes variables for the "bootstrap_panel" theme hook.
 *
 * See template for list of available variables.
 *
 * @see bootstrap-panel.html.twig
 *
 * @ingroup theme_preprocess
 */
function bootstrap_preprocess_bootstrap_panel(&$variables)
{
    $element = $variables['element'];
    Element::setAttributes($element, array('id'));
    Element\RenderElement::setAttributes($element);
    $variables['attributes'] = $element['#attributes'];
    $variables['prefix'] = isset($element['#field_prefix']) ? $element['#field_prefix'] : NULL;
    $variables['suffix'] = isset($element['#field_suffix']) ? $element['#field_suffix'] : NULL;
    $variables['title_display'] = isset($element['#title_display']) ? $element['#title_display'] : NULL;
    $variables['children'] = $element['#children'];
    $variables['required'] = !empty($element['#required']) ? $element['#required'] : NULL;
    $variables['legend']['title'] = !empty($element['#title']) ? Xss::filterAdmin($element['#title']) : '';
    $variables['legend']['attributes'] = new Attribute();
    $variables['legend_span']['attributes'] = new Attribute();
    if (!empty($element['#description'])) {
        $description_id = $element['#attributes']['id'] . '--description';
        $description_attributes['id'] = $description_id;
        $variables['description']['attributes'] = new Attribute($description_attributes);
        $variables['description']['content'] = $element['#description'];
        // Add the description's id to the fieldset aria attributes.
        $variables['attributes']['aria-describedby'] = $description_id;
    }
    $variables['collapsible'] = FALSE;
    if (isset($element['#collapsible'])) {
        $variables['collapsible'] = $element['#collapsible'];
        $variables['attributes']['class'][] = 'collapsible';
    }
    $variables['collapsed'] = FALSE;
    if (isset($element['#collapsed'])) {
        $variables['collapsed'] = $element['#collapsed'];
    }
    // Force grouped fieldsets to not be collapsible (for vertical tabs).
    if (!empty($element['#group'])) {
        $variables['collapsible'] = FALSE;
        $variables['collapsed'] = FALSE;
    }
    if (!isset($element['#id']) && $variables['collapsible']) {
        $element['#id'] = \Drupal\Component\Utility\Html::getUniqueId('bootstrap-panel');
    }
    $variables['target'] = NULL;
    if (isset($element['#id'])) {
        if (!isset($variables['attributes']['id'])) {
            $variables['attributes']['id'] = $element['#id'];
        }
        $variables['target'] = '#' . $element['#id'] . ' > .collapse';
    }
    // Iterate over optional variables.
    $keys = array('description', 'prefix', 'suffix', 'title', 'value');
    foreach ($keys as $key) {
        $variables[$key] = !empty($element["#{$key}"]) ? $element["#{$key}"] : FALSE;
    }
}
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state)
 {
     $config = $this->config('payment_form.payment_type');
     $form['plugin_selector'] = $this->getPluginSelector($form_state)->buildSelectorForm([], $form_state);
     $limit_allowed_plugins_id = Html::getUniqueId('limit_allowed_plugins');
     $form['limit_allowed_plugins'] = ['#default_value' => $config->get('limit_allowed_plugins'), '#id' => $limit_allowed_plugins_id, '#title' => $this->t('Limit allowed payment methods'), '#type' => 'checkbox'];
     $allowed_plugin_ids = $config->get('allowed_plugin_ids');
     $options = [];
     foreach ($this->paymentMethodManager->getDefinitions() as $definition) {
         $options[$definition['id']] = $definition['label'];
     }
     $form['allowed_plugin_ids'] = ['#default_value' => $allowed_plugin_ids, '#multiple' => TRUE, '#options' => $options, '#states' => ['visible' => ['#' . $limit_allowed_plugins_id => ['checked' => TRUE]]], '#title' => $this->t('Allowed payment methods'), '#type' => 'select'];
     return $form + parent::buildForm($form, $form_state);
 }
Esempio n. 15
0
 /**
  * Tests default and custom block categories.
  */
 public function testBlockCategory()
 {
     $this->drupalLogin($this->drupalCreateUser(array('administer views', 'administer blocks')));
     // Create a new view in the UI.
     $edit = array();
     $edit['label'] = $this->randomString();
     $edit['id'] = strtolower($this->randomMachineName());
     $edit['show[wizard_key]'] = 'standard:views_test_data';
     $edit['description'] = $this->randomString();
     $edit['block[create]'] = TRUE;
     $edit['block[style][row_plugin]'] = 'fields';
     $this->drupalPostForm('admin/structure/views/add', $edit, t('Save and edit'));
     // Test that the block was given a default category corresponding to its
     // base table.
     $arguments = array(':id' => 'edit-category-lists-views', ':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-1', ':href' => \Drupal::Url('block.admin_add', array('plugin_id' => 'views_block:' . $edit['id'] . '-block_1', 'theme' => 'classy')), ':text' => $edit['label']);
     $this->drupalGet('admin/structure/block');
     $elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
     $this->assertTrue(!empty($elements), 'The test block appears in the category for its base table.');
     // Duplicate the block before changing the category.
     $this->drupalPostForm('admin/structure/views/view/' . $edit['id'] . '/edit/block_1', array(), t('Duplicate @display_title', array('@display_title' => 'Block')));
     $this->assertUrl('admin/structure/views/view/' . $edit['id'] . '/edit/block_2');
     // Change the block category to a random string.
     $this->drupalGet('admin/structure/views/view/' . $edit['id'] . '/edit/block_1');
     $label = t('Lists (Views)');
     $link = $this->xpath('//a[@id="views-block-1-block-category" and normalize-space(text())=:label]', array(':label' => $label));
     $this->assertTrue(!empty($link));
     $this->clickLink($label);
     $category = $this->randomString();
     $this->drupalPostForm(NULL, array('block_category' => $category), t('Apply'));
     // Duplicate the block after changing the category.
     $this->drupalPostForm(NULL, array(), t('Duplicate @display_title', array('@display_title' => 'Block')));
     $this->assertUrl('admin/structure/views/view/' . $edit['id'] . '/edit/block_3');
     $this->drupalPostForm(NULL, array(), t('Save'));
     // Test that the blocks are listed under the correct categories.
     $category_id = Html::getUniqueId('edit-category-' . SafeMarkup::checkPlain($category));
     $arguments[':id'] = $category_id;
     $this->drupalGet('admin/structure/block');
     $elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
     $this->assertTrue(!empty($elements), 'The test block appears in the custom category.');
     $arguments = array(':id' => 'edit-category-lists-views', ':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-2', ':href' => \Drupal::Url('block.admin_add', array('plugin_id' => 'views_block:' . $edit['id'] . '-block_2', 'theme' => 'classy')), ':text' => $edit['label']);
     $elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
     $this->assertTrue(!empty($elements), 'The first duplicated test block remains in the original category.');
     $arguments = array(':id' => $category_id, ':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-3', ':href' => \Drupal::Url('block.admin_add', array('plugin_id' => 'views_block:' . $edit['id'] . '-block_3', 'theme' => 'classy')), ':text' => $edit['label']);
     $elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
     $this->assertTrue(!empty($elements), 'The second duplicated test block appears in the custom category.');
 }
Esempio n. 16
0
 /**
  * {@inheritdoc}
  */
 public function preprocessVariables(Variables $variables, $hook, array $info)
 {
     if (!empty($variables['description'])) {
         $variables['description'] = FieldFilteredMarkup::create($variables['description']);
     }
     $descriptions = [];
     $cardinality = $variables['cardinality'];
     if (isset($cardinality)) {
         if ($cardinality == -1) {
             $descriptions[] = t('Unlimited number of files can be uploaded to this field.');
         } else {
             $descriptions[] = \Drupal::translation()->formatPlural($cardinality, 'One file only.', 'Maximum @count files.');
         }
     }
     $upload_validators = $variables['upload_validators'];
     if (isset($upload_validators['file_validate_size'])) {
         $descriptions[] = t('@size limit.', ['@size' => format_size($upload_validators['file_validate_size'][0])]);
     }
     if (isset($upload_validators['file_validate_extensions'])) {
         $extensions = new FormattableMarkup('<code>@extensions</code>', ['@extensions' => implode(', ', explode(' ', $upload_validators['file_validate_extensions'][0]))]);
         $descriptions[] = t('Allowed types: @extensions.', ['@extensions' => $extensions]);
     }
     if (isset($upload_validators['file_validate_image_resolution'])) {
         $max = $upload_validators['file_validate_image_resolution'][0];
         $min = $upload_validators['file_validate_image_resolution'][1];
         if ($min && $max && $min == $max) {
             $descriptions[] = t('Images must be exactly <strong>@size</strong> pixels.', ['@size' => $max]);
         } elseif ($min && $max) {
             $descriptions[] = t('Images must be larger than <strong>@min</strong> pixels. Images larger than <strong>@max</strong> pixels will be resized.', ['@min' => $min, '@max' => $max]);
         } elseif ($min) {
             $descriptions[] = t('Images must be larger than <strong>@min</strong> pixels.', ['@min' => $min]);
         } elseif ($max) {
             $descriptions[] = t('Images larger than <strong>@max</strong> pixels will be resized.', ['@max' => $max]);
         }
     }
     $variables['descriptions'] = $descriptions;
     if ($descriptions) {
         $build = array();
         $id = Html::getUniqueId('upload-instructions');
         $build['toggle'] = ['#type' => 'link', '#title' => t('Upload requirements'), '#url' => Url::fromUserInput("#{$id}"), '#icon' => Bootstrap::glyphicon('question-sign'), '#attributes' => ['class' => ['icon-before'], 'data-toggle' => 'popover', 'data-html' => 'true', 'data-placement' => 'bottom', 'data-title' => t('Upload requirements')]];
         $build['requirements'] = ['#type' => 'container', '#theme_wrappers' => ['container__file_upload_help'], '#attributes' => ['id' => $id, 'class' => ['hidden', 'help-block'], 'aria-hidden' => 'true']];
         $build['requirements']['descriptions'] = ['#theme' => 'item_list__file_upload_help', '#items' => $descriptions];
         $variables['popover'] = $build;
     }
 }
Esempio n. 17
0
 /**
  * Expands a radios element into individual radio elements.
  */
 public static function processRadios(&$element, FormStateInterface $form_state, &$complete_form)
 {
     if (count($element['#options']) > 0) {
         $weight = 0;
         foreach ($element['#options'] as $key => $choice) {
             // Maintain order of options as defined in #options, in case the element
             // defines custom option sub-elements, but does not define all option
             // sub-elements.
             $weight += 0.001;
             $element += array($key => array());
             // Generate the parents as the autogenerator does, so we will have a
             // unique id for each radio button.
             $parents_for_id = array_merge($element['#parents'], array($key));
             $element[$key] += array('#type' => 'radio', '#title' => $choice, '#return_value' => $key, '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : FALSE, '#attributes' => $element['#attributes'], '#parents' => $element['#parents'], '#id' => HtmlUtility::getUniqueId('edit-' . implode('-', $parents_for_id)), '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, '#error_no_message' => TRUE, '#weight' => $weight);
         }
     }
     return $element;
 }
Esempio n. 18
0
 /**
  * Determine the target selector for the OpenDialogCommand.
  *
  * @param array &$options
  *   The 'target' option, if set, is used, and then removed from $options.
  * @param RouteMatchInterface $route_match
  *   When no 'target' option is set in $options, $route_match is used instead
  *   to determine the target.
  *
  * @return string
  *   The target selector.
  */
 protected function determineTargetSelector(array &$options, RouteMatchInterface $route_match)
 {
     // Generate the target wrapper for the dialog.
     if (isset($options['target'])) {
         // If the target was nominated in the incoming options, use that.
         $target = $options['target'];
         // Ensure the target includes the #.
         if (substr($target, 0, 1) != '#') {
             $target = '#' . $target;
         }
         // This shouldn't be passed on to jQuery.ui.dialog.
         unset($options['target']);
     } else {
         // Generate a target based on the route id.
         $route_name = $route_match->getRouteName();
         $target = '#' . Html::getUniqueId("drupal-dialog-{$route_name}");
     }
     return $target;
 }
Esempio n. 19
0
 /**
  * {@inheritdoc}
  */
 public function form(array $form, FormStateInterface $form_state)
 {
     /** @var \Drupal\address\Entity\ZoneInterface $zone */
     $zone = $this->entity;
     $user_input = $form_state->getUserInput();
     $form['#tree'] = TRUE;
     $form['name'] = ['#type' => 'textfield', '#title' => $this->t('Name'), '#default_value' => $zone->getName(), '#maxlength' => 255, '#required' => TRUE];
     $form['id'] = ['#type' => 'machine_name', '#title' => $this->t('Machine name'), '#default_value' => $zone->getId(), '#machine_name' => ['exists' => '\\Drupal\\address\\Entity\\Zone::load', 'source' => ['name']], '#maxlength' => 255, '#required' => TRUE];
     $form['scope'] = ['#type' => 'textfield', '#title' => $this->t('Scope'), '#description' => $this->t('Used to group zones by purpose. Examples: tax, shipping.'), '#default_value' => $zone->getScope(), '#maxlength' => 255];
     $form['priority'] = ['#type' => 'weight', '#title' => $this->t('Priority'), '#description' => $this->t('Zones with a higher priority will be matched first.'), '#default_value' => (int) $zone->getPriority(), '#delta' => 10];
     $wrapper_id = Html::getUniqueId('zone-members-ajax-wrapper');
     $form['members'] = ['#type' => 'table', '#header' => [$this->t('Type'), $this->t('Zone member'), $this->t('Weight'), $this->t('Operations')], '#tabledrag' => [['action' => 'order', 'relationship' => 'sibling', 'group' => 'zone-member-order-weight']], '#weight' => 5, '#prefix' => '<div id="' . $wrapper_id . '">', '#suffix' => '</div>'];
     $index = 0;
     /** @var \Drupal\address\Plugin\ZoneMember\ZoneMemberInterface $member */
     foreach ($zone->getMembers() as $key => $member) {
         $member_form =& $form['members'][$index];
         $member_form['#attributes']['class'][] = 'draggable';
         $member_form['#weight'] = isset($user_input['members'][$index]) ? $user_input['members'][$index]['weight'] : $member->getWeight();
         $member_form['type'] = ['#type' => 'markup', '#markup' => $member->getPluginDefinition()['name']];
         $member_parents = ['members', $index, 'form'];
         $member_form_state = $this->buildMemberFormState($member_parents, $form_state);
         $member_form['form'] = $member->buildConfigurationForm([], $member_form_state);
         $member_form['form']['#element_validate'] = ['::memberFormValidate'];
         $member_form['weight'] = ['#type' => 'weight', '#title' => $this->t('Weight for @title', ['@title' => $member->getName()]), '#title_display' => 'invisible', '#default_value' => $member->getWeight(), '#attributes' => ['class' => ['zone-member-order-weight']]];
         $member_form['remove'] = ['#type' => 'submit', '#name' => 'remove_member' . $index, '#value' => $this->t('Remove'), '#limit_validation_errors' => [], '#submit' => ['::removeMemberSubmit'], '#member_index' => $index, '#ajax' => ['callback' => '::membersAjax', 'wrapper' => $wrapper_id]];
         $index++;
     }
     // Sort the members by weight. Ensures weight is preserved on ajax refresh.
     uasort($form['members'], ['\\Drupal\\Component\\Utility\\SortArray', 'sortByWeightProperty']);
     $plugins = [];
     foreach ($this->memberManager->getDefinitions() as $plugin => $definition) {
         $plugins[$plugin] = $definition['name'];
     }
     $form['members']['_new'] = ['#tree' => FALSE];
     $form['members']['_new']['type'] = ['#prefix' => '<div class="zone-member-new">', '#suffix' => '</div>'];
     $form['members']['_new']['type']['plugin'] = ['#type' => 'select', '#title' => $this->t('Zone member type'), '#title_display' => 'invisible', '#options' => $plugins, '#empty_value' => ''];
     $form['members']['_new']['type']['add_member'] = ['#type' => 'submit', '#value' => $this->t('Add'), '#validate' => ['::addMemberValidate'], '#submit' => ['::addMemberSubmit'], '#limit_validation_errors' => [['plugin']], '#ajax' => ['callback' => '::membersAjax', 'wrapper' => $wrapper_id]];
     $form['members']['_new']['member'] = ['data' => []];
     $form['members']['_new']['operations'] = ['data' => []];
     return parent::form($form, $form_state);
 }
Esempio n. 20
0
 /**
  * Builds the customer form.
  *
  * @param array $form
  *   The parent form.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  * @param \Drupal\commerce_order\Entity\OrderInterface $order
  *   The current order, if known.
  *
  * @return array
  *   The parent form with the customer form elements added.
  */
 public function buildCustomerForm(array $form, FormStateInterface $form_state, OrderInterface $order = NULL)
 {
     $selected_customer_type = $form_state->getValue(['customer_type'], 'existing');
     $wrapper_id = Html::getUniqueId('customer-fieldset-wrapper');
     $form['customer'] = ['#type' => 'fieldset', '#title' => t('Customer'), '#prefix' => '<div id="' . $wrapper_id . '">', '#suffix' => '</div>'];
     $form['customer']['customer_type'] = ['#type' => 'radios', '#title' => t('Order for'), '#title_display' => 'invisible', '#attributes' => ['class' => ['container-inline']], '#required' => TRUE, '#options' => ['existing' => t('Existing customer'), 'new' => t('New customer')], '#default_value' => $selected_customer_type, '#ajax' => ['callback' => [$this, 'customerFormAjax'], 'wrapper' => $wrapper_id]];
     if ($selected_customer_type == 'existing') {
         $form['customer']['uid'] = ['#type' => 'entity_autocomplete', '#title' => t('Search'), '#attributes' => ['class' => ['container-inline']], '#placeholder' => t('Search by username or email address'), '#target_type' => 'user', '#selection_settings' => ['match_operator' => 'CONTAINS', 'include_anonymous' => FALSE]];
     } else {
         // New customer.
         $form['customer']['uid'] = ['#type' => 'value', '#value' => 0];
         $form['customer']['mail'] = ['#type' => 'email', '#title' => t('Email'), '#required' => TRUE];
         $form['customer']['password'] = ['#type' => 'container'];
         $form['customer']['password']['generate'] = ['#type' => 'checkbox', '#title' => t('Generate password'), '#default_value' => 1];
         // The password_confirm element needs to be wrapped in order for #states
         // to work properly. See https://www.drupal.org/node/1427838.
         $form['customer']['password']['password_confirm_wrapper'] = ['#type' => 'container', '#states' => ['visible' => [':input[name="generate"]' => ['checked' => FALSE]]]];
         // We cannot make this required due to HTML5 validation.
         $form['customer']['password']['password_confirm_wrapper']['pass'] = ['#type' => 'password_confirm', '#size' => 25];
     }
     return $form;
 }
Esempio n. 21
0
 /**
  * Overrides \Drupal\views\Plugin\views\display\PathPluginBase::render().
  */
 public function render()
 {
     if (!empty($this->options['geolocation_field'])) {
         $geo_field = $this->options['geolocation_field'];
         $this->view->field[$geo_field]->options['exclude'] = TRUE;
     } else {
         // TODO: Throw some exception here, we're done.
         return [];
     }
     if (!empty($this->options['title_field'])) {
         $title_field = $this->options['title_field'];
         $this->view->field[$title_field]->options['exclude'] = TRUE;
     }
     $id = \Drupal\Component\Utility\Html::getUniqueId($this->pluginId);
     $build = ['#theme' => 'geolocation_common_map_display', '#id' => $id, '#attached' => ['library' => ['geolocation/geolocation.commonmap'], 'drupalSettings' => ['geolocation' => ['commonMap' => ['id' => $id]]]]];
     foreach ($this->view->result as $row) {
         $title = empty($title_field) ? '' : $this->view->field[$title_field]->theme($row);
         $geo_items = $this->view->field[$geo_field]->getItems($row);
         foreach ($geo_items as $delta => $item) {
             $geolocation = $item['raw'];
             $position = ['lat' => $geolocation->lat, 'lng' => $geolocation->lng];
             $build['#locations'][] = ['#theme' => 'geolocation_common_map_location', '#content' => $this->view->rowPlugin->render($row), '#title' => $title, '#position' => $position];
         }
     }
     $centre = ['lat' => 0, 'lng' => 0];
     switch ($this->options['centre']) {
         case 'fixed_value':
             $centre = ['lat' => (double) $this->options['centre_fixed_values']['latitude'], 'lng' => (double) $this->options['centre_fixed_values']['longitude']];
             break;
         case 'first_row':
         default:
             if (!empty($build['#locations'][0]['#position'])) {
                 $centre = $build['#locations'][0]['#position'];
             }
             break;
     }
     $build['#centre'] = $centre;
     return $build;
 }
Esempio n. 22
0
 /**
  * {@inheritdoc}
  */
 protected function preprocessVariables(Variables $variables, $hook, array $info)
 {
     // Immediately log an error and return if Bootstrap modals are not enabled.
     if (!$this->theme->getSetting('modal_enabled')) {
         \Drupal::logger('bootstrap')->error(t('Bootstrap modals are not enabled.'));
         return;
     }
     // Retrieve the ID, generating one if needed.
     $id = $variables->getAttribute('id', Html::getUniqueId($variables->offsetGet('id', 'bootstrap-modal')));
     $variables->setAttribute('id', $id);
     unset($variables['id']);
     if ($variables->title) {
         $title_id = $variables->getAttribute('id', "{$id}--title", $variables::TITLE);
         $variables->setAttribute('id', $title_id, $variables::TITLE);
         $variables->setAttribute('aria-labelledby', $title_id);
     }
     // Use a provided modal size or retrieve the default theme setting.
     $variables->size = $variables->size ?: $this->theme->getSetting('modal_size');
     // Convert the description variable.
     $this->preprocessDescription($variables, $hook, $info);
     // Ensure all attributes are proper objects.
     $this->preprocessAttributes($variables, $hook, $info);
 }
Esempio n. 23
0
 /**
  * Tests that the block form has a theme selector when not passed via the URL.
  */
 public function testBlockThemeSelector()
 {
     // Install all themes.
     \Drupal::service('theme_handler')->install(['bartik', 'seven', 'stark']);
     $theme_settings = $this->config('system.theme');
     foreach (['bartik', 'seven', 'stark'] as $theme) {
         $this->drupalGet('admin/structure/block/list/' . $theme);
         $this->assertTitle(t('Block layout') . ' | Drupal');
         // Select the 'Powered by Drupal' block to be placed.
         $block = array();
         $block['id'] = strtolower($this->randomMachineName());
         $block['theme'] = $theme;
         $block['region'] = 'content';
         $this->drupalPostForm('admin/structure/block/add/system_powered_by_block', $block, t('Save block'));
         $this->assertText(t('The block configuration has been saved.'));
         $this->assertUrl('admin/structure/block/list/' . $theme . '?block-placement=' . Html::getClass($block['id']));
         // Set the default theme and ensure the block is placed.
         $theme_settings->set('default', $theme)->save();
         $this->drupalGet('');
         $elements = $this->xpath('//div[@id = :id]', array(':id' => Html::getUniqueId('block-' . $block['id'])));
         $this->assertTrue(!empty($elements), 'The block was found.');
     }
 }
Esempio n. 24
0
 /**
  * {@inheritdoc}
  */
 public function optionLink($text, $section, $class = '', $title = '')
 {
     if (!trim($text)) {
         $text = $this->t('Broken field');
     }
     if (!empty($class)) {
         $text = SafeMarkup::format('<span>@text</span>', array('@text' => $text));
     }
     if (empty($title)) {
         $title = $text;
     }
     return \Drupal::l($text, new Url('views_ui.form_display', array('js' => 'nojs', 'view' => $this->view->storage->id(), 'display_id' => $this->display['id'], 'type' => $section), array('attributes' => array('class' => array('views-ajax-link', $class), 'title' => $title, 'id' => Html::getUniqueId('views-' . $this->display['id'] . '-' . $section)))));
 }
Esempio n. 25
0
 /**
  * {@inheritdoc}
  */
 public function form(array $form, FormStateInterface $form_state)
 {
     /** @var \Drupal\comment\CommentInterface $comment */
     $comment = $this->entity;
     $entity = $this->entityManager->getStorage($comment->getCommentedEntityTypeId())->load($comment->getCommentedEntityId());
     $field_name = $comment->getFieldName();
     $field_definition = $this->entityManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle())[$comment->getFieldName()];
     $config = $this->config('user.settings');
     // In several places within this function, we vary $form on:
     // - The current user's permissions.
     // - Whether the current user is authenticated or anonymous.
     // - The 'user.settings' configuration.
     // - The comment field's definition.
     $form['#cache']['contexts'][] = 'user.permissions';
     $form['#cache']['contexts'][] = 'user.roles:authenticated';
     $this->renderer->addCacheableDependency($form, $config);
     $this->renderer->addCacheableDependency($form, $field_definition->getConfig($entity->bundle()));
     // Use #comment-form as unique jump target, regardless of entity type.
     $form['#id'] = Html::getUniqueId('comment_form');
     $form['#theme'] = array('comment_form__' . $entity->getEntityTypeId() . '__' . $entity->bundle() . '__' . $field_name, 'comment_form');
     $anonymous_contact = $field_definition->getSetting('anonymous');
     $is_admin = $comment->id() && $this->currentUser->hasPermission('administer comments');
     if (!$this->currentUser->isAuthenticated() && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT) {
         $form['#attached']['library'][] = 'core/drupal.form';
         $form['#attributes']['data-user-info-from-browser'] = TRUE;
     }
     // If not replying to a comment, use our dedicated page callback for new
     // Comments on entities.
     if (!$comment->id() && !$comment->hasParentComment()) {
         $form['#action'] = $this->url('comment.reply', array('entity_type' => $entity->getEntityTypeId(), 'entity' => $entity->id(), 'field_name' => $field_name));
     }
     $comment_preview = $form_state->get('comment_preview');
     if (isset($comment_preview)) {
         $form += $comment_preview;
     }
     $form['author'] = array();
     // Display author information in a details element for comment moderators.
     if ($is_admin) {
         $form['author'] += array('#type' => 'details', '#title' => $this->t('Administration'));
     }
     // Prepare default values for form elements.
     $author = '';
     if ($is_admin) {
         if (!$comment->getOwnerId()) {
             $author = $comment->getAuthorName();
         }
         $status = $comment->getStatus();
         if (empty($comment_preview)) {
             $form['#title'] = $this->t('Edit comment %title', array('%title' => $comment->getSubject()));
         }
     } else {
         $status = $this->currentUser->hasPermission('skip comment approval') ? CommentInterface::PUBLISHED : CommentInterface::NOT_PUBLISHED;
     }
     $date = '';
     if ($comment->id()) {
         $date = !empty($comment->date) ? $comment->date : DrupalDateTime::createFromTimestamp($comment->getCreatedTime());
     }
     // The uid field is only displayed when a user with the permission
     // 'administer comments' is editing an existing comment from an
     // authenticated user.
     $owner = $comment->getOwner();
     $form['author']['uid'] = ['#type' => 'entity_autocomplete', '#target_type' => 'user', '#default_value' => $owner->isAnonymous() ? NULL : $owner, '#selection_settings' => ['include_anonymous' => FALSE], '#title' => $this->t('Authored by'), '#description' => $this->t('Leave blank for %anonymous.', ['%anonymous' => $config->get('anonymous')]), '#access' => $is_admin];
     // The name field is displayed when an anonymous user is adding a comment or
     // when a user with the permission 'administer comments' is editing an
     // existing comment from an anonymous user.
     $form['author']['name'] = array('#type' => 'textfield', '#title' => $is_admin ? $this->t('Name for @anonymous', ['@anonymous' => $config->get('anonymous')]) : $this->t('Your name'), '#default_value' => $author, '#required' => $this->currentUser->isAnonymous() && $anonymous_contact == COMMENT_ANONYMOUS_MUST_CONTACT, '#maxlength' => 60, '#access' => $this->currentUser->isAnonymous() || $is_admin, '#size' => 30, '#attributes' => ['data-drupal-default-value' => $config->get('anonymous')]);
     if ($is_admin) {
         // When editing a comment only display the name textfield if the uid field
         // is empty.
         $form['author']['name']['#states'] = ['visible' => [':input[name="uid"]' => array('empty' => TRUE)]];
     }
     // Add author email and homepage fields depending on the current user.
     $form['author']['mail'] = array('#type' => 'email', '#title' => $this->t('Email'), '#default_value' => $comment->getAuthorEmail(), '#required' => $this->currentUser->isAnonymous() && $anonymous_contact == COMMENT_ANONYMOUS_MUST_CONTACT, '#maxlength' => 64, '#size' => 30, '#description' => $this->t('The content of this field is kept private and will not be shown publicly.'), '#access' => $comment->getOwner()->isAnonymous() && $is_admin || $this->currentUser->isAnonymous() && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT);
     $form['author']['homepage'] = array('#type' => 'url', '#title' => $this->t('Homepage'), '#default_value' => $comment->getHomepage(), '#maxlength' => 255, '#size' => 30, '#access' => $is_admin || $this->currentUser->isAnonymous() && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT);
     // Add administrative comment publishing options.
     $form['author']['date'] = array('#type' => 'datetime', '#title' => $this->t('Authored on'), '#default_value' => $date, '#size' => 20, '#access' => $is_admin);
     $form['author']['status'] = array('#type' => 'radios', '#title' => $this->t('Status'), '#default_value' => $status, '#options' => array(CommentInterface::PUBLISHED => $this->t('Published'), CommentInterface::NOT_PUBLISHED => $this->t('Not published')), '#access' => $is_admin);
     return parent::form($form, $form_state, $comment);
 }
Esempio n. 26
0
 /**
  * Creates checkbox or radio elements to populate a tableselect table.
  *
  * @param array $element
  *   An associative array containing the properties and children of the
  *   tableselect element.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  * @param array $complete_form
  *   The complete form structure.
  *
  * @return array
  *   The processed element.
  */
 public static function processTableselect(&$element, FormStateInterface $form_state, &$complete_form)
 {
     if ($element['#multiple']) {
         $value = is_array($element['#value']) ? $element['#value'] : array();
     } else {
         // Advanced selection behavior makes no sense for radios.
         $element['#js_select'] = FALSE;
     }
     $element['#tree'] = TRUE;
     if (count($element['#options']) > 0) {
         if (!isset($element['#default_value']) || $element['#default_value'] === 0) {
             $element['#default_value'] = array();
         }
         // Create a checkbox or radio for each item in #options in such a way that
         // the value of the tableselect element behaves as if it had been of type
         // checkboxes or radios.
         foreach ($element['#options'] as $key => $choice) {
             // Do not overwrite manually created children.
             if (!isset($element[$key])) {
                 if ($element['#multiple']) {
                     $title = '';
                     if (isset($element['#options'][$key]['title']) && is_array($element['#options'][$key]['title'])) {
                         if (!empty($element['#options'][$key]['title']['data']['#title'])) {
                             $title = new TranslatableMarkup('Update @title', array('@title' => $element['#options'][$key]['title']['data']['#title']));
                         }
                     }
                     $element[$key] = array('#type' => 'checkbox', '#title' => $title, '#title_display' => 'invisible', '#return_value' => $key, '#default_value' => isset($value[$key]) ? $key : NULL, '#attributes' => $element['#attributes']);
                 } else {
                     // Generate the parents as the autogenerator does, so we will have a
                     // unique id for each radio button.
                     $parents_for_id = array_merge($element['#parents'], array($key));
                     $element[$key] = array('#type' => 'radio', '#title' => '', '#return_value' => $key, '#default_value' => $element['#default_value'] == $key ? $key : NULL, '#attributes' => $element['#attributes'], '#parents' => $element['#parents'], '#id' => HtmlUtility::getUniqueId('edit-' . implode('-', $parents_for_id)), '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL);
                 }
                 if (isset($element['#options'][$key]['#weight'])) {
                     $element[$key]['#weight'] = $element['#options'][$key]['#weight'];
                 }
             }
         }
     } else {
         $element['#value'] = array();
     }
     return $element;
 }
Esempio n. 27
0
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state)
 {
     // Don't show the form when batch operations are in progress.
     if ($batch = batch_get() && isset($batch['current_set'])) {
         return array('#theme' => '');
     }
     // Make sure that we validate because this form might be submitted
     // multiple times per page.
     $form_state->setValidationEnforced();
     /** @var \Drupal\views\ViewExecutable $view */
     $view = $form_state->get('view');
     $display =& $form_state->get('display');
     $form_state->setUserInput($view->getExposedInput());
     // Let form plugins know this is for exposed widgets.
     $form_state->set('exposed', TRUE);
     // Check if the form was already created
     if ($cache = $this->exposedFormCache->getForm($view->storage->id(), $view->current_display)) {
         return $cache;
     }
     $form['#info'] = array();
     // Go through each handler and let it generate its exposed widget.
     foreach ($view->display_handler->handlers as $type => $value) {
         /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface $handler */
         foreach ($view->{$type} as $id => $handler) {
             if ($handler->canExpose() && $handler->isExposed()) {
                 // Grouped exposed filters have their own forms.
                 // Instead of render the standard exposed form, a new Select or
                 // Radio form field is rendered with the available groups.
                 // When an user choose an option the selected value is split
                 // into the operator and value that the item represents.
                 if ($handler->isAGroup()) {
                     $handler->groupForm($form, $form_state);
                     $id = $handler->options['group_info']['identifier'];
                 } else {
                     $handler->buildExposedForm($form, $form_state);
                 }
                 if ($info = $handler->exposedInfo()) {
                     $form['#info']["{$type}-{$id}"] = $info;
                 }
             }
         }
     }
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array('#name' => '', '#type' => 'submit', '#value' => $this->t('Apply'), '#id' => Html::getUniqueId('edit-submit-' . $view->storage->id()));
     $form['#action'] = $view->hasUrl() ? $view->getUrl()->toString() : Url::fromRoute('<current>')->toString();
     $form['#theme'] = $view->buildThemeFunctions('views_exposed_form');
     $form['#id'] = Html::cleanCssIdentifier('views_exposed_form-' . SafeMarkup::checkPlain($view->storage->id()) . '-' . SafeMarkup::checkPlain($display['id']));
     /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
     $exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
     $exposed_form_plugin->exposedFormAlter($form, $form_state);
     // Save the form.
     $this->exposedFormCache->setForm($view->storage->id(), $view->current_display, $form);
     return $form;
 }
Esempio n. 28
0
 /**
  * Provide a standard set of Apply/Cancel/OK buttons for the forms. Also provide
  * a hidden op operator because the forms plugin doesn't seem to properly
  * provide which button was clicked.
  *
  * TODO: Is the hidden op operator still here somewhere, or is that part of the
  * docblock outdated?
  */
 public function getStandardButtons(&$form, FormStateInterface $form_state, $form_id, $name = NULL)
 {
     $form['actions'] = array('#type' => 'actions');
     if (empty($name)) {
         $name = t('Apply');
         if (!empty($this->stack) && count($this->stack) > 1) {
             $name = t('Apply and continue');
         }
         $names = array(t('Apply'), t('Apply and continue'));
     }
     // Views provides its own custom handling of AJAX form submissions. Usually
     // this happens at the same path, but custom paths may be specified in
     // $form_state.
     $form_url = $form_state->get('url') ?: Url::fromRouteMatch(\Drupal::routeMatch());
     // Forms that are purely informational set an ok_button flag, so we know not
     // to create an "Apply" button for them.
     if (!$form_state->get('ok_button')) {
         $form['actions']['submit'] = array('#type' => 'submit', '#value' => $name, '#id' => 'edit-submit-' . Html::getUniqueId($form_id), '#submit' => array(array($this, 'standardSubmit')), '#button_type' => 'primary', '#ajax' => array('url' => $form_url));
         // Form API button click detection requires the button's #value to be the
         // same between the form build of the initial page request, and the
         // initial form build of the request processing the form submission.
         // Ideally, the button's #value shouldn't change until the form rebuild
         // step. However, \Drupal\views_ui\Form\Ajax\ViewsFormBase::getForm()
         // implements a different multistep form workflow than the Form API does,
         // and adjusts $view->stack prior to form processing, so we compensate by
         // extending button click detection code to support any of the possible
         // button labels.
         if (isset($names)) {
             $form['actions']['submit']['#values'] = $names;
             $form['actions']['submit']['#process'] = array_merge(array('views_ui_form_button_was_clicked'), \Drupal::service('element_info')->getInfoProperty($form['actions']['submit']['#type'], '#process', array()));
         }
         // If a validation handler exists for the form, assign it to this button.
         $form['actions']['submit']['#validate'][] = [$form_state->getFormObject(), 'validateForm'];
     }
     // Create a "Cancel" button. For purely informational forms, label it "OK".
     $cancel_submit = function_exists($form_id . '_cancel') ? $form_id . '_cancel' : array($this, 'standardCancel');
     $form['actions']['cancel'] = array('#type' => 'submit', '#value' => !$form_state->get('ok_button') ? t('Cancel') : t('Ok'), '#submit' => array($cancel_submit), '#validate' => array(), '#ajax' => array('path' => $form_url), '#limit_validation_errors' => array());
     // Compatibility, to be removed later: // TODO: When is "later"?
     // We used to set these items on the form, but now we want them on the $form_state:
     if (isset($form['#title'])) {
         $form_state->set('title', $form['#title']);
     }
     if (isset($form['#section'])) {
         $form_state->set('#section', $form['#section']);
     }
     // Finally, we never want these cached -- our object cache does that for us.
     $form['#no_cache'] = TRUE;
 }
Esempio n. 29
0
 /**
  * {@inheritdoc}
  */
 public function doBuildForm($form_id, &$element, FormStateInterface &$form_state)
 {
     // Initialize as unprocessed.
     $element['#processed'] = FALSE;
     // Use element defaults.
     if (isset($element['#type']) && empty($element['#defaults_loaded']) && ($info = $this->elementInfo->getInfo($element['#type']))) {
         // Overlay $info onto $element, retaining preexisting keys in $element.
         $element += $info;
         $element['#defaults_loaded'] = TRUE;
     }
     // Assign basic defaults common for all form elements.
     $element += array('#required' => FALSE, '#attributes' => array(), '#title_display' => 'before', '#description_display' => 'after', '#errors' => NULL);
     // Special handling if we're on the top level form element.
     if (isset($element['#type']) && $element['#type'] == 'form') {
         if (!empty($element['#https']) && !UrlHelper::isExternal($element['#action'])) {
             global $base_root;
             // Not an external URL so ensure that it is secure.
             $element['#action'] = str_replace('http://', 'https://', $base_root) . $element['#action'];
         }
         // Store a reference to the complete form in $form_state prior to building
         // the form. This allows advanced #process and #after_build callbacks to
         // perform changes elsewhere in the form.
         $form_state->setCompleteForm($element);
         // Set a flag if we have a correct form submission. This is always TRUE
         // for programmed forms coming from self::submitForm(), or if the form_id
         // coming from the POST data is set and matches the current form_id.
         $input = $form_state->getUserInput();
         if ($form_state->isProgrammed() || !empty($input) && (isset($input['form_id']) && $input['form_id'] == $form_id)) {
             $form_state->setProcessInput();
             if (isset($element['#token'])) {
                 $input = $form_state->getUserInput();
                 if (empty($input['form_token']) || !$this->csrfToken->validate($input['form_token'], $element['#token'])) {
                     // Set an early form error to block certain input processing since
                     // that opens the door for CSRF vulnerabilities.
                     $this->setInvalidTokenError($form_state);
                     // This value is checked in self::handleInputElement().
                     $form_state->setInvalidToken(TRUE);
                     // Make sure file uploads do not get processed.
                     $this->requestStack->getCurrentRequest()->files = new FileBag();
                 }
             }
         } else {
             $form_state->setProcessInput(FALSE);
         }
         // All form elements should have an #array_parents property.
         $element['#array_parents'] = array();
     }
     if (!isset($element['#id'])) {
         $unprocessed_id = 'edit-' . implode('-', $element['#parents']);
         $element['#id'] = Html::getUniqueId($unprocessed_id);
         // Provide a selector usable by JavaScript. As the ID is unique, its not
         // possible to rely on it in JavaScript.
         $element['#attributes']['data-drupal-selector'] = Html::getId($unprocessed_id);
     } else {
         // Provide a selector usable by JavaScript. As the ID is unique, its not
         // possible to rely on it in JavaScript.
         $element['#attributes']['data-drupal-selector'] = Html::getId($element['#id']);
     }
     // Add the aria-describedby attribute to associate the form control with its
     // description.
     if (!empty($element['#description'])) {
         $element['#attributes']['aria-describedby'] = $element['#id'] . '--description';
     }
     // Handle input elements.
     if (!empty($element['#input'])) {
         $this->handleInputElement($form_id, $element, $form_state);
     }
     // Allow for elements to expand to multiple elements, e.g., radios,
     // checkboxes and files.
     if (isset($element['#process']) && !$element['#processed']) {
         foreach ($element['#process'] as $callback) {
             $complete_form =& $form_state->getCompleteForm();
             $element = call_user_func_array($form_state->prepareCallback($callback), array(&$element, &$form_state, &$complete_form));
         }
         $element['#processed'] = TRUE;
     }
     // We start off assuming all form elements are in the correct order.
     $element['#sorted'] = TRUE;
     // Recurse through all child elements.
     $count = 0;
     if (isset($element['#access'])) {
         $access = $element['#access'];
         $inherited_access = NULL;
         if ($access instanceof AccessResultInterface && !$access->isAllowed() || $access === FALSE) {
             $inherited_access = $access;
         }
     }
     foreach (Element::children($element) as $key) {
         // Prior to checking properties of child elements, their default
         // properties need to be loaded.
         if (isset($element[$key]['#type']) && empty($element[$key]['#defaults_loaded']) && ($info = $this->elementInfo->getInfo($element[$key]['#type']))) {
             $element[$key] += $info;
             $element[$key]['#defaults_loaded'] = TRUE;
         }
         // Don't squash an existing tree value.
         if (!isset($element[$key]['#tree'])) {
             $element[$key]['#tree'] = $element['#tree'];
         }
         // Children inherit #access from parent.
         if (isset($inherited_access)) {
             $element[$key]['#access'] = $inherited_access;
         }
         // Make child elements inherit their parent's #disabled and #allow_focus
         // values unless they specify their own.
         foreach (array('#disabled', '#allow_focus') as $property) {
             if (isset($element[$property]) && !isset($element[$key][$property])) {
                 $element[$key][$property] = $element[$property];
             }
         }
         // Don't squash existing parents value.
         if (!isset($element[$key]['#parents'])) {
             // Check to see if a tree of child elements is present. If so,
             // continue down the tree if required.
             $element[$key]['#parents'] = $element[$key]['#tree'] && $element['#tree'] ? array_merge($element['#parents'], array($key)) : array($key);
         }
         // Ensure #array_parents follows the actual form structure.
         $array_parents = $element['#array_parents'];
         $array_parents[] = $key;
         $element[$key]['#array_parents'] = $array_parents;
         // Assign a decimal placeholder weight to preserve original array order.
         if (!isset($element[$key]['#weight'])) {
             $element[$key]['#weight'] = $count / 1000;
         } else {
             // If one of the child elements has a weight then we will need to sort
             // later.
             unset($element['#sorted']);
         }
         $element[$key] = $this->doBuildForm($form_id, $element[$key], $form_state);
         $count++;
     }
     // The #after_build flag allows any piece of a form to be altered
     // after normal input parsing has been completed.
     if (isset($element['#after_build']) && !isset($element['#after_build_done'])) {
         foreach ($element['#after_build'] as $callback) {
             $element = call_user_func_array($form_state->prepareCallback($callback), array($element, &$form_state));
         }
         $element['#after_build_done'] = TRUE;
     }
     // If there is a file element, we need to flip a flag so later the
     // form encoding can be set.
     if (isset($element['#type']) && $element['#type'] == 'file') {
         $form_state->setHasFileElement();
     }
     // Final tasks for the form element after self::doBuildForm() has run for
     // all other elements.
     if (isset($element['#type']) && $element['#type'] == 'form') {
         // If there is a file element, we set the form encoding.
         if ($form_state->hasFileElement()) {
             $element['#attributes']['enctype'] = 'multipart/form-data';
         }
         // Allow Ajax submissions to the form action to bypass verification. This
         // is especially useful for multipart forms, which cannot be verified via
         // a response header.
         $element['#attached']['drupalSettings']['ajaxTrustedUrl'][$element['#action']] = TRUE;
         // If a form contains a single textfield, and the ENTER key is pressed
         // within it, Internet Explorer submits the form with no POST data
         // identifying any submit button. Other browsers submit POST data as
         // though the user clicked the first button. Therefore, to be as
         // consistent as we can be across browsers, if no 'triggering_element' has
         // been identified yet, default it to the first button.
         $buttons = $form_state->getButtons();
         if (!$form_state->isProgrammed() && !$form_state->getTriggeringElement() && !empty($buttons)) {
             $form_state->setTriggeringElement($buttons[0]);
         }
         $triggering_element = $form_state->getTriggeringElement();
         // If the triggering element specifies "button-level" validation and
         // submit handlers to run instead of the default form-level ones, then add
         // those to the form state.
         if (isset($triggering_element['#validate'])) {
             $form_state->setValidateHandlers($triggering_element['#validate']);
         }
         if (isset($triggering_element['#submit'])) {
             $form_state->setSubmitHandlers($triggering_element['#submit']);
         }
         // If the triggering element executes submit handlers, then set the form
         // state key that's needed for those handlers to run.
         if (!empty($triggering_element['#executes_submit_callback'])) {
             $form_state->setSubmitted();
         }
         // Special processing if the triggering element is a button.
         if (!empty($triggering_element['#is_button'])) {
             // Because there are several ways in which the triggering element could
             // have been determined (including from input variables set by
             // JavaScript or fallback behavior implemented for IE), and because
             // buttons often have their #name property not derived from their
             // #parents property, we can't assume that input processing that's
             // happened up until here has resulted in
             // $form_state->getValue(BUTTON_NAME) being set. But it's common for
             // forms to have several buttons named 'op' and switch on
             // $form_state->getValue('op') during submit handler execution.
             $form_state->setValue($triggering_element['#name'], $triggering_element['#value']);
         }
     }
     return $element;
 }
Esempio n. 30
0
 /**
  * Tests the exposed block functionality.
  */
 public function testExposedBlock()
 {
     $this->drupalCreateContentType(['type' => 'page']);
     $view = Views::getView('test_exposed_block');
     $view->setDisplay('page_1');
     $block = $this->drupalPlaceBlock('views_exposed_filter_block:test_exposed_block-page_1');
     $this->drupalGet('test_exposed_block');
     // Test there is an exposed form in a block.
     $xpath = $this->buildXPathQuery('//div[@id=:id]/form/@id', array(':id' => Html::getUniqueId('block-' . $block->id())));
     $this->assertFieldByXpath($xpath, $this->getExpectedExposedFormId($view), 'Expected form found in views block.');
     // Test there is not an exposed form in the view page content area.
     $xpath = $this->buildXPathQuery('//div[@class="view-content"]/form/@id', array(':id' => Html::getUniqueId('block-' . $block->id())));
     $this->assertNoFieldByXpath($xpath, $this->getExpectedExposedFormId($view), 'No exposed form found in views content region.');
     // Test there is only one views exposed form on the page.
     $elements = $this->xpath('//form[@id=:id]', array(':id' => $this->getExpectedExposedFormId($view)));
     $this->assertEqual(count($elements), 1, 'One exposed form block found.');
     // Test that the correct option is selected after form submission.
     $this->assertCacheContext('url');
     $this->assertOptionSelected('edit-type', 'All');
     foreach (['All', 'article', 'page'] as $argument) {
         $this->drupalGet('test_exposed_block', ['query' => ['type' => $argument]]);
         $this->assertCacheContext('url');
         $this->assertOptionSelected('edit-type', $argument);
     }
 }