/** * Presents a list of conditions to add to the block_visibility_group entity. * * @param \Drupal\block_visibility_groups\Entity\BlockVisibilityGroup $block_visibility_group * The block_visibility_group entity. * * @return array * The condition selection page. */ public function selectCondition(BlockVisibilityGroup $block_visibility_group, $redirect) { $build = [ '#theme' => 'links', '#links' => [], ]; $available_plugins = $this->conditionManager->getDefinitions(); // @todo Should nesting Conditions be allowed unset($available_plugins['condition_group']); foreach ($available_plugins as $condition_id => $condition) { $build['#links'][$condition_id] = [ 'title' => $condition['label'], 'url' => Url::fromRoute('block_visibility_groups.condition_add', [ 'block_visibility_group' => $block_visibility_group->id(), 'condition_id' => $condition_id, 'redirect' => $redirect, ]), 'attributes' => [ 'class' => ['use-ajax'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode([ 'width' => 'auto', ]), ], ]; } return $build; }
/** * Tests file field formatter Entity Embed Display plugins. */ public function testFileFieldFormatter() { // Ensure that file field formatters are available as plugins. $this->assertAvailableDisplayPlugins($this->file, ['entity_reference:entity_reference_label', 'entity_reference:entity_reference_entity_id', 'file:file_default', 'file:file_table', 'file:file_url_plain']); // Ensure that correct form attributes are returned for the file field // formatter plugins. $form = array(); $form_state = new FormState(); $plugins = array('file:file_table', 'file:file_default', 'file:file_url_plain'); // Ensure that description field is available for all the 'file' plugins. foreach ($plugins as $plugin) { $display = $this->displayPluginManager()->createInstance($plugin, array()); $display->setContextValue('entity', $this->file); $conf_form = $display->buildConfigurationForm($form, $form_state); $this->assertIdentical(array_keys($conf_form), array('description')); $this->assertIdentical($conf_form['description']['#type'], 'textfield'); $this->assertIdentical((string) $conf_form['description']['#title'], 'Description'); } // Test entity embed using 'Generic file' Entity Embed Display plugin. $embed_settings = array('description' => "This is sample description"); $content = '<drupal-entity data-entity-type="file" data-entity-uuid="' . $this->file->uuid() . '" data-entity-embed-display="file:file_default" data-entity-embed-settings=\'' . Json::encode($embed_settings) . '\'>This placeholder should not be rendered.</drupal-entity>'; $settings = array(); $settings['type'] = 'page'; $settings['title'] = 'Test entity embed with file:file_default'; $settings['body'] = array(array('value' => $content, 'format' => 'custom_format')); $node = $this->drupalCreateNode($settings); $this->drupalGet('node/' . $node->id()); $this->assertText($embed_settings['description'], 'Description of the embedded file exists in page.'); $this->assertNoText(strip_tags($content), 'Placeholder does not appears in the output when embed is successful.'); $this->assertLinkByHref(file_create_url($this->file->getFileUri()), 0, 'Link to the embedded file exists.'); }
/** * Tests several valid and invalid read requests on all entity types. */ public function testRead() { // @todo Expand this at least to users. // Define the entity types we want to test. $entity_types = array('entity_test', 'node'); foreach ($entity_types as $entity_type) { $this->enableService('entity:' . $entity_type, 'GET'); // Create a user account that has the required permissions to read // resources via the REST API. $permissions = $this->entityPermissions($entity_type, 'view'); $permissions[] = 'restful get entity:' . $entity_type; $account = $this->drupalCreateUser($permissions); $this->drupalLogin($account); // Create an entity programmatically. $entity = $this->entityCreate($entity_type); $entity->save(); // Read it over the REST API. $response = $this->httpRequest($entity->getSystemPath(), 'GET', NULL, $this->defaultMimeType); $this->assertResponse('200', 'HTTP response code is correct.'); $this->assertHeader('content-type', $this->defaultMimeType); $data = Json::decode($response); // Only assert one example property here, other properties should be // checked in serialization tests. $this->assertEqual($data['uuid'][0]['value'], $entity->uuid(), 'Entity UUID is correct'); // Try to read the entity with an unsupported mime format. $response = $this->httpRequest($entity->getSystemPath(), 'GET', NULL, 'application/wrongformat'); $this->assertResponse(200); $this->assertHeader('Content-type', 'text/html; charset=UTF-8'); // Try to read an entity that does not exist. $response = $this->httpRequest($entity_type . '/9999', 'GET', NULL, $this->defaultMimeType); $this->assertResponse(404); $path = $entity_type == 'node' ? '/node/{node}' : '/entity_test/{entity_test}'; $expected_message = Json::encode(['error' => 'A fatal error occurred: The "' . $entity_type . '" parameter was not converted for the path "' . $path . '" (route name: "rest.entity.' . $entity_type . '.GET.hal_json")']); $this->assertIdentical($expected_message, $response, 'Response message is correct.'); // Make sure that field level access works and that the according field is // not available in the response. Only applies to entity_test. // @see entity_test_entity_field_access() if ($entity_type == 'entity_test') { $entity->field_test_text->value = 'no access value'; $entity->save(); $response = $this->httpRequest($entity->getSystemPath(), 'GET', NULL, $this->defaultMimeType); $this->assertResponse(200); $this->assertHeader('content-type', $this->defaultMimeType); $data = Json::decode($response); $this->assertFalse(isset($data['field_test_text']), 'Field access protected field is not visible in the response.'); } // Try to read an entity without proper permissions. $this->drupalLogout(); $response = $this->httpRequest($entity->getSystemPath(), 'GET', NULL, $this->defaultMimeType); $this->assertResponse(403); $this->assertIdentical('{}', $response); } // Try to read a resource which is not REST API enabled. $account = $this->drupalCreateUser(); $this->drupalLogin($account); $response = $this->httpRequest($account->getSystemPath(), 'GET', NULL, $this->defaultMimeType); $this->assertResponse(404); $expected_message = Json::encode(['error' => 'A fatal error occurred: Unable to find the controller for path "/user/4". Maybe you forgot to add the matching route in your routing configuration?']); $this->assertIdentical($expected_message, $response); }
/** * Tests if custom variables are properly added to the page. */ public function testPiwikCustomVariables() { $site_id = '3'; $this->config('piwik.settings')->set('site_id', $site_id)->save(); $this->config('piwik.settings')->set('url_http', 'http://www.example.com/piwik/')->save(); $this->config('piwik.settings')->set('url_https', 'https://www.example.com/piwik/')->save(); // Basic test if the feature works. $custom_vars = [1 => ['slot' => 1, 'name' => 'Foo 1', 'value' => 'Bar 1', 'scope' => 'visit'], 2 => ['slot' => 2, 'name' => 'Foo 2', 'value' => 'Bar 2', 'scope' => 'page'], 3 => ['slot' => 3, 'name' => 'Foo 3', 'value' => 'Bar 3', 'scope' => 'page'], 4 => ['slot' => 4, 'name' => 'Foo 4', 'value' => 'Bar 4', 'scope' => 'visit'], 5 => ['slot' => 5, 'name' => 'Foo 5', 'value' => 'Bar 5', 'scope' => 'visit']]; $this->config('piwik.settings')->set('custom.variable', $custom_vars)->save(); $this->drupalGet(''); foreach ($custom_vars as $slot) { $this->assertRaw('_paq.push(["setCustomVariable", ' . Json::encode($slot['slot']) . ', ' . Json::encode($slot['name']) . ', ' . Json::encode($slot['value']) . ', ' . Json::encode($slot['scope']) . ']);', '[testPiwikCustomVariables]: setCustomVariable ' . $slot['slot'] . ' is shown.'); } // Test whether tokens are replaced in custom variable names. $site_slogan = $this->randomMachineName(16); $this->config('system.site')->set('slogan', $site_slogan)->save(); $custom_vars = [1 => ['slot' => 1, 'name' => 'Name: [site:slogan]', 'value' => 'Value: [site:slogan]', 'scope' => 'visit'], 2 => ['slot' => 2, 'name' => '', 'value' => $this->randomMachineName(16), 'scope' => 'page'], 3 => ['slot' => 3, 'name' => $this->randomMachineName(16), 'value' => '', 'scope' => 'visit'], 4 => ['slot' => 4, 'name' => '', 'value' => '', 'scope' => 'page'], 5 => ['slot' => 5, 'name' => '', 'value' => '', 'scope' => 'visit']]; $this->config('piwik.settings')->set('custom.variable', $custom_vars)->save(); $this->verbose('<pre>' . print_r($custom_vars, TRUE) . '</pre>'); $this->drupalGet(''); $this->assertRaw('_paq.push(["setCustomVariable", 1, ' . Json::encode("Name: {$site_slogan}") . ', ' . Json::encode("Value: {$site_slogan}") . ', "visit"]', '[testPiwikCustomVariables]: Tokens have been replaced in custom variable.'); $this->assertNoRaw('_paq.push(["setCustomVariable", 2,', '[testPiwikCustomVariables]: Value with empty name is not shown.'); $this->assertNoRaw('_paq.push(["setCustomVariable", 3,', '[testPiwikCustomVariables]: Name with empty value is not shown.'); $this->assertNoRaw('_paq.push(["setCustomVariable", 4,', '[testPiwikCustomVariables]: Empty name and value is not shown.'); $this->assertNoRaw('_paq.push(["setCustomVariable", 5,', '[testPiwikCustomVariables]: Empty name and value is not shown.'); }
/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, PageInterface $page = NULL, $display_variant_id = NULL) { $form = parent::buildForm($form, $form_state, $page, $display_variant_id); // Set up the attributes used by a modal to prevent duplication later. $attributes = ['class' => ['use-ajax'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 'auto'])]; $add_button_attributes = NestedArray::mergeDeep($attributes, ['class' => ['button', 'button--small', 'button-action']]); if ($this->displayVariant instanceof ConditionVariantInterface) { if ($selection_conditions = $this->displayVariant->getSelectionConditions()) { // Selection conditions. $form['selection_section'] = ['#type' => 'details', '#title' => $this->t('Selection Conditions'), '#open' => TRUE]; $form['selection_section']['add'] = ['#type' => 'link', '#title' => $this->t('Add new selection condition'), '#url' => Url::fromRoute('page_manager.selection_condition_select', ['page' => $this->page->id(), 'display_variant_id' => $this->displayVariant->id()]), '#attributes' => $add_button_attributes, '#attached' => ['library' => ['core/drupal.ajax']]]; $form['selection_section']['table'] = ['#type' => 'table', '#header' => [$this->t('Label'), $this->t('Description'), $this->t('Operations')], '#empty' => $this->t('There are no selection conditions.')]; $form['selection_section']['selection_logic'] = ['#type' => 'radios', '#options' => ['and' => $this->t('All conditions must pass'), 'or' => $this->t('Only one condition must pass')], '#default_value' => $this->displayVariant->getSelectionLogic()]; $form['selection_section']['selection'] = ['#tree' => TRUE]; foreach ($selection_conditions as $selection_id => $selection_condition) { $row = []; $row['label']['#markup'] = $selection_condition->getPluginDefinition()['label']; $row['description']['#markup'] = $selection_condition->summary(); $operations = []; $operations['edit'] = ['title' => $this->t('Edit'), 'url' => Url::fromRoute('page_manager.selection_condition_edit', ['page' => $this->page->id(), 'display_variant_id' => $this->displayVariant->id(), 'condition_id' => $selection_id]), 'attributes' => $attributes]; $operations['delete'] = ['title' => $this->t('Delete'), 'url' => Url::fromRoute('page_manager.selection_condition_delete', ['page' => $this->page->id(), 'display_variant_id' => $this->displayVariant->id(), 'condition_id' => $selection_id]), 'attributes' => $attributes]; $row['operations'] = ['#type' => 'operations', '#links' => $operations]; $form['selection_section']['table'][$selection_id] = $row; } } } return $form; }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $form_state->cleanValues(); // This won't have a proper JSON header, but Drupal doesn't check for that // anyway so this is fine until it's replaced with a JsonResponse. print Json::encode($form_state->getValues()); exit; }
/** * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { form_state_values_clean($form_state); // This won't have a proper JSON header, but Drupal doesn't check for that // anyway so this is fine until it's replaced with a JsonResponse. print Json::encode($form_state['values']); exit; }
/** * {@inheritdoc} */ public function render(array $js_assets) { $elements = array(); // A dummy query-string is added to filenames, to gain control over // browser-caching. The string changes on every update or full cache // flush, forcing browsers to load a new copy of the files, as the // URL changed. Files that should not be cached (see _drupal_add_js()) // get REQUEST_TIME as query-string instead, to enforce reload on every // page request. $default_query_string = $this->state->get('system.css_js_query_string') ?: '0'; // For inline JavaScript to validate as XHTML, all JavaScript containing // XHTML needs to be wrapped in CDATA. To make that backwards compatible // with HTML 4, we need to comment out the CDATA-tag. $embed_prefix = "\n<!--//--><![CDATA[//><!--\n"; $embed_suffix = "\n//--><!]]>\n"; // Defaults for each SCRIPT element. $element_defaults = array('#type' => 'html_tag', '#tag' => 'script', '#value' => ''); // Loop through all JS assets. foreach ($js_assets as $js_asset) { // Element properties that do not depend on JS asset type. $element = $element_defaults; $element['#browsers'] = $js_asset['browsers']; // Element properties that depend on item type. switch ($js_asset['type']) { case 'setting': $element['#value_prefix'] = $embed_prefix; $element['#value'] = 'var drupalSettings = ' . Json::encode(drupal_merge_js_settings($js_asset['data'])) . ";"; $element['#value_suffix'] = $embed_suffix; break; case 'inline': $element['#value_prefix'] = $embed_prefix; $element['#value'] = $js_asset['data']; $element['#value_suffix'] = $embed_suffix; break; case 'file': $query_string = empty($js_asset['version']) ? $default_query_string : 'v=' . $js_asset['version']; $query_string_separator = strpos($js_asset['data'], '?') !== FALSE ? '&' : '?'; $element['#attributes']['src'] = file_create_url($js_asset['data']); // Only add the cache-busting query string if this isn't an aggregate // file. if (!isset($js_asset['preprocessed'])) { $element['#attributes']['src'] .= $query_string_separator . ($js_asset['cache'] ? $query_string : REQUEST_TIME); } break; case 'external': $element['#attributes']['src'] = $js_asset['data']; break; default: throw new \Exception('Invalid JS asset type.'); } // Attributes may only be set if this script is output independently. if (!empty($element['#attributes']['src']) && !empty($js_asset['attributes'])) { $element['#attributes'] += $js_asset['attributes']; } $elements[] = $element; } return $elements; }
/** * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { $form = parent::form($form, $form_state); $form['use_admin_theme'] = ['#type' => 'checkbox', '#title' => $this->t('Use admin theme'), '#default_value' => $this->entity->usesAdminTheme()]; $attributes = ['class' => ['use-ajax'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 'auto'])]; $add_button_attributes = NestedArray::mergeDeep($attributes, ['class' => ['button', 'button--small', 'button-action']]); $form['context'] = ['#type' => 'details', '#title' => $this->t('Available context'), '#open' => TRUE]; $form['context']['add'] = ['#type' => 'link', '#title' => $this->t('Add new static context'), '#url' => Url::fromRoute('page_manager.static_context_add', ['page' => $this->entity->id()]), '#attributes' => $add_button_attributes, '#attached' => ['library' => ['core/drupal.ajax']]]; $form['context']['available_context'] = ['#type' => 'table', '#header' => [$this->t('Label'), $this->t('Name'), $this->t('Type'), $this->t('Operations')], '#empty' => $this->t('There is no available context.')]; $contexts = $this->entity->getContexts(); foreach ($contexts as $name => $context) { $context_definition = $context->getContextDefinition(); $row = []; $row['label'] = ['#markup' => $context_definition->getLabel()]; $row['machine_name'] = ['#markup' => $name]; $row['type'] = ['#markup' => $context_definition->getDataType()]; // Add operation links if the context is a static context. $operations = []; if ($this->entity->getStaticContext($name)) { $operations['edit'] = ['title' => $this->t('Edit'), 'url' => Url::fromRoute('page_manager.static_context_edit', ['page' => $this->entity->id(), 'name' => $name]), 'attributes' => $attributes]; $operations['delete'] = ['title' => $this->t('Delete'), 'url' => Url::fromRoute('page_manager.static_context_delete', ['page' => $this->entity->id(), 'name' => $name]), 'attributes' => $attributes]; } $row['operations'] = ['#type' => 'operations', '#links' => $operations]; $form['context']['available_context'][$name] = $row; } $form['display_variant_section'] = ['#type' => 'details', '#title' => $this->t('Display variants'), '#open' => TRUE]; $form['display_variant_section']['add_new_page'] = ['#type' => 'link', '#title' => $this->t('Add new display variant'), '#url' => Url::fromRoute('page_manager.display_variant_select', ['page' => $this->entity->id()]), '#attributes' => $add_button_attributes, '#attached' => ['library' => ['core/drupal.ajax']]]; $form['display_variant_section']['display_variants'] = ['#type' => 'table', '#header' => [$this->t('Label'), $this->t('Plugin'), $this->t('Weight'), $this->t('Operations')], '#empty' => $this->t('There are no display variants.'), '#tabledrag' => [['action' => 'order', 'relationship' => 'sibling', 'group' => 'display-variant-weight']]]; foreach ($this->entity->getVariants() as $display_variant_id => $display_variant) { $row = ['#attributes' => ['class' => ['draggable']]]; $row['label']['#markup'] = $display_variant->label(); $row['id']['#markup'] = $display_variant->adminLabel(); $row['weight'] = ['#type' => 'weight', '#default_value' => $display_variant->getWeight(), '#title' => $this->t('Weight for @display_variant display variant', ['@display_variant' => $display_variant->label()]), '#title_display' => 'invisible', '#attributes' => ['class' => ['display-variant-weight']]]; $operations = []; $operations['edit'] = ['title' => $this->t('Edit'), 'url' => Url::fromRoute('page_manager.display_variant_edit', ['page' => $this->entity->id(), 'display_variant_id' => $display_variant_id])]; $operations['delete'] = ['title' => $this->t('Delete'), 'url' => Url::fromRoute('page_manager.display_variant_delete', ['page' => $this->entity->id(), 'display_variant_id' => $display_variant_id])]; $row['operations'] = ['#type' => 'operations', '#links' => $operations]; $form['display_variant_section']['display_variants'][$display_variant_id] = $row; } if ($access_conditions = $this->entity->getAccessConditions()) { $form['access_section_section'] = ['#type' => 'details', '#title' => $this->t('Access Conditions'), '#open' => TRUE]; $form['access_section_section']['add'] = ['#type' => 'link', '#title' => $this->t('Add new access condition'), '#url' => Url::fromRoute('page_manager.access_condition_select', ['page' => $this->entity->id()]), '#attributes' => $add_button_attributes, '#attached' => ['library' => ['core/drupal.ajax']]]; $form['access_section_section']['access_section'] = ['#type' => 'table', '#header' => [$this->t('Label'), $this->t('Description'), $this->t('Operations')], '#empty' => $this->t('There are no access conditions.')]; $form['access_section_section']['access_logic'] = ['#type' => 'radios', '#options' => ['and' => $this->t('All conditions must pass'), 'or' => $this->t('Only one condition must pass')], '#default_value' => $this->entity->getAccessLogic()]; $form['access_section_section']['access'] = ['#tree' => TRUE]; foreach ($access_conditions as $access_id => $access_condition) { $row = []; $row['label']['#markup'] = $access_condition->getPluginDefinition()['label']; $row['description']['#markup'] = $access_condition->summary(); $operations = []; $operations['edit'] = ['title' => $this->t('Edit'), 'url' => Url::fromRoute('page_manager.access_condition_edit', ['page' => $this->entity->id(), 'condition_id' => $access_id]), 'attributes' => $attributes]; $operations['delete'] = ['title' => $this->t('Delete'), 'url' => Url::fromRoute('page_manager.access_condition_delete', ['page' => $this->entity->id(), 'condition_id' => $access_id]), 'attributes' => $attributes]; $row['operations'] = ['#type' => 'operations', '#links' => $operations]; $form['access_section_section']['access_section'][$access_id] = $row; } } return $form; }
/** * Displays test links that will open in offcanvas tray. * * @return array * Render array with links. */ public function linksDisplay() { return [ 'offcanvas_link_1' => [ '#title' => 'Click Me 1!', '#type' => 'link', '#url' => Url::fromRoute('offcanvas_test.thing1'), '#attributes' => [ 'class' => ['use-ajax'], 'data-dialog-type' => 'dialog', 'data-dialog-renderer' => 'offcanvas', ], '#attached' => [ 'library' => [ 'outside_in/drupal.outside_in', ], ], ], 'offcanvas_link_2' => [ '#title' => 'Click Me 2!', '#type' => 'link', '#url' => Url::fromRoute('offcanvas_test.thing2'), '#attributes' => [ 'class' => ['use-ajax'], 'data-dialog-type' => 'dialog', 'data-dialog-renderer' => 'offcanvas', 'data-dialog-options' => Json::encode([ 'width' => 555, ]), ], '#attached' => [ 'library' => [ 'outside_in/drupal.outside_in', ], ], ], 'other_dialog_links' => [ '#title' => 'Display more links!', '#type' => 'link', '#url' => Url::fromRoute('offcanvas_test.dialog_links'), '#attributes' => [ 'class' => ['use-ajax'], 'data-dialog-type' => 'dialog', 'data-dialog-renderer' => 'offcanvas', ], '#attached' => [ 'library' => [ 'outside_in/drupal.outside_in', ], ], ], ]; }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $main_config = $this->configFactory->get('nodejs.config'); $ext = $form_state->getValue('nodejs_config_extensions'); if ($ext == !NULL) { $ext = explode("\n", str_replace("\r", '', $ext)); } $array = array('scheme' => $form_state->getValue('nodejs_server_scheme'), 'host' => $form_state->getValue('nodejs_config_host'), 'port' => (int) $form_state->getValue('nodejs_config_port'), 'key' => $form_state->getValue('nodejs_config_key'), 'cert' => $form_state->getValue('nodejs_config_cert'), 'resource' => $form_state->getValue('nodejs_config_resource'), 'publishUrl' => $form_state->getValue('nodejs_config_publish_url'), 'serviceKey' => $main_config->get('nodejs_service_key'), 'backend' => array('port' => (int) $form_state->getValue('nodejs_config_backend_port'), 'host' => $form_state->getValue('nodejs_config_backend_host'), 'messagePath' => $form_state->getValue('nodejs_config_backend_message_path')), 'clientsCanWriteToChannels' => (bool) $form_state->getValue('nodejs_config_write_channels'), 'clientsCanWriteToClients' => (bool) $form_state->getValue('nodejs_config_write_clients'), 'extensions' => $ext, 'debug' => (bool) $form_state->getValue('nodejs_config_debug'), 'transports' => array('websocket', 'flashsocket', 'htmlfile', 'xhr-polling', 'jsonp-polling'), 'jsMinification' => true, 'jsEtag' => true, 'logLevel' => 1); $output = 'backendSettings = ' . Json::encode($array); $output = str_replace(array('= {', ',', '}}', ':{', '\\/'), array("= {\n ", ",\n ", "\n }\n}", ":{\n ", '/'), $output); $output = "/**\n* This configuration file was built using the 'Node.js server configuration builder'.\n* For a more fully commented example see the file nodejs.config.js.example in the root of this module\n*/\n" . $output . ';'; $this->configFactory->getEditable('nodejs_config.settings')->set('js_suggestion', $output)->set('host', $form_state->getValue('nodejs_config_host'))->set('port', (int) $form_state->getValue('nodejs_config_port'))->set('scheme', $form_state->getValue('nodejs_server_scheme'))->set('key', $form_state->getValue('nodejs_config_key'))->set('cert', $form_state->getValue('nodejs_config_cert'))->set('resource', $form_state->getValue('nodejs_config_resource'))->set('publish_url', $form_state->getValue('nodejs_config_publish_url'))->set('backend_port', (int) $form_state->getValue('nodejs_config_backend_port'))->set('backend_host', $form_state->getValue('nodejs_config_backend_host'))->set('backend_message_path', $form_state->getValue('nodejs_config_backend_message_path'))->set('write_channels', (bool) $form_state->getValue('nodejs_config_write_channels'))->set('write_clients', (bool) $form_state->getValue('nodejs_config_write_clients'))->set('debug', (bool) $form_state->getValue('nodejs_config_debug'))->set('extensions', $form_state->getValue('nodejs_config_extensions'))->save(); parent::submitForm($form, $form_state); }
/** * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { $form = parent::form($form, $form_state); $menu_links_elements = $this->getMenuLinkElements($this->entity->getTargetMenu()); $layout_options = $this->getLayoutOptions(); $table_header = ['label' => $this->t('Label'), 'category' => $this->t('Category'), 'region' => $this->t('Region'), 'weight' => $this->t('Weight'), 'operations' => $this->t('Operations')]; $form['links'] = ['#type' => 'container', '#title' => $this->t('Menu links'), '#tree' => TRUE]; $blocks = $this->entity->getAllBlocksSortedByLink(); foreach ($menu_links_elements as $link_element_id => $link_element) { // Replace any dots with a underscore since dots are not supported as // keys in the configuration data. $link_element_id = str_replace('.', '_', $link_element_id); $link_layout = $this->entity->getLinkLayout($link_element_id); $regions = $this->getLayoutRegions($link_layout); $link_id = Html::getId($link_element_id); $form['links'][$link_element_id] = ['#type' => 'fieldset', '#title' => $link_element->link->getTitle()]; $form['links'][$link_element_id]['layout'] = ['#type' => 'select', '#title' => $this->t('Layout'), '#options' => $layout_options, '#default_value' => $link_layout, '#ajax' => ['callback' => '::onLayoutSelect', 'wrapper' => "mega-menu-link-{$link_id}-blocks-wrapper"], '#attributes' => ['data-link-element-id' => $link_element_id]]; $form['links'][$link_element_id]['blocks'] = ['#prefix' => '<div id="mega-menu-link-' . $link_id . '-blocks-wrapper">', '#suffix' => '</div>', '#type' => 'table', '#header' => $table_header, '#empty' => $this->t('There are no regions for blocks.')]; // Add regions. foreach ($regions as $region_key => $region_name) { // Tabledrag stuff. $form['links'][$link_element_id]['blocks']['#tabledrag'][] = ['action' => 'match', 'relationship' => 'sibling', 'group' => 'block-region-select', 'subgroup' => 'block-region-' . $region_key, 'hidden' => FALSE]; $form['links'][$link_element_id]['blocks']['#tabledrag'][] = ['action' => 'order', 'relationship' => 'sibling', 'group' => 'block-weight', 'subgroup' => 'block-weight-' . $region_key]; // Regions. $form['links'][$link_element_id]['blocks'][$region_key] = ['#attributes' => ['class' => ['region-title', 'region-title-' . $region_key], 'no_striping' => TRUE]]; if ($region_key === MegaMenuInterface::NO_REGION) { $form['links'][$link_element_id]['blocks'][$region_key]['title'] = ['#markup' => $region_name, '#wrapper_attributes' => ['colspan' => 5]]; } else { $form['links'][$link_element_id]['blocks'][$region_key]['title'] = ['#theme_wrappers' => ['container' => ['#attributes' => ['class' => ['region-title__action']]]], '#prefix' => $region_name, '#type' => 'link', '#title' => $this->t('Place block <span class="visually-hidden">in the %region region</span>', ['%region' => $region_name]), '#url' => Url::fromRoute('mega_menu.block_library', ['mega_menu' => $this->entity->id()], ['query' => ['link' => $link_element_id, 'region' => $region_key]]), '#wrapper_attributes' => ['colspan' => 5], '#attributes' => ['class' => ['use-ajax', 'button', 'button--small'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 700])]]; } $blocks_by_region = isset($blocks[$link_element_id]) ? $blocks[$link_element_id]->getAllByRegion() : []; $region_message_class = empty($blocks_by_region[$region_key]) ? 'region-empty' : 'region-populated'; $form['links'][$link_element_id]['blocks'][$region_key . '-message'] = ['#attributes' => ['class' => ['region-message', 'region-' . $region_key . '-message', $region_message_class]]]; $form['links'][$link_element_id]['blocks'][$region_key . '-message']['message'] = ['#markup' => '<em>' . $this->t('No blocks in this region') . '</em>', '#wrapper_attributes' => ['colspan' => 5]]; if (!isset($blocks_by_region[$region_key])) { continue; } /** @var BlockPluginInterface $block */ foreach ($blocks_by_region[$region_key] as $block_id => $block) { if (!isset($form['links'][$link_element_id])) { continue; } $operations = ['edit' => ['title' => $this->t('Edit'), 'url' => Url::fromRoute('mega_menu.block_edit', ['mega_menu' => $this->entity->id(), 'block_id' => $block_id], ['query' => ['link' => $link_element_id, 'region' => $region_key]]), 'attributes' => ['class' => ['use-ajax', 'button', 'button--small'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 700])]], 'delete' => ['title' => $this->t('Delete'), 'url' => Url::fromRoute('mega_menu.block_delete', ['mega_menu' => $this->entity->id(), 'block_id' => $block_id], ['query' => ['link' => $link_element_id]]), 'attributes' => ['class' => ['use-ajax', 'button', 'button--small'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 700])]]]; $configuration = $block->getConfiguration(); $form['links'][$link_element_id]['blocks'][$block_id] = ['#attributes' => ['class' => ['draggable']], 'label' => ['#markup' => $block->label()], 'category' => ['#markup' => $block->getPluginDefinition()['category']], 'region' => ['#type' => 'select', '#title' => $this->t('Region for @block block', ['@block' => $block->label()]), '#title_display' => 'invisible', '#default_value' => $region_key, '#options' => $regions, '#attributes' => ['class' => ['block-region-select', 'block-region-' . $region_key]]], 'weight' => ['#type' => 'weight', '#default_value' => isset($configuration['weight']) ? $configuration['weight'] : 0, '#title' => $this->t('Weight for @block block', ['@block' => $block->label()]), '#title_display' => 'invisible', '#attributes' => ['class' => ['block-weight', 'block-weight-' . $configuration['region']]]], 'operations' => ['#type' => 'operations', '#links' => $operations]]; } } } return $form; }
/** * Chooses an address to fill out a form. */ protected function selectAddress(array $addresses = []) { $quote_config = \Drupal::config('uc_quote.settings'); $store_address = $quote_config->get('store_default_address'); $store_address = new \Drupal\uc_store\Address(); if (!in_array($store_address, $addresses)) { $addresses[] = $store_address; } $blank = array('first_name' => '', 'last_name' => '', 'phone' => '', 'company' => '', 'street1' => '', 'street2' => '', 'city' => '', 'postal_code' => '', 'country' => 0, 'zone' => 0); $options = array(Json::encode($blank) => t('- Reset fields -')); foreach ($addresses as $address) { $options[Json::encode($address)] = $address->company . ' ' . $address->street1 . ' ' . $address->city; } $select = array('#type' => 'select', '#title' => t('Saved addresses'), '#options' => $options, '#default_value' => Json::encode($addresses[0]), '#attributes' => array('onchange' => 'apply_address(\'pickup\', this.value);')); return $select; }
/** * {@inheritdoc} * * For anonymous users, the "active" class will be calculated on the server, * because most sites serve each anonymous user the same cached page anyway. * For authenticated users, the "active" class will be calculated on the * client (through JavaScript), only data- attributes are added to links to * prevent breaking the render cache. The JavaScript is added in * system_page_build(). * * @see system_page_build() */ public function generateFromUrl($text, Url $url) { // Start building a structured representation of our link to be altered later. $variables = array('text' => is_array($text) ? drupal_render($text) : $text, 'url' => $url, 'options' => $url->getOptions()); // Merge in default options. $variables['options'] += array('attributes' => array(), 'query' => array(), 'html' => FALSE, 'language' => NULL, 'set_active_class' => FALSE, 'absolute' => FALSE); // Add a hreflang attribute if we know the language of this link's url and // hreflang has not already been set. if (!empty($variables['options']['language']) && !isset($variables['options']['attributes']['hreflang'])) { $variables['options']['attributes']['hreflang'] = $variables['options']['language']->id; } // Set the "active" class if the 'set_active_class' option is not empty. if (!empty($variables['options']['set_active_class']) && !$url->isExternal()) { // Add a "data-drupal-link-query" attribute to let the // drupal.active-link library know the query in a standardized manner. if (!empty($variables['options']['query'])) { $query = $variables['options']['query']; ksort($query); $variables['options']['attributes']['data-drupal-link-query'] = Json::encode($query); } // Add a "data-drupal-link-system-path" attribute to let the // drupal.active-link library know the path in a standardized manner. if (!isset($variables['options']['attributes']['data-drupal-link-system-path'])) { // @todo System path is deprecated - use the route name and parameters. $system_path = $url->getInternalPath(); // Special case for the front page. $variables['options']['attributes']['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path; } } // Remove all HTML and PHP tags from a tooltip, calling expensive strip_tags() // only when a quick strpos() gives suspicion tags are present. if (isset($variables['options']['attributes']['title']) && strpos($variables['options']['attributes']['title'], '<') !== FALSE) { $variables['options']['attributes']['title'] = strip_tags($variables['options']['attributes']['title']); } // Allow other modules to modify the structure of the link. $this->moduleHandler->alter('link', $variables); // Move attributes out of options. generateFromRoute(() doesn't need them. $attributes = new Attribute($variables['options']['attributes']); unset($variables['options']['attributes']); $url->setOptions($variables['options']); // The result of the url generator is a plain-text URL. Because we are using // it here in an HTML argument context, we need to encode it properly. $url = String::checkPlain($url->toString()); // Sanitize the link text if necessary. $text = $variables['options']['html'] ? $variables['text'] : String::checkPlain($variables['text']); return SafeMarkup::set('<a href="' . $url . '"' . $attributes . '>' . $text . '</a>'); }
/** * {@inheritdoc} * * This class evaluates the aggregation enabled/disabled condition on a group * by group basis by testing whether an aggregate file has been made for the * group rather than by testing the site-wide aggregation setting. This allows * this class to work correctly even if modules have implemented custom * logic for grouping and aggregating files. */ public function render(array $js_assets) { $elements = array(); // A dummy query-string is added to filenames, to gain control over // browser-caching. The string changes on every update or full cache // flush, forcing browsers to load a new copy of the files, as the // URL changed. Files that should not be cached get REQUEST_TIME as // query-string instead, to enforce reload on every page request. $default_query_string = $this->state->get('system.css_js_query_string') ?: '0'; // Defaults for each SCRIPT element. $element_defaults = array('#type' => 'html_tag', '#tag' => 'script', '#value' => ''); // Loop through all JS assets. foreach ($js_assets as $js_asset) { // Element properties that do not depend on JS asset type. $element = $element_defaults; $element['#browsers'] = $js_asset['browsers']; // Element properties that depend on item type. switch ($js_asset['type']) { case 'setting': $element['#attributes'] = array('type' => 'application/json', 'data-drupal-selector' => 'drupal-settings-json'); $element['#value'] = Json::encode($js_asset['data']); break; case 'file': $query_string = $js_asset['version'] == -1 ? $default_query_string : 'v=' . $js_asset['version']; $query_string_separator = strpos($js_asset['data'], '?') !== FALSE ? '&' : '?'; $element['#attributes']['src'] = file_url_transform_relative(file_create_url($js_asset['data'])); // Only add the cache-busting query string if this isn't an aggregate // file. if (!isset($js_asset['preprocessed'])) { $element['#attributes']['src'] .= $query_string_separator . ($js_asset['cache'] ? $query_string : REQUEST_TIME); } break; case 'external': $element['#attributes']['src'] = $js_asset['data']; break; default: throw new \Exception('Invalid JS asset type.'); } // Attributes may only be set if this script is output independently. if (!empty($element['#attributes']['src']) && !empty($js_asset['attributes'])) { $element['#attributes'] += $js_asset['attributes']; } $elements[] = $element; } return $elements; }
/** * Tests image field formatter Entity Embed Display plugin. */ public function testImageFieldFormatter() { // Ensure that image field formatters are available as plugins. $this->assertAvailableDisplayPlugins($this->image, ['entity_reference:entity_reference_label', 'entity_reference:entity_reference_entity_id', 'file:file_default', 'file:file_table', 'file:file_url_plain', 'image:responsive_image', 'image:image']); // Ensure that correct form attributes are returned for the image plugin. $form = array(); $form_state = new FormState(); $display = $this->displayPluginManager()->createInstance('image:image', array()); $display->setContextValue('entity', $this->image); $conf_form = $display->buildConfigurationForm($form, $form_state); $this->assertIdentical(array_keys($conf_form), array('image_style', 'image_link', 'alt', 'title')); $this->assertIdentical($conf_form['image_style']['#type'], 'select'); $this->assertIdentical((string) $conf_form['image_style']['#title'], 'Image style'); $this->assertIdentical($conf_form['image_link']['#type'], 'select'); $this->assertIdentical((string) $conf_form['image_link']['#title'], 'Link image to'); $this->assertIdentical($conf_form['alt']['#type'], 'textfield'); $this->assertIdentical((string) $conf_form['alt']['#title'], 'Alternate text'); $this->assertIdentical($conf_form['title']['#type'], 'textfield'); $this->assertIdentical((string) $conf_form['title']['#title'], 'Title'); // Test entity embed using 'Image' Entity Embed Display plugin. $alt_text = "This is sample description"; $title = "This is sample title"; $embed_settings = array('image_link' => 'file'); $content = '<drupal-entity data-entity-type="file" data-entity-uuid="' . $this->image->uuid() . '" data-entity-embed-display="image:image" data-entity-embed-settings=\'' . Json::encode($embed_settings) . '\' alt="' . $alt_text . '" title="' . $title . '">This placeholder should not be rendered.</drupal-entity>'; $settings = array(); $settings['type'] = 'page'; $settings['title'] = 'Test entity embed with image:image'; $settings['body'] = array(array('value' => $content, 'format' => 'custom_format')); $node = $this->drupalCreateNode($settings); $this->drupalGet('node/' . $node->id()); $this->assertRaw($alt_text, 'Alternate text for the embedded image is visible when embed is successful.'); $this->assertNoText(strip_tags($content), 'Placeholder does not appears in the output when embed is successful.'); $this->assertLinkByHref(file_create_url($this->image->getFileUri()), 0, 'Link to the embedded image exists.'); // Embed all three field types in one, to ensure they all render correctly. $content = '<drupal-entity data-entity-type="node" data-entity-uuid="' . $this->node->uuid() . '" data-entity-embed-display="entity_reference:entity_reference_label"></drupal-entity>'; $content .= '<drupal-entity data-entity-type="file" data-entity-uuid="' . $this->file->uuid() . '" data-entity-embed-display="file:file_default"></drupal-entity>'; $content .= '<drupal-entity data-entity-type="file" data-entity-uuid="' . $this->image->uuid() . '" data-entity-embed-display="image:image"></drupal-entity>'; $settings = array(); $settings['type'] = 'page'; $settings['title'] = 'Test node entity embedded first then a file entity'; $settings['body'] = array(array('value' => $content, 'format' => 'custom_format')); $node = $this->drupalCreateNode($settings); $this->drupalGet('node/' . $node->id()); }
/** * Get all system variables * * @return array() */ public function getVariablesData() { $data = array(); $variables = array('acquia_spi_send_node_user', 'acquia_spi_admin_priv', 'acquia_spi_module_diff_data', 'acquia_spi_send_watchdog', 'acquia_spi_use_cron', 'cache_backends', 'cache_default_class', 'cache_inc', 'cron_safe_threshold', 'googleanalytics_cache', 'error_level', 'preprocess_js', 'page_cache_maximum_age', 'block_cache', 'preprocess_css', 'page_compression', 'cache', 'cache_lifetime', 'cron_last', 'clean_url', 'redirect_global_clean', 'theme_zen_settings', 'site_offline', 'site_name', 'user_register', 'user_signatures', 'user_admin_role', 'user_email_verification', 'user_cancel_method', 'filter_fallback_format', 'dblog_row_limit', 'date_default_timezone', 'file_default_scheme', 'install_profile', 'maintenance_mode', 'update_last_check', 'site_default_country', 'acquia_spi_saved_variables', 'acquia_spi_set_variables_automatic', 'acquia_spi_ignored_set_variables', 'acquia_spi_set_variables_override'); $allConfigData = self::getAllConfigs(); $spi_def_vars = \Drupal::config('acquia_connector.settings')->get('spi.def_vars'); $waived_spi_def_vars = \Drupal::config('acquia_connector.settings')->get('spi.def_waived_vars'); // Merge hard coded $variables with vars from SPI definition. foreach ($spi_def_vars as $var_name => $var) { if (!in_array($var_name, $waived_spi_def_vars) && !in_array($var_name, $variables)) { $variables[] = $var_name; } } // @todo Add comment settings for node types. foreach ($variables as $name) { if (!empty($this->mapping[$name])) { // state if ($this->mapping[$name][0] == 'state' and !empty($this->mapping[$name][1])) { $data[$name] = \Drupal::state()->get($this->mapping[$name][1]); } elseif ($this->mapping[$name][0] == 'settings' and !empty($this->mapping[$name][1])) { $data[$name] = Settings::get($this->mapping[$name][1]); } else { $key_exists = NULL; $value = Utility\NestedArray::getValue($allConfigData, $this->mapping[$name], $key_exists); if ($key_exists) { $data[$name] = $value; } else { $data[$name] = 0; } } } else { // @todo: Implement D8 way to update variables mapping. $data[$name] = 'Variable not implemented.'; } } // Unset waived vars so they won't be sent to NSPI. foreach ($data as $var_name => $var) { if (in_array($var_name, $waived_spi_def_vars)) { unset($data[$var_name]); } } // Collapse to JSON string to simplify transport. return Json::encode($data); }
/** * Method tests CKEditor image buttons. */ public function testImageButtonDisplay() { $this->drupalLogin($this->admin_user); // Install the Arabic language (which is RTL) and configure as the default. $edit = []; $edit['predefined_langcode'] = 'ar'; $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language')); $edit = ['site_default_language' => 'ar']; $this->drupalPostForm('admin/config/regional/language', $edit, t('Save configuration')); // Once the default language is changed, go to the tested text format // configuration page. $this->drupalGet('admin/config/content/formats/manage/full_html'); // Check if any image button is loaded in CKEditor json. $json_encode = function ($html) { return trim(Json::encode($html), '"'); }; $markup = $json_encode(file_url_transform_relative(file_create_url('core/modules/ckeditor/js/plugins/drupalimage/image.png'))); $this->assertRaw($markup); }
/** * Tests buildForm calls what we expect. * * GIVEN the embridge search form * WHEN buildForm is run * THEN we should have a form structured as we expect. * * @covers ::buildForm * @covers ::getSearchResults * @covers ::formatSearchResults * * @test */ public function buildFormArrayIsReturnedAsExpected() { $form = []; $form_state = new FormState(); $catalog_id = 'test_catalog'; $application_id = 'test_app'; $delta = 0; // Mock up a whole mess of stuff. $this->baseMockBuild($catalog_id, $application_id); $build = $this->form->buildForm($form, $form_state, $this->fieldConfig, $delta); $expected_build = file_get_contents('expected/embridge-search-form-expected-build.json', TRUE); // Assert JSON structures are similar. $this->assertJsonStringEqualsJsonString($expected_build, $this->json->encode($build)); // Test the search results render array is populated correctly. // Test this manually as json encoding clobbers the results. foreach ($build['search_results']['#results'] as $i => $render_result) { $this->assertEquals($this->mockAssets[$i]['asset'], $render_result['#asset']); } }
/** * Get a list of blocks that can be placed in a mega menu. * * @param Request $request * @param MegaMenuInterface $mega_menu * @return array */ public function blockLibrary(Request $request, MegaMenuInterface $mega_menu) { // Get the query parameters needed. $link = $request->query->get('link'); $region = $request->query->get('region'); // Only add blocks which work without any available context. $blocks = $this->blockManager->getDefinitionsForContexts($this->contextRepository->getAvailableContexts()); // Order by category, and then by admin label. $blocks = $this->blockManager->getSortedDefinitions($blocks); $build['filter'] = ['#type' => 'search', '#title' => $this->t('Filter'), '#title_display' => 'invisible', '#size' => 30, '#placeholder' => $this->t('Filter by block name'), '#attributes' => ['class' => ['block-filter-text'], 'data-element' => '.block-add-table', 'title' => $this->t('Enter a part of the block name to filter by.')]]; $headers = [$this->t('Block'), $this->t('Category'), $this->t('Operations')]; $build['blocks'] = ['#type' => 'table', '#header' => $headers, '#rows' => [], '#empty' => $this->t('No blocks available.'), '#attributes' => ['class' => ['block-add-table']]]; // Add each block definition to the table. foreach ($blocks as $block_id => $block) { $links = ['add' => ['title' => $this->t('Place block'), 'url' => Url::fromRoute('mega_menu.block_add', ['mega_menu' => $mega_menu->id(), 'block_id' => $block_id], ['query' => ['link' => $link, 'region' => $region]]), 'attributes' => ['class' => ['use-ajax'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 700])]]]; $build['blocks']['#rows'][] = ['title' => ['data' => ['#type' => 'inline_template', '#template' => '<div class="block-filter-text-source">{{ label }}</div>', '#context' => ['label' => $block['admin_label']]]], 'category' => ['data' => $block['category']], 'operations' => ['data' => ['#type' => 'operations', '#links' => $links]]]; } return $build; }
/** * {@inheritdoc} */ public function build() { $build = []; $links = array('#type' => 'link', '#title' => $this->t('Join the network'), '#url' => Url::fromRoute('user.register'), '#attributes' => array('class' => array('use-ajax btn btn-lg btn-rounded-orange'), 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(array('dialogClass' => 'c4auser-ui-dialog', 'width' => 830)))); $build['welcome_section']['#markup'] = '<div class="item"> </div> <div class="logo"></div> <div class="slogan"> <h2>WELCOME TO your Coders community </h2> <h4>WE ARE GROUP OF GENTLEMEN MAKING AWESOME SOFTWARE SOLUTIONS</h4> </div> <div class="network-btn"> <p>' . render($links) . '</p> </div>'; // <p><a class="btn btn-lg btn-rounded-orange use-ajax" data-dialog-options="{"width":700}" data-dialog-type="modal" href="/user/register" role="button">Join the network<i class="fa fa-angle-right icon-nav"></i></a></p> return $build; }
/** * {@inheritdoc} */ public function build() { $build = parent::build(); $active_theme = $this->themeManager->getActiveTheme(); $theme_name = $active_theme->getName(); $destination = $this->redirectDestination->get(); $visible_regions = $this->getVisibleRegionNames($theme_name); // Build an array of the region names in the right order. $build += array_fill_keys(array_keys($visible_regions), []); foreach ($visible_regions as $region => $region_name) { $query = ['region' => $region]; if ($destination) { $query['destination'] = $destination; } $title = $this->t('<span class="visually-hidden">Place block in the %region region</span>', ['%region' => $region_name]); $operations['block_description'] = ['#type' => 'inline_template', '#template' => '<div class="block-place-region">{{ link }}</div>', '#context' => ['link' => Link::createFromRoute($title, 'block.admin_library', ['theme' => $theme_name], ['query' => $query, 'attributes' => ['title' => $title, 'class' => ['use-ajax', 'button', 'button--small'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 700])]])]]; $build[$region] = ['block_place_operations' => $operations] + $build[$region]; } $build['#attached']['library'][] = 'block_place/drupal.block_place'; return $build; }
/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, AccountProxyInterface $user = NULL, RdfInterface $collection = NULL) { $form['#access'] = $this->access(); $user = User::load($user->id()); $form['collection_id'] = ['#type' => 'hidden', '#title' => $this->t('Collection ID'), '#value' => $collection->id()]; $form['user_id'] = ['#type' => 'hidden', '#title' => $this->t('User ID'), '#value' => $user->id()]; // If the user is already a member of the collection, show a link to the // confirmation form, disguised as a form submit button. The confirmation // form should open in a modal dialog for JavaScript-enabled browsers. if (Og::isMember($collection, $user)) { $form['leave'] = ['#type' => 'link', '#title' => $this->t('Leave this collection'), '#url' => Url::fromRoute('collection.leave_confirm_form', ['rdf_entity' => $collection->id()]), '#attributes' => ['class' => ['use-ajax', 'button', 'button--small', 'button--default', 'button--blue-light', 'mdl-button', 'mdl-js-button', 'mdl-button--raised', 'mdl-js-ripple-effect', 'mdl-button--accent'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 'auto'])]]; $form['#attached']['library'][] = 'core/drupal.ajax'; } else { $form['join'] = ['#attributes' => ['class' => ['button--default', 'button--blue-light', 'mdl-button', 'mdl-js-button', 'mdl-button--raised', 'mdl-js-ripple-effect', 'mdl-button--accent']], '#type' => 'submit', '#value' => $this->t('Join this collection')]; } // This form varies by user and collection. // $metadata = new CacheableMetadata(); // $metadata // ->merge(CacheableMetadata::createFromObject($user)) // ->merge(CacheableMetadata::createFromObject($collection)) // ->applyTo($form); return $form; }
/** * Tests links.html.twig using links with indexed keys. */ function testIndexedKeyedLinks() { // Turn off the query for the // \Drupal\Core\Utility\LinkGeneratorInterface::generate() method to compare // the active link correctly. $original_query = \Drupal::request()->query->all(); \Drupal::request()->query->replace([]); // Verify that empty variables produce no output. $variables = []; $expected = ''; $this->assertThemeOutput('links', $variables, $expected, 'Empty %callback generates no output.'); $variables = []; $variables['heading'] = 'Some title'; $expected = ''; $this->assertThemeOutput('links', $variables, $expected, 'Empty %callback with heading generates no output.'); // Verify that a list of links is properly rendered. $variables = []; $variables['attributes'] = ['id' => 'somelinks']; $variables['links'] = array(array('title' => 'A <link>', 'url' => Url::fromUri('base:a/link')), array('title' => 'Plain "text"'), array('title' => SafeMarkup::format('<span class="unescaped">@text</span>', array('@text' => 'potentially unsafe text that <should> be escaped'))), array('title' => 'Front page', 'url' => Url::fromRoute('<front>')), array('title' => 'Test route', 'url' => Url::fromRoute('router_test.1')), array('title' => 'Query test route', 'url' => Url::fromRoute('router_test.1'), 'query' => array('key' => 'value'))); $expected_links = ''; $expected_links .= '<ul id="somelinks">'; $expected_links .= '<li><a href="' . Url::fromUri('base:a/link')->toString() . '">' . Html::escape('A <link>') . '</a></li>'; $expected_links .= '<li>' . Html::escape('Plain "text"') . '</li>'; $expected_links .= '<li><span class="unescaped">' . Html::escape('potentially unsafe text that <should> be escaped') . '</span></li>'; $expected_links .= '<li><a href="' . Url::fromRoute('<front>')->toString() . '">' . Html::escape('Front page') . '</a></li>'; $expected_links .= '<li><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '">' . Html::escape('Test route') . '</a></li>'; $query = ['key' => 'value']; $expected_links .= '<li><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '">' . Html::escape('Query test route') . '</a></li>'; $expected_links .= '</ul>'; // Verify that passing a string as heading works. $variables['heading'] = 'Links heading'; $expected_heading = '<h2>Links heading</h2>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); // Restore the original request's query. \Drupal::request()->query->replace($original_query); // Verify that passing an array as heading works (core support). $variables['heading'] = ['text' => 'Links heading', 'level' => 'h3', 'attributes' => ['class' => ['heading']]]; $expected_heading = '<h3 class="heading">Links heading</h3>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); // Verify that passing attributes for the heading works. $variables['heading'] = ['text' => 'Links heading', 'level' => 'h3', 'attributes' => ['id' => 'heading']]; $expected_heading = '<h3 id="heading">Links heading</h3>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); // Verify that passing attributes for the links work. $variables['links'][1]['attributes'] = ['class' => ['a/class']]; $expected_links = ''; $expected_links .= '<ul id="somelinks">'; $expected_links .= '<li><a href="' . Url::fromUri('base:a/link')->toString() . '">' . Html::escape('A <link>') . '</a></li>'; $expected_links .= '<li><span class="a/class">' . Html::escape('Plain "text"') . '</span></li>'; $expected_links .= '<li><span class="unescaped">' . Html::escape('potentially unsafe text that <should> be escaped') . '</span></li>'; $expected_links .= '<li><a href="' . Url::fromRoute('<front>')->toString() . '">' . Html::escape('Front page') . '</a></li>'; $expected_links .= '<li><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '">' . Html::escape('Test route') . '</a></li>'; $query = ['key' => 'value']; $expected_links .= '<li><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '">' . Html::escape('Query test route') . '</a></li>'; $expected_links .= '</ul>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); // Verify the data- attributes for setting the "active" class on links. \Drupal::currentUser()->setAccount(new UserSession(array('uid' => 1))); $variables['set_active_class'] = TRUE; $expected_links = ''; $expected_links .= '<ul id="somelinks">'; $expected_links .= '<li><a href="' . Url::fromUri('base:a/link')->toString() . '">' . Html::escape('A <link>') . '</a></li>'; $expected_links .= '<li><span class="a/class">' . Html::escape('Plain "text"') . '</span></li>'; $expected_links .= '<li><span class="unescaped">' . Html::escape('potentially unsafe text that <should> be escaped') . '</span></li>'; $expected_links .= '<li data-drupal-link-system-path="<front>"><a href="' . Url::fromRoute('<front>')->toString() . '" data-drupal-link-system-path="<front>">' . Html::escape('Front page') . '</a></li>'; $expected_links .= '<li data-drupal-link-system-path="router_test/test1"><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '" data-drupal-link-system-path="router_test/test1">' . Html::escape('Test route') . '</a></li>'; $query = ['key' => 'value']; $encoded_query = Html::escape(Json::encode($query)); $expected_links .= '<li data-drupal-link-query="' . $encoded_query . '" data-drupal-link-system-path="router_test/test1"><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '" data-drupal-link-query="' . $encoded_query . '" data-drupal-link-system-path="router_test/test1">' . Html::escape('Query test route') . '</a></li>'; $expected_links .= '</ul>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); }
/** * Shows all possible files in selectable list. */ protected function buildJsFileDisplay($file_ids) { // Gather the files if recursion IS selected. // Get 'em all ready to be punched into the file list. $recursion_file_ids = _uc_file_sort_names(_uc_file_get_dir_file_ids($file_ids, TRUE)); foreach ($recursion_file_ids as $file_id) { $file = uc_file_get_by_id($file_id); $recursion[] = '<li>' . $file->filename . '</li>'; } // Gather the files if recursion ISN'T selected. // Get 'em all ready to be punched into the file list. $no_recursion_file_ids = $file_ids; foreach ($no_recursion_file_ids as $file_id) { $file = uc_file_get_by_id($file_id); $no_recursion[] = '<li>' . $file->filename . '</li>'; } // We'll disable the recursion checkbox if they're equal. $equivalent = $this->displayArraysEquivalent($recursion_file_ids, $no_recursion_file_ids); // The list to show if the recursion checkbox is $key. $result[TRUE] = $equivalent ? FALSE : $recursion; $result[FALSE] = $no_recursion; // Set up some JS to dynamically update the list based on the // recursion checkbox state. drupal_add_js('uc_file_list[false] = ' . Json::encode('<li>' . implode('</li><li>', $no_recursion) . '</li>') . ';', 'inline'); drupal_add_js('uc_file_list[true] = ' . Json::encode('<li>' . implode('</li><li>', $recursion) . '</li>') . ';', 'inline'); return $result; }
/** * Tests BigPipe-delivered HTML responses when JavaScript is enabled. * * Covers: * - \Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber * - \Drupal\big_pipe\Render\BigPipe * - \Drupal\big_pipe\Render\BigPipe::sendPlaceholders() * * @see \Drupal\big_pipe\Tests\BigPipePlaceholderTestCases */ public function testBigPipe() { $this->drupalLogin($this->rootUser); $this->assertSessionCookieExists(TRUE); $this->assertBigPipeNoJsCookieExists(FALSE); // By not calling performMetaRefresh() here, we simulate JavaScript being // enabled, because as far as the BigPipe module is concerned, JavaScript is // enabled in the browser as long as the BigPipe no-JS cookie is *not* set. // @see setUp() // @see performMetaRefresh() $this->drupalGet(Url::fromRoute('big_pipe_test')); $this->assertBigPipeResponseHeadersPresent(); $cases = $this->getTestCases(); $this->assertBigPipeNoJsPlaceholders([$cases['edge_case__invalid_html']->bigPipeNoJsPlaceholder => $cases['edge_case__invalid_html']->embeddedHtmlResponse, $cases['html_attribute_value']->bigPipeNoJsPlaceholder => $cases['html_attribute_value']->embeddedHtmlResponse, $cases['html_attribute_value_subset']->bigPipeNoJsPlaceholder => $cases['html_attribute_value_subset']->embeddedHtmlResponse]); $this->assertBigPipePlaceholders([$cases['html']->bigPipePlaceholderId => Json::encode($cases['html']->embeddedAjaxResponseCommands), $cases['edge_case__html_non_lazy_builder']->bigPipePlaceholderId => Json::encode($cases['edge_case__html_non_lazy_builder']->embeddedAjaxResponseCommands)]); $this->pass('Verifying BigPipe assets are present…', 'Debug'); $this->assertFalse(empty($this->getDrupalSettings()), 'drupalSettings present.'); $this->assertTrue(in_array('big_pipe/big_pipe', explode(',', $this->getDrupalSettings()['ajaxPageState']['libraries'])), 'BigPipe asset library is present.'); // Verify that 4xx responses work fine. (4xx responses are handled by // subrequests to a route pointing to a controller with the desired output.) $this->drupalGet(Url::fromUri('base:non-existing-path')); }
/** * Builds the main "Blocks" portion of the form. * * @return array */ protected function buildBlocksForm() { // Build blocks first for each region. $blocks = []; $entities = $this->load(); /** @var \Drupal\block\BlockInterface[] $entities */ foreach ($entities as $entity_id => $entity) { $definition = $entity->getPlugin()->getPluginDefinition(); $blocks[$entity->getRegion()][$entity_id] = array('label' => $entity->label(), 'entity_id' => $entity_id, 'weight' => $entity->getWeight(), 'entity' => $entity, 'category' => $definition['category']); } $form = array('#type' => 'table', '#header' => array($this->t('Block'), $this->t('Category'), $this->t('Region'), $this->t('Weight'), $this->t('Operations')), '#attributes' => array('id' => 'blocks')); // Weights range from -delta to +delta, so delta should be at least half // of the amount of blocks present. This makes sure all blocks in the same // region get an unique weight. $weight_delta = round(count($entities) / 2); $placement = FALSE; if ($this->request->query->has('block-placement')) { $placement = $this->request->query->get('block-placement'); $form['#attached']['drupalSettings']['blockPlacement'] = $placement; } // Loop over each region and build blocks. $regions = $this->systemRegionList($this->getThemeName(), REGIONS_VISIBLE); $block_regions_with_disabled = $regions + array(BlockInterface::BLOCK_REGION_NONE => $this->t('Disabled', array(), array('context' => 'Plural'))); foreach ($block_regions_with_disabled as $region => $title) { $form['#tabledrag'][] = array('action' => 'match', 'relationship' => 'sibling', 'group' => 'block-region-select', 'subgroup' => 'block-region-' . $region, 'hidden' => FALSE); $form['#tabledrag'][] = array('action' => 'order', 'relationship' => 'sibling', 'group' => 'block-weight', 'subgroup' => 'block-weight-' . $region); $form['region-' . $region] = array('#attributes' => array('class' => array('region-title', 'region-title-' . $region), 'no_striping' => TRUE)); $form['region-' . $region]['title'] = array('#prefix' => $region != BlockInterface::BLOCK_REGION_NONE ? $title : $block_regions_with_disabled[$region], '#type' => 'link', '#title' => $this->t('Place block <span class="visually-hidden">in the %region region</span>', ['%region' => $block_regions_with_disabled[$region]]), '#url' => Url::fromRoute('block.admin_library', ['theme' => $this->getThemeName()], ['query' => ['region' => $region]]), '#wrapper_attributes' => array('colspan' => 5), '#attributes' => ['class' => ['use-ajax', 'button', 'button--small'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 700])]); $form['region-' . $region . '-message'] = array('#attributes' => array('class' => array('region-message', 'region-' . $region . '-message', empty($blocks[$region]) ? 'region-empty' : 'region-populated'))); $form['region-' . $region . '-message']['message'] = array('#markup' => '<em>' . $this->t('No blocks in this region') . '</em>', '#wrapper_attributes' => array('colspan' => 5)); if (isset($blocks[$region])) { foreach ($blocks[$region] as $info) { $entity_id = $info['entity_id']; $form[$entity_id] = array('#attributes' => array('class' => array('draggable'))); if ($placement && $placement == Html::getClass($entity_id)) { $form[$entity_id]['#attributes']['class'][] = 'color-warning'; $form[$entity_id]['#attributes']['class'][] = 'js-block-placed'; } $form[$entity_id]['info'] = array('#plain_text' => $info['label'], '#wrapper_attributes' => array('class' => array('block'))); $form[$entity_id]['type'] = array('#markup' => $info['category']); $form[$entity_id]['region-theme']['region'] = array('#type' => 'select', '#default_value' => $region, '#empty_value' => BlockInterface::BLOCK_REGION_NONE, '#title' => $this->t('Region for @block block', array('@block' => $info['label'])), '#title_display' => 'invisible', '#options' => $regions, '#attributes' => array('class' => array('block-region-select', 'block-region-' . $region)), '#parents' => array('blocks', $entity_id, 'region')); $form[$entity_id]['region-theme']['theme'] = array('#type' => 'hidden', '#value' => $this->getThemeName(), '#parents' => array('blocks', $entity_id, 'theme')); $form[$entity_id]['weight'] = array('#type' => 'weight', '#default_value' => $info['weight'], '#delta' => $weight_delta, '#title' => $this->t('Weight for @block block', array('@block' => $info['label'])), '#title_display' => 'invisible', '#attributes' => array('class' => array('block-weight', 'block-weight-' . $region))); $form[$entity_id]['operations'] = $this->buildOperations($info['entity']); } } } // Do not allow disabling the main system content block when it is present. if (isset($form['system_main']['region'])) { $form['system_main']['region']['#required'] = TRUE; } return $form; }
/** * Tests several valid and invalid read requests on all entity types. */ public function testRead() { // @todo Expand this at least to users. // Define the entity types we want to test. $entity_types = array('entity_test', 'node'); foreach ($entity_types as $entity_type) { $this->enableService('entity:' . $entity_type, 'GET'); // Create a user account that has the required permissions to read // resources via the REST API. $permissions = $this->entityPermissions($entity_type, 'view'); $permissions[] = 'restful get entity:' . $entity_type; $account = $this->drupalCreateUser($permissions); $this->drupalLogin($account); // Create an entity programmatically. $entity = $this->entityCreate($entity_type); $entity->save(); // Read it over the REST API. $response = $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET'); $this->assertResponse('200', 'HTTP response code is correct.'); $this->assertHeader('content-type', $this->defaultMimeType); $data = Json::decode($response); // Only assert one example property here, other properties should be // checked in serialization tests. $this->assertEqual($data['uuid'][0]['value'], $entity->uuid(), 'Entity UUID is correct'); // Try to read the entity with an unsupported mime format. $response = $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', 'wrongformat'), 'GET'); $this->assertResponse(406); $this->assertHeader('Content-type', 'application/json'); // Try to read an entity that does not exist. $response = $this->httpRequest(Url::fromUri('base://' . $entity_type . '/9999', ['query' => ['_format' => $this->defaultFormat]]), 'GET'); $this->assertResponse(404); $path = $entity_type == 'node' ? '/node/{node}' : '/entity_test/{entity_test}'; $expected_message = Json::encode(['message' => 'The "' . $entity_type . '" parameter was not converted for the path "' . $path . '" (route name: "rest.entity.' . $entity_type . '.GET.hal_json")']); $this->assertIdentical($expected_message, $response, 'Response message is correct.'); // Make sure that field level access works and that the according field is // not available in the response. Only applies to entity_test. // @see entity_test_entity_field_access() if ($entity_type == 'entity_test') { $entity->field_test_text->value = 'no access value'; $entity->save(); $response = $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET'); $this->assertResponse(200); $this->assertHeader('content-type', $this->defaultMimeType); $data = Json::decode($response); $this->assertFalse(isset($data['field_test_text']), 'Field access protected field is not visible in the response.'); } // Try to read an entity without proper permissions. $this->drupalLogout(); $response = $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET'); $this->assertResponse(403); $this->assertIdentical('{"message":""}', $response); } // Try to read a resource which is not REST API enabled. $account = $this->drupalCreateUser(); $this->drupalLogin($account); $response = $this->httpRequest($account->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET'); // \Drupal\Core\Routing\RequestFormatRouteFilter considers the canonical, // non-REST route a match, but a lower quality one: no format restrictions // means there's always a match and hence when there is no matching REST // route, the non-REST route is used, but can't render into // application/hal+json, so it returns a 406. $this->assertResponse('406', 'HTTP response code is 406 when the resource does not define formats, because it falls back to the canonical, non-REST route.'); $this->assertEqual($response, Json::encode(['message' => 'Not acceptable format: hal_json'])); }
/** * Tests GetUntransformedTextCommand AJAX command. */ public function testGetUntransformedTextCommand() { // Create an entity with values for the field. $entity = entity_create('entity_test'); $entity->{$this->fieldName}->value = 'Test'; $entity->{$this->fieldName}->format = 'full_html'; $entity->save(); $entity = entity_load('entity_test', $entity->id()); // Verify AJAX response. $controller = new EditorController(); $request = new Request(); $response = $controller->getUntransformedText($entity, $this->fieldName, LanguageInterface::LANGCODE_NOT_SPECIFIED, 'default'); $expected = array(array('command' => 'editorGetUntransformedText', 'data' => 'Test')); $ajax_response_attachments_processor = \Drupal::service('ajax_response.attachments_processor'); $subscriber = new AjaxResponseSubscriber($ajax_response_attachments_processor); $event = new FilterResponseEvent(\Drupal::service('http_kernel'), $request, HttpKernelInterface::MASTER_REQUEST, $response); $subscriber->onResponse($event); $this->assertEqual(Json::encode($expected), $response->getContent(), 'The GetUntransformedTextCommand AJAX command works correctly.'); }
/** * Tests links.html.twig. */ function testLinks() { // Turn off the query for the _l() function to compare the active // link correctly. $original_query = \Drupal::request()->query->all(); \Drupal::request()->query->replace(array()); // Verify that empty variables produce no output. $variables = array(); $expected = ''; $this->assertThemeOutput('links', $variables, $expected, 'Empty %callback generates no output.'); $variables = array(); $variables['heading'] = 'Some title'; $expected = ''; $this->assertThemeOutput('links', $variables, $expected, 'Empty %callback with heading generates no output.'); // Verify that a list of links is properly rendered. $variables = array(); $variables['attributes'] = array('id' => 'somelinks'); $variables['links'] = array('a link' => array('title' => 'A <link>', 'url' => Url::fromUri('base://a/link')), 'plain text' => array('title' => 'Plain "text"'), 'front page' => array('title' => 'Front page', 'url' => Url::fromRoute('<front>')), 'router-test' => array('title' => 'Test route', 'url' => Url::fromRoute('router_test.1')), 'query-test' => array('title' => 'Query test route', 'url' => Url::fromRoute('router_test.1'), 'query' => array('key' => 'value'))); $expected_links = ''; $expected_links .= '<ul id="somelinks">'; $expected_links .= '<li class="a-link"><a href="' . Url::fromUri('base://a/link')->toString() . '">' . String::checkPlain('A <link>') . '</a></li>'; $expected_links .= '<li class="plain-text">' . String::checkPlain('Plain "text"') . '</li>'; $expected_links .= '<li class="front-page"><a href="' . _url('<front>') . '">' . String::checkPlain('Front page') . '</a></li>'; $expected_links .= '<li class="router-test"><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '">' . String::checkPlain('Test route') . '</a></li>'; $query = array('key' => 'value'); $expected_links .= '<li class="query-test"><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '">' . String::checkPlain('Query test route') . '</a></li>'; $expected_links .= '</ul>'; // Verify that passing a string as heading works. $variables['heading'] = 'Links heading'; $expected_heading = '<h2>Links heading</h2>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); // Restore the original request's query. \Drupal::request()->query->replace($original_query); // Verify that passing an array as heading works (core support). $variables['heading'] = array('text' => 'Links heading', 'level' => 'h3', 'attributes' => array('class' => array('heading'))); $expected_heading = '<h3 class="heading">Links heading</h3>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); // Verify that passing attributes for the heading works. $variables['heading'] = array('text' => 'Links heading', 'level' => 'h3', 'attributes' => array('id' => 'heading')); $expected_heading = '<h3 id="heading">Links heading</h3>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); // Verify that passing attributes for the links work. $variables['links']['plain text']['attributes'] = array('class' => array('a/class')); $expected_links = ''; $expected_links .= '<ul id="somelinks">'; $expected_links .= '<li class="a-link"><a href="' . Url::fromUri('base://a/link')->toString() . '">' . String::checkPlain('A <link>') . '</a></li>'; $expected_links .= '<li class="plain-text"><span class="a/class">' . String::checkPlain('Plain "text"') . '</span></li>'; $expected_links .= '<li class="front-page"><a href="' . _url('<front>') . '">' . String::checkPlain('Front page') . '</a></li>'; $expected_links .= '<li class="router-test"><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '">' . String::checkPlain('Test route') . '</a></li>'; $query = array('key' => 'value'); $expected_links .= '<li class="query-test"><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '">' . String::checkPlain('Query test route') . '</a></li>'; $expected_links .= '</ul>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); // Verify the data- attributes for setting the "active" class on links. \Drupal::currentUser()->setAccount(new UserSession(array('uid' => 1))); $variables['set_active_class'] = TRUE; $expected_links = ''; $expected_links .= '<ul id="somelinks">'; $expected_links .= '<li class="a-link"><a href="' . Url::fromUri('base://a/link')->toString() . '">' . String::checkPlain('A <link>') . '</a></li>'; $expected_links .= '<li class="plain-text"><span class="a/class">' . String::checkPlain('Plain "text"') . '</span></li>'; $expected_links .= '<li data-drupal-link-system-path="<front>" class="front-page"><a href="' . _url('<front>') . '" data-drupal-link-system-path="<front>">' . String::checkPlain('Front page') . '</a></li>'; $expected_links .= '<li data-drupal-link-system-path="router_test/test1" class="router-test"><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '" data-drupal-link-system-path="router_test/test1">' . String::checkPlain('Test route') . '</a></li>'; $query = array('key' => 'value'); $encoded_query = String::checkPlain(Json::encode($query)); $expected_links .= '<li data-drupal-link-query="' . $encoded_query . '" data-drupal-link-system-path="router_test/test1" class="query-test"><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '" data-drupal-link-query="' . $encoded_query . '" data-drupal-link-system-path="router_test/test1">' . String::checkPlain('Query test route') . '</a></li>'; $expected_links .= '</ul>'; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); }