? node.kpf ? node.patch ? node_styles.patch ? sites/node ? sites/default/settings.php Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.641 diff -u -p -r1.641 common.inc --- includes/common.inc 15 May 2007 20:19:47 -0000 1.641 +++ includes/common.inc 17 May 2007 03:08:21 -0000 @@ -2360,7 +2360,7 @@ function drupal_common_themes() { 'arguments' => array(), ), 'node' => array( - 'arguments' => array('node' => NULL, 'teaser' => FALSE, 'page' => FALSE), + 'arguments' => array('node' => NULL, 'style' => 'full', 'options' => array()), 'file' => 'node', ), 'submenu' => array( Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.355 diff -u -p -r1.355 theme.inc --- includes/theme.inc 6 May 2007 05:47:51 -0000 1.355 +++ includes/theme.inc 17 May 2007 03:08:21 -0000 @@ -1554,6 +1554,10 @@ function template_preprocess_page(&$vari */ function template_preprocess_node(&$variables) { $node = $variables['node']; + foreach($variables['options'] as $option => $value) { + $variables[$option] = $value; + } + if (module_exists('taxonomy')) { $variables['taxonomy'] = taxonomy_link('taxonomy terms', $node); } @@ -1561,7 +1565,7 @@ function template_preprocess_node(&$vari $variables['taxonomy'] = array(); } - if ($variables['teaser'] && $node->teaser) { + if ($variables['style'] == 'teaser' && $node->teaser) { $variables['content'] = $node->teaser; } elseif (isset($node->body)) { @@ -1591,6 +1595,8 @@ function template_preprocess_node(&$vari $variables['picture'] = ''; } + $variables['template_files'][] = 'node-'. $variables['style'] .'-'. $node->type; + $variables['template_files'][] = 'node-'. $variables['style']; $variables['template_files'][] = 'node-'. $node->type; } Index: modules/aggregator/aggregator.module =================================================================== RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.module,v retrieving revision 1.339 diff -u -p -r1.339 aggregator.module --- modules/aggregator/aggregator.module 14 May 2007 13:43:33 -0000 1.339 +++ modules/aggregator/aggregator.module 17 May 2007 03:08:22 -0000 @@ -1233,15 +1233,15 @@ function aggregator_page_rss() { } while ($item = db_fetch_object($result)) { - switch (variable_get('feed_item_length', 'teaser')) { - case 'teaser': + switch (variable_get('feed_item_length', NODE_BODY_TRIMMED)) { + case NODE_BODY_TRIMMED: $teaser = node_teaser($item->description); if ($teaser != $item->description) { $teaser .= '
\n"; } $item->description = $teaser; break; - case 'title': + case NODE_BODY_HIDDEN: $item->description = ''; break; } Index: modules/blog/blog.module =================================================================== RCS file: /cvs/drupal/drupal/modules/blog/blog.module,v retrieving revision 1.280 diff -u -p -r1.280 blog.module --- modules/blog/blog.module 30 Apr 2007 17:03:23 -0000 1.280 +++ modules/blog/blog.module 17 May 2007 03:08:22 -0000 @@ -152,7 +152,7 @@ function blog_page_user($uid) { $result = pager_query(db_rewrite_sql("SELECT n.nid, n.sticky, n.created FROM {node} n WHERE n.type = 'blog' AND n.uid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10), 0, NULL, $account->uid); while ($node = db_fetch_object($result)) { - $output .= node_view(node_load($node->nid), 1); + $output .= node_view(node_load($node->nid), 'teaser'); } $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); drupal_add_feed(url('blog/'. $account->uid .'/feed'), t('RSS - !title', array('!title' => $title))); @@ -175,7 +175,7 @@ function blog_page_last() { $result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10)); while ($node = db_fetch_object($result)) { - $output .= node_view(node_load($node->nid), 1); + $output .= node_view(node_load($node->nid), 'teaser'); } $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); drupal_add_feed(url('blog/feed'), t('RSS - blogs')); @@ -218,21 +218,21 @@ function blog_form(&$node) { /** * Implementation of hook_view(). */ -function blog_view($node, $teaser = FALSE, $page = FALSE) { - if ($page) { +function blog_view($node, $style = 'full', $options = array()) { + if ($options['page']) { // Breadcrumb navigation $breadcrumb[] = array('path' => 'blog', 'title' => t('Blogs')); $breadcrumb[] = array('path' => 'blog/'. $node->uid, 'title' => t("@name's blog", array('@name' => $node->name))); $breadcrumb[] = array('path' => 'node/'. $node->nid); menu_set_location($breadcrumb); } - return node_prepare($node, $teaser); + return node_prepare($node, $style, $options); } /** * Implementation of hook_link(). */ -function blog_link($type, $node = NULL, $teaser = FALSE) { +function blog_link($type, $node = NULL, $style = 'full') { $links = array(); if ($type == 'node' && $node->type == 'blog') { Index: modules/book/book.module =================================================================== RCS file: /cvs/drupal/drupal/modules/book/book.module,v retrieving revision 1.420 diff -u -p -r1.420 book.module --- modules/book/book.module 14 May 2007 13:43:34 -0000 1.420 +++ modules/book/book.module 17 May 2007 03:08:22 -0000 @@ -74,12 +74,12 @@ function book_access($op, $node) { /** * Implementation of hook_link(). */ -function book_link($type, $node = NULL, $teaser = FALSE) { +function book_link($type, $node = NULL, $style = 'full') { $links = array(); if ($type == 'node' && isset($node->parent)) { - if (!$teaser) { + if ($style != 'teaser') { if (book_access('create', $node) && $node->status == 1) { $links['book_add_child'] = array( 'title' => t('Add child page'), @@ -418,9 +418,20 @@ function book_next($node) { * approved revision of a node (if any) unless we have to display this * page in the context of the moderation queue. */ -function book_content($node, $teaser = FALSE) { +function book_content($node, $style = 'full', $options = array()) { // Return the page body. - return node_prepare($node, $teaser); + return node_prepare($node, $style, $options); +} + +function book_node_styles() { + $styles['default']['options'] = array( + 'show_book_navigation' => FALSE, + ); + + $styles['full']['options'] = array( + 'show_book_navigation' => TRUE, + ); + return $styles; } /** @@ -428,13 +439,13 @@ function book_content($node, $teaser = F * * Appends book navigation to all nodes in the book. */ -function book_nodeapi(&$node, $op, $teaser, $page) { +function book_nodeapi(&$node, $op, $style = 'full', $options = array()) { switch ($op) { case 'load': return db_fetch_array(db_query('SELECT parent, weight FROM {book} WHERE vid = %d', $node->vid)); break; case 'view': - if (!$teaser) { + if ($options['show_book_navigation']) { if (isset($node->parent)) { $path = book_location($node); // Construct the breadcrumb: @@ -449,7 +460,7 @@ function book_nodeapi(&$node, $op, $teas '#weight' => 100, ); - if ($page) { + if ($options['page']) { menu_set_location($node->breadcrumb); } } @@ -783,20 +794,8 @@ function book_recurse($nid = 0, $depth = * - the HTML generated for the given node. */ function book_node_visitor_html_pre($node, $depth, $nid) { - // Remove the delimiter (if any) that separates the teaser from the body. - $node->body = str_replace('', '', $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', FALSE, FALSE); - } - else { - $node = node_prepare($node, FALSE); - } - - // Allow modules to make their own additions to the node. - node_invoke_nodeapi($node, 'print'); + $options = node_get_style_options('print'); + $node = node_build_content($node, 'print', $options); $output .= "'. t('The outline feature allows you to include posts in the book hierarchy.', array('@book' => url('book'))) .'
'; } } - - Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.542 diff -u -p -r1.542 comment.module --- modules/comment/comment.module 14 May 2007 13:43:35 -0000 1.542 +++ modules/comment/comment.module 17 May 2007 03:08:22 -0000 @@ -343,12 +343,12 @@ function theme_comment_block() { /** * Implementation of hook_link(). */ -function comment_link($type, $node = NULL, $teaser = FALSE) { +function comment_link($type, $node = NULL, $style = 'full') { $links = array(); if ($type == 'node' && $node->comment) { - if ($teaser) { + if ($style == 'teaser') { // Main page: display the number of comments that have been posted. if (user_access('access comments')) { @@ -413,7 +413,7 @@ function comment_link($type, $node = NUL } if ($type == 'comment') { - $links = comment_links($node, $teaser); + $links = comment_links($node, $style, $options); } if (isset($links['comment_forbidden'])) { $links['comment_forbidden']['html'] = TRUE; Index: modules/forum/forum.module =================================================================== RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v retrieving revision 1.397 diff -u -p -r1.397 forum.module --- modules/forum/forum.module 14 May 2007 13:43:36 -0000 1.397 +++ modules/forum/forum.module 17 May 2007 03:08:22 -0000 @@ -166,7 +166,7 @@ function forum_perm() { /** * Implementation of hook_nodeapi(). */ -function forum_nodeapi(&$node, $op, $teaser, $page) { +function forum_nodeapi(&$node, $op, $style = 'full', $options = array()) { switch ($op) { case 'delete revision': db_query('DELETE FROM {forum} WHERE vid = %d', $node->vid); @@ -313,11 +313,24 @@ function forum_block($op = 'list', $delt } } + +function forum_node_styles() { + $styles['default']['options'] = array( + 'show_forum_navigation' => FALSE, + ); + + $styles['full']['options'] = array( + 'show_forum_navigation' => TRUE, + ); + return $styles; +} + + /** * Implementation of hook_view(). */ -function forum_view(&$node, $teaser = FALSE, $page = FALSE) { - if ($page) { +function forum_view(&$node, $style = 'full', $options = array()) { + if ($options['page']) { $vocabulary = taxonomy_vocabulary_load(variable_get('forum_nav_vocabulary', '')); // Breadcrumb navigation $breadcrumb = array(); @@ -332,8 +345,8 @@ function forum_view(&$node, $teaser = FA menu_set_location($breadcrumb); } - $node = node_prepare($node, $teaser); - if (!$teaser) { + $node = node_prepare($node, $style, $options); + if ($options['show_forum_navigation']) { $node->content['forum_navigation'] = array( '#value' => theme('forum_topic_navigation', $node), '#weight' => 100, @@ -1185,5 +1198,3 @@ function _forum_get_topic_order_sql($sor $order = _forum_get_topic_order($sortby); return $order['field'] .' '. $order['sort']; } - - Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.814 diff -u -p -r1.814 node.module --- modules/node/node.module 16 May 2007 13:45:16 -0000 1.814 +++ modules/node/node.module 17 May 2007 03:08:23 -0000 @@ -8,6 +8,9 @@ */ define('NODE_NEW_LIMIT', time() - 30 * 24 * 60 * 60); +define('NODE_BODY_HIDDEN', 0); +define('NODE_BODY_TRIMMED', 1); +define('NODE_BODY_FULL', 2); /** * Implementation of hook_help(). @@ -735,54 +738,59 @@ function node_save(&$node) { * @return * An HTML representation of the themed node. */ -function node_view($node, $teaser = FALSE, $page = FALSE, $links = TRUE) { +function node_view($node, $style = 'full', $options = array()) { $node = (object)$node; - $node = node_build_content($node, $teaser, $page); + // Let's merge in the default display options for the current node + // style. + $defaults = node_get_style_options($style); + $options += $defaults; - if ($links) { - $node->links = module_invoke_all('link', 'node', $node, !$page); + $node = node_build_content($node, $style, $options); + + if (!empty($options['show_links'])) { + $node->links = module_invoke_all('link', 'node', $node, $style); drupal_alter('link', $node->links, $node); } - // Set the proper node part, then unset unused $node part so that a bad - // theme can not open a security hole. - $content = drupal_render($node->content); - if ($teaser) { - $node->teaser = $content; - unset($node->body); - } - else { - $node->body = $content; - unset($node->teaser); - } + $node->teaser = $node->body = drupal_render($node->content); // Allow modules to modify the fully-built node. - node_invoke_nodeapi($node, 'alter', $teaser, $page); + node_invoke_nodeapi($node, 'alter', $style, $options); + + if ($options['mark_read']) { + node_tag_new($node->nid); + } - return theme('node', $node, $teaser, $page); + return theme('node', $node, $style, $options); } /** * 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. +function node_prepare($node, $style = 'full', $options = array()) { $node->readmore = (strlen($node->teaser) < strlen($node->body)); - if ($teaser == FALSE) { - $node->body = check_markup($node->body, $node->format, FALSE); - } - else { - $node->teaser = check_markup($node->teaser, $node->format, FALSE); + switch ($options['body_field']) { + case NODE_BODY_HIDDEN: + $content = ''; + break; + + case NODE_BODY_TRIMMED: + $content = check_markup($node->teaser, $node->format, FALSE); + break; + + case NODE_BODY_FULL: + $content = check_markup($node->body, $node->format, FALSE); + break; } - $node->content['body'] = array( - '#value' => $teaser ? $node->teaser : $node->body, - '#weight' => 0, - ); + if (!empty($content)) { + $node->content['body'] = array( + '#value' => $content, + '#weight' => 0, + ); + } return $node; } @@ -801,21 +809,23 @@ function node_prepare($node, $teaser = F * An structured array containing the individual elements * of the node's body. */ -function node_build_content($node, $teaser = FALSE, $page = FALSE) { +function node_build_content($node, $style = 'full', $options = array()) { // Remove the delimiter (if any) that separates the teaser from the body. $node->body = isset($node->body) ? str_replace('', '', $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, $page); + $node = node_invoke($node, 'view', $style, $options); } else { - $node = node_prepare($node, $teaser); + $node = node_prepare($node, $style, $options); } - // Allow modules to make their own additions to the node. - node_invoke_nodeapi($node, 'view', $teaser, $page); + if (empty($options['skip_alter'])) { + // Allow modules to make their own additions to the node. + node_invoke_nodeapi($node, 'view', $style, $options); + } return $node; } @@ -824,18 +834,122 @@ function node_build_content($node, $teas * Generate a page displaying a single node, along with its comments. */ function node_show($node, $cid) { - $output = node_view($node, FALSE, TRUE); + $options = array( + 'page' => TRUE, + 'mark_read' => TRUE, + ); + $output = node_view($node, 'full', $options); if (function_exists('comment_render') && $node->comment) { $output .= comment_render($node, $cid); } - // Update the history table, stating that this user viewed this node. - node_tag_new($node->nid); - return $output; } + +function node_get_styles($requested_style = NULL) { + static $cache; + + if (empty($cache)) { + $cache = _node_style_defaults(); + + foreach ($cache as $style => $data) { + $cache[$style] += array('name' => NULL, 'description' => NULL, 'options' => array()); + } + + foreach (module_implements('node_styles') as $module) { + $styles = module_invoke($module, 'node_styles'); + if (!empty($styles)) { + foreach($styles as $style => $data) { + $data += array('name' => NULL, 'description' => NULL, 'options' => array()); + + if (empty($cache[$style])) { + $cache[$style] = $data; + } + else { + $cache[$style]['options'] = $data['options'] += $cache[$style]['options']; + } + } + } + } + + $default = $cache['default']; + unset($cache['default']); + + foreach ($cache as $style => $data) { + $cache[$style]['options'] += $default['options']; + } + } + + if (empty($requested_style)) { + return $cache; + } + elseif (array_key_exists($requested_style, $cache)) { + return $cache[$requested_style]; + } + else { + return $cache['default']; + } +} + + +function node_get_style_names() { + $styles = node_get_styles(); + foreach ($styles as $key => $style) { + $styles[$key] = $style['name']; + } + return $styles; +} + + +function node_get_style_options($style = 'full') { + $styles = node_get_styles(); + if (!empty($styles[$style])) { + return $styles[$style]['options']; + } +} + + +function _node_style_defaults() { + $styles['default']['options'] = array( + 'show_links' => TRUE, + 'page' => FALSE, + 'mark_read' => FALSE, + 'skip_alter' => FALSE, + 'body_field' => NODE_BODY_FULL, + ); + + $styles['full'] = array( + 'name' => t('Full'), + 'description' => t("The standard view of a node's full content."), + ); + + $styles['teaser'] = array( + 'name' => t('Teaser'), + 'description' => t("The trimmed version of a node for use in listings and summaries. The exact length can be configured on the %settings_url page.", array('%settings_url', l('admin/content/settings', 'Content settings'))), + 'options' => array( + 'body_field' => NODE_BODY_TRIMMED, + ), + ); + + $styles['feed'] = array( + 'name' => t('News Feed'), + 'description' => t("A streamlined version of a node meant for use in a content syndication feed, like RSS."), + 'options' => array( + 'show_links' => FALSE, + 'body_field' => variable_get('feed_item_length', NODE_BODY_TRIMMED), + ), + ); + + $styles['print'] = array( + 'name' => t('Print'), + 'description' => t('A printer-friendly version of a node.'), + ); + + return $styles; +} + /** * Implementation of hook_perm(). */ @@ -1851,59 +1965,44 @@ function node_feed($nodes = 0, $channel global $base_url, $language; if (!$nodes) { - $nodes = db_query_range(db_rewrite_sql('SELECT n.nid, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.created DESC'), 0, variable_get('feed_default_items', 10)); + $nodes = db_query_range(db_rewrite_sql('SELECT n.nid, n.title, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.created DESC'), 0, variable_get('feed_default_items', 10)); } - $item_length = variable_get('feed_item_length', 'teaser'); $namespaces = array('xmlns:dc="http://purl.org/dc/elements/1.1/"'); + $options = node_get_style_options('feed'); $items = ''; - while ($node = db_fetch_object($nodes)) { + while ($result = db_fetch_object($nodes)) { // Load the specified node: - $item = node_load($node->nid); - $link = url("node/$node->nid", array('absolute' => TRUE)); + $node = node_load($result->nid); - if ($item_length != 'title') { - $teaser = ($item_length == 'teaser') ? TRUE : FALSE; - - // Filter and prepare node teaser - if (node_hook($item, 'view')) { - $item = node_invoke($item, 'view', $teaser, FALSE); - } - else { - $item = node_prepare($item, $teaser); - } + $link = url("node/$node->nid", array('absolute' => TRUE)); + $item_title = check_plain($node->title); - // Allow modules to change $node->teaser before viewing. - node_invoke_nodeapi($item, 'view', $teaser, FALSE); + if ($options['body_field'] == NODE_BODY_HIDDEN) { + $item_text = ''; + } + else { + $node = node_build_content($node, 'feed', $options); + $item_text = drupal_render($node->content); } // Allow modules to add additional item fields and/or modify $item - $extra = node_invoke_nodeapi($item, 'rss item'); - $extra = array_merge($extra, array(array('key' => 'pubDate', 'value' => date('r', $item->created)), array('key' => 'dc:creator', 'value' => $item->name), array('key' => 'guid', 'value' => $item->nid .' at '. $base_url, 'attributes' => array('isPermaLink' => 'false')))); + $extra = node_invoke_nodeapi($node, 'rss item'); + $defaults = array( + array('key' => 'pubDate', 'value' => date('r', $node->created)), + array('key' => 'dc:creator', 'value' => $node->name), + array('key' => 'guid', 'value' => $node->nid .' at '. $base_url, 'attributes' => array('isPermaLink' => 'false')) + ); + + $extra = array_merge($extra, $defaults); foreach ($extra as $element) { if (isset($element['namespace'])) { $namespaces = array_merge($namespaces, $element['namespace']); } } - // Prepare the item description - switch ($item_length) { - case 'fulltext': - $item_text = $item->body; - break; - case 'teaser': - $item_text = $item->teaser; - if ($item->readmore) { - $item_text .= ''. l(t('read more'), 'node/'. $item->nid, array('absolute' => TRUE)) .'
'; - } - break; - case 'title': - $item_text = ''; - break; - } - - $items .= format_rss_item($item->title, $link, $item_text, $extra); + $items .= format_rss_item($item_title, $link, $item_text, $extra); } $channel_defaults = array( @@ -2295,12 +2394,12 @@ function theme_node_preview($node) { if (!empty($node->teaser) && !empty($node->body) && $node->teaser != $node->body) { 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. You can insert the delimiter "<!--break-->" (without the quotes) to fine-tune where your post gets split.')); $output .= '