#414424 by sun, chx, Arancaytar, yched, et al: Introduce Form API #type 'text_format' for additional DX/security around rich text fields.
parent
c5bfbe7fa6
commit
47371be0a5
|
@ -5519,9 +5519,6 @@ function drupal_common_theme() {
|
|||
'form_element_label' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
'text_format_wrapper' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
'vertical_tabs' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
|
|
|
@ -1435,7 +1435,15 @@ function _form_builder_handle_input_element($form_id, &$element, &$form_state) {
|
|||
}
|
||||
}
|
||||
}
|
||||
form_set_value($element, $element['#value'], $form_state);
|
||||
// Set the element's value in $form_state['values'], but only, if its key
|
||||
// does not exist yet (a #value_callback may have already populated it).
|
||||
$values = $form_state['values'];
|
||||
foreach ($element['#parents'] as $key) {
|
||||
$values = (isset($values[$key]) ? $values[$key] : NULL);
|
||||
}
|
||||
if (!isset($values)) {
|
||||
form_set_value($element, $element['#value'], $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2205,110 +2213,6 @@ function form_process_radios($element) {
|
|||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text format selector to text elements with the #text_format property.
|
||||
*
|
||||
* The #text_format property should be the ID of an text format, found in
|
||||
* {filter_format}.format, which gets passed to filter_form().
|
||||
*
|
||||
* If the property #text_format is set, the form element will be expanded into
|
||||
* two separate form elements, one holding the content of the element, and the
|
||||
* other holding the text format selector. The original element is shifted into
|
||||
* a child element, but is otherwise unaltered, so that the format selector is
|
||||
* at the same level as the text field which it affects.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* // A simple textarea, such as a node body.
|
||||
* $form['body'] = array(
|
||||
* '#type' => 'textarea',
|
||||
* '#title' => t('Body'),
|
||||
* '#text_format' => isset($node->format) ? $node->format : filter_default_format(),
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
* Becomes:
|
||||
* @code
|
||||
* $form['body'] = array(
|
||||
* // Type switches to 'markup', as we're only interested in submitting the child elements.
|
||||
* '#type' => 'markup',
|
||||
* // 'value' holds the original element.
|
||||
* 'value' => array(
|
||||
* '#type' => 'textarea',
|
||||
* '#title' => t('Body'),
|
||||
* '#parents' => array('body'),
|
||||
* ),
|
||||
* // 'format' holds the text format selector.
|
||||
* 'format' => array(
|
||||
* '#parents' => array('body_format'),
|
||||
* ...
|
||||
* ),
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
* And would result in:
|
||||
* @code
|
||||
* // Original, unaltered form element value.
|
||||
* $form_state['values']['body'] = 'Example content';
|
||||
* // Chosen text format.
|
||||
* $form_state['values']['body_format'] = 1;
|
||||
* @endcode
|
||||
*
|
||||
* @see system_element_info(), filter_form()
|
||||
*/
|
||||
function form_process_text_format($element) {
|
||||
if (isset($element['#text_format'])) {
|
||||
// Determine the form element parents and element name to use for the input
|
||||
// format widget. This simulates the 'element' and 'element_format' pair of
|
||||
// parents that filter_form() expects.
|
||||
$element_parents = $element['#parents'];
|
||||
$element_name = array_pop($element_parents);
|
||||
$element_parents[] = $element_name . '_format';
|
||||
|
||||
// We need to break references, otherwise form_builder recurses infinitely.
|
||||
$element['value'] = (array)$element;
|
||||
$element['value']['#weight'] = 0;
|
||||
unset($element['value']['#description']);
|
||||
$element['#type'] = 'markup';
|
||||
$element['#theme'] = NULL;
|
||||
$element['#theme_wrappers'] = array('text_format_wrapper');
|
||||
$element['format'] = filter_form($element['#text_format'], 1, $element_parents);
|
||||
|
||||
// We need to clear the #text_format from the new child otherwise we
|
||||
// would get into an infinite loop.
|
||||
unset($element['value']['#text_format']);
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme a text format form element.
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - element: An associative array containing the properties of the element.
|
||||
* Properties used: #children, #description
|
||||
*
|
||||
* @return
|
||||
* A string representing the form element.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_text_format_wrapper($variables) {
|
||||
$element = $variables['element'];
|
||||
$output = '<div class="text-format-wrapper">' . "\n";
|
||||
|
||||
$output .= $element['#children'] . "\n";
|
||||
|
||||
if (!empty($element['#description'])) {
|
||||
$output .= '<div class="description">' . $element['#description'] . "</div>\n";
|
||||
}
|
||||
|
||||
$output .= "</div>\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme a checkbox form element.
|
||||
*
|
||||
|
|
17
misc/form.js
17
misc/form.js
|
@ -58,23 +58,6 @@ Drupal.behaviors.formUpdated = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Automatically display the guidelines of the selected text format.
|
||||
*/
|
||||
Drupal.behaviors.filterGuidelines = {
|
||||
attach: function (context) {
|
||||
$('.filter-guidelines', context).once('filter-guidelines')
|
||||
.find('label').hide()
|
||||
.parents('.filter-wrapper').find('select.filter-list')
|
||||
.bind('change', function () {
|
||||
$(this).parents('.filter-wrapper')
|
||||
.find('.filter-guidelines-item').hide()
|
||||
.siblings('#filter-guidelines-' + this.value).show();
|
||||
})
|
||||
.change();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepopulate form fields with information from the visitor cookie.
|
||||
*/
|
||||
|
|
|
@ -443,7 +443,7 @@ function block_add_block_form_submit($form, &$form_state) {
|
|||
->fields(array(
|
||||
'body' => $form_state['values']['body'],
|
||||
'info' => $form_state['values']['info'],
|
||||
'format' => $form_state['values']['body_format'],
|
||||
'format' => $form_state['values']['format'],
|
||||
))
|
||||
->execute();
|
||||
|
||||
|
|
|
@ -420,10 +420,10 @@ function block_custom_block_form($edit = array()) {
|
|||
);
|
||||
$form['body_field']['#weight'] = -17;
|
||||
$form['body_field']['body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#type' => 'text_format',
|
||||
'#title' => t('Block body'),
|
||||
'#default_value' => $edit['body'],
|
||||
'#text_format' => isset($edit['format']) ? $edit['format'] : filter_default_format(),
|
||||
'#format' => isset($edit['format']) ? $edit['format'] : NULL,
|
||||
'#rows' => 15,
|
||||
'#description' => t('The content of the block as shown to the user.'),
|
||||
'#required' => TRUE,
|
||||
|
@ -452,7 +452,7 @@ function block_custom_block_save($edit, $delta) {
|
|||
->fields(array(
|
||||
'body' => $edit['body'],
|
||||
'info' => $edit['info'],
|
||||
'format' => $edit['body_format'],
|
||||
'format' => $edit['format'],
|
||||
))
|
||||
->condition('bid', $delta)
|
||||
->execute();
|
||||
|
|
|
@ -48,7 +48,7 @@ class BlockTestCase extends DrupalWebTestCase {
|
|||
$custom_block = array();
|
||||
$custom_block['info'] = $this->randomName(8);
|
||||
$custom_block['title'] = $this->randomName(8);
|
||||
$custom_block['body'] = $this->randomName(32);
|
||||
$custom_block['body[value]'] = $this->randomName(32);
|
||||
$this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
|
||||
|
||||
// Confirm that the custom block has been created, and then query the created bid.
|
||||
|
@ -85,9 +85,9 @@ class BlockTestCase extends DrupalWebTestCase {
|
|||
$custom_block = array();
|
||||
$custom_block['info'] = $this->randomName(8);
|
||||
$custom_block['title'] = $this->randomName(8);
|
||||
$custom_block['body'] = '<h1>Full HTML</h1>';
|
||||
$custom_block['body[value]'] = '<h1>Full HTML</h1>';
|
||||
$full_html_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchField();
|
||||
$custom_block['body_format'] = $full_html_format_id;
|
||||
$custom_block['body[format]'] = $full_html_format_id;
|
||||
$this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
|
||||
|
||||
// Set the created custom block to a specific region.
|
||||
|
@ -127,7 +127,7 @@ class BlockTestCase extends DrupalWebTestCase {
|
|||
$custom_block = array();
|
||||
$custom_block['info'] = $this->randomName(8);
|
||||
$custom_block['title'] = $title;
|
||||
$custom_block['body'] = $this->randomName(32);
|
||||
$custom_block['body[value]'] = $this->randomName(32);
|
||||
$this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
|
||||
|
||||
$bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
|
||||
|
|
|
@ -2051,7 +2051,6 @@ function comment_submit($comment) {
|
|||
// 1) Filter it into HTML
|
||||
// 2) Strip out all HTML tags
|
||||
// 3) Convert entities back to plain-text.
|
||||
|
||||
$comment['subject'] = truncate_utf8(trim(decode_entities(strip_tags(check_markup($comment['comment_body'][LANGUAGE_NONE][0]['value'], $comment['comment_body'][LANGUAGE_NONE][0]['format'])))), 29, TRUE);
|
||||
// Edge cases where the comment body is populated only by HTML tags will
|
||||
// require a default subject.
|
||||
|
|
|
@ -571,7 +571,7 @@ class CommentAnonymous extends CommentHelperCase {
|
|||
$this->drupalGet('comment/reply/' . $this->node->nid);
|
||||
$this->assertText('You are not authorized to view comments', t('Error attempting to post comment.'));
|
||||
$this->assertNoFieldByName('subject', '', t('Subject field not found.'));
|
||||
$this->assertNoFieldByName('comment', '', t('Comment field not found.'));
|
||||
$this->assertNoFieldByName('comment[value]', '', t('Comment field not found.'));
|
||||
|
||||
user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
|
||||
'access comments' => TRUE,
|
||||
|
|
|
@ -512,10 +512,12 @@ function text_field_widget_settings_form($field, $instance) {
|
|||
*/
|
||||
function text_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $base) {
|
||||
$element = $base;
|
||||
$summary_widget = array();
|
||||
$main_widget = array();
|
||||
|
||||
switch ($instance['widget']['type']) {
|
||||
case 'text_textfield':
|
||||
$element['value'] = $base + array(
|
||||
$main_widget = $base + array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
|
||||
'#size' => $instance['widget']['settings']['size'],
|
||||
|
@ -526,7 +528,7 @@ function text_field_widget_form(&$form, &$form_state, $field, $instance, $langco
|
|||
|
||||
case 'text_textarea_with_summary':
|
||||
$display = !empty($items[$delta]['summary']) || !empty($instance['settings']['display_summary']);
|
||||
$element['summary'] = array(
|
||||
$summary_widget = array(
|
||||
'#type' => $display ? 'textarea' : 'value',
|
||||
'#default_value' => isset($items[$delta]['summary']) ? $items[$delta]['summary'] : NULL,
|
||||
'#title' => t('Summary'),
|
||||
|
@ -543,7 +545,7 @@ function text_field_widget_form(&$form, &$form_state, $field, $instance, $langco
|
|||
// Fall through to the next case.
|
||||
|
||||
case 'text_textarea':
|
||||
$element['value'] = $base + array(
|
||||
$main_widget = $base + array(
|
||||
'#type' => 'textarea',
|
||||
'#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
|
||||
'#rows' => $instance['widget']['settings']['rows'],
|
||||
|
@ -553,11 +555,20 @@ function text_field_widget_form(&$form, &$form_state, $field, $instance, $langco
|
|||
break;
|
||||
}
|
||||
|
||||
if ($instance['settings']['text_processing']) {
|
||||
$element['value']['#text_format'] = isset($items[$delta]['format']) ? $items[$delta]['format'] : filter_default_format();
|
||||
$element['#type'] = 'markup';
|
||||
$element['#input'] = TRUE;
|
||||
$element['#value_callback'] = 'text_field_widget_formatted_text_value';
|
||||
if ($main_widget) {
|
||||
// Conditionally alter the form element's type if text processing is enabled.
|
||||
if ($instance['settings']['text_processing']) {
|
||||
$element = $main_widget;
|
||||
$element['#type'] = 'text_format';
|
||||
$element['#format'] = isset($items[$delta]['format']) ? $items[$delta]['format'] : NULL;
|
||||
$element['#base_type'] = $main_widget['#type'];
|
||||
}
|
||||
else {
|
||||
$element['value'] = $main_widget;
|
||||
}
|
||||
}
|
||||
if ($summary_widget) {
|
||||
$element['summary'] = $summary_widget;
|
||||
}
|
||||
|
||||
return $element;
|
||||
|
@ -580,19 +591,3 @@ function text_field_widget_error($element, $error, $form, &$form_state) {
|
|||
form_error($error_element, $error['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form element #value_callback to re-assign text format value for a formatted text widget.
|
||||
*
|
||||
* #text_format puts the format into 'value_format', while we need it in
|
||||
* 'format'.
|
||||
*/
|
||||
function text_field_widget_formatted_text_value($element, $edit = FALSE, &$form_state) {
|
||||
if ($edit !== FALSE) {
|
||||
// The format selector uses #access = FALSE if only one format is
|
||||
// available. In this case, we don't receive its value, and need to
|
||||
// manually set it.
|
||||
$edit['format'] = !empty($edit['value_format']) ? $edit['value_format'] : filter_default_format();
|
||||
unset($edit['value_format']);
|
||||
return $edit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ class TextFieldTestCase extends DrupalWebTestCase {
|
|||
// no format selector will be displayed.
|
||||
$this->drupalGet('test-entity/add/test-bundle');
|
||||
$this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
|
||||
$this->assertNoFieldByName("{$this->field_name}[$langcode][0][value_format]", '', t('Format selector is not displayed'));
|
||||
$this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is not displayed'));
|
||||
|
||||
// Submit with data that should be filtered.
|
||||
$value = '<em>' . $this->randomName() . '</em>';
|
||||
|
@ -202,11 +202,11 @@ class TextFieldTestCase extends DrupalWebTestCase {
|
|||
// We should now have a 'text format' selector.
|
||||
$this->drupalGet('test-entity/' . $id . '/edit');
|
||||
$this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
|
||||
$this->assertFieldByName("{$this->field_name}[$langcode][0][value_format]", '', t('Format selector is displayed'));
|
||||
$this->assertFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is displayed'));
|
||||
|
||||
// Edit and change the text format to the new one that was created.
|
||||
$edit = array(
|
||||
"{$this->field_name}[$langcode][0][value_format]" => $format_id,
|
||||
"{$this->field_name}[$langcode][0][format]" => $format_id,
|
||||
);
|
||||
$this->drupalPost(NULL, $edit, t('Save'));
|
||||
$this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), t('Entity was updated'));
|
||||
|
|
|
@ -1150,8 +1150,8 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
|||
$langcode = LANGUAGE_NONE;
|
||||
// Pretend the form has been built.
|
||||
drupal_prepare_form('field_test_entity_form', $form, $form_state);
|
||||
$form = form_builder('field_test_entity_form', $form, $form_state);
|
||||
$form_state['values'] = array($this->field_name => array($langcode => $values));
|
||||
drupal_process_form('field_test_entity_form', $form, $form_state);
|
||||
$form_state['values'][$this->field_name][$langcode] = $values;
|
||||
field_attach_submit($entity_type, $entity, $form, $form_state);
|
||||
|
||||
asort($weights);
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
}
|
||||
.filter-wrapper .form-item {
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding: 0 0 0.5em 1.5em;
|
||||
}
|
||||
.filter-wrapper .form-item label {
|
||||
|
|
|
@ -56,6 +56,9 @@ function filter_theme() {
|
|||
'variables' => array('tips' => NULL, 'long' => FALSE),
|
||||
'file' => 'filter.pages.inc',
|
||||
),
|
||||
'text_format_wrapper' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
'filter_tips_more_info' => array(
|
||||
'variables' => array(),
|
||||
),
|
||||
|
@ -65,6 +68,20 @@ function filter_theme() {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_element_info().
|
||||
*
|
||||
* @see filter_process_format()
|
||||
*/
|
||||
function filter_element_info() {
|
||||
$type['text_format'] = array(
|
||||
'#process' => array('filter_process_format'),
|
||||
'#base_type' => 'textarea',
|
||||
'#theme_wrappers' => array('text_format_wrapper'),
|
||||
);
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
|
@ -701,71 +718,194 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE)
|
|||
}
|
||||
|
||||
/**
|
||||
* Generates a selector for choosing a format in a form.
|
||||
* Expands an element into a base element with text format selector attached.
|
||||
*
|
||||
* @param $selected_format
|
||||
* The ID of the format that is currently selected; uses the default format
|
||||
* for the current user if not provided.
|
||||
* @param $weight
|
||||
* The weight of the form element within the form.
|
||||
* @param $parents
|
||||
* The parents array of the element. Required when defining multiple text
|
||||
* formats on a single form or having a different parent than 'format'.
|
||||
* The form element will be expanded into two separate form elements, one
|
||||
* holding the original element, and the other holding the text format selector:
|
||||
* - value: Holds the original element, having its #type changed to the value of
|
||||
* #base_type or 'textarea' by default.
|
||||
* - format: Holds the text format fieldset and the text format selection, using
|
||||
* the text format id specified in #format or the user's default format by
|
||||
* default, if NULL.
|
||||
*
|
||||
* Since most modules expect the value of the new 'format' element *next* to the
|
||||
* original element, filter_process_format() utilizes an #after_build to move
|
||||
* the values of the children of the 'text_format' element so as to let the
|
||||
* submitted form values appear as if they were located on the same level.
|
||||
* For example, considering the input values:
|
||||
* @code
|
||||
* $form_state['input']['body']['value'] = 'foo';
|
||||
* $form_state['input']['body']['format'] = 'foo';
|
||||
* @endcode
|
||||
* The #after_build will process them into:
|
||||
* @code
|
||||
* $form_state['values']['body'] = 'foo';
|
||||
* $form_state['values']['format'] = 'foo';
|
||||
* @endcode
|
||||
*
|
||||
* If multiple text format-enabled elements are required on the same level of
|
||||
* the form structure, modules can set custom #parents on the original element.
|
||||
* Alternatively, the #after_build may be unset through a subsequent #process
|
||||
* callback. If no custom processing occurs, then the submitted form values will
|
||||
* appear like in the $form_state['input'] array above.
|
||||
*
|
||||
* @see filter_form_after_build()
|
||||
*
|
||||
* @param $element
|
||||
* The form element to process. Properties used:
|
||||
* - #base_type: The form element #type to use for the 'value' element.
|
||||
* 'textarea' by default.
|
||||
* - #format: (optional) The text format id to preselect. If 0, NULL, or not
|
||||
* set, the default format for the current user will be used.
|
||||
*
|
||||
* @return
|
||||
* Form API array for the form element.
|
||||
*
|
||||
* @ingroup forms
|
||||
* The expanded element.
|
||||
*/
|
||||
function filter_form($selected_format = NULL, $weight = NULL, $parents = array('format')) {
|
||||
function filter_process_format($element) {
|
||||
global $user;
|
||||
|
||||
// Use the default format for this user if none was selected.
|
||||
if (empty($selected_format)) {
|
||||
$selected_format = filter_default_format($user);
|
||||
// Ensure that children appear as subkeys of this element.
|
||||
$element['#tree'] = TRUE;
|
||||
$blacklist = array(
|
||||
// Make form_builder() regenerate child properties.
|
||||
'#parents',
|
||||
'#id',
|
||||
'#name',
|
||||
// Do not copy this #process function to prevent form_builder() from
|
||||
// recursing infinitely.
|
||||
'#process',
|
||||
// Description is handled by theme_text_format_wrapper().
|
||||
'#description',
|
||||
// Ensure proper ordering of children.
|
||||
'#weight',
|
||||
// Properties already processed for the parent element.
|
||||
'#prefix',
|
||||
'#suffix',
|
||||
'#attached',
|
||||
'#processed',
|
||||
'#theme_wrappers',
|
||||
);
|
||||
// Move this element into sub-element 'value'.
|
||||
unset($element['value']);
|
||||
foreach ($element as $key => $value) {
|
||||
if ($key[0] === '#' && !in_array($key, $blacklist)) {
|
||||
$element['value'][$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of formats that the current user has access to.
|
||||
$formats = filter_formats($user);
|
||||
$element['value']['#type'] = $element['#base_type'];
|
||||
$element['value'] += element_info($element['#base_type']);
|
||||
|
||||
drupal_add_js('misc/form.js');
|
||||
drupal_add_css(drupal_get_path('module', 'filter') . '/filter.css');
|
||||
$element_id = drupal_html_id('edit-' . implode('-', $parents));
|
||||
// Turn original element into a text format wrapper.
|
||||
$path = drupal_get_path('module', 'filter');
|
||||
$element['#attached']['js'][] = $path . '/filter.js';
|
||||
$element['#attached']['css'][] = $path . '/filter.css';
|
||||
|
||||
$form = array(
|
||||
// Apply default #after_build behavior.
|
||||
$element['#after_build'][] = 'filter_form_after_build';
|
||||
|
||||
// Setup child container for the text format widget.
|
||||
$element['format'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#weight' => $weight,
|
||||
'#attributes' => array('class' => array('filter-wrapper')),
|
||||
);
|
||||
$form['format_guidelines'] = array(
|
||||
'#prefix' => '<div id="' . $element_id . '-guidelines" class="filter-guidelines">',
|
||||
'#suffix' => '</div>',
|
||||
'#weight' => 2,
|
||||
|
||||
// Prepare text format guidelines.
|
||||
$element['format']['guidelines'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array('class' => array('filter-guidelines')),
|
||||
'#weight' => 20,
|
||||
);
|
||||
// Get a list of formats that the current user has access to.
|
||||
$formats = filter_formats($user);
|
||||
foreach ($formats as $format) {
|
||||
$options[$format->format] = $format->name;
|
||||
$form['format_guidelines'][$format->format] = array(
|
||||
'#markup' => theme('filter_guidelines', array('format' => $format)),
|
||||
$element['format']['guidelines'][$format->format] = array(
|
||||
'#theme' => 'filter_guidelines',
|
||||
'#format' => $format,
|
||||
);
|
||||
}
|
||||
$form['format'] = array(
|
||||
|
||||
// Use the default format for this user if none was selected.
|
||||
if (empty($element['#format'])) {
|
||||
$element['#format'] = filter_default_format($user);
|
||||
}
|
||||
$element['format']['format'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Text format'),
|
||||
'#options' => $options,
|
||||
'#default_value' => $selected_format,
|
||||
'#parents' => $parents,
|
||||
'#default_value' => $element['#format'],
|
||||
'#access' => count($formats) > 1,
|
||||
'#id' => $element_id,
|
||||
'#weight' => 10,
|
||||
'#attributes' => array('class' => array('filter-list')),
|
||||
);
|
||||
$form['format_help'] = array(
|
||||
'#prefix' => '<div id="' . $element_id . '-help" class="filter-help">',
|
||||
'#markup' => theme('filter_tips_more_info'),
|
||||
'#suffix' => '</div>',
|
||||
'#weight' => 1,
|
||||
'#parents' => array_merge($element['#parents'], array('format')),
|
||||
'#value_callback' => 'filter_form_value_callback_format',
|
||||
);
|
||||
|
||||
return $form;
|
||||
$element['format']['help'] = array(
|
||||
'#type' => 'container',
|
||||
'#theme' => 'filter_tips_more_info',
|
||||
'#attributes' => array('class' => array('filter-help')),
|
||||
'#weight' => 0,
|
||||
);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* After build, we need to move the values up in $form_state.
|
||||
*/
|
||||
function filter_form_after_build($element, &$form_state) {
|
||||
$parents = $element['#parents'];
|
||||
$original_key = array_pop($parents);
|
||||
|
||||
// For text fields, the additional subkeys map 1:1 to field schema columns.
|
||||
if (isset($element['#columns'])) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
foreach (element_children($element) as $key) {
|
||||
$current_parents = $parents;
|
||||
switch ($key) {
|
||||
case 'value':
|
||||
form_set_value(array('#parents' => $element['#parents']), $element[$key]['#value'], $form_state);
|
||||
break;
|
||||
case 'format':
|
||||
$current_parents[] = $key;
|
||||
form_set_value(array('#parents' => $current_parents), $element['format']['format']['#value'], $form_state);
|
||||
break;
|
||||
|
||||
default:
|
||||
$current_parents[] = $key;
|
||||
form_set_value(array('#parents' => $current_parents), $element[$key]['#value'], $form_state);
|
||||
}
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a text format-enabled form element.
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - element: An associative array containing the properties of the element.
|
||||
* Properties used: #children, #description
|
||||
*
|
||||
* @return
|
||||
* A string representing the form element.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_text_format_wrapper($variables) {
|
||||
$element = $variables['element'];
|
||||
$output = '<div class="text-format-wrapper">';
|
||||
$output .= $element['#children'];
|
||||
if (!empty($element['#description'])) {
|
||||
$output .= '<div class="description">' . $element['#description'] . '</div>';
|
||||
}
|
||||
$output .= "</div>\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -305,7 +305,7 @@ class FilterAdminTestCase extends DrupalWebTestCase {
|
|||
$langcode = LANGUAGE_NONE;
|
||||
$edit["title"] = $this->randomName();
|
||||
$edit["body[$langcode][0][value]"] = $text;
|
||||
$edit["body[$langcode][0][value_format]"] = $filtered;
|
||||
$edit["body[$langcode][0][format]"] = $filtered;
|
||||
$this->drupalPost('node/add/page', $edit, t('Save'));
|
||||
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $edit["title"])), t('Filtered node created.'));
|
||||
|
||||
|
@ -317,7 +317,7 @@ class FilterAdminTestCase extends DrupalWebTestCase {
|
|||
|
||||
// Use plain text and see if it escapes all tags, whether allowed or not.
|
||||
$edit = array();
|
||||
$edit["body[$langcode][0][value_format]"] = $plain;
|
||||
$edit["body[$langcode][0][format]"] = $plain;
|
||||
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
|
||||
$this->drupalGet('node/' . $node->nid);
|
||||
$this->assertText(check_plain($text), t('The "Plain text" text format escapes all HTML tags.'));
|
||||
|
@ -1212,9 +1212,9 @@ class FilterHooksTestCase extends DrupalWebTestCase {
|
|||
$custom_block = array();
|
||||
$custom_block['info'] = $this->randomName(8);
|
||||
$custom_block['title'] = $this->randomName(8);
|
||||
$custom_block['body'] = $this->randomName(32);
|
||||
$custom_block['body[value]'] = $this->randomName(32);
|
||||
// Use the format created.
|
||||
$custom_block['body_format'] = $format_id;
|
||||
$custom_block['body[format]'] = $format_id;
|
||||
$this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
|
||||
$this->assertText(t('The block has been created.'), t('New block successfully created.'));
|
||||
|
||||
|
|
|
@ -190,15 +190,16 @@ class PathTaxonomyTermTestCase extends DrupalWebTestCase {
|
|||
*/
|
||||
function testTermAlias() {
|
||||
// Create a term in the default 'Tags' vocabulary with URL alias.
|
||||
$description = $this->randomName();;
|
||||
$edit = array();
|
||||
$edit['name'] = $this->randomName();
|
||||
$edit['description'] = $this->randomName();
|
||||
$edit['description[value]'] = $description;
|
||||
$edit['path[alias]'] = $this->randomName();
|
||||
$this->drupalPost('admin/structure/taxonomy/1/add', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet($edit['path[alias]']);
|
||||
$this->assertText($edit['description'], 'Term can be accessed on URL alias.');
|
||||
$this->assertText($description, 'Term can be accessed on URL alias.');
|
||||
|
||||
// Change the term's URL alias.
|
||||
$tid = db_query("SELECT tid FROM {taxonomy_term_data} WHERE name = :name", array(':name' => $edit['name']))->fetchField();
|
||||
|
@ -208,11 +209,11 @@ class PathTaxonomyTermTestCase extends DrupalWebTestCase {
|
|||
|
||||
// Confirm that the changed alias works.
|
||||
$this->drupalGet($edit2['path[alias]']);
|
||||
$this->assertText($edit['description'], 'Term can be accessed on changed URL alias.');
|
||||
$this->assertText($description, 'Term can be accessed on changed URL alias.');
|
||||
|
||||
// Confirm that the old alias no longer works.
|
||||
$this->drupalGet($edit['path[alias]']);
|
||||
$this->assertNoText($edit['description'], 'Old URL alias has been removed after altering.');
|
||||
$this->assertNoText($description, 'Old URL alias has been removed after altering.');
|
||||
$this->assertResponse(404, 'Old URL alias returns 404.');
|
||||
|
||||
// Remove the term's URL alias.
|
||||
|
@ -222,7 +223,7 @@ class PathTaxonomyTermTestCase extends DrupalWebTestCase {
|
|||
|
||||
// Confirm that the alias no longer works.
|
||||
$this->drupalGet($edit2['path[alias]']);
|
||||
$this->assertNoText($edit['description'], 'Old URL alias has been removed after altering.');
|
||||
$this->assertNoText($description, 'Old URL alias has been removed after altering.');
|
||||
$this->assertResponse(404, 'Old URL alias returns 404.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ class PHPFilterTestCase extends PHPTestCase {
|
|||
// Change filter to PHP filter and see that PHP code is evaluated.
|
||||
$edit = array();
|
||||
$langcode = LANGUAGE_NONE;
|
||||
$edit["body[$langcode][0][value_format]"] = $this->php_code_format;
|
||||
$edit["body[$langcode][0][format]"] = $this->php_code_format;
|
||||
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
|
||||
$this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node->title)), t('PHP code filter turned on.'));
|
||||
|
||||
|
|
|
@ -536,7 +536,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
|
|||
$edit_comment['subject'] = 'Test comment subject';
|
||||
$edit_comment['comment_body[' . LANGUAGE_NONE . '][0][value]'] = '<h1>' . $comment_body . '</h1>';
|
||||
$full_html_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchField();
|
||||
$edit_comment['comment_body[' . LANGUAGE_NONE . '][0][value_format]'] = $full_html_format_id;
|
||||
$edit_comment['comment_body[' . LANGUAGE_NONE . '][0][format]'] = $full_html_format_id;
|
||||
$this->drupalPost('comment/reply/' . $node->nid, $edit_comment, t('Save'));
|
||||
|
||||
// Invoke search index update.
|
||||
|
|
|
@ -337,7 +337,7 @@ function system_element_info() {
|
|||
'#size' => 60,
|
||||
'#maxlength' => 128,
|
||||
'#autocomplete_path' => FALSE,
|
||||
'#process' => array('form_process_text_format', 'ajax_process_form'),
|
||||
'#process' => array('ajax_process_form'),
|
||||
'#theme' => 'textfield',
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
);
|
||||
|
@ -359,7 +359,7 @@ function system_element_info() {
|
|||
'#cols' => 60,
|
||||
'#rows' => 5,
|
||||
'#resizable' => TRUE,
|
||||
'#process' => array('form_process_text_format', 'ajax_process_form'),
|
||||
'#process' => array('ajax_process_form'),
|
||||
'#theme' => 'textarea',
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
);
|
||||
|
|
|
@ -647,10 +647,10 @@ function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary =
|
|||
'#weight' => -5,
|
||||
);
|
||||
$form['description'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#type' => 'text_format',
|
||||
'#title' => t('Description'),
|
||||
'#default_value' => $edit['description'],
|
||||
'#text_format' => $edit['format'],
|
||||
'#format' => $edit['format'],
|
||||
'#weight' => 0,
|
||||
);
|
||||
|
||||
|
@ -780,10 +780,6 @@ function taxonomy_form_term_submit($form, &$form_state) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Massage #text_format.
|
||||
$form_state['values']['format'] = $form_state['values']['description_format'];
|
||||
unset($form_state['values']['description_format']);
|
||||
|
||||
$term = taxonomy_form_term_submit_builder($form, $form_state);
|
||||
|
||||
$status = taxonomy_term_save($term);
|
||||
|
|
|
@ -448,7 +448,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
|
|||
function testTermInterface() {
|
||||
$edit = array(
|
||||
'name' => $this->randomName(12),
|
||||
'description' => $this->randomName(100),
|
||||
'description[value]' => $this->randomName(100),
|
||||
);
|
||||
// Explicitly set the parents field to 'root', to ensure that
|
||||
// taxonomy_form_term_submit() handles the invalid term ID correctly.
|
||||
|
@ -470,11 +470,11 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
|
|||
$this->clickLink(t('edit'));
|
||||
|
||||
$this->assertText($edit['name'], t('The randomly generated term name is present.'));
|
||||
$this->assertText($edit['description'], t('The randomly generated term description is present.'));
|
||||
$this->assertText($edit['description[value]'], t('The randomly generated term description is present.'));
|
||||
|
||||
$edit = array(
|
||||
'name' => $this->randomName(14),
|
||||
'description' => $this->randomName(102),
|
||||
'description[value]' => $this->randomName(102),
|
||||
);
|
||||
|
||||
// Edit the term.
|
||||
|
@ -483,7 +483,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
|
|||
// View the term and check that it is correct.
|
||||
$this->drupalGet('taxonomy/term/' . $term->tid);
|
||||
$this->assertText($edit['name'], t('The randomly generated term name is present.'));
|
||||
$this->assertText($edit['description'], t('The randomly generated term description is present.'));
|
||||
$this->assertText($edit['description[value]'], t('The randomly generated term description is present.'));
|
||||
|
||||
// Check that term feed page is working
|
||||
$this->drupalGet('taxonomy/term/' . $term->tid . '/feed');
|
||||
|
|
Loading…
Reference in New Issue