# These are supported funding model platforms
github: [ssddanbrown]
+ko_fi: ssddanbrown
\ No newline at end of file
blank_issues_enabled: false
contact_links:
- - name: Discord chat support
+ - name: Discord Chat Support
url: https://discord.gg/ztkBqR2
- about: Realtime support / chat with the community and the team.
+ about: Realtime support & chat with the BookStack community and the team.
- name: Debugging & Common Issues
url: https://www.bookstackapp.com/docs/admin/debugging/
- about: Find details on how to debug issues and view common issues with thier resolutions.
+ about: Find details on how to debug issues and view common issues with their resolutions.
+
+ - name: Official Support Plans
+ url: https://www.bookstackapp.com/support/
+ about: View our official support plans that offer assured support for business.
\ No newline at end of file
name: Language Request
-description: Request a new language to be added to CrowdIn for you to translate
+description: Request a new language to be added to Crowdin for you to translate
labels: [":earth_africa: Translations"]
assignees:
- ssddanbrown
This issue template is to request a new language be added to our [Crowdin translation management project](https://crowdin.com/project/bookstack).
Please don't use this template to request a new language that you are not prepared to provide translations for.
options:
- - label: I confirm I'm offering to help translate for this new language via CrowdIn.
+ - label: I confirm I'm offering to help translate for this new language via Crowdin.
required: true
- type: markdown
attributes:
Shukrullo (vodiylik) :: Uzbek
William W. (Nevnt) :: Chinese Traditional
eamaro :: Portuguese
+Ypsilon-dev :: Arabic
const CHAPTER_MOVE = 'chapter_move';
const BOOK_CREATE = 'book_create';
+ const BOOK_CREATE_FROM_CHAPTER = 'book_create_from_chapter';
const BOOK_UPDATE = 'book_update';
const BOOK_DELETE = 'book_delete';
const BOOK_SORT = 'book_sort';
const BOOKSHELF_CREATE = 'bookshelf_create';
+ const BOOKSHELF_CREATE_FROM_BOOK = 'bookshelf_create_from_book';
const BOOKSHELF_UPDATE = 'bookshelf_update';
const BOOKSHELF_DELETE = 'bookshelf_delete';
'name',
($searchTerm || $nameFilter) ? 'value' : DB::raw('COUNT(distinct value) as `values`'),
DB::raw('COUNT(id) as usages'),
- DB::raw('SUM(IF(entity_type = \'BookStack\\\\Page\', 1, 0)) as page_count'),
- DB::raw('SUM(IF(entity_type = \'BookStack\\\\Chapter\', 1, 0)) as chapter_count'),
- DB::raw('SUM(IF(entity_type = \'BookStack\\\\Book\', 1, 0)) as book_count'),
- DB::raw('SUM(IF(entity_type = \'BookStack\\\\BookShelf\', 1, 0)) as shelf_count'),
+ DB::raw('SUM(IF(entity_type = \'page\', 1, 0)) as page_count'),
+ DB::raw('SUM(IF(entity_type = \'chapter\', 1, 0)) as chapter_count'),
+ DB::raw('SUM(IF(entity_type = \'book\', 1, 0)) as book_count'),
+ DB::raw('SUM(IF(entity_type = \'bookshelf\', 1, 0)) as shelf_count'),
])
->orderBy($nameFilter ? 'value' : 'name');
*/
protected function externalIdMatchesGroupNames(string $externalId, array $groupNames): bool
{
- $externalAuthIds = explode(',', strtolower($externalId));
-
- foreach ($externalAuthIds as $externalAuthId) {
- if (in_array(trim($externalAuthId), $groupNames)) {
+ foreach ($this->parseRoleExternalAuthId($externalId) as $externalAuthId) {
+ if (in_array($externalAuthId, $groupNames)) {
return true;
}
}
return false;
}
+ protected function parseRoleExternalAuthId(string $externalId): array
+ {
+ $inputIds = preg_split('/(?<!\\\),/', $externalId);
+ $cleanIds = [];
+
+ foreach ($inputIds as $inputId) {
+ $cleanIds[] = str_replace('\,', ',', trim($inputId));
+ }
+
+ return $cleanIds;
+ }
+
/**
* Match an array of group names to BookStack system roles.
* Formats group names to be lower-case and hyphenated.
// to the server if the browser has a HTTPS connection. This will keep
// the cookie from being sent to you if it can not be done securely.
'secure' => env('SESSION_SECURE_COOKIE', null)
- ?? Str::startsWith(env('APP_URL'), 'https:'),
+ ?? Str::startsWith(env('APP_URL', ''), 'https:'),
// HTTP Access Only
// Setting this value to true will prevent JavaScript from accessing the
{
$book = new Book();
$this->baseRepo->create($book, $input);
+ $this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
Activity::add(ActivityType::BOOK_CREATE, $book);
return $book;
public function update(Book $book, array $input): Book
{
$this->baseRepo->update($book, $input);
+
+ if (array_key_exists('image', $input)) {
+ $this->baseRepo->updateCoverImage($book, $input['image'], $input['image'] === null);
+ }
+
Activity::add(ActivityType::BOOK_UPDATE, $book);
return $book;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Tools\TrashCan;
-use BookStack\Exceptions\ImageUploadException;
use BookStack\Exceptions\NotFoundException;
use BookStack\Facades\Activity;
use Exception;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
-use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;
class BookshelfRepo
{
$shelf = new Bookshelf();
$this->baseRepo->create($shelf, $input);
+ $this->baseRepo->updateCoverImage($shelf, $input['image'] ?? null);
$this->updateBooks($shelf, $bookIds);
Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
$this->updateBooks($shelf, $bookIds);
}
+ if (array_key_exists('image', $input)) {
+ $this->baseRepo->updateCoverImage($shelf, $input['image'], $input['image'] === null);
+ }
+
Activity::add(ActivityType::BOOKSHELF_UPDATE, $shelf);
return $shelf;
}
/**
- * Update which books are assigned to this shelf by
- * syncing the given book ids.
+ * Update which books are assigned to this shelf by syncing the given book ids.
* Function ensures the books are visible to the current user and existing.
*/
protected function updateBooks(Bookshelf $shelf, array $bookIds)
$shelf->books()->sync($syncData);
}
- /**
- * Update the given shelf cover image, or clear it.
- *
- * @throws ImageUploadException
- * @throws Exception
- */
- public function updateCoverImage(Bookshelf $shelf, ?UploadedFile $coverImage, bool $removeImage = false)
- {
- $this->baseRepo->updateCoverImage($shelf, $coverImage, $removeImage);
- }
-
/**
* Copy down the permissions of the given shelf to all child books.
*/
return $parentClass::visible()->where('id', '=', $entityId)->first();
}
- /**
- * Change the page's parent to the given entity.
- */
- protected function changeParent(Page $page, Entity $parent)
- {
- $book = ($parent instanceof Chapter) ? $parent->book : $parent;
- $page->chapter_id = ($parent instanceof Chapter) ? $parent->id : 0;
- $page->save();
-
- if ($page->book->id !== $book->id) {
- $page->changeBook($book->id);
- }
-
- $page->load('book');
- $book->rebuildPermissions();
- }
-
/**
* Get a page revision to update for the given page.
* Checks for an existing revisions before providing a fresh one.
class Cloner
{
- /**
- * @var PageRepo
- */
- protected $pageRepo;
-
- /**
- * @var ChapterRepo
- */
- protected $chapterRepo;
-
- /**
- * @var BookRepo
- */
- protected $bookRepo;
-
- /**
- * @var ImageService
- */
- protected $imageService;
+ protected PageRepo $pageRepo;
+ protected ChapterRepo $chapterRepo;
+ protected BookRepo $bookRepo;
+ protected ImageService $imageService;
public function __construct(PageRepo $pageRepo, ChapterRepo $chapterRepo, BookRepo $bookRepo, ImageService $imageService)
{
public function clonePage(Page $original, Entity $parent, string $newName): Page
{
$copyPage = $this->pageRepo->getNewDraftPage($parent);
- $pageData = $original->getAttributes();
-
- // Update name & tags
+ $pageData = $this->entityToInputData($original);
$pageData['name'] = $newName;
- $pageData['tags'] = $this->entityTagsToInputArray($original);
return $this->pageRepo->publishDraft($copyPage, $pageData);
}
*/
public function cloneChapter(Chapter $original, Book $parent, string $newName): Chapter
{
- $chapterDetails = $original->getAttributes();
+ $chapterDetails = $this->entityToInputData($original);
$chapterDetails['name'] = $newName;
- $chapterDetails['tags'] = $this->entityTagsToInputArray($original);
$copyChapter = $this->chapterRepo->create($chapterDetails, $parent);
*/
public function cloneBook(Book $original, string $newName): Book
{
- $bookDetails = $original->getAttributes();
+ $bookDetails = $this->entityToInputData($original);
$bookDetails['name'] = $newName;
- $bookDetails['tags'] = $this->entityTagsToInputArray($original);
$copyBook = $this->bookRepo->create($bookDetails);
}
}
- if ($original->cover) {
- try {
- $tmpImgFile = tmpfile();
- $uploadedFile = $this->imageToUploadedFile($original->cover, $tmpImgFile);
- $this->bookRepo->updateCoverImage($copyBook, $uploadedFile, false);
- } catch (\Exception $exception) {
- }
+ return $copyBook;
+ }
+
+ /**
+ * Convert an entity to a raw data array of input data.
+ *
+ * @return array<string, mixed>
+ */
+ public function entityToInputData(Entity $entity): array
+ {
+ $inputData = $entity->getAttributes();
+ $inputData['tags'] = $this->entityTagsToInputArray($entity);
+
+ // Add a cover to the data if existing on the original entity
+ if ($entity->cover instanceof Image) {
+ $uploadedFile = $this->imageToUploadedFile($entity->cover);
+ $inputData['image'] = $uploadedFile;
}
- return $copyBook;
+ return $inputData;
+ }
+
+ /**
+ * Copy the permission settings from the source entity to the target entity.
+ */
+ public function copyEntityPermissions(Entity $sourceEntity, Entity $targetEntity): void
+ {
+ $targetEntity->restricted = $sourceEntity->restricted;
+ $permissions = $sourceEntity->permissions()->get(['role_id', 'action'])->toArray();
+ $targetEntity->permissions()->delete();
+ $targetEntity->permissions()->createMany($permissions);
+ $targetEntity->rebuildPermissions();
}
/**
* Convert an image instance to an UploadedFile instance to mimic
* a file being uploaded.
*/
- protected function imageToUploadedFile(Image $image, &$tmpFile): ?UploadedFile
+ protected function imageToUploadedFile(Image $image): ?UploadedFile
{
$imgData = $this->imageService->getImageData($image);
- $tmpImgFilePath = stream_get_meta_data($tmpFile)['uri'];
+ $tmpImgFilePath = tempnam(sys_get_temp_dir(), 'bs_cover_clone_');
file_put_contents($tmpImgFilePath, $imgData);
return new UploadedFile($tmpImgFilePath, basename($image->path));
public function pageToContainedHtml(Page $page)
{
$page->html = (new PageContent($page))->render();
- $pageHtml = view('pages.export', [
+ $pageHtml = view('exports.page', [
'page' => $page,
'format' => 'html',
'cspContent' => $this->cspService->getCspMetaTagValue(),
$pages->each(function ($page) {
$page->html = (new PageContent($page))->render();
});
- $html = view('chapters.export', [
+ $html = view('exports.chapter', [
'chapter' => $chapter,
'pages' => $pages,
'format' => 'html',
public function bookToContainedHtml(Book $book)
{
$bookTree = (new BookContents($book))->getTree(false, true);
- $html = view('books.export', [
+ $html = view('exports.book', [
'book' => $book,
'bookChildren' => $bookTree,
'format' => 'html',
public function pageToPdf(Page $page)
{
$page->html = (new PageContent($page))->render();
- $html = view('pages.export', [
+ $html = view('exports.page', [
'page' => $page,
'format' => 'pdf',
'engine' => $this->pdfGenerator->getActiveEngine(),
$page->html = (new PageContent($page))->render();
});
- $html = view('chapters.export', [
+ $html = view('exports.chapter', [
'chapter' => $chapter,
'pages' => $pages,
'format' => 'pdf',
public function bookToPdf(Book $book)
{
$bookTree = (new BookContents($book))->getTree(false, true);
- $html = view('books.export', [
+ $html = view('exports.book', [
'book' => $book,
'bookChildren' => $bookTree,
'format' => 'pdf',
--- /dev/null
+<?php
+
+namespace BookStack\Entities\Tools;
+
+use BookStack\Actions\ActivityType;
+use BookStack\Entities\Models\Book;
+use BookStack\Entities\Models\Bookshelf;
+use BookStack\Entities\Models\Chapter;
+use BookStack\Entities\Models\Page;
+use BookStack\Entities\Repos\BookRepo;
+use BookStack\Entities\Repos\BookshelfRepo;
+use BookStack\Facades\Activity;
+
+class HierarchyTransformer
+{
+ protected BookRepo $bookRepo;
+ protected BookshelfRepo $shelfRepo;
+ protected Cloner $cloner;
+ protected TrashCan $trashCan;
+
+ public function __construct(BookRepo $bookRepo, BookshelfRepo $shelfRepo, Cloner $cloner, TrashCan $trashCan)
+ {
+ $this->bookRepo = $bookRepo;
+ $this->shelfRepo = $shelfRepo;
+ $this->cloner = $cloner;
+ $this->trashCan = $trashCan;
+ }
+
+ /**
+ * Transform a chapter into a book.
+ * Does not check permissions, check before calling.
+ */
+ public function transformChapterToBook(Chapter $chapter): Book
+ {
+ $inputData = $this->cloner->entityToInputData($chapter);
+ $book = $this->bookRepo->create($inputData);
+ $this->cloner->copyEntityPermissions($chapter, $book);
+
+ /** @var Page $page */
+ foreach ($chapter->pages as $page) {
+ $page->chapter_id = 0;
+ $page->changeBook($book->id);
+ }
+
+ $this->trashCan->destroyEntity($chapter);
+
+ Activity::add(ActivityType::BOOK_CREATE_FROM_CHAPTER, $book);
+
+ return $book;
+ }
+
+ /**
+ * Transform a book into a shelf.
+ * Does not check permissions, check before calling.
+ */
+ public function transformBookToShelf(Book $book): Bookshelf
+ {
+ $inputData = $this->cloner->entityToInputData($book);
+ $shelf = $this->shelfRepo->create($inputData, []);
+ $this->cloner->copyEntityPermissions($book, $shelf);
+
+ $shelfBookSyncData = [];
+
+ /** @var Chapter $chapter */
+ foreach ($book->chapters as $index => $chapter) {
+ $newBook = $this->transformChapterToBook($chapter);
+ $shelfBookSyncData[$newBook->id] = ['order' => $index];
+ if (!$newBook->restricted) {
+ $this->cloner->copyEntityPermissions($shelf, $newBook);
+ }
+ }
+
+ if ($book->directPages->count() > 0) {
+ $book->name .= ' ' . trans('entities.pages');
+ $shelfBookSyncData[$book->id] = ['order' => count($shelfBookSyncData) + 1];
+ $book->save();
+ } else {
+ $this->trashCan->destroyEntity($book);
+ }
+
+ $shelf->books()->sync($shelfBookSyncData);
+
+ Activity::add(ActivityType::BOOKSHELF_CREATE_FROM_BOOK, $shelf);
+
+ return $shelf;
+ }
+}
];
$html = '<body>' . $html . '</body>';
+ $html = str_ireplace(['<br>', '<br />', '<br/>'], "\n", $html);
+
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
/** @var Connection $connection */
$connection = $query->getConnection();
$tagValue = (float) trim($connection->getPdo()->quote($tagValue), "'");
- $query->whereRaw("value ${tagOperator} ${tagValue}");
+ $query->whereRaw("value {$tagOperator} {$tagValue}");
} else {
$query->where('value', $tagOperator, $tagValue);
}
*
* @throws Exception
*/
- protected function destroyEntity(Entity $entity): int
+ public function destroyEntity(Entity $entity): int
{
if ($entity instanceof Page) {
return $this->destroyPage($entity);
*/
protected $dontReport = [
NotFoundException::class,
+ StoppedAuthenticationException::class,
];
/**
}
/**
- * Covert this exception into a response.
+ * Convert this exception into a response.
+ * We add a manual data conversion to UTF8 to ensure any binary data is presentable as a JSON string.
*/
public function render(): JsonResponse
{
- return response()->json($this->data);
+ $cleaned = mb_convert_encoding($this->data, 'UTF-8');
+
+ return response()->json($cleaned);
}
}
{
protected $bookRepo;
- protected $rules = [
- 'create' => [
- 'name' => ['required', 'string', 'max:255'],
- 'description' => ['string', 'max:1000'],
- 'tags' => ['array'],
- ],
- 'update' => [
- 'name' => ['string', 'min:1', 'max:255'],
- 'description' => ['string', 'max:1000'],
- 'tags' => ['array'],
- ],
- ];
-
public function __construct(BookRepo $bookRepo)
{
$this->bookRepo = $bookRepo;
$books = Book::visible();
return $this->apiListingResponse($books, [
- 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by', 'image_id',
+ 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
]);
}
/**
* Create a new book in the system.
+ * The cover image of a book can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
+ * If the 'image' property is null then the book cover image will be removed.
*
* @throws ValidationException
*/
public function create(Request $request)
{
$this->checkPermission('book-create-all');
- $requestData = $this->validate($request, $this->rules['create']);
+ $requestData = $this->validate($request, $this->rules()['create']);
$book = $this->bookRepo->create($requestData);
/**
* Update the details of a single book.
+ * The cover image of a book can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
+ * If the 'image' property is null then the book cover image will be removed.
*
* @throws ValidationException
*/
$book = Book::visible()->findOrFail($id);
$this->checkOwnablePermission('book-update', $book);
- $requestData = $this->validate($request, $this->rules['update']);
+ $requestData = $this->validate($request, $this->rules()['update']);
$book = $this->bookRepo->update($book, $requestData);
return response()->json($book);
return response('', 204);
}
+
+ protected function rules(): array
+ {
+ return [
+ 'create' => [
+ 'name' => ['required', 'string', 'max:255'],
+ 'description' => ['string', 'max:1000'],
+ 'tags' => ['array'],
+ 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
+ ],
+ 'update' => [
+ 'name' => ['string', 'min:1', 'max:255'],
+ 'description' => ['string', 'max:1000'],
+ 'tags' => ['array'],
+ 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
+ ],
+ ];
+ }
}
$book = Book::visible()->findOrFail($id);
$pdfContent = $this->exportFormatter->bookToPdf($book);
- return $this->downloadResponse($pdfContent, $book->slug . '.pdf');
+ return $this->download()->directly($pdfContent, $book->slug . '.pdf');
}
/**
$book = Book::visible()->findOrFail($id);
$htmlContent = $this->exportFormatter->bookToContainedHtml($book);
- return $this->downloadResponse($htmlContent, $book->slug . '.html');
+ return $this->download()->directly($htmlContent, $book->slug . '.html');
}
/**
$book = Book::visible()->findOrFail($id);
$textContent = $this->exportFormatter->bookToPlainText($book);
- return $this->downloadResponse($textContent, $book->slug . '.txt');
+ return $this->download()->directly($textContent, $book->slug . '.txt');
}
/**
$book = Book::visible()->findOrFail($id);
$markdown = $this->exportFormatter->bookToMarkdown($book);
- return $this->downloadResponse($markdown, $book->slug . '.md');
+ return $this->download()->directly($markdown, $book->slug . '.md');
}
}
{
protected BookshelfRepo $bookshelfRepo;
- protected $rules = [
- 'create' => [
- 'name' => ['required', 'string', 'max:255'],
- 'description' => ['string', 'max:1000'],
- 'books' => ['array'],
- 'tags' => ['array'],
- ],
- 'update' => [
- 'name' => ['string', 'min:1', 'max:255'],
- 'description' => ['string', 'max:1000'],
- 'books' => ['array'],
- 'tags' => ['array'],
- ],
- ];
-
/**
* BookshelfApiController constructor.
*/
$shelves = Bookshelf::visible();
return $this->apiListingResponse($shelves, [
- 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by', 'image_id',
+ 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
]);
}
* Create a new shelf in the system.
* An array of books IDs can be provided in the request. These
* will be added to the shelf in the same order as provided.
+ * The cover image of a shelf can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
+ * If the 'image' property is null then the shelf cover image will be removed.
*
* @throws ValidationException
*/
public function create(Request $request)
{
$this->checkPermission('bookshelf-create-all');
- $requestData = $this->validate($request, $this->rules['create']);
+ $requestData = $this->validate($request, $this->rules()['create']);
$bookIds = $request->get('books', []);
$shelf = $this->bookshelfRepo->create($requestData, $bookIds);
* An array of books IDs can be provided in the request. These
* will be added to the shelf in the same order as provided and overwrite
* any existing book assignments.
+ * The cover image of a shelf can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
+ * If the 'image' property is null then the shelf cover image will be removed.
*
* @throws ValidationException
*/
$shelf = Bookshelf::visible()->findOrFail($id);
$this->checkOwnablePermission('bookshelf-update', $shelf);
- $requestData = $this->validate($request, $this->rules['update']);
+ $requestData = $this->validate($request, $this->rules()['update']);
$bookIds = $request->get('books', null);
$shelf = $this->bookshelfRepo->update($shelf, $requestData, $bookIds);
return response('', 204);
}
+
+ protected function rules(): array
+ {
+ return [
+ 'create' => [
+ 'name' => ['required', 'string', 'max:255'],
+ 'description' => ['string', 'max:1000'],
+ 'books' => ['array'],
+ 'tags' => ['array'],
+ 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
+ ],
+ 'update' => [
+ 'name' => ['string', 'min:1', 'max:255'],
+ 'description' => ['string', 'max:1000'],
+ 'books' => ['array'],
+ 'tags' => ['array'],
+ 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
+ ],
+ ];
+ }
}
$chapter = Chapter::visible()->findOrFail($id);
$pdfContent = $this->exportFormatter->chapterToPdf($chapter);
- return $this->downloadResponse($pdfContent, $chapter->slug . '.pdf');
+ return $this->download()->directly($pdfContent, $chapter->slug . '.pdf');
}
/**
$chapter = Chapter::visible()->findOrFail($id);
$htmlContent = $this->exportFormatter->chapterToContainedHtml($chapter);
- return $this->downloadResponse($htmlContent, $chapter->slug . '.html');
+ return $this->download()->directly($htmlContent, $chapter->slug . '.html');
}
/**
$chapter = Chapter::visible()->findOrFail($id);
$textContent = $this->exportFormatter->chapterToPlainText($chapter);
- return $this->downloadResponse($textContent, $chapter->slug . '.txt');
+ return $this->download()->directly($textContent, $chapter->slug . '.txt');
}
/**
$chapter = Chapter::visible()->findOrFail($id);
$markdown = $this->exportFormatter->chapterToMarkdown($chapter);
- return $this->downloadResponse($markdown, $chapter->slug . '.md');
+ return $this->download()->directly($markdown, $chapter->slug . '.md');
}
}
$page = Page::visible()->findOrFail($id);
$pdfContent = $this->exportFormatter->pageToPdf($page);
- return $this->downloadResponse($pdfContent, $page->slug . '.pdf');
+ return $this->download()->directly($pdfContent, $page->slug . '.pdf');
}
/**
$page = Page::visible()->findOrFail($id);
$htmlContent = $this->exportFormatter->pageToContainedHtml($page);
- return $this->downloadResponse($htmlContent, $page->slug . '.html');
+ return $this->download()->directly($htmlContent, $page->slug . '.html');
}
/**
$page = Page::visible()->findOrFail($id);
$textContent = $this->exportFormatter->pageToPlainText($page);
- return $this->downloadResponse($textContent, $page->slug . '.txt');
+ return $this->download()->directly($textContent, $page->slug . '.txt');
}
/**
$page = Page::visible()->findOrFail($id);
$markdown = $this->exportFormatter->pageToMarkdown($page);
- return $this->downloadResponse($markdown, $page->slug . '.md');
+ return $this->download()->directly($markdown, $page->slug . '.md');
}
}
$attachmentStream = $this->attachmentService->streamAttachmentFromStorage($attachment);
if ($request->get('open') === 'true') {
- return $this->streamedInlineDownloadResponse($attachmentStream, $fileName);
+ return $this->download()->streamedInline($attachmentStream, $fileName);
}
- return $this->streamedDownloadResponse($attachmentStream, $fileName);
+ return $this->download()->streamedDirectly($attachmentStream, $fileName);
}
/**
use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\Cloner;
+use BookStack\Entities\Tools\HierarchyTransformer;
use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Entities\Tools\ShelfContext;
use BookStack\Exceptions\ImageUploadException;
}
$book = $this->bookRepo->create($request->all());
- $this->bookRepo->updateCoverImage($book, $request->file('image', null));
if ($bookshelf) {
$bookshelf->appendBook($book);
{
$book = $this->bookRepo->getBySlug($slug);
$this->checkOwnablePermission('book-update', $book);
- $this->validate($request, [
+
+ $validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
]);
- $book = $this->bookRepo->update($book, $request->all());
- $resetCover = $request->has('image_reset');
- $this->bookRepo->updateCoverImage($book, $request->file('image', null), $resetCover);
+ if ($request->has('image_reset')) {
+ $validated['image'] = null;
+ } elseif (array_key_exists('image', $validated) && is_null($validated['image'])) {
+ unset($validated['image']);
+ }
+
+ $book = $this->bookRepo->update($book, $validated);
return redirect($book->getUrl());
}
return redirect($bookCopy->getUrl());
}
+
+ /**
+ * Convert the chapter to a book.
+ */
+ public function convertToShelf(HierarchyTransformer $transformer, string $bookSlug)
+ {
+ $book = $this->bookRepo->getBySlug($bookSlug);
+ $this->checkOwnablePermission('book-update', $book);
+ $this->checkOwnablePermission('book-delete', $book);
+ $this->checkPermission('bookshelf-create-all');
+ $this->checkPermission('book-create-all');
+
+ $shelf = $transformer->transformBookToShelf($book);
+
+ return redirect($shelf->getUrl());
+ }
}
$book = $this->bookRepo->getBySlug($bookSlug);
$pdfContent = $this->exportFormatter->bookToPdf($book);
- return $this->downloadResponse($pdfContent, $bookSlug . '.pdf');
+ return $this->download()->directly($pdfContent, $bookSlug . '.pdf');
}
/**
$book = $this->bookRepo->getBySlug($bookSlug);
$htmlContent = $this->exportFormatter->bookToContainedHtml($book);
- return $this->downloadResponse($htmlContent, $bookSlug . '.html');
+ return $this->download()->directly($htmlContent, $bookSlug . '.html');
}
/**
$book = $this->bookRepo->getBySlug($bookSlug);
$textContent = $this->exportFormatter->bookToPlainText($book);
- return $this->downloadResponse($textContent, $bookSlug . '.txt');
+ return $this->download()->directly($textContent, $bookSlug . '.txt');
}
/**
$book = $this->bookRepo->getBySlug($bookSlug);
$textContent = $this->exportFormatter->bookToMarkdown($book);
- return $this->downloadResponse($textContent, $bookSlug . '.md');
+ return $this->download()->directly($textContent, $bookSlug . '.md');
}
}
public function store(Request $request)
{
$this->checkPermission('bookshelf-create-all');
- $this->validate($request, [
+ $validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
+ 'tags' => ['array'],
]);
$bookIds = explode(',', $request->get('books', ''));
- $shelf = $this->bookshelfRepo->create($request->all(), $bookIds);
- $this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null));
+ $shelf = $this->bookshelfRepo->create($validated, $bookIds);
return redirect($shelf->getUrl());
}
{
$shelf = $this->bookshelfRepo->getBySlug($slug);
$this->checkOwnablePermission('bookshelf-update', $shelf);
- $this->validate($request, [
+ $validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
+ 'tags' => ['array'],
]);
+ if ($request->has('image_reset')) {
+ $validated['image'] = null;
+ } elseif (array_key_exists('image', $validated) && is_null($validated['image'])) {
+ unset($validated['image']);
+ }
+
$bookIds = explode(',', $request->get('books', ''));
- $shelf = $this->bookshelfRepo->update($shelf, $request->all(), $bookIds);
- $resetCover = $request->has('image_reset');
- $this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null), $resetCover);
+ $shelf = $this->bookshelfRepo->update($shelf, $validated, $bookIds);
return redirect($shelf->getUrl());
}
use BookStack\Entities\Repos\ChapterRepo;
use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\Cloner;
+use BookStack\Entities\Tools\HierarchyTransformer;
use BookStack\Entities\Tools\NextPreviousContentLocator;
use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Exceptions\MoveOperationException;
return redirect($chapter->getUrl());
}
+
+ /**
+ * Convert the chapter to a book.
+ */
+ public function convertToBook(HierarchyTransformer $transformer, string $bookSlug, string $chapterSlug)
+ {
+ $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
+ $this->checkOwnablePermission('chapter-update', $chapter);
+ $this->checkOwnablePermission('chapter-delete', $chapter);
+ $this->checkPermission('book-create-all');
+
+ $book = $transformer->transformChapterToBook($chapter);
+
+ return redirect($book->getUrl());
+ }
}
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$pdfContent = $this->exportFormatter->chapterToPdf($chapter);
- return $this->downloadResponse($pdfContent, $chapterSlug . '.pdf');
+ return $this->download()->directly($pdfContent, $chapterSlug . '.pdf');
}
/**
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$containedHtml = $this->exportFormatter->chapterToContainedHtml($chapter);
- return $this->downloadResponse($containedHtml, $chapterSlug . '.html');
+ return $this->download()->directly($containedHtml, $chapterSlug . '.html');
}
/**
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$chapterText = $this->exportFormatter->chapterToPlainText($chapter);
- return $this->downloadResponse($chapterText, $chapterSlug . '.txt');
+ return $this->download()->directly($chapterText, $chapterSlug . '.txt');
}
/**
*/
public function markdown(string $bookSlug, string $chapterSlug)
{
- // TODO: This should probably export to a zip file.
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$chapterText = $this->exportFormatter->chapterToMarkdown($chapter);
- return $this->downloadResponse($chapterText, $chapterSlug . '.md');
+ return $this->download()->directly($chapterText, $chapterSlug . '.md');
}
}
use BookStack\Exceptions\NotifyException;
use BookStack\Facades\Activity;
+use BookStack\Http\Responses\DownloadResponseFactory;
use BookStack\Interfaces\Loggable;
use BookStack\Model;
-use BookStack\Util\WebSafeMimeSniffer;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\JsonResponse;
-use Illuminate\Http\Response;
use Illuminate\Routing\Controller as BaseController;
-use Symfony\Component\HttpFoundation\StreamedResponse;
abstract class Controller extends BaseController
{
}
/**
- * Create a response that forces a download in the browser.
+ * Create and return a new download response factory using the current request.
*/
- protected function downloadResponse(string $content, string $fileName): Response
+ protected function download(): DownloadResponseFactory
{
- return response()->make($content, 200, [
- 'Content-Type' => 'application/octet-stream',
- 'Content-Disposition' => 'attachment; filename="' . str_replace('"', '', $fileName) . '"',
- 'X-Content-Type-Options' => 'nosniff',
- ]);
- }
-
- /**
- * Create a response that forces a download, from a given stream of content.
- */
- protected function streamedDownloadResponse($stream, string $fileName): StreamedResponse
- {
- return response()->stream(function () use ($stream) {
- // End & flush the output buffer otherwise we still seem to use memory.
- // Ignore in testing since output buffers are used to gather a response.
- if (!app()->runningUnitTests()) {
- ob_end_clean();
- }
-
- fpassthru($stream);
- fclose($stream);
- }, 200, [
- 'Content-Type' => 'application/octet-stream',
- 'Content-Disposition' => 'attachment; filename="' . str_replace('"', '', $fileName) . '"',
- 'X-Content-Type-Options' => 'nosniff',
- ]);
- }
-
- /**
- * Create a file download response that provides the file with a content-type
- * correct for the file, in a way so the browser can show the content in browser.
- */
- protected function inlineDownloadResponse(string $content, string $fileName): Response
- {
- $mime = (new WebSafeMimeSniffer())->sniff($content);
-
- return response()->make($content, 200, [
- 'Content-Type' => $mime,
- 'Content-Disposition' => 'inline; filename="' . str_replace('"', '', $fileName) . '"',
- 'X-Content-Type-Options' => 'nosniff',
- ]);
- }
-
- /**
- * Create a file download response that provides the file with a content-type
- * correct for the file, in a way so the browser can show the content in browser,
- * for a given content stream.
- */
- protected function streamedInlineDownloadResponse($stream, string $fileName): StreamedResponse
- {
- $sniffContent = fread($stream, 1000);
- $mime = (new WebSafeMimeSniffer())->sniff($sniffContent);
-
- return response()->stream(function () use ($sniffContent, $stream) {
- echo $sniffContent;
- fpassthru($stream);
- fclose($stream);
- }, 200, [
- 'Content-Type' => $mime,
- 'Content-Disposition' => 'inline; filename="' . str_replace('"', '', $fileName) . '"',
- 'X-Content-Type-Options' => 'nosniff',
- ]);
+ return new DownloadResponseFactory(request());
}
/**
$page->html = (new PageContent($page))->render();
$pdfContent = $this->exportFormatter->pageToPdf($page);
- return $this->downloadResponse($pdfContent, $pageSlug . '.pdf');
+ return $this->download()->directly($pdfContent, $pageSlug . '.pdf');
}
/**
$page->html = (new PageContent($page))->render();
$containedHtml = $this->exportFormatter->pageToContainedHtml($page);
- return $this->downloadResponse($containedHtml, $pageSlug . '.html');
+ return $this->download()->directly($containedHtml, $pageSlug . '.html');
}
/**
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
$pageText = $this->exportFormatter->pageToPlainText($page);
- return $this->downloadResponse($pageText, $pageSlug . '.txt');
+ return $this->download()->directly($pageText, $pageSlug . '.txt');
}
/**
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
$pageText = $this->exportFormatter->pageToMarkdown($page);
- return $this->downloadResponse($pageText, $pageSlug . '.md');
+ return $this->download()->directly($pageText, $pageSlug . '.md');
}
}
$this->logActivity(ActivityType::SETTINGS_UPDATE, $category);
$this->showSuccessNotification(trans('settings.settings_save_success'));
- return redirect("/settings/${category}");
+ return redirect("/settings/{$category}");
}
protected function ensureCategoryExists(string $category): void
/**
* Array of right-to-left locales.
*/
- protected $rtlLocales = ['ar', 'he'];
+ protected $rtlLocales = ['ar', 'fa', 'he'];
/**
* Map of BookStack locale names to best-estimate system locale names.
'es_AR' => 'es_AR',
'et' => 'et_EE',
'eu' => 'eu_ES',
+ 'fa' => 'fa_IR',
'fr' => 'fr_FR',
'he' => 'he_IL',
'hr' => 'hr_HR',
$appUrl = config('app.url', null);
if ($appUrl) {
- return '/' . rtrim(implode('/', array_slice(explode('/', $appUrl), 3)), '/');
+ $parsedBaseUrl = rtrim(implode('/', array_slice(explode('/', $appUrl), 3)), '/');
+
+ return empty($parsedBaseUrl) ? '' : ('/' . $parsedBaseUrl);
}
return parent::getBaseUrl();
--- /dev/null
+<?php
+
+namespace BookStack\Http\Responses;
+
+use BookStack\Util\WebSafeMimeSniffer;
+use Illuminate\Http\Request;
+use Illuminate\Http\Response;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+
+class DownloadResponseFactory
+{
+ protected Request $request;
+
+ public function __construct(Request $request)
+ {
+ $this->request = $request;
+ }
+
+ /**
+ * Create a response that directly forces a download in the browser.
+ */
+ public function directly(string $content, string $fileName): Response
+ {
+ return response()->make($content, 200, $this->getHeaders($fileName));
+ }
+
+ /**
+ * Create a response that forces a download, from a given stream of content.
+ */
+ public function streamedDirectly($stream, string $fileName): StreamedResponse
+ {
+ return response()->stream(function () use ($stream) {
+
+ // End & flush the output buffer, if we're in one, otherwise we still use memory.
+ // Output buffer may or may not exist depending on PHP `output_buffering` setting.
+ // Ignore in testing since output buffers are used to gather a response.
+ if (!empty(ob_get_status()) && !app()->runningUnitTests()) {
+ ob_end_clean();
+ }
+
+ fpassthru($stream);
+ fclose($stream);
+ }, 200, $this->getHeaders($fileName));
+ }
+
+ /**
+ * Create a file download response that provides the file with a content-type
+ * correct for the file, in a way so the browser can show the content in browser,
+ * for a given content stream.
+ */
+ public function streamedInline($stream, string $fileName): StreamedResponse
+ {
+ $sniffContent = fread($stream, 2000);
+ $mime = (new WebSafeMimeSniffer())->sniff($sniffContent);
+
+ return response()->stream(function () use ($sniffContent, $stream) {
+ echo $sniffContent;
+ fpassthru($stream);
+ fclose($stream);
+ }, 200, $this->getHeaders($fileName, $mime));
+ }
+
+ /**
+ * Get the common headers to provide for a download response.
+ */
+ protected function getHeaders(string $fileName, string $mime = 'application/octet-stream'): array
+ {
+ $disposition = ($mime === 'application/octet-stream') ? 'attachment' : 'inline';
+ $downloadName = str_replace('"', '', $fileName);
+
+ return [
+ 'Content-Type' => $mime,
+ 'Content-Disposition' => "{$disposition}; filename=\"{$downloadName}\"",
+ 'X-Content-Type-Options' => 'nosniff',
+ ];
+ }
+}
return 'uploads/files/' . $path;
}
- /**
- * Get an attachment from storage.
- *
- * @throws FileNotFoundException
- */
- public function getAttachmentFromStorage(Attachment $attachment): string
- {
- return $this->getStorageDisk()->get($this->adjustPathForStorageDisk($attachment->path));
- }
-
/**
* Stream an attachment from storage.
*
'application/json',
'application/octet-stream',
'application/pdf',
+ 'audio/aac',
+ 'audio/midi',
+ 'audio/mpeg',
+ 'audio/ogg',
+ 'audio/opus',
+ 'audio/wav',
+ 'audio/webm',
+ 'audio/x-m4a',
'image/apng',
'image/bmp',
'image/jpeg',
},
{
"name": "aws/aws-sdk-php",
- "version": "3.222.1",
+ "version": "3.225.1",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "632621d97180e82d3adc1245a7b272774c30dbf5"
+ "reference": "b795c9c14997dac771f66d1f6cbadb62c742373a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/632621d97180e82d3adc1245a7b272774c30dbf5",
- "reference": "632621d97180e82d3adc1245a7b272774c30dbf5",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b795c9c14997dac771f66d1f6cbadb62c742373a",
+ "reference": "b795c9c14997dac771f66d1f6cbadb62c742373a",
"shasum": ""
},
"require": {
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
- "source": "https://github.com/aws/aws-sdk-php/tree/3.222.1"
+ "source": "https://github.com/aws/aws-sdk-php/tree/3.225.1"
},
- "time": "2022-04-28T18:17:24+00:00"
+ "time": "2022-06-09T18:19:43+00:00"
},
{
"name": "bacon/bacon-qr-code",
},
{
"name": "barryvdh/laravel-dompdf",
- "version": "v1.0.0",
+ "version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-dompdf.git",
- "reference": "e3f429e97087b2ef19b83e5ed313f080f2477685"
+ "reference": "de83130d029289e1b59f28b41c314ce1d157b4a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/e3f429e97087b2ef19b83e5ed313f080f2477685",
- "reference": "e3f429e97087b2ef19b83e5ed313f080f2477685",
+ "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/de83130d029289e1b59f28b41c314ce1d157b4a0",
+ "reference": "de83130d029289e1b59f28b41c314ce1d157b4a0",
"shasum": ""
},
"require": {
- "dompdf/dompdf": "^1",
+ "dompdf/dompdf": "^1.2.1",
"illuminate/support": "^6|^7|^8|^9",
"php": "^7.2 || ^8.0"
},
],
"support": {
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
- "source": "https://github.com/barryvdh/laravel-dompdf/tree/v1.0.0"
+ "source": "https://github.com/barryvdh/laravel-dompdf/tree/v1.0.2"
},
"funding": [
{
"type": "github"
}
],
- "time": "2022-01-29T08:02:59+00:00"
+ "time": "2022-05-19T15:08:38+00:00"
},
{
"name": "barryvdh/laravel-snappy",
},
{
"name": "doctrine/cache",
- "version": "2.1.1",
+ "version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
- "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce"
+ "reference": "1ca8f21980e770095a31456042471a57bc4c68fb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/cache/zipball/331b4d5dbaeab3827976273e9356b3b453c300ce",
- "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce",
+ "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb",
+ "reference": "1ca8f21980e770095a31456042471a57bc4c68fb",
"shasum": ""
},
"require": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
- "alcaeus/mongo-php-adapter": "^1.1",
"cache/integration-tests": "dev-master",
- "doctrine/coding-standard": "^8.0",
- "mongodb/mongodb": "^1.1",
- "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
- "predis/predis": "~1.0",
+ "doctrine/coding-standard": "^9",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psr/cache": "^1.0 || ^2.0 || ^3.0",
- "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev",
- "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev"
- },
- "suggest": {
- "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
+ "symfony/cache": "^4.4 || ^5.4 || ^6",
+ "symfony/var-exporter": "^4.4 || ^5.4 || ^6"
},
"type": "library",
"autoload": {
],
"support": {
"issues": "https://github.com/doctrine/cache/issues",
- "source": "https://github.com/doctrine/cache/tree/2.1.1"
+ "source": "https://github.com/doctrine/cache/tree/2.2.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-07-17T14:49:29+00:00"
+ "time": "2022-05-20T20:07:39+00:00"
},
{
"name": "doctrine/dbal",
- "version": "3.3.5",
+ "version": "3.3.6",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
- "reference": "719663b15983278227669c8595151586a2ff3327"
+ "reference": "9e7f76dd1cde81c62574fdffa5a9c655c847ad21"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/dbal/zipball/719663b15983278227669c8595151586a2ff3327",
- "reference": "719663b15983278227669c8595151586a2ff3327",
+ "url": "https://api.github.com/repos/doctrine/dbal/zipball/9e7f76dd1cde81c62574fdffa5a9c655c847ad21",
+ "reference": "9e7f76dd1cde81c62574fdffa5a9c655c847ad21",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2",
"doctrine/cache": "^1.11|^2.0",
- "doctrine/deprecations": "^0.5.3",
+ "doctrine/deprecations": "^0.5.3|^1",
"doctrine/event-manager": "^1.0",
"php": "^7.3 || ^8.0",
"psr/cache": "^1|^2|^3",
},
"require-dev": {
"doctrine/coding-standard": "9.0.0",
- "jetbrains/phpstorm-stubs": "2021.1",
- "phpstan/phpstan": "1.5.3",
- "phpstan/phpstan-strict-rules": "^1.1",
- "phpunit/phpunit": "9.5.16",
+ "jetbrains/phpstorm-stubs": "2022.1",
+ "phpstan/phpstan": "1.6.3",
+ "phpstan/phpstan-strict-rules": "^1.2",
+ "phpunit/phpunit": "9.5.20",
"psalm/plugin-phpunit": "0.16.1",
"squizlabs/php_codesniffer": "3.6.2",
"symfony/cache": "^5.2|^6.0",
"symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0",
- "vimeo/psalm": "4.22.0"
+ "vimeo/psalm": "4.23.0"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
- "source": "https://github.com/doctrine/dbal/tree/3.3.5"
+ "source": "https://github.com/doctrine/dbal/tree/3.3.6"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-05T09:50:18+00:00"
+ "time": "2022-05-02T17:21:01+00:00"
},
{
"name": "doctrine/deprecations",
- "version": "v0.5.3",
+ "version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
- "reference": "9504165960a1f83cc1480e2be1dd0a0478561314"
+ "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314",
- "reference": "9504165960a1f83cc1480e2be1dd0a0478561314",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+ "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
},
"require-dev": {
- "doctrine/coding-standard": "^6.0|^7.0|^8.0",
- "phpunit/phpunit": "^7.0|^8.0|^9.0",
- "psr/log": "^1.0"
+ "doctrine/coding-standard": "^9",
+ "phpunit/phpunit": "^7.5|^8.5|^9.5",
+ "psr/log": "^1|^2|^3"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/v0.5.3"
+ "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
},
- "time": "2021-03-21T12:59:47+00:00"
+ "time": "2022-05-02T15:47:09+00:00"
},
{
"name": "doctrine/event-manager",
},
{
"name": "guzzlehttp/guzzle",
- "version": "7.4.2",
+ "version": "7.4.4",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4"
+ "reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ac1ec1cd9b5624694c3a40be801d94137afb12b4",
- "reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/e3ff079b22820c2029d4c2a87796b6a0b8716ad8",
+ "reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
- "source": "https://github.com/guzzle/guzzle/tree/7.4.2"
+ "source": "https://github.com/guzzle/guzzle/tree/7.4.4"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-03-20T14:16:28+00:00"
+ "time": "2022-06-09T21:39:15+00:00"
},
{
"name": "guzzlehttp/promises",
},
{
"name": "guzzlehttp/psr7",
- "version": "2.2.1",
+ "version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2"
+ "reference": "83260bb50b8fc753c72d14dc1621a2dac31877ee"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/c94a94f120803a18554c1805ef2e539f8285f9a2",
- "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/83260bb50b8fc753c72d14dc1621a2dac31877ee",
+ "reference": "83260bb50b8fc753c72d14dc1621a2dac31877ee",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.2-dev"
+ "dev-master": "2.3-dev"
}
},
"autoload": {
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/2.2.1"
+ "source": "https://github.com/guzzle/psr7/tree/2.3.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-03-20T21:55:58+00:00"
+ "time": "2022-06-09T08:26:02+00:00"
},
{
"name": "intervention/image",
- "version": "2.7.1",
+ "version": "2.7.2",
"source": {
"type": "git",
"url": "https://github.com/Intervention/image.git",
- "reference": "744ebba495319501b873a4e48787759c72e3fb8c"
+ "reference": "04be355f8d6734c826045d02a1079ad658322dad"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Intervention/image/zipball/744ebba495319501b873a4e48787759c72e3fb8c",
- "reference": "744ebba495319501b873a4e48787759c72e3fb8c",
+ "url": "https://api.github.com/repos/Intervention/image/zipball/04be355f8d6734c826045d02a1079ad658322dad",
+ "reference": "04be355f8d6734c826045d02a1079ad658322dad",
"shasum": ""
},
"require": {
"authors": [
{
"name": "Oliver Vogel",
- "email": "oliver@olivervogel.com",
- "homepage": "http://olivervogel.com/"
+ "email": "oliver@intervention.io",
+ "homepage": "https://intervention.io/"
}
],
"description": "Image handling and manipulation library with support for Laravel integration",
],
"support": {
"issues": "https://github.com/Intervention/image/issues",
- "source": "https://github.com/Intervention/image/tree/2.7.1"
+ "source": "https://github.com/Intervention/image/tree/2.7.2"
},
"funding": [
{
- "url": "https://www.paypal.me/interventionphp",
+ "url": "https://paypal.me/interventionio",
"type": "custom"
},
{
"type": "github"
}
],
- "time": "2021-12-16T16:49:26+00:00"
+ "time": "2022-05-21T17:30:32+00:00"
},
{
"name": "knplabs/knp-snappy",
},
{
"name": "laravel/framework",
- "version": "v8.83.10",
+ "version": "v8.83.16",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "148ae59b7da6c3db6736374d357c5aaef9506fb7"
+ "reference": "6be5abd144faf517879af7298e9d79f06f250f75"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/148ae59b7da6c3db6736374d357c5aaef9506fb7",
- "reference": "148ae59b7da6c3db6736374d357c5aaef9506fb7",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/6be5abd144faf517879af7298e9d79f06f250f75",
+ "reference": "6be5abd144faf517879af7298e9d79f06f250f75",
"shasum": ""
},
"require": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2022-04-27T14:07:37+00:00"
+ "time": "2022-06-07T15:09:06+00:00"
},
{
"name": "laravel/serializable-closure",
- "version": "v1.1.1",
+ "version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
- "reference": "9e4b005daa20b0c161f3845040046dc9ddc1d74e"
+ "reference": "09f0e9fb61829f628205b7c94906c28740ff9540"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/9e4b005daa20b0c161f3845040046dc9ddc1d74e",
- "reference": "9e4b005daa20b0c161f3845040046dc9ddc1d74e",
+ "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/09f0e9fb61829f628205b7c94906c28740ff9540",
+ "reference": "09f0e9fb61829f628205b7c94906c28740ff9540",
"shasum": ""
},
"require": {
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
- "time": "2022-02-11T19:23:53+00:00"
+ "time": "2022-05-16T17:09:47+00:00"
},
{
"name": "laravel/socialite",
},
{
"name": "laravel/ui",
- "version": "v3.4.5",
+ "version": "v3.4.6",
"source": {
"type": "git",
"url": "https://github.com/laravel/ui.git",
- "reference": "f11d295de1508c5bb56206a620b00b6616de414c"
+ "reference": "65ec5c03f7fee2c8ecae785795b829a15be48c2c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/ui/zipball/f11d295de1508c5bb56206a620b00b6616de414c",
- "reference": "f11d295de1508c5bb56206a620b00b6616de414c",
+ "url": "https://api.github.com/repos/laravel/ui/zipball/65ec5c03f7fee2c8ecae785795b829a15be48c2c",
+ "reference": "65ec5c03f7fee2c8ecae785795b829a15be48c2c",
"shasum": ""
},
"require": {
"ui"
],
"support": {
- "source": "https://github.com/laravel/ui/tree/v3.4.5"
+ "source": "https://github.com/laravel/ui/tree/v3.4.6"
},
- "time": "2022-02-21T14:59:16+00:00"
+ "time": "2022-05-20T13:38:08+00:00"
},
{
"name": "league/commonmark",
},
{
"name": "monolog/monolog",
- "version": "2.5.0",
+ "version": "2.7.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
- "reference": "4192345e260f1d51b365536199744b987e160edc"
+ "reference": "5579edf28aee1190a798bfa5be8bc16c563bd524"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4192345e260f1d51b365536199744b987e160edc",
- "reference": "4192345e260f1d51b365536199744b987e160edc",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/5579edf28aee1190a798bfa5be8bc16c563bd524",
+ "reference": "5579edf28aee1190a798bfa5be8bc16c563bd524",
"shasum": ""
},
"require": {
"require-dev": {
"aws/aws-sdk-php": "^2.4.9 || ^3.0",
"doctrine/couchdb": "~1.0@dev",
- "elasticsearch/elasticsearch": "^7",
+ "elasticsearch/elasticsearch": "^7 || ^8",
+ "ext-json": "*",
"graylog2/gelf-php": "^1.4.2",
+ "guzzlehttp/guzzle": "^7.4",
+ "guzzlehttp/psr7": "^2.2",
"mongodb/mongodb": "^1.8",
"php-amqplib/php-amqplib": "~2.4 || ^3",
"php-console/php-console": "^3.1.3",
- "phpspec/prophecy": "^1.6.1",
+ "phpspec/prophecy": "^1.15",
"phpstan/phpstan": "^0.12.91",
- "phpunit/phpunit": "^8.5",
+ "phpunit/phpunit": "^8.5.14",
"predis/predis": "^1.1",
"rollbar/rollbar": "^1.3 || ^2 || ^3",
- "ruflin/elastica": ">=0.90@dev",
- "swiftmailer/swiftmailer": "^5.3|^6.0"
+ "ruflin/elastica": "^7",
+ "swiftmailer/swiftmailer": "^5.3|^6.0",
+ "symfony/mailer": "^5.4 || ^6",
+ "symfony/mime": "^5.4 || ^6"
},
"suggest": {
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
- "source": "https://github.com/Seldaek/monolog/tree/2.5.0"
+ "source": "https://github.com/Seldaek/monolog/tree/2.7.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-08T15:43:54+00:00"
+ "time": "2022-06-09T08:59:12+00:00"
},
{
"name": "mtdowling/jmespath.php",
},
{
"name": "nesbot/carbon",
- "version": "2.57.0",
+ "version": "2.58.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
- "reference": "4a54375c21eea4811dbd1149fe6b246517554e78"
+ "reference": "97a34af22bde8d0ac20ab34b29d7bfe360902055"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4a54375c21eea4811dbd1149fe6b246517554e78",
- "reference": "4a54375c21eea4811dbd1149fe6b246517554e78",
+ "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/97a34af22bde8d0ac20ab34b29d7bfe360902055",
+ "reference": "97a34af22bde8d0ac20ab34b29d7bfe360902055",
"shasum": ""
},
"require": {
"phpmd/phpmd": "^2.9",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12.54 || ^1.0",
- "phpunit/phpunit": "^7.5.20 || ^8.5.14",
+ "phpunit/php-file-iterator": "^2.0.5",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23",
"squizlabs/php_codesniffer": "^3.4"
},
"bin": [
"type": "tidelift"
}
],
- "time": "2022-02-13T18:13:33+00:00"
+ "time": "2022-04-25T19:31:17+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v4.13.2",
+ "version": "v4.14.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "210577fe3cf7badcc5814d99455df46564f3c077"
+ "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077",
- "reference": "210577fe3cf7badcc5814d99455df46564f3c077",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1",
+ "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0"
},
- "time": "2021-11-30T19:35:32+00:00"
+ "time": "2022-05-31T20:59:12+00:00"
},
{
"name": "onelogin/php-saml",
},
{
"name": "paragonie/constant_time_encoding",
- "version": "v2.5.0",
+ "version": "v2.6.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
- "reference": "9229e15f2e6ba772f0c55dd6986c563b937170a8"
+ "reference": "3f3bf06406244a94aeffd5818ba05b41a1754ae5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/9229e15f2e6ba772f0c55dd6986c563b937170a8",
- "reference": "9229e15f2e6ba772f0c55dd6986c563b937170a8",
+ "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/3f3bf06406244a94aeffd5818ba05b41a1754ae5",
+ "reference": "3f3bf06406244a94aeffd5818ba05b41a1754ae5",
"shasum": ""
},
"require": {
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
"source": "https://github.com/paragonie/constant_time_encoding"
},
- "time": "2022-01-17T05:32:27+00:00"
+ "time": "2022-06-10T07:38:28+00:00"
},
{
"name": "paragonie/random_compat",
},
{
"name": "psy/psysh",
- "version": "v0.11.2",
+ "version": "v0.11.5",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
- "reference": "7f7da640d68b9c9fec819caae7c744a213df6514"
+ "reference": "c23686f9c48ca202710dbb967df8385a952a2daf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/bobthecow/psysh/zipball/7f7da640d68b9c9fec819caae7c744a213df6514",
- "reference": "7f7da640d68b9c9fec819caae7c744a213df6514",
+ "url": "https://api.github.com/repos/bobthecow/psysh/zipball/c23686f9c48ca202710dbb967df8385a952a2daf",
+ "reference": "c23686f9c48ca202710dbb967df8385a952a2daf",
"shasum": ""
},
"require": {
"symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4"
},
"require-dev": {
- "bamarni/composer-bin-plugin": "^1.2",
- "hoa/console": "3.17.05.02"
+ "bamarni/composer-bin-plugin": "^1.2"
},
"suggest": {
"ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
"ext-pdo-sqlite": "The doc command requires SQLite to work.",
"ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.",
- "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.",
- "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit."
+ "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history."
},
"bin": [
"bin/psysh"
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
- "source": "https://github.com/bobthecow/psysh/tree/v0.11.2"
+ "source": "https://github.com/bobthecow/psysh/tree/v0.11.5"
},
- "time": "2022-02-28T15:28:54+00:00"
+ "time": "2022-05-27T18:03:49+00:00"
},
{
"name": "ralouphie/getallheaders",
},
{
"name": "symfony/console",
- "version": "v5.4.8",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b"
+ "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b",
- "reference": "ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b",
+ "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb",
+ "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb",
"shasum": ""
},
"require": {
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v5.4.8"
+ "source": "https://github.com/symfony/console/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-12T16:02:29+00:00"
+ "time": "2022-05-18T06:17:34+00:00"
},
{
"name": "symfony/css-selector",
},
{
"name": "symfony/error-handler",
- "version": "v5.4.8",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
- "reference": "c1fcde614dfe99d62a83b796a53b8bad358b266a"
+ "reference": "c116cda1f51c678782768dce89a45f13c949455d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/error-handler/zipball/c1fcde614dfe99d62a83b796a53b8bad358b266a",
- "reference": "c1fcde614dfe99d62a83b796a53b8bad358b266a",
+ "url": "https://api.github.com/repos/symfony/error-handler/zipball/c116cda1f51c678782768dce89a45f13c949455d",
+ "reference": "c116cda1f51c678782768dce89a45f13c949455d",
"shasum": ""
},
"require": {
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/error-handler/tree/v5.4.8"
+ "source": "https://github.com/symfony/error-handler/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-12T15:48:08+00:00"
+ "time": "2022-05-21T13:57:48+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v5.4.3",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d"
+ "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dec8a9f58d20df252b9cd89f1c6c1530f747685d",
- "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
+ "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
"shasum": ""
},
"require": {
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.3"
+ "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-01-02T09:53:40+00:00"
+ "time": "2022-05-05T16:45:39+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
},
{
"name": "symfony/http-foundation",
- "version": "v5.4.8",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "ff2818d1c3d49860bcae1f2cbb5eb00fcd3bf9e2"
+ "reference": "6b0d0e4aca38d57605dcd11e2416994b38774522"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ff2818d1c3d49860bcae1f2cbb5eb00fcd3bf9e2",
- "reference": "ff2818d1c3d49860bcae1f2cbb5eb00fcd3bf9e2",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6b0d0e4aca38d57605dcd11e2416994b38774522",
+ "reference": "6b0d0e4aca38d57605dcd11e2416994b38774522",
"shasum": ""
},
"require": {
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v5.4.8"
+ "source": "https://github.com/symfony/http-foundation/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-22T08:14:12+00:00"
+ "time": "2022-05-17T15:07:29+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v5.4.8",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "cf7e61106abfc19b305ca0aedc41724ced89a02a"
+ "reference": "34b121ad3dc761f35fe1346d2f15618f8cbf77f8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/cf7e61106abfc19b305ca0aedc41724ced89a02a",
- "reference": "cf7e61106abfc19b305ca0aedc41724ced89a02a",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/34b121ad3dc761f35fe1346d2f15618f8cbf77f8",
+ "reference": "34b121ad3dc761f35fe1346d2f15618f8cbf77f8",
"shasum": ""
},
"require": {
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-kernel/tree/v5.4.8"
+ "source": "https://github.com/symfony/http-kernel/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-27T17:22:21+00:00"
+ "time": "2022-05-27T07:09:08+00:00"
},
{
"name": "symfony/mime",
- "version": "v5.4.8",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
- "reference": "af49bc163ec3272f677bde3bc44c0d766c1fd662"
+ "reference": "2b3802a24e48d0cfccf885173d2aac91e73df92e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mime/zipball/af49bc163ec3272f677bde3bc44c0d766c1fd662",
- "reference": "af49bc163ec3272f677bde3bc44c0d766c1fd662",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/2b3802a24e48d0cfccf885173d2aac91e73df92e",
+ "reference": "2b3802a24e48d0cfccf885173d2aac91e73df92e",
"shasum": ""
},
"require": {
"mime-type"
],
"support": {
- "source": "https://github.com/symfony/mime/tree/v5.4.8"
+ "source": "https://github.com/symfony/mime/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-12T15:48:08+00:00"
+ "time": "2022-05-21T10:24:18+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "30885182c981ab175d4d034db0f6f469898070ab"
+ "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
- "reference": "30885182c981ab175d4d034db0f6f469898070ab",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
+ "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-10-20T20:35:02+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-iconv",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git",
- "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40"
+ "reference": "143f1881e655bebca1312722af8068de235ae5dc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f1aed619e28cb077fc83fac8c4c0383578356e40",
- "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40",
+ "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/143f1881e655bebca1312722af8068de235ae5dc",
+ "reference": "143f1881e655bebca1312722af8068de235ae5dc",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-iconv/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-iconv/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-01-04T09:04:05+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "81b86b50cf841a64252b439e738e97f4a34e2783"
+ "reference": "433d05519ce6990bf3530fba6957499d327395c2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783",
- "reference": "81b86b50cf841a64252b439e738e97f4a34e2783",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2",
+ "reference": "433d05519ce6990bf3530fba6957499d327395c2",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-11-23T21:10:46+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
- "reference": "749045c69efb97c70d25d7463abba812e91f3a44"
+ "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44",
- "reference": "749045c69efb97c70d25d7463abba812e91f3a44",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
+ "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-09-14T14:02:44+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8"
+ "reference": "219aa369ceff116e673852dce47c3a41794c14bd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8",
- "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
+ "reference": "219aa369ceff116e673852dce47c3a41794c14bd",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-02-19T12:13:01+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825"
+ "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825",
- "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
+ "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-11-30T18:21:41+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-php72",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
- "reference": "9a142215a36a3888e30d0a9eeea9766764e96976"
+ "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976",
- "reference": "9a142215a36a3888e30d0a9eeea9766764e96976",
+ "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2",
+ "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-05-27T09:17:38+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-php73",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
- "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5"
+ "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5",
- "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5",
+ "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85",
+ "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-06-05T21:20:04+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-php80",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c"
+ "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c",
- "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
+ "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-03-04T08:16:47+00:00"
+ "time": "2022-05-10T07:21:04+00:00"
},
{
"name": "symfony/polyfill-php81",
- "version": "v1.25.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
- "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f"
+ "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
- "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
+ "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1",
+ "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.23-dev"
+ "dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0"
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-09-13T13:58:11+00:00"
+ "time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/process",
},
{
"name": "symfony/string",
- "version": "v5.4.8",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8"
+ "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8",
- "reference": "3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8",
+ "url": "https://api.github.com/repos/symfony/string/zipball/985e6a9703ef5ce32ba617c9c7d97873bb7b2a99",
+ "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99",
"shasum": ""
},
"require": {
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v5.4.8"
+ "source": "https://github.com/symfony/string/tree/v5.4.9"
},
"funding": [
{
},
{
"name": "symfony/translation",
- "version": "v5.4.8",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "f5c0f6d1f20993b2606f3a5f36b1dc8c1899170b"
+ "reference": "1639abc1177d26bcd4320e535e664cef067ab0ca"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/f5c0f6d1f20993b2606f3a5f36b1dc8c1899170b",
- "reference": "f5c0f6d1f20993b2606f3a5f36b1dc8c1899170b",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/1639abc1177d26bcd4320e535e664cef067ab0ca",
+ "reference": "1639abc1177d26bcd4320e535e664cef067ab0ca",
"shasum": ""
},
"require": {
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/translation/tree/v5.4.8"
+ "source": "https://github.com/symfony/translation/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-22T08:14:12+00:00"
+ "time": "2022-05-06T12:33:37+00:00"
},
{
"name": "symfony/translation-contracts",
},
{
"name": "symfony/var-dumper",
- "version": "v5.4.8",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "cdcadd343d31ad16fc5e006b0de81ea307435053"
+ "reference": "af52239a330fafd192c773795520dc2dd62b5657"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/cdcadd343d31ad16fc5e006b0de81ea307435053",
- "reference": "cdcadd343d31ad16fc5e006b0de81ea307435053",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/af52239a330fafd192c773795520dc2dd62b5657",
+ "reference": "af52239a330fafd192c773795520dc2dd62b5657",
"shasum": ""
},
"require": {
"dump"
],
"support": {
- "source": "https://github.com/symfony/var-dumper/tree/v5.4.8"
+ "source": "https://github.com/symfony/var-dumper/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-26T13:19:20+00:00"
+ "time": "2022-05-21T10:24:18+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
},
{
"name": "webmozart/assert",
- "version": "1.10.0",
+ "version": "1.11.0",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
- "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
+ "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
- "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
+ "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
+ "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
"shasum": ""
},
"require": {
- "php": "^7.2 || ^8.0",
- "symfony/polyfill-ctype": "^1.8"
+ "ext-ctype": "*",
+ "php": "^7.2 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
- "source": "https://github.com/webmozarts/assert/tree/1.10.0"
+ "source": "https://github.com/webmozarts/assert/tree/1.11.0"
},
- "time": "2021-03-09T10:59:23+00:00"
+ "time": "2022-06-03T18:03:27+00:00"
}
],
"packages-dev": [
{
"name": "composer/ca-bundle",
- "version": "1.3.1",
+ "version": "1.3.2",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
- "reference": "4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b"
+ "reference": "fd5dd441932a7e10ca6e5b490e272d34c8430640"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/ca-bundle/zipball/4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b",
- "reference": "4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b",
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/fd5dd441932a7e10ca6e5b490e272d34c8430640",
+ "reference": "fd5dd441932a7e10ca6e5b490e272d34c8430640",
"shasum": ""
},
"require": {
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues",
- "source": "https://github.com/composer/ca-bundle/tree/1.3.1"
+ "source": "https://github.com/composer/ca-bundle/tree/1.3.2"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-10-28T20:44:15+00:00"
+ "time": "2022-05-24T11:56:16+00:00"
},
{
"name": "composer/composer",
- "version": "2.3.5",
+ "version": "2.3.7",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
- "reference": "50c47b1f907cfcdb8f072b88164d22b527557ae1"
+ "reference": "10cd375cf85dede2ff417ceab517ef9a0dc55407"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/composer/zipball/50c47b1f907cfcdb8f072b88164d22b527557ae1",
- "reference": "50c47b1f907cfcdb8f072b88164d22b527557ae1",
+ "url": "https://api.github.com/repos/composer/composer/zipball/10cd375cf85dede2ff417ceab517ef9a0dc55407",
+ "reference": "10cd375cf85dede2ff417ceab517ef9a0dc55407",
"shasum": ""
},
"require": {
"react/promise": "^2.8",
"seld/jsonlint": "^1.4",
"seld/phar-utils": "^1.2",
- "symfony/console": "^5.4.1 || ^6.0",
+ "symfony/console": "^5.4.7 || ^6.0.7",
"symfony/filesystem": "^5.4 || ^6.0",
"symfony/finder": "^5.4 || ^6.0",
"symfony/polyfill-php73": "^1.24",
"extra": {
"branch-alias": {
"dev-main": "2.3-dev"
+ },
+ "phpstan": {
+ "includes": [
+ "phpstan/rules.neon"
+ ]
}
},
"autoload": {
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/composer/issues",
- "source": "https://github.com/composer/composer/tree/2.3.5"
+ "source": "https://github.com/composer/composer/tree/2.3.7"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-13T14:43:00+00:00"
+ "time": "2022-06-06T14:43:28+00:00"
},
{
"name": "composer/metadata-minifier",
},
{
"name": "composer/spdx-licenses",
- "version": "1.5.6",
+ "version": "1.5.7",
"source": {
"type": "git",
"url": "https://github.com/composer/spdx-licenses.git",
- "reference": "a30d487169d799745ca7280bc90fdfa693536901"
+ "reference": "c848241796da2abf65837d51dce1fae55a960149"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/a30d487169d799745ca7280bc90fdfa693536901",
- "reference": "a30d487169d799745ca7280bc90fdfa693536901",
+ "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/c848241796da2abf65837d51dce1fae55a960149",
+ "reference": "c848241796da2abf65837d51dce1fae55a960149",
"shasum": ""
},
"require": {
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/spdx-licenses/issues",
- "source": "https://github.com/composer/spdx-licenses/tree/1.5.6"
+ "source": "https://github.com/composer/spdx-licenses/tree/1.5.7"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2021-11-18T10:14:14+00:00"
+ "time": "2022-05-23T07:37:50+00:00"
},
{
"name": "composer/xdebug-handler",
},
{
"name": "phpstan/phpstan",
- "version": "1.6.3",
+ "version": "1.7.12",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "6128620b98292e0b69ea6d799871d77163681c8e"
+ "reference": "32f10779d9cd88a9cbd972ec611a4148a3cbbc7e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6128620b98292e0b69ea6d799871d77163681c8e",
- "reference": "6128620b98292e0b69ea6d799871d77163681c8e",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/32f10779d9cd88a9cbd972ec611a4148a3cbbc7e",
+ "reference": "32f10779d9cd88a9cbd972ec611a4148a3cbbc7e",
"shasum": ""
},
"require": {
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
- "source": "https://github.com/phpstan/phpstan/tree/1.6.3"
+ "source": "https://github.com/phpstan/phpstan/tree/1.7.12"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-28T11:27:53+00:00"
+ "time": "2022-06-09T12:39:36+00:00"
},
{
"name": "phpunit/php-code-coverage",
},
{
"name": "symfony/dom-crawler",
- "version": "v5.4.6",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "c0bda97480d96337bd3866026159a8b358665457"
+ "reference": "a213cbc80382320b0efdccdcdce232f191fafe3a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c0bda97480d96337bd3866026159a8b358665457",
- "reference": "c0bda97480d96337bd3866026159a8b358665457",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/a213cbc80382320b0efdccdcdce232f191fafe3a",
+ "reference": "a213cbc80382320b0efdccdcdce232f191fafe3a",
"shasum": ""
},
"require": {
"description": "Eases DOM navigation for HTML and XML documents",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/dom-crawler/tree/v5.4.6"
+ "source": "https://github.com/symfony/dom-crawler/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-03-02T12:42:23+00:00"
+ "time": "2022-05-04T14:46:32+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v5.4.7",
+ "version": "v5.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f"
+ "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/3a4442138d80c9f7b600fb297534ac718b61d37f",
- "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/36a017fa4cce1eff1b8e8129ff53513abcef05ba",
+ "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba",
"shasum": ""
},
"require": {
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v5.4.7"
+ "source": "https://github.com/symfony/filesystem/tree/v5.4.9"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-04-01T12:33:59+00:00"
+ "time": "2022-05-20T13:55:35+00:00"
},
{
"name": "theseer/tokenizer",
public function definition()
{
return [
- 'display_name' => $this->faker->sentence(3),
- 'description' => $this->faker->sentence(10),
+ 'display_name' => $this->faker->sentence(3),
+ 'description' => $this->faker->sentence(10),
+ 'external_auth_id' => '',
];
}
}
"updated_at": "2019-12-11T20:57:31.000000Z",
"created_by": 1,
"updated_by": 1,
- "owned_by": 1,
- "image_id": 3
+ "owned_by": 1
},
{
"id": 2,
"updated_at": "2019-12-11T20:57:23.000000Z",
"created_by": 4,
"updated_by": 3,
- "owned_by": 3,
- "image_id": 34
+ "owned_by": 3
}
],
"total": 14
"updated_at": "2020-01-12T14:16:10.000000Z",
"created_by": 1,
"updated_by": 1,
- "owned_by": 1,
- "image_id": 452
+ "owned_by": 1
}
\ No newline at end of file
"updated_at": "2020-04-10T13:00:45.000000Z",
"created_by": 4,
"updated_by": 1,
- "owned_by": 1,
- "image_id": 31
+ "owned_by": 1
},
{
"id": 9,
"updated_at": "2020-04-10T13:00:58.000000Z",
"created_by": 4,
"updated_by": 1,
- "owned_by": 1,
- "image_id": 28
+ "owned_by": 1
},
{
"id": 10,
"updated_at": "2020-04-10T13:00:53.000000Z",
"created_by": 4,
"updated_by": 1,
- "owned_by": 4,
- "image_id": 30
+ "owned_by": 4
}
],
"total": 3
"created_by": 1,
"updated_by": 1,
"owned_by": 1,
- "image_id": 501,
"created_at": "2020-04-10T13:24:09.000000Z",
"updated_at": "2020-04-10T13:48:22.000000Z"
}
\ No newline at end of file
"packages": {
"": {
"dependencies": {
- "clipboard": "^2.0.10",
- "codemirror": "^5.65.2",
+ "clipboard": "^2.0.11",
+ "codemirror": "^5.65.5",
"dropzone": "^5.9.3",
- "markdown-it": "^12.3.2",
+ "markdown-it": "^13.0.1",
"markdown-it-task-lists": "^2.1.1",
+ "snabbdom": "^3.5.0",
"sortablejs": "^1.15.0"
},
"devDependencies": {
"chokidar-cli": "^3.0",
- "esbuild": "0.14.36",
+ "esbuild": "0.14.42",
"livereload": "^0.9.3",
"npm-run-all": "^4.1.5",
"punycode": "^2.1.1",
- "sass": "^1.50.0"
+ "sass": "^1.52.1"
}
},
"node_modules/ansi-regex": {
}
},
"node_modules/clipboard": {
- "version": "2.0.10",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.10.tgz",
- "integrity": "sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g==",
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
+ "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
"dependencies": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
}
},
"node_modules/codemirror": {
- "version": "5.65.2",
- "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz",
- "integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA=="
+ "version": "5.65.5",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.5.tgz",
+ "integrity": "sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w=="
},
"node_modules/color-convert": {
"version": "1.9.3",
"dev": true
},
"node_modules/entities": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
- "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "engines": {
+ "node": ">=0.12"
+ },
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
}
},
"node_modules/esbuild": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.36.tgz",
- "integrity": "sha512-HhFHPiRXGYOCRlrhpiVDYKcFJRdO0sBElZ668M4lh2ER0YgnkLxECuFe7uWCf23FrcLc59Pqr7dHkTqmRPDHmw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz",
+ "integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==",
"dev": true,
"hasInstallScript": true,
"bin": {
"node": ">=12"
},
"optionalDependencies": {
- "esbuild-android-64": "0.14.36",
- "esbuild-android-arm64": "0.14.36",
- "esbuild-darwin-64": "0.14.36",
- "esbuild-darwin-arm64": "0.14.36",
- "esbuild-freebsd-64": "0.14.36",
- "esbuild-freebsd-arm64": "0.14.36",
- "esbuild-linux-32": "0.14.36",
- "esbuild-linux-64": "0.14.36",
- "esbuild-linux-arm": "0.14.36",
- "esbuild-linux-arm64": "0.14.36",
- "esbuild-linux-mips64le": "0.14.36",
- "esbuild-linux-ppc64le": "0.14.36",
- "esbuild-linux-riscv64": "0.14.36",
- "esbuild-linux-s390x": "0.14.36",
- "esbuild-netbsd-64": "0.14.36",
- "esbuild-openbsd-64": "0.14.36",
- "esbuild-sunos-64": "0.14.36",
- "esbuild-windows-32": "0.14.36",
- "esbuild-windows-64": "0.14.36",
- "esbuild-windows-arm64": "0.14.36"
+ "esbuild-android-64": "0.14.42",
+ "esbuild-android-arm64": "0.14.42",
+ "esbuild-darwin-64": "0.14.42",
+ "esbuild-darwin-arm64": "0.14.42",
+ "esbuild-freebsd-64": "0.14.42",
+ "esbuild-freebsd-arm64": "0.14.42",
+ "esbuild-linux-32": "0.14.42",
+ "esbuild-linux-64": "0.14.42",
+ "esbuild-linux-arm": "0.14.42",
+ "esbuild-linux-arm64": "0.14.42",
+ "esbuild-linux-mips64le": "0.14.42",
+ "esbuild-linux-ppc64le": "0.14.42",
+ "esbuild-linux-riscv64": "0.14.42",
+ "esbuild-linux-s390x": "0.14.42",
+ "esbuild-netbsd-64": "0.14.42",
+ "esbuild-openbsd-64": "0.14.42",
+ "esbuild-sunos-64": "0.14.42",
+ "esbuild-windows-32": "0.14.42",
+ "esbuild-windows-64": "0.14.42",
+ "esbuild-windows-arm64": "0.14.42"
}
},
"node_modules/esbuild-android-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.36.tgz",
- "integrity": "sha512-jwpBhF1jmo0tVCYC/ORzVN+hyVcNZUWuozGcLHfod0RJCedTDTvR4nwlTXdx1gtncDqjk33itjO+27OZHbiavw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz",
+ "integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==",
"cpu": [
"x64"
],
}
},
"node_modules/esbuild-android-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.36.tgz",
- "integrity": "sha512-/hYkyFe7x7Yapmfv4X/tBmyKnggUmdQmlvZ8ZlBnV4+PjisrEhAvC3yWpURuD9XoB8Wa1d5dGkTsF53pIvpjsg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz",
+ "integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==",
"cpu": [
"arm64"
],
}
},
"node_modules/esbuild-darwin-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.36.tgz",
- "integrity": "sha512-kkl6qmV0dTpyIMKagluzYqlc1vO0ecgpviK/7jwPbRDEv5fejRTaBBEE2KxEQbTHcLhiiDbhG7d5UybZWo/1zQ==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz",
+ "integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==",
"cpu": [
"x64"
],
}
},
"node_modules/esbuild-darwin-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.36.tgz",
- "integrity": "sha512-q8fY4r2Sx6P0Pr3VUm//eFYKVk07C5MHcEinU1BjyFnuYz4IxR/03uBbDwluR6ILIHnZTE7AkTUWIdidRi1Jjw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.42.tgz",
+ "integrity": "sha512-bU2tHRqTPOaoH/4m0zYHbFWpiYDmaA0gt90/3BMEFaM0PqVK/a6MA2V/ypV5PO0v8QxN6gH5hBPY4YJ2lopXgA==",
"cpu": [
"arm64"
],
}
},
"node_modules/esbuild-freebsd-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.36.tgz",
- "integrity": "sha512-Hn8AYuxXXRptybPqoMkga4HRFE7/XmhtlQjXFHoAIhKUPPMeJH35GYEUWGbjteai9FLFvBAjEAlwEtSGxnqWww==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz",
+ "integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==",
"cpu": [
"x64"
],
}
},
"node_modules/esbuild-freebsd-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.36.tgz",
- "integrity": "sha512-S3C0attylLLRiCcHiJd036eDEMOY32+h8P+jJ3kTcfhJANNjP0TNBNL30TZmEdOSx/820HJFgRrqpNAvTbjnDA==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz",
+ "integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==",
"cpu": [
"arm64"
],
}
},
"node_modules/esbuild-linux-32": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.36.tgz",
- "integrity": "sha512-Eh9OkyTrEZn9WGO4xkI3OPPpUX7p/3QYvdG0lL4rfr73Ap2HAr6D9lP59VMF64Ex01LhHSXwIsFG/8AQjh6eNw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz",
+ "integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==",
"cpu": [
"ia32"
],
}
},
"node_modules/esbuild-linux-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.36.tgz",
- "integrity": "sha512-vFVFS5ve7PuwlfgoWNyRccGDi2QTNkQo/2k5U5ttVD0jRFaMlc8UQee708fOZA6zTCDy5RWsT5MJw3sl2X6KDg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.42.tgz",
+ "integrity": "sha512-2L0HbzQfbTuemUWfVqNIjOfaTRt9zsvjnme6lnr7/MO9toz/MJ5tZhjqrG6uDWDxhsaHI2/nsDgrv8uEEN2eoA==",
"cpu": [
"x64"
],
}
},
"node_modules/esbuild-linux-arm": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.36.tgz",
- "integrity": "sha512-NhgU4n+NCsYgt7Hy61PCquEz5aevI6VjQvxwBxtxrooXsxt5b2xtOUXYZe04JxqQo+XZk3d1gcr7pbV9MAQ/Lg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.42.tgz",
+ "integrity": "sha512-STq69yzCMhdRaWnh29UYrLSr/qaWMm/KqwaRF1pMEK7kDiagaXhSL1zQGXbYv94GuGY/zAwzK98+6idCMUOOCg==",
"cpu": [
"arm"
],
}
},
"node_modules/esbuild-linux-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.36.tgz",
- "integrity": "sha512-24Vq1M7FdpSmaTYuu1w0Hdhiqkbto1I5Pjyi+4Cdw5fJKGlwQuw+hWynTcRI/cOZxBcBpP21gND7W27gHAiftw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz",
+ "integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==",
"cpu": [
"arm64"
],
}
},
"node_modules/esbuild-linux-mips64le": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.36.tgz",
- "integrity": "sha512-hZUeTXvppJN+5rEz2EjsOFM9F1bZt7/d2FUM1lmQo//rXh1RTFYzhC0txn7WV0/jCC7SvrGRaRz0NMsRPf8SIA==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz",
+ "integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==",
"cpu": [
"mips64el"
],
}
},
"node_modules/esbuild-linux-ppc64le": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.36.tgz",
- "integrity": "sha512-1Bg3QgzZjO+QtPhP9VeIBhAduHEc2kzU43MzBnMwpLSZ890azr4/A9Dganun8nsqD/1TBcqhId0z4mFDO8FAvg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.42.tgz",
+ "integrity": "sha512-8ohIVIWDbDT+i7lCx44YCyIRrOW1MYlks9fxTo0ME2LS/fxxdoJBwHWzaDYhjvf8kNpA+MInZvyOEAGoVDrMHg==",
"cpu": [
"ppc64"
],
}
},
"node_modules/esbuild-linux-riscv64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.36.tgz",
- "integrity": "sha512-dOE5pt3cOdqEhaufDRzNCHf5BSwxgygVak9UR7PH7KPVHwSTDAZHDoEjblxLqjJYpc5XaU9+gKJ9F8mp9r5I4A==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz",
+ "integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==",
"cpu": [
"riscv64"
],
}
},
"node_modules/esbuild-linux-s390x": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.36.tgz",
- "integrity": "sha512-g4FMdh//BBGTfVHjF6MO7Cz8gqRoDPzXWxRvWkJoGroKA18G9m0wddvPbEqcQf5Tbt2vSc1CIgag7cXwTmoTXg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.42.tgz",
+ "integrity": "sha512-YFRhPCxl8nb//Wn6SiS5pmtplBi4z9yC2gLrYoYI/tvwuB1jldir9r7JwAGy1Ck4D7sE7wBN9GFtUUX/DLdcEQ==",
"cpu": [
"s390x"
],
}
},
"node_modules/esbuild-netbsd-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.36.tgz",
- "integrity": "sha512-UB2bVImxkWk4vjnP62ehFNZ73lQY1xcnL5ZNYF3x0AG+j8HgdkNF05v67YJdCIuUJpBuTyCK8LORCYo9onSW+A==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.42.tgz",
+ "integrity": "sha512-QYSD2k+oT9dqB/4eEM9c+7KyNYsIPgzYOSrmfNGDIyJrbT1d+CFVKvnKahDKNJLfOYj8N4MgyFaU9/Ytc6w5Vw==",
"cpu": [
"x64"
],
}
},
"node_modules/esbuild-openbsd-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.36.tgz",
- "integrity": "sha512-NvGB2Chf8GxuleXRGk8e9zD3aSdRO5kLt9coTQbCg7WMGXeX471sBgh4kSg8pjx0yTXRt0MlrUDnjVYnetyivg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.42.tgz",
+ "integrity": "sha512-M2meNVIKWsm2HMY7+TU9AxM7ZVwI9havdsw6m/6EzdXysyCFFSoaTQ/Jg03izjCsK17FsVRHqRe26Llj6x0MNA==",
"cpu": [
"x64"
],
}
},
"node_modules/esbuild-sunos-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.36.tgz",
- "integrity": "sha512-VkUZS5ftTSjhRjuRLp+v78auMO3PZBXu6xl4ajomGenEm2/rGuWlhFSjB7YbBNErOchj51Jb2OK8lKAo8qdmsQ==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.42.tgz",
+ "integrity": "sha512-uXV8TAZEw36DkgW8Ak3MpSJs1ofBb3Smkc/6pZ29sCAN1KzCAQzsje4sUwugf+FVicrHvlamCOlFZIXgct+iqQ==",
"cpu": [
"x64"
],
}
},
"node_modules/esbuild-windows-32": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.36.tgz",
- "integrity": "sha512-bIar+A6hdytJjZrDxfMBUSEHHLfx3ynoEZXx/39nxy86pX/w249WZm8Bm0dtOAByAf4Z6qV0LsnTIJHiIqbw0w==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz",
+ "integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==",
"cpu": [
"ia32"
],
}
},
"node_modules/esbuild-windows-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.36.tgz",
- "integrity": "sha512-+p4MuRZekVChAeueT1Y9LGkxrT5x7YYJxYE8ZOTcEfeUUN43vktSn6hUNsvxzzATrSgq5QqRdllkVBxWZg7KqQ==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.42.tgz",
+ "integrity": "sha512-j3cdK+Y3+a5H0wHKmLGTJcq0+/2mMBHPWkItR3vytp/aUGD/ua/t2BLdfBIzbNN9nLCRL9sywCRpOpFMx3CxzA==",
"cpu": [
"x64"
],
}
},
"node_modules/esbuild-windows-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.36.tgz",
- "integrity": "sha512-fBB4WlDqV1m18EF/aheGYQkQZHfPHiHJSBYzXIo8yKehek+0BtBwo/4PNwKGJ5T0YK0oc8pBKjgwPbzSrPLb+Q==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.42.tgz",
+ "integrity": "sha512-+lRAARnF+hf8J0mN27ujO+VbhPbDqJ8rCcJKye4y7YZLV6C4n3pTRThAb388k/zqF5uM0lS5O201u0OqoWSicw==",
"cpu": [
"arm64"
],
"dev": true
},
"node_modules/linkify-it": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
- "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
+ "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"dependencies": {
"uc.micro": "^1.0.1"
}
"dev": true
},
"node_modules/markdown-it": {
- "version": "12.3.2",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
- "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+ "version": "13.0.1",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
+ "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"dependencies": {
"argparse": "^2.0.1",
- "entities": "~2.1.0",
- "linkify-it": "^3.0.1",
+ "entities": "~3.0.1",
+ "linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
}
},
"node_modules/sass": {
- "version": "1.50.0",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz",
- "integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==",
+ "version": "1.52.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz",
+ "integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/snabbdom": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz",
+ "integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g==",
+ "engines": {
+ "node": ">=8.3.0"
+ }
+ },
"node_modules/sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
}
},
"clipboard": {
- "version": "2.0.10",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.10.tgz",
- "integrity": "sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g==",
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
+ "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
}
},
"codemirror": {
- "version": "5.65.2",
- "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz",
- "integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA=="
+ "version": "5.65.5",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.5.tgz",
+ "integrity": "sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w=="
},
"color-convert": {
"version": "1.9.3",
"dev": true
},
"entities": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
- "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
},
"error-ex": {
"version": "1.3.2",
}
},
"esbuild": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.36.tgz",
- "integrity": "sha512-HhFHPiRXGYOCRlrhpiVDYKcFJRdO0sBElZ668M4lh2ER0YgnkLxECuFe7uWCf23FrcLc59Pqr7dHkTqmRPDHmw==",
- "dev": true,
- "requires": {
- "esbuild-android-64": "0.14.36",
- "esbuild-android-arm64": "0.14.36",
- "esbuild-darwin-64": "0.14.36",
- "esbuild-darwin-arm64": "0.14.36",
- "esbuild-freebsd-64": "0.14.36",
- "esbuild-freebsd-arm64": "0.14.36",
- "esbuild-linux-32": "0.14.36",
- "esbuild-linux-64": "0.14.36",
- "esbuild-linux-arm": "0.14.36",
- "esbuild-linux-arm64": "0.14.36",
- "esbuild-linux-mips64le": "0.14.36",
- "esbuild-linux-ppc64le": "0.14.36",
- "esbuild-linux-riscv64": "0.14.36",
- "esbuild-linux-s390x": "0.14.36",
- "esbuild-netbsd-64": "0.14.36",
- "esbuild-openbsd-64": "0.14.36",
- "esbuild-sunos-64": "0.14.36",
- "esbuild-windows-32": "0.14.36",
- "esbuild-windows-64": "0.14.36",
- "esbuild-windows-arm64": "0.14.36"
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz",
+ "integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==",
+ "dev": true,
+ "requires": {
+ "esbuild-android-64": "0.14.42",
+ "esbuild-android-arm64": "0.14.42",
+ "esbuild-darwin-64": "0.14.42",
+ "esbuild-darwin-arm64": "0.14.42",
+ "esbuild-freebsd-64": "0.14.42",
+ "esbuild-freebsd-arm64": "0.14.42",
+ "esbuild-linux-32": "0.14.42",
+ "esbuild-linux-64": "0.14.42",
+ "esbuild-linux-arm": "0.14.42",
+ "esbuild-linux-arm64": "0.14.42",
+ "esbuild-linux-mips64le": "0.14.42",
+ "esbuild-linux-ppc64le": "0.14.42",
+ "esbuild-linux-riscv64": "0.14.42",
+ "esbuild-linux-s390x": "0.14.42",
+ "esbuild-netbsd-64": "0.14.42",
+ "esbuild-openbsd-64": "0.14.42",
+ "esbuild-sunos-64": "0.14.42",
+ "esbuild-windows-32": "0.14.42",
+ "esbuild-windows-64": "0.14.42",
+ "esbuild-windows-arm64": "0.14.42"
}
},
"esbuild-android-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.36.tgz",
- "integrity": "sha512-jwpBhF1jmo0tVCYC/ORzVN+hyVcNZUWuozGcLHfod0RJCedTDTvR4nwlTXdx1gtncDqjk33itjO+27OZHbiavw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz",
+ "integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==",
"dev": true,
"optional": true
},
"esbuild-android-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.36.tgz",
- "integrity": "sha512-/hYkyFe7x7Yapmfv4X/tBmyKnggUmdQmlvZ8ZlBnV4+PjisrEhAvC3yWpURuD9XoB8Wa1d5dGkTsF53pIvpjsg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz",
+ "integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==",
"dev": true,
"optional": true
},
"esbuild-darwin-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.36.tgz",
- "integrity": "sha512-kkl6qmV0dTpyIMKagluzYqlc1vO0ecgpviK/7jwPbRDEv5fejRTaBBEE2KxEQbTHcLhiiDbhG7d5UybZWo/1zQ==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz",
+ "integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==",
"dev": true,
"optional": true
},
"esbuild-darwin-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.36.tgz",
- "integrity": "sha512-q8fY4r2Sx6P0Pr3VUm//eFYKVk07C5MHcEinU1BjyFnuYz4IxR/03uBbDwluR6ILIHnZTE7AkTUWIdidRi1Jjw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.42.tgz",
+ "integrity": "sha512-bU2tHRqTPOaoH/4m0zYHbFWpiYDmaA0gt90/3BMEFaM0PqVK/a6MA2V/ypV5PO0v8QxN6gH5hBPY4YJ2lopXgA==",
"dev": true,
"optional": true
},
"esbuild-freebsd-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.36.tgz",
- "integrity": "sha512-Hn8AYuxXXRptybPqoMkga4HRFE7/XmhtlQjXFHoAIhKUPPMeJH35GYEUWGbjteai9FLFvBAjEAlwEtSGxnqWww==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz",
+ "integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==",
"dev": true,
"optional": true
},
"esbuild-freebsd-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.36.tgz",
- "integrity": "sha512-S3C0attylLLRiCcHiJd036eDEMOY32+h8P+jJ3kTcfhJANNjP0TNBNL30TZmEdOSx/820HJFgRrqpNAvTbjnDA==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz",
+ "integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==",
"dev": true,
"optional": true
},
"esbuild-linux-32": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.36.tgz",
- "integrity": "sha512-Eh9OkyTrEZn9WGO4xkI3OPPpUX7p/3QYvdG0lL4rfr73Ap2HAr6D9lP59VMF64Ex01LhHSXwIsFG/8AQjh6eNw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz",
+ "integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==",
"dev": true,
"optional": true
},
"esbuild-linux-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.36.tgz",
- "integrity": "sha512-vFVFS5ve7PuwlfgoWNyRccGDi2QTNkQo/2k5U5ttVD0jRFaMlc8UQee708fOZA6zTCDy5RWsT5MJw3sl2X6KDg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.42.tgz",
+ "integrity": "sha512-2L0HbzQfbTuemUWfVqNIjOfaTRt9zsvjnme6lnr7/MO9toz/MJ5tZhjqrG6uDWDxhsaHI2/nsDgrv8uEEN2eoA==",
"dev": true,
"optional": true
},
"esbuild-linux-arm": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.36.tgz",
- "integrity": "sha512-NhgU4n+NCsYgt7Hy61PCquEz5aevI6VjQvxwBxtxrooXsxt5b2xtOUXYZe04JxqQo+XZk3d1gcr7pbV9MAQ/Lg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.42.tgz",
+ "integrity": "sha512-STq69yzCMhdRaWnh29UYrLSr/qaWMm/KqwaRF1pMEK7kDiagaXhSL1zQGXbYv94GuGY/zAwzK98+6idCMUOOCg==",
"dev": true,
"optional": true
},
"esbuild-linux-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.36.tgz",
- "integrity": "sha512-24Vq1M7FdpSmaTYuu1w0Hdhiqkbto1I5Pjyi+4Cdw5fJKGlwQuw+hWynTcRI/cOZxBcBpP21gND7W27gHAiftw==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz",
+ "integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==",
"dev": true,
"optional": true
},
"esbuild-linux-mips64le": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.36.tgz",
- "integrity": "sha512-hZUeTXvppJN+5rEz2EjsOFM9F1bZt7/d2FUM1lmQo//rXh1RTFYzhC0txn7WV0/jCC7SvrGRaRz0NMsRPf8SIA==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz",
+ "integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==",
"dev": true,
"optional": true
},
"esbuild-linux-ppc64le": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.36.tgz",
- "integrity": "sha512-1Bg3QgzZjO+QtPhP9VeIBhAduHEc2kzU43MzBnMwpLSZ890azr4/A9Dganun8nsqD/1TBcqhId0z4mFDO8FAvg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.42.tgz",
+ "integrity": "sha512-8ohIVIWDbDT+i7lCx44YCyIRrOW1MYlks9fxTo0ME2LS/fxxdoJBwHWzaDYhjvf8kNpA+MInZvyOEAGoVDrMHg==",
"dev": true,
"optional": true
},
"esbuild-linux-riscv64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.36.tgz",
- "integrity": "sha512-dOE5pt3cOdqEhaufDRzNCHf5BSwxgygVak9UR7PH7KPVHwSTDAZHDoEjblxLqjJYpc5XaU9+gKJ9F8mp9r5I4A==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz",
+ "integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==",
"dev": true,
"optional": true
},
"esbuild-linux-s390x": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.36.tgz",
- "integrity": "sha512-g4FMdh//BBGTfVHjF6MO7Cz8gqRoDPzXWxRvWkJoGroKA18G9m0wddvPbEqcQf5Tbt2vSc1CIgag7cXwTmoTXg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.42.tgz",
+ "integrity": "sha512-YFRhPCxl8nb//Wn6SiS5pmtplBi4z9yC2gLrYoYI/tvwuB1jldir9r7JwAGy1Ck4D7sE7wBN9GFtUUX/DLdcEQ==",
"dev": true,
"optional": true
},
"esbuild-netbsd-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.36.tgz",
- "integrity": "sha512-UB2bVImxkWk4vjnP62ehFNZ73lQY1xcnL5ZNYF3x0AG+j8HgdkNF05v67YJdCIuUJpBuTyCK8LORCYo9onSW+A==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.42.tgz",
+ "integrity": "sha512-QYSD2k+oT9dqB/4eEM9c+7KyNYsIPgzYOSrmfNGDIyJrbT1d+CFVKvnKahDKNJLfOYj8N4MgyFaU9/Ytc6w5Vw==",
"dev": true,
"optional": true
},
"esbuild-openbsd-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.36.tgz",
- "integrity": "sha512-NvGB2Chf8GxuleXRGk8e9zD3aSdRO5kLt9coTQbCg7WMGXeX471sBgh4kSg8pjx0yTXRt0MlrUDnjVYnetyivg==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.42.tgz",
+ "integrity": "sha512-M2meNVIKWsm2HMY7+TU9AxM7ZVwI9havdsw6m/6EzdXysyCFFSoaTQ/Jg03izjCsK17FsVRHqRe26Llj6x0MNA==",
"dev": true,
"optional": true
},
"esbuild-sunos-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.36.tgz",
- "integrity": "sha512-VkUZS5ftTSjhRjuRLp+v78auMO3PZBXu6xl4ajomGenEm2/rGuWlhFSjB7YbBNErOchj51Jb2OK8lKAo8qdmsQ==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.42.tgz",
+ "integrity": "sha512-uXV8TAZEw36DkgW8Ak3MpSJs1ofBb3Smkc/6pZ29sCAN1KzCAQzsje4sUwugf+FVicrHvlamCOlFZIXgct+iqQ==",
"dev": true,
"optional": true
},
"esbuild-windows-32": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.36.tgz",
- "integrity": "sha512-bIar+A6hdytJjZrDxfMBUSEHHLfx3ynoEZXx/39nxy86pX/w249WZm8Bm0dtOAByAf4Z6qV0LsnTIJHiIqbw0w==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz",
+ "integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==",
"dev": true,
"optional": true
},
"esbuild-windows-64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.36.tgz",
- "integrity": "sha512-+p4MuRZekVChAeueT1Y9LGkxrT5x7YYJxYE8ZOTcEfeUUN43vktSn6hUNsvxzzATrSgq5QqRdllkVBxWZg7KqQ==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.42.tgz",
+ "integrity": "sha512-j3cdK+Y3+a5H0wHKmLGTJcq0+/2mMBHPWkItR3vytp/aUGD/ua/t2BLdfBIzbNN9nLCRL9sywCRpOpFMx3CxzA==",
"dev": true,
"optional": true
},
"esbuild-windows-arm64": {
- "version": "0.14.36",
- "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.36.tgz",
- "integrity": "sha512-fBB4WlDqV1m18EF/aheGYQkQZHfPHiHJSBYzXIo8yKehek+0BtBwo/4PNwKGJ5T0YK0oc8pBKjgwPbzSrPLb+Q==",
+ "version": "0.14.42",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.42.tgz",
+ "integrity": "sha512-+lRAARnF+hf8J0mN27ujO+VbhPbDqJ8rCcJKye4y7YZLV6C4n3pTRThAb388k/zqF5uM0lS5O201u0OqoWSicw==",
"dev": true,
"optional": true
},
"dev": true
},
"linkify-it": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
- "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
+ "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"requires": {
"uc.micro": "^1.0.1"
}
"dev": true
},
"markdown-it": {
- "version": "12.3.2",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
- "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+ "version": "13.0.1",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
+ "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"requires": {
"argparse": "^2.0.1",
- "entities": "~2.1.0",
- "linkify-it": "^3.0.1",
+ "entities": "~3.0.1",
+ "linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
}
}
},
"sass": {
- "version": "1.50.0",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz",
- "integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==",
+ "version": "1.52.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz",
+ "integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==",
"dev": true,
"requires": {
"chokidar": ">=3.0.0 <4.0.0",
"object-inspect": "^1.9.0"
}
},
+ "snabbdom": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz",
+ "integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g=="
+ },
"sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
{
"private": true,
"scripts": {
- "build:css:dev": "sass ./resources/sass:./public/dist",
- "build:css:watch": "sass ./resources/sass:./public/dist --watch",
+ "build:css:dev": "sass ./resources/sass:./public/dist --embed-sources",
+ "build:css:watch": "sass ./resources/sass:./public/dist --watch --embed-sources",
"build:css:production": "sass ./resources/sass:./public/dist -s compressed",
"build:js:dev": "node dev/build/esbuild.js",
"build:js:watch": "chokidar --initial \"./resources/**/*.js\" -c \"npm run build:js:dev\"",
},
"devDependencies": {
"chokidar-cli": "^3.0",
- "esbuild": "0.14.36",
+ "esbuild": "0.14.42",
"livereload": "^0.9.3",
"npm-run-all": "^4.1.5",
"punycode": "^2.1.1",
- "sass": "^1.50.0"
+ "sass": "^1.52.1"
},
"dependencies": {
- "clipboard": "^2.0.10",
- "codemirror": "^5.65.2",
+ "clipboard": "^2.0.11",
+ "codemirror": "^5.65.5",
"dropzone": "^5.9.3",
- "markdown-it": "^12.3.2",
+ "markdown-it": "^13.0.1",
"markdown-it-task-lists": "^2.1.1",
+ "snabbdom": "^3.5.0",
"sortablejs": "^1.15.0"
}
}
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16.59 9H15V4c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v5H7.41c-.89 0-1.34 1.08-.71 1.71l4.59 4.59c.39.39 1.02.39 1.41 0l4.59-4.59c.63-.63.19-1.71-.7-1.71zM5 19c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H6c-.55 0-1 .45-1 1z"/></svg>
\ No newline at end of file
import 'codemirror/mode/rust/rust';
import 'codemirror/mode/shell/shell';
import 'codemirror/mode/sql/sql';
+import 'codemirror/mode/stex/stex';
import 'codemirror/mode/toml/toml';
import 'codemirror/mode/vb/vb';
import 'codemirror/mode/vbscript/vbscript';
diff: 'diff',
for: 'fortran',
fortran: 'fortran',
+ 'f#': 'text/x-fsharp',
+ fsharp: 'text/x-fsharp',
go: 'go',
haskell: 'haskell',
hs: 'haskell',
html: 'htmlmixed',
ini: 'properties',
- javascript: 'javascript',
- json: {name: 'javascript', json: true},
- js: 'javascript',
- jl: 'julia',
- julia: 'julia',
+ javascript: 'text/javascript',
+ json: 'application/json',
+ js: 'text/javascript',
+ jl: 'text/x-julia',
+ julia: 'text/x-julia',
+ latex: 'text/x-stex',
lua: 'lua',
md: 'markdown',
mdown: 'markdown',
pl: 'perl',
powershell: 'powershell',
properties: 'properties',
- ocaml: 'mllike',
+ ocaml: 'text/x-ocaml',
pascal: 'text/x-pascal',
pas: 'text/x-pascal',
php: (content) => {
rs: 'rust',
shell: 'shell',
sh: 'shell',
+ stext: 'text/x-stex',
bash: 'shell',
toml: 'toml',
+ ts: 'text/typescript',
+ typescript: 'text/typescript',
sql: 'text/x-sql',
vbs: 'vbscript',
vbscript: 'vbscript',
});
}
+/**
+ * Create an inline editor to replace the given textarea.
+ * @param {HTMLTextAreaElement} textArea
+ * @param {String} mode
+ * @returns {CodeMirror3}
+ */
+export function inlineEditor(textArea, mode) {
+ return CodeMirror.fromTextArea(textArea, {
+ mode: getMode(mode, textArea.value),
+ lineNumbers: true,
+ lineWrapping: false,
+ theme: getTheme(),
+ });
+}
+
/**
* Set the mode of a codemirror instance.
* @param cmInstance
--- /dev/null
+import {slideUp, slideDown} from "../services/animations";
+
+/**
+ * @extends {Component}
+ */
+class ChapterContents {
+
+ setup() {
+ this.list = this.$refs.list;
+ this.toggle = this.$refs.toggle;
+
+ this.isOpen = this.toggle.classList.contains('open');
+ this.toggle.addEventListener('click', this.click.bind(this));
+ }
+
+ open() {
+ this.toggle.classList.add('open');
+ this.toggle.setAttribute('aria-expanded', 'true');
+ slideDown(this.list, 180);
+ this.isOpen = true;
+ }
+
+ close() {
+ this.toggle.classList.remove('open');
+ this.toggle.setAttribute('aria-expanded', 'false');
+ slideUp(this.list, 180);
+ this.isOpen = false;
+ }
+
+ click(event) {
+ event.preventDefault();
+ this.isOpen ? this.close() : this.open();
+ }
+
+}
+
+export default ChapterContents;
+++ /dev/null
-import {slideUp, slideDown} from "../services/animations";
-
-class ChapterToggle {
-
- constructor(elem) {
- this.elem = elem;
- this.isOpen = elem.classList.contains('open');
- elem.addEventListener('click', this.click.bind(this));
- }
-
- open() {
- const list = this.elem.parentNode.querySelector('.inset-list');
- this.elem.classList.add('open');
- this.elem.setAttribute('aria-expanded', 'true');
- slideDown(list, 240);
- }
-
- close() {
- const list = this.elem.parentNode.querySelector('.inset-list');
- this.elem.classList.remove('open');
- this.elem.setAttribute('aria-expanded', 'false');
- slideUp(list, 240);
- }
-
- click(event) {
- event.preventDefault();
- this.isOpen ? this.close() : this.open();
- this.isOpen = !this.isOpen;
- }
-
-}
-
-export default ChapterToggle;
onSelect(this.languageLinks, event => {
const language = event.target.dataset.lang;
this.languageInput.value = language;
- this.updateEditorMode(language);
+ this.languageInputChange(language);
});
onEnterPress(this.languageInput, e => this.save());
+ this.languageInput.addEventListener('input', e => this.languageInputChange(this.languageInput.value));
onSelect(this.saveButton, e => this.save());
onChildEvent(this.historyList, 'button', 'click', (event, elem) => {
this.callback = callback;
this.show()
- .then(() => this.updateEditorMode(language))
+ .then(() => this.languageInputChange(language))
.then(() => window.importVersioned('code'))
.then(Code => Code.setContent(this.editor, code));
}
Code.setMode(this.editor, language, this.editor.getValue());
}
+ languageInputChange(language) {
+ this.updateEditorMode(language);
+ const inputLang = language.toLowerCase();
+ let matched = false;
+
+ for (const link of this.languageLinks) {
+ const lang = link.dataset.lang.toLowerCase().trim();
+ const isMatch = inputLang && lang.startsWith(inputLang);
+ link.classList.toggle('active', isMatch);
+ if (isMatch && !matched) {
+ link.scrollIntoView({block: "center", behavior: "smooth"});
+ matched = true;
+ }
+ }
+ }
+
loadHistory() {
this.history = JSON.parse(window.sessionStorage.getItem(this.historyKey) || '{}');
const historyKeys = Object.keys(this.history).reverse();
--- /dev/null
+/**
+ * A simple component to render a code editor within the textarea
+ * this exists upon.
+ * @extends {Component}
+ */
+class CodeTextarea {
+
+ async setup() {
+ const mode = this.$opts.mode;
+ const Code = await window.importVersioned('code');
+ Code.inlineEditor(this.$el, mode);
+ }
+
+}
+
+export default CodeTextarea;
\ No newline at end of file
import {debounce} from "../services/util";
+import {transitionHeight} from "../services/animations";
class DropdownSearch {
try {
const resp = await window.$http.get(this.getAjaxUrl(searchTerm));
+ const animate = transitionHeight(this.listContainerElem, 80);
this.listContainerElem.innerHTML = resp.data;
+ animate();
} catch (err) {
console.error(err);
}
this.menu.classList.add('anim', 'menuIn');
this.toggle.setAttribute('aria-expanded', 'true');
+ const menuOriginalRect = this.menu.getBoundingClientRect();
+ let heightOffset = 0;
+ const toggleHeight = this.toggle.getBoundingClientRect().height;
+ const dropUpwards = menuOriginalRect.bottom > window.innerHeight;
+
+ // If enabled, Move to body to prevent being trapped within scrollable sections
if (this.moveMenu) {
- // Move to body to prevent being trapped within scrollable sections
- this.rect = this.menu.getBoundingClientRect();
this.body.appendChild(this.menu);
this.menu.style.position = 'fixed';
if (this.direction === 'right') {
- this.menu.style.right = `${(this.rect.right - this.rect.width)}px`;
+ this.menu.style.right = `${(menuOriginalRect.right - menuOriginalRect.width)}px`;
} else {
- this.menu.style.left = `${this.rect.left}px`;
+ this.menu.style.left = `${menuOriginalRect.left}px`;
}
- this.menu.style.top = `${this.rect.top}px`;
- this.menu.style.width = `${this.rect.width}px`;
+ this.menu.style.width = `${menuOriginalRect.width}px`;
+ heightOffset = dropUpwards ? (window.innerHeight - menuOriginalRect.top - toggleHeight / 2) : menuOriginalRect.top;
+ }
+
+ // Adjust menu to display upwards if near the bottom of the screen
+ if (dropUpwards) {
+ this.menu.style.top = 'initial';
+ this.menu.style.bottom = `${heightOffset}px`;
+ } else {
+ this.menu.style.top = `${heightOffset}px`;
+ this.menu.style.bottom = 'initial';
}
// Set listener to hide on mouse leave or window click
this.menu.style.display = 'none';
this.menu.classList.remove('anim', 'menuIn');
this.toggle.setAttribute('aria-expanded', 'false');
+ this.menu.style.top = '';
+ this.menu.style.bottom = '';
+
if (this.moveMenu) {
this.menu.style.position = '';
this.menu.style[this.direction] = '';
- this.menu.style.top = '';
this.menu.style.width = '';
this.container.appendChild(this.menu);
}
+
this.showing = false;
}
getFocusable() {
- return Array.from(this.menu.querySelectorAll('[tabindex],[href],button,input:not([type=hidden])'));
+ return Array.from(this.menu.querySelectorAll('[tabindex]:not([tabindex="-1"]),[href],button,input:not([type=hidden])'));
}
focusNext() {
import autoSuggest from "./auto-suggest.js"
import backToTop from "./back-to-top.js"
import bookSort from "./book-sort.js"
-import chapterToggle from "./chapter-toggle.js"
+import chapterContents from "./chapter-contents.js"
import codeEditor from "./code-editor.js"
import codeHighlighter from "./code-highlighter.js"
+import codeTextarea from "./code-textarea.js"
import collapsible from "./collapsible.js"
import confirmDialog from "./confirm-dialog"
import customCheckbox from "./custom-checkbox.js"
"auto-suggest": autoSuggest,
"back-to-top": backToTop,
"book-sort": bookSort,
- "chapter-toggle": chapterToggle,
+ "chapter-contents": chapterContents,
"code-editor": codeEditor,
"code-highlighter": codeHighlighter,
+ "code-textarea": codeTextarea,
"collapsible": collapsible,
"confirm-dialog": confirmDialog,
"custom-checkbox": customCheckbox,
import mdTasksLists from 'markdown-it-task-lists';
import Clipboard from "../services/clipboard";
import {debounce} from "../services/util";
-
+import {patchDomFromHtmlString} from "../services/vdom";
import DrawIO from "../services/drawio";
class MarkdownEditor {
updateAndRender() {
const content = this.cm.getValue();
this.input.value = content;
+
const html = this.markdown.render(content);
window.$events.emit('editor-html-change', html);
window.$events.emit('editor-markdown-change', content);
// Set body content
+ const target = this.getDisplayTarget();
this.displayDoc.body.className = 'page-content';
- this.displayDoc.body.innerHTML = html;
+ patchDomFromHtmlString(target, html);
// Copy styles from page head and set custom styles for editor
this.loadStylesIntoDisplay();
}
+ getDisplayTarget() {
+ const body = this.displayDoc.body;
+
+ if (body.children.length === 0) {
+ const wrap = document.createElement('div');
+ this.displayDoc.body.append(wrap);
+ }
+
+ return body.children[0];
+ }
+
loadStylesIntoDisplay() {
if (this.displayStylesLoaded) return;
this.displayDoc.documentElement.classList.add('markdown-editor-display');
const currentPaddingTop = computedStyles.getPropertyValue('padding-top');
const currentPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
const animStyles = {
- height: [`${currentHeight}px`, '0px'],
+ maxHeight: [`${currentHeight}px`, '0px'],
overflow: ['hidden', 'hidden'],
paddingTop: [currentPaddingTop, '0px'],
paddingBottom: [currentPaddingBottom, '0px'],
const targetPaddingTop = computedStyles.getPropertyValue('padding-top');
const targetPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
const animStyles = {
- height: ['0px', `${targetHeight}px`],
+ maxHeight: ['0px', `${targetHeight}px`],
overflow: ['hidden', 'hidden'],
paddingTop: ['0px', targetPaddingTop],
paddingBottom: ['0px', targetPaddingBottom],
animateStyles(element, animStyles, animTime);
}
+/**
+ * Transition the height of the given element between two states.
+ * Call with first state, and you'll receive a function in return.
+ * Call the returned function in the second state to animate between those two states.
+ * If animating to/from 0-height use the slide-up/slide down as easier alternatives.
+ * @param {Element} element - Element to animate
+ * @param {Number} animTime - Animation time in ms
+ * @returns {function} - Function to run in second state to trigger animation.
+ */
+export function transitionHeight(element, animTime = 400) {
+ const startHeight = element.getBoundingClientRect().height;
+ const initialComputedStyles = getComputedStyle(element);
+ const startPaddingTop = initialComputedStyles.getPropertyValue('padding-top');
+ const startPaddingBottom = initialComputedStyles.getPropertyValue('padding-bottom');
+
+ return () => {
+ cleanupExistingElementAnimation(element);
+ const targetHeight = element.getBoundingClientRect().height;
+ const computedStyles = getComputedStyle(element);
+ const targetPaddingTop = computedStyles.getPropertyValue('padding-top');
+ const targetPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
+ const animStyles = {
+ height: [`${startHeight}px`, `${targetHeight}px`],
+ overflow: ['hidden', 'hidden'],
+ paddingTop: [startPaddingTop, targetPaddingTop],
+ paddingBottom: [startPaddingBottom, targetPaddingBottom],
+ };
+
+ animateStyles(element, animStyles, animTime);
+ };
+}
+
/**
* Animate the css styles of an element using FLIP animation techniques.
* Styles must be an object where the keys are style properties, camelcase, and the values
--- /dev/null
+import {
+ init,
+ attributesModule,
+ toVNode
+} from "snabbdom";
+
+let patcher;
+
+/**
+ * @returns {Function}
+ */
+function getPatcher() {
+ if (patcher) return patcher;
+
+
+ patcher = init([
+ attributesModule,
+ ]);
+
+ return patcher;
+}
+
+/**
+ * @param {Element} domTarget
+ * @param {String} html
+ */
+export function patchDomFromHtmlString(domTarget, html) {
+ const contentDom = document.createElement('div');
+ contentDom.innerHTML = html;
+ getPatcher()(toVNode(domTarget), toVNode(contentDom));
+}
\ No newline at end of file
throw new Error(`Not an image file`);
}
- let ext = 'png';
- if (file.name) {
- let fileNameMatches = file.name.match(/\.(.+)$/);
- if (fileNameMatches.length > 1) ext = fileNameMatches[1];
- }
-
- const remoteFilename = "image-" + Date.now() + "." + ext;
+ const remoteFilename = file.name || `image-${Date.now()}.png`;
const formData = new FormData();
formData.append('file', file, remoteFilename);
formData.append('uploaded_to', pageId);
getContent() {
const code = this.querySelector('code') || this.querySelector('pre');
const tempEl = document.createElement('pre');
- tempEl.innerHTML = code.innerHTML.replace().replace(/<br\s*[\/]?>/gi ,'\n').replace(/\ufeff/g, '');
+ tempEl.innerHTML = code.innerHTML.replace(/\ufeff/g, '');
+
+ const brs = tempEl.querySelectorAll('br');
+ for (const br of brs) {
+ br.replaceWith('\n');
+ }
+
return tempEl.textContent;
}
const container = this.shadowRoot.querySelector('.CodeMirrorContainer');
const renderCodeMirror = (Code) => {
+ console.log({content});
this.cm = Code.wysiwygView(container, content, this.getLanguage());
Code.updateLayout(this.cm);
setTimeout(() => {
showPopup(editor, textContent, '', (newCode, newLang) => {
const pre = doc.createElement('pre');
const code = doc.createElement('code');
+ console.log(newCode);
code.classList.add(`language-${newLang}`);
code.innerText = newCode;
pre.append(code);
// Pages
'page_create' => 'تم إنشاء صفحة',
- 'page_create_notification' => 'Page successfully created',
+ 'page_create_notification' => 'تم إنشاء الصفحة بنجاح',
'page_update' => 'تم تحديث الصفحة',
- 'page_update_notification' => 'Page successfully updated',
+ 'page_update_notification' => 'تم تحديث الصفحة بنجاح',
'page_delete' => 'تم حذف الصفحة',
- 'page_delete_notification' => 'Page successfully deleted',
+ 'page_delete_notification' => 'تم حذف الصفحة بنجاح',
'page_restore' => 'تمت استعادة الصفحة',
- 'page_restore_notification' => 'Page successfully restored',
+ 'page_restore_notification' => 'تمت استعادة الصفحة بنجاح',
'page_move' => 'تم نقل الصفحة',
// Chapters
'chapter_create' => 'تم إنشاء فصل',
- 'chapter_create_notification' => 'Chapter successfully created',
+ 'chapter_create_notification' => 'تم إنشاء الفصل بنجاح',
'chapter_update' => 'تم تحديث الفصل',
- 'chapter_update_notification' => 'Chapter successfully updated',
+ 'chapter_update_notification' => 'تم تحديث الفصل بنجاح',
'chapter_delete' => 'تم حذف الفصل',
- 'chapter_delete_notification' => 'Chapter successfully deleted',
+ 'chapter_delete_notification' => 'تم حذف الفصل بنجاح',
'chapter_move' => 'تم نقل الفصل',
// Books
'book_create' => 'تم إنشاء كتاب',
- 'book_create_notification' => 'Book successfully created',
+ 'book_create_notification' => 'تم إنشاء الكتاب بنجاح',
'book_update' => 'تم تحديث الكتاب',
- 'book_update_notification' => 'Book successfully updated',
+ 'book_update_notification' => 'تم تحديث الكتاب بنجاح',
'book_delete' => 'تم حذف الكتاب',
- 'book_delete_notification' => 'Book successfully deleted',
+ 'book_delete_notification' => 'تم حذف الكتاب بنجاح',
'book_sort' => 'تم سرد الكتاب',
- 'book_sort_notification' => 'Book successfully re-sorted',
+ 'book_sort_notification' => 'تم إعادة فرز الكتاب بنجاح',
// Bookshelves
- 'bookshelf_create' => 'created bookshelf',
- 'bookshelf_create_notification' => 'Bookshelf successfully created',
+ 'bookshelf_create' => 'تم إنشاء رف كتب',
+ 'bookshelf_create_notification' => 'تم إنشاء الرف بنجاح',
'bookshelf_update' => 'تم تحديث الرف',
- 'bookshelf_update_notification' => 'Bookshelf successfully updated',
+ 'bookshelf_update_notification' => 'تم تحديث الرف بنجاح',
'bookshelf_delete' => 'تم تحديث الرف',
- 'bookshelf_delete_notification' => 'Bookshelf successfully deleted',
+ 'bookshelf_delete_notification' => 'تم حذف الرف بنجاح',
// Favourites
- 'favourite_add_notification' => '":name" has been added to your favourites',
- 'favourite_remove_notification' => '":name" has been removed from your favourites',
+ 'favourite_add_notification' => 'تم إضافة ":name" إلى المفضلة لديك',
+ 'favourite_remove_notification' => 'تم إزالة ":name" من المفضلة لديك',
// MFA
- 'mfa_setup_method_notification' => 'Multi-factor method successfully configured',
- 'mfa_remove_method_notification' => 'Multi-factor method successfully removed',
+ 'mfa_setup_method_notification' => 'تم تكوين طريقة متعددة العوامل بنجاح',
+ 'mfa_remove_method_notification' => 'تمت إزالة طريقة متعددة العوامل بنجاح',
// Webhooks
- 'webhook_create' => 'created webhook',
- 'webhook_create_notification' => 'Webhook successfully created',
- 'webhook_update' => 'updated webhook',
- 'webhook_update_notification' => 'Webhook successfully updated',
- 'webhook_delete' => 'deleted webhook',
- 'webhook_delete_notification' => 'Webhook successfully deleted',
+ 'webhook_create' => 'تم إنشاء webhook',
+ 'webhook_create_notification' => 'تم إنشاء Webhook بنجاح',
+ 'webhook_update' => 'تم تحديث webhook',
+ 'webhook_update_notification' => 'تم تحديث Webhook بنجاح',
+ 'webhook_delete' => 'حذف webhook',
+ 'webhook_delete_notification' => 'تم حذف Webhook بنجاح',
// Users
- 'user_update_notification' => 'User successfully updated',
- 'user_delete_notification' => 'User successfully removed',
+ 'user_update_notification' => 'تم تحديث المستخدم بنجاح',
+ 'user_delete_notification' => 'تم إزالة المستخدم بنجاح',
// Other
'commented_on' => 'تم التعليق',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'Hebraisk',
'hr' => 'Hrvatski',
'es_AR' => 'Spanisch Argentinisch',
'et' => 'Estnisch',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Französisch',
'he' => 'Hebräisch',
'hr' => 'Kroatisch',
'es_AR' => 'Spanisch Argentinisch',
'et' => 'Estnisch',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Französisch',
'he' => 'עברית',
'hr' => 'Kroatisch',
// Books
'book_create' => 'created book',
'book_create_notification' => 'Book successfully created',
+ 'book_create_from_chapter' => 'converted chapter to book',
+ 'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
'book_update' => 'updated book',
'book_update_notification' => 'Book successfully updated',
'book_delete' => 'deleted book',
// Bookshelves
'bookshelf_create' => 'created bookshelf',
'bookshelf_create_notification' => 'Bookshelf successfully created',
+ 'bookshelf_create_from_book' => 'converted book to bookshelf',
+ 'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
'bookshelf_update' => 'updated bookshelf',
'bookshelf_update_notification' => 'Bookshelf successfully updated',
'bookshelf_delete' => 'deleted bookshelf',
'previous' => 'Previous',
'filter_active' => 'Active Filter:',
'filter_clear' => 'Clear Filter',
+ 'download' => 'Download',
+ 'open_in_tab' => 'Open in Tab',
// Sort Options
'sort_options' => 'Sort Options',
'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.',
'copy_consider_attachments' => 'Page attachments will not be copied.',
'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.',
+
+ // Conversions
+ 'convert_to_shelf' => 'Convert to Shelf',
+ 'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
+ 'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
+ 'convert_book' => 'Convert Book',
+ 'convert_book_confirm' => 'Are you sure you want to convert this book?',
+ 'convert_undo_warning' => 'This cannot be as easily undone.',
+ 'convert_to_book' => 'Convert to Book',
+ 'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
+ 'convert_chapter' => 'Convert Chapter',
+ 'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
];
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Francés',
'he' => 'עברית',
'hr' => 'Croata',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Francés',
'he' => 'עברית',
'hr' => 'Croata',
'es_AR' => 'Español Argentina (Argentiina hispaania keel)',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français (prantsuse keel)',
'he' => 'עברית (heebrea keel)',
'hr' => 'Hrvatski (horvaadi keel)',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'webhook_delete_notification' => 'وب هوک با موفقیت حذف شد',
// Users
- 'user_update_notification' => 'User successfully updated',
- 'user_delete_notification' => 'User successfully removed',
+ 'user_update_notification' => 'کاربر با موفقیت به روز شد',
+ 'user_delete_notification' => 'کاربر با موفقیت حذف شد',
// Other
'commented_on' => 'ثبت دیدگاه',
'status_active' => 'فعال',
'status_inactive' => 'غیر فعال',
'never' => 'هرگز',
- 'none' => 'None',
+ 'none' => 'هیچکدام',
// Header
'header_menu_expand' => 'گسترش منو',
'pages_edit_draft_save_at' => 'پیش نویس ذخیره شده در',
'pages_edit_delete_draft' => 'حذف پیش نویس',
'pages_edit_discard_draft' => 'دور انداختن پیش نویس',
- 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
- 'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
- 'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
- 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
+ 'pages_edit_switch_to_markdown' => 'به ویرایشگر Markdown بروید',
+ 'pages_edit_switch_to_markdown_clean' => '(مطالب تمیز)',
+ 'pages_edit_switch_to_markdown_stable' => '(محتوای پایدار)',
+ 'pages_edit_switch_to_wysiwyg' => 'به ویرایشگر WYSIWYG بروید',
'pages_edit_set_changelog' => 'تنظیم تغییرات',
'pages_edit_enter_changelog_desc' => 'توضیح مختصری از تغییراتی که ایجاد کرده اید وارد کنید',
'pages_edit_enter_changelog' => 'وارد کردن تغییرات',
- 'pages_editor_switch_title' => 'Switch Editor',
- 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
- 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
- 'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
- 'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.',
- 'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.',
+ 'pages_editor_switch_title' => 'ویرایشگر را تغییر دهید',
+ 'pages_editor_switch_are_you_sure' => 'آیا مطمئن هستید که می خواهید ویرایشگر این صفحه را تغییر دهید؟',
+ 'pages_editor_switch_consider_following' => 'هنگام تغییر ویرایشگر موارد زیر را در نظر بگیرید:',
+ 'pages_editor_switch_consideration_a' => 'پس از ذخیره، گزینه ویرایشگر جدید توسط هر ویرایشگر آینده، از جمله ویرایشگرانی که ممکن است خودشان نتوانند نوع ویرایشگر را تغییر دهند، استفاده خواهد شد.',
+ 'pages_editor_switch_consideration_b' => 'این به طور بالقوه می تواند منجر به از دست دادن جزئیات و نحو در شرایط خاص شود.',
+ 'pages_editor_switch_consideration_c' => 'تغییرات برچسبها یا تغییرات ثبت شده از آخرین ذخیرهسازی انجام شده، در این تغییر باقی نمیمانند.',
'pages_save' => 'ذخیره صفحه',
'pages_title' => 'عنوان صفحه',
'pages_name' => 'نام صفحه',
'pages_revisions_number' => '#',
'pages_revisions_numbered' => 'تجدید نظر #:id',
'pages_revisions_numbered_changes' => 'بازبینی #:id تغییرات',
- 'pages_revisions_editor' => 'Editor Type',
+ 'pages_revisions_editor' => 'نوع ویرایشگر',
'pages_revisions_changelog' => 'لیست تغییرات',
'pages_revisions_changes' => 'تغییرات',
'pages_revisions_current' => 'نسخهی جاری',
'settings' => 'تنظیمات',
'settings_save' => 'تنظیمات را ذخیره کن',
'settings_save_success' => 'تنظیمات ذخیره شد',
- 'system_version' => 'System Version',
- 'categories' => 'Categories',
+ 'system_version' => 'نسخه سیستم',
+ 'categories' => 'دسته بندی ها',
// App Settings
'app_customization' => 'سفارشی سازی',
'app_secure_images' => 'آپلود تصویر با امنیت بالاتر',
'app_secure_images_toggle' => 'آپلود تصویر با امنیت بالاتر',
'app_secure_images_desc' => 'به دلایل عملکرد، همه تصاویر عمومی هستند. این گزینه یک رشته تصادفی و غیرقابل حدس زدن را در مقابل آدرس های تصویر اضافه می کند. برای جلوگیری از دسترسی آسان، اطمینان حاصل کنید که فهرست های دایرکتوری فعال نیستند.',
- 'app_default_editor' => 'Default Page Editor',
+ 'app_default_editor' => 'ویرایشگر پیش فرض صفحه',
'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.',
'app_custom_html' => 'محتوای اصلی HTML سفارشی',
'app_custom_html_desc' => 'هر محتوای اضافه شده در اینجا در پایین بخش <head> هر صفحه درج می شود. این برای تغییر سبک ها یا اضافه کردن کد تجزیه و تحلیل مفید است.',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Espagnol (Argentine)',
'et' => 'Estonien',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'Hébreu',
'hr' => 'Croate',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'pages_edit_draft_save_at' => 'Bozza salvata alle ',
'pages_edit_delete_draft' => 'Elimina Bozza',
'pages_edit_discard_draft' => 'Scarta Bozza',
- 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
- 'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
- 'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
- 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
+ 'pages_edit_switch_to_markdown' => 'Passa all\'editor Markdown',
+ 'pages_edit_switch_to_markdown_clean' => '(Contenuto Chiaro)',
+ 'pages_edit_switch_to_markdown_stable' => '(Contenuto Stabile)',
+ 'pages_edit_switch_to_wysiwyg' => 'Passa all\'editor WYSIWYG',
'pages_edit_set_changelog' => 'Imposta Changelog',
'pages_edit_enter_changelog_desc' => 'Inserisci una breve descrizione dei cambiamenti che hai apportato',
'pages_edit_enter_changelog' => 'Inserisci Changelog',
- 'pages_editor_switch_title' => 'Switch Editor',
- 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
- 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
- 'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
- 'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.',
- 'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.',
+ 'pages_editor_switch_title' => 'Cambia Editor',
+ 'pages_editor_switch_are_you_sure' => 'Sei sicuro di voler cambiare l\'editor di questa pagina?',
+ 'pages_editor_switch_consider_following' => 'Considerare quanto segue quando si cambia editor:',
+ 'pages_editor_switch_consideration_a' => 'Una volta salvata, la nuova opzione di editor sarà utilizzata da qualsiasi editor futuro, inclusi quelli che potrebbero non essere in grado di cambiare il tipo di editor da solo.',
+ 'pages_editor_switch_consideration_b' => 'Ciò può potenzialmente portare a una perdita di dettagli e sintassi in determinate circostanze.',
+ 'pages_editor_switch_consideration_c' => 'Le modifiche al tag o al changelog, fatte dall\'ultimo salvataggio, non persisteranno in questa modifica.',
'pages_save' => 'Salva Pagina',
'pages_title' => 'Titolo Pagina',
'pages_name' => 'Nome Pagina',
'pages_revisions_number' => '#',
'pages_revisions_numbered' => 'Revisione #:id',
'pages_revisions_numbered_changes' => 'Modifiche Revisione #:id',
- 'pages_revisions_editor' => 'Editor Type',
+ 'pages_revisions_editor' => 'Tipo Di Editor',
'pages_revisions_changelog' => 'Cambiamenti',
'pages_revisions_changes' => 'Cambiamenti',
'pages_revisions_current' => 'Versione Corrente',
'app_secure_images' => 'Abilitare una sicurezza maggiore per le immagini caricate?',
'app_secure_images_toggle' => 'Abilita sicurezza aggiuntiva negli upload delle immagini',
'app_secure_images_desc' => 'Per una ragione di prestazioni, tutte le immagini sono pubbliche. Questa opzione aaggiunge una stringa, difficile da indovinare, random negli url delle immagini. Assicurati che il listing delle cartelle non sia abilitato per prevenire un accesso semplice.',
- 'app_default_editor' => 'Default Page Editor',
- 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.',
+ 'app_default_editor' => 'Editor Di Pagina Predefinito',
+ 'app_default_editor_desc' => 'Seleziona quale editor sarà usato per impostazione predefinita quando modifichi nuove pagine. Questa impostazione potrà essere sovrascritta a livello di pagina dove i permessi lo permettano.',
'app_custom_html' => 'Contenuto Head HTML Custom',
'app_custom_html_desc' => 'Qualsiasi contenuto aggiunto qui verrà inserito alla fine della sezione <head> di tutte le pagine. Questo è utile per sovrascrivere lo stile o aggiungere il codice per gli analytics.',
'app_custom_html_disabled_notice' => 'Il contenuto HTML personalizzato è disabilitato su questa pagina impostazioni per garantire che eventuali modifiche possano essere ripristinate.',
'role_access_api' => 'API sistema d\'accesso',
'role_manage_settings' => 'Gestire impostazioni app',
'role_export_content' => 'Esporta contenuto',
- 'role_editor_change' => 'Change page editor',
+ 'role_editor_change' => 'Cambia editor di pagina',
'role_asset' => 'Permessi Entità',
'roles_system_warning' => 'Siate consapevoli che l\'accesso a uno dei tre permessi qui sopra, può consentire a un utente di modificare i propri privilegi o i privilegi di altri nel sistema. Assegna ruoli con questi permessi solo ad utenti fidati.',
'role_asset_desc' => 'Questi permessi controllano l\'accesso di default alle entità. I permessi nei Libri, Capitoli e Pagine sovrascriveranno questi.',
'es_AR' => 'Spagnolo d\'Argentina',
'et' => 'Estone',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Francese',
'he' => 'Ebraico',
'hr' => 'Croato',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => '히브리어',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
*/
return [
// General editor terms
- 'general' => 'General',
- 'advanced' => 'Advanced',
- 'none' => 'None',
+ 'general' => 'Vispārīgi',
+ 'advanced' => 'Papildu iespējas',
+ 'none' => 'Neviens',
'cancel' => 'Atcelt',
'save' => 'Saglabāt',
'close' => 'Aizvērt',
- 'undo' => 'Undo',
- 'redo' => 'Redo',
- 'left' => 'Left',
- 'center' => 'Center',
- 'right' => 'Right',
- 'top' => 'Top',
- 'middle' => 'Middle',
- 'bottom' => 'Bottom',
+ 'undo' => 'Atsaukt',
+ 'redo' => 'Atcelt atsaukšanu',
+ 'left' => 'Pa kreisi',
+ 'center' => 'Centrā',
+ 'right' => 'Pa labi',
+ 'top' => 'Augšā',
+ 'middle' => 'Vidū',
+ 'bottom' => 'Apakšā',
'width' => 'Platums',
'height' => 'Augstums',
'More' => 'Vairāk',
- 'select' => 'Select...',
+ 'select' => 'Atlasīt...',
// Toolbar
'formats' => 'Formāti',
- 'header_large' => 'Large Header',
- 'header_medium' => 'Medium Header',
- 'header_small' => 'Small Header',
- 'header_tiny' => 'Tiny Header',
+ 'header_large' => 'Liels virsraksts',
+ 'header_medium' => 'Vidējs virsraksts',
+ 'header_small' => 'Mazs virsraksts',
+ 'header_tiny' => 'Ļoti mazs virsraksts',
'paragraph' => 'Rindkopa',
- 'blockquote' => 'Blockquote',
- 'inline_code' => 'Inline code',
+ 'blockquote' => 'Citāts',
+ 'inline_code' => 'Kods iekļauts rindā',
'callouts' => 'Norādes',
'callout_information' => 'Informācija',
- 'callout_success' => 'Success',
+ 'callout_success' => 'Veiksmīgi',
'callout_warning' => 'Brīdinājums',
- 'callout_danger' => 'Danger',
- 'bold' => 'Bold',
- 'italic' => 'Italic',
- 'underline' => 'Underline',
- 'strikethrough' => 'Strikethrough',
- 'superscript' => 'Superscript',
- 'subscript' => 'Subscript',
+ 'callout_danger' => 'Bīstami',
+ 'bold' => 'Treknraksts',
+ 'italic' => 'Slīpraksts',
+ 'underline' => 'Pasvītrojums',
+ 'strikethrough' => 'Pārsvītrojums',
+ 'superscript' => 'Augšraksts',
+ 'subscript' => 'Apakšraksts',
'text_color' => 'Teksta krāsa',
- 'custom_color' => 'Custom color',
- 'remove_color' => 'Remove color',
+ 'custom_color' => 'Pielāgot krāsu',
+ 'remove_color' => 'Noņemt krāsu',
'background_color' => 'Fona krāsa',
- 'align_left' => 'Align left',
- 'align_center' => 'Align center',
- 'align_right' => 'Align right',
- 'align_justify' => 'Justify',
- 'list_bullet' => 'Bullet list',
+ 'align_left' => 'Līdzināt pa kreisi',
+ 'align_center' => 'Līdzināt pa vidu',
+ 'align_right' => 'Līdzināt pa labi',
+ 'align_justify' => 'Līdzināt gar abām malām',
+ 'list_bullet' => 'Nenumurēts saraksts',
'list_numbered' => 'Numurēts saraksts',
- 'list_task' => 'Task list',
+ 'list_task' => 'Uzdevumu saraksts',
'indent_increase' => 'Palielināt atkāpi',
'indent_decrease' => 'Samazināt atkāpi',
'table' => 'Tabula',
'insert_image' => 'Ievietot attēlu',
- 'insert_image_title' => 'Insert/Edit Image',
- 'insert_link' => 'Insert/edit link',
- 'insert_link_title' => 'Insert/Edit Link',
- 'insert_horizontal_line' => 'Insert horizontal line',
- 'insert_code_block' => 'Insert code block',
- 'insert_drawing' => 'Insert/edit drawing',
- 'drawing_manager' => 'Drawing manager',
- 'insert_media' => 'Insert/edit media',
- 'insert_media_title' => 'Insert/Edit Media',
- 'clear_formatting' => 'Clear formatting',
- 'source_code' => 'Source code',
- 'source_code_title' => 'Source Code',
- 'fullscreen' => 'Fullscreen',
- 'image_options' => 'Image options',
+ 'insert_image_title' => 'Ievietot/rediģēt attēlu',
+ 'insert_link' => 'Ievietot/rediģēt saiti',
+ 'insert_link_title' => 'Ievietot/rediģēt saiti',
+ 'insert_horizontal_line' => 'Ievietot horizontālu līniju',
+ 'insert_code_block' => 'Ievietot koda bloku',
+ 'insert_drawing' => 'Ievietot/rediģēt zīmējumu',
+ 'drawing_manager' => 'Zīmēšanas pārvaldnieks',
+ 'insert_media' => 'Ievietot/rediģēt mediju',
+ 'insert_media_title' => 'Ievietot/rediģēt mediju',
+ 'clear_formatting' => 'Notīrīt noformējumu',
+ 'source_code' => 'Pirmkods',
+ 'source_code_title' => 'Pirmkods',
+ 'fullscreen' => 'Pilnekrāns',
+ 'image_options' => 'Attēla uzstādījumu',
// Tables
- 'table_properties' => 'Table properties',
- 'table_properties_title' => 'Table Properties',
- 'delete_table' => 'Delete table',
- 'insert_row_before' => 'Insert row before',
- 'insert_row_after' => 'Insert row after',
- 'delete_row' => 'Delete row',
- 'insert_column_before' => 'Insert column before',
- 'insert_column_after' => 'Insert column after',
- 'delete_column' => 'Delete column',
+ 'table_properties' => 'Tabulas īpašības',
+ 'table_properties_title' => 'Tabulas īpašības',
+ 'delete_table' => 'Dzēst tabulu',
+ 'insert_row_before' => 'Ievietot rindu augstāk',
+ 'insert_row_after' => 'Ievietot rindu zemāk',
+ 'delete_row' => 'Dzēst rindu',
+ 'insert_column_before' => 'Ievietot kolonnu pirms',
+ 'insert_column_after' => 'Ievietot kolonnu pēc',
+ 'delete_column' => 'Dzēst kolonnu',
'table_cell' => 'Šūna',
'table_row' => 'Rinda',
'table_column' => 'Kolonna',
- 'cell_properties' => 'Cell properties',
- 'cell_properties_title' => 'Cell Properties',
- 'cell_type' => 'Cell type',
+ 'cell_properties' => 'Šūnas īpašības',
+ 'cell_properties_title' => 'Šūnas īpašības',
+ 'cell_type' => 'Šūnas tips',
'cell_type_cell' => 'Šūna',
- 'cell_scope' => 'Scope',
- 'cell_type_header' => 'Header cell',
- 'merge_cells' => 'Merge cells',
- 'split_cell' => 'Split cell',
- 'table_row_group' => 'Row Group',
- 'table_column_group' => 'Column Group',
- 'horizontal_align' => 'Horizontal align',
- 'vertical_align' => 'Vertical align',
- 'border_width' => 'Border width',
- 'border_style' => 'Border style',
- 'border_color' => 'Border color',
- 'row_properties' => 'Row properties',
- 'row_properties_title' => 'Row Properties',
- 'cut_row' => 'Cut row',
- 'copy_row' => 'Copy row',
- 'paste_row_before' => 'Paste row before',
- 'paste_row_after' => 'Paste row after',
- 'row_type' => 'Row type',
- 'row_type_header' => 'Header',
- 'row_type_body' => 'Body',
- 'row_type_footer' => 'Footer',
- 'alignment' => 'Alignment',
- 'cut_column' => 'Cut column',
- 'copy_column' => 'Copy column',
- 'paste_column_before' => 'Paste column before',
- 'paste_column_after' => 'Paste column after',
- 'cell_padding' => 'Cell padding',
- 'cell_spacing' => 'Cell spacing',
- 'caption' => 'Caption',
- 'show_caption' => 'Show caption',
- 'constrain' => 'Constrain proportions',
- 'cell_border_solid' => 'Solid',
- 'cell_border_dotted' => 'Dotted',
- 'cell_border_dashed' => 'Dashed',
- 'cell_border_double' => 'Double',
- 'cell_border_groove' => 'Groove',
- 'cell_border_ridge' => 'Ridge',
- 'cell_border_inset' => 'Inset',
- 'cell_border_outset' => 'Outset',
- 'cell_border_none' => 'None',
- 'cell_border_hidden' => 'Hidden',
+ 'cell_scope' => 'Darbības lauks',
+ 'cell_type_header' => 'Galvenes šūna',
+ 'merge_cells' => 'Sapludināt šūnas',
+ 'split_cell' => 'Sadalīt šūnas',
+ 'table_row_group' => 'Rindu grupa',
+ 'table_column_group' => 'Kolonnu grupa',
+ 'horizontal_align' => 'Horizontāls novietojums',
+ 'vertical_align' => 'Vertikāls novietojums',
+ 'border_width' => 'Apmales platums',
+ 'border_style' => 'Apmales veids',
+ 'border_color' => 'Apmales krāsa',
+ 'row_properties' => 'Rindas īpašības',
+ 'row_properties_title' => 'Rindas īpašības',
+ 'cut_row' => 'Izgriezt rindu',
+ 'copy_row' => 'Kopēt rindu',
+ 'paste_row_before' => 'Ielīmēt rindu augstāk',
+ 'paste_row_after' => 'Ielīmēt rindu zemāk',
+ 'row_type' => 'Rindas tips',
+ 'row_type_header' => 'Galvene',
+ 'row_type_body' => 'Pamata saturs',
+ 'row_type_footer' => 'Kājene',
+ 'alignment' => 'Līdzināšana',
+ 'cut_column' => 'Izgriezt kolonnu',
+ 'copy_column' => 'Kopēt kolonnu',
+ 'paste_column_before' => 'Ielīmēt kolonnu pirms',
+ 'paste_column_after' => 'Ielīmēt kolonnu pēc',
+ 'cell_padding' => 'Šūnu iekšējais attālums',
+ 'cell_spacing' => 'Šūnu attālums',
+ 'caption' => 'Virsraksts',
+ 'show_caption' => 'Parādīt virsrakstu',
+ 'constrain' => 'Saglabāt proporcijas',
+ 'cell_border_solid' => 'Pilna',
+ 'cell_border_dotted' => 'Punktēta',
+ 'cell_border_dashed' => 'Raustīta līnija',
+ 'cell_border_double' => 'Dubulta',
+ 'cell_border_groove' => 'Iedoba',
+ 'cell_border_ridge' => 'Izcelta',
+ 'cell_border_inset' => 'Iespiesta',
+ 'cell_border_outset' => 'Pacelta',
+ 'cell_border_none' => 'Nekas',
+ 'cell_border_hidden' => 'Paslēpts',
// Images, links, details/summary & embed
- 'source' => 'Source',
- 'alt_desc' => 'Alternative description',
- 'embed' => 'Embed',
- 'paste_embed' => 'Paste your embed code below:',
+ 'source' => 'Avots',
+ 'alt_desc' => 'Alternatīvais apraksts',
+ 'embed' => 'Iekļaut',
+ 'paste_embed' => 'Iekopējiet savu iekļaušanas kodu zemāk:',
'url' => 'URL',
- 'text_to_display' => 'Text to display',
+ 'text_to_display' => 'Attēlojamais teksts',
'title' => 'Nosaukums',
- 'open_link' => 'Open link in...',
- 'open_link_current' => 'Current window',
- 'open_link_new' => 'New window',
- 'insert_collapsible' => 'Insert collapsible block',
- 'collapsible_unwrap' => 'Unwrap',
- 'edit_label' => 'Edit label',
- 'toggle_open_closed' => 'Toggle open/closed',
- 'collapsible_edit' => 'Edit collapsible block',
- 'toggle_label' => 'Toggle label',
+ 'open_link' => 'Atvērt saiti...',
+ 'open_link_current' => 'Šis logs',
+ 'open_link_new' => 'Jauns logs',
+ 'insert_collapsible' => 'Ievietot sakļaujamu bloku',
+ 'collapsible_unwrap' => 'Attīt',
+ 'edit_label' => 'Rediģēt marķējumu',
+ 'toggle_open_closed' => 'Pārslēgt atvērts/aizvērts',
+ 'collapsible_edit' => 'Rediģēt sakļaujamu bloku',
+ 'toggle_label' => 'Pārslēgt marķējumu',
// About view
- 'about' => 'About the editor',
- 'about_title' => 'About the WYSIWYG Editor',
- 'editor_license' => 'Editor License & Copyright',
- 'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under an LGPL v2.1 license.',
- 'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.',
- 'save_continue' => 'Save Page & Continue',
- 'callouts_cycle' => '(Keep pressing to toggle through types)',
- 'link_selector' => 'Link to content',
+ 'about' => 'Par redaktoru',
+ 'about_title' => 'Par WYSIWYG redaktoru',
+ 'editor_license' => 'Redaktora licence un autortiesības',
+ 'editor_tiny_license' => 'Šis redaktors ir izveidots, izmantojot :tinyLink, kas ir publicēts ar LGPL v2.1 licenci.',
+ 'editor_tiny_license_link' => 'TinyMCE autortiesības un licences detaļas var atrast šeit.',
+ 'save_continue' => 'Saglabāt lapu un turpināt',
+ 'callouts_cycle' => '(Turpiniet spiest, lai pārslēgtu tipus)',
+ 'link_selector' => 'Saite uz saturu',
'shortcuts' => 'Saīsnes',
'shortcut' => 'Saīsne',
- 'shortcuts_intro' => 'The following shortcuts are available in the editor:',
+ 'shortcuts_intro' => 'Šajā redaktorā pieejamas šādas saīsnes:',
'windows_linux' => '(Windows/Linux)',
'mac' => '(Mac)',
'description' => 'Apraksts',
'pages_edit_draft_save_at' => 'Melnraksts saglabāts ',
'pages_edit_delete_draft' => 'Dzēst melnrakstu',
'pages_edit_discard_draft' => 'Atmest malnrakstu',
- 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
- 'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
- 'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
- 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
+ 'pages_edit_switch_to_markdown' => 'Pārslēgties uz Markdown redaktoru',
+ 'pages_edit_switch_to_markdown_clean' => '(Iztīrītais saturs)',
+ 'pages_edit_switch_to_markdown_stable' => '(Stabilais saturs)',
+ 'pages_edit_switch_to_wysiwyg' => 'Pārslēgties uz WYSIWYG redaktoru',
'pages_edit_set_changelog' => 'Pievienot izmaiņu aprakstu',
'pages_edit_enter_changelog_desc' => 'Ievadi nelielu aprakstu par vaiktajām izmaiņām',
'pages_edit_enter_changelog' => 'Izmaiņu apraksts',
- 'pages_editor_switch_title' => 'Switch Editor',
- 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
- 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
- 'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
- 'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.',
- 'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.',
+ 'pages_editor_switch_title' => 'Pārslēgt redaktoru',
+ 'pages_editor_switch_are_you_sure' => 'Vai tiešām vēlaties pārslēgt šai lapai lietojamo redaktoru?',
+ 'pages_editor_switch_consider_following' => 'Pārslēdzot redaktorus, ņemiet vērā:',
+ 'pages_editor_switch_consideration_a' => 'Pēc saglabāšanas jaunā redaktora izvēle tiks izmantota nākotnē visiem lietotājiem, tai skaitā tiem, kam var nebūt tiesības pašiem mainīt redaktora veidu.',
+ 'pages_editor_switch_consideration_b' => 'Tas var noteiktos apstākļos novest pie iespējamiem noformējuma un sintakses zudumiem.',
+ 'pages_editor_switch_consideration_c' => 'Birku vai izmaiņu saraksta ieraksti, kas veikti kopš pēdējās saglabāšanas, nesaglabāsies kopā ar šīm izmaiņām.',
'pages_save' => 'Saglabāt lapu',
'pages_title' => 'Lapas virsraksts',
'pages_name' => 'Lapas nosaukums',
'pages_revisions_number' => '#',
'pages_revisions_numbered' => 'Revīzija #:id',
'pages_revisions_numbered_changes' => 'Revīzijas #:id izmaiņas',
- 'pages_revisions_editor' => 'Editor Type',
+ 'pages_revisions_editor' => 'Redaktora veids',
'pages_revisions_changelog' => 'Izmaiņu žurnāls',
'pages_revisions_changes' => 'Izmaiņas',
'pages_revisions_current' => 'Pašreizējā versija',
'settings' => 'Iestatījumi',
'settings_save' => 'Saglabāt iestatījumus',
'settings_save_success' => 'Iestatījumi saglabāti',
- 'system_version' => 'System Version',
- 'categories' => 'Categories',
+ 'system_version' => 'Sistēmas versija',
+ 'categories' => 'Kategorijas',
// App Settings
'app_customization' => 'Pielāgojumi',
'app_secure_images' => 'Paaugstinātas drošības attēlu ielāde',
'app_secure_images_toggle' => 'Ieslēgt paaugstinātas drošības attēlu ielādi',
'app_secure_images_desc' => 'Ātrdarbības nolūkos attēli ir publiski pieejami. Šī opcija pievieno nejaušu grūti uzminamu teksta virkni attēlu adresēs. Pārliecinieties kā ir izslēgta direktoriju pārlūkošana, lai nepieļautu vieglu piekļuvi šiem failiem.',
- 'app_default_editor' => 'Default Page Editor',
- 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.',
+ 'app_default_editor' => 'Noklusētais lapu redaktors',
+ 'app_default_editor_desc' => 'Izvēlieties noklusēto redaktoru jaunu lapu rediģēšanai. To iespējams norādīt arī lapu līmenī, ja piekļuves tiesības to atļauj.',
'app_custom_html' => 'Pielāgot HTML head saturu',
'app_custom_html_desc' => 'Šis saturs tiks pievienots <head> sadaļas apakšā visām lapām. Tas ir noderīgi papildinot CSS stilus vai pievienojot analītikas kodu.',
'app_custom_html_disabled_notice' => 'Pielāgots HTML head saturs ir izslēgts šajā uzstādījumu lapā, lai nodrošinātu, ka iespējams atcelt jebkādas kritiskas izmaiņas.',
'role_access_api' => 'Piekļūt sistēmas API',
'role_manage_settings' => 'Pārvaldīt iestatījumus',
'role_export_content' => 'Eksportēt saturu',
- 'role_editor_change' => 'Change page editor',
+ 'role_editor_change' => 'Mainīt lapu redaktoru',
'role_asset' => 'Resursa piekļuves tiesības',
'roles_system_warning' => 'Jebkuras no trīs augstāk redzamajām atļaujām dod iespēju lietotājam mainīt savas un citu lietotāju sistēmas atļaujas. Pievieno šīs grupu atļaujas tikai tiem lietotājiem, kuriem uzticies.',
'role_asset_desc' => 'Šīs piekļuves tiesības kontrolē noklusēto piekļuvi sistēmas resursiem. Grāmatām, nodaļām un lapām norādītās tiesības būs pārākas par šīm.',
'es_AR' => 'Español Argentina',
'et' => 'Igauņu',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'toggle_label' => 'Schakel label aan/uit',
// About view
- 'about' => 'Over de editor',
- 'about_title' => 'Over de WYSIWYG-bewerker',
- 'editor_license' => 'Editor Licentie & Copyright',
- 'editor_tiny_license' => 'Deze editor is gebouwd met :tinyLink, dat aangeboden wordt via een LGPL v2.1 licentie.',
+ 'about' => 'Over de bewerker',
+ 'about_title' => 'Over de WYSIWYG Bewerker',
+ 'editor_license' => 'Bewerker Licentie & Copyright',
+ 'editor_tiny_license' => 'Deze bewerker is gebouwd met :tinyLink, dat aangeboden wordt via een LGPL v2.1 licentie.',
'editor_tiny_license_link' => 'De copyright- en licentiegegevens van TinyMCE vindt u hier.',
'save_continue' => 'Pagina opslaan en verdergaan',
'callouts_cycle' => '(Blijf drukken om door de types te wisselen)',
'pages_edit_draft_save_at' => 'Concept opgeslagen op ',
'pages_edit_delete_draft' => 'Concept verwijderen',
'pages_edit_discard_draft' => 'Concept verwijderen',
- 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
- 'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
- 'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
- 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
+ 'pages_edit_switch_to_markdown' => 'Verander naar Markdown Bewerker',
+ 'pages_edit_switch_to_markdown_clean' => '(Schoongemaakte Inhoud)',
+ 'pages_edit_switch_to_markdown_stable' => '(Stabiele Inhoud)',
+ 'pages_edit_switch_to_wysiwyg' => 'Verander naar WYSIWYG Bewerker',
'pages_edit_set_changelog' => 'Wijzigingslogboek instellen',
'pages_edit_enter_changelog_desc' => 'Geef een korte omschrijving van de wijzigingen die je gemaakt hebt',
'pages_edit_enter_changelog' => 'Voeg toe aan wijzigingslogboek',
- 'pages_editor_switch_title' => 'Switch Editor',
- 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
- 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
- 'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
- 'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.',
- 'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.',
+ 'pages_editor_switch_title' => 'Wijzig Bewerker',
+ 'pages_editor_switch_are_you_sure' => 'Weet u zeker dat u de bewerker voor deze pagina wilt wijzigen?',
+ 'pages_editor_switch_consider_following' => 'Houd rekening met het volgende als u van bewerker verandert:',
+ 'pages_editor_switch_consideration_a' => 'Eenmaal opgeslagen, zal de nieuwe bewerker keuze gebruikt worden door alle toekomstige gebruikers, ook diegene die zelf niet van bewerker type kunnen veranderen.',
+ 'pages_editor_switch_consideration_b' => 'Dit kan mogelijks tot een verlies van detail en syntax leiden in bepaalde omstandigheden.',
+ 'pages_editor_switch_consideration_c' => 'De veranderingen aan Tags of aan het wijzigingslogboek, sinds de laatste keer opslaan, zullen niet behouden blijven met deze wijziging.',
'pages_save' => 'Pagina opslaan',
'pages_title' => 'Pagina titel',
'pages_name' => 'Pagina naam',
- 'pages_md_editor' => 'Bewerken',
+ 'pages_md_editor' => 'Bewerker',
'pages_md_preview' => 'Voorbeeld',
'pages_md_insert_image' => 'Afbeelding invoegen',
'pages_md_insert_link' => 'Entity link invoegen',
'pages_revisions_number' => '#',
'pages_revisions_numbered' => 'Revisie #:id',
'pages_revisions_numbered_changes' => 'Revisie #:id wijzigingen',
- 'pages_revisions_editor' => 'Editor Type',
+ 'pages_revisions_editor' => 'Bewerker Type',
'pages_revisions_changelog' => 'Wijzigingsoverzicht',
'pages_revisions_changes' => 'Wijzigingen',
'pages_revisions_current' => 'Huidige versie',
'app_secure_images' => 'Uploaden van afbeeldingen met hogere beveiliging',
'app_secure_images_toggle' => 'Activeer uploaden van afbeeldingen met hogere beveiliging',
'app_secure_images_desc' => 'Om prestatieredenen zijn alle afbeeldingen openbaar. Deze optie voegt een willekeurige en moeilijk te raden tekst toe aan de URL\'s van de afbeeldingen. Zorg ervoor dat "directory indexes" niet ingeschakeld zijn om eenvoudige toegang te voorkomen.',
- 'app_default_editor' => 'Default Page Editor',
- 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.',
+ 'app_default_editor' => 'Standaard Pagina Bewerker',
+ 'app_default_editor_desc' => 'Selecteer welke bewerker standaard zal worden gebruikt bij het bewerken van nieuwe pagina\'s. Dit kan worden overschreven op paginaniveau als de rechten dat toestaan.',
'app_custom_html' => 'HTML aan <head> toevoegen',
'app_custom_html_desc' => 'Alle hieronder toegevoegde data wordt aan het einde van de <head> sectie van elke pagina toegevoegd. Gebruik dit om stijlen te overschrijven of analytische code toe te voegen.',
'app_custom_html_disabled_notice' => 'Bovenstaande wordt niet toegevoegd aan deze pagina om ervoor te zorgen dat je foutieve code steeds ongedaan kan maken.',
'role_access_api' => 'Ga naar systeem API',
'role_manage_settings' => 'Beheer app instellingen',
'role_export_content' => 'Exporteer inhoud',
- 'role_editor_change' => 'Change page editor',
+ 'role_editor_change' => 'Wijzig pagina bewerker',
'role_asset' => 'Asset Machtigingen',
'roles_system_warning' => 'Wees ervan bewust dat toegang tot een van de bovengenoemde drie machtigingen een gebruiker in staat kan stellen zijn eigen machtigingen of de machtigingen van anderen in het systeem kan wijzigen. Wijs alleen rollen toe met deze machtigingen aan vertrouwde gebruikers.',
'role_asset_desc' => 'Deze machtigingen bepalen de standaard toegang tot de assets binnen het systeem. Machtigingen op boeken, hoofdstukken en pagina\'s overschrijven deze instelling.',
'es_AR' => 'Español Argentina (Argentijns Spaans)',
'et' => 'Eesti keel (Estisch)',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français (Frans)',
'he' => 'עברית (Hebreeuws)',
'hr' => 'Hrvatski (Kroatisch)',
'pages_edit_draft_save_at' => 'Wersja robocza zapisana ',
'pages_edit_delete_draft' => 'Usuń wersje roboczą',
'pages_edit_discard_draft' => 'Porzuć wersje roboczą',
- 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
- 'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
- 'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
- 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
+ 'pages_edit_switch_to_markdown' => 'Przełącz na edytor Markdown',
+ 'pages_edit_switch_to_markdown_clean' => '(Czysta zawartość)',
+ 'pages_edit_switch_to_markdown_stable' => '(Statyczna zawartość)',
+ 'pages_edit_switch_to_wysiwyg' => 'Przełącz na edytor WYSIWYG',
'pages_edit_set_changelog' => 'Ustaw dziennik zmian',
'pages_edit_enter_changelog_desc' => 'Opisz zmiany, które zostały wprowadzone',
'pages_edit_enter_changelog' => 'Wyświetl dziennik zmian',
- 'pages_editor_switch_title' => 'Switch Editor',
- 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
- 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
- 'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
- 'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.',
- 'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.',
+ 'pages_editor_switch_title' => 'Przełącz edytor',
+ 'pages_editor_switch_are_you_sure' => 'Czy na pewno chcesz zmienić edytor dla tej strony?',
+ 'pages_editor_switch_consider_following' => 'Przy zmianie edytorów pamiętaj, że:',
+ 'pages_editor_switch_consideration_a' => 'Po zapisaniu nowo ustawiony edytor będzie używany przez przyszłych edytujących użytkowników, w tym również tych, którzy sami mogą nie być w stanie zmienić edytora.',
+ 'pages_editor_switch_consideration_b' => 'Może to potencjalnie prowadzić do utraty szczegółów i składni w pewnych przypadkach.',
+ 'pages_editor_switch_consideration_c' => 'Zmiany w znacznikach lub w dzienniku zmian, zrobione od ostatniego zapisu, nie zostaną zapamiętane przy tej zmianie.',
'pages_save' => 'Zapisz stronę',
'pages_title' => 'Tytuł strony',
'pages_name' => 'Nazwa strony',
'pages_revisions_number' => '#',
'pages_revisions_numbered' => 'Wersja #:id',
'pages_revisions_numbered_changes' => 'Zmiany w wersji #:id',
- 'pages_revisions_editor' => 'Editor Type',
+ 'pages_revisions_editor' => 'Typ edytora',
'pages_revisions_changelog' => 'Dziennik zmian',
'pages_revisions_changes' => 'Zmiany',
'pages_revisions_current' => 'Obecna wersja',
'app_secure_images' => 'Włączyć przesyłanie obrazów o wyższym poziomie bezpieczeństwa?',
'app_secure_images_toggle' => 'Włącz wyższy poziom bezpieczeństwa dla obrazów',
'app_secure_images_desc' => 'Ze względów wydajnościowych wszystkie obrazki są publiczne. Ta opcja dodaje dodatkowy, trudny do odgadnięcia losowy ciąg na początku nazwy obrazka. Upewnij się że indeksowanie katalogów jest zablokowane, aby uniemożliwić łatwy dostęp do obrazków.',
- 'app_default_editor' => 'Default Page Editor',
- 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.',
+ 'app_default_editor' => 'Domyślny edytor stron',
+ 'app_default_editor_desc' => 'Wybierz, który edytor będzie domyślnie używany podczas edycji nowych stron. Może to być nadpisane na poziomie strony, na którym pozwalają na to uprawnienia.',
'app_custom_html' => 'Własna zawartość w tagu <head>',
'app_custom_html_desc' => 'Zawartość dodana tutaj zostanie dołączona na dole sekcji <head> każdej strony. Przydatne przy nadpisywaniu styli lub dodawaniu analityki.',
'app_custom_html_disabled_notice' => 'Niestandardowa zawartość nagłówka HTML jest wyłączona na tej stronie ustawień aby zapewnić, że wszystkie błedne zmiany (braking change) mogą zostać cofnięte.',
'role_access_api' => 'Dostęp do systemowego API',
'role_manage_settings' => 'Zarządzanie ustawieniami aplikacji',
'role_export_content' => 'Eksportuj zawartość',
- 'role_editor_change' => 'Change page editor',
+ 'role_editor_change' => 'Zmień edytor strony',
'role_asset' => 'Zarządzanie zasobami',
'roles_system_warning' => 'Pamiętaj, że dostęp do trzech powyższych uprawnień może pozwolić użytkownikowi na zmianę własnych uprawnień lub uprawnień innych osób w systemie. Przypisz tylko role z tymi uprawnieniami do zaufanych użytkowników.',
'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia książek, rozdziałów i stron nadpisują te ustawienia.',
'es_AR' => 'Español Argentina',
'et' => 'Estoński',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'İbranice',
'hr' => 'Hrvatski',
'width' => 'Ширина',
'height' => 'Висота',
'More' => 'Більше',
- 'select' => 'Select...',
+ 'select' => 'Вибрати…',
// Toolbar
'formats' => 'Формати',
'align_left' => 'Вирівняти по лівому краю',
'align_center' => 'Вирівняти по центру',
'align_right' => 'Вирівнювання по правому краю',
- 'align_justify' => 'Justify',
+ 'align_justify' => 'За шириною',
'list_bullet' => 'Маркований список',
'list_numbered' => 'Нумерований список',
- 'list_task' => 'Task list',
+ 'list_task' => 'Список завдань',
'indent_increase' => 'Збільшити відступ',
'indent_decrease' => 'Зменшити відступ',
'table' => 'Таблиця',
'cell_type_cell' => 'Комірка',
'cell_scope' => 'Scope',
'cell_type_header' => 'Комірка заголовка',
- 'merge_cells' => 'Merge cells',
- 'split_cell' => 'Split cell',
+ 'merge_cells' => 'Об\'єднати комірки',
+ 'split_cell' => 'Роз\'єднати комірку',
'table_row_group' => 'Група рядків',
'table_column_group' => 'Група стовпців',
'horizontal_align' => 'Горизонтальне вирівнювання',
'toggle_label' => 'Перемкнути ярлики',
// About view
- 'about' => 'About the editor',
+ 'about' => 'Про редактор',
'about_title' => 'Про WYSIWYG редактор',
'editor_license' => 'Ліцензія редактора і авторські права',
'editor_tiny_license' => 'Цей редактор побудований за допомогою :tinyLink що забезпечується під ліцензією LGPL v2.1.',
'pages_edit_draft_save_at' => 'Чернетка збережена о ',
'pages_edit_delete_draft' => 'Видалити чернетку',
'pages_edit_discard_draft' => 'Відхилити чернетку',
- 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
- 'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
- 'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
- 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
+ 'pages_edit_switch_to_markdown' => 'Змінити редактор на Markdown',
+ 'pages_edit_switch_to_markdown_clean' => '(Очистити вміст)',
+ 'pages_edit_switch_to_markdown_stable' => '(Стабілізувати вміст)',
+ 'pages_edit_switch_to_wysiwyg' => 'Змінити редактор на WYSIWYG',
'pages_edit_set_changelog' => 'Встановити журнал змін',
'pages_edit_enter_changelog_desc' => 'Введіть короткий опис внесених вами змін',
'pages_edit_enter_changelog' => 'Введіть список змін',
- 'pages_editor_switch_title' => 'Switch Editor',
+ 'pages_editor_switch_title' => 'Змінити редактор',
'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
'settings' => 'Налаштування',
'settings_save' => 'Зберегти налаштування',
'settings_save_success' => 'Налаштування збережено',
- 'system_version' => 'System Version',
- 'categories' => 'Categories',
+ 'system_version' => 'Версія',
+ 'categories' => 'Категорії',
// App Settings
'app_customization' => 'Налаштування',
'app_secure_images' => 'Вищі налаштування безпеки для зображень',
'app_secure_images_toggle' => 'Увімкунти вищі налаштування безпеки для завантаження зображень',
'app_secure_images_desc' => 'З міркувань продуктивності всі зображення є загальнодоступними. Цей параметр додає випадковий, важко передбачуваний рядок перед URL-адресами зображень. Переконайтеся, що індексація каталогів не активована, щоб запобігти легкому доступу.',
- 'app_default_editor' => 'Default Page Editor',
- 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.',
+ 'app_default_editor' => 'Стандартний редактор сторінок',
+ 'app_default_editor_desc' => 'Виберіть, який редактор буде використовуватися за замовчуванням під час редагування нових сторінок. Це можна перевизначити на рівні дозволів сторінки.',
'app_custom_html' => 'Користувацький вміст HTML-заголовку',
'app_custom_html_desc' => 'Будь-який доданий тут вміст буде вставлено в нижню частину розділу <head> кожної сторінки. Це зручно для перевизначення стилів, або додавання коду аналітики.',
'app_custom_html_disabled_notice' => 'На цій сторінці налаштувань відключений користувацький вміст заголовка HTML, щоб гарантувати, що будь-які невдалі зміни можна буде відновити.',
'role_access_api' => 'Доступ до системного API',
'role_manage_settings' => 'Керування налаштуваннями програми',
'role_export_content' => 'Вміст експорту',
- 'role_editor_change' => 'Change page editor',
+ 'role_editor_change' => 'Змінити редактор сторінок',
'role_asset' => 'Дозволи',
'roles_system_warning' => 'Майте на увазі, що доступ до будь-якого з вищезазначених трьох дозволів може дозволити користувачеві змінювати власні привілеї або привілеї інших в системі. Ролі з цими дозволами призначайте лише довіреним користувачам.',
'role_asset_desc' => 'Ці дозволи контролюють стандартні доступи всередині системи. Права на книги, розділи та сторінки перевизначать ці дозволи.',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'meta_updated' => '更新于 :timeLength',
'meta_updated_name' => '由 :user 更新于 :timeLength',
'meta_owned_name' => '拥有者 :user',
- 'entity_select' => '实体选择',
+ 'entity_select' => '选择项目',
'images' => '图片',
'my_recent_drafts' => '我最近的草稿',
'my_recently_viewed' => '我最近看过',
'pages_edit_delete_draft' => '删除草稿',
'pages_edit_discard_draft' => '放弃草稿',
'pages_edit_switch_to_markdown' => '切换到 Markdown 编辑器',
- 'pages_edit_switch_to_markdown_clean' => 'ï¼\88æ¸\85é\99¤内容)',
+ 'pages_edit_switch_to_markdown_clean' => 'ï¼\88æ\95´ç\90\86内容)',
'pages_edit_switch_to_markdown_stable' => '(保留内容)',
'pages_edit_switch_to_wysiwyg' => '切换到所见即所得编辑器',
'pages_edit_set_changelog' => '更新说明',
'pages_editor_switch_title' => '切换编辑器',
'pages_editor_switch_are_you_sure' => '您确定要更改此页面的编辑器吗?',
'pages_editor_switch_consider_following' => '更改编辑器时请注意以下事项:',
- 'pages_editor_switch_consideration_a' => '一旦保存,任何未来的编辑都将使用新的编辑器,包括那些可能无法自行更改编辑器类型的编辑器。',
- 'pages_editor_switch_consideration_b' => '这可能导致在某些情况下失去细节和语法。',
- 'pages_editor_switch_consideration_c' => '此次修改不会保存上次保存后修改的标签和更改日志。',
+ 'pages_editor_switch_consideration_a' => '一旦保存,任何未来的编辑都将使用新的编辑器,包括那些没有权限自行更改编辑器类型的用户。',
+ 'pages_editor_switch_consideration_b' => '在某些情况下这可能会导致丢失页面格式或功能损坏。',
+ 'pages_editor_switch_consideration_c' => '上次保存后修改的标签和更改日志将不会被保存。',
'pages_save' => '保存页面',
'pages_title' => '页面标题',
'pages_name' => '页面名',
'pages_md_editor' => '编者',
'pages_md_preview' => '预览',
'pages_md_insert_image' => '插入图片',
- 'pages_md_insert_link' => '插入实体链接',
+ 'pages_md_insert_link' => '插入项目链接',
'pages_md_insert_drawing' => '插入图表',
'pages_not_in_chapter' => '本页面不在某章节中',
'pages_move' => '移动页面',
'page_custom_home_deletion' => '无法删除一个被设置为主页的页面',
// Entities
- 'entity_not_found' => '未找到实体',
+ 'entity_not_found' => '未找到项目',
'bookshelf_not_found' => '未找到书架',
'book_not_found' => '未找到图书',
'page_not_found' => '未找到页面',
// Webhooks
'webhooks' => 'Webhooks',
'webhooks_create' => '新建 Webhook',
- 'webhooks_none_created' => '尚未创建任何 webhook',
+ 'webhooks_none_created' => '尚未创建任何 Webhook。',
'webhooks_edit' => '编辑 Webhook',
'webhooks_save' => '保存 Webhook',
'webhooks_details' => 'Webhook 详情',
- 'webhooks_details_desc' => '提供一个用户友好的名称和一个 POST endpoint 作为 webhook 数据发送的位置。',
+ 'webhooks_details_desc' => '提供一个用户友好的名称和一个 POST Endpoint 作为 Webhook 数据发送的位置。',
'webhooks_events' => 'Webhook 事件',
- 'webhooks_events_desc' => '选择所有应触发此 webhook 的事件。',
- 'webhooks_events_warning' => '请记住,即使应用了自定义权限,所有选定的事件也仍然会被触发。 确保使用此 webhook 不会泄露机密内容。',
+ 'webhooks_events_desc' => '选择所有应触发此 Webhook 的事件。',
+ 'webhooks_events_warning' => '请记住,即使应用了自定义权限,所有选定的事件也仍然会被触发。 确保使用此 Webhook 不会泄露机密内容。',
'webhooks_events_all' => '所有系统事件',
'webhooks_name' => 'Webhook 名称',
'webhooks_timeout' => 'Webhook 请求超时(秒)',
'webhooks_delete_warning' => '这将会从系统中完全删除名为 “:webhookName” 的 webhook。',
'webhooks_delete_confirm' => '您确定要删除此 Webhook 吗?',
'webhooks_format_example' => 'Webhook 格式示例',
- 'webhooks_format_example_desc' => 'Webhook 数据会用 POST 请求按照以下 JSON 格式发送到设置的 endpoint。 “related_item” 和 “url” 属性是可选的,取决于触发的事件类型。',
+ 'webhooks_format_example_desc' => 'Webhook 数据会以 POST 请求按照以下 JSON 格式发送到设置的 Endpoint。 “related_item” 和 “url” 属性是可选的,取决于触发的事件类型。',
'webhooks_status' => 'Webhook 状态',
'webhooks_last_called' => '最后一次调用:',
'webhooks_last_errored' => '最后一个错误:',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
+ 'fa' => 'فارسی',
'fr' => 'Français',
'he' => '希伯來語',
'hr' => 'Hrvatski',
@include lightDark(background-color, #FFF, #222);
box-shadow: $bs-card;
border-radius: 3px;
- border: 1px solid transparent;
.body, p.empty-text {
padding: $-m;
}
+
// System wide notifications
[notification] {
position: fixed;
}
}
-[chapter-toggle] {
+.chapter-contents-toggle {
cursor: pointer;
margin: 0;
transition: all ease-in-out 180ms;
transform: rotate(90deg);
}
svg[data-icon="caret-right"] + * {
- margin-inline-start: $-xs;
+ margin-inline-start: $-xxs;
}
}
}
}
-.popup-footer button, .popup-header-close {
- position: absolute;
- top: 0;
- right: 0;
+.popup-header button, .popup-footer button {
margin: 0;
- height: 40px;
border-radius: 0;
box-shadow: none;
- &:active {
- outline: 0;
+ color: #FFF;
+ padding: $-xs $-m;
+}
+
+.popup-header button:not(.popup-header-close) {
+ font-size: 0.8rem;
+}
+
+.popup-header button:hover {
+ background-color: rgba(255, 255, 255, 0.1);
+}
+
+.popup-footer {
+ justify-content: end;
+ background-color: var(--color-primary-light);
+ min-height: 41px;
+ button {
+ padding: 10px $-m;
}
}
+
.popup-header-close {
- background-color: transparent;
border: 0;
color: #FFF;
font-size: 16px;
- padding: 0 $-m;
+ cursor: pointer;
+ svg {
+ margin-right: 0;
+ }
}
.popup-header, .popup-footer {
- display: block !important;
+ display: flex;
position: relative;
height: 40px;
- flex: none !important;
+ flex: 0;
.popup-title {
color: #FFF;
+ margin-right: auto;
padding: 8px $-m;
}
+ &.flex-container-row {
+ display: flex !important;
+ }
}
body.flexbox-support #entity-selector-wrap .popup-body .form-group {
height: 444px;
}
}
-.image-manager .corner-button {
- margin: 0;
- border-radius: 0;
- padding: $-m;
-}
-
// Dropzone
/*
* The MIT License
}
.code-editor .CodeMirror {
- height: 400px;
+ height: auto;
+ min-height: 50vh;
+ border-bottom: 0;
}
.code-editor .lang-options {
- max-width: 540px;
- margin-bottom: $-s;
- a {
- margin-inline-end: $-xs;
- text-decoration: underline;
+ overflow-y: scroll;
+ flex-basis: 200px;
+ flex-grow: 1;
+}
+
+.code-editor .lang-options button {
+ display: block;
+ padding: $-xs $-m;
+ border-bottom: 1px solid;
+ @include lightDark(color, #333, #AAA);
+ @include lightDark(border-bottom-color, #EEE, #000);
+ cursor: pointer;
+ width: 100%;
+ text-align: left;
+ font-family: $mono;
+ font-size: 0.7rem;
+ &:hover, &.active {
+ background-color: var(--color-primary-light);
+ color: var(--color-primary);
}
}
-@include smaller-than($m) {
- .code-editor .lang-options {
+.code-editor label {
+ background-color: var(--color-primary-light);
+ width: 100%;
+ color: var(--color-primary);
+ padding: $-xxs $-m;
+ margin-bottom: 0;
+}
+
+.code-editor-language-list {
+ position: relative;
+ width: 160px;
+ z-index: 2;
+ align-items: stretch;
+}
+
+.code-editor-language-list input {
+ border-radius: 0;
+ border: 0;
+ border-bottom: 1px solid #DDD;
+ padding: $-xs $-m;
+}
+
+.code-editor-main {
+ flex: 1;
+ min-width: 0;
+ .CodeMirror {
+ margin-bottom: 0;
+ z-index: 1;
max-width: 100%;
+ width: 100%;
+ }
+}
+
+@include smaller-than($s) {
+ .code-editor .lang-options {
+ display: none;
+ }
+ .code-editor-body-wrap {
+ flex-direction: column;
}
- .code-editor .CodeMirror {
- height: 200px;
+ .code-editor-language-list, .code-editor-language-list input {
+ width: 100%;
}
}
}
}
+
+.dropdown-search {
+ position: relative;
+}
+.dropdown-search-toggle-breadcrumb {
+ border: 1px solid transparent;
+ border-radius: 4px;
+ line-height: normal;
+ padding: $-xs;
+ &:hover {
+ border-color: #DDD;
+ }
+ .svg-icon {
+ margin-inline-end: 0;
+ }
+}
+.dropdown-search-toggle-select {
+ display: flex;
+ gap: $-s;
+ line-height: normal;
+ .svg-icon {
+ height: 16px;
+ margin: 0;
+ }
+ .avatar {
+ height: 22px;
+ width: 22px;
+ }
+ .avatar + span {
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .dropdown-search-toggle-caret {
+ font-size: 1.15rem;
+ }
+}
+.dropdown-search-toggle-select-label {
+ min-width: 0;
+ white-space: nowrap;
+}
+.dropdown-search-toggle-select-caret {
+ font-size: 1.5rem;
+ line-height: 0;
+ margin-left: auto;
+ margin-top: -2px;
+}
+
.dropdown-search-dropdown {
box-shadow: $bs-med;
overflow: hidden;
display: none;
position: absolute;
z-index: 80;
- right: -$-m;
+ right: 0;
+ top: 0;
+ margin-top: $-m;
@include rtl {
right: auto;
left: -$-m;
text-decoration: none;
}
}
- input {
+ input, input:focus {
padding-inline-start: $-xl;
border-radius: 0;
border: 0;
border-bottom: 1px solid #DDD;
}
+ input:focus {
+ outline: 0;
+ }
}
@include smaller-than($m) {
.dropdown-search-dropdown .dropdown-search-list {
max-height: 240px;
}
-}
-
-.custom-select-input {
- max-width: 280px;
- border: 1px solid #D4D4D4;
- border-radius: 3px;
}
\ No newline at end of file
@include lightDark(color, #666, #AAA);
display: inline-block;
font-size: $fs-m;
- padding: $-xs*1.5;
+ padding: $-xs*1.8;
+ height: 40px;
width: 250px;
max-width: 100%;
}
}
-.inline-input-style {
+.title-input input[type="text"] {
display: block;
width: 100%;
padding: $-s;
-}
-
-.title-input input[type="text"] {
- @extend .inline-input-style;
margin-top: 0;
font-size: 2em;
+ height: auto;
}
.title-input.page-title {
max-width: 840px;
margin: 0 auto;
border: none;
+ height: auto;
}
}
}
.description-input textarea {
- @extend .inline-input-style;
+ display: block;
+ width: 100%;
+ padding: $-s;
font-size: $fs-m;
color: #666;
- width: 100%;
+ height: auto;
}
div[editor-type="markdown"] .title-input.page-title input[type="text"] {
}
input {
display: block;
+ padding: $-xs * 1.5;
padding-inline-start: $-l + 4px;
width: 300px;
max-width: 100%;
+ height: auto;
}
&.flexible input {
width: 100%;
color: rgb(250, 250, 250);
border-bottom: 1px solid #DDD;
box-shadow: $bs-card;
- padding: $-xxs 0;
@include lightDark(border-bottom-color, #DDD, #000);
@include whenDark {
filter: saturate(0.8) brightness(0.8);
}
+ .header-links {
+ display: flex;
+ align-items: center;
+ justify-content: end;
+ }
.links {
display: inline-block;
vertical-align: top;
}
.links a {
display: inline-block;
- padding: $-m;
+ padding: 10px $-m;
color: #FFF;
+ border-radius: 3px;
+ }
+ .links a:hover {
+ text-decoration: none;
+ background-color: rgba(255, 255, 255, .15);
}
.dropdown-container {
padding-inline-start: $-m;
.user-name {
vertical-align: top;
position: relative;
- display: inline-block;
+ display: inline-flex;
+ align-items: center;
cursor: pointer;
- > * {
- vertical-align: top;
- }
+ padding: $-s;
+ margin: 0 (-$-s);
+ border-radius: 3px;
+ gap: $-xs;
> span {
padding-inline-start: $-xs;
display: inline-block;
- padding-top: $-xxs;
+ line-height: 1;
}
> svg {
- padding-top: 4px;
font-size: 18px;
+ margin-top: -2px;
+ margin-inline-end: 0;
+ }
+ &:hover {
+ background-color: rgba(255, 255, 255, 0.15);
}
@include between($l, $xl) {
padding-inline-start: $-xs;
header .search-box {
display: inline-block;
- margin-top: 10px;
input {
background-color: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 40px;
color: #EEE;
z-index: 2;
+ height: auto;
+ padding: $-xs*1.5;
padding-inline-start: 40px;
&:focus {
outline: none;
- border: 1px solid rgba(255, 255, 255, 0.6);
+ border: 1px solid rgba(255, 255, 255, 0.4);
}
}
button {
z-index: 1;
left: 16px;
+ top: 10px;
+ color: #FFF;
+ opacity: 0.6;
@include lightDark(color, rgba(255, 255, 255, 0.8), #AAA);
@include rtl {
left: auto;
margin-block-end: 0;
}
}
- ::-webkit-input-placeholder { /* Chrome/Opera/Safari */
- color: #DDD;
- }
- ::-moz-placeholder { /* Firefox 19+ */
- color: #DDD;
+ input::placeholder {
+ color: #FFF;
+ opacity: 0.6;
}
@include between($l, $xl) {
max-width: 200px;
}
+ &:focus-within button {
+ opacity: 1;
+ }
}
.logo {
- display: inline-block;
+ display: inline-flex;
+ padding: ($-s - 6px) $-s;
+ margin: 6px (-$-s);
+ gap: $-s;
+ align-items: center;
+ border-radius: 4px;
&:hover {
color: #FFF;
text-decoration: none;
+ background-color: rgba(255, 255, 255, .15);
}
}
+
.logo-text {
- display: inline-block;
font-size: 1.8em;
color: #fff;
font-weight: 400;
- @include padding(14px, $-l, 14px, 0);
- vertical-align: top;
line-height: 1;
}
.logo-image {
- @include margin($-xs, $-s, $-xs, 0);
- vertical-align: top;
height: 43px;
}
overflow: hidden;
position: absolute;
box-shadow: $bs-hover;
- margin-top: -$-xs;
+ margin-top: $-m;
+ padding: $-xs 0;
&.show {
display: block;
}
}
header .links a, header .dropdown-container ul li a, header .dropdown-container ul li button {
text-align: start;
- display: block;
- padding: $-s $-m;
+ display: grid;
+ align-items: center;
+ padding: 8px $-m;
+ gap: $-m;
color: $text-dark;
+ grid-template-columns: 16px auto;
+ line-height: 1.4;
@include lightDark(color, $text-dark, #eee);
svg {
margin-inline-end: $-s;
+ width: 16px;
}
&:hover {
- @include lightDark(background-color, #eee, #333);
- @include lightDark(color, #000, #fff);
+ background-color: var(--color-primary-light);
+ color: var(--color-primary);
text-decoration: none;
}
&:focus {
}
}
-.dropdown-search {
- position: relative;
- .dropdown-search-toggle {
- padding: $-xs;
- border: 1px solid transparent;
- border-radius: 4px;
- &:hover {
- border-color: #DDD;
- }
- }
- .svg-icon {
- margin-inline-end: 0;
- }
-}
-
-.dropdown-search-toggle.compact {
- padding: $-xxs $-xs;
- .avatar {
- height: 22px;
- width: 22px;
- }
-}
-
.faded {
a, button, span, span > div {
color: #666;
}
}
+.gap-m {
+ gap: $-m;
+}
+
+.justify-flex-start {
+ justify-content: flex-start;
+}
.justify-flex-end {
justify-content: flex-end;
}
}
@include larger-than($xxl) {
.tri-layout-left-contents, .tri-layout-right-contents {
- padding: $-m;
+ padding: $-xl $-m;
position: sticky;
- top: $-m;
+ top: 0;
max-height: 100vh;
min-height: 50vh;
overflow-y: scroll;
justify-self: stretch;
align-self: stretch;
height: auto;
- margin-inline-end: $-l;
+ margin-inline-end: $-xs;
}
.icon:after {
opacity: 0.5;
> .content {
flex: 1;
}
- .chapter-expansion-toggle {
+ .chapter-contents-toggle {
border-radius: 0 4px 4px 0;
- padding: $-xs $-m;
+ padding: $-xs ($-m + $-xxs);
width: 100%;
text-align: start;
}
- .chapter-expansion-toggle:hover {
+ .chapter-contents-toggle:hover {
background-color: rgba(0, 0, 0, 0.06);
}
}
@include margin($-xs, -$-s, 0, -$-s);
padding-inline-start: 0;
padding-inline-end: 0;
- position: relative;
-
- &:after, .sub-menu:after {
- content: '';
- display: block;
- position: absolute;
- left: $-m;
- top: 1rem;
- bottom: 1rem;
- border-inline-start: 4px solid rgba(0, 0, 0, 0.1);
- z-index: 0;
- @include rtl {
- left: auto;
- right: $-m;
- }
- }
ul {
list-style: none;
}
.entity-list-item {
- padding-top: $-xxs;
- padding-bottom: $-xxs;
+ padding-top: 2px;
+ padding-bottom: 2px;
background-clip: content-box;
border-radius: 0 3px 3px 0;
padding-inline-end: 0;
.content {
+ width: 100%;
padding-top: $-xs;
padding-bottom: $-xs;
max-width: calc(100% - 20px);
}
}
.entity-list-item.selected {
- @include lightDark(background-color, rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.08));
+ @include lightDark(background-color, rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.06));
}
.entity-list-item.no-hover {
margin-top: -$-xs;
margin-top: -.2rem;
margin-inline-start: -1rem;
}
- [chapter-toggle] {
- padding-inline-start: .7rem;
- padding-bottom: .2rem;
+ .chapter-contents-toggle {
+ display: block;
+ width: 100%;
+ text-align: left;
+ padding: $-xxs $-s ($-xxs * 2) $-s;
+ border-radius: 0 3px 3px 0;
+ line-height: 1;
+ margin-top: -$-xxs;
+ margin-bottom: -$-xxs;
+ &:hover {
+ @include lightDark(background-color, rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.06));
+ }
}
.entity-list-item .icon {
z-index: 2;
align-self: stretch;
flex-shrink: 0;
border-radius: 1px;
- opacity: 0.6;
+ opacity: 0.8;
}
.entity-list-item .icon:after {
opacity: 1;
}
}
-.chapter-child-menu {
- ul.sub-menu {
- display: none;
- padding-inline-start: 0;
- position: relative;
- }
- [chapter-toggle].open + .sub-menu {
- display: block;
- }
+.chapter-child-menu ul.sub-menu {
+ display: none;
+ padding-inline-start: 0;
+ position: relative;
+ margin-bottom: 0;
}
// Sortable Lists
padding: $-s $-m;
display: flex;
align-items: center;
+ gap: $-m;
background-color: transparent;
border: 0;
width: 100%;
color: #666;
}
> span:first-child {
- margin-inline-end: $-m;
flex-basis: 1.88em;
flex: none;
}
cursor: pointer;
}
&:not(.no-hover):hover {
+ @include lightDark(background-color, rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.06));
text-decoration: none;
- background-color: rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
&.outline-hover:hover {
}
}
-.card .entity-list-item:not(.no-hover):hover {
- @include lightDark(background-color, #F2F2F2, #2d2d2d)
+.split-icon-list-item {
+ display: flex;
+ align-items: center;
+ gap: $-m;
+ background-color: transparent;
+ border: 0;
+ width: 100%;
+ position: relative;
+ word-break: break-word;
+ border-radius: 4px;
+ > a {
+ padding: $-s $-m;
+ display: flex;
+ align-items: center;
+ gap: $-m;
+ flex: 1;
+ }
+ > a:hover {
+ text-decoration: none;
+ }
+ .icon {
+ flex-basis: 1.88em;
+ flex: none;
+ }
+ &:hover {
+ @include lightDark(background-color, rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.06));
+ }
+}
+
+.icon-list-item-dropdown {
+ margin-inline-start: auto;
+ align-self: stretch;
+ display: flex;
+ align-items: stretch;
+ border-inline-start: 1px solid rgba(0, 0, 0, .1);
+ visibility: hidden;
+}
+.split-icon-list-item:hover .icon-list-item-dropdown,
+.split-icon-list-item:focus-within .icon-list-item-dropdown {
+ visibility: visible;
+}
+.icon-list-item-dropdown-toggle {
+ padding: $-xs;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ @include lightDark(color, #888, #999);
+ svg {
+ margin: 0;
+ }
+ &:hover {
+ @include lightDark(background-color, rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.06));
+ }
+}
+
+.card .entity-list-item:not(.no-hover, .book-contents .entity-list-item):hover {
+ @include lightDark(background-color, #F2F2F2, #2d2d2d);
+ border-radius: 0;
}
.card .entity-list-item .entity-list-item:hover {
background-color: #EEEEEE;
}
.entity-list-item-children {
- padding: $-m;
+ padding: $-m $-l;
> div {
overflow: hidden;
- padding: $-xs 0;
- margin-top: -$-xs;
+ padding: 0 0 $-xs 0;
}
.entity-chip {
text-overflow: ellipsis;
display: block;
white-space: nowrap;
}
+ > .entity-list > .entity-list-item:last-child {
+ margin-bottom: -$-xs;
+ }
}
.entity-list-item-image {
font-size: $fs-m * 0.8;
padding-top: $-xs;
}
+ .entity-list-item p:empty {
+ padding-top: 0;
+ }
p {
margin: 0;
}
right: 0;
margin: $-m 0;
@include lightDark(background-color, #fff, #333);
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18);
- border-radius: 1px;
+ box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.18);
+ border-radius: 3px;
min-width: 180px;
padding: $-xs 0;
@include lightDark(color, #555, #eee);
}
}
+// Shift in sidebar dropdown menus to prevent shadows
+// being cut by scrollable container.
+.tri-layout-right .dropdown-menu,
+.tri-layout-left .dropdown-menu {
+ right: $-xs;
+}
+
// Books grid view
.featured-image-container {
position: relative;
}
}
}
+
+.entity-meta-item {
+ display: flex;
+ line-height: 1.2;
+ margin: 0.6em 0;
+ align-content: start;
+ gap: $-s;
+ a {
+ line-height: 1.2;
+ }
+ svg {
+ flex-shrink: 0;
+ width: 1em;
+ margin: 0;
+ }
+}
}
}
-.entity-list-item > span:first-child, .icon-list-item > span:first-child, .chapter-expansion > .icon {
+.entity-list-item > span:first-child,
+.icon-list-item > span:first-child,
+.split-icon-list-item > a > .icon,
+.chapter-expansion > .icon {
font-size: 0.8rem;
width: 1.88em;
height: 1.88em;
+ flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.chapter-hint + h1 {
margin-top: 0;
+}
+
+// PDF specific overrides
+body.export-format-pdf {
+ font-size: 14px;
+ line-height: 1.2;
+
+ h1, h2, h3, h4, h5, h6 {
+ line-height: 1.2;
+ }
+
+ table {
+ max-width: 800px !important;
+ font-size: 0.8em;
+ width: 100% !important;
+ }
+
+ table td {
+ width: auto !important;
+ }
+
+ .page-content .float {
+ float: none !important;
+ }
+
+ .page-content img.align-left, .page-content img.align-right {
+ float: none !important;
+ clear: both;
+ display: block;
+ }
+
+}
+
+// DOMPDF pdf export specific overrides
+body.export-format-pdf.export-engine-dompdf {
+ // Fix for full width linked image sizes on DOMPDF
+ .page-content a > img {
+ max-width: 700px;
+ }
+ // Undoes the above for table images to prevent visually worse scenario, Awaiting next DOMPDF release for patch
+ .page-content td a > img {
+ max-width: 100%;
+ }
}
\ No newline at end of file
animation-timing-function: cubic-bezier(.62, .28, .23, .99);
margin-inline-end: 4px;
background-color: var(--color-page);
- animation-delay: 0.3s;
+ animation-delay: -300ms;
}
> div:first-child {
left: -($loadingSize+$-xs);
background-color: var(--color-book);
- animation-delay: 0s;
+ animation-delay: -600ms;
}
> div:last-of-type {
left: $loadingSize+$-xs;
background-color: var(--color-chapter);
- animation-delay: 0.6s;
+ animation-delay: 0ms;
}
> span {
margin-inline-start: $-s;
.skip-to-content-link {
position: fixed;
- top: -$-xxl;
+ top: -52px;
left: 0;
background-color: #FFF;
z-index: 15;
<div class="mb-xs"><a href="#request-format">Request Format</a></div>
<div class="mb-xs"><a href="#listing-endpoints">Listing Endpoints</a></div>
<div class="mb-xs"><a href="#error-handling">Error Handling</a></div>
+ <div class="mb-xs"><a href="#rate-limits">Rate Limits</a></div>
</div>
@foreach($docs as $model => $endpoints)
"message": "No authorization token found on the request"
}
}
-</code></pre>
\ No newline at end of file
+</code></pre>
+
+<hr>
+
+<h5 id="rate-limits" class="text-mono mb-m">Rate Limits</h5>
+<p>
+ The API has built-in per-user rate-limiting to prevent potential abuse using the API.
+ By default, this is set to 180 requests per minute but this can be changed by an administrator
+ by setting an "API_REQUESTS_PER_MIN" .env option like so:
+</p>
+
+<pre><code class="language-bash"># The number of API requests that can be made per minute by a single user.
+API_REQUESTS_PER_MIN=180</code></pre>
+
+<p>
+ When the limit is reached you will receive a 429 "Too Many Attempts." error response.
+ It's generally good practice to limit requests made from your API client, where possible, to avoid
+ affecting normal use of the system caused by over-consuming system resources.
+ Keep in mind there may be other rate-limiting factors such as web-server & firewall controls.
+</p>
\ No newline at end of file
<div component="attachments-list">
@foreach($attachments as $attachment)
<div class="attachment icon-list">
- <a class="icon-list-item py-xs attachment-{{ $attachment->external ? 'link' : 'file' }}" href="{{ $attachment->getUrl() }}" @if($attachment->external) target="_blank" @endif>
- <span class="icon">@icon($attachment->external ? 'export' : 'file')</span>
- <span>{{ $attachment->name }}</span>
- </a>
+ <div class="split-icon-list-item attachment-{{ $attachment->external ? 'link' : 'file' }}">
+ <a href="{{ $attachment->getUrl() }}" @if($attachment->external) target="_blank" @endif>
+ <div class="icon">@icon($attachment->external ? 'export' : 'file')</div>
+ <div class="label">{{ $attachment->name }}</div>
+ </a>
+ @if(!$attachment->external)
+ <div component="dropdown" class="icon-list-item-dropdown">
+ <button refs="dropdown@toggle" type="button" class="icon-list-item-dropdown-toggle">@icon('caret-down')</button>
+ <ul refs="dropdown@menu" class="dropdown-menu" role="menu">
+ <a href="{{ $attachment->getUrl(false) }}" class="icon-item">
+ @icon('download')
+ <div>{{ trans('common.download') }}</div>
+ </a>
+ <a href="{{ $attachment->getUrl(true) }}" target="_blank" class="icon-item">
+ @icon('export')
+ <div>{{ trans('common.open_in_tab') }}</div>
+ </a>
+ </ul>
+ </div>
+ @endif
+ </div>
</div>
@endforeach
</div>
\ No newline at end of file
]])
</div>
- <main class="content-wrap card">
+ <main class="content-wrap card auto-height">
<h1 class="list-heading">{{ trans('entities.books_edit') }}</h1>
<form action="{{ $book->getUrl() }}" method="POST" enctype="multipart/form-data">
<input type="hidden" name="_method" value="PUT">
@include('books.parts.form', ['model' => $book, 'returnLocation' => $book->getUrl()])
</form>
</main>
+
+
+ @if(userCan('book-delete', $book) && userCan('book-create-all') && userCan('bookshelf-create-all'))
+ @include('books.parts.convert-to-shelf', ['book' => $book])
+ @endif
</div>
@stop
\ No newline at end of file
+++ /dev/null
-@extends('layouts.export')
-
-@section('title', $book->name)
-
-@section('content')
- <h1 style="font-size: 4.8em">{{$book->name}}</h1>
-
- <p>{{ $book->description }}</p>
-
- @if(count($bookChildren) > 0)
- <ul class="contents">
- @foreach($bookChildren as $bookChild)
- <li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
- @if($bookChild->isA('chapter') && count($bookChild->visible_pages) > 0)
- <ul>
- @foreach($bookChild->visible_pages as $page)
- <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
- @endforeach
- </ul>
- @endif
- @endforeach
- </ul>
- @endif
-
- @foreach($bookChildren as $bookChild)
- <div class="page-break"></div>
- <h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
-
- @if($bookChild->isA('chapter'))
- <p>{{ $bookChild->description }}</p>
-
- @if(count($bookChild->visible_pages) > 0)
- @foreach($bookChild->visible_pages as $page)
- <div class="page-break"></div>
- <div class="chapter-hint">{{$bookChild->name}}</div>
- <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
- {!! $page->html !!}
- @endforeach
- @endif
-
- @else
- {!! $bookChild->html !!}
- @endif
-
- @endforeach
-@endsection
\ No newline at end of file
--- /dev/null
+<div class="content-wrap card auto-height">
+ <h2 class="list-heading">{{ trans('entities.convert_to_shelf') }}</h2>
+ <p>
+ {{ trans('entities.convert_to_shelf_contents_desc') }}
+ <br><br>
+ {{ trans('entities.convert_to_shelf_permissions_desc') }}
+ </p>
+ <div class="text-right">
+ <div component="dropdown" class="dropdown-container">
+ <button refs="dropdown@toggle" class="button outline" aria-haspopup="true" aria-expanded="false">{{ trans('entities.convert_book') }}</button>
+ <ul refs="dropdown@menu" class="dropdown-menu" role="menu">
+ <li class="px-m py-s text-small text-muted">
+ {{ trans('entities.convert_book_confirm') }}
+ <br>
+ {{ trans('entities.convert_undo_warning') }}
+ </li>
+ <li>
+ <form action="{{ $book->getUrl('/convert-to-shelf') }}" method="POST">
+ {!! csrf_field() !!}
+ <button type="submit" class="text-primary text-item">{{ trans('common.confirm') }}</button>
+ </form>
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
\ No newline at end of file
@section('right')
<div class="mb-xl">
<h5>{{ trans('common.details') }}</h5>
- <div class="text-small text-muted blended-links">
+ <div class="blended-links">
@include('entities.meta', ['entity' => $book])
@if($book->restricted)
<div class="active-restriction">
@if(userCan('restrictions-manage', $book))
- <a href="{{ $book->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.books_permissions_active') }}</a>
+ <a href="{{ $book->getUrl('/permissions') }}" class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.books_permissions_active') }}</div>
+ </a>
@else
- @icon('lock'){{ trans('entities.books_permissions_active') }}
+ <div class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.books_permissions_active') }}</div>
+ </div>
@endif
</div>
@endif
]])
</div>
- <main class="content-wrap card">
+ <main class="content-wrap card auto-height">
<h1 class="list-heading">{{ trans('entities.chapters_edit') }}</h1>
<form action="{{ $chapter->getUrl() }}" method="POST">
<input type="hidden" name="_method" value="PUT">
</form>
</main>
+ @if(userCan('chapter-delete', $chapter) && userCan('book-create-all'))
+ @include('chapters.parts.convert-to-book')
+ @endif
+
</div>
@stop
\ No newline at end of file
+++ /dev/null
-@extends('layouts.export')
-
-@section('title', $chapter->name)
-
-@section('content')
- <h1 style="font-size: 4.8em">{{$chapter->name}}</h1>
-
- <p>{{ $chapter->description }}</p>
-
- @if(count($pages) > 0)
- <ul class="contents">
- @foreach($pages as $page)
- <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
- @endforeach
- </ul>
- @endif
-
- @foreach($pages as $page)
- <div class="page-break"></div>
- <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
- {!! $page->html !!}
- @endforeach
-@endsection
\ No newline at end of file
-<div class="chapter-child-menu">
- <button chapter-toggle type="button" aria-expanded="{{ $isOpen ? 'true' : 'false' }}"
- class="text-muted @if($isOpen) open @endif">
+<div component="chapter-contents" class="chapter-child-menu">
+ <button type="button"
+ refs="chapter-contents@toggle"
+ aria-expanded="{{ $isOpen ? 'true' : 'false' }}"
+ class="text-muted chapter-contents-toggle @if($isOpen) open @endif">
@icon('caret-right') @icon('page') <span>{{ trans_choice('entities.x_pages', $bookChild->visible_pages->count()) }}</span>
</button>
- <ul class="sub-menu inset-list @if($isOpen) open @endif" @if($isOpen) style="display: block;" @endif role="menu">
+ <ul refs="chapter-contents@list"
+ class="chapter-contents-list sub-menu inset-list @if($isOpen) open @endif" @if($isOpen)
+ style="display: block;" @endif
+ role="menu">
@foreach($bookChild->visible_pages as $childPage)
<li class="list-item-page {{ $childPage->isA('page') && $childPage->draft ? 'draft' : '' }}" role="presentation">
@include('entities.list-item-basic', ['entity' => $childPage, 'classes' => $current->matches($childPage)? 'selected' : '' ])
--- /dev/null
+<div class="content-wrap card auto-height">
+ <h2 class="list-heading">{{ trans('entities.convert_to_book') }}</h2>
+ <div class="grid half left-focus no-row-gap">
+ <p>
+ {{ trans('entities.convert_to_book_desc') }}
+ </p>
+ <div class="text-m-right">
+ <div component="dropdown" class="dropdown-container">
+ <button refs="dropdown@toggle" class="button outline" aria-haspopup="true" aria-expanded="false">
+ {{ trans('entities.convert_chapter') }}
+ </button>
+ <ul refs="dropdown@menu" class="dropdown-menu" role="menu">
+ <li class="px-m py-s text-small text-muted">
+ {{ trans('entities.convert_chapter_confirm') }}
+ <br>
+ {{ trans('entities.convert_undo_warning') }}
+ </li>
+ <li>
+ <form action="{{ $chapter->getUrl('/convert-to-book') }}" method="POST">
+ {!! csrf_field() !!}
+ <button type="submit" class="text-primary text-item">{{ trans('common.confirm') }}</button>
+ </form>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+</div>
\ No newline at end of file
<div class="content">
<h4 class="entity-list-item-name break-text">{{ $chapter->name }}</h4>
<div class="entity-item-snippet">
- <p class="text-muted break-text mb-s">{{ $chapter->getExcerpt() }}</p>
+ <p class="text-muted break-text">{{ $chapter->getExcerpt() }}</p>
</div>
</div>
</a>
@if ($chapter->visible_pages->count() > 0)
<div class="chapter chapter-expansion">
<span class="icon text-chapter">@icon('page')</span>
- <div class="content">
- <button type="button" chapter-toggle
+ <div component="chapter-contents" class="content">
+ <button type="button"
+ refs="chapter-contents@toggle"
aria-expanded="false"
- class="text-muted chapter-expansion-toggle">@icon('caret-right') <span>{{ trans_choice('entities.x_pages', $chapter->visible_pages->count()) }}</span></button>
- <div class="inset-list">
+ class="text-muted chapter-contents-toggle">@icon('caret-right') <span>{{ trans_choice('entities.x_pages', $chapter->visible_pages->count()) }}</span></button>
+ <div refs="chapter-contents@list" class="inset-list chapter-contents-list">
<div class="entity-list-item-children">
@include('entities.list', ['entities' => $chapter->visible_pages])
</div>
<div class="mb-xl">
<h5>{{ trans('common.details') }}</h5>
- <div class="blended-links text-small text-muted">
+ <div class="blended-links">
@include('entities.meta', ['entity' => $chapter])
@if($book->restricted)
<div class="active-restriction">
@if(userCan('restrictions-manage', $book))
- <a href="{{ $book->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.books_permissions_active') }}</a>
+ <a href="{{ $book->getUrl('/permissions') }}" class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.books_permissions_active') }}</div>
+ </a>
@else
- @icon('lock'){{ trans('entities.books_permissions_active') }}
+ <div class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.books_permissions_active') }}</div>
+ </div>
@endif
</div>
@endif
@if($chapter->restricted)
<div class="active-restriction">
@if(userCan('restrictions-manage', $chapter))
- <a href="{{ $chapter->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.chapters_permissions_active') }}</a>
+ <a href="{{ $chapter->getUrl('/permissions') }}" class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.chapters_permissions_active') }}</div>
+ </a>
@else
- @icon('lock'){{ trans('entities.chapters_permissions_active') }}
+ <div class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.chapters_permissions_active') }}</div>
+ </div>
@endif
</div>
@endif
<div class="popup-header primary-background">
<div class="popup-title">{{ $title }}</div>
- <button refs="popup@hide" type="button" class="popup-header-close">x</button>
+ <button refs="popup@hide" type="button" class="popup-header-close">@icon('close')</button>
</div>
<div class="px-m py-m">
+++ /dev/null
-<style>
- @if (!app()->runningUnitTests())
- {!! file_get_contents(public_path('/dist/export-styles.css')) !!}
- @endif
-</style>
-
-@if ($format === 'pdf')
- <style>
-
- /* PDF size adjustments */
- body {
- font-size: 14px;
- line-height: 1.2;
- }
-
- h1, h2, h3, h4, h5, h6 {
- line-height: 1.2;
- }
-
- table {
- max-width: 800px !important;
- font-size: 0.8em;
- width: 100% !important;
- }
-
- table td {
- width: auto !important;
- }
-
- /* Patches for CSS variable colors */
- a {
- color: {{ setting('app-color') }};
- }
-
- blockquote {
- border-left-color: {{ setting('app-color') }};
- }
-
- /* Patches for content layout */
- .page-content .float {
- float: none !important;
- }
-
- .page-content img.align-left, .page-content img.align-right {
- float: none !important;
- clear: both;
- display: block;
- }
-
- @if($engine === \BookStack\Entities\Tools\PdfGenerator::ENGINE_DOMPDF)
- {{-- Fix for full width linked image sizes on DOMPDF --}}
- .page-content a > img {
- max-width: 700px;
- }
- {{-- Undoes the above for table images to prevent visually worse scenario, Awaiting next DOMPDF release for patch --}}
- .page-content td a > img {
- max-width: 100%;
- }
- @endif
- </style>
-@endif
\ No newline at end of file
class="mobile-menu-toggle hide-over-l">@icon('more')</button>
</div>
- <div class="flex-container-row justify-center hide-under-l">
+ <div class="flex-container-column items-center justify-center hide-under-l">
@if (hasAppAccess())
<form action="{{ url('/search') }}" method="GET" class="search-box" role="search">
<button id="header-search-box-button" type="submit" aria-label="{{ trans('common.search') }}" tabindex="-1">@icon('search') </button>
@endif
</div>
- <div class="text-right">
- <nav refs="header-mobile-toggle@menu" class="header-links">
- <div class="links text-center">
- @if (hasAppAccess())
- <a class="hide-over-l" href="{{ url('/search') }}">@icon('search'){{ trans('common.search') }}</a>
- @if(userCanOnAny('view', \BookStack\Entities\Models\Bookshelf::class) || userCan('bookshelf-view-all') || userCan('bookshelf-view-own'))
- <a href="{{ url('/shelves') }}">@icon('bookshelf'){{ trans('entities.shelves') }}</a>
- @endif
- <a href="{{ url('/books') }}">@icon('books'){{ trans('entities.books') }}</a>
- @if(signedInUser() && userCan('settings-manage'))
- <a href="{{ url('/settings') }}">@icon('settings'){{ trans('settings.settings') }}</a>
- @endif
- @if(signedInUser() && userCan('users-manage') && !userCan('settings-manage'))
- <a href="{{ url('/settings/users') }}">@icon('users'){{ trans('settings.users') }}</a>
- @endif
+ <nav refs="header-mobile-toggle@menu" class="header-links">
+ <div class="links text-center">
+ @if (hasAppAccess())
+ <a class="hide-over-l" href="{{ url('/search') }}">@icon('search'){{ trans('common.search') }}</a>
+ @if(userCanOnAny('view', \BookStack\Entities\Models\Bookshelf::class) || userCan('bookshelf-view-all') || userCan('bookshelf-view-own'))
+ <a href="{{ url('/shelves') }}">@icon('bookshelf'){{ trans('entities.shelves') }}</a>
@endif
+ <a href="{{ url('/books') }}">@icon('books'){{ trans('entities.books') }}</a>
+ @if(signedInUser() && userCan('settings-manage'))
+ <a href="{{ url('/settings') }}">@icon('settings'){{ trans('settings.settings') }}</a>
+ @endif
+ @if(signedInUser() && userCan('users-manage') && !userCan('settings-manage'))
+ <a href="{{ url('/settings/users') }}">@icon('users'){{ trans('settings.users') }}</a>
+ @endif
+ @endif
- @if(!signedInUser())
- @if(setting('registration-enabled') && config('auth.method') === 'standard')
- <a href="{{ url('/register') }}">@icon('new-user'){{ trans('auth.sign_up') }}</a>
- @endif
- <a href="{{ url('/login') }}">@icon('login'){{ trans('auth.log_in') }}</a>
+ @if(!signedInUser())
+ @if(setting('registration-enabled') && config('auth.method') === 'standard')
+ <a href="{{ url('/register') }}">@icon('new-user'){{ trans('auth.sign_up') }}</a>
@endif
- </div>
- @if(signedInUser())
- <?php $currentUser = user(); ?>
- <div class="dropdown-container" component="dropdown" option:dropdown:bubble-escapes="true">
+ <a href="{{ url('/login') }}">@icon('login'){{ trans('auth.log_in') }}</a>
+ @endif
+ </div>
+ @if(signedInUser())
+ <?php $currentUser = user(); ?>
+ <div class="dropdown-container" component="dropdown" option:dropdown:bubble-escapes="true">
<span class="user-name py-s hide-under-l" refs="dropdown@toggle"
aria-haspopup="true" aria-expanded="false" aria-label="{{ trans('common.profile_menu') }}" tabindex="0">
<img class="avatar" src="{{$currentUser->getAvatar(30)}}" alt="{{ $currentUser->name }}">
<span class="name">{{ $currentUser->getShortName(9) }}</span> @icon('caret-down')
</span>
- <ul refs="dropdown@menu" class="dropdown-menu" role="menu">
- <li>
- <a href="{{ url('/favourites') }}" class="icon-item">
- @icon('star')
- <div>{{ trans('entities.my_favourites') }}</div>
- </a>
- </li>
- <li>
- <a href="{{ $currentUser->getProfileUrl() }}" class="icon-item">
- @icon('user')
- <div>{{ trans('common.view_profile') }}</div>
- </a>
- </li>
- <li>
- <a href="{{ $currentUser->getEditUrl() }}" class="icon-item">
- @icon('edit')
- <div>{{ trans('common.edit_profile') }}</div>
- </a>
- </li>
- <li>
- <form action="{{ url(config('auth.method') === 'saml2' ? '/saml2/logout' : '/logout') }}"
- method="post">
- {{ csrf_field() }}
- <button class="icon-item">
- @icon('logout')
- <div>{{ trans('auth.logout') }}</div>
- </button>
- </form>
- </li>
- <li><hr></li>
- <li>
- @include('common.dark-mode-toggle', ['classes' => 'icon-item'])
- </li>
- </ul>
- </div>
- @endif
- </nav>
- </div>
+ <ul refs="dropdown@menu" class="dropdown-menu" role="menu">
+ <li>
+ <a href="{{ url('/favourites') }}" class="icon-item">
+ @icon('star')
+ <div>{{ trans('entities.my_favourites') }}</div>
+ </a>
+ </li>
+ <li>
+ <a href="{{ $currentUser->getProfileUrl() }}" class="icon-item">
+ @icon('user')
+ <div>{{ trans('common.view_profile') }}</div>
+ </a>
+ </li>
+ <li>
+ <a href="{{ $currentUser->getEditUrl() }}" class="icon-item">
+ @icon('edit')
+ <div>{{ trans('common.edit_profile') }}</div>
+ </a>
+ </li>
+ <li>
+ <form action="{{ url(config('auth.method') === 'saml2' ? '/saml2/logout' : '/logout') }}"
+ method="post">
+ {{ csrf_field() }}
+ <button class="icon-item">
+ @icon('logout')
+ <div>{{ trans('auth.logout') }}</div>
+ </button>
+ </form>
+ </li>
+ <li><hr></li>
+ <li>
+ @include('common.dark-mode-toggle', ['classes' => 'icon-item'])
+ </li>
+ </ul>
+ </div>
+ @endif
+ </nav>
</div>
</header>
option:dropdown-search:url="/search/entity/siblings?entity_type={{$entity->getType()}}&entity_id={{ $entity->id }}"
option:dropdown-search:local-search-selector=".entity-list-item"
>
- <div class="dropdown-search-toggle" refs="dropdown@toggle"
+ <div class="dropdown-search-toggle-breadcrumb" refs="dropdown@toggle"
aria-haspopup="true" aria-expanded="false" tabindex="0">
<div class="separator">@icon('chevron-right')</div>
</div>
<div refs="dropdown-search@loading">
@include('common.loading-icon')
</div>
- <div refs="dropdown-search@listContainer" class="dropdown-search-list px-m"></div>
+ <div refs="dropdown-search@listContainer" class="dropdown-search-list px-m" tabindex="-1"></div>
</div>
</div>
\ No newline at end of file
-<div component="dropdown" class="dropdown-container" id="export-menu">
+<div component="dropdown"
+ class="dropdown-container"
+ id="export-menu">
+
<div refs="dropdown@toggle" class="icon-list-item"
aria-haspopup="true" aria-expanded="false" aria-label="{{ trans('entities.export') }}" tabindex="0">
<span>@icon('export')</span>
<span>{{ trans('entities.export') }}</span>
</div>
+
<ul refs="dropdown@menu" class="wide dropdown-menu" role="menu">
<li><a href="{{ $entity->getUrl('/export/html') }}" target="_blank" class="label-item"><span>{{ trans('entities.export_html') }}</span><span>.html</span></a></li>
<li><a href="{{ $entity->getUrl('/export/pdf') }}" target="_blank" class="label-item"><span>{{ trans('entities.export_pdf') }}</span><span>.pdf</span></a></li>
<li><a href="{{ $entity->getUrl('/export/plaintext') }}" target="_blank" class="label-item"><span>{{ trans('entities.export_text') }}</span><span>.txt</span></a></li>
<li><a href="{{ $entity->getUrl('/export/markdown') }}" target="_blank" class="label-item"><span>{{ trans('entities.export_md') }}</span><span>.md</span></a></li>
</ul>
+
</div>
<div class="entity-meta">
@if($entity->isA('revision'))
- <div>
- @icon('history'){{ trans('entities.pages_revision') }}
- {{ trans('entities.pages_revisions_number') }}{{ $entity->revision_number == 0 ? '' : $entity->revision_number }}
+ <div class="entity-meta-item">
+ @icon('history')
+ <div>
+ {{ trans('entities.pages_revision') }}
+ {{ trans('entities.pages_revisions_number') }}{{ $entity->revision_number == 0 ? '' : $entity->revision_number }}
+ </div>
</div>
@endif
@if ($entity->isA('page'))
- <div>
- @if (userCan('page-update', $entity)) <a href="{{ $entity->getUrl('/revisions') }}"> @endif
- @icon('history'){{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }}
- @if (userCan('page-update', $entity))</a>@endif
- </div>
+ @if (userCan('page-update', $entity)) <a href="{{ $entity->getUrl('/revisions') }}" class="entity-meta-item"> @else <div class="entity-meta-item"> @endif
+ @icon('history'){{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }}
+ @if (userCan('page-update', $entity))</a> @else </div> @endif
@endif
@if ($entity->ownedBy && $entity->owned_by !== $entity->created_by)
- <div>
- @icon('user'){!! trans('entities.meta_owned_name', [
- 'user' => "<a href='{$entity->ownedBy->getProfileUrl()}'>".e($entity->ownedBy->name). "</a>"
- ]) !!}
+ <div class="entity-meta-item">
+ @icon('user')
+ <div>
+ {!! trans('entities.meta_owned_name', [
+ 'user' => "<a href='{$entity->ownedBy->getProfileUrl()}'>".e($entity->ownedBy->name). "</a>"
+ ]) !!}
+ </div>
</div>
@endif
@if ($entity->createdBy)
- <div>
- @icon('star'){!! trans('entities.meta_created_name', [
- 'timeLength' => '<span title="'.$entity->created_at->toDayDateTimeString().'">'.$entity->created_at->diffForHumans() . '</span>',
- 'user' => "<a href='{$entity->createdBy->getProfileUrl()}'>".e($entity->createdBy->name). "</a>"
- ]) !!}
+ <div class="entity-meta-item">
+ @icon('star')
+ <div>
+ {!! trans('entities.meta_created_name', [
+ 'timeLength' => '<span title="'.$entity->created_at->toDayDateTimeString().'">'.$entity->created_at->diffForHumans() . '</span>',
+ 'user' => "<a href='{$entity->createdBy->getProfileUrl()}'>".e($entity->createdBy->name). "</a>"
+ ]) !!}
+ </div>
</div>
@else
- <div>
- @icon('star')<span title="{{$entity->created_at->toDayDateTimeString()}}">{{ trans('entities.meta_created', ['timeLength' => $entity->created_at->diffForHumans()]) }}</span>
+ <div class="entity-meta-item">
+ @icon('star')
+ <span title="{{$entity->created_at->toDayDateTimeString()}}">{{ trans('entities.meta_created', ['timeLength' => $entity->created_at->diffForHumans()]) }}</span>
</div>
@endif
@if ($entity->updatedBy)
- <div>
- @icon('edit'){!! trans('entities.meta_updated_name', [
- 'timeLength' => '<span title="' . $entity->updated_at->toDayDateTimeString() .'">' . $entity->updated_at->diffForHumans() .'</span>',
- 'user' => "<a href='{$entity->updatedBy->getProfileUrl()}'>".e($entity->updatedBy->name). "</a>"
- ]) !!}
+ <div class="entity-meta-item">
+ @icon('edit')
+ <div>
+ {!! trans('entities.meta_updated_name', [
+ 'timeLength' => '<span title="' . $entity->updated_at->toDayDateTimeString() .'">' . $entity->updated_at->diffForHumans() .'</span>',
+ 'user' => "<a href='{$entity->updatedBy->getProfileUrl()}'>".e($entity->updatedBy->name). "</a>"
+ ]) !!}
+ </div>
</div>
@elseif (!$entity->isA('revision'))
- <div>
- @icon('edit')<span title="{{ $entity->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }}</span>
+ <div class="entity-meta-item">
+ @icon('edit')
+ <span title="{{ $entity->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }}</span>
</div>
@endif
</div>
\ No newline at end of file
<div class="popup-body small" tabindex="-1">
<div class="popup-header primary-background">
<div class="popup-title">{{ trans('entities.entity_select') }}</div>
- <button refs="popup@hide" type="button" class="popup-header-close">x</button>
+ <button refs="popup@hide" type="button" class="popup-header-close">@icon('close')</button>
</div>
@include('entities.selector', ['name' => 'entity-selector'])
<div class="popup-footer">
- <button refs="entity-selector-popup@select" type="button" disabled="true" class="button corner-button">{{ trans('common.select') }}</button>
+ <button refs="entity-selector-popup@select" type="button" disabled="true" class="button">{{ trans('common.select') }}</button>
</div>
</div>
</div>
--- /dev/null
+@extends('layouts.export')
+
+@section('title', $book->name)
+
+@section('content')
+
+ <h1 style="font-size: 4.8em">{{$book->name}}</h1>
+ <p>{{ $book->description }}</p>
+
+ @include('exports.parts.book-contents-menu', ['children' => $bookChildren])
+
+ @foreach($bookChildren as $bookChild)
+ @if($bookChild->isA('chapter'))
+ @include('exports.parts.chapter-item', ['chapter' => $bookChild])
+ @else
+ @include('exports.parts.page-item', ['page' => $bookChild, 'chapter' => null])
+ @endif
+ @endforeach
+
+@endsection
\ No newline at end of file
--- /dev/null
+@extends('layouts.export')
+
+@section('title', $chapter->name)
+
+@section('content')
+
+ <h1 style="font-size: 4.8em">{{$chapter->name}}</h1>
+ <p>{{ $chapter->description }}</p>
+
+ @include('exports.parts.chapter-contents-menu', ['pages' => $pages])
+
+ @foreach($pages as $page)
+ @include('exports.parts.page-item', ['page' => $page, 'chapter' => null])
+ @endforeach
+
+@endsection
\ No newline at end of file
<hr>
<div class="text-muted text-small">
- @include('entities.export-meta', ['entity' => $page])
+ @include('exports.parts.meta', ['entity' => $page])
</div>
@endsection
\ No newline at end of file
--- /dev/null
+@if(count($children) > 0)
+ <ul class="contents">
+ @foreach($children as $bookChild)
+ <li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
+ @if($bookChild->isA('chapter') && count($bookChild->visible_pages) > 0)
+ @include('exports.parts.chapter-contents-menu', ['pages' => $bookChild->visible_pages])
+ @endif
+ @endforeach
+ </ul>
+@endif
\ No newline at end of file
--- /dev/null
+@if (count($pages) > 0)
+ <ul class="contents">
+ @foreach($pages as $page)
+ <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
+ @endforeach
+ </ul>
+@endif
\ No newline at end of file
--- /dev/null
+<div class="page-break"></div>
+<h1 id="chapter-{{$chapter->id}}">{{ $chapter->name }}</h1>
+
+<p>{{ $chapter->description }}</p>
+
+@if(count($chapter->visible_pages) > 0)
+ @foreach($chapter->visible_pages as $page)
+ @include('exports.parts.page-item', ['page' => $page, 'chapter' => $chapter])
+ @endforeach
+@endif
\ No newline at end of file
--- /dev/null
+<div class="page-break"></div>
+
+@if (isset($chapter))
+ <div class="chapter-hint">{{$chapter->name}}</div>
+@endif
+
+<h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
+{!! $page->html !!}
\ No newline at end of file
--- /dev/null
+{{-- Fetch in our standard export styles --}}
+<style>
+ @if (!app()->runningUnitTests())
+ {!! file_get_contents(public_path('/dist/export-styles.css')) !!}
+ @endif
+</style>
+
+{{-- Apply any additional styles that can't be applied via our standard SCSS export styles --}}
+@if ($format === 'pdf')
+ <style>
+ /* Patches for CSS variable colors within PDF exports */
+ a {
+ color: {{ setting('app-color') }};
+ }
+
+ blockquote {
+ border-left-color: {{ setting('app-color') }};
+ }
+ </style>
+@endif
\ No newline at end of file
<div>
<div class="form-group">
<label for="owner">{{ trans('entities.permissions_owner') }}</label>
- @include('form.user-select', ['user' => $model->ownedBy, 'name' => 'owned_by', 'compact' => false])
+ @include('form.user-select', ['user' => $model->ownedBy, 'name' => 'owned_by'])
</div>
</div>
</div>
-<div class="dropdown-search custom-select-input" components="dropdown dropdown-search user-select"
+<div class="dropdown-search" components="dropdown dropdown-search user-select"
option:dropdown-search:url="/search/users/select"
>
<input refs="user-select@input" type="hidden" name="{{ $name }}" value="{{ $user->id ?? '' }}">
<div refs="dropdown@toggle"
- class="dropdown-search-toggle {{ $compact ? 'compact' : '' }} flex-container-row items-center"
+ class="dropdown-search-toggle-select input-base"
aria-haspopup="true" aria-expanded="false" tabindex="0">
- <div refs="user-select@user-info" class="flex-container-row items-center px-s">
+ <div refs="user-select@user-info" class="dropdown-search-toggle-select-label flex-container-row items-center">
@if($user)
- <img class="avatar small mr-m" src="{{ $user->getAvatar($compact ? 22 : 30) }}" alt="{{ $user->name }}">
+ <img class="avatar small mr-m" src="{{ $user->getAvatar(30) }}" width="30" height="30" alt="{{ $user->name }}">
<span>{{ $user->name }}</span>
@else
<span>{{ trans('settings.users_none_selected') }}</span>
@endif
</div>
- <span style="font-size: {{ $compact ? '1.15rem' : '1.5rem' }}; margin-left: auto;">
+ <span class="dropdown-search-toggle-select-caret">
@icon('caret-down')
</span>
</div>
</div>
</div>
- <script nonce="{{ $cspNonce }}">
- setTimeout(async () => {
- const result = await window.components["confirm-dialog"][0].show();
- console.log({result});
- }, 1000);
- </script>
-
<div class="container" id="home-default">
<div class="grid third gap-xxl no-row-gap" >
<div>
<meta http-equiv="Content-Security-Policy" content="{{ $cspContent }}">
@endif
- @include('common.export-styles', ['format' => $format, 'engine' => $engine ?? ''])
- @include('common.export-custom-head')
+ @include('exports.parts.styles', ['format' => $format, 'engine' => $engine ?? ''])
+ @include('exports.parts.custom-head')
</head>
-<body>
+<body class="export export-format-{{ $format }} export-engine-{{ $engine ?? 'none' }}">
<div class="page-content">
@yield('content')
</div>
<div refs="tri-layout@container" class="tri-layout-container" @yield('container-attrs') >
- <div class="tri-layout-left print-hidden pt-m" id="sidebar">
+ <div class="tri-layout-left print-hidden" id="sidebar">
<aside class="tri-layout-left-contents">
@yield('left')
</aside>
</div>
</div>
- <div class="tri-layout-right print-hidden pt-m">
+ <div class="tri-layout-right print-hidden">
<aside class="tri-layout-right-contents">
@yield('right')
</aside>
<div components="popup code-editor" class="popup-background code-editor">
<div refs="code-editor@container" class="popup-body" tabindex="-1">
- <div class="popup-header primary-background">
+ <div class="popup-header flex-container-row primary-background">
<div class="popup-title">{{ trans('components.code_editor') }}</div>
- <button class="popup-header-close" refs="popup@hide">x</button>
+ <div component="dropdown" refs="code-editor@historyDropDown" class="flex-container-row">
+ <button refs="dropdown@toggle">
+ <span>@icon('history')</span>
+ <span>{{ trans('components.code_session_history') }}</span>
+ </button>
+ <ul refs="dropdown@menu code-editor@historyList" class="dropdown-menu"></ul>
+ </div>
+ <button class="popup-header-close" refs="popup@hide">@icon('close')</button>
</div>
- <div class="p-l popup-content">
- <div class="form-group">
+ <div class="code-editor-body-wrap flex-container-row flex-fill">
+ <div class="code-editor-language-list flex-container-column flex-fill">
<label for="code-editor-language">{{ trans('components.code_language') }}</label>
+ <input refs="code-editor@languageInput" id="code-editor-language" type="text">
<div class="lang-options">
- <small>
- <a refs="code-editor@languageLink" data-lang="CSS">CSS</a>
- <a refs="code-editor@languageLink" data-lang="C">C</a>
- <a refs="code-editor@languageLink" data-lang="C++">C++</a>
- <a refs="code-editor@languageLink" data-lang="C#">C#</a>
- <a refs="code-editor@languageLink" data-lang="Fortran">Fortran</a>
- <a refs="code-editor@languageLink" data-lang="Go">Go</a>
- <a refs="code-editor@languageLink" data-lang="HTML">HTML</a>
- <a refs="code-editor@languageLink" data-lang="INI">INI</a>
- <a refs="code-editor@languageLink" data-lang="Java">Java</a>
- <a refs="code-editor@languageLink" data-lang="JavaScript">JavaScript</a>
- <a refs="code-editor@languageLink" data-lang="JSON">JSON</a>
- <a refs="code-editor@languageLink" data-lang="Lua">Lua</a>
- <a refs="code-editor@languageLink" data-lang="MarkDown">MarkDown</a>
- <a refs="code-editor@languageLink" data-lang="Nginx">Nginx</a>
- <a refs="code-editor@languageLink" data-lang="PASCAL">Pascal</a>
- <a refs="code-editor@languageLink" data-lang="Perl">Perl</a>
- <a refs="code-editor@languageLink" data-lang="PHP">PHP</a>
- <a refs="code-editor@languageLink" data-lang="Powershell">Powershell</a>
- <a refs="code-editor@languageLink" data-lang="Python">Python</a>
- <a refs="code-editor@languageLink" data-lang="Ruby">Ruby</a>
- <a refs="code-editor@languageLink" data-lang="shell">Shell/Bash</a>
- <a refs="code-editor@languageLink" data-lang="SQL">SQL</a>
- <a refs="code-editor@languageLink" data-lang="VBScript">VBScript</a>
- <a refs="code-editor@languageLink" data-lang="VB.NET">VB.NET</a>
- <a refs="code-editor@languageLink" data-lang="XML">XML</a>
- <a refs="code-editor@languageLink" data-lang="YAML">YAML</a>
- </small>
+ <button type="button" refs="code-editor@languageLink" data-lang="CSS">CSS</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="C">C</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="C++">C++</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="C#">C#</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="diff">Diff</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Fortran">Fortran</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="F#">F#</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Go">Go</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Haskell">Haskell</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="HTML">HTML</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="INI">INI</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Java">Java</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="JavaScript">JavaScript</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="JSON">JSON</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Julia">Julia</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="kotlin">Kotlin</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="LaTeX">LaTeX</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Lua">Lua</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="MarkDown">MarkDown</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Nginx">Nginx</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="ocaml">OCaml</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="PASCAL">Pascal</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Perl">Perl</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="PHP">PHP</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Powershell">Powershell</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Python">Python</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="Ruby">Ruby</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="rust">Rust</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="shell">Shell/Bash</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="SQL">SQL</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="typescript">TypeScript</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="VBScript">VBScript</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="VB.NET">VB.NET</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="XML">XML</button>
+ <button type="button" refs="code-editor@languageLink" data-lang="YAML">YAML</button>
</div>
- <input refs="code-editor@languageInput" id="code-editor-language" type="text">
</div>
- <div class="form-group">
- <div class="grid half no-break v-end mb-xs">
- <div>
- <label for="code-editor-content">{{ trans('components.code_content') }}</label>
- </div>
- <div class="text-right">
- <div component="dropdown" refs="code-editor@historyDropDown" class="inline block">
- <button refs="dropdown@toggle" class="text-button text-small">@icon('history') {{ trans('components.code_session_history') }}</button>
- <ul refs="dropdown@menu code-editor@historyList" class="dropdown-menu"></ul>
- </div>
- </div>
- </div>
-
- <div class="clearfix"></div>
+ <div class="code-editor-main flex-fill">
<textarea refs="code-editor@editor"></textarea>
</div>
- <div class="form-group">
- <button refs="code-editor@saveButton" type="button" class="button">{{ trans('components.code_save') }}</button>
- </div>
+ </div>
+ <div class="popup-footer">
+ <button refs="code-editor@saveButton" type="button" class="button">{{ trans('components.code_save') }}</button>
</div>
</div>
</div>
<div class="action-buttons px-m py-xs">
- <div component="dropdown" dropdown-move-menu class="dropdown-container">
+ <div component="dropdown"
+ option:dropdown:move-menu="true"
+ class="dropdown-container">
<button refs="dropdown@toggle" type="button" aria-haspopup="true" aria-expanded="false" class="text-primary text-button">@icon('edit') <span refs="page-editor@changelogDisplay">{{ trans('entities.pages_edit_set_changelog') }}</span></button>
<ul refs="dropdown@menu" class="wide dropdown-menu">
<li class="px-l py-m">
<div class="popup-header primary-background">
<div class="popup-title">{{ trans('components.image_select') }}</div>
- <button refs="popup@hide" type="button" class="popup-header-close">x</button>
+ <button refs="popup@hide" type="button" class="popup-header-close">@icon('close')</button>
</div>
<div class="flex-fill image-manager-body">
</div>
<div refs="image-manager@formContainer" class="inner flex"></div>
-
- <button refs="image-manager@selectButton" type="button" class="hidden button corner-button">
- {{ trans('components.image_select_image') }}
- </button>
</div>
</div>
+ <div class="popup-footer">
+ <button refs="image-manager@selectButton" type="button" class="hidden button">
+ {{ trans('components.image_select_image') }}
+ </button>
+ </div>
+
</div>
</div>
</div>
\ No newline at end of file
@section('right')
<div id="page-details" class="entity-details mb-xl">
<h5>{{ trans('common.details') }}</h5>
- <div class="body text-small blended-links">
+ <div class="blended-links">
@include('entities.meta', ['entity' => $page])
@if($book->restricted)
<div class="active-restriction">
@if(userCan('restrictions-manage', $book))
- <a href="{{ $book->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.books_permissions_active') }}</a>
+ <a href="{{ $book->getUrl('/permissions') }}" class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.books_permissions_active') }}</div>
+ </a>
@else
- @icon('lock'){{ trans('entities.books_permissions_active') }}
+ <div class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.books_permissions_active') }}</div>
+ </div>
@endif
</div>
@endif
@if($page->chapter && $page->chapter->restricted)
<div class="active-restriction">
@if(userCan('restrictions-manage', $page->chapter))
- <a href="{{ $page->chapter->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.chapters_permissions_active') }}</a>
+ <a href="{{ $page->chapter->getUrl('/permissions') }}" class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.chapters_permissions_active') }}</div>
+ </a>
@else
- @icon('lock'){{ trans('entities.chapters_permissions_active') }}
+ <div class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.chapters_permissions_active') }}</div>
+ </div>
@endif
</div>
@endif
@if($page->restricted)
<div class="active-restriction">
@if(userCan('restrictions-manage', $page))
- <a href="{{ $page->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.pages_permissions_active') }}</a>
+ <a href="{{ $page->getUrl('/permissions') }}" class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.pages_permissions_active') }}</div>
+ </a>
@else
- @icon('lock'){{ trans('entities.pages_permissions_active') }}
+ <div class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.pages_permissions_active') }}</div>
+ </div>
@endif
</div>
@endif
@if($page->template)
- <div>
- @icon('template'){{ trans('entities.pages_is_template') }}
+ <div class="entity-meta-item">
+ @icon('template')
+ <div>{{ trans('entities.pages_is_template') }}</div>
</div>
@endif
</div>
<h1 class="list-heading">{{ trans('settings.audit') }}</h1>
<p class="text-muted">{{ trans('settings.audit_desc') }}</p>
- <div class="flex-container-row">
- <div component="dropdown" class="list-sort-type dropdown-container mr-m">
+ <form action="{{ url('/settings/audit') }}" method="get" class="flex-container-row wrap justify-flex-start gap-m">
+
+ <div component="dropdown" class="list-sort-type dropdown-container">
<label for="">{{ trans('settings.audit_event_filter') }}</label>
<button refs="dropdown@toggle" aria-haspopup="true" aria-expanded="false" aria-label="{{ trans('common.sort_options') }}" class="input-base text-left">{{ $listDetails['event'] ?: trans('settings.audit_event_filter_no_filter') }}</button>
<ul refs="dropdown@menu" class="dropdown-menu">
</ul>
</div>
- <form action="{{ url('/settings/audit') }}" method="get" class="flex-container-row mr-m">
- @if(!empty($listDetails['event']))
- <input type="hidden" name="event" value="{{ $listDetails['event'] }}">
- @endif
-
- @foreach(['date_from', 'date_to'] as $filterKey)
- <div class="mr-m">
- <label for="audit_filter_{{ $filterKey }}">{{ trans('settings.audit_' . $filterKey) }}</label>
- <input id="audit_filter_{{ $filterKey }}"
- component="submit-on-change"
- type="date"
- name="{{ $filterKey }}"
- value="{{ $listDetails[$filterKey] ?? '' }}">
- </div>
- @endforeach
+ @if(!empty($listDetails['event']))
+ <input type="hidden" name="event" value="{{ $listDetails['event'] }}">
+ @endif
- <div class="form-group ml-auto mr-m"
- component="submit-on-change"
- option:submit-on-change:filter='[name="user"]'>
- <label for="owner">{{ trans('settings.audit_table_user') }}</label>
- @include('form.user-select', ['user' => $listDetails['user'] ? \BookStack\Auth\User::query()->find($listDetails['user']) : null, 'name' => 'user', 'compact' => true])
+ @foreach(['date_from', 'date_to'] as $filterKey)
+ <div class=>
+ <label for="audit_filter_{{ $filterKey }}">{{ trans('settings.audit_' . $filterKey) }}</label>
+ <input id="audit_filter_{{ $filterKey }}"
+ component="submit-on-change"
+ type="date"
+ name="{{ $filterKey }}"
+ value="{{ $listDetails[$filterKey] ?? '' }}">
</div>
+ @endforeach
+ <div class="form-group"
+ component="submit-on-change"
+ option:submit-on-change:filter='[name="user"]'>
+ <label for="owner">{{ trans('settings.audit_table_user') }}</label>
+ @include('form.user-select', ['user' => $listDetails['user'] ? \BookStack\Auth\User::query()->find($listDetails['user']) : null, 'name' => 'user'])
+ </div>
- <div class="form-group ml-auto">
- <label for="ip">{{ trans('settings.audit_table_ip') }}</label>
- @include('form.text', ['name' => 'ip', 'model' => (object) $listDetails])
- <input type="submit" style="display: none">
- </div>
- </form>
- </div>
+
+ <div class="form-group">
+ <label for="ip">{{ trans('settings.audit_table_ip') }}</label>
+ @include('form.text', ['name' => 'ip', 'model' => (object) $listDetails])
+ <input type="submit" style="display: none">
+ </div>
+ </form>
<hr class="mt-l mb-s">
<div>
<label for="setting-app-custom-head" class="setting-list-label">{{ trans('settings.app_custom_html') }}</label>
<p class="small">{{ trans('settings.app_custom_html_desc') }}</p>
- <textarea name="setting-app-custom-head" id="setting-app-custom-head" class="simple-code-input mt-m">{{ setting('app-custom-head', '') }}</textarea>
+ <div class="mt-m">
+ <textarea component="code-textarea"
+ option:code-textarea:mode="html"
+ name="setting-app-custom-head"
+ id="setting-app-custom-head"
+ class="simple-code-input">{{ setting('app-custom-head', '') }}</textarea>
+ </div>
<p class="small text-right">{{ trans('settings.app_custom_html_disabled_notice') }}</p>
</div>
<div id="details" class="mb-xl">
<h5>{{ trans('common.details') }}</h5>
- <div class="text-small text-muted blended-links">
+ <div class="blended-links">
@include('entities.meta', ['entity' => $shelf])
@if($shelf->restricted)
<div class="active-restriction">
@if(userCan('restrictions-manage', $shelf))
- <a href="{{ $shelf->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.shelves_permissions_active') }}</a>
+ <a href="{{ $shelf->getUrl('/permissions') }}" class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.shelves_permissions_active') }}</div>
+ </a>
@else
- @icon('lock'){{ trans('entities.shelves_permissions_active') }}
+ <div class="entity-meta-item">
+ @icon('lock')
+ <div>{{ trans('entities.shelves_permissions_active') }}</div>
+ </div>
@endif
</div>
@endif
<p class="small">{{ trans('settings.users_migrate_ownership_desc') }}</p>
</div>
<div>
- @include('form.user-select', ['name' => 'new_owner_id', 'user' => null, 'compact' => false])
+ @include('form.user-select', ['name' => 'new_owner_id', 'user' => null])
</div>
</div>
@endif
Route::get('/books/{slug}/delete', [BookController::class, 'showDelete']);
Route::get('/books/{bookSlug}/copy', [BookController::class, 'showCopy']);
Route::post('/books/{bookSlug}/copy', [BookController::class, 'copy']);
+ Route::post('/books/{bookSlug}/convert-to-shelf', [BookController::class, 'convertToShelf']);
Route::get('/books/{bookSlug}/sort', [BookSortController::class, 'show']);
Route::put('/books/{bookSlug}/sort', [BookSortController::class, 'update']);
Route::get('/books/{bookSlug}/export/html', [BookExportController::class, 'html']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/copy', [ChapterController::class, 'showCopy']);
Route::post('/books/{bookSlug}/chapter/{chapterSlug}/copy', [ChapterController::class, 'copy']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/edit', [ChapterController::class, 'edit']);
+ Route::post('/books/{bookSlug}/chapter/{chapterSlug}/convert-to-book', [ChapterController::class, 'convertToBook']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/permissions', [ChapterController::class, 'showPermissions']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/export/pdf', [ChapterExportController::class, 'pdf']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/export/html', [ChapterExportController::class, 'html']);
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
+use Tests\Uploads\UsesImages;
class BooksApiTest extends TestCase
{
use TestsApi;
+ use UsesImages;
protected string $baseEndpoint = '/api/books';
$this->assertGreaterThan(Carbon::now()->subDay()->unix(), $book->updated_at->unix());
}
+ public function test_update_cover_image_control()
+ {
+ $this->actingAsApiEditor();
+ /** @var Book $book */
+ $book = Book::visible()->first();
+ $this->assertNull($book->cover);
+ $file = $this->getTestImage('image.png');
+
+ // Ensure cover image can be set via API
+ $resp = $this->call('PUT', $this->baseEndpoint . "/{$book->id}", [
+ 'name' => 'My updated API book with image',
+ ], [], ['image' => $file]);
+ $book->refresh();
+
+ $resp->assertStatus(200);
+ $this->assertNotNull($book->cover);
+
+ // Ensure further updates without image do not clear cover image
+ $resp = $this->put($this->baseEndpoint . "/{$book->id}", [
+ 'name' => 'My updated book again',
+ ]);
+ $book->refresh();
+
+ $resp->assertStatus(200);
+ $this->assertNotNull($book->cover);
+
+ // Ensure update with null image property clears image
+ $resp = $this->put($this->baseEndpoint . "/{$book->id}", [
+ 'image' => null,
+ ]);
+ $book->refresh();
+
+ $resp->assertStatus(200);
+ $this->assertNull($book->cover);
+ }
+
public function test_delete_endpoint()
{
$this->actingAsApiEditor();
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
+use Tests\Uploads\UsesImages;
class ShelvesApiTest extends TestCase
{
use TestsApi;
+ use UsesImages;
protected string $baseEndpoint = '/api/shelves';
$this->assertTrue($shelf->books()->count() === 0);
}
+ public function test_update_cover_image_control()
+ {
+ $this->actingAsApiEditor();
+ /** @var Book $shelf */
+ $shelf = Bookshelf::visible()->first();
+ $this->assertNull($shelf->cover);
+ $file = $this->getTestImage('image.png');
+
+ // Ensure cover image can be set via API
+ $resp = $this->call('PUT', $this->baseEndpoint . "/{$shelf->id}", [
+ 'name' => 'My updated API shelf with image',
+ ], [], ['image' => $file]);
+ $shelf->refresh();
+
+ $resp->assertStatus(200);
+ $this->assertNotNull($shelf->cover);
+
+ // Ensure further updates without image do not clear cover image
+ $resp = $this->put($this->baseEndpoint . "/{$shelf->id}", [
+ 'name' => 'My updated shelf again',
+ ]);
+ $shelf->refresh();
+
+ $resp->assertStatus(200);
+ $this->assertNotNull($shelf->cover);
+
+ // Ensure update with null image property clears image
+ $resp = $this->put($this->baseEndpoint . "/{$shelf->id}", [
+ 'image' => null,
+ ]);
+ $shelf->refresh();
+
+ $resp->assertStatus(200);
+ $this->assertNull($shelf->cover);
+ }
+
public function test_delete_endpoint()
{
$this->actingAsApiEditor();
--- /dev/null
+<?php
+
+namespace Tests\Auth;
+
+use BookStack\Auth\Access\GroupSyncService;
+use BookStack\Auth\Role;
+use BookStack\Auth\User;
+use Tests\TestCase;
+
+class GroupSyncServiceTest extends TestCase
+{
+ public function test_user_is_assigned_to_matching_roles()
+ {
+ $user = $this->getViewer();
+
+ $roleA = Role::factory()->create(['display_name' => 'Wizards']);
+ $roleB = Role::factory()->create(['display_name' => 'Gremlins']);
+ $roleC = Role::factory()->create(['display_name' => 'ABC123', 'external_auth_id' => 'sales']);
+ $roleD = Role::factory()->create(['display_name' => 'DEF456', 'external_auth_id' => 'admin-team']);
+
+ foreach ([$roleA, $roleB, $roleC, $roleD] as $role) {
+ $this->assertFalse($user->hasRole($role->id));
+ }
+
+ (new GroupSyncService())->syncUserWithFoundGroups($user, ['Wizards', 'Gremlinz', 'Sales', 'Admin Team'], false);
+
+ $user = User::query()->find($user->id);
+ $this->assertTrue($user->hasRole($roleA->id));
+ $this->assertFalse($user->hasRole($roleB->id));
+ $this->assertTrue($user->hasRole($roleC->id));
+ $this->assertTrue($user->hasRole($roleD->id));
+ }
+
+ public function test_multiple_values_in_role_external_auth_id_handled()
+ {
+ $user = $this->getViewer();
+ $role = Role::factory()->create(['display_name' => 'ABC123', 'external_auth_id' => 'sales, engineering, developers, marketers']);
+ $this->assertFalse($user->hasRole($role->id));
+
+ (new GroupSyncService())->syncUserWithFoundGroups($user, ['Developers'], false);
+
+ $user = User::query()->find($user->id);
+ $this->assertTrue($user->hasRole($role->id));
+ }
+
+ public function test_commas_can_be_used_in_external_auth_id_if_escaped()
+ {
+ $user = $this->getViewer();
+ $role = Role::factory()->create(['display_name' => 'ABC123', 'external_auth_id' => 'sales\,-developers, marketers']);
+ $this->assertFalse($user->hasRole($role->id));
+
+ (new GroupSyncService())->syncUserWithFoundGroups($user, ['Sales, Developers'], false);
+
+ $user = User::query()->find($user->id);
+ $this->assertTrue($user->hasRole($role->id));
+ }
+}
public function test_dump_user_details_option_works()
{
- config()->set(['services.ldap.dump_user_details' => true]);
+ config()->set(['services.ldap.dump_user_details' => true, 'services.ldap.thumbnail_attribute' => 'jpegphoto']);
$this->commonLdapMocks(1, 1, 1, 1, 1);
$this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)
->andReturn(['count' => 1, 0 => [
'uid' => [$this->mockUser->name],
'cn' => [$this->mockUser->name],
- 'dn' => ['dc=test' . config('services.ldap.base_dn')],
+ // Test dumping binary data for avatar responses
+ 'jpegphoto' => base64_decode('/9j/4AAQSkZJRg=='),
+ 'dn' => ['dc=test' . config('services.ldap.base_dn')],
]]);
$resp = $this->post('/login', [
}
}
+ public function test_login_mfa_interception_does_not_log_error()
+ {
+ $logHandler = $this->withTestLogger();
+
+ [$user, $secret, $loginResp] = $this->startTotpLogin();
+
+ $loginResp->assertRedirect('/mfa/verify');
+ $this->assertFalse($logHandler->hasErrorRecords());
+ }
+
/**
* @return array<User, string, TestResponse>
*/
/** @var Book $copy */
$copy = Book::query()->where('name', '=', 'My copy book')->first();
+
$this->assertNotNull($copy->cover);
$this->assertNotEquals($book->cover->id, $copy->cover->id);
}
--- /dev/null
+<?php
+
+namespace Tests\Entity;
+
+use BookStack\Actions\ActivityType;
+use BookStack\Actions\Tag;
+use BookStack\Entities\Models\Book;
+use BookStack\Entities\Models\Bookshelf;
+use BookStack\Entities\Models\Chapter;
+use BookStack\Entities\Models\Page;
+use Tests\TestCase;
+
+class ConvertTest extends TestCase
+{
+ public function test_chapter_edit_view_shows_convert_option()
+ {
+ /** @var Chapter $chapter */
+ $chapter = Chapter::query()->first();
+
+ $resp = $this->asEditor()->get($chapter->getUrl('/edit'));
+ $resp->assertSee('Convert to Book');
+ $resp->assertSee('Convert Chapter');
+ $resp->assertElementExists('form[action$="/convert-to-book"] button');
+ }
+
+ public function test_convert_chapter_to_book()
+ {
+ /** @var Chapter $chapter */
+ $chapter = Chapter::query()->whereHas('pages')->first();
+ $chapter->tags()->save(new Tag(['name' => 'Category', 'value' => 'Penguins']));
+ /** @var Page $childPage */
+ $childPage = $chapter->pages()->first();
+
+ $resp = $this->asEditor()->post($chapter->getUrl('/convert-to-book'));
+ $resp->assertRedirectContains('/books/');
+
+ /** @var Book $newBook */
+ $newBook = Book::query()->orderBy('id', 'desc')->first();
+
+ $this->assertDatabaseMissing('chapters', ['id' => $chapter->id]);
+ $this->assertDatabaseHas('pages', ['id' => $childPage->id, 'book_id' => $newBook->id, 'chapter_id' => 0]);
+ $this->assertCount(1, $newBook->tags);
+ $this->assertEquals('Category', $newBook->tags->first()->name);
+ $this->assertEquals('Penguins', $newBook->tags->first()->value);
+ $this->assertEquals($chapter->name, $newBook->name);
+ $this->assertEquals($chapter->description, $newBook->description);
+
+ $this->assertActivityExists(ActivityType::BOOK_CREATE_FROM_CHAPTER, $newBook);
+ }
+
+ public function test_convert_chapter_to_book_requires_permissions()
+ {
+ /** @var Chapter $chapter */
+ $chapter = Chapter::query()->first();
+ $user = $this->getViewer();
+
+ $permissions = ['chapter-delete-all', 'book-create-all', 'chapter-update-all'];
+ $this->giveUserPermissions($user, $permissions);
+
+ foreach ($permissions as $permission) {
+ $this->removePermissionFromUser($user, $permission);
+ $resp = $this->actingAs($user)->post($chapter->getUrl('/convert-to-book'));
+ $this->assertPermissionError($resp);
+ $this->giveUserPermissions($user, [$permission]);
+ }
+
+ $resp = $this->actingAs($user)->post($chapter->getUrl('/convert-to-book'));
+ $this->assertNotPermissionError($resp);
+ $resp->assertRedirect();
+ }
+
+ public function test_book_edit_view_shows_convert_option()
+ {
+ $book = Book::query()->first();
+
+ $resp = $this->asEditor()->get($book->getUrl('/edit'));
+ $resp->assertSee('Convert to Shelf');
+ $resp->assertSee('Convert Book');
+ $resp->assertSee('Note that permissions on shelves do not auto-cascade to content');
+ $resp->assertElementExists('form[action$="/convert-to-shelf"] button');
+ }
+
+ public function test_book_convert_to_shelf()
+ {
+ /** @var Book $book */
+ $book = Book::query()->whereHas('directPages')->whereHas('chapters')->firstOrFail();
+ $book->tags()->save(new Tag(['name' => 'Category', 'value' => 'Ducks']));
+ /** @var Page $childPage */
+ $childPage = $book->directPages()->first();
+ /** @var Chapter $childChapter */
+ $childChapter = $book->chapters()->whereHas('pages')->firstOrFail();
+ /** @var Page $chapterChildPage */
+ $chapterChildPage = $childChapter->pages()->firstOrFail();
+ $bookChapterCount = $book->chapters()->count();
+ $systemBookCount = Book::query()->count();
+
+ // Run conversion
+ $resp = $this->asEditor()->post($book->getUrl('/convert-to-shelf'));
+
+ /** @var Bookshelf $newShelf */
+ $newShelf = Bookshelf::query()->orderBy('id', 'desc')->first();
+
+ // Checks for new shelf
+ $resp->assertRedirectContains('/shelves/');
+ $this->assertDatabaseMissing('chapters', ['id' => $childChapter->id]);
+ $this->assertCount(1, $newShelf->tags);
+ $this->assertEquals('Category', $newShelf->tags->first()->name);
+ $this->assertEquals('Ducks', $newShelf->tags->first()->value);
+ $this->assertEquals($book->name, $newShelf->name);
+ $this->assertEquals($book->description, $newShelf->description);
+ $this->assertEquals($newShelf->books()->count(), $bookChapterCount + 1);
+ $this->assertEquals($systemBookCount + $bookChapterCount, Book::query()->count());
+ $this->assertActivityExists(ActivityType::BOOKSHELF_CREATE_FROM_BOOK, $newShelf);
+
+ // Checks for old book to contain child pages
+ $this->assertDatabaseHas('books', ['id' => $book->id, 'name' => $book->name . ' Pages']);
+ $this->assertDatabaseHas('pages', ['id' => $childPage->id, 'book_id' => $book->id, 'chapter_id' => 0]);
+
+ // Checks for nested page
+ $chapterChildPage->refresh();
+ $this->assertEquals(0, $chapterChildPage->chapter_id);
+ $this->assertEquals($childChapter->name, $chapterChildPage->book->name);
+ }
+
+ public function test_book_convert_to_shelf_requires_permissions()
+ {
+ /** @var Book $book */
+ $book = Book::query()->first();
+ $user = $this->getViewer();
+
+ $permissions = ['book-delete-all', 'bookshelf-create-all', 'book-update-all', 'book-create-all'];
+ $this->giveUserPermissions($user, $permissions);
+
+ foreach ($permissions as $permission) {
+ $this->removePermissionFromUser($user, $permission);
+ $resp = $this->actingAs($user)->post($book->getUrl('/convert-to-shelf'));
+ $this->assertPermissionError($resp);
+ $this->giveUserPermissions($user, [$permission]);
+ }
+
+ $resp = $this->actingAs($user)->post($book->getUrl('/convert-to-shelf'));
+ $this->assertNotPermissionError($resp);
+ $resp->assertRedirect();
+ }
+}
$search->assertSee('My supercool <great> <strong>TestPageContent</strong> page', false);
}
+ public function test_words_adjacent_to_lines_breaks_can_be_matched_with_normal_terms()
+ {
+ $page = $this->newPage(['name' => 'TermA', 'html' => '
+ <p>TermA<br>TermB<br>TermC</p>
+ ']);
+
+ $search = $this->asEditor()->get('/search?term=' . urlencode('TermB TermC'));
+
+ $search->assertSee($page->getUrl(), false);
+ }
+
public function test_searches_with_user_filters_adds_them_into_advanced_search_form()
{
$resp = $this->asEditor()->get('/search?term=' . urlencode('test {updated_by:me} {created_by:dan}'));
$resp->assertElementExists('head meta[http-equiv="Content-Security-Policy"][content*="script-src "]');
}
}
+
+ public function test_html_exports_contain_body_classes_for_export_identification()
+ {
+ $page = Page::query()->first();
+
+ $resp = $this->asEditor()->get($page->getUrl('/export/html'));
+ $resp->assertElementExists('body.export.export-format-html.export-engine-none');
+ }
}
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page;
+use BookStack\Entities\Repos\BaseRepo;
use BookStack\Entities\Repos\BookRepo;
-use BookStack\Entities\Repos\BookshelfRepo;
use Illuminate\Support\Str;
use Tests\Uploads\UsesImages;
$this->assertArrayNotHasKey('image', $tags);
// Test image set if image has cover image
- $shelfRepo = app(BookshelfRepo::class);
- $shelfRepo->updateCoverImage($shelf, $this->getTestImage('image.png'));
+ $baseRepo = app(BaseRepo::class);
+ $baseRepo->updateCoverImage($shelf, $this->getTestImage('image.png'));
$resp = $this->asEditor()->get($shelf->getUrl());
$tags = $this->getOpenGraphTags($resp);
/**
* Completely remove the given permission name from the given user.
*/
- protected function removePermissionFromUser(User $user, string $permission)
+ protected function removePermissionFromUser(User $user, string $permissionName)
{
- $permission = RolePermission::query()->where('name', '=', $permission)->first();
+ $permissionService = app()->make(PermissionService::class);
+
+ /** @var RolePermission $permission */
+ $permission = RolePermission::query()->where('name', '=', $permissionName)->firstOrFail();
+
+ $roles = $user->roles()->whereHas('permissions', function ($query) use ($permission) {
+ $query->where('id', '=', $permission->id);
+ })->get();
+
/** @var Role $role */
- foreach ($user->roles as $role) {
+ foreach ($roles as $role) {
$role->detachPermission($permission);
+ $permissionService->buildJointPermissionForRole($role);
}
+
$user->clearPermissionCache();
}
foreach ($elements as $element) {
$element = new Crawler($element);
- if (preg_match("/$pattern/i", $element->html())) {
+ if (preg_match("/$pattern/i", $element->text())) {
$matched = true;
break;
}
$this->assertEquals('/cool/docs', $bsRequest->getBaseUrl());
$this->assertEquals('https://donkey.example.com:8091/cool/docs/login', $bsRequest->getUri());
}
+
+ public function test_app_url_without_path_does_not_duplicate_path_slash()
+ {
+ config()->set('app.url', 'https://donkey.example.com');
+
+ // Have to manually get and wrap request in our custom type due to testing mechanics
+ $this->get('/settings');
+ $bsRequest = Request::createFrom(request());
+
+ $this->assertEquals('https://donkey.example.com', $bsRequest->getSchemeAndHttpHost());
+ $this->assertEquals('', $bsRequest->getBaseUrl());
+ $this->assertEquals('/settings', $bsRequest->getPathInfo());
+ $this->assertEquals('https://donkey.example.com/settings', $bsRequest->getUri());
+ }
}