Index: bookmarks.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/bookmarks/bookmarks.module,v
retrieving revision 1.36
diff -u -F^f -r1.36 bookmarks.module
--- bookmarks.module	21 Apr 2005 21:42:21 -0000	1.36
+++ bookmarks.module	25 Oct 2005 00:38:48 -0000
@@ -55,6 +55,12 @@ function bookmarks_menu($may_cache) {
   $items[] = array('path' => "bookmarks/$user->uid/add", 'title' => t('add bookmark'),
     'callback' => 'bookmarks_page', 'access' => $access, 'weight' => 10,
     'type' => MENU_LOCAL_TASK);
+  $items[] = array('path' => "bookmarks/$user->uid/group", 'title' => t('groups'),
+    'callback' => 'bookmarks_page', 'access' => $access, 'weight' => 15,
+    'type' => MENU_LOCAL_TASK);
+  $items[] = array('path' => "bookmarks/$user->uid/addgroup", 'title' => t('add group'),
+    'callback' => 'bookmarks_page', 'access' => $access, 'weight' => 20,
+    'type' => MENU_LOCAL_TASK);
 
   return $items;
 }
@@ -89,7 +95,7 @@ function theme_bookmarks_block() {
   // Do not let anonymous users have bookmarks, even if the admin decides this
   if ($user->uid != 0 && user_access('access bookmarks')) {
 
-    $result = db_query('SELECT url, title FROM {bookmarks} WHERE uid = %d ORDER BY title', $user->uid);
+    $result = db_query('SELECT url, title FROM {bookmarks_link} WHERE uid = %d ORDER BY title', $user->uid);
     $bookmarks = array();
     while ($data = db_fetch_object($result)) {
       $bookmarks[] = '<div class="icon">'. theme('bookmarks_delete', $data->url) .'</div>'. _bookmarks_get_link($data->url, $data->title);
@@ -176,7 +182,23 @@ function bookmarks_page() {
         $output .= bookmarks_form($edit);
       }
       break;
-
+	case 'group' :
+	  $title = 'All groups';
+	  $output = bookmarks_group_overview();
+	  break;
+    case 'addgroup':
+      $title = t('Create new group');
+	  $output = bookmarks_group_form($edit);
+	  break;
+    case 'groupedit':
+      $title = t('Edit group');
+      $output = ($gid = $_GET['gid']) ? bookmarks_group_form(bookmarks_group_load($gid)) : drupal_set_message(t('Group cannot be edited, because it is not in your list.'), 'error');
+      break;
+	case t('Save group'):
+	  $title = t('Groups');
+	  bookmarks_group_save($edit);
+	  drupal_goto("bookmarks/$user->uid/group");
+	  break;
     default:
       $output = bookmarks_overview();
   }
@@ -188,7 +210,7 @@ function bookmarks_page() {
 function bookmarks_delete($url) {
   global $user;
 
-  db_query("DELETE FROM {bookmarks} WHERE uid = %d AND url = '%s'", $user->uid, urldecode($url));
+  db_query("DELETE FROM {bookmarks_link} WHERE uid = %d AND url = '%s'", $user->uid, urldecode($url));
   drupal_set_message(t('Deleted bookmark.'));
 
   if ($_GET['block']) { //User has most likely clicked delete via their bookmark block. Show them their originating page.
@@ -202,6 +224,8 @@ function bookmarks_delete($url) {
 function bookmarks_form($edit = null) {
   $group = form_textfield(t('Title'), 'title', $edit['title'], 60, 128, null, null, true);
   $group .= form_textfield(t('URL'), 'url', $edit['url'], 60, 128, t('Enter the address of the page you want to bookmark. This can be an internal or external reference.'), null, true);
+  $groups = _bookmarks_group_child();
+  $group .= form_select(t('Parent node'), 'gid', $edit['gid'], $groups, null, 0, false, true);
   $group .= form_hidden('old_url', urlencode($edit['url']));
   $group .= form_submit(t('Save'));
   $form = form_group(t('Bookmark details'), $group);
@@ -209,9 +233,32 @@ function bookmarks_form($edit = null) {
   return form($form);
 }
 
+function bookmarks_group_form($edit = null) {
+  $group = form_textfield(t('Title'), 'title', $edit['title'], 60, 128, null, null, true);
+  $groups = _bookmarks_group_child();
+  if ($edit != NULL) {
+    $current_title = $groups[$edit['gid']];
+	$current_childs = array($edit['gid'] => $current_title);
+	_bookmarks_group_child_loop($edit['gid'], $current_childs, (strpos($current_title, '>') / 2));
+//	$group .= '<pre>' . print_r($groups,true)."\n".print_r($current_childs,true).'</pre>';
+	$groups = array_diff_assoc($groups, $current_childs);
+  }
+  $group .= form_select(t('Parent node'), 'group_parent_id', $edit['group_parent_id'], $groups, null, 0, false, true);
+  $group .= form_hidden('gid', $edit['gid']);
+  $group .= form_submit(t('Save group'));
+  $form = form_group(t('Group details'), $group);
+
+  return form($form);
+}
+
 function bookmarks_load($url) {
   global $user;
-  return db_fetch_array(db_query("SELECT * FROM {bookmarks} WHERE uid = %d AND url = '%s'", $user->uid, $url));
+  return db_fetch_array(db_query("SELECT * FROM {bookmarks_link} WHERE uid = %d AND url = '%s'", $user->uid, $url));
+}
+
+function bookmarks_group_load($gid) {
+  global $user;
+  return db_fetch_array(db_query("SELECT * FROM {bookmarks_group} WHERE uid = %d AND gid = %d", $user->uid, $gid));
 }
 
 function bookmarks_load_quicklink() {
@@ -257,20 +304,21 @@ function bookmarks_load_weblink($nid) {
 }
 
 function bookmarks_overview() {
-
   global $user;
 
   $header = array(
     array('data' => t('title'), 'field' => 'title', 'sort' => 'desc'),
     array('data' => t('link'), 'field' => 'url'),
+	array('data' => t('group'), 'field' => 'bookmarks_group.gid'),
     array('data' => t('operations'), 'colspan' => 2)
   );
-  $sql = 'SELECT url, title FROM {bookmarks} WHERE uid = '. db_escape_string($user->uid). tablesort_sql($header);
+  $sql = 'SELECT url, bookmarks_link.title AS title, bookmarks_group.title AS group_title FROM {bookmarks_link} LEFT JOIN {bookmarks_group} ON bookmarks_link.gid = bookmarks_group.gid WHERE bookmarks_link.uid = '. db_escape_string($user->uid). tablesort_sql($header);
   $result = pager_query($sql, 50);
 
   while ($data = db_fetch_object($result)) {
     $title = (strlen($data->url) > 50) ? substr($data->url, 0, 47). '...' : $data->url;
-    $rows[] = array($data->title, _bookmarks_get_link($data->url, $title), '&nbsp;'.l(t('edit'), "bookmarks/$user->uid/edit", null, 'url=' . urlencode($data->url)).' '. l(t('delete'), "bookmarks/$user->uid/delete", null, 'url=' . urlencode($data->url)));
+	$group_title = (strlen($data->group_title) > 50) ? substr($data->group_title, 0, 47). '...' : $data->group_title;
+    $rows[] = array($data->title, _bookmarks_get_link($data->url, $title), $group_title,'&nbsp;'.l(t('edit'), "bookmarks/$user->uid/edit", null, 'url=' . urlencode($data->url)).' '. l(t('delete'), "bookmarks/$user->uid/delete", null, 'url=' . urlencode($data->url)));
   }
 
   $pager = theme('pager', null, 50, 0, tablesort_pager());
@@ -282,20 +330,77 @@ function bookmarks_overview() {
   return $output;
 }
 
+function bookmarks_group_overview() {
+  global $user;
+
+  $header = array(
+    array('data' => t('title')),
+    array('data' => t('operations'), 'colspan' => 2)
+  );
+
+  $groups = _bookmarks_group_child();
+  
+  foreach ($groups as $key => $value) {
+    $title = (strlen($value) > 50) ? substr($value, 0, 47). '...' : $value;
+    $rows[] = array($value, '&nbsp;'.l(t('edit'), "bookmarks/$user->uid/groupedit", null, 'gid=' . $key).' '. l(t('delete'), "bookmarks/$user->uid/groupdelete", null, 'gid=' . $key));
+  }
+
+  $output .= (count($rows) == 0) ? t('You have no groups.') : theme('table', $header, $rows);
+  return $output;
+}
+
+function _bookmarks_group_child() {
+  global $user;
+  
+  $group_tree = array(0 => "[Top level]");
+  
+  $sql = 'SELECT gid, title FROM {bookmarks_group} WHERE group_parent_id = 0 AND uid = ' . db_escape_string($user->uid);
+  $result = db_query($sql);
+  while ($data = db_fetch_object($result)) {
+    $group_tree[$data->gid] = "$data->title";
+	_bookmarks_group_child_loop($data->gid, $group_tree, 0);
+  }
+  return $group_tree;
+}
+
+function _bookmarks_group_child_loop($gid, &$group_array, $i) {
+  global $user;
+
+  $i++;
+  $sql = 'SELECT gid, title FROM {bookmarks_group} WHERE group_parent_id = ' . $gid . ' AND uid = ' . db_escape_string($user->uid);
+  $result = db_query($sql);
+  while ($data = db_fetch_object($result)) {
+    $group_array[$data->gid] = str_repeat('-', 2*$i) . ">" . "$data->title";
+	_bookmarks_group_child_loop($data->gid, $group_array, $i);
+  }
+}
+
 function bookmarks_save($edit) {
   global $user;
 
   $edit['old_url'] = urldecode($edit['old_url']);
-  if ($edit['old_url'] && db_result(db_query("SELECT COUNT(uid) FROM {bookmarks} WHERE uid = %d AND url = '%s'", $user->uid, $edit['old_url']))) {
-    db_query("UPDATE {bookmarks} SET title = '%s', url = '%s' WHERE uid = %d AND url = '%s'", $edit['title'], $edit['url'], $user->uid, $edit['old_url']);
+  if ($edit['old_url'] && db_result(db_query("SELECT COUNT(uid) FROM {bookmarks_link} WHERE uid = %d AND url = '%s'", $user->uid, $edit['old_url']))) {
+    db_query("UPDATE {bookmarks_link} SET title = '%s', url = '%s', gid = %d WHERE uid = %d AND url = '%s'", $edit['title'], $edit['url'], $edit['gid'], $user->uid, $edit['old_url']);
     drupal_set_message(t('The bookmark has been updated.'));
   }
   else {
-    db_query("INSERT INTO {bookmarks} (uid, url, title) VALUES (%d, '%s', '%s')", $user->uid, $edit['url'], $edit['title']);
+    db_query("INSERT INTO {bookmarks_link} (uid, gid, url, title) VALUES (%d, %d, '%s', '%s')", $user->uid, $edit['gid'], $edit['url'], $edit['title']);
     drupal_set_message(t('The link has been added to your bookmarks.'));
   }
 }
 
+function bookmarks_group_save($edit) {
+  global $user;
+  
+  if (db_result(db_query("SELECT COUNT(gid) FROM {bookmarks_group} WHERE gid = %d AND uid = %d", $edit['gid'], $user->uid))) {
+    db_query("UPDATE {bookmarks_group} SET title = '%s', group_parent_id = %d WHERE uid = %d AND gid = %d", $edit['title'], $edit['group_parent_id'], $user->uid, $edit['gid']);
+    drupal_set_message(t('The group has been updated.'));
+  } else {
+    db_query("INSERT INTO {bookmarks_group} (uid, group_parent_id, title) VALUES (%d, %d, '%s')", $user->uid, $edit['group_parent_id'], $edit['title']);
+    drupal_set_message(t('The group has been added to your bookmarks.'));
+  }
+}
+
 function bookmarks_validate($edit) {
   $errors = array();
 
Index: bookmarks.mysql
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/bookmarks/bookmarks.mysql,v
retrieving revision 1.2
diff -u -F^f -r1.2 bookmarks.mysql
--- bookmarks.mysql	11 Oct 2003 18:46:36 -0000	1.2
+++ bookmarks.mysql	25 Oct 2005 00:38:48 -0000
@@ -1,7 +1,16 @@
-CREATE TABLE bookmarks (
-  uid INT UNSIGNED NOT NULL,
-  url VARCHAR(128) NOT NULL,
-  title VARCHAR(128) NOT NULL
+CREATE TABLE bookmarks_group (
+  gid int(10) unsigned NOT NULL auto_increment,
+  group_parent_id int(10) unsigned NOT NULL default '0',
+  uid int(10) unsigned NOT NULL default '0',
+  title varchar(128) NOT NULL,
+  PRIMARY KEY  (`gid`)
+);
+
+CREATE TABLE bookmarks_link (
+  uid int(10) unsigned NOT NULL default '0',
+  gid int(10) unsigned NOT NULL default '0',
+  url varchar(128) NOT NULL,
+  title varchar(128) NOT NULL,
+  KEY uid (uid)
 );
 
-ALTER TABLE bookmarks ADD INDEX (uid);
