Includes indicator on books added to sort operation.
}
/**
- * Sorts a book using a given mapping array.
+ * Update the sort options of a book, setting the auto-sort and/or updating
+ * child order via mapping.
*/
public function update(Request $request, BookSorter $sorter, string $bookSlug)
{
$book = $this->queries->findVisibleBySlugOrFail($bookSlug);
$this->checkOwnablePermission('book-update', $book);
+ $loggedActivityForBook = false;
- // Return if no map sent
- if (!$request->filled('sort-tree')) {
- return redirect($book->getUrl());
- }
+ // Sort via map
+ if ($request->filled('sort-tree')) {
+ $sortMap = BookSortMap::fromJson($request->get('sort-tree'));
+ $booksInvolved = $sorter->sortUsingMap($sortMap);
- $sortMap = BookSortMap::fromJson($request->get('sort-tree'));
- $booksInvolved = $sorter->sortUsingMap($sortMap);
+ // Rebuild permissions and add activity for involved books.
+ foreach ($booksInvolved as $bookInvolved) {
+ Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
+ if ($bookInvolved->id === $book->id) {
+ $loggedActivityForBook = true;
+ }
+ }
+ }
- // Rebuild permissions and add activity for involved books.
- foreach ($booksInvolved as $bookInvolved) {
- Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
+ if ($request->filled('auto-sort')) {
+ $sortSetId = intval($request->get('auto-sort')) ?: null;
+ if ($sortSetId && SortSet::query()->find($sortSetId) === null) {
+ $sortSetId = null;
+ }
+ $book->sort_set_id = $sortSetId;
+ $book->save();
+ $sorter->runBookAutoSort($book);
+ if (!$loggedActivityForBook) {
+ Activity::add(ActivityType::BOOK_SORT, $book);
+ }
}
return redirect($book->getUrl());
use BookStack\Activity\Models\Loggable;
use BookStack\Entities\Models\Book;
use Carbon\Carbon;
+use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
{
return $this->hasMany(Book::class);
}
+
+ public static function allByName(): Collection
+ {
+ return static::query()
+ ->withCount('books')
+ ->orderBy('name', 'asc')
+ ->get();
+ }
}
'books_search_this' => 'Search this book',
'books_navigation' => 'Book Navigation',
'books_sort' => 'Sort Book Contents',
- 'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books.',
+ 'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books. Optionally an auto sort option can be set to automatically sort this book\'s contents upon changes.',
+ 'books_sort_auto_sort' => 'Auto Sort Option',
+ 'books_sort_auto_sort_active' => 'Auto Sort Active: :sortName',
'books_sort_named' => 'Sort Book :bookName',
'books_sort_name' => 'Sort by Name',
'books_sort_created' => 'Sort by Created Date',
--- /dev/null
+<svg version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m3 18h6v-2h-6zm0-12v2h18v-2zm0 7h11v-2h-11z"/><g transform="matrix(.024132 0 0 .024132 3.6253 26.687)"><path d="m602.72-360v-146.6h-58.639l117.28-205.24v146.6h58.639z" stroke-width=".73298"/></g></svg>
margin-bottom: vars.$m;
padding: vars.$m vars.$xl;
position: relative;
+ summary:focus {
+ outline: 1px dashed var(--color-primary);
+ outline-offset: 5px;
+ }
&::before {
pointer-events: none;
content: '';
<span>@icon('book')</span>
<span>{{ $book->name }}</span>
</div>
+ <div class="flex-container-row items-center text-book">
+ @if($book->sortSet)
+ <span title="{{ trans('entities.books_sort_auto_sort_active', ['sortName' => $book->sortSet->name]) }}">@icon('auto-sort')</span>
+ @endif
+ </div>
</h5>
</summary>
<div class="sort-box-options pb-sm">
<div>
<div component="book-sort" class="card content-wrap auto-height">
<h1 class="list-heading">{{ trans('entities.books_sort') }}</h1>
- <p class="text-muted">{{ trans('entities.books_sort_desc') }}</p>
+
+ <div class="flex-container-row gap-m wrap mb-m">
+ <p class="text-muted flex min-width-s mb-none">{{ trans('entities.books_sort_desc') }}</p>
+ <div class="min-width-s">
+ @php
+ $autoSortVal = intval(old('auto-sort') ?? $book->sort_set_id ?? 0);
+ @endphp
+ <label for="auto-sort">{{ trans('entities.books_sort_auto_sort') }}</label>
+ <select id="auto-sort"
+ name="auto-sort"
+ form="sort-form"
+ class="{{ $errors->has('auto-sort') ? 'neg' : '' }}">
+ <option value="0" @if($autoSortVal === 0) selected @endif>-- {{ trans('common.none') }} --</option>
+ @foreach(\BookStack\Sorting\SortSet::allByName() as $set)
+ <option value="{{$set->id}}"
+ @if($autoSortVal === $set->id) selected @endif
+ >
+ {{ $set->name }}
+ </option>
+ @endforeach
+ </select>
+ </div>
+ </div>
<div refs="book-sort@sortContainer">
@include('books.parts.sort-box', ['book' => $book, 'bookChildren' => $bookChildren])
</div>
- <form action="{{ $book->getUrl('/sort') }}" method="POST">
- {!! csrf_field() !!}
+ <form id="sort-form" action="{{ $book->getUrl('/sort') }}" method="POST">
+ {{ csrf_field() }}
<input type="hidden" name="_method" value="PUT">
<input refs="book-sort@input" type="hidden" name="sort-tree">
<div class="list text-right">
@extends('settings.layout')
@php
- $sortSets = \BookStack\Sorting\SortSet::query()
- ->withCount('books')
- ->orderBy('name', 'asc')
- ->get();
+ $sortSets = \BookStack\Sorting\SortSet::allByName();
@endphp
@section('card')