Index: modules/node/content_types.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/content_types.inc,v
retrieving revision 1.84
diff -u -r1.84 content_types.inc
--- modules/node/content_types.inc	29 Jul 2009 06:39:34 -0000	1.84
+++ modules/node/content_types.inc	3 Aug 2009 13:48:23 -0000
@@ -16,7 +16,7 @@
   $rows = array();
 
   foreach ($names as $key => $name) {
-    $type = $types[$key]; 
+    $type = $types[$key];
     if (node_hook($type->type, 'form')) {
       $type_url_str = str_replace('_', '-', $type->type);
       $row = array(theme('node_admin_overview', $name, $type));
@@ -37,7 +37,7 @@
   if (empty($rows)) {
     $rows[] = array(array('data' => t('No content types available. <a href="@link">Add content type</a>.', array('@link' => url('admin/structure/types/add'))), 'colspan' => '5', 'class' => 'message'));
   }
-  
+
   $build['node_table'] = array(
     '#theme' => 'table',
     '#header' => $header,
@@ -182,12 +182,23 @@
     '#description' => t('Enable the <em>submitted by Username on date</em> text.'),
   );
   $form['display']['teaser_length'] = array(
-    '#type' => 'select', 
+    '#type' => 'select',
     '#title' => t('Length of trimmed posts'),
     '#default_value' => variable_get('teaser_length_' . $type->type, 600),
     '#options' => drupal_map_assoc(array(0, 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000), '_node_characters'),
     '#description' => t("The maximum number of characters used in the trimmed version of content.")
   );
+  $form['display']['teaser_read_more_location'] = array(
+    '#type' => 'radios',
+    '#title' => t('Read more link'),
+    '#default_value' => variable_get('teaser_read_more_location_' . $type->type, 'inline'),
+    '#options' => array(
+      'hidden' => t('Do not display a read more link for this content type'),
+      'inline' => t('Display the read more link inline as part of the trimmed post'),
+      'link' => t('Display the read more link in the links section, underneath the trimmed post'),
+    ),
+    '#description' => t('Determine the location of "read more" links which allow a user to click through to the full post from the trimmed post.'),
+  );
   $form['old_type'] = array(
     '#type' => 'value',
     '#value' => $type->type,
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1090
diff -u -r1.1090 node.module
--- modules/node/node.module	31 Jul 2009 19:01:02 -0000	1.1090
+++ modules/node/node.module	3 Aug 2009 13:48:25 -0000
@@ -469,6 +469,7 @@
       );
       $field = field_create_field($field);
     }
+
     if (empty($instance)) {
       $instance = array(
         'field_name' => 'body',
@@ -492,11 +493,25 @@
           ),
         ),
       );
+
+      if (variable_get('teaser_read_more_location_' . $type->type, 'inline') == 'inline') {
+        $instance['settings']['read_more'] = t('Read more');
+      }
+      else {
+        $instance['settings']['read_more'] = '';
+      }
+
       field_create_instance($instance);
     }
     else {
       $instance['label'] = $type->body_label;
       $instance['settings']['display_summary'] = TRUE;
+      if (variable_get('teaser_read_more_location_' . $type->type, 'inline') == 'inline') {
+        $instance['settings']['read_more'] = t('Read more');
+      }
+      else {
+        $instance['settings']['read_more'] = '';
+      }
       field_update_instance($instance);
     }
   }
@@ -1145,11 +1160,13 @@
   // to know when a teaser view is different than a full view.
   $links = array();
   if ($build_mode == 'teaser') {
-    $links['node_readmore'] = array(
-      'title' => t('Read more'),
-      'href' => 'node/' . $node->nid,
-      'attributes' => array('rel' => 'tag', 'title' => strip_tags($node->title))
-    );
+    if (variable_get('teaser_read_more_location_' . $node->type, 'inline') == 'link') {
+      $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(
     '#theme' => 'links',
@@ -1601,14 +1618,16 @@
   $links = array();
 
   if ($type == 'node') {
-    if ($build_mode == 'teaser') {
-      $links['node_read_more'] = array(
-        'title' => t('Read more'),
-        'href' => "node/$node->nid",
-        // The title attribute gets escaped when the links are processed, so
-        // there is no need to escape here.
-        'attributes' => array('title' => t('Read the rest of !title.', array('!title' => $node->title)))
-      );
+    if (variable_get('teaser_read_more_location_' . $type->type, 'inline') == 'link') {
+      if ($build_mode == 'teaser') {
+        $links['node_read_more'] = array(
+          'title' => t('Read more'),
+          'href' => "node/$node->nid",
+          // The title attribute gets escaped when the links are processed, so
+          // there is no need to escape here.
+          'attributes' => array('title' => t('Read the rest of !title.', array('!title' => $node->title)))
+        );
+      }
     }
   }
 
Index: modules/field/modules/text/text.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.module,v
retrieving revision 1.16
diff -u -r1.16 text.module
--- modules/field/modules/text/text.module	1 Aug 2009 06:03:12 -0000	1.16
+++ modules/field/modules/text/text.module	3 Aug 2009 13:48:23 -0000
@@ -32,6 +32,9 @@
     'field_formatter_text_summary_or_trimmed' => array(
       'arguments' => array('element' => NULL),
     ),
+    'read_more' => array(
+      'arguments' => array('link' => NULL, 'inline' => FALSE),
+    ),
   );
 }
 
@@ -68,7 +71,7 @@
       'label' => t('Long text and summary'),
       'description' => t('This field stores long text in the database along with optional summary text.'),
       'settings' => array('max_length' => ''),
-      'instance_settings' => array('text_processing' => 1, 'display_summary' => 0),
+      'instance_settings' => array('text_processing' => 1, 'display_summary' => 0, 'read_more' => ''),
       'default_widget' => 'text_textarea_with_summary',
       'default_formatter' => 'text_summary_or_trimmed',
     ),
@@ -302,12 +305,53 @@
   $instance = field_info_instance($element['#field_name'], $element['#bundle']);
 
   if (!empty($element['#item']['safe_summary'])) {
-    return $element['#item']['safe_summary'];
+    $summary =  $element['#item']['safe_summary'];
   }
   else {
     $size = variable_get('teaser_length_' . $element['#bundle'], 600);
-    return text_summary($element['#item']['safe'], $instance['settings']['text_processing'] ? $element['#item']['format'] : NULL, $size);
+    $summary = text_summary($element['#item']['safe'], $instance['settings']['text_processing'] ? $element['#item']['format'] : NULL, $size);
   }
+
+  if (!empty($instance['settings']['read_more'])) {
+    // Define the tags that allow the read more link to be inserted right before their
+    // closing tag. If the summary ends with any other tag, the read more link will be
+    // appended at the end of the summary instead.
+    $inline_tags = array('p');
+
+    $htmlDom = DOMDocument::loadHTML($summary);
+
+    // The result of DOMDocument::saveXML($bodyNode) is a partial (X)HTML document.
+    // We only need what is inside the body tag.
+    $bodyNode = $htmlDom->getElementsByTagName('body')->item(0);
+
+    // Fetch the last element in the summary.
+    $node = $bodyNode->lastChild;
+
+    // Determine how to insert the read more link into the summary. Inline means the
+    // the link will be inserted before the ending tag of the last element in the summary,
+    // otherwise the link will be appended to the summary as a stand-alone element.
+    $inline = in_array($node->tagName, $inline_tags);
+
+    // Create and theme the read more link.
+    $link = $htmlDom->createDocumentFragment();
+    $link->appendXml(theme('read_more', l($instance['settings']['read_more'], 'node/' . $element['#object']->nid), $inline));
+
+    // Add the read more link to the summary.
+    if ($inline) {
+      $node->appendChild($link);
+    }
+    else {
+      $bodyNode->appendChild($link);
+    }
+
+    // DOM manipulation treats our fragment as a full document. Extract the contents of
+    // the <body> element, as we are only interested in that.
+    if (preg_match("|^<body[^>]*>(.*)</body>$|s", $htmlDom->saveXML($bodyNode), $matches)) {
+      $summary = $matches[1];
+    }
+  }
+
+  return $summary;
 }
 
 /**
@@ -744,3 +788,7 @@
   }
 }
 
+function theme_read_more($link, $inline = FALSE) {
+  $element = ($inline ? 'span' : 'div');
+  return ' <'. $element .' class="read-more">' . $link . '</'. $element .'>';
+}
\ No newline at end of file
