book.module 14.8 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
function book_node($field) {
  global $user;

Dries's avatar
   
Dries committed
7
  $info["name"] = t("book page");
Dries's avatar
   
Dries committed
8
  $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
9
10
11
12
13

  return $info[$field];
}

function book_access($op, $node) {
Dries's avatar
   
Dries committed
14
  global $user;
Dries's avatar
   
Dries committed
15
16

  if ($op == "view") {
Dries's avatar
   
Dries committed
17
18
19
20
21
22
23
24
    /*
    ** 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
25
26
27
28
29
30
31
32
  }

  if  ($op == "create") {
    return 1;
  }

  if ($op == "update") {

Dries's avatar
   
Dries committed
33
    /*
Dries's avatar
   
Dries committed
34
35
36
37
    ** Everyone can upate a book page if there are no suggested updates
    ** of that page waiting for approval 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
38
39
    */

Dries's avatar
   
Dries committed
40
    return !$node->moderate && $node->revision;
Dries's avatar
   
Dries committed
41
  }
Dries's avatar
   
Dries committed
42
43
}

Dries's avatar
   
Dries committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
function book_save($op, $node) {

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

  if ($op == "create") {
    return array("moderate" => 1, "parent", "promote" => 0, "status" => 1, "weight");
  }

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

  if ($op == "update") {
    if (user_access("administer nodes")) {
      /*
      ** If a node administrator updates a book page, we don't create a
      ** new revision unless we are explicitly instructed to.
      */

      return array("parent", "weight");
    }
    else {
      /*
      ** 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 derault.
      */

      return array("created" => time(), "moderate" => 1, "parent", "promote" => 0, "score" => 0, "status" => 1, "users" => "", "revisions", "votes" => 0, "weight");
    }
  }

}

Dries's avatar
   
Dries committed
80
81
82
function book_link($type) {
  if ($type == "page" && user_access("access content")) {
    $links[] = "<a href=\"module.php?mod=book\">". t("collaborative book") ."</a>";
Dries's avatar
   
Dries committed
83
  }
Dries's avatar
   
Dries committed
84

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

Dries's avatar
   
Dries committed
89
  return $links ? $links : array();
Dries's avatar
   
Dries committed
90
91
}

Dries's avatar
   
Dries committed
92
function book_load($node) {
Dries's avatar
   
Dries committed
93
  $book = db_fetch_object(db_query("SELECT parent, weight, revision FROM book WHERE nid = '$node->nid'"));
Dries's avatar
   
Dries committed
94
  return $book;
Dries's avatar
   
Dries committed
95
96
}

Dries's avatar
   
Dries committed
97
function book_insert($node) {
Dries's avatar
   
Dries committed
98
  db_query("INSERT INTO book (nid, parent, weight) VALUES ('$node->nid', '$node->parent', '$node->weight')");
Dries's avatar
   
Dries committed
99
}
Dries's avatar
   
Dries committed
100

Dries's avatar
   
Dries committed
101
function book_update($node) {
Dries's avatar
   
Dries committed
102
  db_query("UPDATE book SET parent = '$node->parent', weight = '$node->weight' WHERE nid = '$node->nid'");
Dries's avatar
   
Dries committed
103
}
Dries's avatar
   
Dries committed
104

Dries's avatar
   
Dries committed
105
106
function book_delete($node) {
  db_query("DELETE FROM book WHERE nid = '$node->nid'");
Dries's avatar
   
Dries committed
107
108
}

Dries's avatar
   
Dries committed
109

Dries's avatar
   
Dries committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
function book_form($node, $help, $error) {
  global $user;

  $output .= form_select(t("Parent"), "parent", $node->parent, book_toc(), t("The parent subject or category the page belongs in."));
  $output .= form_textarea(t("Content"), "body", $node->body, 60, 20, t("Allowed HTML tags") .": ". htmlspecialchars(variable_get("allowed_html", "")));
  $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")) {
    $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 nodes will sink and the lighter nodes will be positioned nearer the top."));
  }
  else {

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

Dries's avatar
   
Dries committed
126
127
    $help = book_node("description");

Dries's avatar
   
Dries committed
128
129
130
131
132
133
134
135

    /*
    ** If a regular user updates a book page, we create a new revision
    ** authored by that user:
    */

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

Dries's avatar
   
Dries committed
136
    $node->uid = $user->uid;    // $node is passed by reference
Dries's avatar
   
Dries committed
137
138
139
140
141
142
143
    $node->name = $user->name;

  }

  return $output;
}

Dries's avatar
   
Dries committed
144
function book_location($node, $nodes = array()) {
Dries's avatar
   
Dries committed
145
  $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
146
147
148
149
150
151
152
  if ($parent->title) {
    $nodes = book_location($parent, $nodes);
    array_push($nodes, $parent);
  }
  return $nodes;
}

Dries's avatar
   
Dries committed
153
function book_view($node, $main = 0) {
Dries's avatar
   
Dries committed
154
155
156
157
158
159
160
161
162
  global $theme, $mod;

  /*
  ** Always display the most recently approved revision of a node
  ** unless we have to display it in the context of the moderation
  ** queue.
  */

  if ($node->moderate && $mod != "queue") {
Dries's avatar
   
Dries committed
163
    $node = node_revision_load($node, end(node_revision_list($node)));
Dries's avatar
   
Dries committed
164
165
166
167
168
169
170
  }

  /*
  ** 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
171

Dries's avatar
   
Dries committed
172
173
  if ($main) {
    $theme->node($node, $main);
Dries's avatar
   
Dries committed
174
  }
Dries's avatar
   
Dries committed
175
176
  else {
    if ($node->nid && $node->parent) {
Dries's avatar
   
Dries committed
177
178
      $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) ."')) 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) ."')) ORDER BY b.weight DESC, n.title DESC"));
Dries's avatar
   
Dries committed
179
    }
Dries's avatar
   
Dries committed
180

Dries's avatar
   
Dries committed
181
    $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n";
Dries's avatar
   
Dries committed
182

Dries's avatar
   
Dries committed
183
184
    if ($node->title) {
      foreach (book_location($node) as $level) {
Dries's avatar
   
Dries committed
185
        $location .= "$indent <a href=\"node.php?id=$level->nid\">$level->title</a><br />";
Dries's avatar
   
Dries committed
186
187
        $indent .= "-";
      }
Dries's avatar
   
Dries committed
188

Dries's avatar
   
Dries committed
189
190
191
      $output .= " <tr><td colspan=\"2\">$location</td><td align=\"right\"><a href=\"module.php?mod=node&op=edit&id=$node->nid\">". t("update this book page") ."</a></td></tr>";
      $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
192
    }
Dries's avatar
   
Dries committed
193

Dries's avatar
   
Dries committed
194
    if ($node->body) {
Dries's avatar
   
Dries committed
195
      $output .= " <tr><td colspan=\"3\"><br />". check_output($node->body, 1) ."</td></tr>";
Dries's avatar
   
Dries committed
196
    }
Dries's avatar
 
Dries committed
197

Dries's avatar
   
Dries committed
198
    if ($node->nid) {
Dries's avatar
   
Dries committed
199
      $output .= " <tr><td colspan=\"3\"><br />". book_tree($node->nid) ."</td></tr>";
Dries's avatar
   
Dries committed
200
    }
Dries's avatar
   
Dries committed
201

Dries's avatar
   
Dries committed
202
203
204
205
    $output .= " <tr><td colspan=\"3\"><hr /></td></tr>";
    $output .= " <tr><td align=\"left\" width=\"33%\">". ($prev ? "<a href=\"node.php?id=$prev->nid\">". t("previous") ."</a>" : t("previous")) ."</td><td align=\"center\" width=\"34%\"><a href=\"module.php?mod=book\">index</a></td><td align=\"right\" width=\"33%\">". ($next ? "<a href=\"node.php?id=$next->nid\">". t("next") ."</a>" : t("next")) ."</td></tr>";
    $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\">". t("up") ."</a>" : t("up")) ."</td><td align=\"right\" width=\"33%\">". ($next ? "<small>". check_output($next->title) ."</small>" : "&nbsp;") ."</td></tr>";
    $output .= "</table>";
Dries's avatar
   
Dries committed
206

Dries's avatar
   
Dries committed
207
208
    $theme->box(t("Handbook"), $output);
  }
Dries's avatar
 
Dries committed
209
210
}

Dries's avatar
   
Dries committed
211
function book_toc($parent = "", $indent = "", $toc = array()) {
Dries's avatar
   
Dries committed
212

Dries's avatar
   
Dries committed
213
214
215
216
217
218
219
220
221
  /*
  ** Select all child nodes:
  */

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

  /*
  ** Add the root node:
  */
Dries's avatar
   
Dries committed
222

Dries's avatar
   
Dries committed
223
  if (user_access("administer nodes")) {
Dries's avatar
   
Dries committed
224
    $toc[0] = "<root>";
Dries's avatar
   
Dries committed
225
226
  }

Dries's avatar
   
Dries committed
227
228
229
230
  /*
  ** Build the table of contents:
  */

Dries's avatar
   
Dries committed
231
  while ($node = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
232
233
    $toc[$node->nid] = "$indent $node->title";
    $toc = book_toc($node->nid, "$indent-", $toc);
Dries's avatar
   
Dries committed
234
  }
Dries's avatar
   
Dries committed
235

Dries's avatar
   
Dries committed
236
237
238
  return $toc;
}

Dries's avatar
Dries committed
239
function book_tree($parent = "", $depth = 0) {
Dries's avatar
 
Dries committed
240

Dries's avatar
   
Dries committed
241
  if ($depth < 3) {
Dries's avatar
   
Dries committed
242
243
244
245
    /*
    ** Select all child nodes and render them into a table of contents:
    */

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

Dries's avatar
   
Dries committed
248
249
250
     while ($page = db_fetch_object($result)) {
       // load the node:
       $node = node_load(array("nid" => $page->nid));
Dries's avatar
   
Dries committed
251

Dries's avatar
   
Dries committed
252
253
254
255
       // take the most recent approved revision:
       if ($node->moderate) {
         $node = node_revision_load($node, end(node_revision_list($node)));
       }
Dries's avatar
   
Dries committed
256

Dries's avatar
   
Dries committed
257
258
       // output the content:
       $output .= "<li><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a></li>";
Dries's avatar
   
Dries committed
259

Dries's avatar
   
Dries committed
260
261
262
263
264
       // build the sub-tree of each child:
       $output .= book_tree($node->nid, $depth + 1);
     }

     $output = "<ul>$output</ul>";
Dries's avatar
   
Dries committed
265

Dries's avatar
   
Dries committed
266
  }
Dries's avatar
   
Dries committed
267

Dries's avatar
   
Dries committed
268
269
270
  return $output;
}

Dries's avatar
   
Dries committed
271
function book_render() {
Dries's avatar
   
Dries committed
272
  global $theme;
Dries's avatar
Dries committed
273

Dries's avatar
   
Dries committed
274
  $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 ORDER BY b.weight");
Dries's avatar
   
Dries committed
275

Dries's avatar
   
Dries committed
276
277
278
279
280
281
  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
282
      $node = node_revision_load($node, end(node_revision_list($node)));
Dries's avatar
   
Dries committed
283
284
285
    }

    // output the content:
Dries's avatar
   
Dries committed
286
    $output .= "<dt><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a></dt><dd>". check_output($node->body, 1) ."<br /><br /></dd>";
Dries's avatar
   
Dries committed
287
288
289
  }

  $theme->header();
Dries's avatar
   
Dries committed
290
  $theme->box(t("Handbook"), "<dl>$output</dl>");
Dries's avatar
   
Dries committed
291
292
293
294
295
296
  $theme->footer();
}

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

Dries's avatar
   
Dries committed
297
  if (user_access("access content")) {
Dries's avatar
   
Dries committed
298
299
    switch ($op) {
      case "feed":
Dries's avatar
   
Dries committed
300
        print book_export_html($id, $depth = 1);
Dries's avatar
   
Dries committed
301
302
303
        break;
      default:
        book_render();
Dries's avatar
   
Dries committed
304
305
306
307
308
309
310
    }
  }
  else {
    $theme->header();
    $theme->box(t("Access denied"), message_access());
    $theme->footer();
  }
Dries's avatar
 
Dries committed
311
312
}

Dries's avatar
   
Dries committed
313
function book_export_html($id = "", $depth = 1) {
Dries's avatar
   
Dries committed
314
  $result = db_query("SELECT n.nid FROM node n LEFT JOIN book b ON n.nid = b.nid WHERE n.type = 'book' AND n.status = 1 AND n.nid = '". check_input($id) ."'");
Dries's avatar
   
Dries committed
315

Dries's avatar
   
Dries committed
316
317
318
  while ($page = db_fetch_object($result)) {
    // load the node:
    $node = node_load(array("nid" => $page->nid));
Dries's avatar
   
Dries committed
319

Dries's avatar
   
Dries committed
320
321
    // take the most recent approved revision:
    if ($node->moderate) {
Dries's avatar
   
Dries committed
322
      $node = node_revision_load($node, end(node_revision_list($node)));
Dries's avatar
   
Dries committed
323
324
325
    }

    // output the content:
Dries's avatar
   
Dries committed
326
    $output .= "<h$depth>". check_output($node->title) ."</h$depth>";
Dries's avatar
   
Dries committed
327
328
329
330

    if ($node->body) {
      $output .= "<blockquote>". check_output($node->body, 1) ."</blockquote>";
    }
Dries's avatar
   
Dries committed
331
  }
Dries's avatar
   
Dries committed
332

Dries's avatar
   
Dries committed
333
334
335
336
337
338
  $output .= book_export_html_recursive($id, $depth);

  return $output;
}

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

Dries's avatar
   
Dries committed
341
342
343
344
345
346
  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
347
      $node = node_revision_load($node, end(node_revision_list($node)));
Dries's avatar
   
Dries committed
348
349
350
    }

    // output the content:
Dries's avatar
   
Dries committed
351
    $output .= "<h$depth>". check_output($node->title) ."</h$depth>";
Dries's avatar
   
Dries committed
352
353
354
355
356

    if ($node->body) {
      $output .= "<blockquote>". check_output($node->body, 1) ."</blockquote>";
    }

Dries's avatar
   
Dries committed
357
    $output .= book_export_html_recursive($node->nid, $depth + 1);
Dries's avatar
   
Dries committed
358
  }
Dries's avatar
   
Dries committed
359

Dries's avatar
   
Dries committed
360
361
  return $output;
}
Dries's avatar
   
Dries committed
362

Dries's avatar
   
Dries committed
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
function book_admin_page($nid, $depth = 0) {
  $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);

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

  while ($node = db_fetch_object($result)) {
    $node = node_load(array("nid" => $node->nid));

    $output .= "<tr>";
    $output .= " <td><div style=\"padding-left: ". (25 * $depth) ."px;\">$node->title</div></td>";
    $output .= " <td align=\"center\">". ($rev = end(node_revision_list($node)) ? $rev : 0) ."</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>";
    $output .= book_admin_page($node->nid, $depth + 1);
  }

  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>";
  $output .= book_admin_page($nid);
  $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) {
      case "orphan":
        print book_admin_orphan();
        break;
      case "view":
        print book_admin_view($id);
        break;
      default:
    }
  }
}

Dries's avatar
 
Dries committed
452
?>