diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc index ff5dac8..024adc9 100644 --- a/core/modules/book/book.admin.inc +++ b/core/modules/book/book.admin.inc @@ -43,186 +43,6 @@ function book_admin_overview() { } /** - * Form constructor for administering a single book's hierarchy. - * - * @param \Drupal\Core\Entity\EntityInterface $node - * The node of the top-level page in the book. - * - * @see book_menu() - * @see book_admin_edit_validate() - * @see book_admin_edit_submit() - * @ingroup forms - */ -function book_admin_edit($form, $form_state, EntityInterface $node) { - drupal_set_title($node->label()); - $form['#node'] = $node; - _book_admin_table($node, $form); - $form['save'] = array( - '#type' => 'submit', - '#value' => t('Save book pages'), - ); - - return $form; -} - -/** - * Form validation handler for book_admin_edit(). - * - * Checks that the book has not been changed while using the form. - * - * @see book_admin_edit_submit() - */ -function book_admin_edit_validate($form, &$form_state) { - if ($form_state['values']['tree_hash'] != $form_state['values']['tree_current_hash']) { - form_set_error('', t('This book has been modified by another user, the changes could not be saved.')); - } -} - -/** - * Form submission handler for book_admin_edit(). - * - * This function takes care to save parent menu items before their children. - * Saving menu items in the incorrect order can break the menu tree. - * - * @see book_admin_edit_validate() - * @see menu_overview_form_submit() - */ -function book_admin_edit_submit($form, &$form_state) { - // Save elements in the same order as defined in post rather than the form. - // This ensures parents are updated before their children, preventing orphans. - $order = array_flip(array_keys($form_state['input']['table'])); - $form['table'] = array_merge($order, $form['table']); - - // Track updates. - $updated = FALSE; - foreach (element_children($form['table']) as $key) { - if ($form['table'][$key]['#item']) { - $row = $form['table'][$key]; - $values = $form_state['values']['table'][$key]; - - // Update menu item if moved. - if ($row['plid']['#default_value'] != $values['plid'] || $row['weight']['#default_value'] != $values['weight']) { - $menu_link = entity_load('menu_link', $values['mlid']); - $menu_link->weight = $values['weight']; - $menu_link->plid = $values['plid']; - $menu_link->save(); - $updated = TRUE; - } - - // Update the title if changed. - if ($row['title']['#default_value'] != $values['title']) { - $node = node_load($values['nid']); - $langcode = LANGUAGE_NOT_SPECIFIED; - $node->title = $values['title']; - $node->book['link_title'] = $values['title']; - $node->setNewRevision(); - $node->log = t('Title changed from %original to %current.', array('%original' => $node->title, '%current' => $values['title'])); - - $node->save(); - watchdog('content', 'book: updated %title.', array('%title' => $node->label()), WATCHDOG_NOTICE, l(t('view'), 'node/' . $node->nid)); - } - } - } - if ($updated) { - // Flush static and cache. - drupal_static_reset('book_menu_subtree_data'); - $cid = 'links:' . $form['#node']->book['menu_name'] . ':subtree-cid:' . $form['#node']->book['mlid']; - cache('menu')->delete($cid); - } - - drupal_set_message(t('Updated book %title.', array('%title' => $form['#node']->label()))); -} - -/** - * Builds the table portion of the form for the book administration page. - * - * @param \Drupal\Core\Entity\EntityInterface $node - * The node of the top-level page in the book. - * @param $form - * The form that is being modified, passed by reference. - * - * @see book_admin_edit() - */ -function _book_admin_table(EntityInterface $node, &$form) { - $form['table'] = array( - '#theme' => 'book_admin_table', - '#tree' => TRUE, - ); - - $tree = book_menu_subtree_data($node->book); - $tree = array_shift($tree); // Do not include the book item itself. - if ($tree['below']) { - $hash = drupal_hash_base64(serialize($tree['below'])); - // Store the hash value as a hidden form element so that we can detect - // if another user changed the book hierarchy. - $form['tree_hash'] = array( - '#type' => 'hidden', - '#default_value' => $hash, - ); - $form['tree_current_hash'] = array( - '#type' => 'value', - '#value' => $hash, - ); - _book_admin_table_tree($tree['below'], $form['table']); - } - -} - -/** - * Helps build the main table in the book administration page form. - * - * @param $tree - * A subtree of the book menu hierarchy. - * @param $form - * The form that is being modified, passed by reference. - * - * @return - * The modified form array. - * - * @see book_admin_edit() - */ -function _book_admin_table_tree($tree, &$form) { - // The delta must be big enough to give each node a distinct value. - $count = count($tree); - $delta = ($count < 30) ? 15 : intval($count / 2) + 1; - - foreach ($tree as $data) { - $form['book-admin-' . $data['link']['nid']] = array( - '#item' => $data['link'], - 'nid' => array('#type' => 'value', '#value' => $data['link']['nid']), - 'depth' => array('#type' => 'value', '#value' => $data['link']['depth']), - 'href' => array('#type' => 'value', '#value' => $data['link']['href']), - 'title' => array( - '#type' => 'textfield', - '#default_value' => $data['link']['link_title'], - '#maxlength' => 255, - '#size' => 40, - ), - 'weight' => array( - '#type' => 'weight', - '#default_value' => $data['link']['weight'], - '#delta' => max($delta, abs($data['link']['weight'])), - '#title' => t('Weight for @title', array('@title' => $data['link']['title'])), - '#title_display' => 'invisible', - ), - 'plid' => array( - '#type' => 'hidden', - '#default_value' => $data['link']['plid'], - ), - 'mlid' => array( - '#type' => 'hidden', - '#default_value' => $data['link']['mlid'], - ), - ); - if ($data['below']) { - _book_admin_table_tree($data['below'], $form); - } - } - - return $form; -} - -/** * Returns HTML for a book administration form. * * @param array $variables diff --git a/core/modules/book/book.module b/core/modules/book/book.module index 26f324e..56aa508 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -53,6 +53,7 @@ function book_theme() { ), 'book_admin_table' => array( 'render element' => 'form', + 'file' => 'book.admin.inc', ), 'book_all_books_block' => array( 'render element' => 'book_menus', @@ -152,12 +153,8 @@ function book_menu() { ); $items['admin/content/book/%node'] = array( 'title' => 'Re-order book pages and change titles', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('book_admin_edit', 3), - 'access callback' => '_book_outline_access', - 'access arguments' => array(3), + 'route_name' => 'book_admin_edit', 'type' => MENU_CALLBACK, - 'file' => 'book.admin.inc', ); $items['book'] = array( 'title' => 'Books', diff --git a/core/modules/book/book.routing.yml b/core/modules/book/book.routing.yml index 3af7c08..a85e379 100644 --- a/core/modules/book/book.routing.yml +++ b/core/modules/book/book.routing.yml @@ -4,3 +4,11 @@ book_settings: _form: 'Drupal\book\BookSettingsForm' requirements: _permission: 'administer site configuration' + +book_admin_edit: + pattern: '/admin/content/book/{node}' + defaults: + _form: 'Drupal\book\Form\BookAdminEditForm' + requirements: + _book_outline_access: 'TRUE' + node: \d+ diff --git a/core/modules/book/lib/Drupal/book/Access/OutlineAccessCheck.php b/core/modules/book/lib/Drupal/book/Access/OutlineAccessCheck.php new file mode 100644 index 0000000..2cd4903 --- /dev/null +++ b/core/modules/book/lib/Drupal/book/Access/OutlineAccessCheck.php @@ -0,0 +1,32 @@ +getRequirements()); + } + + /** + * Implements AccessCheckInterface::access(). + */ + public function access(Route $route, Request $request) { + return user_access('administer book outlines') && node_access('view', $request->attributes->get('node')); + } +} diff --git a/core/modules/book/lib/Drupal/book/BookBundle.php b/core/modules/book/lib/Drupal/book/BookBundle.php new file mode 100644 index 0000000..0c4fe11 --- /dev/null +++ b/core/modules/book/lib/Drupal/book/BookBundle.php @@ -0,0 +1,25 @@ +register('access_check.book.outline', 'Drupal\book\Access\OutlineAccessCheck') + ->addTag('access_check'); + } +} diff --git a/core/modules/book/lib/Drupal/book/Form/BookAdminEditForm.php b/core/modules/book/lib/Drupal/book/Form/BookAdminEditForm.php new file mode 100644 index 0000000..8466153 --- /dev/null +++ b/core/modules/book/lib/Drupal/book/Form/BookAdminEditForm.php @@ -0,0 +1,225 @@ +cache = $cache; + } + + /** + * Implements \Drupal\Core\ControllerInterface::create(). + */ + public static function create(ContainerInterface $container) { + return new static($container->get('cache.menu')); + } + + /** + * Implements \Drupal\Core\Form\FormInterface::getFormID(). + */ + public function getFormID() { + return 'book_admin_edit'; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::buildForm(). + * + * @param \Drupal\Core\Entity\EntityInterface $node + * The node of the top-level page in the book. + * + * @ingroup forms + */ + public function buildForm(array $form, array &$form_state, EntityInterface $node = NULL) { + drupal_set_title($node->label()); + $form['#node'] = $node; + $this->bookAdminTable($node, $form); + $form['save'] = array( + '#type' => 'submit', + '#value' => t('Save book pages'), + ); + + return $form; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::validateForm(). + * + * Checks that the book has not been changed while using the form. + */ + public function validateForm(array &$form, array &$form_state) { + if ($form_state['values']['tree_hash'] != $form_state['values']['tree_current_hash']) { + form_set_error('', t('This book has been modified by another user, the changes could not be saved.')); + } + } + + /** + * Implements \Drupal\Core\Form\FormInterface::submitForm(). + * + * This function takes care to save parent menu items before their children. + * Saving menu items in the incorrect order can break the menu tree. + * + * @see menu_overview_form_submit() + */ + public function submitForm(array &$form, array &$form_state) { + // Save elements in the same order as defined in post rather than the form. + // This ensures parents are updated before their children, preventing orphans. + $order = array_flip(array_keys($form_state['input']['table'])); + $form['table'] = array_merge($order, $form['table']); + + // Track updates. + $updated = FALSE; + foreach (element_children($form['table']) as $key) { + if ($form['table'][$key]['#item']) { + $row = $form['table'][$key]; + $values = $form_state['values']['table'][$key]; + + // Update menu item if moved. + if ($row['plid']['#default_value'] != $values['plid'] || $row['weight']['#default_value'] != $values['weight']) { + $menu_link = entity_load('menu_link', $values['mlid']); + $menu_link->weight = $values['weight']; + $menu_link->plid = $values['plid']; + $menu_link->save(); + $updated = TRUE; + } + + // Update the title if changed. + if ($row['title']['#default_value'] != $values['title']) { + $node = node_load($values['nid']); + $langcode = LANGUAGE_NOT_SPECIFIED; + $node->title = $values['title']; + $node->book['link_title'] = $values['title']; + $node->setNewRevision(); + $node->log = t('Title changed from %original to %current.', array('%original' => $node->title, '%current' => $values['title'])); + + $node->save(); + watchdog('content', 'book: updated %title.', array('%title' => $node->label()), WATCHDOG_NOTICE, l(t('view'), 'node/' . $node->nid)); + } + } + } + if ($updated) { + // Flush static and cache. + drupal_static_reset('book_menu_subtree_data'); + $cid = 'links:' . $form['#node']->book['menu_name'] . ':subtree-cid:' . $form['#node']->book['mlid']; + $this->cache->delete($cid); + } + + drupal_set_message(t('Updated book %title.', array('%title' => $form['#node']->label()))); + } + + /** + * Builds the table portion of the form for the book administration page. + * + * @param \Drupal\Core\Entity\EntityInterface $node + * The node of the top-level page in the book. + * @param $form + * The form that is being modified, passed by reference. + * + * @see book_admin_edit() + */ + protected function bookAdminTable(EntityInterface $node, &$form) { + $form['table'] = array( + '#theme' => 'book_admin_table', + '#tree' => TRUE, + ); + + $tree = book_menu_subtree_data($node->book); + $tree = array_shift($tree); // Do not include the book item itself. + if ($tree['below']) { + $hash = drupal_hash_base64(serialize($tree['below'])); + // Store the hash value as a hidden form element so that we can detect + // if another user changed the book hierarchy. + $form['tree_hash'] = array( + '#type' => 'hidden', + '#default_value' => $hash, + ); + $form['tree_current_hash'] = array( + '#type' => 'value', + '#value' => $hash, + ); + $this->bookAdminTableTree($tree['below'], $form['table']); + } + } + + /** + * Helps build the main table in the book administration page form. + * + * @param $tree + * A subtree of the book menu hierarchy. + * @param $form + * The form that is being modified, passed by reference. + * + * @return + * The modified form array. + * + * @see book_admin_edit() + */ + protected function bookAdminTableTree($tree, &$form) { + // The delta must be big enough to give each node a distinct value. + $count = count($tree); + $delta = ($count < 30) ? 15 : intval($count / 2) + 1; + + foreach ($tree as $data) { + $form['book-admin-' . $data['link']['nid']] = array( + '#item' => $data['link'], + 'nid' => array('#type' => 'value', '#value' => $data['link']['nid']), + 'depth' => array('#type' => 'value', '#value' => $data['link']['depth']), + 'href' => array('#type' => 'value', '#value' => $data['link']['href']), + 'title' => array( + '#type' => 'textfield', + '#default_value' => $data['link']['link_title'], + '#maxlength' => 255, + '#size' => 40, + ), + 'weight' => array( + '#type' => 'weight', + '#default_value' => $data['link']['weight'], + '#delta' => max($delta, abs($data['link']['weight'])), + '#title' => t('Weight for @title', array('@title' => $data['link']['title'])), + '#title_display' => 'invisible', + ), + 'plid' => array( + '#type' => 'hidden', + '#default_value' => $data['link']['plid'], + ), + 'mlid' => array( + '#type' => 'hidden', + '#default_value' => $data['link']['mlid'], + ), + ); + if ($data['below']) { + $this->bookAdminTableTree($data['below'], $form); + } + } + + return $form; + } + +}