diff --git modules/field/field.module modules/field/field.module index 163f448..6707ce4 100644 --- modules/field/field.module +++ modules/field/field.module @@ -1010,6 +1010,41 @@ } /** + * Check if any fields should trigger a readmore. + * + * This will parse through all renderable fields in the renederable array + * and check for #readmore property. If #readmore is TRUE, then we will + * return TRUE to signify that the caller should include a readmore link. + * + * @param $elements + * An array of renderable fields + * @return + * True if a single element has #readmore set to TRUE, otherwise FALSE. + */ +function field_has_read_more($elements){ + // Early-return if the user does not have access. + if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) { + return FALSE; + } + + // Return if #read_more is set on this element. + if (!empty($elements['#read_more']) && $elements['#read_more']) { + return TRUE; + } + + // Iterate through children. + foreach (element_children($elements) as $key) { + if (field_has_read_more($elements[$key])) { + // A child element has #read_more set to TRUE. + return TRUE; + } + } + + // Neither this element, nor any child elements had #read_more set. + return FALSE; +} + +/** * Theme preprocess function for theme_field() and field.tpl.php. * * @see theme_field() diff --git modules/field/modules/text/text.module modules/field/modules/text/text.module index 89c605c..d62095c 100644 --- modules/field/modules/text/text.module +++ modules/field/modules/text/text.module @@ -262,23 +262,34 @@ case 'text_trimmed': foreach ($items as $delta => $item) { $output = _text_sanitize($instance, $langcode, $item, 'value'); + $readmore = FALSE; if ($display['type'] == 'text_trimmed') { - $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL, $display['settings']['trim_length']); + $trimmed_output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL, $display['settings']['trim_length']); + if ($trimmed_output != $output){ + $readmore = TRUE; + } + $output = $trimmed_output; } - $element[$delta] = array('#markup' => $output); + $element[$delta] = array('#markup' => $output, '#read_more' => $readmore); } break; case 'text_summary_or_trimmed': foreach ($items as $delta => $item) { + $readmore = FALSE; if (!empty($item['summary'])) { + $readmore = TRUE; $output = _text_sanitize($instance, $langcode, $item, 'summary'); } else { $output = _text_sanitize($instance, $langcode, $item, 'value'); - $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL, $display['settings']['trim_length']); + $trimmed_output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL, $display['settings']['trim_length']); + if ($trimmed_output != $output){ + $readmore = TRUE; + } + $output = $trimmed_output; } - $element[$delta] = array('#markup' => $output); + $element[$delta] = array('#markup' => $output, '#read_more' => $readmore); } break; diff --git modules/node/node.module modules/node/node.module index c052f4b..7d44c38 100644 --- modules/node/node.module +++ modules/node/node.module @@ -1370,7 +1370,9 @@ '#pre_render' => array('drupal_pre_render_links'), '#attributes' => array('class' => array('links', 'inline')), ); - if ($view_mode == 'teaser') { + // Only show read more in teaser view_mode and if a field has #read_more + // set to TRUE. + if ($view_mode == 'teaser' && field_has_read_more($node->content)) { $node_title_stripped = strip_tags($node->title); $links['node-readmore'] = array( 'title' => t('Read more about @title', array('@title' => $node_title_stripped)), diff --git modules/node/node.test modules/node/node.test index 8a871c0..18856bd 100644 --- modules/node/node.test +++ modules/node/node.test @@ -2146,3 +2146,141 @@ } } } + +/** + * Test the "Read more" link for teasers. + */ +class NodeTeaserReadMoreTest extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Teaser read more', + 'description' => 'Test the "Read more" link for teasers.', + 'group' => 'Node', + ); + } + + function setUp() { + parent::setUp(); + + $web_user = $this->drupalCreateUser(array( + 'create article content', + 'create page content', + 'administer filters', + filter_permission_name(filter_format_load('filtered_html')), + filter_permission_name(filter_format_load('full_html')), + 'administer content types', + 'access administration pages', + 'bypass node access', + 'administer taxonomy', + 'administer nodes', + )); + $this->drupalLogin($web_user); + } + + /** + * Create a node where teaser and full view are equal. The "Read more" link + * must not appear. + */ + function testTeaserIsComplete() { + $node1 = $this->drupalCreateNode(array( + 'type' => 'article', + 'promote' => 1, + 'body' => array( + LANGUAGE_NONE => array( + '0' => array( + 'value' => 'body_' . $this->randomName(32), + ), + ), + ), + ) ); + + $this->drupalGet('node'); + $this->assertText($node1->title, t('Node title appears on the default listing.')); + $this->assertText($node1->body['und'][0]['value'], t('Node body appears on the default listing.')); + // Confirm that promoted node appears without the read more link in the + // default node listing. + $this->assertNoText('Read more', t('"Read more" does not appear in the default listing.')); + } + + /** + * Create a node with a tag where teaser and full view are equal. The + * "Read more" link must not appear. + */ + function testTeaserIsCompleteWithTag() { + // Post an article with a taxonomy term. + $langcode = LANGUAGE_NONE; + $tag = 'tag_' . $this->randomName(8); + $edit = array(); + $edit['title'] = 'title_' . $this->randomName(8); + $edit["body[$langcode][0][value]"] = 'body_' . $this->randomName(32); + $edit["field_tags[$langcode]"] = $tag; + $edit['promote'] = 1; + $this->drupalPost('node/add/article', $edit, t('Save')); + $node1 = $this->drupalGetNodeByTitle($edit['title']); + + $this->drupalGet('node'); + $this->assertText($node1->title, t('Node title appears on the default listing.')); + $this->assertText($node1->body['und'][0]['value'], t('Node body appears on the default listing.')); + $this->assertText($tag, t('Tag appears on the default listing.')); + // Confirm that promoted node appears without the read more link in the + // default node listing. + $this->assertNoText('Read more', t('"Read more" does not appear in the default listing.')); + } + + /** + * Create a node with a summary. The "Read more" link must be set. + */ + function testTeaserSummary() { + $body = 'body_' . $this->randomName(32); + $summary = 'summary_' . $this->randomName(32); + $node1 = $this->drupalCreateNode(array( + 'type' => 'article', + 'promote' => 1, + 'body' => array( + LANGUAGE_NONE => array( + '0' => array( + 'value' => $body, + 'summary' => $summary, + ), + ), + ), + ) ); + + $this->drupalGet('node'); + $this->assertText($node1->title, t('Node title appears on the default listing.')); + $this->assertText($summary, t('The summary text appears in the default listing.')); + $this->assertNoText($body, t('The body text does not appear in the default listing.')); + // Confirm that promoted node appears with the read more link in the + // default node listing. + $this->assertText('Read more', t('"Read more" appears in the default listing.')); + } + + /** + * Create a node with trimmed body. The "Read more" link must be set. + */ + function testTeaserTrimmed() { + $node1 = $this->drupalCreateNode(array( + 'type' => 'article', + 'promote' => 1, + 'body' => array( + LANGUAGE_NONE => array( + '0' => array( + 'value' => 'teaserbody', + // Set text format to Full HTML due to bug http://drupal.org/node/881006 + 'format' => 'full_html', + ), + ), + ), + ) ); + + $this->drupalGet('node'); + $this->assertText($node1->title, t('Node title appears on the default listing.')); + $this->assertText('teaser', t('The teaser text appears in the default listing.')); + $this->assertNoText('body', t('The body text does not appear in the default listing.')); + // Confirm that promoted node appears with the read more link in the + // default node listing. + $this->assertText('Read more', t('"Read more" appears in the default listing.')); + } + +} \ No newline at end of file