diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc index 611537b..04915f7 100644 --- a/core/modules/book/book.admin.inc +++ b/core/modules/book/book.admin.inc @@ -5,190 +5,6 @@ * Administration page callbacks for the Book module. */ -use Drupal\Component\Utility\Crypt; -use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Language\Language; - -/** - * 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::LANGCODE_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->id())); - } - } - } - 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 = Crypt::hashBase64(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. * @@ -196,7 +12,7 @@ function _book_admin_table_tree($tree, &$form) { * An associative array containing: * - form: A render element representing the form. * - * @see book_admin_table() + * @see \Drupal\book\Form\BookAdminEditForm::bookAdminTable() * @ingroup themeable */ function theme_book_admin_table($variables) { diff --git a/core/modules/book/book.module b/core/modules/book/book.module index 22b9ea9..095fe53 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -79,6 +79,7 @@ function book_theme() { ), 'book_admin_table' => array( 'render element' => 'form', + 'file' => 'book.admin.inc', ), 'book_all_books_block' => array( 'render element' => 'book_menus', @@ -173,15 +174,6 @@ function book_menu() { 'type' => MENU_LOCAL_TASK, 'weight' => 100, ); - $items['admin/structure/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), - 'type' => MENU_CALLBACK, - 'file' => 'book.admin.inc', - ); $items['book'] = array( 'title' => 'Books', 'route_name' => 'book_render', @@ -429,7 +421,8 @@ function _book_add_form_elements(&$form, &$form_state, EntityInterface $node) { $form['book']['plid'] = _book_parent_select($node->book); - // @see _book_admin_table_tree(). The weight may be larger than 15. + // @see \Drupal\book\Form\BookAdminEditForm::bookAdminTableTree(). The weight + // may be larger than 15. $form['book']['weight'] = array( '#type' => 'weight', '#title' => t('Weight'), diff --git a/core/modules/book/book.routing.yml b/core/modules/book/book.routing.yml index b44ccfb..413e690 100644 --- a/core/modules/book/book.routing.yml +++ b/core/modules/book/book.routing.yml @@ -28,3 +28,15 @@ book_export: requirements: _permission: 'access printer-friendly version' _entity_access: 'node.view' + +book_admin_edit: + pattern: '/admin/structure/book/{node}' + defaults: + _form: 'Drupal\book\Form\BookAdminEditForm' + _title: 'Re-order book pages and change titles' + options: + _access_mode: 'ALL' + requirements: + _permission: 'administer book outlines' + _entity_access: 'node.view' + node: \d+ 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..c48fb30 --- /dev/null +++ b/core/modules/book/lib/Drupal/book/Form/BookAdminEditForm.php @@ -0,0 +1,234 @@ +cache = $cache; + $this->nodeStorage = $node_storage; + $this->menuLinkStorage = $menu_link_storage; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + $entity_manager = $container->get('entity.manager'); + return new static( + $container->get('cache.menu'), + $entity_manager->getStorageController('node'), + $entity_manager->getStorageController('menu_link') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormID() { + return 'book_admin_edit'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state, NodeInterface $node = NULL) { + $form['#title'] = $node->label(); + $form['#node'] = $node; + $this->bookAdminTable($node, $form); + $form['save'] = array( + '#type' => 'submit', + '#value' => $this->t('Save book pages'), + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + if ($form_state['values']['tree_hash'] != $form_state['values']['tree_current_hash']) { + form_set_error('', $this->t('This book has been modified by another user, the changes could not be saved.')); + } + } + + /** + * {@inheritdoc} + */ + 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 = $this->menuLinkStorage->load($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 = $this->nodeStorage->load($values['nid']); + $node->log = $this->t('Title changed from %original to %current.', array('%original' => $node->label(), '%current' => $values['title'])); + $node->title = $values['title']; + $node->book['link_title'] = $values['title']; + $node->setNewRevision(); + $node->save(); + watchdog('content', 'book: updated %title.', array('%title' => $node->label()), WATCHDOG_NOTICE, l($this->t('view'), 'node/' . $node->id())); + } + } + } + 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($this->t('Updated book %title.', array('%title' => $form['#node']->label()))); + } + + /** + * Builds the table portion of the form for the book administration page. + * + * @param \Drupal\node\NodeInterface $node + * The node of the top-level page in the book. + * @param array $form + * The form that is being modified, passed by reference. + * + * @see self::buildForm() + */ + protected function bookAdminTable(NodeInterface $node, array &$form) { + $form['table'] = array( + '#theme' => 'book_admin_table', + '#tree' => TRUE, + ); + + $tree = book_menu_subtree_data($node->book); + // Do not include the book item itself. + $tree = array_shift($tree); + if ($tree['below']) { + $hash = Crypt::hashBase64(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 array $tree + * A subtree of the book menu hierarchy. + * @param array $form + * The form that is being modified, passed by reference. + * + * @see self::buildForm() + */ + protected function bookAdminTableTree(array $tree, array &$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' => $this->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); + } + } + } + +}