Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
|
@ -92,8 +92,9 @@ function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_pa
|
|||
}
|
||||
// For easiest integration with the form API and the testing framework, we
|
||||
// always give the button a unique #value, rather than playing around with
|
||||
// #name.
|
||||
$button_title = !empty($triggering_element['#title']) ? $triggering_element['#title'] : $trigger_key;
|
||||
// #name. We also cast the #title to string as we will use it as an array
|
||||
// key and it may be a TranslatableMarkup.
|
||||
$button_title = !empty($triggering_element['#title']) ? (string) $triggering_element['#title'] : $trigger_key;
|
||||
if (empty($seen_buttons[$button_title])) {
|
||||
$wrapping_element[$button_key]['#value'] = t('Update "@title" choice', array(
|
||||
'@title' => $button_title,
|
||||
|
@ -314,7 +315,7 @@ function views_ui_build_form_url(FormStateInterface $form_state) {
|
|||
function views_ui_form_button_was_clicked($element, FormStateInterface $form_state) {
|
||||
$user_input = $form_state->getUserInput();
|
||||
$process_input = empty($element['#disabled']) && ($form_state->isProgrammed() || ($form_state->isProcessingInput() && (!isset($element['#access']) || $element['#access'])));
|
||||
if ($process_input && !$form_state->getTriggeringElement() && !empty($element['#is_button']) && isset($user_input[$element['#name']]) && isset($element['#values']) && in_array($user_input[$element['#name']], $element['#values'], TRUE)) {
|
||||
if ($process_input && !$form_state->getTriggeringElement() && !empty($element['#is_button']) && isset($user_input[$element['#name']]) && isset($element['#values']) && in_array($user_input[$element['#name']], array_map('strval', $element['#values']), TRUE)) {
|
||||
$form_state->setTriggeringElement($element);
|
||||
}
|
||||
return $element;
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
id: views-ui
|
||||
module: views_ui
|
||||
label: 'View edit page'
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- views_ui
|
||||
id: views-ui
|
||||
label: 'View edit page'
|
||||
module: views_ui
|
||||
routes:
|
||||
- route_name: entity.view.edit_form
|
||||
- route_name: entity.view.edit_display_form
|
||||
-
|
||||
route_name: entity.view.edit_form
|
||||
-
|
||||
route_name: entity.view.edit_display_form
|
||||
tips:
|
||||
views-main:
|
||||
id: views-main
|
||||
|
@ -80,12 +86,9 @@ tips:
|
|||
views-ui-preview:
|
||||
id: views-ui-preview
|
||||
plugin: text
|
||||
label: 'Preview'
|
||||
label: Preview
|
||||
body: 'Show a preview of the view output.'
|
||||
weight: 10
|
||||
location: left
|
||||
attributes:
|
||||
data-id: preview-submit
|
||||
dependencies:
|
||||
module:
|
||||
- views_ui
|
||||
|
|
|
@ -512,6 +512,14 @@ td.group-title {
|
|||
margin-right: 0.2083em;
|
||||
}
|
||||
|
||||
.views-ui-display-tab-setting > span {
|
||||
margin-left: 0.5em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .views-ui-display-tab-setting > span {
|
||||
margin-left: 0;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
/** Applies an overridden(italics) font style to overridden buckets.
|
||||
* The better way to implement this would be to add the overridden class
|
||||
* to the bucket header when the bucket is overridden and style it as a
|
||||
|
@ -552,20 +560,20 @@ td.group-title {
|
|||
|
||||
/* The contents of the popup dialog on the views edit form. */
|
||||
.views-filterable-options .form-type-checkbox {
|
||||
border: 1px solid #ccc;
|
||||
padding: 5px 8px;
|
||||
border-top: none;
|
||||
}
|
||||
.views-filterable-options {
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
.views-filterable-options .filterable-option.odd .form-type-checkbox {
|
||||
background-color: #f3f4ee;
|
||||
}
|
||||
.filterable-option .form-item {
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
.views-filterable-options .filterable-option .title {
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
.views-filterable-options .form-type-checkbox .description {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
|
|
|
@ -291,7 +291,7 @@
|
|||
*/
|
||||
Drupal.viewsUi.AddItemForm.prototype.handleCheck = function (event) {
|
||||
var $target = $(event.target);
|
||||
var label = $.trim($target.next().text());
|
||||
var label = $.trim($target.closest('td').next().html());
|
||||
// Add/remove the checked item to the list.
|
||||
if ($target.is(':checked')) {
|
||||
this.$selected_div.show().css('display', 'block');
|
||||
|
@ -443,11 +443,18 @@
|
|||
*/
|
||||
this.$form = $form;
|
||||
|
||||
/**
|
||||
* Add a keyup handler to the search box.
|
||||
*/
|
||||
this.$searchBox = this.$form.find('[data-drupal-selector="edit-override-controls-options-search"]');
|
||||
this.$searchBox.on('keyup', $.proxy(this.handleKeyup, this));
|
||||
// Click on the title checks the box.
|
||||
this.$form.on('click', 'td.title', function (event) {
|
||||
var $target = $(event.currentTarget);
|
||||
$target.closest('tr').find('input').trigger('click');
|
||||
});
|
||||
|
||||
var searchBoxSelector = '[data-drupal-selector="edit-override-controls-options-search"]';
|
||||
var controlGroupSelector = '[data-drupal-selector="edit-override-controls-group"]';
|
||||
this.$form.on('formUpdated', searchBoxSelector + ',' + controlGroupSelector, $.proxy(this.handleFilter, this));
|
||||
|
||||
this.$searchBox = this.$form.find(searchBoxSelector);
|
||||
this.$controlGroup = this.$form.find(controlGroupSelector);
|
||||
|
||||
/**
|
||||
* Get a list of option labels and their corresponding divs and maintain it
|
||||
|
@ -455,8 +462,6 @@
|
|||
*/
|
||||
this.options = this.getOptions(this.$form.find('.filterable-option'));
|
||||
|
||||
// Restripe on initial loading.
|
||||
this.handleKeyup();
|
||||
// Trap the ENTER key in the search box so that it doesn't submit the form.
|
||||
this.$searchBox.on('keypress', function (event) {
|
||||
if (event.which === 13) {
|
||||
|
@ -486,7 +491,7 @@
|
|||
for (var i = 0; i < length; i++) {
|
||||
$option = $($allOptions[i]);
|
||||
$label = $option.find('label');
|
||||
$description = $option.find('div.description');
|
||||
$description = $option.find('.description');
|
||||
options[i] = {
|
||||
// Search on the lowercase version of the label text + description.
|
||||
searchText: $label.text().toLowerCase() + " " + $description.text().toLowerCase(),
|
||||
|
@ -500,52 +505,41 @@
|
|||
},
|
||||
|
||||
/**
|
||||
* Keyup handler for the search box that hides or shows the relevant
|
||||
* Filter handler for the search box and type select that hides or shows the relevant
|
||||
* options.
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
* The keyup event.
|
||||
* The formUpdated event.
|
||||
*/
|
||||
handleKeyup: function (event) {
|
||||
var found;
|
||||
var option;
|
||||
var zebraClass;
|
||||
|
||||
handleFilter: function (event) {
|
||||
// Determine the user's search query. The search text has been converted
|
||||
// to lowercase.
|
||||
var search = this.$searchBox.val().toLowerCase();
|
||||
var words = search.split(' ');
|
||||
var wordsLength = words.length;
|
||||
|
||||
// Start the counter for restriping rows.
|
||||
var zebraCounter = 0;
|
||||
// Get selected Group
|
||||
var group = this.$controlGroup.val();
|
||||
|
||||
// Search through the search texts in the form for matching text.
|
||||
var length = this.options.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
// Use a local variable for the option being searched, for performance.
|
||||
option = this.options[i];
|
||||
found = true;
|
||||
this.options.forEach(function (option) {
|
||||
function hasWord(word) {
|
||||
return option.searchText.indexOf(word) !== -1;
|
||||
}
|
||||
|
||||
var found = true;
|
||||
// Each word in the search string has to match the item in order for the
|
||||
// item to be shown.
|
||||
for (var j = 0; j < wordsLength; j++) {
|
||||
if (option.searchText.indexOf(words[j]) === -1) {
|
||||
found = false;
|
||||
}
|
||||
if (search) {
|
||||
found = words.every(hasWord);
|
||||
}
|
||||
if (found) {
|
||||
zebraClass = (zebraCounter % 2) ? 'odd' : 'even';
|
||||
// Show the checkbox row, and restripe it.
|
||||
option.$div.removeClass('even odd');
|
||||
option.$div.addClass(zebraClass);
|
||||
option.$div.show();
|
||||
zebraCounter++;
|
||||
if (found && group !== 'all') {
|
||||
found = option.$div.hasClass(group);
|
||||
}
|
||||
else {
|
||||
// The search string wasn't found; hide this item.
|
||||
option.$div.hide();
|
||||
}
|
||||
}
|
||||
|
||||
option.$div.toggle(found);
|
||||
});
|
||||
|
||||
// Adapt dialog to content size.
|
||||
$(event.target).trigger('dialogContentResize');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -601,7 +595,7 @@
|
|||
}
|
||||
var $context = $(context);
|
||||
var $table = $context.find('#views-rearrange-filters').once('views-rearrange-filters');
|
||||
var $operator = $context.find('.form-item-filter-groups-operator').once('views-rearrange-filters');
|
||||
var $operator = $context.find('.js-form-item-filter-groups-operator').once('views-rearrange-filters');
|
||||
if ($table.length) {
|
||||
new Drupal.viewsUi.RearrangeFilterHandler($table, $operator);
|
||||
}
|
||||
|
@ -1004,9 +998,9 @@
|
|||
attach: function (context) {
|
||||
var $context = $(context);
|
||||
|
||||
var $selectAll = $context.find('.form-item-options-value-all').once('filterConfigSelectAll');
|
||||
var $selectAll = $context.find('.js-form-item-options-value-all').once('filterConfigSelectAll');
|
||||
var $selectAllCheckbox = $selectAll.find('input[type=checkbox]');
|
||||
var $checkboxes = $selectAll.closest('.form-checkboxes').find('.js-form-type-checkbox:not(.form-item-options-value-all) input[type="checkbox"]');
|
||||
var $checkboxes = $selectAll.closest('.form-checkboxes').find('.js-form-type-checkbox:not(.js-form-item-options-value-all) input[type="checkbox"]');
|
||||
|
||||
if ($selectAll.length) {
|
||||
// Show the select all checkbox.
|
||||
|
|
|
@ -121,13 +121,15 @@ class ViewsUIController extends ControllerBase {
|
|||
public function reportPlugins() {
|
||||
$rows = Views::pluginList();
|
||||
foreach ($rows as &$row) {
|
||||
$views = [];
|
||||
// Link each view name to the view itself.
|
||||
foreach ($row['views'] as $row_name => $view) {
|
||||
$row['views'][$row_name] = $this->l($view, new Url('entity.view.edit_form', array('view' => $view)));
|
||||
$views[] = $this->l($view, new Url('entity.view.edit_form', array('view' => $view)));
|
||||
}
|
||||
unset($row['views']);
|
||||
$row['views']['data'] = [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $row['views'],
|
||||
'#items' => $views,
|
||||
'#context' => ['list_style' => 'comma-list'],
|
||||
];
|
||||
}
|
||||
|
|
|
@ -107,11 +107,15 @@ class AddHandler extends ViewsFormBase {
|
|||
$form['options']['name'] = array(
|
||||
'#prefix' => '<div class="views-radio-box form-checkboxes views-filterable-options">',
|
||||
'#suffix' => '</div>',
|
||||
'#tree' => TRUE,
|
||||
'#default_value' => 'all',
|
||||
'#type' => 'tableselect',
|
||||
'#header' => array(
|
||||
'title' => $this->t('Title'),
|
||||
'group' => $this->t('Category'),
|
||||
'help' => $this->t('Description'),
|
||||
),
|
||||
'#js_select' => FALSE,
|
||||
);
|
||||
|
||||
// Group options first to simplify the usage of #states.
|
||||
$grouped_options = array();
|
||||
foreach ($options as $key => $option) {
|
||||
$group = preg_replace('/[^a-z0-9]/', '-', strtolower($option['group']));
|
||||
|
@ -137,23 +141,22 @@ class AddHandler extends ViewsFormBase {
|
|||
|
||||
foreach ($grouped_options as $group => $group_options) {
|
||||
foreach ($group_options as $key => $option) {
|
||||
$form['options']['name'][$key] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])),
|
||||
'#description' => $option['help'],
|
||||
'#return_value' => $key,
|
||||
'#prefix' => "<div class='filterable-option'>",
|
||||
'#suffix' => '</div>',
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
array(
|
||||
':input[name="override[controls][group]"]' => array('value' => 'all'),
|
||||
),
|
||||
array(
|
||||
':input[name="override[controls][group]"]' => array('value' => $group),
|
||||
),
|
||||
)
|
||||
)
|
||||
$form['options']['name']['#options'][$key] = array(
|
||||
'#attributes' => array(
|
||||
'class' => array('filterable-option', $group),
|
||||
),
|
||||
'title' => array(
|
||||
'data' => array(
|
||||
'#title' => $option['title'],
|
||||
'#plain_text' => $option['title'],
|
||||
),
|
||||
'class' => array('title'),
|
||||
),
|
||||
'group' => $option['group'],
|
||||
'help' => array(
|
||||
'data' => $option['help'],
|
||||
'class' => array('description'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -162,7 +165,7 @@ class AddHandler extends ViewsFormBase {
|
|||
}
|
||||
else {
|
||||
$form['options']['markup'] = array(
|
||||
'#markup' => '<div class="form-item">' . $this->t('There are no @types available to add.', array('@types' => $ltitle)) . '</div>',
|
||||
'#markup' => '<div class="js-form-item form-item">' . $this->t('There are no @types available to add.', array('@types' => $ltitle)) . '</div>',
|
||||
);
|
||||
}
|
||||
// Add a div to show the selected items
|
||||
|
|
|
@ -44,7 +44,7 @@ class Analyze extends ViewsFormBase {
|
|||
$messages = $analyzer->getMessages($view->getExecutable());
|
||||
|
||||
$form['analysis'] = array(
|
||||
'#prefix' => '<div class="form-item">',
|
||||
'#prefix' => '<div class="js-form-item form-item">',
|
||||
'#suffix' => '</div>',
|
||||
'#markup' => $analyzer->formatMessages($messages),
|
||||
);
|
||||
|
|
|
@ -160,7 +160,7 @@ class ConfigHandler extends ViewsFormBase {
|
|||
$form['options']['form_description'] = array(
|
||||
'#markup' => $handler->definition['help'],
|
||||
'#theme_wrappers' => array('container'),
|
||||
'#attributes' => array('class' => array('form-item description')),
|
||||
'#attributes' => array('class' => array('js-form-item form-item description')),
|
||||
'#weight' => -1000,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -222,8 +222,6 @@ abstract class ViewsFormBase extends FormBase implements ViewsFormInterface {
|
|||
}
|
||||
$output = $renderer->renderRoot($form);
|
||||
|
||||
drupal_process_attached($form);
|
||||
|
||||
// These forms have the title built in, so set the title here:
|
||||
$title = $form_state->get('title') ?: '';
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ class BreakLockForm extends EntityConfirmFormBase {
|
|||
'#theme' => 'username',
|
||||
'#account' => $account,
|
||||
);
|
||||
return $this->t('By breaking this lock, any unsaved changes made by !user will be lost.', array('!user' => drupal_render($username)));
|
||||
return $this->t('By breaking this lock, any unsaved changes made by @user will be lost.', array('@user' => drupal_render($username)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -69,8 +69,8 @@ class AreaEntityUITest extends UITestBase {
|
|||
$this->assertFieldByName('options[target]', $entity_test->id());
|
||||
|
||||
// Replace the header target entities with argument placeholders.
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => '!1'], 'Apply');
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test", ['options[target]' => '!1'], 'Apply');
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => '{{ raw_arguments.null }}'], 'Apply');
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test", ['options[target]' => '{{ raw_arguments.null }}'], 'Apply');
|
||||
$this->drupalPostForm(NULL, [], 'Save');
|
||||
|
||||
// Confirm that the argument placeholders are saved.
|
||||
|
@ -78,15 +78,15 @@ class AreaEntityUITest extends UITestBase {
|
|||
$header = $view->getDisplay('default')['display_options']['header'];
|
||||
$this->assertEqual(['entity_block', 'entity_entity_test'], array_keys($header));
|
||||
|
||||
$this->assertEqual('!1', $header['entity_block']['target']);
|
||||
$this->assertEqual('!1', $header['entity_entity_test']['target']);
|
||||
$this->assertEqual('{{ raw_arguments.null }}', $header['entity_block']['target']);
|
||||
$this->assertEqual('{{ raw_arguments.null }}', $header['entity_entity_test']['target']);
|
||||
|
||||
// Confirm that the argument placeholders are still displayed in the form.
|
||||
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_block");
|
||||
$this->assertFieldByName('options[target]', '!1');
|
||||
$this->assertFieldByName('options[target]', '{{ raw_arguments.null }}');
|
||||
|
||||
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test");
|
||||
$this->assertFieldByName('options[target]', '!1');
|
||||
$this->assertFieldByName('options[target]', '{{ raw_arguments.null }}');
|
||||
|
||||
// Change the targets for both headers back to the entities.
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => $block->id()], 'Apply');
|
||||
|
|
61
core/modules/views_ui/src/Tests/ArgumentValidatorTest.php
Normal file
61
core/modules/views_ui/src/Tests/ArgumentValidatorTest.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views_ui\Tests\ArgumentValidatorTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\views_ui\Tests;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the Argument validator through the UI.
|
||||
*
|
||||
* @group views_ui
|
||||
*/
|
||||
class ArgumentValidatorTest extends UITestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('test_argument');
|
||||
|
||||
/**
|
||||
* Tests the 'Specify validation criteria' checkbox functionality.
|
||||
*/
|
||||
public function testSpecifyValidation() {
|
||||
// Specify a validation based on Node for the 'id' argument on the default
|
||||
// display and assert that this works.
|
||||
$this->saveArgumentHandlerWithValidationOptions(TRUE);
|
||||
$view = Views::getView('test_argument');
|
||||
$handler = $view->getHandler('default', 'argument', 'id');
|
||||
$this->assertTrue($handler['specify_validation'], 'Validation for this argument has been turned on.');
|
||||
$this->assertEqual('entity:node', $handler['validate']['type'], 'Validation for the argument is based on the node.');
|
||||
|
||||
// Uncheck the 'Specify validation criteria' checkbox and expect the
|
||||
// validation type to be reset back to 'none'.
|
||||
$this->saveArgumentHandlerWithValidationOptions(FALSE);
|
||||
$view = Views::getView('test_argument');
|
||||
$handler = $view->getHandler('default', 'argument', 'id');
|
||||
$this->assertFalse($handler['specify_validation'], 'Validation for this argument has been turned off.');
|
||||
$this->assertEqual('none', $handler['validate']['type'], 'Validation for the argument has been reverted to Basic Validation.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the test_argument view with changes made to the argument handler
|
||||
* both with and without specify_validation turned on.
|
||||
*
|
||||
* @param boolean $specify_validation
|
||||
*/
|
||||
protected function saveArgumentHandlerWithValidationOptions($specify_validation) {
|
||||
$options = array(
|
||||
'options[validate][type]' => 'entity---node',
|
||||
'options[specify_validation]' => $specify_validation,
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_argument/default/argument/id', $options, t('Apply'));
|
||||
$this->drupalPostForm('admin/structure/views/view/test_argument', array(), t('Save'));
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\views_ui\Tests;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
|
@ -101,12 +102,85 @@ class CustomBooleanTest extends UITestBase {
|
|||
$view = Views::getView('test_view');
|
||||
$output = $view->preview();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->{$values['test']}(strpos($output, $values['true']), SafeMarkup::format('Expected custom boolean TRUE value %value in output for %type', ['%value' => $values['true'], '%type' => $type]));
|
||||
$this->{$values['test']}(strpos($output, $values['false']), SafeMarkup::format('Expected custom boolean FALSE value %value in output for %type', ['%value' => $values['false'], '%type' => $type]));
|
||||
}
|
||||
}
|
||||
|
||||
$replacements = array('%type' => $type);
|
||||
$this->{$values['test']}(strpos($output, $values['true']), format_string('Expected custom boolean TRUE value in output for %type.', $replacements));
|
||||
$this->{$values['test']}(strpos($output, $values['false']), format_string('Expected custom boolean FALSE value in output for %type', $replacements));
|
||||
/**
|
||||
* Tests the setting and output of custom labels for boolean values.
|
||||
*/
|
||||
public function testCustomOptionTemplate() {
|
||||
// Install theme to test with template system.
|
||||
\Drupal::service('theme_handler')->install(['views_test_theme']);
|
||||
|
||||
// Set the default theme for Views preview.
|
||||
$this->config('system.theme')
|
||||
->set('default', 'views_test_theme')
|
||||
->save();
|
||||
$this->assertEqual($this->config('system.theme')->get('default'), 'views_test_theme');
|
||||
|
||||
// Add the boolean field handler to the test view.
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
|
||||
$view->displayHandlers->get('default')->overrideOption('fields', [
|
||||
'age' => [
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
'plugin_id' => 'boolean',
|
||||
],
|
||||
]);
|
||||
$view->save();
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
$custom_true = 'Yay';
|
||||
$custom_false = 'Nay';
|
||||
|
||||
// Set up some custom value mappings for different types.
|
||||
$custom_values = array(
|
||||
'plain' => array(
|
||||
'true' => $custom_true,
|
||||
'false' => $custom_false,
|
||||
'test' => 'assertTrue',
|
||||
),
|
||||
'allowed tag' => array(
|
||||
'true' => '<p>' . $custom_true . '</p>',
|
||||
'false' => '<p>' . $custom_false . '</p>',
|
||||
'test' => 'assertTrue',
|
||||
),
|
||||
'disallowed tag' => array(
|
||||
'true' => '<script>' . $custom_true . '</script>',
|
||||
'false' => '<script>' . $custom_false . '</script>',
|
||||
'test' => 'assertFalse',
|
||||
),
|
||||
);
|
||||
|
||||
// Run the same tests on each type.
|
||||
foreach ($custom_values as $type => $values) {
|
||||
$options = array(
|
||||
'options[type]' => 'custom',
|
||||
'options[type_custom_true]' => $values['true'],
|
||||
'options[type_custom_false]' => $values['false'],
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_view/default/field/age', $options, 'Apply');
|
||||
|
||||
// Save the view.
|
||||
$this->drupalPostForm('admin/structure/views/view/test_view', array(), 'Save');
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
$output = $view->preview();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->{$values['test']}(strpos($output, $values['true']), SafeMarkup::format('Expected custom boolean TRUE value %value in output for %type', ['%value' => $values['true'], '%type' => $type]));
|
||||
$this->{$values['test']}(strpos($output, $values['false']), SafeMarkup::format('Expected custom boolean FALSE value %value in output for %type', ['%value' => $values['false'], '%type' => $type]));
|
||||
|
||||
// Assert that we are using the correct template.
|
||||
$this->setRawContent($output);
|
||||
$this->assertText('llama', 'Loaded the correct views-view-field.html.twig template');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,13 @@ class DefaultViewsTest extends UITestBase {
|
|||
*/
|
||||
public static $testViews = array('test_view_status', 'test_page_display_menu', 'test_page_display_arguments');
|
||||
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests default views.
|
||||
*/
|
||||
|
|
|
@ -33,6 +33,8 @@ class DisplayAttachmentTest extends UITestBase {
|
|||
|
||||
$attachment_display_url = 'admin/structure/views/nojs/display/test_attachment_ui/attachment_1/displays';
|
||||
$this->drupalGet($attachment_display_url);
|
||||
// Display labels should be escaped.
|
||||
$this->assertEscaped('<em>Page</em>');
|
||||
|
||||
foreach (array('default', 'page-1') as $display_id) {
|
||||
$this->assertNoFieldChecked("edit-displays-$display_id", format_string('Make sure the @display_id can be marked as attached', array('@display_id' => $display_id)));
|
||||
|
@ -40,6 +42,9 @@ class DisplayAttachmentTest extends UITestBase {
|
|||
|
||||
// Save the attachments and test the value on the view.
|
||||
$this->drupalPostForm($attachment_display_url, array('displays[page_1]' => 1), t('Apply'));
|
||||
// Options summary should be escaped.
|
||||
$this->assertEscaped('<em>Page</em>');
|
||||
$this->assertNoRaw('<em>Page</em>');
|
||||
$result = $this->xpath('//a[@id = :id]', array(':id' => 'views-attachment-1-displays'));
|
||||
$this->assertEqual($result[0]->attributes()->title, t('Page'));
|
||||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
|
|
|
@ -55,6 +55,8 @@ class DisplayFeedTest extends UITestBase {
|
|||
|
||||
// Check the attach TO interface.
|
||||
$this->drupalGet('admin/structure/views/nojs/display/' . $view_name . '/feed_1/displays');
|
||||
// Display labels should be escaped.
|
||||
$this->assertEscaped('<em>Page</em>');
|
||||
|
||||
// Load all the options of the checkbox.
|
||||
$result = $this->xpath('//div[@id="edit-displays"]/div');
|
||||
|
@ -71,8 +73,12 @@ class DisplayFeedTest extends UITestBase {
|
|||
|
||||
// Post and save this and check the output.
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/' . $view_name . '/feed_1/displays', array('displays[page]' => 'page'), t('Apply'));
|
||||
// Options summary should be escaped.
|
||||
$this->assertEscaped('<em>Page</em>');
|
||||
$this->assertNoRaw('<em>Page</em>');
|
||||
|
||||
$this->drupalGet('admin/structure/views/view/' . $view_name . '/edit/feed_1');
|
||||
$this->assertFieldByXpath('//*[@id="views-feed-1-displays"]', 'Page');
|
||||
$this->assertFieldByXpath('//*[@id="views-feed-1-displays"]', '<em>Page</em>');
|
||||
|
||||
// Add the default display, so there should now be multiple displays.
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/' . $view_name . '/feed_1/displays', array('displays[default]' => 'default'), t('Apply'));
|
||||
|
|
|
@ -17,6 +17,12 @@ use Drupal\menu_link_content\Entity\MenuLinkContent;
|
|||
*/
|
||||
class DisplayPathTest extends UITestBase {
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -57,7 +63,10 @@ class DisplayPathTest extends UITestBase {
|
|||
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/page_1/path', array('path' => $random_path), t('Apply'));
|
||||
$this->assertText('/' . $random_path, 'The custom path appears in the summary.');
|
||||
$this->assertLink(t('View @display', array('@display' => 'Page')), 0, 'view page link found on the page.');
|
||||
$display_link_text = t('View @display', ['@display' => 'Page']);
|
||||
$this->assertLink($display_link_text, 0, 'view page link found on the page.');
|
||||
$this->clickLink($display_link_text);
|
||||
$this->assertUrl($random_path);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,9 +9,9 @@ namespace Drupal\views_ui\Tests;
|
|||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
|
||||
use Drupal\views\Views;
|
||||
use Drupal\Core\Template\Attribute;
|
||||
use Drupal\views\Entity\View;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the display UI.
|
||||
|
@ -34,6 +34,26 @@ class DisplayTest extends UITestBase {
|
|||
*/
|
||||
public static $modules = array('contextual');
|
||||
|
||||
/**
|
||||
* Tests adding a display.
|
||||
*/
|
||||
public function testAddDisplay() {
|
||||
$view = $this->randomView();
|
||||
$this->assertNoText('Block');
|
||||
$this->assertNoText('Block 2');
|
||||
|
||||
$this->drupalPostForm(NULL, [], t('Add @display', ['@display' => 'Block']));
|
||||
$this->assertText('Block');
|
||||
$this->assertNoText('Block 2');
|
||||
|
||||
// Views has special form handling in views_ui_form_button_was_clicked()
|
||||
// to be able to change the submit button text via JS, this simulates what
|
||||
// the JS is doing.
|
||||
$this->drupalPostForm(NULL, [], NULL, [], [], NULL, '&op=Block');
|
||||
$this->assertText('Block');
|
||||
$this->assertText('Block 2');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests reordering of displays.
|
||||
*/
|
||||
|
@ -180,6 +200,8 @@ class DisplayTest extends UITestBase {
|
|||
$view->enable()->save();
|
||||
$this->container->get('router.builder')->rebuildIfNeeded();
|
||||
|
||||
// When no "main content" block is placed, we find a contextual link
|
||||
// placeholder for editing just the view.
|
||||
$this->drupalGet('test-display');
|
||||
$id = 'entity.view.edit_form:view=test_display:location=page&name=test_display&display_id=page_1&langcode=en';
|
||||
// @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder()
|
||||
|
@ -192,6 +214,15 @@ class DisplayTest extends UITestBase {
|
|||
$this->assertResponse(200);
|
||||
$json = Json::decode($response);
|
||||
$this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="entityviewedit-form"><a href="' . base_path() . 'admin/structure/views/view/test_display/edit/page_1">Edit view</a></li></ul>');
|
||||
|
||||
// When a "main content" is placed, we still find a contextual link
|
||||
// placeholder for editing just the view (not the main content block).
|
||||
// @see system_block_view_system_main_block_alter()
|
||||
$this->drupalPlaceBlock('system_main_block', ['id' => 'main_content']);
|
||||
$this->drupalGet('test-display');
|
||||
$id = 'entity.view.edit_form:view=test_display:location=page&name=test_display&display_id=page_1&langcode=en';
|
||||
// @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder()
|
||||
$this->assertRaw('<div' . new Attribute(array('data-contextual-id' => $id)) . '></div>', format_string('Contextual link placeholder with id @id exists.', array('@id' => $id)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,6 +245,35 @@ class DisplayTest extends UITestBase {
|
|||
$this->assertTrue($elements, 'The disabled class was found on the form wrapper.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that no XSS is possible for buttons.
|
||||
*/
|
||||
public function testDisplayTitleInButtonsXss() {
|
||||
$xss_markup = '"><script>alert(123)</script>';
|
||||
$view = $this->randomView();
|
||||
$view = View::load($view['id']);
|
||||
\Drupal::configFactory()->getEditable('views.settings')->set('ui.show.master_display', TRUE)->save();
|
||||
|
||||
foreach ([$xss_markup, '"><script>alert(123)</script>'] as $input) {
|
||||
$display =& $view->getDisplay('page_1');
|
||||
$display['display_title'] = $input;
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet("admin/structure/views/view/{$view->id()}");
|
||||
$escaped = views_ui_truncate($input, 25);
|
||||
$this->assertEscaped($escaped);
|
||||
$this->assertNoRaw($xss_markup);
|
||||
|
||||
$this->drupalGet("admin/structure/views/view/{$view->id()}/edit/page_1");
|
||||
$this->assertEscaped("View $escaped");
|
||||
$this->assertNoRaw("View $xss_markup");
|
||||
$this->assertEscaped("Duplicate $escaped");
|
||||
$this->assertNoRaw("Duplicate $xss_markup");
|
||||
$this->assertEscaped("Delete $escaped");
|
||||
$this->assertNoRaw("Delete $xss_markup");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the action links on the edit display UI.
|
||||
*/
|
||||
|
@ -225,16 +285,24 @@ class DisplayTest extends UITestBase {
|
|||
$display_title_path = 'admin/structure/views/nojs/display/test_display/block_1/display_title';
|
||||
$this->drupalPostForm($display_title_path, array('display_title' => $display_title), t('Apply'));
|
||||
|
||||
$placeholder = array('!display_title' => $display_title);
|
||||
// Ensure that the title is escaped as expected.
|
||||
$this->assertEscaped($display_title);
|
||||
$this->assertNoRaw($display_title);
|
||||
|
||||
// Ensure that the dropdown buttons are displayed correctly.
|
||||
$this->assertFieldByXpath('//input[@type="submit"]', t('Duplicate !display_title', $placeholder));
|
||||
$this->assertFieldByXpath('//input[@type="submit"]', t('Delete !display_title', $placeholder));
|
||||
$this->assertFieldByXpath('//input[@type="submit"]', t('Disable !display_title', $placeholder));
|
||||
$this->assertNoFieldByXpath('//input[@type="submit"]', t('Enable !display_title', $placeholder));
|
||||
$this->assertFieldByXpath('//input[@type="submit"]', 'Duplicate ' . $display_title);
|
||||
$this->assertFieldByXpath('//input[@type="submit"]', 'Delete ' . $display_title);
|
||||
$this->assertFieldByXpath('//input[@type="submit"]', 'Disable ' . $display_title);
|
||||
$this->assertNoFieldByXpath('//input[@type="submit"]', 'Enable ' . $display_title);
|
||||
|
||||
// Disable the display so we can test the rendering of the "Enable" button.
|
||||
$this->drupalPostForm(NULL, NULL, t('Disable !display_title', $placeholder));
|
||||
$this->assertFieldByXpath('//input[@type="submit"]', t('Enable !display_title', $placeholder));
|
||||
$this->assertNoFieldByXpath('//input[@type="submit"]', t('Disable !display_title', $placeholder));
|
||||
$this->drupalPostForm(NULL, NULL, 'Disable ' . $display_title);
|
||||
$this->assertFieldByXpath('//input[@type="submit"]', 'Enable ' . $display_title);
|
||||
$this->assertNoFieldByXpath('//input[@type="submit"]', 'Disable ' . $display_title);
|
||||
|
||||
// Ensure that the title is escaped as expected.
|
||||
$this->assertEscaped($display_title);
|
||||
$this->assertNoRaw($display_title);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,12 @@ namespace Drupal\views_ui\Tests;
|
|||
*/
|
||||
class DuplicateTest extends UITestBase {
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if duplicated view exists and has correct label.
|
||||
*/
|
||||
|
|
|
@ -42,21 +42,24 @@ class FieldUITest extends UITestBase {
|
|||
// Ensure that the expected tokens appear in the UI.
|
||||
$edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/age';
|
||||
$this->drupalGet($edit_handler_url);
|
||||
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
|
||||
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/ul/li');
|
||||
$this->assertEqual((string) $result[0], '{{ age }} == Age');
|
||||
|
||||
$edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/id';
|
||||
$this->drupalGet($edit_handler_url);
|
||||
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
|
||||
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/ul/li');
|
||||
$this->assertEqual((string) $result[0], '{{ age }} == Age');
|
||||
$this->assertEqual((string) $result[1], '{{ id }} == ID');
|
||||
|
||||
$edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/name';
|
||||
$this->drupalGet($edit_handler_url);
|
||||
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
|
||||
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/ul/li');
|
||||
$this->assertEqual((string) $result[0], '{{ age }} == Age');
|
||||
$this->assertEqual((string) $result[1], '{{ id }} == ID');
|
||||
$this->assertEqual((string) $result[2], '{{ name }} == Name');
|
||||
|
||||
$result = $this->xpath('//details[@id="edit-options-more"]');
|
||||
$this->assertEqual(empty($result), true, "Container 'more' is empty and should not be displayed.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
namespace Drupal\views_ui\Tests;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
|
@ -23,7 +25,16 @@ class HandlerTest extends UITestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('test_view_empty', 'test_view_broken');
|
||||
public static $testViews = array('test_view_empty', 'test_view_broken', 'node');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Tests\ViewTestBase::schemaDefinition().
|
||||
|
@ -137,6 +148,40 @@ class HandlerTest extends UITestBase {
|
|||
$this->assertTrue(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was added to the view itself.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests escaping of field labels in help text.
|
||||
*/
|
||||
public function testHandlerHelpEscaping() {
|
||||
// Setup a field with two instances using a different label.
|
||||
// Ensure that the label is escaped properly.
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => 'field_test',
|
||||
'entity_type' => 'node',
|
||||
'type' => 'string',
|
||||
])->save();
|
||||
|
||||
FieldConfig::create([
|
||||
'field_name' => 'field_test',
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
'label' => 'The giraffe" label'
|
||||
])->save();
|
||||
|
||||
FieldConfig::create([
|
||||
'field_name' => 'field_test',
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'article',
|
||||
'label' => 'The <em>giraffe"</em> label <script>alert("the return of the xss")</script>'
|
||||
])->save();
|
||||
|
||||
$this->drupalGet('admin/structure/views/nojs/add-handler/content/default/field');
|
||||
$this->assertEscaped('Appears in: page, article. Also known as: Content: The <em>giraffe"</em> label <script>alert("the return of the xss")</script>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests broken handlers.
|
||||
*/
|
||||
|
@ -155,7 +200,7 @@ class HandlerTest extends UITestBase {
|
|||
$this->assertIdentical((string) $result[0], $text, 'Ensure the broken handler text was found.');
|
||||
|
||||
$this->drupalGet($href);
|
||||
$result = $this->xpath('//h1');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertTrue(strpos((string) $result[0], $text) !== FALSE, 'Ensure the broken handler text was found.');
|
||||
|
||||
$original_configuration = [
|
||||
|
|
|
@ -14,6 +14,12 @@ namespace Drupal\views_ui\Tests;
|
|||
*/
|
||||
class OverrideDisplaysTest extends UITestBase {
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that displays can be overridden via the UI.
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\views_ui\Tests;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityViewMode;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
|
@ -87,6 +88,13 @@ class RowUITest extends UITestBase {
|
|||
$this->drupalPostForm(NULL, ['row[type]' => 'entity:node'], t('Apply'));
|
||||
$this->assertUrl($row_options_url);
|
||||
$this->assertFieldByName('row_options[view_mode]', 'teaser');
|
||||
|
||||
// Change the teaser label to have markup so we can test escaping.
|
||||
$teaser = EntityViewMode::load('node.teaser');
|
||||
$teaser->set('label', 'Teaser <em>markup</em>');
|
||||
$teaser->save();
|
||||
$this->drupalGet('admin/structure/views/view/frontpage/edit/default');
|
||||
$this->assertEscaped('Teaser <em>markup</em>');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,13 +45,18 @@ class ViewEditTest extends UITestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests the machine name form.
|
||||
* Tests the machine name and administrative comment forms.
|
||||
*/
|
||||
public function testMachineNameOption() {
|
||||
public function testOtherOptions() {
|
||||
$this->drupalGet('admin/structure/views/view/test_view');
|
||||
// Add a new attachment display.
|
||||
$this->drupalPostForm(NULL, array(), 'Add Attachment');
|
||||
|
||||
// Test that a long administrative comment is truncated.
|
||||
$edit = array('display_comment' => 'one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen');
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/attachment_1/display_comment', $edit, 'Apply');
|
||||
$this->assertText('one two three four five six seven eight nine ten eleven twelve thirteen fourteen...');
|
||||
|
||||
// Change the machine name for the display from page_1 to test_1.
|
||||
$edit = array('display_id' => 'test_1');
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/attachment_1/display_id', $edit, 'Apply');
|
||||
|
@ -105,7 +110,7 @@ class ViewEditTest extends UITestBase {
|
|||
$this->assertResponse(200);
|
||||
$langcode_url = 'admin/structure/views/nojs/display/' . $view_name . '/' . $display . '/rendering_language';
|
||||
$this->assertNoLinkByHref($langcode_url);
|
||||
$this->assertNoLink(t('!type language selected for page', array('!type' => t('Content'))));
|
||||
$this->assertNoLink(t('@type language selected for page', array('@type' => t('Content'))));
|
||||
$this->assertNoLink(t('Content language of view row'));
|
||||
}
|
||||
|
||||
|
@ -122,12 +127,12 @@ class ViewEditTest extends UITestBase {
|
|||
$langcode_url = 'admin/structure/views/nojs/display/' . $view_name . '/' . $display . '/rendering_language';
|
||||
if ($view_name == 'test_view') {
|
||||
$this->assertNoLinkByHref($langcode_url);
|
||||
$this->assertNoLink(t('!type language selected for page', array('!type' => t('Content'))));
|
||||
$this->assertNoLink(t('@type language selected for page', array('@type' => t('Content'))));
|
||||
$this->assertNoLink(t('Content language of view row'));
|
||||
}
|
||||
else {
|
||||
$this->assertLinkByHref($langcode_url);
|
||||
$this->assertNoLink(t('!type language selected for page', array('!type' => t('Content'))));
|
||||
$this->assertNoLink(t('@type language selected for page', array('@type' => t('Content'))));
|
||||
$this->assertLink(t('Content language of view row'));
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,22 @@ class XssTest extends UITestBase {
|
|||
$this->assertEscaped('<marquee>test</marquee>', 'Field admin label is properly escaped.');
|
||||
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/sa_contrib_2013_035/page_1/header/area');
|
||||
$this->assertRaw('[title] == &lt;marquee&gt;test&lt;/marquee&gt;', 'Token label is properly escaped.');
|
||||
$this->assertRaw('[title_1] == &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;', 'Token label is properly escaped.');
|
||||
$this->assertEscaped('{{ title }} == <marquee>test</marquee>', 'Token label is properly escaped.');
|
||||
$this->assertEscaped('{{ title_1 }} == <script>alert("XSS")</script>', 'Token label is properly escaped.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the admin UI for double escaping.
|
||||
*/
|
||||
public function testNoDoubleEscaping() {
|
||||
$this->drupalGet('admin/structure/views');
|
||||
$this->assertNoEscaped('<');
|
||||
|
||||
$this->drupalGet('admin/structure/views/view/sa_contrib_2013_035');
|
||||
$this->assertNoEscaped('<');
|
||||
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/sa_contrib_2013_035/page_1/header/area');
|
||||
$this->assertNoEscaped('<');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,23 +8,20 @@
|
|||
namespace Drupal\views_ui;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\HtmlCommand;
|
||||
use Drupal\Core\Ajax\ReplaceCommand;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Datetime\DateFormatterInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\ElementInfoManagerInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Drupal\views\Views;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* Form controller for the Views edit form.
|
||||
|
@ -48,7 +45,7 @@ class ViewEditForm extends ViewFormBase {
|
|||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
* @var \Drupal\Core\Datetime\DateFormatterInterface
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
|
@ -66,12 +63,12 @@ class ViewEditForm extends ViewFormBase {
|
|||
* The factory for the temp store object.
|
||||
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
|
||||
* The request stack object.
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
|
||||
* The date Formatter service.
|
||||
* @param \Drupal\Core\Render\ElementInfoManagerInterface $element_info
|
||||
* The element info manager.
|
||||
*/
|
||||
public function __construct(SharedTempStoreFactory $temp_store_factory, RequestStack $requestStack, DateFormatter $date_formatter, ElementInfoManagerInterface $element_info) {
|
||||
public function __construct(SharedTempStoreFactory $temp_store_factory, RequestStack $requestStack, DateFormatterInterface $date_formatter, ElementInfoManagerInterface $element_info) {
|
||||
$this->tempStore = $temp_store_factory->get('views');
|
||||
$this->requestStack = $requestStack;
|
||||
$this->dateFormatter = $date_formatter;
|
||||
|
@ -139,14 +136,14 @@ class ViewEditForm extends ViewFormBase {
|
|||
'#account' => $this->entityManager->getStorage('user')->load($view->lock->owner),
|
||||
);
|
||||
$lock_message_substitutions = array(
|
||||
'!user' => drupal_render($username),
|
||||
'!age' => $this->dateFormatter->formatTimeDiffSince($view->lock->updated),
|
||||
'@url' => $view->url('break-lock-form'),
|
||||
'@user' => drupal_render($username),
|
||||
'@age' => $this->dateFormatter->formatTimeDiffSince($view->lock->updated),
|
||||
':url' => $view->url('break-lock-form'),
|
||||
);
|
||||
$form['locked'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array('class' => array('view-locked', 'messages', 'messages--warning')),
|
||||
'#children' => $this->t('This view is being edited by user !user, and is therefore locked from editing by others. This lock is !age old. Click here to <a href="@url">break this lock</a>.', $lock_message_substitutions),
|
||||
'#children' => $this->t('This view is being edited by user @user, and is therefore locked from editing by others. This lock is @age old. Click here to <a href=":url">break this lock</a>.', $lock_message_substitutions),
|
||||
'#weight' => -10,
|
||||
);
|
||||
}
|
||||
|
@ -402,7 +399,7 @@ class ViewEditForm extends ViewFormBase {
|
|||
if (!$is_enabled) {
|
||||
$build['top']['actions']['enable'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Enable !display_title', array('!display_title' => $display_title)),
|
||||
'#value' => $this->t('Enable @display_title', ['@display_title' => $display_title]),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#submit' => array('::submitDisplayEnable', '::submitDelayDestination'),
|
||||
'#prefix' => '<li class="enable">',
|
||||
|
@ -414,18 +411,17 @@ class ViewEditForm extends ViewFormBase {
|
|||
elseif ($view->status() && $view->getExecutable()->displayHandlers->get($display['id'])->hasPath()) {
|
||||
$path = $view->getExecutable()->displayHandlers->get($display['id'])->getPath();
|
||||
if ($path && (strpos($path, '%') === FALSE)) {
|
||||
$uri = "base:$path";
|
||||
if (!parse_url($path, PHP_URL_SCHEME)) {
|
||||
// @todo Views should expect and store a leading /. See:
|
||||
// https://www.drupal.org/node/2423913
|
||||
$url = Url::fromUserInput('/' . ltrim($uri, '/'));
|
||||
$url = Url::fromUserInput('/' . ltrim($path, '/'));
|
||||
}
|
||||
else {
|
||||
$url = Url::fromUri($uri);
|
||||
$url = Url::fromUri("base:$path");
|
||||
}
|
||||
$build['top']['actions']['path'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('View !display_title', array('!display_title' => $display_title)),
|
||||
'#title' => $this->t('View @display_title', ['@display_title' => $display_title]),
|
||||
'#options' => array('alt' => array($this->t("Go to the real page for this display"))),
|
||||
'#url' => $url,
|
||||
'#prefix' => '<li class="view">',
|
||||
|
@ -436,7 +432,7 @@ class ViewEditForm extends ViewFormBase {
|
|||
if (!$is_default) {
|
||||
$build['top']['actions']['duplicate'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Duplicate !display_title', array('!display_title' => $display_title)),
|
||||
'#value' => $this->t('Duplicate @display_title', ['@display_title' => $display_title]),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#submit' => array('::submitDisplayDuplicate', '::submitDelayDestination'),
|
||||
'#prefix' => '<li class="duplicate">',
|
||||
|
@ -446,7 +442,7 @@ class ViewEditForm extends ViewFormBase {
|
|||
// Always allow a display to be deleted.
|
||||
$build['top']['actions']['delete'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Delete !display_title', array('!display_title' => $display_title)),
|
||||
'#value' => $this->t('Delete @display_title', ['@display_title' => $display_title]),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#submit' => array('::submitDisplayDelete', '::submitDelayDestination'),
|
||||
'#prefix' => '<li class="delete">',
|
||||
|
@ -460,7 +456,7 @@ class ViewEditForm extends ViewFormBase {
|
|||
|
||||
$build['top']['actions']['duplicate_as'][$type] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Duplicate as !type', array('!type' => $label)),
|
||||
'#value' => $this->t('Duplicate as @type', ['@type' => $label]),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#submit' => array('::submitDuplicateDisplayAsType', '::submitDelayDestination'),
|
||||
'#prefix' => '<li class="duplicate">',
|
||||
|
@ -471,7 +467,7 @@ class ViewEditForm extends ViewFormBase {
|
|||
else {
|
||||
$build['top']['actions']['undo_delete'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Undo delete of !display_title', array('!display_title' => $display_title)),
|
||||
'#value' => $this->t('Undo delete of @display_title', ['@display_title' => $display_title]),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#submit' => array('::submitDisplayUndoDelete', '::submitDelayDestination'),
|
||||
'#prefix' => '<li class="undo-delete">',
|
||||
|
@ -481,7 +477,7 @@ class ViewEditForm extends ViewFormBase {
|
|||
if ($is_enabled) {
|
||||
$build['top']['actions']['disable'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Disable !display_title', array('!display_title' => $display_title)),
|
||||
'#value' => $this->t('Disable @display_title', ['@display_title' => $display_title]),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#submit' => array('::submitDisplayDisable', '::submitDelayDestination'),
|
||||
'#prefix' => '<li class="disable">',
|
||||
|
@ -753,14 +749,14 @@ class ViewEditForm extends ViewFormBase {
|
|||
foreach (Views::fetchPluginNames('display', NULL, array($view->get('base_table'))) as $type => $label) {
|
||||
$element['add_display'][$type] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Add !display', array('!display' => $label)),
|
||||
'#value' => $this->t('Add @display', array('@display' => $label)),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#submit' => array('::submitDisplayAdd', '::submitDelayDestination'),
|
||||
'#attributes' => array('class' => array('add-display')),
|
||||
// Allow JavaScript to remove the 'Add ' prefix from the button label when
|
||||
// placing the button in a "Add" dropdown menu.
|
||||
'#process' => array_merge(array('views_ui_form_button_was_clicked'), $this->elementInfo->getInfoProperty('submit', '#process', array())),
|
||||
'#values' => array($this->t('Add !display', array('!display' => $label)), $label),
|
||||
'#values' => array($this->t('Add @display', array('@display' => $label)), $label),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1131,12 +1127,8 @@ class ViewEditForm extends ViewFormBase {
|
|||
$last = end($keys);
|
||||
foreach ($contents as $key => $pid) {
|
||||
if ($key != $last) {
|
||||
if ($group_info['groups'][$gid] == 'OR') {
|
||||
$store[$pid]['#link'] = $this->t('!link OR', ['!link' => $store[$pid]['#link']]);
|
||||
}
|
||||
else {
|
||||
$store[$pid]['#link'] = $this->t('!link AND', ['!link' => $store[$pid]['#link']]);
|
||||
}
|
||||
$operator = $group_info['groups'][$gid] == 'OR' ? $this->t('OR') : $this->t('AND');
|
||||
$store[$pid]['#link'] = SafeMarkup::format('@link <span>@operator</span>', ['@link' => $store[$pid]['#link'], '@operator' => $operator]);
|
||||
}
|
||||
$build['fields'][$pid] = $store[$pid];
|
||||
}
|
||||
|
|
|
@ -246,7 +246,7 @@ class ViewListBuilder extends ConfigEntityListBuilder {
|
|||
$definition = $this->displayManager->getDefinition($display['display_plugin']);
|
||||
if (!empty($definition['admin'])) {
|
||||
// Cast the admin label to a string since it is an object.
|
||||
// @see \Drupal\Core\StringTranslation\TranslationWrapper
|
||||
// @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
$displays[] = (string) $definition['admin'];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1206,6 +1206,8 @@ class ViewUI implements ViewEntityInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
$this->storage->calculateDependencies();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ views_ui.admin:
|
|||
- core/drupalSettings
|
||||
- core/jquery.once
|
||||
- core/jquery.form
|
||||
- core/drupal.form
|
||||
- core/drupal.ajax
|
||||
- core/drupal.dropbutton
|
||||
- views/views.ajax
|
||||
|
|
|
@ -20,17 +20,15 @@ function views_ui_help($route_name, RouteMatchInterface $route_match) {
|
|||
case 'help.page.views_ui':
|
||||
$output = '';
|
||||
$output .= '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('The Views UI module provides an interface for managing views for the <a href="@views">Views module</a>. For more information, see the <a href="@handbook">online documentation for the Views UI module</a>.', array('@views' => \Drupal::url('help.page', array('name' => 'views')), '@handbook' => 'https://www.drupal.org/documentation/modules/views_ui')) . '</p>';
|
||||
$output .= '<p>' . t('The Views UI module provides an interface for managing views for the <a href=":views">Views module</a>. For more information, see the <a href=":handbook">online documentation for the Views UI module</a>.', array(':views' => \Drupal::url('help.page', array('name' => 'views')), ':handbook' => 'https://www.drupal.org/documentation/modules/views_ui')) . '</p>';
|
||||
$output .= '<h3>' . t('Uses') . '</h3>';
|
||||
$output .= '<dl>';
|
||||
$output .= '<dt>' . t('Creating and managing views.') . '</dt>';
|
||||
$output .= '<dd>' . t('Views can be created from the <a href="@list">Views list page</a> by using the "Add new view" action. Existing views can be managed from the <a href="@list">Views list page</a> by locating the view in the "Enabled" or "Disabled" list and selecting the desired operation action, for example "Edit".', array('@list' => \Drupal::url('entity.view.collection', array('name' => 'views_ui')))) . '</dd>';
|
||||
$output .= '<dt>' . t('Enabling and disabling views.') . '<dt>';
|
||||
$output .= '<dd>' . t('Views can be enabled or disabled from the <a href="@list">Views list page</a>. To enable a view, find the view within the "Disabled" list and select the "Enable" operation. To disable a view find the view within the "Enabled" list and select the "Disable" operation.', array('@list' => \Drupal::url('entity.view.collection', array('name' => 'views_ui')))) . '</dd>';
|
||||
$output .= '<dt>' . t('Exporting and importing views.') . '</dt>';
|
||||
$output .= '<dd>' . t('Views can be exported and imported as configuration files by using the <a href="@config">Configuration Manager module</a>.', array('@config' => (\Drupal::moduleHandler()->moduleExists('config')) ? \Drupal::url('help.page', array('name' => 'config')) : '#')) . '</dd>';
|
||||
$output .= '<dt>' . t('Theming views.') . '</dt>';
|
||||
$output .= '<dd>' . t('The template files used by views can be overridden from a custom theme. When editing a view, you can see the templates that are used and alternatives for overriding them by clicking on the "Templates" link, found in the Advanced > Other section under "Output".') . '</dd>';
|
||||
$output .= '<dt>' . t('Creating and managing views') . '</dt>';
|
||||
$output .= '<dd>' . t('Views can be created from the <a href=":list">Views list page</a> by using the "Add new view" action. Existing views can be managed from the <a href=":list">Views list page</a> by locating the view in the "Enabled" or "Disabled" list and selecting the desired operation action, for example "Edit".', array(':list' => \Drupal::url('entity.view.collection', array('name' => 'views_ui')))) . '</dd>';
|
||||
$output .= '<dt>' . t('Enabling and disabling views') . '<dt>';
|
||||
$output .= '<dd>' . t('Views can be enabled or disabled from the <a href=":list">Views list page</a>. To enable a view, find the view within the "Disabled" list and select the "Enable" operation. To disable a view find the view within the "Enabled" list and select the "Disable" operation.', array(':list' => \Drupal::url('entity.view.collection', array('name' => 'views_ui')))) . '</dd>';
|
||||
$output .= '<dt>' . t('Exporting and importing views') . '</dt>';
|
||||
$output .= '<dd>' . t('Views can be exported and imported as configuration files by using the <a href=":config">Configuration Manager module</a>.', array(':config' => (\Drupal::moduleHandler()->moduleExists('config')) ? \Drupal::url('help.page', array('name' => 'config')) : '#')) . '</dd>';
|
||||
$output .= '</dl>';
|
||||
return $output;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ views_ui.settings_basic:
|
|||
path: '/admin/structure/views/settings'
|
||||
defaults:
|
||||
_form: '\Drupal\views_ui\Form\BasicSettingsForm'
|
||||
_title: 'Settings'
|
||||
_title: 'Views settings'
|
||||
requirements:
|
||||
_permission: 'administer views'
|
||||
|
||||
|
@ -26,7 +26,7 @@ views_ui.settings_advanced:
|
|||
path: '/admin/structure/views/settings/advanced'
|
||||
defaults:
|
||||
_form: '\Drupal\views_ui\Form\AdvancedSettingsForm'
|
||||
_title: 'Advanced'
|
||||
_title: 'Advanced Views settings'
|
||||
requirements:
|
||||
_permission: 'administer views'
|
||||
|
||||
|
|
Reference in a new issue