=== modified file 'includes/form.inc'
--- includes/form.inc	2007-03-27 05:13:53 +0000
+++ includes/form.inc	2007-03-29 00:00:56 +0000
@@ -1450,6 +1450,17 @@ function theme_form($element) {
  */
 function theme_textarea($element) {
   $class = array('form-textarea');
+
+  // Add teaser behaviour (must come before resizable)
+  if (!empty($element['#teaser'])) {
+    drupal_add_js('misc/teaser.js');
+    // Note: arrays are merged in drupal_get_js().
+    drupal_add_js(array('teaserButton' => array(t('Join teaser'), t('Split teaser at cursor'))), 'setting');
+    drupal_add_js(array('teaser' => array($element['#id'] => $element['#teaser'])), 'setting');
+    $class[] = 'teaser';
+  }
+
+  // Add resizable behaviour
   if ($element['#resizable'] !== FALSE) {
     drupal_add_js('misc/textarea.js');
     $class[] = 'resizable';

=== modified file 'misc/drupal.js'
--- misc/drupal.js	2006-10-14 02:39:48 +0000
+++ misc/drupal.js	2007-03-29 00:00:56 +0000
@@ -200,6 +200,26 @@ Drupal.encodeURIComponent = function (it
   return uri.indexOf('?q=') ? item : item.replace('%26', '%2526').replace('%23', '%2523');
 };
 
+/**
+ * Get the text selection in a textarea.
+ */
+Drupal.getSelection = function (element) {
+  if (document.selection) {
+    // The current selection
+    var range1 = document.selection.createRange();
+    var range2 = range1.duplicate();
+    // Select all text.
+    range2.moveToElementText(element);
+    // Now move 'dummy' end point to end point of original range.
+    range2.setEndPoint('EndToEnd', range1);
+    // Now we can calculate start and end points.
+    var start = range2.text.length - range1.text.length;
+    var end = start + range1.text.length;
+    return { 'start': start, 'end': end };
+  }
+  return { 'start': element.selectionStart, 'end': element.selectionEnd };
+}
+
 // Global Killswitch on the <html> element
 if (Drupal.jsEnabled) {
   document.documentElement.className = 'js';

=== modified file 'misc/textarea.js'
--- misc/textarea.js	2007-02-15 07:10:11 +0000
+++ misc/textarea.js	2007-03-29 00:00:56 +0000
@@ -7,6 +7,12 @@ Drupal.textareaAttach = function() {
     $(this).wrap('<div class="resizable-textarea"></div>')
       .parent().append($('<div class="grippie"></div>').mousedown(startDrag));
 
+    // Inherit visibility
+    if ($(this).is(':hidden')) {
+      $(this).parent().hide();
+      $(this).show();
+    }
+
     var grippie = $('div.grippie', $(this).parent())[0];
     grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px';
 

=== modified file 'modules/block/block.module'
--- modules/block/block.module	2007-03-27 05:13:53 +0000
+++ modules/block/block.module	2007-03-29 00:00:56 +0000
@@ -584,8 +584,8 @@ function block_box_form($edit = array())
     '#required' => TRUE,
     '#weight' => -19,
   );
-  $form['body_filter']['#weight'] = -17;
-  $form['body_filter']['body'] = array(
+  $form['body_field']['#weight'] = -17;
+  $form['body_field']['body'] = array(
     '#type' => 'textarea',
     '#title' => t('Block body'),
     '#default_value' => $edit['body'],
@@ -596,7 +596,7 @@ function block_box_form($edit = array())
   if (!isset($edit['format'])) {
     $edit['format'] = FILTER_FORMAT_DEFAULT;
   }
-  $form['body_filter']['format'] = filter_form($edit['format'], -16);
+  $form['body_field']['format'] = filter_form($edit['format'], -16);
 
   return $form;
 }

=== modified file 'modules/blog/blog.module'
--- modules/blog/blog.module	2007-03-27 05:13:53 +0000
+++ modules/blog/blog.module	2007-03-29 00:00:56 +0000
@@ -211,8 +211,7 @@ function blog_form(&$node) {
   }
 
   $form['title'] = array('#type' => 'textfield', '#title' => check_plain($type->title_label), '#required' => TRUE, '#default_value' => !empty($node->title) ? $node->title : NULL, '#weight' => -5);
-  $form['body_filter']['body'] = array('#type' => 'textarea', '#title' => check_plain($type->body_label), '#default_value' => !empty($node->body) ? $node->title : NULL, '#rows' => 20, '#required' => TRUE);
-  $form['body_filter']['filter'] = filter_form($node->format);
+  $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
   return $form;
 }
 

=== modified file 'modules/book/book.module'
--- modules/book/book.module	2007-03-27 05:13:53 +0000
+++ modules/book/book.module	2007-03-29 00:00:56 +0000
@@ -215,13 +215,8 @@ function book_form(&$node) {
     '#default_value' => $node->title,
     '#weight' => -5,
   );
-  $form['body_filter']['body'] = array('#type' => 'textarea',
-    '#title' => check_plain($type->body_label),
-    '#default_value' => $node->body,
-    '#rows' => 20,
-    '#required' => TRUE,
-  );
-  $form['body_filter']['format'] = filter_form($node->format);
+
+  $form['body_field'] = node_body_field($node, $type->body_label, 1);
 
   if (user_access('administer nodes')) {
     $form['weight'] = array('#type' => 'weight',

=== modified file 'modules/forum/forum.module'
--- modules/forum/forum.module	2007-03-27 05:13:53 +0000
+++ modules/forum/forum.module	2007-03-29 00:00:56 +0000
@@ -400,8 +400,7 @@ function forum_form(&$node) {
     $form['shadow'] = array('#type' => 'checkbox', '#title' => t('Leave shadow copy'), '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
   }
 
-  $form['body_filter']['body'] = array('#type' => 'textarea', '#title' => check_plain($type->body_label), '#default_value' => !empty($node->body) ? $node->body : '', '#rows' => 20, '#required' => TRUE);
-  $form['body_filter']['format'] = filter_form($node->format);
+  $form['body_field'] = node_body_field($node, $type->body_label, 1);
 
   return $form;
 }

=== modified file 'modules/node/node.module'
--- modules/node/node.module	2007-03-27 05:13:53 +0000
+++ modules/node/node.module	2007-03-29 00:02:24 +0000
@@ -139,6 +139,28 @@ function node_mark($nid, $timestamp) {
 }
 
 /**
+ * See if the user used JS to submit a teaser.
+ */
+function node_teaser_js(&$form, $form_values) {
+  // Glue the teaser to the body.
+  if (isset($form['#post']['teaser_js'])) {
+    if (trim($form_values['teaser_js'])) {
+      // Space the teaser from the body
+      $body = trim($form_values['teaser_js']) ."\r\n<!--break-->\r\n". trim($form_values['body']);
+    }
+    else {
+      // Empty teaser, no spaces.
+      $body = '<!--break-->'. $form_values['body'];
+    }
+    // Pass value onto preview/submit
+    form_set_value($form['body'], $body);
+    // Pass value back onto form
+    $form['body']['#value'] = $body;
+  }
+  return $form;
+}
+
+/**
  * Automatically generate a teaser for a node body in a given format.
  */
 function node_teaser($body, $format = NULL) {
@@ -1845,7 +1867,16 @@ function node_submit($node) {
   // Auto-generate the teaser, but only if it hasn't been set (e.g. by a
   // module-provided 'teaser' form item).
   if (!isset($node->teaser)) {
-    $node->teaser = isset($node->body) ? node_teaser($node->body, isset($node->format) ? $node->format : NULL) : '';
+    if (isset($node->body)) {
+      $node->teaser = node_teaser($node->body, isset($node->format) ? $node->format : NULL);
+      // 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));
+      }
+    }
+    else {
+      $node->teaser = '';
+    }
   }
 
   if (user_access('administer nodes')) {
@@ -2185,6 +2216,10 @@ function node_preview($node) {
     // 'teaser' form item).
     if (!isset($node->teaser)) {
       $node->teaser = empty($node->body) ? '' : node_teaser($node->body, $node->format);
+       // 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:
@@ -2210,7 +2245,7 @@ function node_preview($node) {
 function theme_node_preview($node) {
   $output = '<div class="preview">';
   if ($node->teaser && $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 "&lt;!--break--&gt;" (without the quotes) to fine-tune where your post gets split.'));
+    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 .= node_view(drupal_clone($node), 1, FALSE, 0);
     $output .= '<h3>'. t('Preview full version') .'</h3>';
@@ -2928,6 +2963,42 @@ function node_content_access($op, $node)
 }
 
 /**
+ * Return a node body field, with format and teaser.
+ */
+function node_body_field(&$node, $label, $word_count) {
+
+  // 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'));
+
+  $form['teaser_js'] = array(
+    '#type' => 'textarea',
+    '#rows' => 10,
+    '#teaser' => 'edit-body',
+    '#disabled' => TRUE);
+
+  $form['teaser_include'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Include teaser in body'),
+    '#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));
+
+  $form['format'] = filter_form($node->format);
+
+  return $form;
+}
+/**
  * Implementation of hook_form().
  */
 function node_content_form($node) {
@@ -2945,13 +3016,7 @@ function node_content_form($node) {
   }
 
   if ($type->has_body) {
-    $form['body_filter']['body'] = array(
-      '#type' => 'textarea',
-      '#title' => check_plain($type->body_label),
-      '#default_value' => $node->body,
-      '#rows' => 20,
-      '#required' => ($type->min_word_count > 0));
-    $form['body_filter']['format'] = filter_form($node->format);
+    $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
   }
 
   return $form;

=== modified file 'modules/system/system.css'
--- modules/system/system.css	2007-03-02 09:40:13 +0000
+++ modules/system/system.css	2007-03-29 00:00:56 +0000
@@ -358,6 +358,31 @@ html.js .resizable-textarea textarea {
 }
 
 /*
+** Teaser splitter
+*/
+.joined + .grippie {
+  height: 5px;
+  background-position: center 1px;
+  margin-bottom: -2px;
+}
+input.teaser-button {
+  float: right;
+  margin-right: 5%;
+  margin-top: 0;
+}
+.teaser-checkbox div.form-item {
+  float: right;
+  margin: 0 5% 0 0;
+  padding: 0;
+}
+textarea.teaser {
+  display: none;
+}
+html.js .no-js {
+  display: none;
+}
+
+/*
 ** Progressbar styles
 */
 .progress {

