Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.186
diff -u -F^f -r1.186 form.inc
--- includes/form.inc	6 Apr 2007 13:27:20 -0000	1.186
+++ includes/form.inc	7 Apr 2007 03:39:15 -0000
@@ -1452,6 +1452,18 @@ 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 summary'), t('Split summary at cursor'))), 'setting');
+    drupal_add_js(array('teaserCheckbox' => array($element['#id'] => $element['#teaser_checkbox'])), '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';
Index: misc/drupal.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/drupal.js,v
retrieving revision 1.29
diff -u -F^f -r1.29 drupal.js
--- misc/drupal.js	14 Oct 2006 02:39:48 -0000	1.29
+++ misc/drupal.js	7 Apr 2007 03:39:15 -0000
@@ -200,6 +200,26 @@
   return uri.indexOf('?q=') ? item : item.replace('%26', '%2526').replace('%23', '%2523');
 };
 
+/**
+ * Get the text selection in a textarea.
+ */
+Drupal.getSelection = function (element) {
+  if (typeof(element.selectionStart) != 'number' && 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';
Index: misc/teaser.js
===================================================================
RCS file: misc/teaser.js
diff -N misc/teaser.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/teaser.js	7 Apr 2007 03:39:15 -0000
@@ -0,0 +1,80 @@
+// $Id$
+
+/**
+ * Auto-attach for teaser behaviour.
+ *
+ * Note: depends on resizable textareas.
+ */
+Drupal.teaserAttach = function() {
+  $('textarea.teaser:not(.joined)').each(function() {
+    var teaser = $(this).addClass('joined');
+
+    // Move teaser textarea before body, and remove its form-item wrapper.
+    var body = $('#'+ Drupal.settings.teaser[this.id]);
+    var checkbox = $('#'+ Drupal.settings.teaserCheckbox[this.id]).parent();
+    var parent = teaser[0].parentNode;
+    $(body).before(teaser);
+    $(parent).remove();
+
+    function trim(text) {
+      return text.replace(/^\s+/g, '').replace(/\s+$/g, '');
+    }
+
+    // Join the teaser back to the body.
+    function join_teaser() {
+      if (teaser.val()) {
+        body.val(trim(teaser.val()) +'\r\n\r\n'+ trim(body.val()));
+      }
+      // Hide and disable teaser
+      $(teaser).attr('disabled', 'disabled');
+      $(teaser).parent().slideUp('fast');
+      // Change label
+      $(this).val(Drupal.settings.teaserButton[1]);
+      // Show separate teaser checkbox
+      $(checkbox).hide();
+    }
+
+    // Split the teaser from the body.
+    function split_teaser() {
+      body[0].focus();
+      var selection = Drupal.getSelection(body[0]);
+      var split = selection.start;
+      var text = body.val();
+
+      // Note: using val() fails sometimes. jQuery bug?
+      teaser[0].value = trim(text.slice(0, split));
+      body[0].value = trim(text.slice(split));
+      // Reveal and enable teaser
+      $(teaser).attr('disabled', '');
+      $(teaser).parent().slideDown('fast');
+      // Change label
+      $(this).val(Drupal.settings.teaserButton[0]);
+      // Show separate teaser checkbox
+      $(checkbox).show();
+    }
+
+    // Add split/join button.
+    var button = $('<div class="teaser-button-wrapper"><input type="button" class="teaser-button" /></div>');
+    var include = $('#'+ this.id.substring(0, this.id.length - 2) +'include');
+    $(include).parent().parent().before(button);
+
+    // Extract the teaser from the body, if set. Otherwise, stay in joined mode.
+    var text = body.val().split('<!--break-->', 2);
+    if (text.length == 2) {
+      teaser[0].value = trim(text[0]);
+      body[0].value = trim(text[1]);
+      $(teaser).attr('disabled', '');
+      $('input', button).val(Drupal.settings.teaserButton[0]).toggle(join_teaser, split_teaser);
+    }
+    else {
+      $(teaser).hide();
+      $('input', button).val(Drupal.settings.teaserButton[1]).toggle(split_teaser, join_teaser);
+      $(checkbox).hide();
+    }
+    
+  });
+}
+
+if (Drupal.jsEnabled) {
+  $(document).ready(Drupal.teaserAttach);
+}
Index: misc/textarea.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/textarea.js,v
retrieving revision 1.12
diff -u -F^f -r1.12 textarea.js
--- misc/textarea.js	15 Feb 2007 07:10:11 -0000	1.12
+++ misc/textarea.js	7 Apr 2007 03:39:15 -0000
@@ -7,6 +7,12 @@
     $(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';
 
Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.255
diff -u -F^f -r1.255 block.module
--- modules/block/block.module	6 Apr 2007 13:27:20 -0000	1.255
+++ modules/block/block.module	7 Apr 2007 03:39:15 -0000
@@ -595,8 +595,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'],
@@ -607,7 +607,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;
 }
Index: modules/blog/blog.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/blog/blog.module,v
retrieving revision 1.277
diff -u -F^f -r1.277 blog.module
--- modules/blog/blog.module	27 Mar 2007 05:13:53 -0000	1.277
+++ modules/blog/blog.module	7 Apr 2007 03:39:15 -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;
 }
 
Index: modules/book/book.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.module,v
retrieving revision 1.415
diff -u -F^f -r1.415 book.module
--- modules/book/book.module	6 Apr 2007 13:27:21 -0000	1.415
+++ modules/book/book.module	7 Apr 2007 03:39:15 -0000
@@ -232,13 +232,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',
Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.391
diff -u -F^f -r1.391 forum.module
--- modules/forum/forum.module	6 Apr 2007 13:27:21 -0000	1.391
+++ modules/forum/forum.module	7 Apr 2007 03:39:15 -0000
@@ -423,8 +423,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;
 }
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.797
diff -u -F^f -r1.797 node.module
--- modules/node/node.module	6 Apr 2007 13:27:22 -0000	1.797
+++ modules/node/node.module	7 Apr 2007 03:39:15 -0000
@@ -171,6 +171,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) {
@@ -1876,7 +1898,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')) {
@@ -2216,6 +2247,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:
@@ -2241,7 +2276,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>';
@@ -2958,6 +2993,43 @@ 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',
+    '#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));
+
+  $form['format'] = filter_form($node->format);
+
+  return $form;
+}
+/**
  * Implementation of hook_form().
  */
 function node_content_form($node) {
@@ -2975,13 +3047,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;
Index: modules/system/system.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.css,v
retrieving revision 1.23
diff -u -F^f -r1.23 system.css
--- modules/system/system.css	2 Mar 2007 09:40:13 -0000	1.23
+++ modules/system/system.css	7 Apr 2007 03:39:15 -0000
@@ -358,6 +358,31 @@
 }
 
 /*
+** Teaser splitter
+*/
+.joined + .grippie {
+  height: 5px;
+  background-position: center 1px;
+  margin-bottom: -2px;
+}
+div.teaser-button-wrapper {
+  float: right;
+  padding-right: 5%;
+  margin: 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 {
Index: themes/bluemarine/bluemarine.info
===================================================================
RCS file: themes/bluemarine/bluemarine.info
diff -N themes/bluemarine/bluemarine.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ themes/bluemarine/bluemarine.info	7 Apr 2007 03:39:15 -0000
@@ -0,0 +1,3 @@
+; $Id$
+name = Bluemarine
+description = Designed by Kristjan Jansen.
Index: themes/chameleon/chameleon.info
===================================================================
RCS file: themes/chameleon/chameleon.info
diff -N themes/chameleon/chameleon.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ themes/chameleon/chameleon.info	7 Apr 2007 03:39:15 -0000
@@ -0,0 +1,9 @@
+; $Id$
+name = Chameleon
+description = Designed by Dries Buytaert.
+regions[left] = Left sidebar
+regions[right] = Right sidebar
+features[] = logo
+features[] = favicon
+features[] = name
+features[] = slogan
Index: themes/chameleon/marvin/marvin.info
===================================================================
RCS file: themes/chameleon/marvin/marvin.info
diff -N themes/chameleon/marvin/marvin.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ themes/chameleon/marvin/marvin.info	7 Apr 2007 03:39:15 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Marvin
+description = Designed by Dries Buytaert.
+regions[left] = Left sidebar
+regions[right] = Right sidebar
Index: themes/garland/garland.info
===================================================================
RCS file: themes/garland/garland.info
diff -N themes/garland/garland.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ themes/garland/garland.info	7 Apr 2007 03:39:15 -0000
@@ -0,0 +1,3 @@
+; $Id$
+name = Garland
+description = Designed by Stefan Nagtegaal and Steven Wittens.
Index: themes/garland/minnelli/minnelli.info
===================================================================
RCS file: themes/garland/minnelli/minnelli.info
diff -N themes/garland/minnelli/minnelli.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ themes/garland/minnelli/minnelli.info	7 Apr 2007 03:39:15 -0000
@@ -0,0 +1,3 @@
+; $Id$
+name = Minnelli
+description = Designed by Stefan Nagtegaal and Steven Wittens.
Index: themes/pushbutton/pushbutton.info
===================================================================
RCS file: themes/pushbutton/pushbutton.info
diff -N themes/pushbutton/pushbutton.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ themes/pushbutton/pushbutton.info	7 Apr 2007 03:39:15 -0000
@@ -0,0 +1,3 @@
+; $Id$
+name = Pushbutton
+description = Designed by Robert Castelo.
