? vertical_tabs-323112-53_0.patch
? vertical_tabs_-323112-54.patch
? vertical_tabs_-323112-55.patch
? vertical_tabs_-323112-56.patch
? vertical_tabs_-323112-57.patch
? vtabs_b.patch
? sites/default/files
? sites/default/settings.php
Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.320
diff -u -p -r1.320 form.inc
--- includes/form.inc	3 Feb 2009 18:55:29 -0000	1.320
+++ includes/form.inc	21 Feb 2009 01:30:35 -0000
@@ -877,6 +877,19 @@ function form_builder($form_id, $form, &
   if (isset($form['#input']) && $form['#input']) {
     _form_builder_handle_input_element($form_id, $form, $form_state, $complete_form);
   }
+  if (!isset($form['#id'])) {
+    $form['#id'] = form_clean_id('edit-' . implode('-', $form['#parents']));
+  }
+  // Allow for elements to expand to multiple elements, e.g., radios,
+  // checkboxes and files.
+  if (isset($form['#process']) && !$form['#processed']) {
+    foreach ($form['#process'] as $process) {
+      if (drupal_function_exists($process)) {
+        $form = $process($form, isset($edit) ? $edit : NULL, $form_state, $complete_form);
+      }
+    }
+    $form['#processed'] = TRUE;
+  }
   $form['#defaults_loaded'] = TRUE;
 
   // We start off assuming all form elements are in the correct order.
@@ -984,9 +997,6 @@ function _form_builder_handle_input_elem
     }
     array_unshift($form['#parents'], $name);
   }
-  if (!isset($form['#id'])) {
-    $form['#id'] = form_clean_id('edit-' . implode('-', $form['#parents']));
-  }
 
   if (!empty($form['#disabled'])) {
     $form['#attributes']['disabled'] = 'disabled';
@@ -1055,16 +1065,6 @@ function _form_builder_handle_input_elem
       }
     }
   }
-  // Allow for elements to expand to multiple elements, e.g., radios,
-  // checkboxes and files.
-  if (isset($form['#process']) && !$form['#processed']) {
-    foreach ($form['#process'] as $process) {
-      if (drupal_function_exists($process)) {
-        $form = $process($form, isset($edit) ? $edit : NULL, $form_state, $complete_form);
-      }
-    }
-    $form['#processed'] = TRUE;
-  }
   form_set_value($form, $form['#value'], $form_state);
 }
 
@@ -1499,6 +1499,7 @@ function theme_fieldset($element) {
       $element['#attributes']['class'] .= ' collapsed';
     }
   }
+  $element['#attributes']['id'] = $element['#id'];
 
   return '<fieldset' . drupal_attributes($element['#attributes']) . '>' . ($element['#title'] ? '<legend>' . $element['#title'] . '</legend>' : '') . (isset($element['#description']) && $element['#description'] ? '<div class="description">' . $element['#description'] . '</div>' : '') . (!empty($element['#children']) ? $element['#children'] : '') . (isset($element['#value']) ? $element['#value'] : '') . "</fieldset>\n";
 }
@@ -1929,6 +1930,50 @@ function form_process_ahah($element) {
 }
 
 /**
+ * Add vertical tabs to the page.
+ */
+function form_process_vertical_tabs(&$element) {
+  static $js_added = array();
+  $tab_added = FALSE;
+  // If the element has a vertical tab, and it is visible, then add it to the JavaScript.
+  if (isset($element['#vertical_tab']) && $element['#vertical_tab'] && (isset($element['#access']) ? $element['#access'] : TRUE)) {
+    // If it's not a full array (with the keys "callback" and "arguments"), find out what it is.
+    if (!is_array($element['#vertical_tab'])) {
+      // If it's a string, convert it.
+      if (is_string($element['#vertical_tab'])) {
+        $element['#vertical_tab'] = array('callback' => $element['#vertical_tab']);
+      }
+      // Otherwise, there's no callback.
+      else {
+        $element['#vertical_tab'] = array();
+      }
+    }
+    if (!isset($js_added[$element['#id']])) {
+      // Add the tab to the JavaScript.
+      $js_added[$element['#id']] = array(
+        'name' => (isset($element['#title']) ? $element['#title'] : ''),
+        'callback' => (isset($element['#vertical_tab']['callback']) ? $element['#vertical_tab']['callback'] : ''),
+        'arguments' => (isset($element['#vertical_tab']['arguments']) ? $element['#vertical_tab']['arguments'] : array()),
+      );
+    }
+    else {
+      $tab_added = TRUE;
+    }
+    // If there's more than one tab, then add the JavaScript and add the previous element.
+    if (count($js_added) == 2) {
+      drupal_add_js(array('verticalTabs' => $js_added), 'setting');
+      drupal_add_js('misc/vertical-tabs.js', array('weight' => 0));
+      drupal_add_css('misc/vertical-tabs.css');
+    }
+    // Otherwise, just add the current element.
+    elseif (count($js_added) > 2 && !$tab_added) {
+      drupal_add_js(array('verticalTabs' => array($element['#id'] => $js_added[$element['#id']])), 'setting');
+    }
+  }
+  return $element;
+}
+
+/**
  * Format a checkbox.
  *
  * @param $element
Index: misc/drupal.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/drupal.js,v
retrieving revision 1.50
diff -u -p -r1.50 drupal.js
--- misc/drupal.js	18 Feb 2009 13:46:52 -0000	1.50
+++ misc/drupal.js	21 Feb 2009 01:30:35 -0000
@@ -1,6 +1,6 @@
 // $Id: drupal.js,v 1.50 2009/02/18 13:46:52 webchick Exp $
 
-var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {} };
+var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {}, 'verticalTabs': {} };
 
 // Allow other JavaScript libraries to use $.
 jQuery.noConflict();
Index: misc/vertical-tabs.css
===================================================================
RCS file: misc/vertical-tabs.css
diff -N misc/vertical-tabs.css
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/vertical-tabs.css	21 Feb 2009 01:30:35 -0000
@@ -0,0 +1,101 @@
+/* $Id */
+
+.vertical-tabs-list .description {
+  display: block;
+}
+
+/* Border style of tabs and content */
+div.vertical-tabs-div,
+ul.vertical-tabs-list {
+  border: 1px solid #ccc;
+}
+
+/* Make space for the tabs on each side */
+.vertical-tabs {
+  margin-left: 180px;
+  margin-right: 5%;
+}
+
+/* Set the background image on the tabs and content */
+.vertical-tabs,
+.vertical-tabs ul.vertical-tabs-list {
+  background: #fff;
+}
+
+/* Position and layout of tabs container */
+.vertical-tabs ul.vertical-tabs-list { 
+  width: 179px;
+  float: left;
+  margin: 0 0 0 -180px;
+  border-right: 0px;
+  z-index: 1;
+  border-bottom: 0;
+  list-style-type: none;
+  list-style-image: none;
+  padding: 0;
+  display: inline;
+}
+
+
+/* Reset LIs which probably have awkward layout inherited from tabs */
+.vertical-tabs ul.vertical-tabs-list li {
+  float: none;
+  margin: 0;
+  padding: 0;
+  background-image: none;
+}
+
+/* Layout of each tab */
+.vertical-tabs ul.vertical-tabs-list a {
+  display: block;
+  margin: 0;
+  padding: .4em .3em .1em .6em;
+  background: #fafafa;
+  text-align: left;
+  font-weight: normal;
+  border-bottom: 1px solid #ccc;
+}
+
+.vertical-tabs ul.vertical-tabs-list a.vertical-tabs-nodescription {
+  padding-bottom: .4em;
+}
+
+.vertical-tabs ul.vertical-tabs-list .description {
+  padding: 0;
+  line-height: normal;
+  min-height: 0;
+  white-space: normal;
+}
+
+.vertical-tabs ul.vertical-tabs-list a {
+  border-right: 1px solid #ccc;
+}
+
+/* Hover state of tabs */
+.vertical-tabs ul.vertical-tabs-list a:hover {
+  text-decoration: none;
+  cursor: pointer;
+}
+
+.vertical-tabs ul.vertical-tabs-list a:focus {
+  outline: none;
+}
+
+/* Selected tab */
+.vertical-tabs ul.vertical-tabs-list li.selected a {
+  background: transparent none;
+  color: black;
+  border-right: 0;
+}
+
+/* Reset some important elements of each panel */
+.vertical-tabs .vertical-tabs-div {
+  margin: 0;
+  padding: .5em;
+  margin-top: -1px;
+  margin-left: -1px;
+  background: transparent none;
+}
+
+.buttons {
+  clear: both;
+}
Index: misc/vertical-tabs.js
===================================================================
RCS file: misc/vertical-tabs.js
diff -N misc/vertical-tabs.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/vertical-tabs.js	21 Feb 2009 01:30:35 -0000
@@ -0,0 +1,83 @@
+// $Id$
+
+(function($) {
+
+/**
+ * Main vertical tabs behavior - create the vertical tabs.
+ */
+Drupal.behaviors.verticalTabs = {
+  attach: function() {
+    // Make sure that the vertical tabs list hasn't already been constructed.
+    if (!$('.vertical-tabs-list').size()) {
+      // Create the first <div> and the <ul> in it.
+      var ul = $('<div class="vertical-tabs"><ul class="vertical-tabs-list"></ul></div>').find('ul');
+      // Iterate through each vertical tab that needs to be created, and create it.
+      $.each(Drupal.settings.verticalTabs, function(k, v) {
+        var description = '', cssClass = 'vertical-tabs-list-' + k;
+        // If there's a callback, that means there's a description, so add the <span>.
+        // However, we don't actually add the description, because verticalTabsReload already does it for us.
+        // Otherwise add the CSS class denoting there is no description, so we can style it potentially differently.
+        if (v.callback && Drupal.verticalTabs[v.callback]) {
+          description = ' <span class="description"></span>';
+        }
+        else {
+          cssClass += ' vertical-tabs-nodescription';
+        }
+        // Add the <li> itself.
+        ul.append($('<li><a href="#' + k + '" class="' + cssClass + '">'+ v.name + description +'</a></li>')
+            // Add the click action to the link.
+            .find('a')
+            .bind('click', function() {
+              // Add the "selected" class to the clicked tab, and remove it from the other tabs.
+              $(this).parent().addClass('selected').siblings().removeClass('selected');
+              // Show this tab and hide all the other tabs.
+              $('.vertical-tabs-' + k).show().siblings('.vertical-tabs-div').hide();
+              return false;
+            })
+            .end())
+          .end()
+          // Add the fieldset itself.
+          .append($('#' + k + ' .fieldset-wrapper')
+            .addClass('vertical-tabs-div')
+            .addClass('vertical-tabs-' + k))
+          .find('ul');
+        $('#' + k).remove();
+      });
+      // Put the <ul> in, but before the buttons.
+      ul.end().insertBefore('.buttons');
+      // Calculate the hight of the highest thing.
+      var max = $('.vertical-tabs ul').height();
+      $('.vertical-tabs-div').each(function() {
+        max = Math.max(max, $(this).height());
+      });
+      $('.vertical-tabs-div').height(max).hide();
+      // Show and select the first tab.
+      $('.vertical-tabs-div:first').show();
+      $('.vertical-tabs ul li:first').addClass('selected');
+      $('.vertical-tabs-div input, .vertical-tabs-div textarea, .vertical-tabs-div select').change(Drupal.behaviors.verticalTabsReload.attach);
+    }
+  }
+};
+
+/**
+ * Reload the vertical tab descriptions.
+ */
+Drupal.behaviors.verticalTabsReload = {
+  attach: function() {
+    // Iterate through all the tabs.
+    $.each(Drupal.settings.verticalTabs, function(k, v) {
+      // If there is a callback, then call it and stick the result in .description.
+      if (v.callback && Drupal.verticalTabs[v.callback]) {
+        $('.vertical-tabs ul.vertical-tabs-list a.vertical-tabs-list-'+ k +' span.description').html(Drupal.verticalTabs[v.callback].apply(this, v.arguments));
+      }
+    });
+    // Recalculate heights.
+    var max = $('.vertical-tabs ul').height();
+    $('.vertical-tabs-div').each(function() {
+      max = Math.max(max, $(this).height());
+    });
+    $('.vertical-tabs-div').height(max);
+  }
+}
+
+})(jQuery);
Index: modules/book/book.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.css,v
retrieving revision 1.8
diff -u -p -r1.8 book.css
--- modules/book/book.css	19 Dec 2008 15:42:26 -0000	1.8
+++ modules/book/book.css	21 Feb 2009 01:30:35 -0000
@@ -36,7 +36,7 @@
   margin-bottom: 0;
 }
 #edit-book-bid-wrapper .description {
-  clear: both;
+  clear: none;
 }
 #book-admin-edit select {
   margin-right: 24px;
Index: modules/book/book.js
===================================================================
RCS file: modules/book/book.js
diff -N modules/book/book.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/book/book.js	21 Feb 2009 01:30:35 -0000
@@ -0,0 +1,21 @@
+// $Id$
+
+(function($) {
+
+Drupal.verticalTabs.nodeFormBook = function() {
+  var text = $('#edit-book-bid option[selected]').text();
+  if (text == Drupal.t('<none>')) {
+    return Drupal.t('Not in book');
+  }
+  else if (text == Drupal.t('<create a new book>')) {
+    return Drupal.t('New book');
+  }
+  return text;
+}
+if (Drupal.jsEnabled) {
+  $(document).ready(function() {
+    $('#edit-book-pick-book').css('display', 'none');
+  });
+}
+
+})(jQuery);
\ No newline at end of file
Index: modules/book/book.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.module,v
retrieving revision 1.486
diff -u -p -r1.486 book.module
--- modules/book/book.module	18 Feb 2009 13:46:53 -0000	1.486
+++ modules/book/book.module	21 Feb 2009 01:30:36 -0000
@@ -415,7 +415,7 @@ function _book_parent_select($book_link)
 function _book_add_form_elements(&$form, $node) {
   // Need this for AJAX.
   $form['#cache'] = TRUE;
-  drupal_add_js("if (Drupal.jsEnabled) { jQuery(function() { jQuery('#edit-book-pick-book').css('display', 'none'); }); }", 'inline');
+  drupal_add_js(drupal_get_path('module', 'book') .'/book.js');
 
   $form['book'] = array(
     '#type' => 'fieldset',
@@ -425,6 +425,7 @@ function _book_add_form_elements(&$form,
     '#collapsed' => TRUE,
     '#tree' => TRUE,
     '#attributes' => array('class' => 'book-outline-form'),
+    '#vertical_tab' => 'nodeFormBook',
   );
   foreach (array('menu_name', 'mlid', 'nid', 'router_path', 'has_children', 'options', 'module', 'original_bid', 'parent_depth_limit') as $key) {
     $form['book'][$key] = array(
Index: modules/comment/comment-node-form.js
===================================================================
RCS file: modules/comment/comment-node-form.js
diff -N modules/comment/comment-node-form.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/comment/comment-node-form.js	21 Feb 2009 01:30:36 -0000
@@ -0,0 +1,15 @@
+// $Id$
+
+(function($) {
+
+Drupal.verticalTabs.nodeFormComment = function() {
+  var input = $('.vertical-tabs-edit-comment-settings input[checked]');
+  if (!input.size()) {
+    input = $('.vertical-tabs-edit-comment-settings input')[Drupal.settings.nodeForm.comment];
+  }
+  else {
+    return $(input).parent().text().replace(/^\s*(.*)\s*$/, '$1');
+  }
+}
+
+})(jQuery);
\ No newline at end of file
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.693
diff -u -p -r1.693 comment.module
--- modules/comment/comment.module	18 Feb 2009 15:19:55 -0000	1.693
+++ modules/comment/comment.module	21 Feb 2009 01:30:36 -0000
@@ -574,6 +574,8 @@ function comment_form_node_type_form_alt
 function comment_form_alter(&$form, $form_state, $form_id) {
   if (!empty($form['#node_edit_form'])) {
     $node = $form['#node'];
+    drupal_add_js(drupal_get_path('module', 'comment') . '/comment-node-form.js');
+    drupal_add_js(array('nodeForm' => array('comment' => $node->comment)), 'setting');
     $form['comment_settings'] = array(
       '#type' => 'fieldset',
       '#access' => user_access('administer comments'),
@@ -581,6 +583,7 @@ function comment_form_alter(&$form, $for
       '#collapsible' => TRUE,
       '#collapsed' => TRUE,
       '#weight' => 30,
+      '#vertical_tab' => 'nodeFormComment',
     );
     $form['comment_settings']['comment'] = array(
       '#type' => 'radios',
Index: modules/menu/menu.js
===================================================================
RCS file: modules/menu/menu.js
diff -N modules/menu/menu.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/menu/menu.js	21 Feb 2009 01:30:36 -0000
@@ -0,0 +1,14 @@
+// $Id$
+
+(function($) {
+
+Drupal.verticalTabs.nodeFormMenu = function() {
+  if ($('#edit-menu-link-title').val()) {
+    return $('#edit-menu-link-title').val();
+  }
+  else {
+    return Drupal.t('Not in menu');
+  }
+}
+
+})(jQuery);
\ No newline at end of file
Index: modules/menu/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v
retrieving revision 1.178
diff -u -p -r1.178 menu.module
--- modules/menu/menu.module	31 Jan 2009 16:56:00 -0000	1.178
+++ modules/menu/menu.module	21 Feb 2009 01:30:36 -0000
@@ -388,6 +388,7 @@ function _menu_parent_depth_limit($item)
  */
 function menu_form_alter(&$form, $form_state, $form_id) {
   if (!empty($form['#node_edit_form'])) {
+    drupal_add_js(drupal_get_path('module', 'menu') . '/menu.js');
     // Note - doing this to make sure the delete checkbox stays in the form.
     $form['#cache'] = TRUE;
 
@@ -398,7 +399,8 @@ function menu_form_alter(&$form, $form_s
       '#collapsible' => TRUE,
       '#collapsed' => FALSE,
       '#tree' => TRUE,
-      '#weight' => -2,
+      '#weight' => 5,
+      '#vertical_tab' => 'nodeFormMenu',
       '#attributes' => array('class' => 'menu-item-form'),
     );
     $item = $form['#node']->menu;
Index: modules/node/node.js
===================================================================
RCS file: modules/node/node.js
diff -N modules/node/node.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/node/node.js	21 Feb 2009 01:30:36 -0000
@@ -0,0 +1,42 @@
+// $Id$
+
+(function($) {
+
+Drupal.verticalTabs.nodeFormRevision = function() {
+  var val = $('#edit-revision').attr('checked');
+  if (val) {
+    return Drupal.t('Create new revision');
+  }
+  else {
+    return Drupal.t('Don\'t create new revision');
+  }
+}
+
+Drupal.verticalTabs.nodeFormAuthoring = function() {
+  var name = $('#edit-name').val(), date = $('#edit-date').val();
+  if (date) {
+    return Drupal.t('By @name on @date', { '@name': name, '@date': date });
+  }
+  else {
+    return Drupal.t('By @name', { '@name': name });
+  }
+}
+
+Drupal.verticalTabs.nodeFormPublishingOptions = function() {
+  var vals = [];
+  if ($('#edit-status').attr('checked')) {
+    vals.push(Drupal.t('Published'));
+  }
+  if ($('#edit-promote').attr('checked')) {
+    vals.push(Drupal.t('Promoted to front page'));
+  }
+  if ($('#edit-sticky').attr('checked')) {
+    vals.push(Drupal.t('Sticky on top of lists'));
+  }
+  if (vals.join(', ') == '') {
+    return Drupal.t('None');
+  }
+  return vals.join(', ');
+}
+
+})(jQuery);
\ No newline at end of file
Index: modules/node/node.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.pages.inc,v
retrieving revision 1.55
diff -u -p -r1.55 node.pages.inc
--- modules/node/node.pages.inc	13 Feb 2009 02:22:09 -0000	1.55
+++ modules/node/node.pages.inc	21 Feb 2009 01:30:36 -0000
@@ -97,6 +97,7 @@ function node_object_prepare(&$node) {
  * Generate the node add/edit form array.
  */
 function node_form(&$form_state, $node) {
+  drupal_add_js(drupal_get_path('module', 'node') . '/node.js');
   global $user;
 
   if (isset($form_state['node'])) {
@@ -156,6 +157,7 @@ function node_form(&$form_state, $node) 
       // Collapsed by default when "Create new revision" is unchecked
       '#collapsed' => !$node->revision,
       '#weight' => 20,
+      '#vertical_tab' => 'nodeFormRevision',
     );
     $form['revision_information']['revision'] = array(
       '#access' => user_access('administer nodes'),
@@ -179,6 +181,7 @@ function node_form(&$form_state, $node) 
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
     '#weight' => 90,
+    '#vertical_tab' => 'nodeFormAuthoring',
   );
   $form['author']['name'] = array(
     '#type' => 'textfield',
@@ -208,6 +211,7 @@ function node_form(&$form_state, $node) 
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
     '#weight' => 95,
+    '#vertical_tab' => 'nodeFormPublishingOptions',
   );
   $form['options']['status'] = array(
     '#type' => 'checkbox',
@@ -234,8 +238,11 @@ function node_form(&$form_state, $node) 
   }
 
   // Add the buttons.
-  $form['buttons'] = array();
-  $form['buttons']['#weight'] = 100;
+  $form['buttons'] = array(
+    '#weight' => 100,
+    '#prefix' => '<div class="buttons">',
+    '#suffix' => '</div>',
+  );
   $form['buttons']['submit'] = array(
     '#type' => 'submit',
     '#access' => !variable_get('node_preview', 0) || (!form_get_errors() && isset($form_state['node_preview'])),
Index: modules/path/path.js
===================================================================
RCS file: modules/path/path.js
diff -N modules/path/path.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/path/path.js	21 Feb 2009 01:30:36 -0000
@@ -0,0 +1,16 @@
+// $Id$
+
+(function($) {
+
+Drupal.verticalTabs.nodeFormPath = function() {
+  var path = $('#edit-path-1').val();
+
+  if (path) {
+    return Drupal.t('Alias: @alias', { '@alias': path });
+  }
+  else {
+    return Drupal.t('No alias');
+  }
+}
+
+})(jQuery);
Index: modules/path/path.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.module,v
retrieving revision 1.152
diff -u -p -r1.152 path.module
--- modules/path/path.module	9 Dec 2008 11:30:24 -0000	1.152
+++ modules/path/path.module	21 Feb 2009 01:30:36 -0000
@@ -188,6 +188,7 @@ function path_nodeapi_delete($node) {
  */
 function path_form_alter(&$form, $form_state, $form_id) {
   if (!empty($form['#node_edit_form'])) {
+    drupal_add_js(drupal_get_path('module', 'path') .'/path.js');
     $path = isset($form['#node']->path) ? $form['#node']->path : NULL;
     $form['path'] = array(
       '#type' => 'fieldset',
@@ -196,6 +197,7 @@ function path_form_alter(&$form, $form_s
       '#collapsed' => empty($path),
       '#access' => user_access('create url aliases'),
       '#weight' => 30,
+      '#vertical_tab' => 'nodeFormPath',
     );
     $form['path']['path'] = array(
       '#type' => 'textfield',
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.667
diff -u -p -r1.667 system.module
--- modules/system/system.module	11 Feb 2009 05:33:18 -0000	1.667
+++ modules/system/system.module	21 Feb 2009 01:30:37 -0000
@@ -419,7 +419,7 @@ function system_elements() {
     '#collapsible' => FALSE,
     '#collapsed' => FALSE,
     '#value' => NULL,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('form_process_ahah', 'form_process_vertical_tabs'),
     '#theme_wrapper' => 'fieldset',
   );
 
Index: modules/upload/upload.js
===================================================================
RCS file: modules/upload/upload.js
diff -N modules/upload/upload.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/upload/upload.js	21 Feb 2009 01:30:37 -0000
@@ -0,0 +1,15 @@
+// $Id$
+
+(function($) {
+
+Drupal.verticalTabs.nodeFormAttachments = function() {
+  var size = $('#upload-attachments tbody tr').size();
+  if (size) {
+    return Drupal.formatPlural(size, '1 attachment', '@count attachments');
+  }
+  else {
+    return Drupal.t('No attachments');
+  }
+}
+
+})
Index: modules/upload/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.module,v
retrieving revision 1.228
diff -u -p -r1.228 upload.module
--- modules/upload/upload.module	20 Feb 2009 10:26:35 -0000	1.228
+++ modules/upload/upload.module	21 Feb 2009 01:30:37 -0000
@@ -224,6 +224,8 @@ function upload_form_alter(&$form, $form
   if (!empty($form['#node_edit_form'])) {
     $node = $form['#node'];
     if (variable_get("upload_$node->type", TRUE)) {
+      drupal_add_js(drupal_get_path('module', 'upload') .'/upload.js');
+
       // Attachments fieldset
       $form['attachments'] = array(
         '#type' => 'fieldset',
@@ -235,6 +237,7 @@ function upload_form_alter(&$form, $form
         '#prefix' => '<div class="attachments">',
         '#suffix' => '</div>',
         '#weight' => 30,
+        '#vertical_tab' => 'nodeFormAttachments',
       );
 
       // Wrapper for fieldset contents (used by ahah.js).
