1<?php 2 3/** 4 * @file 5 * User page callbacks for the book module. 6 */ 7 8/** 9 * Menu callback: Prints a listing of all books. 10 * 11 * @return string 12 * A HTML-formatted string with the listing of all books content. 13 * 14 * @see book_menu() 15 */ 16function book_render() { 17 $book_list = array(); 18 foreach (book_get_books() as $book) { 19 $book_list[] = l($book['title'], $book['href'], $book['options']); 20 } 21 22 return theme('item_list', array('items' => $book_list)); 23} 24 25/** 26 * Menu callback; Generates representations of a book page and its children. 27 * 28 * The function delegates the generation of output to helper functions. The 29 * function name is derived by prepending 'book_export_' to the given output 30 * type. So, e.g., a type of 'html' results in a call to the function 31 * book_export_html(). 32 * 33 * @param $type 34 * A string encoding the type of output requested. The following types are 35 * currently supported in book module: 36 * - html: Printer-friendly HTML. 37 * Other types may be supported in contributed modules. 38 * @param $nid 39 * An integer representing the node id (nid) of the node to export 40 * 41 * @return 42 * A string representing the node and its children in the book hierarchy in a 43 * format determined by the $type parameter. 44 * 45 * @see book_menu() 46 */ 47function book_export($type, $nid) { 48 // Check that the node exists and that the current user has access to it. 49 $node = node_load($nid); 50 if (!$node) { 51 return MENU_NOT_FOUND; 52 } 53 if (!node_access('view', $node)) { 54 return MENU_ACCESS_DENIED; 55 } 56 57 $type = drupal_strtolower($type); 58 59 $export_function = 'book_export_' . $type; 60 61 if (function_exists($export_function)) { 62 print call_user_func($export_function, $nid); 63 } 64 else { 65 drupal_set_message(t('Unknown export format.')); 66 drupal_not_found(); 67 } 68} 69 70/** 71 * Generates HTML for export when invoked by book_export(). 72 * 73 * The given node is embedded to its absolute depth in a top level section. For 74 * example, a child node with depth 2 in the hierarchy is contained in 75 * (otherwise empty) <div> elements corresponding to depth 0 and depth 1. 76 * This is intended to support WYSIWYG output - e.g., level 3 sections always 77 * look like level 3 sections, no matter their depth relative to the node 78 * selected to be exported as printer-friendly HTML. 79 * 80 * @param $nid 81 * An integer representing the node id (nid) of the node to export. 82 * 83 * @return 84 * A string containing HTML representing the node and its children in 85 * the book hierarchy. 86 */ 87function book_export_html($nid) { 88 if (user_access('access printer-friendly version')) { 89 $node = node_load($nid); 90 if (isset($node->book)) { 91 $tree = book_menu_subtree_data($node->book); 92 $contents = book_export_traverse($tree, 'book_node_export'); 93 return theme('book_export_html', array('title' => $node->title, 'contents' => $contents, 'depth' => $node->book['depth'])); 94 } 95 else { 96 drupal_not_found(); 97 } 98 } 99 else { 100 drupal_access_denied(); 101 } 102} 103 104/** 105 * Menu callback: Shows the outline form for a single node. 106 * 107 * @param $node 108 * The book node for which to show the outline. 109 * 110 * @return string 111 * A HTML-formatted string with the outline form for a single node. 112 * 113 * @see book_menu() 114 */ 115function book_outline($node) { 116 drupal_set_title($node->title); 117 return drupal_get_form('book_outline_form', $node); 118} 119 120/** 121 * Form constructor for the book outline form. 122 * 123 * Allows handling of all book outline operations via the outline tab. 124 * 125 * @param $node 126 * The book node for which to show the outline. 127 * 128 * @see book_outline_form_submit() 129 * @see book_remove_button_submit() 130 * @ingroup forms 131 */ 132function book_outline_form($form, &$form_state, $node) { 133 if (!isset($node->book)) { 134 // The node is not part of any book yet - set default options. 135 $node->book = _book_link_defaults($node->nid); 136 } 137 else { 138 $node->book['original_bid'] = $node->book['bid']; 139 } 140 141 // Find the depth limit for the parent select. 142 if (!isset($node->book['parent_depth_limit'])) { 143 $node->book['parent_depth_limit'] = _book_parent_depth_limit($node->book); 144 } 145 $form['#node'] = $node; 146 $form['#id'] = 'book-outline'; 147 _book_add_form_elements($form, $form_state, $node); 148 149 $form['book']['#collapsible'] = FALSE; 150 151 $form['update'] = array( 152 '#type' => 'submit', 153 '#value' => $node->book['original_bid'] ? t('Update book outline') : t('Add to book outline'), 154 '#weight' => 15, 155 ); 156 157 $form['remove'] = array( 158 '#type' => 'submit', 159 '#value' => t('Remove from book outline'), 160 '#access' => _book_node_is_removable($node), 161 '#weight' => 20, 162 '#submit' => array('book_remove_button_submit'), 163 ); 164 165 return $form; 166} 167 168/** 169 * Form submission handler for book_outline_form(). 170 * 171 * Redirects to removal confirmation form. 172 * 173 * @see book_outline_form_submit() 174 */ 175function book_remove_button_submit($form, &$form_state) { 176 $form_state['redirect'] = 'node/' . $form['#node']->nid . '/outline/remove'; 177} 178 179/** 180 * Form submission handler for book_outline_form(). 181 * 182 * @see book_remove_button_submit() 183 */ 184function book_outline_form_submit($form, &$form_state) { 185 $node = $form['#node']; 186 $form_state['redirect'] = "node/" . $node->nid; 187 $book_link = $form_state['values']['book']; 188 if (!$book_link['bid']) { 189 drupal_set_message(t('No changes were made')); 190 191 return; 192 } 193 194 $book_link['menu_name'] = book_menu_name($book_link['bid']); 195 $node->book = $book_link; 196 if (_book_update_outline($node)) { 197 if ($node->book['parent_mismatch']) { 198 // This will usually only happen when JS is disabled. 199 drupal_set_message(t('The post has been added to the selected book. You may now position it relative to other pages.')); 200 $form_state['redirect'] = "node/" . $node->nid . "/outline"; 201 } 202 else { 203 drupal_set_message(t('The book outline has been updated.')); 204 } 205 } 206 else { 207 drupal_set_message(t('There was an error adding the post to the book.'), 'error'); 208 } 209} 210 211/** 212 * Form constructor to confirm removal of a node from a book. 213 * 214 * @param $node 215 * The node to delete. 216 * 217 * @see book_remove_form_submit() 218 * @ingroup forms 219 */ 220function book_remove_form($form, &$form_state, $node) { 221 $form['#node'] = $node; 222 $title = array('%title' => $node->title); 223 224 if ($node->book['has_children']) { 225 $description = t('%title has associated child pages, which will be relocated automatically to maintain their connection to the book. To recreate the hierarchy (as it was before removing this page), %title may be added again using the Outline tab, and each of its former child pages will need to be relocated manually.', $title); 226 } 227 else { 228 $description = t('%title may be added to hierarchy again using the Outline tab.', $title); 229 } 230 231 return confirm_form($form, t('Are you sure you want to remove %title from the book hierarchy?', $title), 'node/' . $node->nid, $description, t('Remove')); 232} 233 234/** 235 * Form submission handler for book_remove_form(). 236 */ 237function book_remove_form_submit($form, &$form_state) { 238 $node = $form['#node']; 239 if (_book_node_is_removable($node)) { 240 menu_link_delete($node->book['mlid']); 241 db_delete('book') 242 ->condition('nid', $node->nid) 243 ->execute(); 244 drupal_set_message(t('The post has been removed from the book.')); 245 } 246 $form_state['redirect'] = 'node/' . $node->nid; 247} 248