Index: modules/book/book.install =================================================================== RCS file: /cvs/drupal/drupal/modules/book/book.install,v retrieving revision 1.6 diff -u -p -r1.6 book.install --- modules/book/book.install 1 Sep 2006 07:40:08 -0000 1.6 +++ modules/book/book.install 25 May 2007 03:01:07 -0000 @@ -9,25 +9,25 @@ function book_install() { case 'mysql': case 'mysqli': db_query("CREATE TABLE {book} ( - vid int unsigned NOT NULL default '0', + mlid int unsigned NOT NULL default '0', nid int unsigned NOT NULL default '0', - parent int NOT NULL default '0', - weight tinyint NOT NULL default '0', - PRIMARY KEY (vid), + bookid int unsigned NOT NULL default '0', + child_type varchar(32) NOT NULL default '', + PRIMARY KEY (mlid), KEY nid (nid), - KEY parent (parent) + KEY bookid (bookid) ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); break; case 'pgsql': db_query("CREATE TABLE {book} ( - vid int_unsigned NOT NULL default '0', + mlid int_unsigned NOT NULL default '0', nid int_unsigned NOT NULL default '0', - parent int NOT NULL default '0', - weight smallint NOT NULL default '0', - PRIMARY KEY (vid) + bookid int_unsigned NOT NULL default '0', + child_type varchar(32) NOT NULL default '', + PRIMARY KEY (mlid) )"); db_query("CREATE INDEX {book}_nid_idx ON {book} (nid)"); - db_query("CREATE INDEX {book}_parent_idx ON {book} (parent)"); + db_query("CREATE INDEX {book}_bookid_idx ON {book} (bookid)"); break; } } @@ -36,5 +36,78 @@ function book_install() { * Implementation of hook_uninstall(). */ function book_uninstall() { + // TODO: delete menu links db_query('DROP TABLE {book}'); + +} + +/** + * Save old data and create new table. + */ +function book_update_6001() { + $ret = array(); + + if (db_result(db_query("SELECT COUNT(*) FROM {node_type} WHERE type = 'book'"))) { + $ret[] = update_sql("UPDATE {node_type} SET custom = 1, modified = 1, locked = 0 WHERE type = 'book'"); + } + switch ($GLOBALS['db_type']) { + case 'mysql': + case 'mysqli': + $ret[] = update_sql("CREATE TABLE {book}_t ( + nid int unsigned NOT NULL default '0', + parent int NOT NULL default '0', + weight tinyint NOT NULL default '0', + PRIMARY KEY (nid), + KEY parent (parent) + ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); + break; + case 'pgsql': + $ret[] = update_sql("CREATE TABLE {book}_t ( + nid int_unsigned NOT NULL default '0', + parent int NOT NULL default '0', + weight smallint NOT NULL default '0', + PRIMARY KEY (nid) + )"); + db_query("CREATE INDEX {book}_parent_idx ON {book} (parent)"); + break; + } + } + + $ret[] = update_sql("INSERT INTO {book}_t (nid, parent, weight) SELECT nid, parent, weight FROM {book} b INNER JOIN {node} n ON n.vid = b.vid"); + $ret[] = update_sql("DROP TABLE {book}"); + switch ($GLOBALS['db_type']) { + case 'mysql': + case 'mysqli': + $ret[] = update_sql("CREATE TABLE {book} ( + mlid int unsigned NOT NULL default '0', + nid int unsigned NOT NULL default '0', + bookid int unsigned NOT NULL default '0', + child_type varchar(32) NOT NULL default '', + PRIMARY KEY (mlid), + KEY nid (nid), + KEY bookid (bookid) + ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); + break; + case 'pgsql': + $ret[] = update_sql("CREATE TABLE {book} ( + mlid int_unsigned NOT NULL default '0', + nid int_unsigned NOT NULL default '0', + bookid int_unsigned NOT NULL default '0', + child_type varchar(32) NOT NULL default '', + PRIMARY KEY (mlid) + )"); + $ret[] = update_sql("CREATE INDEX {book}_nid_idx ON {book} (nid)"); + $ret[] = update_sql("CREATE INDEX {book}_bookid_idx ON {book} (bookid)"); + break; + } + + return $ret; +} + +/** + * Transfer old data into new table and menu system. + */ +function book_update_6002() { + $ret = array(); + } Index: modules/book/book.module =================================================================== RCS file: /cvs/drupal/drupal/modules/book/book.module,v retrieving revision 1.420 diff -u -p -r1.420 book.module --- modules/book/book.module 14 May 2007 13:43:34 -0000 1.420 +++ modules/book/book.module 25 May 2007 03:01:07 -0000 @@ -6,18 +6,6 @@ * Allows users to collaboratively author a book. */ -/** - * Implementation of hook_node_info(). - */ -function book_node_info() { - return array( - 'book' => array( - 'name' => t('Book page'), - 'module' => 'book', - 'description' => t("A book is a collaborative writing effort: users can collaborate writing the pages of the book, positioning the pages in the right order, and reviewing or modifying pages previously written. So when you have some information to share or when you read a page of the book and you didn't like it, or if you think a certain page could have been written better, you can do something about it."), - ) - ); -} /** * Implementation of hook_theme() @@ -40,35 +28,7 @@ function book_theme() { * Implementation of hook_perm(). */ function book_perm() { - return array('outline posts in books', 'create book pages', 'create new books', 'edit book pages', 'edit own book pages', 'see printer-friendly version'); -} - -/** - * Implementation of hook_access(). - */ -function book_access($op, $node) { - global $user; - - if ($op == 'create') { - // Only registered users can create book pages. Given the nature - // of the book module this is considered to be a good/safe idea. - return user_access('create book pages'); - } - - if ($op == 'update') { - // Only registered users can update book pages. Given the nature - // of the book module this is considered to be a good/safe idea. - // One can only update a book page if there are no suggested updates - // of that page waiting for approval. That is, only updates that - // don't overwrite the current or pending information are allowed. - - if (user_access('edit book pages') || ($node->uid == $user->uid && user_access('edit own book pages'))) { - return TRUE; - } - else { - // do nothing. node-access() will determine further access - } - } + return array('outline posts in books', 'create new books', 'see printer-friendly version'); } /** @@ -78,12 +38,13 @@ function book_link($type, $node = NULL, $links = array(); - if ($type == 'node' && isset($node->parent)) { + if ($type == 'node' && isset($node->bookid)) { if (!$teaser) { - if (book_access('create', $node) && $node->status == 1) { + if (node_access('create', $node->child_type) && $node->status == 1) { $links['book_add_child'] = array( 'title' => t('Add child page'), - 'href' => "node/add/book/parent/$node->nid" + 'href' => "node/add/". $node->child_type + 'query' => "parent=". $node->nid; ); } if (user_access('see printer-friendly version')) { @@ -146,7 +107,7 @@ function book_menu() { function _book_outline_access($node) { // Only add the outline-tab for non-book pages: - return user_access('outline posts in books') && $node && ($node->type != 'book'); + return user_access('outline posts in books') && node_access('view', $node); } function book_init() { @@ -168,20 +129,15 @@ function book_block($op = 'list', $delta else if ($op == 'view') { // Only display this block when the user is browsing a book: if (arg(0) == 'node' && is_numeric(arg(1))) { - $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, b.parent FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.nid = %d'), arg(1)); - if (db_num_rows($result) > 0) { - $node = db_fetch_object($result); - - $path = book_location($node); - $path[] = $node; - - $expand = array(); - foreach ($path as $key => $node) { - $expand[] = $node->nid; + $node = node_load(arg(1)); + $bookid = isset($node->bookid) ? $node->bookid : FALSE; + if ($bookid) { + $title = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), $bookid)); + if ($title) { + + $block['subject'] = check_plain($title); + $block['content'] = menu_tree(book_menu_name($node)); } - - $block['subject'] = check_plain($path[0]->title); - $block['content'] = book_tree($expand[0], 5, $expand); } } @@ -189,12 +145,6 @@ function book_block($op = 'list', $delta } } -/** - * Implementation of hook_insert(). - */ -function book_insert($node) { - db_query("INSERT INTO {book} (nid, vid, parent, weight) VALUES (%d, %d, %d, %d)", $node->nid, $node->vid, $node->parent, $node->weight); -} /** * Implementation of hook_submit(). @@ -209,36 +159,34 @@ function book_submit(&$form_values) { } /** - * Implementation of hook_form(). + * Implementation of hook_form_alter(). */ -function book_form(&$node) { +function book_form_alter() { + + return; + $type = node_get_types('type', $node); if (!empty($node->nid) && !$node->parent && !user_access('create new books')) { $form['parent'] = array('#type' => 'value', '#value' => $node->parent); } else { - $form['parent'] = array('#type' => 'select', + if (!empty($_GET['parent']) && !isset($node->book_link['plid'])) { + $node->book_link['plid'] = $_GET['parent']; + } + $form['book_link']['#tree'] = TRUE; + $form['book_link']['plid'] = array('#type' => 'select', '#title' => t('Parent'), - '#default_value' => (isset($node->parent) ? $node->parent : arg(4)), + '#default_value' => (isset($node->book_link['plid']) ? $node->book_link['plid'] : 0), '#options' => book_toc(isset($node->nid) ? $node->nid : 0), '#weight' => -4, '#description' => user_access('create new books') ? t('The parent section in which to place this page. Note that each page whose parent is <top-level> is an independent, top-level book.') : t('The parent that this page belongs in.'), ); } - $form['title'] = array('#type' => 'textfield', - '#title' => check_plain($type->title_label), - '#required' => TRUE, - '#default_value' => $node->title, - '#weight' => -5, - ); - - $form['body_field'] = node_body_field($node, $type->body_label, 1); - if (user_access('administer nodes')) { - $form['weight'] = array('#type' => 'weight', + $form['book_link']['weight'] = array('#type' => 'weight', '#title' => t('Weight'), - '#default_value' => isset($node->weight) ? $node->weight : 0, + '#default_value' => isset($node->book_link['weight']) ? $node->book_link['weight'] : 0, '#delta' => 15, '#weight' => 5, '#description' => t('Pages at a given level are ordered first by weight and then by title.'), @@ -247,9 +195,9 @@ function book_form(&$node) { else { // If a regular user updates a book page, we preserve the node weight; otherwise // we use 0 as the default for new pages - $form['weight'] = array( + $form['book_link']['weight'] = array( '#type' => 'value', - '#value' => isset($node->weight) ? $node->weight : 0, + '#value' => isset($node->book_link['weight']) ? $node->book_link['weight'] : 0, ); } @@ -322,105 +270,53 @@ function book_outline_submit($form_value return; } -/** - * Given a node, this function returns an array of 'book node' objects - * representing the path in the book tree from the root to the - * parent of the given node. - * - * @param $node - * A book node object for which to compute the path. - * - * @return - * An array of book node objects representing the path nodes root to - * parent of the given node. Returns an empty array if the node does - * not exist or is not part of a book hierarchy. - */ -function book_location($node, $nodes = array()) { - $parent = db_fetch_object(db_query(db_rewrite_sql('SELECT n.nid, n.title, b.parent, b.weight FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.nid = %d'), $node->parent)); - if (isset($parent->title)) { - $nodes = book_location($parent, $nodes); - $nodes[] = $parent; +function book_get_flat_menu($node) { + static $flat = array(); + + if (!isset($flat[$node->nid])) { + $tree = menu_tree_all_data($node->menu_link['menu_name'], $node->menu_link); + $flat[$node->nid] = array(); + _book_flatten_menu($tree, $flat[$node->nid]); } - return $nodes; + + return $flat[$node->nid]; } -/** - * Given a node, this function returns an array of 'book node' objects - * representing the path in the book tree from the given node down to - * the last sibling of it. - * - * @param $node - * A book node object where the path starts. - * - * @return - * An array of book node objects representing the path nodes from the - * given node. Returns an empty array if the node does not exist or - * is not part of a book hierarchy or there are no siblings. - */ -function book_location_down($node, $nodes = array()) { - $last_direct_child = db_fetch_object(db_query(db_rewrite_sql('SELECT n.nid, n.title, b.parent, b.weight FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.status = 1 AND b.parent = %d ORDER BY b.weight DESC, n.title DESC'), $node->nid)); - if ($last_direct_child) { - $nodes[] = $last_direct_child; - $nodes = book_location_down($last_direct_child, $nodes); +function _book_flatten_menu($tree, &$flat) { + + foreach ($tree as $data) { + if (!$data['link']['hidden']) { + $flat[$data['link']['mlid']] = $data['link']; + if ($data['below']) { + _book_flatten_menu($data['below'], &$flat) + } + } } - return $nodes; + } /** - * Fetches the node object of the previous page of the book. + * Fetches the menu link for the previous page of the book. */ function book_prev($node) { // If the parent is zero, we are at the start of a book so there is no previous. - if ($node->parent == 0) { + if ($node->menu_link['plid'] == 0) { return NULL; } - // Previous on the same level: - $direct_above = db_fetch_object(db_query(db_rewrite_sql("SELECT n.nid, n.title, b.weight FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE b.parent = %d AND n.status = 1 AND (b.weight < %d OR (b.weight = %d AND n.title < '%s')) ORDER BY b.weight DESC, n.title DESC"), $node->parent, $node->weight, $node->weight, $node->title)); - if ($direct_above) { - // Get last leaf of $above. - $path = book_location_down($direct_above); +// $prev = db_fetch_object(db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.nid = %d AND n.status = 1'), $node->parent)); - return $path ? (count($path) > 0 ? array_pop($path) : NULL) : $direct_above; - } - else { - // Direct parent: - $prev = db_fetch_object(db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.nid = %d AND n.status = 1'), $node->parent)); - return $prev; - } } /** - * Fetches the node object of the next page of the book. + * Fetches the menu link for the next page of the book. */ function book_next($node) { - // get first direct child - $child = db_fetch_object(db_query(db_rewrite_sql('SELECT n.nid, n.title, b.weight FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE b.parent = %d AND n.status = 1 ORDER BY b.weight ASC, n.title ASC'), $node->nid)); - if ($child) { - return $child; - } - - // No direct child: get next for this level or any parent in this book. - $path = book_location($node); // Path to top-level node including this one. - $path[] = $node; - while (($leaf = array_pop($path)) && count($path)) { - $next = db_fetch_object(db_query(db_rewrite_sql("SELECT n.nid, n.title, b.weight FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE b.parent = %d AND n.status = 1 AND (b.weight > %d OR (b.weight = %d AND n.title > '%s')) ORDER BY b.weight ASC, n.title ASC"), $leaf->parent, $leaf->weight, $leaf->weight, $leaf->title)); - if ($next) { - return $next; - } - } } -/** - * Returns the content of a given node. If $teaser if TRUE, returns - * the teaser rather than full content. Displays the most recently - * approved revision of a node (if any) unless we have to display this - * page in the context of the moderation queue. - */ -function book_content($node, $teaser = FALSE) { - // Return the page body. - return node_prepare($node, $teaser); +function book_menu_name($node) { + return 'book-toc-'. $node->bookid; } /** @@ -431,18 +327,16 @@ function book_content($node, $teaser = F function book_nodeapi(&$node, $op, $teaser, $page) { switch ($op) { case 'load': - return db_fetch_array(db_query('SELECT parent, weight FROM {book} WHERE vid = %d', $node->vid)); + $info = db_fetch_array(db_query('SELECT b.bookid, b.child_type, ml.* FROM {book} b INNER JOIN {menu_links} ml ON b.mlid = ml.mlid WHERE b.nid = %d', $node->nid)); + $ret['bookid'] = $info['bookid']; + $ret['child_type'] = $info['child_type']; + unset($info['child_type'], $info['bookid']); + $ret['book_lnk'] = $info; + return $ret; break; case 'view': if (!$teaser) { - if (isset($node->parent)) { - $path = book_location($node); - // Construct the breadcrumb: - $node->breadcrumb = array(); // Overwrite the trail with a book trail. - foreach ($path as $level) { - $node->breadcrumb[] = array('path' => 'node/'. $level->nid, 'title' => $level->title); - } - $node->breadcrumb[] = array('path' => 'node/'. $node->nid); + if (isset($node->bookid)) { $node->content['book_navigation'] = array( '#value' => theme('book_navigation', $node), @@ -450,25 +344,25 @@ function book_nodeapi(&$node, $op, $teas ); if ($page) { - menu_set_location($node->breadcrumb); + menu_set_active_menu_name(book_menu_name($node)); } } } break; + case 'insert': + if (isset($node->bookid)) { + menu_link_save($node->book_link); + db_query("INSERT INTO {book} SET parent = %d, weight = %d WHERE vid = %d", $node->parent, $node->weight, $node->vid); + } case 'update': - if (isset($node->parent)) { - if (!empty($node->revision)) { - db_query("INSERT INTO {book} (nid, vid, parent, weight) VALUES (%d, %d, %d, %d)", $node->nid, $node->vid, $node->parent, $node->weight); - } - else { - db_query("UPDATE {book} SET parent = %d, weight = %d WHERE vid = %d", $node->parent, $node->weight, $node->vid); - } + if (isset($node->bookid)) { + menu_link_save($node->book_link); + db_query("UPDATE {book} SET parent = %d, weight = %d WHERE vid = %d", $node->parent, $node->weight, $node->vid); } - break; - case 'delete revision': - db_query('DELETE FROM {book} WHERE vid = %d', $node->vid); + break; case 'delete': + menu_link_delete($node->book_link) db_query('DELETE FROM {book} WHERE nid = %d', $node->nid); break; } @@ -591,28 +485,10 @@ function book_tree_recurse($nid, $depth, } /** - * Returns an HTML nested list (wrapped in a menu-class div) representing the book nodes - * as a tree. - */ -function book_tree($parent = 0, $depth = 3, $unfold = array()) { - $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, b.parent, b.weight FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.status = 1 ORDER BY b.weight, n.title')); - - while ($node = db_fetch_object($result)) { - $list = isset($children[$node->parent]) ? $children[$node->parent] : array(); - $list[] = $node; - $children[$node->parent] = $list; - } - - if ($tree = book_tree_recurse($parent, $depth, $children, $unfold)) { - return ''; - } -} - -/** * Menu callback; prints a listing of all books. */ function book_render() { - $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, b.weight FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE b.parent = 0 AND n.status = 1 ORDER BY b.weight, n.title')); + $result = db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE b.bookid = b.nid AND n.status = 1 ORDER BY n.title')); $books = array(); while ($node = db_fetch_object($result)) { @@ -641,6 +517,8 @@ function book_render() { * */ function book_export($type, $nid) { + return; + $type = drupal_strtolower($type); $node_result = db_query(db_rewrite_sql('SELECT n.nid, n.title, b.parent FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.nid = %d'), $nid); if (db_num_rows($node_result) > 0) { @@ -758,7 +636,7 @@ function book_recurse($nid = 0, $depth = $output .= call_user_func($visit_post, $node, $depth); } else { - # default + // default $output .= book_node_visitor_html_post($node, $depth); } }