Parent Directory
|
Revision Log
|
Revision Graph
task #350303: Move license and donation information to places fitting with cvs.drupal.org guidelines http://drupal.org/node/439226
| 1 | <?php |
| 2 | // $Id: outline.module,v 1.57 2009/04/07 09:11:14 augustin Exp $ |
| 3 | |
| 4 | /** |
| 5 | * @file |
| 6 | * A module to enhance the core book.module, adding more customability and flexibility. |
| 7 | * |
| 8 | */ |
| 9 | |
| 10 | // functions are in this order: |
| 11 | ////// GENERAL HOOKS ///////////////////////////////////////////////////////////////////////////////////// |
| 12 | ////// FORM HANDLING ///////////////////////////////////////////////////////////////////////////////////// |
| 13 | ////// OWN FUNCTIONS ///////////////////////////////////////////////////////////////////////////////////// |
| 14 | ////// MENU CALLBACKS //////////////////////////////////////////////////////////////////////////////////// |
| 15 | ////// THEME FUNCTIONS /////////////////////////////////////////////////////////////////////////////////// |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 22 | ////// GENERAL HOOKS ///////////////////////////////////////////////////////////////////////////////////// |
| 23 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 24 | ////// Listed in alphabetical order ////////////////////////////////////////////////////////////////////// |
| 25 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 26 | |
| 27 | /** |
| 28 | * Implementation of hook_form_alter(). |
| 29 | * |
| 30 | * @see book_form_alter() |
| 31 | */ |
| 32 | function outline_form_alter(&$form, $form_state, $form_id) { |
| 33 | |
| 34 | // Site wide settings. |
| 35 | if ('book_admin_settings' == $form_id) { |
| 36 | $form['book_child_type']['#description'] .= '<br /><strong>' . t('This setting is the site-wide default. Outline.module allows you to have a per-book default and a per node value.') . '</strong>'; |
| 37 | } |
| 38 | |
| 39 | $node_form = FALSE; |
| 40 | // Add or remove node form items according to outline perm settings. |
| 41 | if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) { |
| 42 | $node_form = TRUE; |
| 43 | $node = $form['#node']; |
| 44 | if(isset($node->nid)) { |
| 45 | _outline_load_node($node); |
| 46 | } |
| 47 | $book_action = user_access('administer book outlines'); |
| 48 | if (user_access('add content to books') && ((!empty($node->book['mlid']) && !empty($node->nid)) |
| 49 | || book_type_is_allowed($node->type))) { |
| 50 | $book_action = TRUE; |
| 51 | } |
| 52 | $action = outline_check_action($node, 'node_form', $book_action); |
| 53 | switch ($action) { |
| 54 | case 'create': |
| 55 | // Copied from book_form_alter(); |
| 56 | _book_add_form_elements($form, $node); |
| 57 | $form['book']['pick-book'] = array( |
| 58 | '#type' => 'submit', |
| 59 | '#value' => t('Change book (update list of parents)'), |
| 60 | '#submit' => array('node_form_submit_build_node'), |
| 61 | '#weight' => 20, |
| 62 | ); |
| 63 | break; |
| 64 | case 'delete': |
| 65 | unset($form['book']); |
| 66 | // fallthrough to set default values. |
| 67 | case 'leave off': |
| 68 | if (!empty($node->outline)) { // The book is outlined, but the user has no permission to change the book settings. |
| 69 | $form['bid'] = array( |
| 70 | '#type' => 'value', |
| 71 | '#value' => $node->book['bid'], |
| 72 | ); |
| 73 | $form['mlid'] = array( |
| 74 | '#type' => 'value', |
| 75 | '#value' => $node->book['mlid'], |
| 76 | ); |
| 77 | } |
| 78 | break; |
| 79 | } |
| 80 | if (!empty($form['book'])) { |
| 81 | $form['book']['bid']['#options'] = _outline_book_options($node); |
| 82 | } |
| 83 | |
| 84 | } |
| 85 | |
| 86 | // Node outline tab and node form. |
| 87 | if (!empty($form['book']) && ('book_outline_form' == $form_id // Form on node outline tab, or (below) form on node edit tab. |
| 88 | || $node_form)) { |
| 89 | |
| 90 | $access = TRUE; // TODO. See book_form_alter(). |
| 91 | if ($access) { |
| 92 | // We replace the ahah callback with our own. |
| 93 | $form['book']['bid']['#ahah']['path'] = 'outline/js/form'; |
| 94 | $form['book']['bid']['#ahah']['wrapper'] = 'outline-ahah-wrapper'; |
| 95 | // The weights are added to make sure the wrapper includes only and all what we want. |
| 96 | $form['book']['plid']['#weight'] = 11; |
| 97 | |
| 98 | $form['book']['outline-ahah-wrapper-begin'] = array( |
| 99 | '#value' => ' ', |
| 100 | '#prefix' => '<div id="outline-ahah-wrapper">', |
| 101 | '#weight' => 10, |
| 102 | ); |
| 103 | $form['book']['outline-ahah-wrapper-end'] = array( |
| 104 | '#value' => ' ', |
| 105 | '#suffix' => '</div>', |
| 106 | '#weight' => 12, |
| 107 | ); |
| 108 | // Add our own form elements. |
| 109 | $bid = isset($form['#node']->book['bid']) ? $form['#node']->book['bid'] : 0; |
| 110 | outline_add_elements_form($form, $bid); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | // In addition to the fields above, we need to add a submit handler for the form on the outline tab. |
| 115 | if ('book_outline_form' == $form_id) { |
| 116 | $form['#submit'][] = 'outline_tab_form_submit'; |
| 117 | } |
| 118 | |
| 119 | } |
| 120 | |
| 121 | /** |
| 122 | * Implementation of hook_help(). |
| 123 | */ |
| 124 | function outline_help($path, $arg) { |
| 125 | // TODO: http://drupal.org/node/114774#hook-help |
| 126 | switch ($path) { |
| 127 | case 'admin/help#outline': |
| 128 | return t('<p>Outline module enhances the functionality of book.module. It allows to have a more fine grained customization of each book, adding more settings and permissions to it.</p>'); |
| 129 | |
| 130 | case 'admin/content/book/settings': |
| 131 | return t('<p>You may also look at the <a href="!outline-setting-url">outline.module setting page</a> for more relevant settings.</p>', array('!outline-setting-url' => url('admin/settings/outline'))); |
| 132 | |
| 133 | case 'admin/content/book/%': |
| 134 | return t('See the menu setting to insert other pages into menu outline.'); |
| 135 | |
| 136 | case 'admin/build/menu-customize/%': |
| 137 | // TODO: if (% is_book outline) ... |
| 138 | return t('check the book setting.'); |
| 139 | |
| 140 | case 'admin/settings/outline': |
| 141 | return t('<p>You may also look at the <a href="!book-setting-url">book.module setting page</a> for more relevant settings.</p>', array('!book-setting-url' => url('admin/content/book/settings'))); |
| 142 | |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Implementation of hook_init(). |
| 148 | */ |
| 149 | function outline_init() { |
| 150 | drupal_add_css(drupal_get_path('module', 'outline') .'/stylesheet.css'); |
| 151 | } |
| 152 | |
| 153 | /** |
| 154 | * Implementation of hook_link(). |
| 155 | */ |
| 156 | function outline_link($type, $node = NULL, $teaser = FALSE) { |
| 157 | global $user; |
| 158 | $links = array(); |
| 159 | |
| 160 | if ('node' == $type && isset($node->book)) { |
| 161 | $bid = $node->outline['bid']; |
| 162 | if (!$teaser) { |
| 163 | $action = outline_check_perm($node, FALSE, 'add'); |
| 164 | if ($action) { |
| 165 | if (outline_check_author_perm($bid, $user->uid)) { |
| 166 | $child_type = variable_get('book_child_type', 'book'); |
| 167 | $node_type = $node->outline['books'][$bid]['child_type']; |
| 168 | $child_type_book_default = $node->outline['books'][$bid]['default_child_type']; |
| 169 | if ('<default>' != $node_type) { // A node defining its own child type. |
| 170 | $child_type = $node_type; |
| 171 | } |
| 172 | elseif ('<default>' != $child_type_book_default) { |
| 173 | $child_type = $child_type_book_default; |
| 174 | } |
| 175 | |
| 176 | if (node_access('create', $child_type) && 1 == $node->status && $node->book['depth'] < MENU_MAX_DEPTH) { |
| 177 | $links['outline_add_child'] = array( |
| 178 | 'title' => t('Add child !node_type', array( '!node_type' => node_get_types('name', $child_type))), |
| 179 | 'href' => "node/add/". str_replace('_', '-', $child_type), |
| 180 | 'query' => "parent=". $node->book['mlid'], |
| 181 | ); |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | } |
| 186 | } |
| 187 | return $links; |
| 188 | } |
| 189 | |
| 190 | /** |
| 191 | * Implementation of hook_link_alter(). |
| 192 | */ |
| 193 | function outline_link_alter(&$links, $node) { |
| 194 | // Since hook_link_alter is called several times, it's easier to unset the book_add_child link |
| 195 | // which has already been replaced by our own in outline_link(). |
| 196 | if (isset($links['book_add_child'])) { |
| 197 | unset($links['book_add_child']); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | /** |
| 202 | * Implementation of hook_menu(). |
| 203 | */ |
| 204 | function outline_menu() { |
| 205 | $items = array(); |
| 206 | |
| 207 | $items['admin/settings/outline'] = array( |
| 208 | 'title' => 'Outline settings', |
| 209 | 'description' => 'Set the site-wide default the TOC depth.', |
| 210 | 'page callback' => 'drupal_get_form', |
| 211 | 'page arguments' => array('outline_admin_settings'), |
| 212 | 'access arguments' => array('administer book outlines')); |
| 213 | $items['outline/js/form'] = array( |
| 214 | 'page callback' => 'outline_form_update', |
| 215 | 'access arguments' => array('access content'), |
| 216 | 'type' => MENU_CALLBACK, |
| 217 | ); |
| 218 | $items['admin/content/book'] = array( |
| 219 | 'title' => 'Books', |
| 220 | 'description' => "Manage your site's book outlines.", |
| 221 | 'page callback' => 'outline_admin_overview', |
| 222 | 'access arguments' => array('administer book outlines'), |
| 223 | ); |
| 224 | $items['admin/content/book/%node/permission'] = array( |
| 225 | 'title' => 'Edit the book permissions', |
| 226 | 'page callback' => 'drupal_get_form', |
| 227 | 'page arguments' => array('outline_permission_form', 3), |
| 228 | 'access callback' => '_book_outline_access', |
| 229 | 'access arguments' => array(3), |
| 230 | 'type' => MENU_CALLBACK, |
| 231 | ); |
| 232 | |
| 233 | return $items; |
| 234 | } |
| 235 | |
| 236 | /** |
| 237 | * Implementation of hook_nodeapi(). |
| 238 | */ |
| 239 | function outline_nodeapi(&$node, $op, $teaser, $page) { |
| 240 | global $user; |
| 241 | |
| 242 | switch ($op) { |
| 243 | case 'delete revision': |
| 244 | db_query('DELETE FROM {outline_book} WHERE book_vid = %d', $node->vid); |
| 245 | db_query('DELETE FROM {outline_node} WHERE vid = %d', $node->vid); |
| 246 | break; |
| 247 | case 'load': |
| 248 | // If we need, we can completely override the book meta data, thereby controlling which book navigation it will show. // TODO |
| 249 | |
| 250 | $info = NULL; |
| 251 | $result = db_query('SELECT n.*, b.book_vid, b.uid, b.default_child_type, b.default_toc_depth, b.book_role_perm, b.book_user_perm, b.restricted_types |
| 252 | FROM {outline_node} n JOIN {outline_book} b ON n.book_vid = b.book_vid WHERE nid = %d AND vid = %d ORDER BY is_default DESC', |
| 253 | $node->nid, $node->vid); |
| 254 | while ($row = db_fetch_array($result)) { |
| 255 | if ($row['is_default']) { |
| 256 | $info['outline']['bid'] = $row['bid']; |
| 257 | } |
| 258 | $info['outline']['books'][$row['bid']] = $row; |
| 259 | } |
| 260 | return $info; |
| 261 | case 'prepare': |
| 262 | // Prepare defaults in cases they are needed but book.module didn't prepare them. |
| 263 | // Why doesn't book.module prepare the node in every case, regardless to permissions? |
| 264 | // Is there any side effect to it? |
| 265 | if (empty($node->nid) && isset($_GET['parent']) && is_numeric($_GET['parent'])) { |
| 266 | // Load outline property to $node object. |
| 267 | $parent = book_link_load($_GET['parent']); |
| 268 | $result = db_query('SELECT b.* FROM {outline_book} b JOIN {node} n ON b.bid = n.nid |
| 269 | WHERE b.bid = %d AND n.vid = b.book_vid', $parent['bid']); |
| 270 | $node->outline = array(); |
| 271 | $row = db_fetch_array($result); |
| 272 | $node->outline['bid'] = $row['bid']; |
| 273 | $node->outline['books'][$row['bid']] = $row; |
| 274 | } |
| 275 | |
| 276 | if (empty($node->book) && !user_access('add content to books') && !user_access('administer book outlines')) { |
| 277 | $node->book = array(); |
| 278 | if (empty($node->nid) && isset($_GET['parent']) && is_numeric($_GET['parent'])) { |
| 279 | // Handle "Add child page" links: |
| 280 | $parent = book_link_load($_GET['parent']); |
| 281 | if ($parent && $parent['access']) { |
| 282 | $node->book['bid'] = $parent['bid']; |
| 283 | $node->book['plid'] = $parent['mlid']; |
| 284 | $node->book['menu_name'] = $parent['menu_name']; |
| 285 | } |
| 286 | } |
| 287 | // Set defaults. |
| 288 | $node->book += _book_link_defaults(!empty($node->nid) ? $node->nid : 'new'); |
| 289 | } |
| 290 | else { |
| 291 | if (isset($node->book['bid']) && !isset($node->book['original_bid'])) { |
| 292 | $node->book['original_bid'] = $node->book['bid']; |
| 293 | } |
| 294 | } |
| 295 | // Find the depth limit for the parent select. |
| 296 | if (isset($node->book['bid']) && !isset($node->book['parent_depth_limit'])) { |
| 297 | $node->book['parent_depth_limit'] = _book_parent_depth_limit($node->book); |
| 298 | } |
| 299 | break; |
| 300 | |
| 301 | case 'view': |
| 302 | if (!$teaser) { |
| 303 | if (!empty($node->book['bid']) && NODE_BUILD_NORMAL == $node->build_mode) { |
| 304 | $node->content['outline_navigation'] = array( |
| 305 | '#value' => theme('outline_navigation', $node), |
| 306 | '#weight' => 101, |
| 307 | ); |
| 308 | |
| 309 | } |
| 310 | } |
| 311 | break; |
| 312 | case 'update': |
| 313 | case 'insert': |
| 314 | _outline_update_outline($node); |
| 315 | break; |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | /** |
| 320 | * Implementation of hook_perm(). |
| 321 | */ |
| 322 | function outline_perm() { |
| 323 | //return array('administer outlines', 'outline posts', 'create new volumes', 'see printer-friendly version'); |
| 324 | } |
| 325 | |
| 326 | /** |
| 327 | * Implementation of hook_theme() |
| 328 | */ |
| 329 | function outline_theme() { |
| 330 | return array( |
| 331 | 'outline_navigation' => array( |
| 332 | 'arguments' => array('node' => NULL), |
| 333 | 'template' => 'Outline-navigation', // It is modified from the original book-navigation template. |
| 334 | ), |
| 335 | ); |
| 336 | } |
| 337 | |
| 338 | /** |
| 339 | * Implementation of hook_theme_registry_alter(). |
| 340 | */ |
| 341 | function outline_theme_registry_alter(&$theme_registry) { |
| 342 | // We cannot use this function to alter the book_navigation theme registry, |
| 343 | // because otherwise book.module would call template_preprocess_outline_navigation |
| 344 | // with the wrong argument. |
| 345 | // We must completely obliterate it instead. |
| 346 | $theme_registry['book_navigation'] = NULL; |
| 347 | } |
| 348 | |
| 349 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 350 | ////// FORM HANDLING ///////////////////////////////////////////////////////////////////////////////////// |
| 351 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 352 | |
| 353 | /** |
| 354 | * Form builder: edit the book outline permissions. |
| 355 | * |
| 356 | */ |
| 357 | function outline_permission_form(&$form_state, $node) { |
| 358 | $bid = $node->book['bid']; |
| 359 | if ($node->nid != $bid) { |
| 360 | drupal_goto('admin/content/book/' . $bid . '/permission'); |
| 361 | } |
| 362 | drupal_set_title(t('Outline permissions for %book', array('%book' => $node->title))); |
| 363 | $form = array(); |
| 364 | |
| 365 | $breadcrumb = array(); |
| 366 | $breadcrumb[] = l(t('Home'), NULL); |
| 367 | $breadcrumb[] = l(t('Administer'), 'admin'); |
| 368 | $breadcrumb[] = l(t('Content management'), 'admin/content'); |
| 369 | $breadcrumb[] = l(t('Books'), 'admin/content/book'); |
| 370 | drupal_set_breadcrumb($breadcrumb); |
| 371 | |
| 372 | $perms = array( |
| 373 | 'add' => array( |
| 374 | 'title' => t('Add content'), |
| 375 | 'description' => t('Grant the permission to add or move nodes into this book.'), |
| 376 | 'book_perm' => t('add content to books'), |
| 377 | 'per_role_perm' => TRUE, |
| 378 | ), |
| 379 | 'author' => array( |
| 380 | 'title' => t('Authorship'), |
| 381 | 'description' => t('If any user is set below, only nodes authored by these users can be added to the book. |
| 382 | Thus, you can have a single author or a multi-authors book, where the authors are specified.') . ' ' . |
| 383 | t('Make sure that the authors themselves have the right to add nodes to their own book!') . '<br />' . |
| 384 | t('If no user is specified, nodes authored by anybody can be added to the outline.') . '<br />' . |
| 385 | t('Users with the %perm can add any node authored by anybody in any case.', array('%perm' => t('administer book outlines'))), |
| 386 | 'book_perm' => t('add content to books'), |
| 387 | 'per_role_perm' => FALSE, |
| 388 | ), |
| 389 | ); |
| 390 | |
| 391 | $form['bid'] = array( |
| 392 | '#type' => 'value', |
| 393 | '#value' => $bid, |
| 394 | ); |
| 395 | |
| 396 | $form['vid'] = array( |
| 397 | '#type' => 'value', |
| 398 | '#value' => $node->vid, |
| 399 | ); |
| 400 | |
| 401 | $restrict_per_role = $node->outline['books'][$bid]['book_role_perm']; |
| 402 | |
| 403 | $form['restrict_per_role_previous_value'] = array( |
| 404 | '#type' => 'value', |
| 405 | '#value' => $restrict_per_role, |
| 406 | ); |
| 407 | |
| 408 | $form['restrict_per_role'] = array( |
| 409 | '#type' => 'checkbox', |
| 410 | '#title' => t('Restrict to specific roles.'), |
| 411 | '#default_value' => $restrict_per_role, |
| 412 | '#description' => t('Check this box to restrict or expand all the permissions below to specific roles for this book.') . '<br />' . |
| 413 | t('Uncheck it to remove all such restrictions and use the book module default permissions.'), |
| 414 | ); |
| 415 | |
| 416 | $form['perm'] = array( |
| 417 | '#type' => 'fieldset', |
| 418 | '#title' => t('Permissions for this book'), |
| 419 | '#collapsible' => FALSE, |
| 420 | '#tree' => TRUE, |
| 421 | ); |
| 422 | |
| 423 | foreach ($perms AS $name => $perm) { |
| 424 | $form['perm'][$name] = array( |
| 425 | '#type' => 'fieldset', |
| 426 | '#title' => $perm['title'], |
| 427 | '#collapsible' => TRUE, |
| 428 | '#collapsed' => FALSE, //TRUE, |
| 429 | '#tree' => TRUE, |
| 430 | ); |
| 431 | |
| 432 | $form['perm'][$name]['description'] = array( |
| 433 | '#value' => '<p>' . $perm['description'] . '</p>', |
| 434 | ); |
| 435 | |
| 436 | // Per ROLE form elements. |
| 437 | |
| 438 | if ($restrict_per_role && $perm['per_role_perm']) { |
| 439 | $roles = user_roles(TRUE); |
| 440 | $restrict_per_role_description = '<p>' . |
| 441 | t('Currently only the users who have the role listed above have this permission for this book.') . '<br />' . |
| 442 | t('Uncheck the %restrict box if you want to use the book module defaults instead.', |
| 443 | array('%restrict' => t('Restrict to specific roles.'))) |
| 444 | . '</p>'; |
| 445 | $role_default_value = array(); |
| 446 | $result = db_query("SELECT * FROM {outline_perm} WHERE bid = %d AND perm = '%s' AND type = 'role'", $bid, $name); |
| 447 | while ($role = db_fetch_object($result)) { |
| 448 | $role_default_value[$role->type_id] = $role->type_id; |
| 449 | } |
| 450 | } |
| 451 | elseif ($perm['per_role_perm']) { |
| 452 | $roles = array(); |
| 453 | $role_default_value = array(); |
| 454 | $restrict_per_role_description = '<p>' . t('Currently all users with the %perm have this permission for this book.<br /> |
| 455 | Check the %restrict box if you want to restrict or expand the permissions to specific roles.', |
| 456 | array('%perm' => $perm['book_perm'], '%restrict' => t('Restrict to specific roles.'))) . '</p>'; |
| 457 | } |
| 458 | |
| 459 | if ($perm['per_role_perm']) { |
| 460 | $form['perm'][$name]['roles'] = array( |
| 461 | '#type' => 'checkboxes', |
| 462 | '#title' => t('Roles'), |
| 463 | '#default_value' => $role_default_value, |
| 464 | '#options' => $roles, |
| 465 | '#description' => $restrict_per_role_description, |
| 466 | ); |
| 467 | } |
| 468 | else { |
| 469 | $form['perm'][$name]['roles'] = array( |
| 470 | '#type' => 'value', |
| 471 | '#value' => FALSE, |
| 472 | ); |
| 473 | } |
| 474 | |
| 475 | // Per USER form elements. |
| 476 | |
| 477 | $users = array(); |
| 478 | $user_default_value = array(); |
| 479 | $result = db_query("SELECT * FROM {outline_perm} WHERE bid = %d AND perm = '%s' AND type = 'user'", |
| 480 | $bid, $name); |
| 481 | while ($item = db_fetch_object($result)) { |
| 482 | $user = user_load(array('uid' => $item->type_id)); |
| 483 | $users[$user->uid] = $user->name; |
| 484 | $user_default_value[$user->uid] = $user->uid; |
| 485 | } |
| 486 | $description = t('Uncheck a user name to revoke the permission.'); |
| 487 | if (empty($users)) { |
| 488 | $description = t('No individual user have this permission.'); |
| 489 | } |
| 490 | |
| 491 | $form['perm'][$name]['users'] = array( |
| 492 | '#type' => 'checkboxes', |
| 493 | '#title' => t('Users'), |
| 494 | '#default_value' => array(), |
| 495 | '#options' => $users, |
| 496 | '#description' => $description, |
| 497 | '#default_value' => $user_default_value, |
| 498 | ); |
| 499 | |
| 500 | $form['perm'][$name]['new_user'] = array( |
| 501 | '#type' => 'textfield', |
| 502 | '#title' => t('Add a new user'), |
| 503 | '#description' => t('Individually selected users will be given this additional permission regardless of their roles or other permissions.'), |
| 504 | '#default_value' => '', |
| 505 | '#autocomplete_path' => 'user/autocomplete', |
| 506 | ); |
| 507 | } |
| 508 | |
| 509 | |
| 510 | $form['submit'] = array( |
| 511 | '#type' => 'submit', |
| 512 | '#value' => t('Submit'), |
| 513 | ); |
| 514 | |
| 515 | return $form; |
| 516 | } |
| 517 | |
| 518 | /** |
| 519 | * Form submit callback. |
| 520 | * |
| 521 | */ |
| 522 | function outline_permission_form_submit($form, &$form_state) { |
| 523 | $v = $form_state['values']; |
| 524 | $book_user_perm = FALSE; |
| 525 | |
| 526 | foreach ($v['perm'] AS $perm_name => $perm) { |
| 527 | |
| 528 | // Save permissions per role: |
| 529 | if ($v['restrict_per_role_previous_value'] && FALSE !== $perm['roles']) { |
| 530 | db_query("DELETE FROM {outline_perm} WHERE bid = %d AND perm = '%s' AND type = 'role'", $v['bid'], $perm_name); |
| 531 | foreach ($perm['roles'] AS $role_id) { |
| 532 | if ($role_id) { |
| 533 | db_query("INSERT INTO {outline_perm} (bid, perm, type, type_id) VALUES (%d, '%s', 'role', %d)", |
| 534 | $v['bid'], $perm_name, $role_id); |
| 535 | } |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | // Save permissions per user: |
| 540 | db_query("DELETE FROM {outline_perm} WHERE bid = %d AND perm = '%s' AND type = 'user'", $v['bid'], $perm_name); |
| 541 | if ($perm['new_user']) { |
| 542 | $user = user_load(array('name' => $perm['new_user'])); |
| 543 | if ('author' != $perm_name) { |
| 544 | $book_user_perm = TRUE; |
| 545 | } |
| 546 | db_query("INSERT INTO {outline_perm} (bid, perm, type, type_id) VALUES (%d, '%s', 'user', %d)", |
| 547 | $v['bid'], $perm_name, $user->uid); |
| 548 | } |
| 549 | foreach ($perm['users'] AS $user_id) { |
| 550 | if ($user_id) { |
| 551 | if ('author' != $perm_name) { |
| 552 | $book_user_perm = TRUE; |
| 553 | } |
| 554 | db_query("INSERT INTO {outline_perm} (bid, perm, type, type_id) VALUES (%d, '%s', 'user', %d)", |
| 555 | $v['bid'], $perm_name, $user_id); |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | } |
| 560 | |
| 561 | db_query('UPDATE {outline_book} SET book_role_perm = %d, book_user_perm = %d WHERE bid = %d AND book_vid = %d', |
| 562 | $v['restrict_per_role'], $book_user_perm, $v['bid'], $v['vid']); |
| 563 | drupal_set_message(t('The permissions have been saved'), 'status'); |
| 564 | } |
| 565 | |
| 566 | /** |
| 567 | * Submit handler for the form on the node outline tab. |
| 568 | * |
| 569 | * See also related handling in outline_nodeapi(). |
| 570 | */ |
| 571 | function outline_tab_form_submit($form, &$form_state) { |
| 572 | $node = $form['#node']; |
| 573 | _outline_update_outline($node); |
| 574 | } |
| 575 | |
| 576 | /** |
| 577 | * Common helper fonction for outline_tab_form_submit() and node forms. |
| 578 | * |
| 579 | * Performs all additions and updates to the book outline through node addition, |
| 580 | * node editing, node deletion, or the outline tab. |
| 581 | * See _book_update_outline(). |
| 582 | * |
| 583 | * This function has to catter for all the following scenarios (list non exhaustive): |
| 584 | * |
| 585 | * - A node is created, but not outlined: |
| 586 | * $node->is_new = 1; |
| 587 | * $node->book['bid'] = 0; |
| 588 | * $node->revision = 0; |
| 589 | * $node->outline = ''; |
| 590 | * -> do nothing. |
| 591 | * |
| 592 | * - A non-outlined node is edited and is used to create a new book without a revision: |
| 593 | * $node->is_new = ''; |
| 594 | * $node->book['bid'] = $node->nid; |
| 595 | * $node->revision = 0; |
| 596 | * $node->outline = ''; |
| 597 | * -> INSERT. |
| 598 | * |
| 599 | * - A non-outlined node is edited and is outlined in an existing book without a revision: |
| 600 | * $node->is_new = ''; |
| 601 | * $node->book['bid'] = $bid; // i.e. !empty(). |
| 602 | * $node->revision = 0; |
| 603 | * $node->outline = ''; |
| 604 | * -> INSERT. |
| 605 | * |
| 606 | * - An outlined node is edited without a revision: |
| 607 | * $node->is_new = ''; |
| 608 | * $node->book['bid'] = $bid; // i.e. !empty(). |
| 609 | * $node->revision = 0; |
| 610 | * -> UPDATE. |
| 611 | * |
| 612 | */ |
| 613 | function _outline_update_outline($node) { |
| 614 | // Check whether there exist an outline record for this node. |
| 615 | // $node->outline is passed empty, so we set it here. |
| 616 | _outline_load_node($node); |
| 617 | |
| 618 | $bid = FALSE; |
| 619 | if (!empty($node->book['bid'])) { // The book form was set. |
| 620 | $bid = $node->book['bid']; |
| 621 | $mlid = $node->book['mlid']; |
| 622 | $o = $node->outline; |
| 623 | } |
| 624 | elseif (!empty($node->bid)) { // There was no book form. Get values if applicable. |
| 625 | $bid = $node->bid; |
| 626 | $mlid = $node->mlid; |
| 627 | $o = $node->outline; |
| 628 | } |
| 629 | |
| 630 | // Set defaults for users without proper permissions: |
| 631 | if ($bid && !isset($node->book['outline'])) { |
| 632 | // TODO: bugfix use proper default values. |
| 633 | $b = array(); |
| 634 | $b['child_type'] = isset($o['books'][$bid]['child_type']) ? $o['books'][$bid]['child_type'] : '<default>'; |
| 635 | $b['toc_depth'] = isset($o['books'][$bid]['toc_depth']) ? $o['books'][$bid]['toc_depth'] : -1; |
| 636 | $b['book_toc_depth'] = isset($o['books'][$bid]['default_toc_depth']) ? $o['books'][$bid]['default_toc_depth'] : -1; |
| 637 | } |
| 638 | elseif (isset($node->book['outline'])) { |
| 639 | $b = $node->book['outline']; |
| 640 | } |
| 641 | else { // Nothing to do. |
| 642 | return; |
| 643 | } |
| 644 | |
| 645 | // Update an existing page which is already outlined, and without making a new revision: |
| 646 | if ($bid && empty($node->is_new) && empty($node->revision) && !empty($node->outline)) { |
| 647 | // The vid doesn't change. |
| 648 | if ($bid == $node->nid) { // We are updating a book cover. |
| 649 | db_query("UPDATE {outline_book} |
| 650 | SET uid = %d, default_child_type = '%s', default_toc_depth = %d, book_role_perm = %d, book_user_perm = %d |
| 651 | WHERE book_vid = %d", |
| 652 | $node->uid, $b['child_type'], $b['book_toc_depth'], $o['books'][$bid]['book_role_perm'], |
| 653 | $o['books'][$bid]['book_user_perm'], $node->vid); |
| 654 | db_query("UPDATE {outline_node} SET mlid = %d, child_type = '%s', toc_depth = %d WHERE vid = %d", |
| 655 | $mlid, $b['child_type'], $b['toc_depth'], $node->vid); |
| 656 | } |
| 657 | elseif (isset($node->outline)) { // We are upating a page in the book. |
| 658 | db_query("UPDATE {outline_node} SET mlid = %d, child_type = '%s', toc_depth = %d WHERE vid = %d", |
| 659 | $mlid, $b['child_type'], $b['toc_depth'], $node->vid); |
| 660 | } |
| 661 | return; // No INSERT to be done in this case. |
| 662 | } |
| 663 | |
| 664 | // Create a new page, or insert a new revision, or insert a previously not outlined node: |
| 665 | if ($bid) { // The page is added to a book. |
| 666 | if ($bid == $node->nid) { // We are creating a new book. |
| 667 | db_query("INSERT INTO {outline_book} (bid, book_vid, uid, default_child_type, default_toc_depth, book_role_perm, book_user_perm) |
| 668 | VALUES (%d, %d, %d, '%s', '%s', %d, %d)", |
| 669 | $bid, $node->vid, $node->uid, $b['child_type'], $b['book_toc_depth'], $o['books'][$bid]['book_role_perm'], |
| 670 | $o['books'][$bid]['book_user_perm']); |
| 671 | db_query("INSERT INTO {outline_node} (mlid, nid, vid, bid, book_vid, is_default, child_type, toc_depth) |
| 672 | VALUES (%d, %d, %d, %d, %d, 1, '%s', %d)", |
| 673 | $mlid, $node->nid, $node->vid, $bid, $node->vid, $b['child_type'], $b['toc_depth']); |
| 674 | // Update the vid in {outline_node}, so that the JOIN is up to date. |
| 675 | db_query('UPDATE {outline_node} SET book_vid = %d WHERE bid = %d', $node->vid, $node->nid); |
| 676 | } |
| 677 | else { |
| 678 | $book_vid = db_result(db_query('SELECT vid FROM {node} WHERE nid = %d', $bid)); |
| 679 | db_query("INSERT INTO {outline_node} (mlid, nid, vid, bid, book_vid, is_default, child_type, toc_depth) |
| 680 | VALUES (%d, %d, %d, %d, %d, 1, '%s', %d)", |
| 681 | $mlid, $node->nid, $node->vid, $bid, $book_vid, $b['child_type'], $b['toc_depth']); |
| 682 | |
| 683 | } |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | /** |
| 688 | * Form builder: add exta settings form elements to the node forms and on the outline tab. |
| 689 | * |
| 690 | * @param $bid: 0 if <none>, 'new' if <create a new book> or the bid of the chosen book. |
| 691 | */ |
| 692 | function outline_add_elements_form(&$form, $bid) { |
| 693 | global $user; |
| 694 | $node = $form['#node']; |
| 695 | |
| 696 | if (!$bid) { // we are not inserting the node in a book. |
| 697 | $form['book']['outline'] = array(); // Unset the outline form. |
| 698 | return; |
| 699 | } |
| 700 | |
| 701 | $is_book_cover = FALSE; |
| 702 | if ('new' == $bid || (!empty($node->nid) && $bid == $node->nid)) { |
| 703 | $is_book_cover = TRUE; |
| 704 | } |
| 705 | |
| 706 | $access = user_access('administer book outlines'); |
| 707 | if (!$access) { |
| 708 | return; |
| 709 | } |
| 710 | |
| 711 | $form['book']['outline'] = array( |
| 712 | '#type' => 'fieldset', |
| 713 | '#title' => t('Outline options'), |
| 714 | '#collapsible' => FALSE, |
| 715 | '#collapsed' => FALSE, |
| 716 | '#tree' => TRUE, |
| 717 | '#weight' => 11, |
| 718 | '#access' => $access, |
| 719 | ); |
| 720 | |
| 721 | // |
| 722 | // Child page node type. |
| 723 | // |
| 724 | |
| 725 | $types = node_get_types(); |
| 726 | $book_allowed_types = variable_get('book_allowed_types', array('book')); |
| 727 | $nt_options = array(); |
| 728 | $nt_options['<default>'] = '<use the book default>'; |
| 729 | foreach ($book_allowed_types as $nt) { |
| 730 | $nt_options[$nt] = $types[$nt]->name; |
| 731 | } |
| 732 | $site_default_type = variable_get('book_child_type', 'book'); |
| 733 | $nt_description = t('What node type do you want to chose for child pages?'); |
| 734 | |
| 735 | if ($is_book_cover) { |
| 736 | $nt_description .= '<br />'. t('The site default is currenty %nt but it may be changed any time', array('%nt' => $site_default_type)); |
| 737 | $nt_options['<default>'] = '<use the site default>'; |
| 738 | |
| 739 | } else { |
| 740 | $default_child_type = isset($node->outline['books'][$bid]['default_child_type']) |
| 741 | ? $node->outline['books'][$bid]['default_child_type'] : '<default>'; |
| 742 | if ('<default>' == $default_child_type) { |
| 743 | $default_child_type = $site_default_type; |
| 744 | } |
| 745 | $nt_description .= '<br />'. t('The book default is currenty %nt but it may be changed any time', array('%nt' => $default_child_type)); |
| 746 | } |
| 747 | |
| 748 | $form['book']['outline']['child_type'] = array( |
| 749 | '#type' => 'select', |
| 750 | '#title' => t('Content type for child pages'), |
| 751 | '#description' => $nt_description, |
| 752 | '#default_value' => (empty($node->outline['books'][$bid]['child_type']) ? '<default>' : $node->outline['books'][$bid]['child_type']), |
| 753 | '#options' => $nt_options, |
| 754 | '#access' => $access, |
| 755 | ); |
| 756 | |
| 757 | // |
| 758 | // TOC depth for child pages: |
| 759 | // |
| 760 | |
| 761 | $toc_options = drupal_map_assoc(array(-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); |
| 762 | $toc_options[-1] = '<use the site default>'; |
| 763 | $toc_description = t('The table of contents on the outline page will be displayed to this depth (depending upon your theme).'); |
| 764 | $site_default_toc_depth = variable_get('toc_default_depth', 5); |
| 765 | |
| 766 | if ($is_book_cover) { |
| 767 | $book_toc_description = $toc_description; |
| 768 | $book_toc_description .= '<br />'. t('This value will apply for the whole book, though it can be overridden at the node level if wanted.'); |
| 769 | $book_toc_description .= '<br />'. t('The site default is currenty %toc but it may be changed any time', |
| 770 | array('%toc' => $site_default_toc_depth)); |
| 771 | |
| 772 | $form['book']['outline']['book_toc_depth'] = array( |
| 773 | '#type' => 'select', |
| 774 | '#title' => t('Preferred depth for table of contents display <em>for child pages</em>'), |
| 775 | '#default_value' => (empty($node->outline['books'][$bid]['default_toc_depth']) ? -1 : $node->outline['books'][$bid]['default_toc_depth']), |
| 776 | '#options' => $toc_options, |
| 777 | '#description' => $book_toc_description, |
| 778 | '#access' => $access, |
| 779 | ); |
| 780 | |
| 781 | } |
| 782 | |
| 783 | // |
| 784 | // TOC depth for each node: |
| 785 | // |
| 786 | |
| 787 | $toc_options[-1] = '<use the book default>'; |
| 788 | |
| 789 | $default_toc_depth = isset($node->outline['books'][$bid]['default_toc_depth']) |
| 790 | ? $node->outline['books'][$bid]['default_toc_depth'] : '<default>'; |
| 791 | if (-1 == $default_toc_depth) { |
| 792 | $default_toc_depth = $site_default_toc_depth; |
| 793 | } |
| 794 | $toc_description .= '<br />'. t('The book default is currenty %toc but it may be changed any time', array('%toc' => $default_toc_depth)); |
| 795 | |
| 796 | $form['book']['outline']['toc_depth'] = array( |
| 797 | '#type' => 'select', |
| 798 | '#title' => t('Preferred depth for table of contents display'), |
| 799 | '#default_value' => (empty($node->outline['books'][$bid]['toc_depth']) ? -1 : $node->outline['books'][$bid]['toc_depth']), |
| 800 | '#options' => $toc_options, |
| 801 | '#description' => $toc_description, |
| 802 | '#access' => $access, |
| 803 | ); |
| 804 | } |
| 805 | |
| 806 | /** |
| 807 | * Form builder, for the admin setting pages (book and outline's). |
| 808 | */ |
| 809 | function outline_admin_settings_form() { |
| 810 | |
| 811 | $description = t('This value will be overriden by a per-book specific setting, if there is one.'); |
| 812 | $description .= t("This setting only makes a difference with outline's alternative navigation box."); |
| 813 | $form['toc_default_depth'] = array( |
| 814 | '#type' => 'select', |
| 815 | '#title' => t('Default depth for table of contents display for posts newly added to an outline'), |
| 816 | '#description' => $description, |
| 817 | '#default_value' => variable_get('toc_default_depth', 5), |
| 818 | '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9)), |
| 819 | ); |
| 820 | |
| 821 | return $form; |
| 822 | } |
| 823 | |
| 824 | |
| 825 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 826 | ////// OWN FUNCTIONS ///////////////////////////////////////////////////////////////////////////////////// |
| 827 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 828 | |
| 829 | /** |
| 830 | * Check if there are any authorships restriction to nodes added in outline. |
| 831 | * |
| 832 | * @param $uid int: |
| 833 | * $user->uid. |
| 834 | * @return bool: |
| 835 | * whether the user is allowed to perform the operation or not. |
| 836 | */ |
| 837 | function outline_check_author_perm($bid, $uid) { |
| 838 | |
| 839 | $count = db_result(db_query("SELECT COUNT(*) FROM {outline_perm} WHERE bid = %d AND perm = 'author' AND type = 'user'", $bid)); |
| 840 | if (!$count) { |
| 841 | return TRUE; // There are no record, so no restriction apply. |
| 842 | } |
| 843 | |
| 844 | $count = db_result(db_query("SELECT COUNT(*) FROM {outline_perm} WHERE bid = %d AND perm = 'author' AND type = 'user' |
| 845 | AND type_id = %d", $bid, $uid)); |
| 846 | if ($count) { |
| 847 | return TRUE; // Nodes by this author are allowed. |
| 848 | } |
| 849 | |
| 850 | return FALSE; // Nodes by this author are not allowed. |
| 851 | } |
| 852 | |
| 853 | /** |
| 854 | * Returns an array of books a user can add or move nodes to. |
| 855 | * |
| 856 | * This array can be directly used in a form. |
| 857 | */ |
| 858 | function _outline_book_options($node) { |
| 859 | global $user; |
| 860 | static $options; |
| 861 | |
| 862 | if (isset($options)) { |
| 863 | return $options; |
| 864 | } |
| 865 | |
| 866 | // See book.module book_form_alter(). |
| 867 | $options = array(); |
| 868 | $nid = isset($node->nid) ? $node->nid : 'new'; |
| 869 | |
| 870 | if (isset($node->nid) && ($nid == $node->book['original_bid']) && (0 == $node->book['parent_depth_limit'])) { |
| 871 | // This is the top level node in a maximum depth book and thus cannot be moved. |
| 872 | $options[$node->nid] = $node->title; |
| 873 | } |
| 874 | else { |
| 875 | foreach (book_get_books() as $book) { |
| 876 | $book_node = node_load($book['nid']); |
| 877 | if (outline_check_perm($book_node, user_access('add content to books'), 'add')) { |
| 878 | if ($book_node->book['bid'] == $node->book['original_bid']) { // We can leave the node in the current book. |
| 879 | $options[$book['nid']] = $book['title']; |
| 880 | } |
| 881 | elseif (outline_check_author_perm($book_node->book['bid'], $node->uid)) { // For other books, see authorship restrictions. |
| 882 | $options[$book['nid']] = $book['title']; |
| 883 | } |
| 884 | } |
| 885 | } |
| 886 | } |
| 887 | if (user_access('create new books') && ('new' == $nid || ($nid != $node->book['original_bid']))) { |
| 888 | // The node can become a new book, if it is not one already. |
| 889 | $options = array($nid => '<'. t('create a new book') .'>') + $options; |
| 890 | } |
| 891 | if (!$node->book['mlid']) { |
| 892 | // The node is not currently in a the hierarchy. |
| 893 | $options = array(0 => '<'. t('none') .'>') + $options; |
| 894 | } |
| 895 | |
| 896 | // If 'none' is the only option, unset everything. |
| 897 | if (1 == count($options) && isset($options[0]) && '<'. t('none') .'>' == $options[0]) { |
| 898 | $options = array(); |
| 899 | } |
| 900 | return $options; |
| 901 | } |
| 902 | |
| 903 | /** |
| 904 | * Load the $node->outline property into the node object. |
| 905 | * |
| 906 | * The node object passed to some hooks are not fully loaded and do not contain the $node->outline property. |
| 907 | * We cannot use node_load() as it will override the original values of other $node properties. |
| 908 | */ |
| 909 | function _outline_load_node(&$node) { |
| 910 | static $outline; |
| 911 | |
| 912 | if (isset($outline) && empty($node->old_vid)) { // When creating a new revision, we must force a reload. |
| 913 | $node->outline = $outline; |
| 914 | } |
| 915 | |
| 916 | if (empty($node->outline)) { |
| 917 | // When creating a new revision to a node, we need to check the record for the older revision. |
| 918 | $current_vid = $node->vid; |
| 919 | if (!empty($node->old_vid)) { |
| 920 | $node->vid = $node->old_vid; |
| 921 | } |
| 922 | $load_outline = outline_nodeapi($node, 'load', 0, 1); |
| 923 | $node->outline = $load_outline['outline']; |
| 924 | $outline = $load_outline['outline']; |
| 925 | $node->vid = $current_vid; |
| 926 | } |
| 927 | } |
| 928 | |
| 929 | /** |
| 930 | * Check whether the user is permitted to perform the action or not. |
| 931 | * |
| 932 | * @param $outline_action (bool): |
| 933 | * It is actually the default book.module permission. |
| 934 | */ |
| 935 | function outline_check_perm($node, $outline_action, $perm) { |
| 936 | global $user; |
| 937 | $bid = $node->outline['bid']; |
| 938 | |
| 939 | if (user_access('administer book outlines')) { |
| 940 | $outline_action = TRUE; |
| 941 | } |
| 942 | elseif ($node->outline['books'][$bid]['book_role_perm']) { |
| 943 | $rids = array(); |
| 944 | foreach ($user->roles AS $rid => $role) { |
| 945 | $rids[$rid] = $rid; |
| 946 | } |
| 947 | $args = array(); |
| 948 | $args[] = $bid; |
| 949 | $args[] = 'add'; |
| 950 | $args += $rids; |
| 951 | $count = db_result(db_query("SELECT COUNT(*) FROM {outline_perm} WHERE bid = %d AND perm = '%s' AND type = 'role' |
| 952 | AND type_id IN (" . db_placeholders($rids) . ")", $args)); |
| 953 | $outline_action = !empty($count); |
| 954 | } |
| 955 | |
| 956 | if (!$outline_action && $node->outline['books'][$bid]['book_user_perm']) { |
| 957 | $count = db_result(db_query("SELECT COUNT(*) FROM {outline_perm} WHERE bid = %d AND perm = '%s' AND type = 'user' |
| 958 | AND type_id = %d", $bid, $perm, $user->uid)); |
| 959 | $outline_action = !empty($count); |
| 960 | } |
| 961 | |
| 962 | return $outline_action; |
| 963 | } |
| 964 | |
| 965 | /** |
| 966 | * Check whether we need to overrule book.module's behavior, and if so in which way. |
| 967 | * |
| 968 | * @param: $node node object. |
| 969 | * @param: $context, string identifying the context (who is calling this function). // TODO: when all features are implemented, check whether $context is needed. Remove if necessary. |
| 970 | * @param: $book_action, bool: whether book.module believes the user has the perm or not. |
| 971 | * @return: $action string. |
| 972 | */ |
| 973 | function outline_check_action($node, $context, $book_action) { |
| 974 | |
| 975 | if (empty($node->outline)) { // Creating a new node. Book.module didn't set anything for lack of permission. |
| 976 | $options = _outline_book_options($node); |
| 977 | if (!empty($options)) { |
| 978 | return 'create'; |
| 979 | } |
| 980 | else { |
| 981 | return 'leave off'; |
| 982 | } |
| 983 | } |
| 984 | |
| 985 | $outline_action = outline_check_perm($node, $book_action, 'add'); |
| 986 | |
| 987 | switch (TRUE) { |
| 988 | case $book_action AND $outline_action: |
| 989 | // Both modules agree the user has such a perm. Some extra checks might be needed. |
| 990 | return 'leave on'; |
| 991 | case !$book_action AND !$outline_action: |
| 992 | // Both modules agree the use has no such perm. Do nothing. |
| 993 | return 'leave off'; |
| 994 | case $book_action AND !$outline_action: |
| 995 | // Overule book.module: remove the appropriate items. |
| 996 | return 'delete'; |
| 997 | case !$book_action AND $outline_action: |
| 998 | // Overule book.module: add the appropriate items. |
| 999 | return 'create'; |
| 1000 | } |
| 1001 | |
| 1002 | } |
| 1003 | |
| 1004 | /** |
| 1005 | * Format the menu links for the TOC of the current page. |
| 1006 | * |
| 1007 | * @param $node |
| 1008 | * The node object for the current page. |
| 1009 | */ |
| 1010 | function outline_page_toc($node) { |
| 1011 | $book_link = $node->book; |
| 1012 | $tree = menu_tree_all_data($book_link['menu_name']); |
| 1013 | $tree = _outline_page_toc_find_current_page($tree, $book_link); |
| 1014 | $depth = _outline_get_actual_toc_depth($node); |
| 1015 | $tree = _outline_page_toc_limit_depth($tree, $depth); |
| 1016 | if ($tree) { |
| 1017 | return menu_tree_output($tree); |
| 1018 | } |
| 1019 | } |
| 1020 | |
| 1021 | /** |
| 1022 | * Helper function for outline_page_toc(). |
| 1023 | * |
| 1024 | * The array structure returned by menu_tree_all_data has strange keys |
| 1025 | * containing the number 50000, the node title and its mlid. |
| 1026 | * I have not been able to find which part of core set such strange keys. |
| 1027 | * Therefore, in this function, I don't care what the keys are named. |
| 1028 | * |
| 1029 | * @param: $tree |
| 1030 | * The part of the menu array returned by menu_tree_all_data() |
| 1031 | * where we're looking for the portion of the array which is starting with the current page. |
| 1032 | * @param $book_link |
| 1033 | * The menu array for the current page. |
| 1034 | * |
| 1035 | * @return $found |
| 1036 | * The part of the menu array returned by menu_tree_all_data() |
| 1037 | * that we want to display on the current page. |
| 1038 | * |
| 1039 | */ |
| 1040 | function _outline_page_toc_find_current_page($tree, $book_link) { |
| 1041 | if (!empty($tree)) { |
| 1042 | foreach ($tree AS $key => $data) { |
| 1043 | if ($data['link']['mlid'] == $book_link['mlid']) { |
| 1044 | $found = $tree[$key]['below']; |
| 1045 | return $found; |
| 1046 | } |
| 1047 | if (!empty($data['below'])) { |
| 1048 | foreach ($data['below'] AS $key_below => $below) { |
| 1049 | $found = _outline_page_toc_find_current_page(array($key_below => $below), $book_link); |
| 1050 | if ($found) { |
| 1051 | return $found; |
| 1052 | } |
| 1053 | } |
| 1054 | } |
| 1055 | } |
| 1056 | } |
| 1057 | } |
| 1058 | |
| 1059 | /** |
| 1060 | * Helper function for outline_page_toc(). |
| 1061 | * |
| 1062 | * @param $tree |
| 1063 | * The part of the menu array returned by menu_tree_all_data() |
| 1064 | * that we have to curtail according to depth. |
| 1065 | * |
| 1066 | * @param $depth |
| 1067 | * Integer, the number of levels we have left to go down before we cut whatever is below. |
| 1068 | */ |
| 1069 | function _outline_page_toc_limit_depth($tree, $depth) { |
| 1070 | if (0 == $depth) { |
| 1071 | return NULL; |
| 1072 | } |
| 1073 | |
| 1074 | if (is_array($tree)) { |
| 1075 | foreach ($tree AS $key => $branch) { |
| 1076 | if (!empty($branch['below'])) { |
| 1077 | $tree[$key]['below'] = _outline_page_toc_limit_depth($branch['below'], $depth - 1); |
| 1078 | } |
| 1079 | } |
| 1080 | } |
| 1081 | |
| 1082 | return $tree; |
| 1083 | } |
| 1084 | |
| 1085 | /** |
| 1086 | * Helper function: get the actual TOC depth to use on a node view. |
| 1087 | * |
| 1088 | * The TOC depth can be set at the node level, at the book level, or at the site level. |
| 1089 | * Return the most appropriate depth set. |
| 1090 | */ |
| 1091 | function _outline_get_actual_toc_depth($node) { |
| 1092 | $bid = $node->outline['bid']; |
| 1093 | // Node level: |
| 1094 | if ( -1 != $node->outline['books'][$bid]['toc_depth']) { |
| 1095 | return $node->outline['books'][$bid]['toc_depth']; |
| 1096 | } |
| 1097 | // Book level: |
| 1098 | if ( -1 != $node->outline['books'][$bid]['default_toc_depth']) { |
| 1099 | return $node->outline['books'][$bid]['default_toc_depth']; |
| 1100 | } |
| 1101 | // Site level: |
| 1102 | return variable_get('toc_default_depth', 5); |
| 1103 | } |
| 1104 | |
| 1105 | |
| 1106 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 1107 | ////// MENU CALLBACKS //////////////////////////////////////////////////////////////////////////////////// |
| 1108 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 1109 | |
| 1110 | |
| 1111 | /** |
| 1112 | * Returns an administrative overview of all books. |
| 1113 | * |
| 1114 | * We override book_admin_overview() so that we can add our own operations. |
| 1115 | */ |
| 1116 | function outline_admin_overview() { |
| 1117 | $rows = array(); |
| 1118 | foreach (book_get_books() as $book) { |
| 1119 | $rows[] = array('data' => array( |
| 1120 | l(t('edit'), 'node/' . $book['nid'] . '/edit'), |
| 1121 | l(t('permissions'), 'admin/content/book/' . $book['nid'] . '/permission'), |
| 1122 | l(t('outline'), 'admin/content/book/'. $book['nid']), |
| 1123 | array('data' => l($book['title'], $book['href'], $book['options']), 'class' => 'book-title') |
| 1124 | )); |
| 1125 | } |
| 1126 | $headers = array(array('data' => t('Operations'), 'colspan' => 3), array('data' => t('Book'), 'width' => '100%', 'class' => 'book-title')); |
| 1127 | |
| 1128 | return theme('table', $headers, $rows, array('id' => 'outline-admin-overview')); |
| 1129 | } |
| 1130 | |
| 1131 | /** |
| 1132 | * Menu callback: change outline module administrative settings |
| 1133 | */ |
| 1134 | function outline_admin_settings() { |
| 1135 | $form = outline_admin_settings_form(); |
| 1136 | return system_settings_form($form); |
| 1137 | } |
| 1138 | |
| 1139 | |
| 1140 | |
| 1141 | /** |
| 1142 | * AJAX callback to replace the book parent select options. |
| 1143 | * |
| 1144 | * This function is modified from the original book_form_update(). |
| 1145 | * |
| 1146 | * This function is called when the selected book is changed. It updates the |
| 1147 | * cached form (either the node form or the book outline form) and returns |
| 1148 | * rendered output to be used to replace the select containing the possible |
| 1149 | * parent pages in the newly selected book. |
| 1150 | * |
| 1151 | * @param $build_id |
| 1152 | * The form's build_id. |
| 1153 |