book.module 24.5 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
 
Dries committed
4 5 6 7 8 9 10 11 12
function book_help() {
  $output .= "<h3>Maintain a FAQ with <i>Collaborative book</i></h3>";
  $output .= "<p>The collaborative book (i.e. <code>book.module</code>) in Drupal is a terrific way to easily manage an FAQ (Frequently Asked Questions) section of your web site. The main benefit for an administrator is that you don't have to write all the questions/answers by yourself.  Let the community do it for you!</p>";
  $output .= "<p>In order to setup the FAQ, you have to create a new <i>book</i> which will hold all your content.  To do so, click on <i>create book page</i> in your user box.  Give it a thoughtful title and body.  A title like \"Estonia Travel - FAQ\" is nice.  You may always edit these fields later.  You will probably want to designate <i><root></i> as the parent of this page.  Leave the <i>log message</i> and <i>type</i> fields blank for now.  After you've submitted this book page, you are ready to begin filling up your book with questions that are frequently asked.</p>";
  $output .= "<p>Whenever you come across a post which you want to include in your FAQ, click on the <i>administer</i> link.  Then click on the <i>edit book outline</i> button at the bottom of the page. Then place the relevant post wherever is most appropriate in your book by selecting a <i>parent</i>.  Books are quite flexible. They can have sections like <i>Flying to Estonia</i>, <i>Eating in Estonia</i> and so on.  As you get more experienced with the <i>Collaborative book</i>, you can reorganize posts in your book so that it stays organized.</p>";
  $output .= "<p>Notes:</p><ul><li>Any comments attached to those relevant posts which you designate as book pages will also be transported into your book.  This is a great feature, since much wisdom is shared via comments. And remember that all future comments and edits will automatically be reflected in your book.</li><li>You may wish to edit the title and teaser of posts when adding them to your FAQ.  This is done on the same page as the <i>edit book outline</i> button.  Clear titles help users navigate quickly to the information that they seek.</li><li>Book pages may come from any content type (blog, story, page, etc.).  If you are creating a post solely for inclusion in your book, then use the <i>create book page</i> link.</li><li>If you don't see the <i>administer</i> link, then you probably have insufficient <a href=\"admin.php?mod=user&op=permission\">permissions</a>.</li><li>If you want to get really fancy, note that Books are one of the few content types which allow raw PHP in their <i>body</i>.  So you've got lots of geeky possibilities there.</li></ul>";
  return $output;
}

Dries's avatar
 
Dries committed
13 14 15
function book_node($field) {
  global $user;

Dries's avatar
 
Dries committed
16
  $info["name"] = t("book page");
Dries's avatar
 
Dries committed
17
  $info["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.");
Dries's avatar
 
Dries committed
18 19 20 21 22

  return $info[$field];
}

function book_access($op, $node) {
Dries's avatar
 
Dries committed
23
  global $user;
Dries's avatar
 
Dries committed
24 25

  if ($op == "view") {
Dries's avatar
 
Dries committed
26 27 28 29 30 31 32 33
    /*
    ** Everyone can access all published book pages whether these pages
    ** are still waiting for approval or not.  We might not always want
    ** to display pages that are waiting for approval, but we take care
    ** of that problem in the book_view() function.
    */

    return $node->status;
Dries's avatar
 
Dries committed
34 35
  }

Dries's avatar
 
Dries committed
36
  if ($op == "create") {
Dries's avatar
 
Dries committed
37 38 39 40 41 42
    /*
    ** 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->uid;
Dries's avatar
 
Dries committed
43 44 45
  }

  if ($op == "update") {
Dries's avatar
 
Dries committed
46
    /*
Dries's avatar
 
Dries committed
47 48 49 50 51 52 53
    ** 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 upate a book page if there are no suggested updates
    ** of that page waiting for approval, when it is not a PHP-page and
    ** as long as the "create new revision"-bit is set.  That is, only
    ** updates that don't overwrite the current or pending information
    ** are allowed.
Dries's avatar
 
Dries committed
54
    */
Dries's avatar
 
Dries committed
55 56

    return $user->uid && !$node->moderate && !$node->format && $node->revision;
Dries's avatar
 
Dries committed
57
  }
Dries's avatar
 
Dries committed
58 59
}

Dries's avatar
 
Dries committed
60
function book_save($op, $node) {
Dries's avatar
 
Dries committed
61
  global $user;
Dries's avatar
 
Dries committed
62 63 64 65 66 67

  if ($op == "approve") {
    return array("status" => 1);
  }

  if ($op == "create") {
Dries's avatar
 
Dries committed
68
    if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
69 70 71 72 73
      return array("format", "parent", "weight");
    }
    else {
      return array("format", "moderate" => 1, "parent", "promote" => 0, "status" => 1, "weight");
    }
Dries's avatar
 
Dries committed
74 75 76 77 78 79 80
  }

  if ($op == "decline") {
    return array("status" => 0);
  }

  if ($op == "update") {
Dries's avatar
 
Dries committed
81
    if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
82
      /*
Dries's avatar
 
Dries committed
83 84
      ** If a node administrator updates a book page, we don't create a
      ** new revision unless we are explicitly instructed to.
Dries's avatar
 
Dries committed
85 86
      */

Dries's avatar
 
Dries committed
87
      return array("format", "parent", "weight");
Dries's avatar
 
Dries committed
88
    }
Dries's avatar
 
Dries committed
89
    else {
Dries's avatar
 
Dries committed
90
      /*
Dries's avatar
 
Dries committed
91 92 93
      ** If a regular user updates a book page, we always create a new
      ** revision.  All new revisions have to be approved (moderation)
      ** and are not promoted by default.  See also: book_load().
Dries's avatar
 
Dries committed
94 95
      */

Dries's avatar
 
Dries committed
96
      return array("created" => time(), "format", "moderate" => 1, "parent", "promote" => 0, "score" => 0, "status" => 1, "users" => "", "revisions", "votes" => 0, "weight");
Dries's avatar
 
Dries committed
97 98 99 100 101
    }
  }

}

Dries's avatar
 
Dries committed
102
function book_link($type, $node = 0, $main = 0) {
Dries's avatar
 
Dries committed
103
  if ($type == "page" && user_access("access content")) {
Dries's avatar
 
Dries committed
104 105 106
    $links[] = "<a href=\"module.php?mod=book\" title=\"". t("Read and contribute to the collaborative books.") ."\">". t("collaborative book") ."</a>";
  }

107
  if ($type == "menu.create" && user_access("post content")) {
Dries's avatar
 
Dries committed
108
    $links[] = "<a href=\"module.php?mod=node&op=add&type=book\" title=\"". t("Add a new book page.") ."\">". t("create book page") ."</a>";
Dries's avatar
 
Dries committed
109
  }
Dries's avatar
 
Dries committed
110

Dries's avatar
 
Dries committed
111 112 113 114
  if ($type == "admin" && user_access("administer nodes")) {
    $links[] = "<a href=\"admin.php?mod=book\">". t("collaborative book") ."</a>";
  }

Dries's avatar
 
Dries committed
115
  if ($type == "node" && $node->type == "book" && book_access("update", $node)) {
Dries's avatar
 
Dries committed
116
    $links[] = "<a href=\"module.php?mod=node&op=edit&id=$node->nid\" title=\"". t("Suggest an update for this book page.") ."\">". t("edit this page") ."</a>";
Dries's avatar
 
Dries committed
117 118
  }

Dries's avatar
 
Dries committed
119
  return $links ? $links : array();
Dries's avatar
 
Dries committed
120 121
}

Dries's avatar
 
Dries committed
122
function book_load($node) {
Dries's avatar
 
Dries committed
123 124
  global $user, $REQUEST_URI;

Dries's avatar
 
Dries committed
125
  $book = db_fetch_object(db_query("SELECT format, parent, weight FROM book WHERE nid = '$node->nid'"));
Dries's avatar
 
Dries committed
126 127

  if (strstr($REQUEST_URI, "module.php?mod=node&op=edit")) {
Dries's avatar
 
Dries committed
128

Dries's avatar
 
Dries committed
129 130 131 132 133 134 135
    /*
    ** If a user is about to update a book page, we overload some
    ** fields to reflect the changes.  We use the $REQUEST_URI to
    ** dectect this as we don't want to interfer with updating a
    ** book page through the admin pages.  See also: book_save().
    */

Dries's avatar
 
Dries committed
136 137 138 139 140 141 142 143
    if ($user->uid) {
      $book->uid = $user->uid;
      $book->name = $user->name;
    }
    else {
      $book->uid = 0;
      $book->name = "";
    }
Dries's avatar
 
Dries committed
144
  }
Dries's avatar
 
Dries committed
145

Dries's avatar
 
Dries committed
146 147 148
  /*
  ** We set the revision field to indicate that we have to create
  ** a new revision when updating this book page.  We enable this
Dries's avatar
 
Dries committed
149
  ** always such that the "edit this page"-links appear.
Dries's avatar
 
Dries committed
150
  */
Dries's avatar
 
Dries committed
151

Dries's avatar
 
Dries committed
152
  $book->revision = 1;
Dries's avatar
 
Dries committed
153

Dries's avatar
 
Dries committed
154
  return $book;
Dries's avatar
 
Dries committed
155 156
}

Dries's avatar
 
Dries committed
157
function book_insert($node) {
Dries's avatar
 
Dries committed
158 159 160 161 162 163
  if (!user_access("administer nodes")) {
    $node->format = 0;
    $node->weight = 0;
  }

  db_query("INSERT INTO book (nid, format, parent, weight) VALUES ('$node->nid', '$node->format', '$node->parent', '$node->weight')");
Dries's avatar
 
Dries committed
164
}
Dries's avatar
 
Dries committed
165

Dries's avatar
 
Dries committed
166
function book_update($node) {
Dries's avatar
 
Dries committed
167 168 169 170 171 172
  if (!user_access("administer nodes")) {
    $node->format = 0;
    $node->weight = 0;
  }

  db_query("UPDATE book SET format = '$node->format', parent = '$node->parent', weight = '$node->weight' WHERE nid = '$node->nid'");
Dries's avatar
 
Dries committed
173
}
Dries's avatar
 
Dries committed
174

175
function book_delete(&$node) {
Dries's avatar
 
Dries committed
176
  db_query("DELETE FROM book WHERE nid = '$node->nid'");
Dries's avatar
 
Dries committed
177 178
}

179
function book_form(&$node, &$help, &$error) {
Dries's avatar
 
Dries committed
180
  global $user, $op;
Dries's avatar
 
Dries committed
181 182

  $output .= form_select(t("Parent"), "parent", $node->parent, book_toc(), t("The parent subject or category the page belongs in."));
Dries's avatar
 
Dries committed
183

Dries's avatar
 
Dries committed
184 185 186 187 188 189 190 191 192
  if ($node->format) {
    if ($op != t("Preview")) {
      $node->body = addslashes($node->body);
    }
  }
  else {
    if ($node->teaser) {
      $output .= form_textarea(t("Teaser"), "teaser", $node->teaser, 60, 5, $error["teaser"]);
    }
Dries's avatar
 
Dries committed
193 194 195
  }

  $output .= form_textarea(t("Body"), "body", $node->body, 60, 20, t("Allowed HTML tags") .": ". htmlspecialchars(variable_get("allowed_html", "")));
Dries's avatar
 
Dries committed
196 197 198
  $output .= form_textarea(t("Log message"), "history", $node->history, 60, 5, t("An explanation of the additions or updates being made to help the group understand your motivations."));

  if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
199 200
    $output .= form_select(t("Weight"), "weight", $node->weight, array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30), t("The heavier pages will sink and the lighter pages will be positioned nearer the top."));
    $output .= form_select("Type", "format", $node->format, array(0 => "HTML / text", 1 => "PHP"));
Dries's avatar
 
Dries committed
201 202 203 204 205 206 207
  }
  else {

    /*
    ** Carry out some explanation or submission guidelines:
    */

Dries's avatar
 
Dries committed
208 209
    $help = book_node("description");

Dries's avatar
 
Dries committed
210 211 212 213 214 215 216 217 218 219 220
    /*
    ** If a regular user updates a book page, we create a new revision
    ** authored by that user:
    */

    $output .= form_hidden("revision", 1);
  }

  return $output;
}

Dries's avatar
 
Dries committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
function book_node_link($node = 0) {
  global $user, $op, $edit;

  if ($node->type != "book") {

    if ($edit["nid"]) {
      $node = node_load(array("nid" => $edit["nid"]));
    }

    if ($op == t("Add to book outline")) {
      db_query("INSERT INTO book (nid, parent, weight) VALUES ('$node->nid', '". check_query($edit["parent"]) ."', '". check_query($edit["weight"]) ."')");
      $output .= status(t("added the node to the book."));
    }

    if ($op == t("Update book outline")) {
      db_query("UPDATE book SET parent = '". check_query($edit["parent"]) ."', weight = '". check_query($edit["weight"]) ."' WHERE nid = '$node->nid'");
      $output .= status(t("updated the book outline."));
    }

    if ($op == t("Remove from book outline")) {
      db_query("DELETE FROM book WHERE nid = '$node->nid'");
      $output .= status(t("removed the node form the book."));
    }

    $output .= "<h3>". t("Edit book outline") ."</h3>";

    if ($edit["nid"]) {
      $page = db_fetch_object(db_query("SELECT * FROM book WHERE nid = '$node->nid'"));

      $output .= form_select(t("Parent"), "parent", $page->parent, book_toc(), t("The parent subject or category the page belongs in."));
      $output .= form_select(t("Weight"), "weight", $page->weight, array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30), t("The heavier pages will sink and the lighter pages will be positioned nearer the top."));

      if ($page->nid) {
        $output .= form_submit(t("Update book outline"));
        $output .= form_submit(t("Remove from book outline"));
      }
      else {
        $output .= form_submit(t("Add to book outline"));
      }

    }
    else {
      $output .= form_submit(t("Edit book outline"));
    }

    $output .= form_hidden("nid", $node->nid);

    return form($output, "post", "admin.php?mod=book&op=outline");
  }
}

Dries's avatar
 
Dries committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
/*
** Return the the most recent revision that matches the specified
** conditions.
*/

function book_revision_load($page, $conditions = array()) {

  $revisions = array_reverse(node_revision_list($page));

  foreach ($revisions as $revision) {

    /*
    ** Extract the specified revision:
    */

    $node = node_revision_load($page, $revision);

    /*
    ** Check to see if the conditions are met:
    */

    $status = 1;

    foreach ($conditions as $key => $value) {
      if ($node->$key != $value) {
        $status = 0;
      }
    }

    if ($status) {
      return $node;
    }
  }
}

/*
** Return the path (call stack) to a certain book page.
*/

Dries's avatar
 
Dries committed
311
function book_location($node, $nodes = array()) {
Dries's avatar
 
Dries committed
312
  $parent = db_fetch_object(db_query("SELECT n.nid, n.title, b.parent FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.nid = '$node->parent'"));
Dries's avatar
 
Dries committed
313 314 315 316 317 318 319
  if ($parent->title) {
    $nodes = book_location($parent, $nodes);
    array_push($nodes, $parent);
  }
  return $nodes;
}

Dries's avatar
 
Dries committed
320 321 322 323 324 325 326 327
function book_body($node) {
  global $theme, $op;

  if ($node->format == 1) {
    /*
    ** Make sure only authorized users can preview PHP pages.
    */

Dries's avatar
 
Dries committed
328
    if ($op == t("Preview")) {
Dries's avatar
 
Dries committed
329
      if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
330 331 332 333 334
        $node->body = stripslashes($node->body);  // see also book_form()
      }
      else {
        return;
      }
Dries's avatar
 
Dries committed
335 336 337 338 339 340 341 342
    }

    ob_start();
    eval($node->body);
    $output = ob_get_contents();
    ob_end_clean();
  }
  else {
Dries's avatar
 
Dries committed
343
    $output = check_output(filter($node->body), 1);
Dries's avatar
 
Dries committed
344 345 346 347 348
  }

  return $output;
}

Dries's avatar
 
Dries committed
349
function book_view($node, $main = 0) {
Dries's avatar
 
Dries committed
350 351 352 353
  global $theme, $mod;

  /*
  ** Always display the most recently approved revision of a node
Dries's avatar
 
Dries committed
354 355
  ** (if any) unless we have to display this page in the context of
  ** the moderation queue.
Dries's avatar
 
Dries committed
356 357 358
  */

  if ($node->moderate && $mod != "queue") {
Dries's avatar
 
Dries committed
359 360 361 362 363
    $revision = book_revision_load($node, array("moderate" => 0, "status" => 1));

    if ($revision) {
      $node = $revision;
    }
Dries's avatar
 
Dries committed
364 365
  }

Dries's avatar
 
Dries committed
366 367 368 369 370 371 372
  /*
  ** Extract the page body.  If body is dynamic (using PHP code), the body
  ** will be generated.
  */

  $node->body = book_body($node);

Dries's avatar
 
Dries committed
373 374 375 376 377
  /*
  ** Display the node.  If not displayed on the main page, we render
  ** the node as a page in the book with extra links to the previous
  ** and the next page.
  */
Dries's avatar
 
Dries committed
378

Dries's avatar
 
Dries committed
379 380
  if ($main) {
    $theme->node($node, $main);
Dries's avatar
 
Dries committed
381
  }
Dries's avatar
 
Dries committed
382
  else {
Dries's avatar
 
Dries committed
383 384 385 386
    /*
    ** Construct the "next" and "previous" links:
    */

Dries's avatar
 
Dries committed
387
    if ($node->nid && $node->parent) {
388 389
      $next = db_fetch_object(db_query("SELECT n.nid, n.title FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.status = 1 AND b.parent = '$node->parent' AND (b.weight > '$node->weight' OR (b.weight = '$node->weight' AND n.title > '". check_query($node->title) ."')) AND (n.moderate = 0 OR n.revisions != '') ORDER BY b.weight ASC, n.title ASC"));
      $prev = db_fetch_object(db_query("SELECT n.nid, n.title FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.status = 1 AND b.parent = '$node->parent' AND (b.weight < '$node->weight' OR (b.weight = '$node->weight' AND n.title < '". check_query($node->title) ."')) AND (n.moderate = 0 OR n.revisions != '') ORDER BY b.weight DESC, n.title DESC"));
Dries's avatar
 
Dries committed
390
    }
Dries's avatar
 
Dries committed
391

Dries's avatar
 
Dries committed
392
    $output .= "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\" width=\"100%\">";
Dries's avatar
 
Dries committed
393

Dries's avatar
 
Dries committed
394 395
    if ($node->title) {
      foreach (book_location($node) as $level) {
Dries's avatar
 
Dries committed
396
        $location .= "$indent <a href=\"node.php?id=$level->nid\">$level->title</a><br />";
Dries's avatar
 
Dries committed
397 398
        $indent .= "-";
      }
Dries's avatar
 
Dries committed
399

Dries's avatar
 
Dries committed
400
      $output .= " <tr><td colspan=\"3\">$location</td></tr>";
Dries's avatar
 
Dries committed
401 402
      $output .= " <tr><td colspan=\"3\"><hr /></td></tr>";
      $output .= " <tr><td colspan=\"3\"><b><big>". check_output($node->title) ."</big></b>". ($node->body ? "<br /><small><i>". sprintf(t("Last updated by %s on %s"), format_name($node), format_date($node->created)) ."</i></small> " : "") ."</td></tr>";
Dries's avatar
 
Dries committed
403
    }
Dries's avatar
 
Dries committed
404

Dries's avatar
 
Dries committed
405
    if ($node->body) {
Dries's avatar
 
Dries committed
406
      $output .= " <tr><td colspan=\"3\"><br />$node->body</td></tr>";
Dries's avatar
 
Dries committed
407
    }
Dries's avatar
 
Dries committed
408

Dries's avatar
 
Dries committed
409
    if ($node->nid) {
Dries's avatar
 
Dries committed
410
      $output .= " <tr><td colspan=\"3\"><br />". book_tree($node->nid) ."</td></tr>";
Dries's avatar
 
Dries committed
411
    }
Dries's avatar
 
Dries committed
412

Dries's avatar
 
Dries committed
413
    $output .= " <tr><td colspan=\"3\"><hr /></td></tr>";
Dries's avatar
 
Dries committed
414
    $output .= " <tr><td align=\"left\" width=\"33%\">". ($prev ? "<a href=\"node.php?id=$prev->nid\" title=\"". t("View the previous page in this book.") ."\">". t("previous") ."</a>" : t("previous")) ."</td><td align=\"center\" width=\"34%\"><a href=\"module.php?mod=book\" title=\"". t("View this book's table of contents.") ."\">index</a></td><td align=\"right\" width=\"33%\">". ($next ? "<a href=\"node.php?id=$next->nid\" title=\"". t("View the next page in this book.") ."\">". t("next") ."</a>" : t("next")) ."</td></tr>";
Dries's avatar
 
Dries committed
415
    $output .= " <tr><td align=\"left\" width=\"33%\">". ($prev ? "<small>". check_output($prev->title) ."</small>" : "&nbsp;") ."</td><td align=\"center\" width=\"34%\">". ($node->parent ? "<a href=\"node.php?id=$node->parent\" title=\"". t("View this page's parent section.") ."\">". t("up") ."</a>" : t("up")) ."</td><td align=\"right\" width=\"33%\">". ($next ? "<small>". check_output($next->title) ."</small>" : "&nbsp;") ."</td></tr>";
Dries's avatar
 
Dries committed
416 417
    $output .= " <tr><td colspan=\"3\"><hr /></td></tr>";
    $output .= " <tr><td colspan=\"3\" align=\"right\"><div style=\"margin: 10 10 10 10;\">". $theme->links(link_node($node, $main)) ."</div></td></tr>";
Dries's avatar
 
Dries committed
418
    $output .= "</table>";
Dries's avatar
 
Dries committed
419

Dries's avatar
 
Dries committed
420 421
    $theme->box(t("Handbook"), $output);
  }
Dries's avatar
 
Dries committed
422 423
}

Dries's avatar
 
Dries committed
424 425 426 427 428 429 430 431 432 433 434 435
function book_toc_recurse($nid, $indent, $toc, $children) {

  if ($children[$nid]) {
    foreach ($children[$nid] as $foo => $node) {
      $toc[$node->nid] = "$indent $node->title";
      $toc = book_toc_recurse($node->nid, "$indent--", $toc, $children);
    }
  }

  return $toc;
}

Dries's avatar
 
Dries committed
436
function book_toc($parent = 0, $indent = "", $toc = array()) {
Dries's avatar
 
Dries committed
437

Dries's avatar
 
Dries committed
438
  $result = db_query("SELECT n.nid, n.title, b.parent FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.type = 'book' AND n.status = '1' ORDER BY b.weight, n.title");
Dries's avatar
 
Dries committed
439

Dries's avatar
 
Dries committed
440 441 442 443 444
  while ($node = db_fetch_object($result)) {
    $list = $children[$node->parent] ? $children[$node->parent] : array();
    array_push($list, $node);
    $children[$node->parent] = $list;
  }
Dries's avatar
 
Dries committed
445 446

  /*
Dries's avatar
 
Dries committed
447 448
  ** If the user is an administrator, add the root node; only
  ** administrators can start new books.
Dries's avatar
 
Dries committed
449
  */
Dries's avatar
 
Dries committed
450

Dries's avatar
 
Dries committed
451
  if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
452
    $toc[0] = "<root>";
Dries's avatar
 
Dries committed
453 454
  }

Dries's avatar
 
Dries committed
455
  /*
Dries's avatar
 
Dries committed
456
  ** Iterate root book nodes:
Dries's avatar
 
Dries committed
457 458
  */

Dries's avatar
 
Dries committed
459
  $toc = book_toc_recurse($parent, $indent, $toc, $children);
Dries's avatar
 
Dries committed
460

Dries's avatar
 
Dries committed
461 462 463
  return $toc;
}

Dries's avatar
 
Dries committed
464

Dries's avatar
 
Dries committed
465
function book_tree_recurse($nid, $depth, $children) {
Dries's avatar
 
Dries committed
466

Dries's avatar
 
Dries committed
467
  if ($depth > 0) {
Dries's avatar
 
Dries committed
468 469
    if ($children[$nid]) {
      foreach ($children[$nid] as $foo => $node) {
Dries's avatar
 
Dries committed
470
        $output .= "<li><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a></li>";
Dries's avatar
 
Dries committed
471 472 473 474

        if ($tree = book_tree_recurse($node->nid, $depth - 1, $children)) {
          $output .= "<ul>$tree</ul>";
        }
Dries's avatar
 
Dries committed
475 476
      }
    }
Dries's avatar
 
Dries committed
477 478 479 480 481
  }

  return $output;
}

Dries's avatar
 
Dries committed
482

Dries's avatar
 
Dries committed
483 484 485
function book_tree($parent = 0, $depth = 3) {

  $result = db_query("SELECT n.nid, n.title, b.parent FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.type = 'book' AND n.status = '1' ORDER BY b.weight, n.title");
Dries's avatar
 
Dries committed
486

Dries's avatar
 
Dries committed
487 488 489 490
  while ($node = db_fetch_object($result)) {
    $list = $children[$node->parent] ? $children[$node->parent] : array();
    array_push($list, $node);
    $children[$node->parent] = $list;
Dries's avatar
 
Dries committed
491
  }
Dries's avatar
 
Dries committed
492

Dries's avatar
 
Dries committed
493 494
  $output = book_tree_recurse($parent, $depth, $children);
  $output = "<ul>$output</ul>";
Dries's avatar
 
Dries committed
495

Dries's avatar
 
Dries committed
496 497 498
  return $output;
}

Dries's avatar
 
Dries committed
499

Dries's avatar
 
Dries committed
500
function book_render() {
Dries's avatar
 
Dries committed
501
  global $theme;
Dries's avatar
Dries committed
502

503
  $result = db_query("SELECT n.nid FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE b.parent = 0 AND n.status = 1 AND (n.moderate = 0 OR n.revisions != '') ORDER BY b.weight");
Dries's avatar
 
Dries committed
504

Dries's avatar
 
Dries committed
505 506 507 508 509 510
  while ($page = db_fetch_object($result)) {
    // load the node:
    $node = node_load(array("nid" => $page->nid));

    // take the most recent approved revision:
    if ($node->moderate) {
Dries's avatar
 
Dries committed
511
      $node = book_revision_load($node, array("moderate" => 0, "status" => 1));
Dries's avatar
 
Dries committed
512 513
    }

Dries's avatar
 
Dries committed
514 515
    if ($node) {
      // output the content:
Dries's avatar
 
Dries committed
516
      $output .= "<dt><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a></dt><dd>". book_body($node) ."<br /><br /></dd>";
Dries's avatar
 
Dries committed
517
    }
Dries's avatar
 
Dries committed
518 519 520
  }

  $theme->header();
Dries's avatar
 
Dries committed
521
  $theme->box(t("Handbook"), "<dl>$output</dl>");
Dries's avatar
 
Dries committed
522 523 524 525 526 527
  $theme->footer();
}

function book_page() {
  global $op, $id, $theme;

Dries's avatar
 
Dries committed
528
  if (user_access("access content")) {
Dries's avatar
 
Dries committed
529 530
    switch ($op) {
      case "feed":
Dries's avatar
 
Dries committed
531
        print book_export_html($id, $depth = 1);
Dries's avatar
 
Dries committed
532 533 534
        break;
      default:
        book_render();
Dries's avatar
 
Dries committed
535 536 537 538 539 540 541
    }
  }
  else {
    $theme->header();
    $theme->box(t("Access denied"), message_access());
    $theme->footer();
  }
Dries's avatar
 
Dries committed
542 543
}

Dries's avatar
 
Dries committed
544
function book_export_html($id = "", $depth = 1) {
Dries's avatar
 
Dries committed
545
  $result = db_query("SELECT n.nid FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.status = 1 AND n.nid = '". check_input($id) ." AND (n.moderate = 0 OR n.revisions != '')'");
Dries's avatar
 
Dries committed
546

Dries's avatar
 
Dries committed
547 548 549
  while ($page = db_fetch_object($result)) {
    // load the node:
    $node = node_load(array("nid" => $page->nid));
Dries's avatar
 
Dries committed
550

Dries's avatar
 
Dries committed
551 552
    // take the most recent approved revision:
    if ($node->moderate) {
Dries's avatar
 
Dries committed
553
      $node = book_revision_load($node, array("moderate" => 0, "status" => 1));
Dries's avatar
 
Dries committed
554 555
    }

Dries's avatar
 
Dries committed
556 557 558
    if ($node) {
      // output the content:
      $output .= "<h$depth>". check_output($node->title) ."</h$depth>";
Dries's avatar
 
Dries committed
559

Dries's avatar
 
Dries committed
560
      if ($node->body) {
Dries's avatar
 
Dries committed
561
        $output .= "<ul>". book_body($node) ."</ul>";
Dries's avatar
 
Dries committed
562
      }
Dries's avatar
 
Dries committed
563
    }
Dries's avatar
 
Dries committed
564
  }
Dries's avatar
 
Dries committed
565

Dries's avatar
 
Dries committed
566
  $output .= book_export_html_recurse($id, $depth);
Dries's avatar
 
Dries committed
567 568 569 570

  return $output;
}

Dries's avatar
 
Dries committed
571
function book_export_html_recurse($parent = "", $depth = 1) {
Dries's avatar
 
Dries committed
572
  $result = db_query("SELECT n.nid FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.status = 1 AND b.parent = '$parent' AND (n.moderate = 0 OR n.revisions != '') ORDER BY b.weight");
Dries's avatar
 
Dries committed
573

Dries's avatar
 
Dries committed
574 575 576 577 578 579
  while ($page = db_fetch_object($result)) {
    // load the node:
    $node = node_load(array("nid" => $page->nid));

    // take the most recent approved revision:
    if ($node->moderate) {
Dries's avatar
 
Dries committed
580
      $node = book_revision_load($node, array("moderate" => 0, "status" => 1));
Dries's avatar
 
Dries committed
581 582
    }

Dries's avatar
 
Dries committed
583 584 585
    if ($node) {
      // output the content:
      $output .= "<h$depth>". check_output($node->title) ."</h$depth>";
Dries's avatar
 
Dries committed
586

Dries's avatar
 
Dries committed
587
      if ($node->body) {
Dries's avatar
 
Dries committed
588
        $output .= "<ul>". book_body($node) ."</ul>";
Dries's avatar
 
Dries committed
589
      }
Dries's avatar
 
Dries committed
590

Dries's avatar
 
Dries committed
591
      $output .= book_export_html_recurse($node->nid, $depth + 1);
Dries's avatar
 
Dries committed
592
    }
Dries's avatar
 
Dries committed
593
  }
Dries's avatar
 
Dries committed
594

Dries's avatar
 
Dries committed
595 596
  return $output;
}
Dries's avatar
 
Dries committed
597

Dries's avatar
 
Dries committed
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
function book_admin_view_line($node, $depth = 0) {

  /*
  ** Extract the revision number:
  */

  if ($list = node_revision_list($node)) {
    $revision = end($list);
  }
  else {
    $revision = 0;
  }

  /*
  ** Diplay the book page:
  */

  $output .= "<tr>";
  $output .= " <td><div style=\"padding-left: ". (25 * $depth) ."px;\"><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a></div></td>";
  $output .= " <td align=\"center\">$revision</td>";
  $output .= " <td><a href=\"admin.php?mod=node&op=edit&id=$node->nid\">". t("edit page") ."</td>";
  $output .= " <td><a href=\"admin.php?mod=node&op=delete&id=$node->nid\">". t("delete page") ."</td>";
  $output .= "</tr>";

  return $output;
}

function book_admin_view_book($nid, $depth = 1) {
Dries's avatar
 
Dries committed
626 627
  $weight = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30);

Dries's avatar
 
Dries committed
628
  $result = db_query("SELECT n.nid FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE b.parent = '$nid' ORDER BY b.weight, n.title");
Dries's avatar
 
Dries committed
629 630 631

  while ($node = db_fetch_object($result)) {
    $node = node_load(array("nid" => $node->nid));
Dries's avatar
 
Dries committed
632 633
    $output .= book_admin_view_line($node, $depth);
    $output .= book_admin_view_book($node->nid, $depth + 1);
Dries's avatar
 
Dries committed
634 635 636 637 638 639 640 641 642 643 644 645
  }

  return $output;
}

function book_admin_view($nid, $depth = 0) {

  $node = node_load(array("nid" => $nid));

  $output .= "<h3>". check_output($node->title) ."</h3>";
  $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">";
  $output .= " <tr><th>title</th><th>rev</th><th colspan=\"2\">operations</th></tr>";
Dries's avatar
 
Dries committed
646 647
  $output .= book_admin_view_line($node);
  $output .= book_admin_view_book($nid);
Dries's avatar
 
Dries committed
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
  $output .= "</table>";

  return $output;
}

function book_admin_orphan() {

  $result = db_query("SELECT n.nid, n.title, b.parent FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.type = 'book'");

  while ($page = db_fetch_object($result)) {
    $pages[$page->nid] = $page;
  }

  $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">";
  $output .= " <tr><th>title</th><th colspan=\"2\">operations</th></tr>";
  foreach ($pages as $nid => $node) {
    if ($node->parent && empty($pages[$node->parent])) {
      $output .= "<tr><td><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a></td><td><a href=\"admin.php?mod=node&op=edit&id=$node->nid\">". t("edit page") ."</td><td><a href=\"admin.php?mod=node&op=delete&id=$node->nid\">". t("delete page") ."</td>";
    }
  }
  $output .= "</table>";

  return $output;
}

function book_admin_links() {
  $result = db_query("SELECT n.nid, n.title FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE b.parent = 0 ORDER BY b.weight, n.title");

  while ($book = db_fetch_object($result)) {
    $links[] = "<a href=\"admin.php?mod=book&op=view&id=$book->nid\">". t("book") .": <i>". check_output($book->title) ."</i></a>";
  }

  return $links;
}

function book_admin() {
  global $id, $op;

  if (user_access("administer nodes")) {

    /*
    ** Compile a list of the administrative links:
    */

    $links = book_admin_links();
    $links[] = "<a href=\"admin.php?mod=book&op=orphan\">". t("orphan pages") ."</a>";

    print "<small>". implode(" &middot; ", $links) ."</small><hr />";

    switch ($op) {
Dries's avatar
 
Dries committed
698 699 700 701 702 703
      case t("Edit book outline"):
      case t("Add to book outline"):
      case t("Remove from book outline"):
      case t("Update book outline"):
        print book_node_link();
        break;
Dries's avatar
 
Dries committed
704 705 706 707 708 709 710 711 712 713 714
      case "orphan":
        print book_admin_orphan();
        break;
      case "view":
        print book_admin_view($id);
        break;
      default:
    }
  }
}

Dries's avatar
 
Dries committed
715
?>