book_link_weight-1.0.0-beta1/src/Form/BookLinkWeightForm.php
src/Form/BookLinkWeightForm.php
<?php
namespace Drupal\book_link_weight\Form;
use Drupal\book\BookManagerInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Book Link Weight form alterations.
*/
class BookLinkWeightForm {
/**
* The default delta for the book link weight drop-down.
*/
const DEFAULT_DELTA = 20;
/**
* The book manager.
*
* @var Drupal\book\BookManagerInterface
*/
protected $bookManager;
/**
* Create an instance of the book ui form.
*/
public function __construct(BookManagerInterface $book_manager) {
$this->bookManager = $book_manager;
}
/**
* Alter the book outline element.
*/
public function alterBookOutlineForm(&$form, FormStateInterface $form_state) {
if (!empty($form['book']['bid']['#default_value']) && !empty($form['book']['pid']['#default_value'])) {
$entity = $form_state->getformObject()->getEntity();
$link = $this->bookManager->loadBookLink($form['book']['pid']['#default_value']);
$subTree = [
'below' => [],
];
if ($link) {
$parentTree = $this->bookManager->bookSubtreeData($link);
$subTree = reset($parentTree);
}
$delta = self::DEFAULT_DELTA;
if (!empty($subTree['below'])) {
$count = count($subTree['below']);
// Use 1.5 rather than 2 as the factor for the delta to give a bit more
// breathing space in the re-ordering of elements, this logic kicks in
// when there are more than 30 child pages.
// @see BookAdminEditForm::bookAdminTableTree().
$delta = ($count < 30) ? self::DEFAULT_DELTA : intval($count / 1.5) + 1;
}
$form['book']['pid'] += [
'#ajax' => [
'callback' => ['Drupal\book_link_weight\Form\BookLinkWeightForm', 'bookWeightTableUpdate'],
'wrapper' => 'edit-book-weight-wrapper',
'effect' => 'fade',
'speed' => 'fast',
],
];
$form['book']['pid']['#attributes']['class'][] = 'js-book-parent-select';
$form['book']['table'] = [
'#type' => 'table',
'#header' => [
'name' => t('Name'),
'weight' => t('Weight'),
],
'#prefix' => '<div id="edit-book-weight-wrapper">',
'#suffix' => '</div>',
'#id' => 'book-order',
'#tabledrag' => [
[
'action' => 'order',
'relationship' => 'sibling',
'group' => 'book-item-weight',
],
],
];
/*
* Default the weight to 0, in case the parent has no previous children.
* @see https://www.drupal.org/project/book_link_weight/issues/3195742
*/
$lastWeight = 0;
foreach ($subTree['below'] as $key => $item) {
$form['book']['table'][$item['link']['nid']] = [
'#attributes' => ['class' => ['draggable']],
'#weight' => $item['link']['weight'],
'name' => [
'#markup' => $item['link']['title'],
],
'weight' => [
'#type' => 'weight',
'#delta' => max($delta, abs($item['link']['weight'])),
'#title' => t('Weight'),
'#default_value' => $item['link']['weight'],
'#title_display' => 'invisible',
'#attributes' => ['class' => ['book-item-weight']],
],
];
$lastWeight = $item['link']['weight'];
}
$currentTitle = $this->getCurrentTitle($form, $form_state);
$nextRowWeight = $lastWeight + 1;
$pageNid = 0;
if (!$entity->isNew()) {
$pageNid = $entity->id();
if (isset($form['book']['table'][$pageNid])) {
$nextRowWeight = $form['book']['table'][$pageNid]['weight']['#default_value'];
}
}
$form['book']['table'][$pageNid] = [
'#attributes' => ['class' => ['draggable']],
'#weight' => $nextRowWeight,
'name' => [
'#markup' => "<span class='book-item-weight-current-item'>{$currentTitle}</span>",
],
'weight' => [
'#type' => 'weight',
'#delta' => max($delta, abs($nextRowWeight)),
'#title' => t('Weight'),
'#default_value' => $nextRowWeight,
'#title_display' => 'invisible',
'#attributes' => ['class' => ['book-item-weight']],
],
];
}
else {
/*
* In the event of no parent being selected we just output the empty form
* this allows it to be populated with content when a parent is selected.
*/
$form['book']['table'] = [
'#type' => 'table',
'#header' => [
'name' => t('Name'),
'weight' => t('Weight'),
],
'#attributes' => ['class' => ['visually-hidden']],
'#prefix' => '<div id="edit-book-weight-wrapper">',
'#suffix' => '</div>',
'#id' => 'book-order',
'#empty' => 'No sibling elements',
'#tabledrag' => [
[
'action' => 'order',
'relationship' => 'sibling',
'group' => 'book-item-weight',
],
],
];
}
$form['book']['weight']['#type'] = 'hidden';
$form['#attached']['library'][] = 'book_link_weight/book_link_weight';
foreach (array_keys($form['actions']) as $action) {
if ($action != 'preview' && isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') {
array_unshift($form['actions'][$action]['#submit'], ['Drupal\book_link_weight\Form\BookLinkWeightForm', 'bookOutlineSubmit']);
}
}
}
/**
* Get the current title from the node form.
*/
protected function getCurrentTitle(array $form, FormStateInterface $form_state) {
$form_id = $form['#form_id'];
if ($form_state->getValue('title') && $form_state->getValue('title')[0]['value']) {
return $form_state->getValue('title')[0]['value'];
}
elseif (!empty($form['title']['widget'][0]['value']['#default_value'])) {
return $form['title']['widget'][0]['value']['#default_value'];
}
elseif (substr($form_id, 0, 4) === 'node' && substr($form_id, -17) === 'book_outline_form' && !empty($form['#title'])) {
// This is the outline form on the outline page. The title lives in
// a different key.
return $form['#title'];
}
return t("Current page");
}
/**
* Submit handler for saving book outline weight.
*
* @see alterBookOutlineForm()
*/
public static function bookOutlineSubmit($form, FormStateInterface $form_state) {
$bookManager = \Drupal::service('book.manager');
$values = $form_state->getValues();
if (!empty($values['book']['table'])) {
foreach ($values['book']['table'] as $key => $item) {
// A key of zero means a new node.
// Using double equals for the second comparison because
// $values[book][nid] is a string while key is a number.
if ($key === 0 || $key == $values['book']['nid']) {
// Set the weight of this node.
$values['book']['weight'] = $item['weight'];
$form_state->setValue('book', $values['book']);
}
else {
// Update the weights of the sibling book links.
$link = $bookManager->loadBookLink($key);
$link['weight'] = $item['weight'];
$bookManager->saveBookLink($link, FALSE);
}
}
}
}
/**
* Ajax function to update the node form book outline weight table.
*/
public static function bookWeightTableUpdate($form, FormStateInterface $form_state) {
return $form['book']['table'];
}
}
