summaryrefslogtreecommitdiff
path: root/modules/node
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2009-06-12 08:39:40 +0000
committerDries Buytaert <dries@buytaert.net>2009-06-12 08:39:40 +0000
commit3d64cb5ecae7c0d093e1343f87901769dc7d819e (patch)
tree765b3104ae2bbdf96ac677f8deab9b5457ffa4bf /modules/node
parentbfdea95337376b00e60049b640c076e8ab32293f (diff)
downloadbrdo-3d64cb5ecae7c0d093e1343f87901769dc7d819e.tar.gz
brdo-3d64cb5ecae7c0d093e1343f87901769dc7d819e.tar.bz2
- Patch #372743 by bjaspan, yched, KarenS, catch et al: node body and teasers as fields. Oh, my.
Diffstat (limited to 'modules/node')
-rw-r--r--modules/node/node.api.php3
-rw-r--r--modules/node/node.install134
-rw-r--r--modules/node/node.module355
-rw-r--r--modules/node/node.pages.inc82
-rw-r--r--modules/node/node.test187
5 files changed, 243 insertions, 518 deletions
diff --git a/modules/node/node.api.php b/modules/node/node.api.php
index d3058a57d..66630b7d0 100644
--- a/modules/node/node.api.php
+++ b/modules/node/node.api.php
@@ -204,7 +204,7 @@ function hook_node_grants_alter(&$grants, $account, $op) {
// Get our list of banned roles.
$restricted = variable_get('example_restricted_roles', array());
-
+
if ($op != 'view' && !empty($restricted)) {
// Now check the roles for this account against the restrictions.
foreach ($restricted as $role_id) {
@@ -904,7 +904,6 @@ function hook_view($node, $teaser = FALSE) {
menu_set_location($breadcrumb);
}
- $node = node_prepare($node, $teaser);
$node->content['myfield'] = array(
'#value' => theme('mymodule_myfield', $node->myfield),
'#weight' => 1,
diff --git a/modules/node/node.install b/modules/node/node.install
index 9ec782dea..72c82481a 100644
--- a/modules/node/node.install
+++ b/modules/node/node.install
@@ -213,18 +213,6 @@ function node_schema() {
'not null' => TRUE,
'default' => '',
),
- 'body' => array(
- 'description' => 'The body of this version.',
- 'type' => 'text',
- 'not null' => TRUE,
- 'size' => 'big',
- ),
- 'teaser' => array(
- 'description' => 'The teaser of this version.',
- 'type' => 'text',
- 'not null' => TRUE,
- 'size' => 'big',
- ),
'log' => array(
'description' => 'The log entry explaining the changes in this version.',
'type' => 'text',
@@ -237,12 +225,6 @@ function node_schema() {
'not null' => TRUE,
'default' => 0,
),
- 'format' => array(
- 'description' => "The text format used by this version's body.",
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
),
'indexes' => array(
'nid' => array('nid'),
@@ -304,7 +286,7 @@ function node_schema() {
'default' => '',
),
'has_body' => array(
- 'description' => 'Boolean indicating whether this type uses the {node_revision}.body field.',
+ 'description' => 'Boolean indicating whether this type has the body field attached.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -416,6 +398,7 @@ function node_update_7004() {
// Map old preview setting to new values order.
$original_preview ? $original_preview = 2 : $original_preview = 1;
+ $node_types_clear();
$type_list = node_type_get_types();
// Apply original settings to all types.
@@ -430,6 +413,119 @@ function node_update_7004() {
}
/**
+ * Convert body and teaser from node properties to fields.
+ */
+function node_update_7005(&$context) {
+ $ret = array('#finished' => 0);
+
+ // Get node type info for every invocation.
+ node_type_clear();
+ $node_types = node_type_get_types();
+ $body_types = array();
+ foreach ($node_types as $type => $info) {
+ if ($info->has_body) {
+ $body_types[] = $type;
+ }
+ }
+
+ if (!isset($context['total'])) {
+ // Initial invocation.
+
+ // Re-save node types to create body field instances.
+ foreach ($node_types as $type => $info) {
+ if ($info->has_body) {
+ node_type_save($info);
+ }
+ }
+
+ // Initialize state for future calls.
+ $context['last'] = 0;
+ $context['count'] = 0;
+
+ $query = db_select('node', 'n');
+ $query->join('node_revision', 'nr', 'n.vid = nr.vid');
+ $query->condition('n.type', $body_types, 'IN');
+ $context['total'] = $query->countQuery()->execute()->fetchField();
+ }
+ else {
+ // Subsequent invocations.
+
+ $found = FALSE;
+ if ($context['total']) {
+ // Operate on every revision of every node (whee!), in batches.
+ $batch_size = 50;
+ $query = db_select('node', 'n');
+ $nr = $query->innerJoin('node_revision', 'nr', 'n.vid = nr.vid');
+ $revisions = $query
+ ->fields('n', array('type'))
+ ->fields($nr)
+ ->condition('nr.vid', $context['last'], '>')
+ ->condition('n.type', $body_types, 'IN')
+ ->orderBy('nr.vid', 'ASC')
+ ->execute();
+
+ // Load each reversion of each node, set up 'body'
+ // appropriately, and save the node's field data. Note that
+ // node_load() will not return the body or teaser values from
+ // {node_revision} because those columns have been removed from the
+ // schema structure in memory (but not yet from the database),
+ // so we get the values from the explicit query of the table
+ // instead.
+ foreach ($revisions as $revision) {
+ $found = TRUE;
+
+ if ($node_types[$revision->type]->has_body) {
+ $node = (object) array(
+ 'nid' => $revision->nid,
+ 'vid' => $revision->vid,
+ 'type' => $revision->type,
+ );
+ if (!empty($revision->teaser) && $revision->teaser != text_summary($revision->body)) {
+ $node->body[0]['summary'] = $revision->teaser;
+ }
+ // Do this after text_summary() above.
+ $break = '<!--break-->';
+ if (substr($revision->body, 0, strlen($break)) == $break) {
+ $revision->body = substr($revision->body, strlen($break));
+ }
+ $node->body[0]['value'] = $revision->body;
+ $node->body[0]['format'] = $revision->format;
+ // This is a core update and no contrib modules are enabled yet, so
+ // we can assume default field storage for a faster update.
+ field_sql_storage_field_storage_write('node', $node, FIELD_STORAGE_INSERT, array());
+ }
+
+ $context['last'] = $revision->vid;
+ $context['count'] += 1;
+
+ if (--$batch_size == 0) {
+ break;
+ }
+ }
+
+ $ret['#finished'] = min(0.99, $context['count'] / $context['total']);
+ }
+
+ if (!$found) {
+ // All nodes are processed.
+ $ret[] = array('success' => TRUE, 'query' => "{$context['total']} node body and teaser properties migrated to the 'body' field.");
+
+ // Remove the now-obsolete body info from node_revision.
+ db_drop_field($ret, 'node_revision', 'body');
+ db_drop_field($ret, 'node_revision', 'teaser');
+ db_drop_field($ret, 'node_revision', 'format');
+
+ // We're done.
+ $ret['#finished'] = 1;
+ }
+ }
+
+ return $ret;
+}
+
+
+
+/**
* @} End of "defgroup updates-6.x-to-7.x"
* The next series of updates should start at 8000.
*/
diff --git a/modules/node/node.module b/modules/node/node.module
index d853da33f..85bcceb36 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -291,186 +291,6 @@ function node_mark($nid, $timestamp) {
}
/**
- * See if the user used JS to submit a teaser.
- */
-function node_teaser_js(&$form, &$form_state) {
- if (isset($form_state['input']['teaser_js'])) {
- // Glue the teaser to the body.
- if (trim($form_state['values']['teaser_js'])) {
- // Space the teaser from the body
- $body = trim($form_state['values']['teaser_js']) . "\r\n<!--break-->\r\n" . trim($form_state['values']['body']);
- }
- else {
- // Empty teaser, no spaces.
- $body = '<!--break-->' . $form_state['values']['body'];
- }
- // Pass updated body value on to preview/submit form processing.
- form_set_value($form['body'], $body, $form_state);
- // Pass updated body value back onto form for those cases
- // in which the form is redisplayed.
- $form['body']['#value'] = $body;
- }
- return $form;
-}
-
-/**
- * Ensure value of "teaser_include" checkbox is consistent with other form data.
- *
- * This handles two situations in which an unchecked checkbox is rejected:
- *
- * 1. The user defines a teaser (summary) but it is empty;
- * 2. The user does not define a teaser (summary) (in this case an
- * unchecked checkbox would cause the body to be empty, or missing
- * the auto-generated teaser).
- *
- * If JavaScript is active then it is used to force the checkbox to be
- * checked when hidden, and so the second case will not arise.
- *
- * In either case a warning message is output.
- */
-function node_teaser_include_verify(&$form, &$form_state) {
- $message = '';
-
- // $form_state['input'] is set only when the form is built for preview/submit.
- if (isset($form_state['input']['body']) && isset($form_state['values']['teaser_include']) && !$form_state['values']['teaser_include']) {
- // "teaser_include" checkbox is present and unchecked.
- if (strpos($form_state['values']['body'], '<!--break-->') === 0) {
- // Teaser is empty string.
- $message = t('You specified that the summary should not be shown when this post is displayed in full view. This setting is ignored when the summary is empty.');
- }
- elseif (strpos($form_state['values']['body'], '<!--break-->') === FALSE) {
- // Teaser delimiter is not present in the body.
- $message = t('You specified that the summary should not be shown when this post is displayed in full view. This setting has been ignored since you have not defined a summary for the post. (To define a summary, insert the delimiter "&lt;!--break--&gt;" (without the quotes) in the Body of the post to indicate the end of the summary and the start of the main content.)');
- }
-
- if (!empty($message)) {
- drupal_set_message($message, 'warning');
- // Pass new checkbox value on to preview/submit form processing.
- form_set_value($form['teaser_include'], 1, $form_state);
- // Pass new checkbox value back onto form for those cases
- // in which form is redisplayed.
- $form['teaser_include']['#value'] = 1;
- }
- }
-
- return $form;
-}
-
-/**
- * Generate a teaser for a node body.
- *
- * If the end of the teaser is not indicated using the <!--break--> delimiter
- * then we generate the teaser automatically, trying to end it at a sensible
- * place such as the end of a paragraph, a line break, or the end of a
- * sentence (in that order of preference).
- *
- * @param $body
- * The content for which a teaser will be generated.
- * @param $format
- * The format of the content. If the content contains PHP code, we do not
- * split it up to prevent parse errors. If the line break filter is present
- * then we treat newlines embedded in $body as line breaks.
- * @param $size
- * The desired character length of the teaser. If omitted, the default
- * value will be used. Ignored if the special delimiter is present
- * in $body.
- * @return
- * The generated teaser.
- */
-function node_teaser($body, $format = NULL, $size = NULL) {
-
- if (!isset($size)) {
- $size = variable_get('teaser_length', 600);
- }
-
- // Find where the delimiter is in the body
- $delimiter = strpos($body, '<!--break-->');
-
- // If the size is zero, and there is no delimiter, the entire body is the teaser.
- if ($size == 0 && $delimiter === FALSE) {
- return $body;
- }
-
- // If a valid delimiter has been specified, use it to chop off the teaser.
- if ($delimiter !== FALSE) {
- return substr($body, 0, $delimiter);
- }
-
- // We check for the presence of the PHP evaluator filter in the current
- // format. If the body contains PHP code, we do not split it up to prevent
- // parse errors.
- if (isset($format)) {
- $filters = filter_list_format($format);
- if (isset($filters['php/0']) && strpos($body, '<?') !== FALSE) {
- return $body;
- }
- }
-
- // If we have a short body, the entire body is the teaser.
- if (drupal_strlen($body) <= $size) {
- return $body;
- }
-
- // If the delimiter has not been specified, try to split at paragraph or
- // sentence boundaries.
-
- // The teaser may not be longer than maximum length specified. Initial slice.
- $teaser = truncate_utf8($body, $size);
-
- // Store the actual length of the UTF8 string -- which might not be the same
- // as $size.
- $max_rpos = strlen($teaser);
-
- // How much to cut off the end of the teaser so that it doesn't end in the
- // middle of a paragraph, sentence, or word.
- // Initialize it to maximum in order to find the minimum.
- $min_rpos = $max_rpos;
-
- // Store the reverse of the teaser. We use strpos on the reversed needle and
- // haystack for speed and convenience.
- $reversed = strrev($teaser);
-
- // Build an array of arrays of break points grouped by preference.
- $break_points = array();
-
- // A paragraph near the end of sliced teaser is most preferable.
- $break_points[] = array('</p>' => 0);
-
- // If no complete paragraph then treat line breaks as paragraphs.
- $line_breaks = array('<br />' => 6, '<br>' => 4);
- // Newline only indicates a line break if line break converter
- // filter is present.
- if (isset($filters['filter/1'])) {
- $line_breaks["\n"] = 1;
- }
- $break_points[] = $line_breaks;
-
- // If the first paragraph is too long, split at the end of a sentence.
- $break_points[] = array('. ' => 1, '! ' => 1, '? ' => 1, '。' => 0, '؟ ' => 1);
-
- // Iterate over the groups of break points until a break point is found.
- foreach ($break_points as $points) {
- // Look for each break point, starting at the end of the teaser.
- foreach ($points as $point => $offset) {
- // The teaser is already reversed, but the break point isn't.
- $rpos = strpos($reversed, strrev($point));
- if ($rpos !== FALSE) {
- $min_rpos = min($rpos + $offset, $min_rpos);
- }
- }
-
- // If a break point was found in this group, slice and return the teaser.
- if ($min_rpos !== $max_rpos) {
- // Don't slice with length 0. Length must be <0 to slice from RHS.
- return ($min_rpos === 0) ? $teaser : substr($teaser, 0, 0 - $min_rpos);
- }
- }
-
- // If a break point was not found, still return a teaser.
- return $teaser;
-}
-
-/**
* Extract the type name.
*
* @param $node
@@ -632,6 +452,7 @@ function node_type_save($info) {
if (!empty($type->old_type) && $type->old_type != $type->type) {
field_attach_rename_bundle($type->old_type, $type->type);
}
+ node_configure_fields($type);
module_invoke_all('node_type', 'update', $type);
return SAVED_UPDATED;
}
@@ -642,13 +463,74 @@ function node_type_save($info) {
->execute();
field_attach_create_bundle($type->type);
-
+ node_configure_fields($type);
module_invoke_all('node_type', 'insert', $type);
return SAVED_NEW;
}
}
/**
+ * Manage the field(s) for a node type.
+ *
+ * Currently, the node module manages a single Field API field,
+ * 'body'. If $type->has_body is true, this function ensures the
+ * 'body' field exists and creates an instance of it for the bundle
+ * $type->type (e.g. 'page', 'story', ...). If $type->has_body is
+ * false, this function removes the instance (if it exists) for the
+ * 'body' field on $type->type.
+ */
+function node_configure_fields($type) {
+ // Add or remove the body field, as needed.
+ $field = field_info_field('body');
+ $instance = field_info_instance('body', $type->type);
+ if ($type->has_body) {
+ if (empty($field)) {
+ $field = array(
+ 'field_name' => 'body',
+ 'type' => 'text_with_summary',
+ );
+ $field = field_create_field($field);
+ }
+ if (empty($instance)) {
+ $instance = array(
+ 'field_name' => 'body',
+ 'bundle' => $type->type,
+ 'label' => $type->body_label,
+ 'widget_type' => 'text_textarea_with_summary',
+ 'settings' => array('display_summary' => TRUE),
+
+ // With no UI in core, we have to define default
+ // formatters for the teaser and full view.
+ // This may change if the method of handling displays
+ // is changed or if a UI gets into core.
+ 'display' => array(
+ 'full' => array(
+ 'label' => 'hidden',
+ 'type' => 'text_default',
+ 'exclude' => 0,
+ ),
+ 'teaser' => array(
+ 'label' => 'hidden',
+ 'type' => 'text_summary_or_trimmed',
+ 'exclude' => 0,
+ ),
+ ),
+ );
+ field_create_instance($instance);
+ }
+ else {
+ $instance['label'] = $type->body_label;
+ $instance['settings']['display_summary'] = TRUE;
+ field_update_instance($instance);
+ }
+ }
+ elseif (!empty($instance)) {
+ field_delete_instance($instance);
+ }
+
+}
+
+/**
* Deletes a node type from the database.
*
* @param $type
@@ -1004,7 +886,8 @@ function node_validate($node, $form = array()) {
// Make sure the body has the minimum number of words.
// TODO : use a better word counting algorithm that will work in other languages
- if (!empty($type->min_word_count) && isset($node->body) && count(explode(' ', $node->body)) < $type->min_word_count) {
+ if (!empty($type->min_word_count) && isset($node->body[0]['value']) && count(explode(' ', $node->body[0]['value'])) < $type->min_word_count) {
+ // TODO: Use Field API to set this error.
form_set_error('body', t('The body of your @type is too short. You need at least %words words.', array('%words' => $type->min_word_count, '@type' => $type->name)));
}
@@ -1041,25 +924,6 @@ function node_submit($node) {
// Convert the node to an object, if necessary.
$node = (object)$node;
- // Generate the teaser, but only if it hasn't been set (e.g. by a
- // module-provided 'teaser' form item).
- if (!isset($node->teaser)) {
- if (isset($node->body)) {
- $node->format = (!empty($node->body_format) ? $node->body_format : FILTER_FORMAT_DEFAULT);
- $node->teaser = node_teaser($node->body, isset($node->format) ? $node->format : NULL, variable_get('teaser_length_' . $node->type, 600));
- // Chop off the teaser from the body if needed. The teaser_include
- // property might not be set (eg. in Blog API postings), so only act on
- // it, if it was set with a given value.
- if (isset($node->teaser_include) && !$node->teaser_include && $node->teaser == substr($node->body, 0, strlen($node->teaser))) {
- $node->body = substr($node->body, strlen($node->teaser));
- }
- }
- else {
- $node->teaser = '';
- $node->format = 0;
- }
- }
-
if (user_access('administer nodes')) {
// Populate the "authored by" field.
if ($account = user_load_by_name($node->name)) {
@@ -1105,16 +969,6 @@ function node_save($node) {
if (!isset($node->log)) {
$node->log = '';
}
-
- // For the same reasons, make sure we have $node->teaser and
- // $node->body. We should consider making these fields nullable
- // in a future version since node types are not required to use them.
- if (!isset($node->teaser)) {
- $node->teaser = '';
- }
- if (!isset($node->body)) {
- $node->body = '';
- }
}
elseif (!empty($node->revision)) {
$node->old_vid = $node->vid;
@@ -1274,30 +1128,6 @@ function node_build($node, $teaser = FALSE) {
}
/**
- * Apply filters and build the node's standard elements.
- */
-function node_prepare($node, $teaser = FALSE) {
- // First we'll overwrite the existing node teaser and body with
- // the filtered copies! Then, we'll stick those into the content
- // array and set the read more flag if appropriate.
- $node->readmore = (strlen($node->teaser) < strlen($node->body));
-
- if ($teaser == FALSE) {
- $node->body = check_markup($node->body, $node->format, $node->language, FALSE);
- }
- else {
- $node->teaser = check_markup($node->teaser, $node->format, $node->language, FALSE);
- }
-
- $node->content['body'] = array(
- '#markup' => $teaser ? $node->teaser : $node->body,
- '#weight' => 0,
- );
-
- return $node;
-}
-
-/**
* Builds a structured array representing the node's content.
*
* The content built for the node will vary depending on the $node->build_mode
@@ -1322,30 +1152,41 @@ function node_prepare($node, $teaser = FALSE) {
*
* @return
* An structured array containing the individual elements
- * of the node's body.
+ * of the node's content.
*/
function node_build_content($node, $teaser = FALSE) {
-
// The build mode identifies the target for which the node is built.
if (!isset($node->build_mode)) {
$node->build_mode = NODE_BUILD_NORMAL;
}
- // Remove the delimiter (if any) that separates the teaser from the body.
- $node->body = isset($node->body) ? str_replace('<!--break-->', '', $node->body) : '';
-
// The 'view' hook can be implemented to overwrite the default function
// to display nodes.
if (node_hook($node, 'view')) {
$node = node_invoke($node, 'view', $teaser);
}
- else {
- $node = node_prepare($node, $teaser);
- }
// Build fields content.
+ if (empty($node->content)) {
+ $node->content = array();
+ };
$node->content += field_attach_view('node', $node, $teaser);
+ // Always display a read more link on teasers because we have no way
+ // to know when a teaser view is different than a full view.
+ $links = array();
+ if ($teaser) {
+ $links['node_readmore'] = array(
+ 'title' => t('Read more'),
+ 'href' => 'node/' . $node->nid,
+ 'attributes' => array('rel' => 'tag', 'title' => strip_tags($node->title))
+ );
+ }
+ $node->content['links']['node'] = array(
+ '#type' => 'node_links',
+ '#value' => $links
+ );
+
// Allow modules to make their own additions to the node.
module_invoke_all('node_view', $node, $teaser);
@@ -1649,16 +1490,16 @@ function node_search($op = 'search', $keys = NULL) {
// Load results.
$results = array();
foreach ($find as $item) {
- // Build the node body.
+ // Render the node.
$node = node_load($item->sid);
$node->build_mode = NODE_BUILD_SEARCH_RESULT;
$node = node_build_content($node, FALSE, FALSE);
- $node->body = drupal_render($node->content);
+ $node->rendered = drupal_render($node->content);
// Fetch comments for snippet.
- $node->body .= module_invoke('comment', 'node_update_index', $node);
+ $node->rendered .= module_invoke('comment', 'node_update_index', $node);
// Fetch terms for snippet.
- $node->body .= module_invoke('taxonomy', 'node_update_index', $node);
+ $node->rendered .= module_invoke('taxonomy', 'node_update_index', $node);
$extra = module_invoke_all('node_search_result', $node);
@@ -1671,7 +1512,7 @@ function node_search($op = 'search', $keys = NULL) {
'node' => $node,
'extra' => $extra,
'score' => $total ? ($item->calculated_score / $total) : 0,
- 'snippet' => search_excerpt($keys, $node->body),
+ 'snippet' => search_excerpt($keys, $node->rendered),
);
}
return $results;
@@ -1801,7 +1642,7 @@ function node_link($type, $node = NULL, $teaser = FALSE) {
$links = array();
if ($type == 'node') {
- if ($teaser == 1 && $node->teaser && !empty($node->readmore)) {
+ if ($teaser == 1) {
$links['node_read_more'] = array(
'title' => t('Read more'),
'href' => "node/$node->nid",
@@ -2254,12 +2095,12 @@ function _node_index_node($node) {
// results half-life calculation.
variable_set('node_cron_last', $node->changed);
- // Build the node body.
+ // Render the node.
$node->build_mode = NODE_BUILD_SEARCH_INDEX;
$node = node_build_content($node, FALSE, FALSE);
- $node->body = drupal_render($node->content);
+ $node->rendered = drupal_render($node->content);
- $text = '<h1>' . check_plain($node->title) . '</h1>' . $node->body;
+ $text = '<h1>' . check_plain($node->title) . '</h1>' . $node->rendered;
// Fetch extra data normally not visible
$extra = module_invoke_all('node_update_index', $node);
@@ -2464,10 +2305,6 @@ function node_access($op, $node, $account = NULL) {
if (empty($account)) {
$account = $user;
}
- // If the node is in a restricted format, disallow editing.
- if ($op == 'update' && !filter_access($node->format)) {
- return FALSE;
- }
if (user_access('bypass node access', $account)) {
return TRUE;
@@ -2977,9 +2814,9 @@ function node_content_access($op, $node, $account) {
* Implement hook_form().
*/
function node_content_form($node, $form_state) {
-
+
$type = node_type_get_type($node);
-
+
$form = array();
if ($type->has_title) {
@@ -2993,8 +2830,6 @@ function node_content_form($node, $form_state) {
);
}
- $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
-
return $form;
}
diff --git a/modules/node/node.pages.inc b/modules/node/node.pages.inc
index 729a991db..ee362cbf6 100644
--- a/modules/node/node.pages.inc
+++ b/modules/node/node.pages.inc
@@ -114,7 +114,7 @@ function node_form(&$form_state, $node) {
$form['#prefix'] = $form_state['node_preview'];
}
$node = (object)$node;
- foreach (array('body', 'title', 'format') as $key) {
+ foreach (array('title') as $key) {
if (!isset($node->$key)) {
$node->$key = NULL;
}
@@ -287,52 +287,6 @@ function node_form(&$form_state, $node) {
}
/**
- * Return a node body field, with format and teaser.
- */
-function node_body_field($node, $label, $word_count) {
- // Do not generate a body field if the type does not specify one.
- if (!node_type_get_type($node->type)->has_body) {
- return array();
- }
-
- // Check if we need to restore the teaser at the beginning of the body.
- $include = !isset($node->teaser) || ($node->teaser == substr($node->body, 0, strlen($node->teaser)));
-
- $form = array(
- '#after_build' => array('node_teaser_js', 'node_teaser_include_verify'));
-
- $form['#prefix'] = '<div class="body-field-wrapper clearfix">';
- $form['#suffix'] = '</div>';
-
- $form['teaser_js'] = array(
- '#type' => 'textarea',
- '#rows' => 10,
- '#teaser' => 'edit-body',
- '#teaser_checkbox' => 'edit-teaser-include',
- '#disabled' => TRUE,
- );
-
- $form['teaser_include'] = array(
- '#type' => 'checkbox',
- '#title' => t('Show summary in full view'),
- '#default_value' => $include,
- '#prefix' => '<div class="teaser-checkbox">',
- '#suffix' => '</div>',
- );
-
- $form['body'] = array(
- '#type' => 'textarea',
- '#title' => check_plain($label),
- '#default_value' => $include ? $node->body : ($node->teaser . $node->body),
- '#rows' => 20,
- '#required' => ($word_count > 0),
- '#text_format' => isset($node->format) ? $node->format : FILTER_FORMAT_DEFAULT,
- );
-
- return $form;
-}
-
-/**
* Button submit function: handle the 'Delete' button on the node form.
*/
function node_form_delete_submit($form, &$form_state) {
@@ -393,16 +347,6 @@ function node_preview($node) {
$node->changed = REQUEST_TIME;
- // Extract a teaser, if it hasn't been set (e.g. by a module-provided
- // 'teaser' form item).
- if (!isset($node->teaser)) {
- $node->teaser = empty($node->body) ? '' : node_teaser($node->body, $node->format, variable_get('teaser_length_' . $type, 600));
- // Chop off the teaser from the body if needed.
- if (!$node->teaser_include && $node->teaser == substr($node->body, 0, strlen($node->teaser))) {
- $node->body = substr($node->body, strlen($node->teaser));
- }
- }
-
// Display a preview of the node.
// Previewing alters $node so it needs to be cloned.
if (!form_get_errors()) {
@@ -428,28 +372,20 @@ function theme_node_preview($node) {
$output = '<div class="preview">';
$preview_trimmed_version = FALSE;
- // Do we need to preview trimmed version of post as well as full version?
- if (isset($node->teaser) && isset($node->body)) {
- $teaser = trim($node->teaser);
- $body = trim(str_replace('<!--break-->', '', $node->body));
-
- // Preview trimmed version if teaser and body will appear different;
- // also (edge case) if both teaser and body have been specified by the user
- // and are actually the same.
- if ($teaser != $body || ($body && strpos($node->body, '<!--break-->') === 0)) {
- $preview_trimmed_version = TRUE;
- }
- }
- if ($preview_trimmed_version) {
+ $trimmed = drupal_render(node_build(clone $node, TRUE));
+ $full = drupal_render(node_build($node, FALSE));
+
+ // Do we need to preview trimmed version of post as well as full version?
+ if ($trimmed != $full) {
drupal_set_message(t('The trimmed version of your post shows what your post looks like when promoted to the main page or when exported for syndication.<span class="no-js"> You can insert the delimiter "&lt;!--break--&gt;" (without the quotes) to fine-tune where your post gets split.</span>'));
$output .= '<h3>' . t('Preview trimmed version') . '</h3>';
- $output .= drupal_render(node_build(clone $node, TRUE));
+ $output .= $trimmed;
$output .= '<h3>' . t('Preview full version') . '</h3>';
- $output .= drupal_render(node_build($node, FALSE));
+ $output .= $full;
}
else {
- $output .= drupal_render(node_build($node, FALSE));
+ $output .= $full;
}
$output .= "</div>\n";
diff --git a/modules/node/node.test b/modules/node/node.test
index 252ebbd3c..152a1353b 100644
--- a/modules/node/node.test
+++ b/modules/node/node.test
@@ -141,7 +141,7 @@ class NodeRevisionsTestCase extends DrupalWebTestCase {
// Confirm the correct revision text appears on "view revisions" page.
$this->drupalGet("node/$node->nid/revisions/$node->vid/view");
- $this->assertText($node->body, t('Correct text displays for version.'));
+ $this->assertText($node->body[0]['value'], t('Correct text displays for version.'));
// Confirm the correct log message appears on "revisions overview" page.
$this->drupalGet("node/$node->nid/revisions");
@@ -155,7 +155,7 @@ class NodeRevisionsTestCase extends DrupalWebTestCase {
array('@type' => 'Page', '%title' => $nodes[1]->title,
'%revision-date' => format_date($nodes[1]->revision_timestamp))), t('Revision reverted.'));
$reverted_node = node_load($node->nid);
- $this->assertTrue(($nodes[1]->body == $reverted_node->body), t('Node reverted correctly.'));
+ $this->assertTrue(($nodes[1]->body[0]['value'] == $reverted_node->body[0]['value']), t('Node reverted correctly.'));
// Confirm revisions delete properly.
$this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/delete", array(), t('Delete'));
@@ -166,151 +166,6 @@ class NodeRevisionsTestCase extends DrupalWebTestCase {
}
}
-class NodeTeaserTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => t('Node teaser'),
- 'description' => t('Test node_teaser() with different strings and lengths.'),
- 'group' => t('Node'),
- );
- }
-
- /**
- * Tests an edge case where if the first sentence is a question and
- * subsequent sentences are not. This is edge case is documented at
- * http://drupal.org/node/180425.
- */
- function testFirstSentenceQuestion() {
- $body = 'A question? A sentence. Another sentence.';
- $expected = 'A question? A sentence.';
- $this->callNodeTeaser($body, $expected, NULL, 30);
- }
-
- /**
- * Test teaser with long example.
- */
- function testLongSentence() {
- $body = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' . // 125
- 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ' . // 108
- 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ' . // 103
- 'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; // 110
- $expected = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' .
- 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ' .
- 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.';
- // First three sentences add up to: 336, so add one for space and then 3 to get half-way into next word.
- $this->callNodeTeaser($body, $expected, NULL, 340);
- }
-
- /**
- * Test various teaser length edge cases.
- */
- function testLength() {
- // This body string tests a number of edge cases.
- $body = "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>";
-
- // The teasers we expect node_teaser() to return when $size is the index
- // of each array item.
- // Using an text format with no line-break filter:
- $teasers = array(
- "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
- "<",
- "<p",
- "<p>",
- "<p>\n",
- "<p>\nH",
- "<p>\nHi",
- "<p>\nHi\n",
- "<p>\nHi\n<",
- "<p>\nHi\n</",
- "<p>\nHi\n</p",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
- "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
- "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
- );
-
- // And Using an text format WITH the line-break filter.
- $teasers_lb = array(
- "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
- "<",
- "<p",
- "<p>",
- "<p>",
- "<p>",
- "<p>",
- "<p>\nHi",
- "<p>\nHi",
- "<p>\nHi",
- "<p>\nHi",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>",
- "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
- "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
- "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
- );
-
- // Test node_teaser() for different sizes.
- for ($i = 0; $i <= 37; $i++) {
- $this->callNodeTeaser($body, $teasers[$i], NULL, $i);
- $this->callNodeTeaser($body, $teasers_lb[$i], 1, $i);
- $this->callNodeTeaser($body, $teasers_lb[$i], 2, $i);
- }
- }
-
- /**
- * Calls node_teaser() and asserts that the expected teaser is returned.
- */
- function callNodeTeaser($body, $expected, $format = NULL, $size = NULL) {
- $teaser = node_teaser($body, $format, $size);
- $this->assertIdentical($teaser, $expected, t('Generated teaser "@teaser" matches expected teaser.', array('@teaser' => $teaser)));
- }
-}
-
class PageEditTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -331,10 +186,11 @@ class PageEditTestCase extends DrupalWebTestCase {
* Check node edit functionality.
*/
function testPageEdit() {
+ $body_key = 'body[0][value]';
// Create node to edit.
$edit = array();
$edit['title'] = $this->randomName(8);
- $edit['body'] = $this->randomName(16);
+ $edit[$body_key] = $this->randomName(16);
$this->drupalPost('node/add/page', $edit, t('Save'));
// Check that the node exists in the database.
@@ -350,18 +206,18 @@ class PageEditTestCase extends DrupalWebTestCase {
// Check that the title and body fields are displayed with the correct values.
$this->assertLink(t('Edit'), 0, t('Edit tab found.'));
$this->assertFieldByName('title', $edit['title'], t('Title field displayed.'));
- $this->assertFieldByName('body', '<!--break-->' . $edit['body'], t('Body field displayed.'));
+ $this->assertFieldByName($body_key, $edit[$body_key], t('Body field displayed.'));
// Edit the content of the node.
$edit = array();
$edit['title'] = $this->randomName(8);
- $edit['body'] = $this->randomName(16);
+ $edit[$body_key] = $this->randomName(16);
// Stay on the current page, without reloading.
$this->drupalPost(NULL, $edit, t('Save'));
// Check that the title and body fields are displayed with the updated values.
$this->assertText($edit['title'], t('Title displayed.'));
- $this->assertText($edit['body'], t('Body displayed.'));
+ $this->assertText($edit[$body_key], t('Body displayed.'));
}
}
@@ -385,44 +241,47 @@ class PagePreviewTestCase extends DrupalWebTestCase {
* Check the node preview functionality.
*/
function testPagePreview() {
+ $body_key = 'body[0][value]';
+
// Fill in node creation form and preview node.
$edit = array();
$edit['title'] = $this->randomName(8);
- $edit['body'] = $this->randomName(16);
+ $edit[$body_key] = $this->randomName(16);
$this->drupalPost('node/add/page', $edit, t('Preview'));
// Check that the preview is displaying the title and body.
$this->assertTitle(t('Preview | Drupal'), t('Page title is preview.'));
$this->assertText($edit['title'], t('Title displayed.'));
- $this->assertText($edit['body'], t('Body displayed.'));
+ $this->assertText($edit[$body_key], t('Body displayed.'));
// Check that the title and body fields are displayed with the correct values.
$this->assertFieldByName('title', $edit['title'], t('Title field displayed.'));
- $this->assertFieldByName('body', '<!--break-->' . $edit['body'], t('Body field displayed.'));
+ $this->assertFieldByName($body_key, $edit[$body_key], t('Body field displayed.'));
}
/**
* Check the node preview functionality, when using revisions.
*/
function testPagePreviewWithRevisions() {
+ $body_key = 'body[0][value]';
// Force revision on page content.
variable_set('node_options_page', array('status', 'revision'));
// Fill in node creation form and preview node.
$edit = array();
$edit['title'] = $this->randomName(8);
- $edit['body'] = $this->randomName(16);
+ $edit[$body_key] = $this->randomName(16);
$edit['log'] = $this->randomName(32);
$this->drupalPost('node/add/page', $edit, t('Preview'));
// Check that the preview is displaying the title and body.
$this->assertTitle(t('Preview | Drupal'), t('Page title is preview.'));
$this->assertText($edit['title'], t('Title displayed.'));
- $this->assertText($edit['body'], t('Body displayed.'));
+ $this->assertText($edit[$body_key], t('Body displayed.'));
// Check that the title and body fields are displayed with the correct values.
$this->assertFieldByName('title', $edit['title'], t('Title field displayed.'));
- $this->assertFieldByName('body', '<!--break-->' . $edit['body'], t('Body field displayed.'));
+ $this->assertFieldByName($body_key, $edit[$body_key], t('Body field displayed.'));
// Check that the log field has the correct value.
$this->assertFieldByName('log', $edit['log'], t('Log field displayed.'));
@@ -452,7 +311,7 @@ class PageCreationTestCase extends DrupalWebTestCase {
// Create a node.
$edit = array();
$edit['title'] = $this->randomName(8);
- $edit['body'] = $this->randomName(16);
+ $edit['body[0][value]'] = $this->randomName(16);
$this->drupalPost('node/add/page', $edit, t('Save'));
// Check that the page has been created.
@@ -599,7 +458,7 @@ class NodePostSettingsTestCase extends DrupalWebTestCase {
// Create a node.
$edit = array();
$edit['title'] = $this->randomName(8);
- $edit['body'] = $this->randomName(16);
+ $edit['body[0][value]'] = $this->randomName(16);
$this->drupalPost('node/add/page', $edit, t('Save'));
// Check that the post information is displayed.
@@ -620,7 +479,7 @@ class NodePostSettingsTestCase extends DrupalWebTestCase {
// Create a node.
$edit = array();
$edit['title'] = $this->randomName(8);
- $edit['body'] = $this->randomName(16);
+ $edit['body[0][value]'] = $this->randomName(16);
$this->drupalPost('node/add/page', $edit, t('Save'));
// Check that the post information is displayed.
@@ -726,7 +585,7 @@ class NodeAccessRecordsAlterUnitTest extends DrupalWebTestCase {
$this->assertEqual(count($records), 1, t('Returned the correct number of rows.'));
$this->assertEqual($records[0]->realm, 'test_page_realm', t('Grant with page_realm acquired for node without alteration.'));
$this->assertEqual($records[0]->gid, 1, t('Grant with gid = 1 acquired for node without alteration.'));
-
+
// Create a promoted page node.
$node3 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
$this->assertTrue(node_load($node3->nid), t('Promoted page node created.'));
@@ -785,7 +644,7 @@ class NodeSaveTestCase extends DrupalWebTestCase {
$title = $this->randomName(8);
$node = array(
'title' => $title,
- 'body' => $this->randomName(32),
+ 'body' => array(array('value' => $this->randomName(32))),
'uid' => $this->web_user->uid,
'type' => 'article',
'nid' => $test_nid,
@@ -845,7 +704,7 @@ class NodeAccessRebuildTestCase extends DrupalWebTestCase {
'group' => t('Node'),
);
}
-
+
function setUp() {
parent::setUp();
@@ -853,7 +712,7 @@ class NodeAccessRebuildTestCase extends DrupalWebTestCase {
$this->drupalLogin($web_user);
$this->web_user = $web_user;
}
-
+
function testNodeAccessRebuild() {
$this->drupalGet('admin/reports/status');
$this->clickLink(t('Rebuild permissions'));