Commit 3a9a3125 authored by Dries's avatar Dries

Merge branch '8.x' of git.drupal.org:project/drupal into 8.x

parents 055716fe 3aa3e5d1
......@@ -7025,6 +7025,9 @@ function drupal_common_theme() {
'number' => array(
'render element' => 'element',
),
'range' => array(
'render element' => 'element',
),
'form' => array(
'render element' => 'element',
),
......
......@@ -606,7 +606,7 @@ function file_load_multiple($fids = array(), $conditions = array()) {
* A file ID.
*
* @return
* A file object.
* An object representing the file, or FALSE if the file was not found.
*
* @see hook_file_load()
* @see file_load_multiple()
......
......@@ -3968,6 +3968,29 @@ function theme_number($variables) {
return $output;
}
/**
* Returns HTML for a range form element.
*
* @param $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
* Properties used: #title, #value, #description, #size, #min, #max,
* #required, #attributes, #step.
*
* @ingroup themeable
*/
function theme_range($variables) {
$element = $variables['element'];
$element['#attributes']['type'] = 'range';
element_set_attributes($element, array('id', 'name', 'value', 'step', 'min', 'max'));
_form_set_class($element, array('form-range'));
$output = '<input' . drupal_attributes($element['#attributes']) . ' />';
return $output;
}
/**
* Form element validation handler for #type 'number'.
*
......
......@@ -20,20 +20,20 @@
* Drupal\Core\Cache\CacheBackendInterface was called MyCustomCache, the
* following line would make Drupal use it for the 'cache_page' bin:
* @code
* variable_set('cache_class_cache_page', 'MyCustomCache');
* $conf['cache_classes']['cache_page'] = 'MyCustomCache';
* @endcode
*
* Additionally, you can register your cache implementation to be used by
* default for all cache bins by setting the variable 'cache_default_class' to
* the name of your implementation of the
* Drupal\Core\Cache\CacheBackendInterface, e.g.
* default for all cache bins by setting the $conf['cache_classes'] variable and
* changing the value of the 'cache' key to the name of your implementation of
* the Drupal\Core\Cache\CacheBackendInterface, e.g.
* @code
* variable_set('cache_default_class', 'MyCustomCache');
* $conf['cache_classes']['cache'] = 'MyCustomCache';
* @endcode
*
* To implement a completely custom cache bin, use the same variable format:
* @code
* variable_set('cache_class_custom_bin', 'MyCustomCache');
* $conf['cache_classes']['custom_bin'] = 'MyCustomCache';
* @endcode
* To access your custom cache bin, specify the name of the bin when storing
* or retrieving cached data:
......@@ -104,7 +104,7 @@ function getMultiple(&$cids);
* identify objects used to build the cache item, which should trigger
* cache invalidation when updated. For example if a cached item represents
* a node, both the node ID and the author's user ID might be passed in as
* tags. For example array('node' => array(123), 'user' => array(92)).*
* tags. For example array('node' => array(123), 'user' => array(92)).
*/
function set($cid, $data, $expire = CACHE_PERMANENT, array $tags = array());
......
......@@ -959,6 +959,10 @@ function field_has_data($field) {
->fieldCondition($field)
->range(0, 1)
->count()
// Neutralize the 'entity_field_access' query tag added by
// field_sql_storage_field_storage_query(). The result cannot depend on the
// access grants of the current user.
->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT')
->execute();
}
......
......@@ -515,7 +515,12 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
}
else {
$select_query = db_select($tablename, $table_alias);
$select_query->addTag('entity_field_access');
// Allow queries internal to the Field API to opt out of the access
// check, for situations where the query's results should not depend on
// the access grants for the current user.
if (!isset($query->tags['DANGEROUS_ACCESS_CHECK_OPT_OUT'])) {
$select_query->addTag('entity_field_access');
}
$select_query->addMetaData('base_table', $tablename);
$select_query->fields($table_alias, array('entity_type', 'entity_id', 'revision_id', 'bundle'));
$field_base_table = $table_alias;
......
......@@ -69,7 +69,7 @@ function help_help($path, $arg) {
* Implements hook_preprocess_block().
*/
function help_preprocess_block(&$variables) {
if ($variables['block']->module == 'help') {
if ($variables['block']->module == 'system' && $variables['block']->delta == 'help') {
$variables['attributes_array']['role'] = 'complementary';
}
}
......@@ -2510,3 +2510,77 @@ class NodeAccessPagerTestCase extends DrupalWebTestCase {
$this->assertNoRaw('page=2', t('No third page exists.'));
}
}
/**
* Tests the interaction of the node access system with fields.
*/
class NodeAccessFieldTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node access and fields',
'description' => 'Tests the interaction of the node access system with fields.',
'group' => 'Node',
);
}
public function setUp() {
parent::setUp('node_access_test', 'field_ui');
node_access_rebuild();
// Create some users.
$this->admin_user = $this->drupalCreateUser(array('access content', 'bypass node access'));
$this->content_admin_user = $this->drupalCreateUser(array('access content', 'administer content types'));
// Add a custom field to the page content type.
$this->field_name = drupal_strtolower($this->randomName() . '_field_name');
$this->field = field_create_field(array('field_name' => $this->field_name, 'type' => 'text'));
$this->instance = field_create_instance(array(
'field_name' => $this->field_name,
'entity_type' => 'node',
'bundle' => 'page',
));
}
/**
* Tests administering fields when node access is restricted.
*/
function testNodeAccessAdministerField() {
// Create a page node.
$langcode = LANGUAGE_NOT_SPECIFIED;
$field_data = array();
$value = $field_data[$langcode][0]['value'] = $this->randomName();
$node = $this->drupalCreateNode(array($this->field_name => $field_data));
// Log in as the administrator and confirm that the field value is present.
$this->drupalLogin($this->admin_user);
$this->drupalGet("node/{$node->nid}");
$this->assertText($value, 'The saved field value is visible to an administrator.');
// Log in as the content admin and try to view the node.
$this->drupalLogin($this->content_admin_user);
$this->drupalGet("node/{$node->nid}");
$this->assertText('Access denied', 'Access is denied for the content admin.');
// Modify the field default as the content admin.
$edit = array();
$default = 'Sometimes words have two meanings';
$edit["{$this->field_name}[$langcode][0][value]"] = $default;
$this->drupalPost(
"admin/structure/types/manage/page/fields/{$this->field_name}",
$edit,
t('Save settings')
);
// Log in as the administrator.
$this->drupalLogin($this->admin_user);
// Confirm that the existing node still has the correct field value.
$this->drupalGet("node/{$node->nid}");
$this->assertText($value, 'The original field value is visible to an administrator.');
// Confirm that the new default value appears when creating a new node.
$this->drupalGet('node/add/page');
$this->assertRaw($default, 'The updated default value is displayed when creating a new node.');
}
}
......@@ -17,7 +17,7 @@
* @see template_preprocess_poll_results()
*/
?>
<article class="poll">
<div class="poll">
<?php if ($block): ?>
<h3 class="poll-title"><?php print $title; ?></h3>
<?php endif; ?>
......@@ -30,7 +30,7 @@
<?php if (!empty($cancel_form)): ?>
<?php print $cancel_form; ?>
<?php endif; ?>
</article>
</div>
<?php if ($block): ?>
<div class="links"><?php print $links; ?></div>
<?php endif; ?>
......@@ -14,7 +14,7 @@
* @see template_preprocess_poll_vote()
*/
?>
<article class="poll">
<div class="poll">
<div class="vote-form">
<?php if ($block): ?>
......@@ -26,4 +26,4 @@
</div>
<?php // This is the 'rest' of the form, in case items have been added. ?>
<?php print $rest ?>
</article>
</div>
......@@ -233,10 +233,10 @@ class PollCreateTestCase extends PollWebTestCase {
$this->clickLink($title);
$this->assertText($new_option, 'New option found.');
$option = $this->xpath('//article[@id="node-1"]//article[@class="poll"]//dt[@class="choice-title"]');
$option = $this->xpath('//article[@id="node-1"]//div[@class="poll"]//dt[@class="choice-title"]');
$this->assertEqual(end($option), $new_option, 'Last item is equal to new option.');
$votes = $this->xpath('//article[@id="node-1"]//article[@class="poll"]//div[@class="percent"]');
$votes = $this->xpath('//article[@id="node-1"]//div[@class="poll"]//div[@class="percent"]');
$this->assertTrue(strpos(end($votes), $vote_count) > 0, t("Votes saved."));
}
......
......@@ -2267,6 +2267,7 @@ protected function handleForm(&$post, &$edit, &$upload, $submit, $form) {
case 'textarea':
case 'url':
case 'number':
case 'range':
case 'hidden':
case 'password':
case 'email':
......
......@@ -413,6 +413,18 @@ function system_element_info() {
'#theme' => 'number',
'#theme_wrappers' => array('form_element'),
);
$types['range'] = array(
'#input' => TRUE,
'#size' => 30,
'#step' => 1,
'#min' => 0,
'#max' => 100,
'#maxlength' => 128,
'#process' => array('ajax_process_form'),
'#element_validate' => array('form_validate_number'),
'#theme' => 'range',
'#theme_wrappers' => array('form_element'),
);
$types['machine_name'] = array(
'#input' => TRUE,
'#default_value' => NULL,
......
......@@ -301,12 +301,11 @@ class FormsTestCase extends DrupalWebTestCase {
}
/**
* Tests validation of #type 'number' elements.
* Tests validation of #type 'number' and 'range' elements.
*/
function testNumber() {
$form = $form_state = array();
$form = form_test_number($form, $form_state);
$this->drupalGet('form-test/number');
// Array with all the error messages to be checked.
$error_messages = array(
......@@ -339,25 +338,28 @@ class FormsTestCase extends DrupalWebTestCase {
'float_step_any_no_error' => 0,
);
// Post form and show errors.
$this->drupalPost(NULL, array(), 'Submit');
foreach ($expected as $element => $error) {
// Create placeholder array.
$placeholders = array(
'%name' => $form[$element]['#title'],
'%min' => isset($form[$element]['#min']) ? $form[$element]['#min'] : '0',
'%max' => isset($form[$element]['#max']) ? $form[$element]['#max'] : '0',
);
foreach ($error_messages as $id => $message) {
// Check if the error exists on the page, if the current message ID is
// expected. Otherwise ensure that the error message is not present.
if ($id === $error) {
$this->assertRaw(format_string($message, $placeholders));
}
else {
$this->assertNoRaw(format_string($message, $placeholders));
// First test the number element type, then range.
foreach (array('form-test/number', 'form-test/number/range') as $path) {
// Post form and show errors.
$this->drupalPost($path, array(), 'Submit');
foreach ($expected as $element => $error) {
// Create placeholder array.
$placeholders = array(
'%name' => $form[$element]['#title'],
'%min' => isset($form[$element]['#min']) ? $form[$element]['#min'] : '0',
'%max' => isset($form[$element]['#max']) ? $form[$element]['#max'] : '0',
);
foreach ($error_messages as $id => $message) {
// Check if the error exists on the page, if the current message ID is
// expected. Otherwise ensure that the error message is not present.
if ($id === $error) {
$this->assertRaw(format_string($message, $placeholders));
}
else {
$this->assertNoRaw(format_string($message, $placeholders));
}
}
}
}
......@@ -406,7 +408,7 @@ class FormsTestCase extends DrupalWebTestCase {
// All the elements should be marked as disabled, including the ones below
// the disabled container.
$this->assertEqual(count($disabled_elements), 38, 'The correct elements have the disabled property in the HTML code.');
$this->assertEqual(count($disabled_elements), 39, 'The correct elements have the disabled property in the HTML code.');
$this->drupalPost(NULL, $edit, t('Submit'));
$returned_values['hijacked'] = drupal_json_decode($this->content);
......
......@@ -139,6 +139,12 @@ function form_test_menu() {
'page arguments' => array('form_test_number'),
'access callback' => TRUE,
);
$items['form-test/number/range'] = array(
'title' => 'Range',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_number', 'range'),
'access callback' => TRUE,
);
$items['form-test/checkboxes-radios'] = array(
'title' => t('Checkboxes, Radios'),
'page callback' => 'drupal_get_form',
......@@ -1153,11 +1159,14 @@ function form_test_select_submit($form, &$form_state) {
}
/**
* Builds a form to test #type 'number' validation.
* Builds a form to test #type 'number' and 'range' validation.
*
* @param $element
* The element type to test. Can be 'number' or 'range'. Defaults to 'number'.
*/
function form_test_number($form, &$form_state) {
function form_test_number($form, &$form_state, $element = 'number') {
$base = array(
'#type' => 'number',
'#type' => $element,
);
$form['integer_no_number'] = $base + array(
......@@ -1476,23 +1485,16 @@ function _form_test_disabled_elements($form, &$form_state) {
);
}
// Weight.
$form['weight'] = array(
'#type' => 'weight',
'#title' => 'weight',
'#default_value' => 10,
'#test_hijack_value' => 5,
'#disabled' => TRUE,
);
// Number.
$form['number'] = array(
'#type' => 'number',
'#title' => 'number',
'#disabled' => TRUE,
'#default_value' => 1,
'#test_hijack_value' => 2,
);
// Weight, number, range.
foreach (array('weight', 'number', 'range') as $type) {
$form[$type] = array(
'#type' => $type,
'#title' => $type,
'#default_value' => 10,
'#test_hijack_value' => 5,
'#disabled' => TRUE,
);
}
// Date.
$form['date'] = array(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment