mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-02-05 16:49:47 +03:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf0ba9f756 | ||
|
|
05f8034439 | ||
|
|
1d1186c901 | ||
|
|
641a26cdf7 | ||
|
|
5fd8e7e0e9 | ||
|
|
d926ca5f71 | ||
|
|
b69722c3b5 | ||
|
|
c9aa1c979f |
@@ -143,10 +143,6 @@ STORAGE_URL=false
|
||||
# Can be 'standard', 'ldap', 'saml2' or 'oidc'
|
||||
AUTH_METHOD=standard
|
||||
|
||||
# Automatically initiate login via external auth system if it's the only auth method.
|
||||
# Works with saml2 or oidc auth methods.
|
||||
AUTH_AUTO_INITIATE=false
|
||||
|
||||
# Social authentication configuration
|
||||
# All disabled by default.
|
||||
# Refer to https://www.bookstackapp.com/docs/admin/third-party-auth/
|
||||
|
||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1,4 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [ssddanbrown]
|
||||
ko_fi: ssddanbrown
|
||||
4
.github/ISSUE_TEMPLATE/language_request.yml
vendored
4
.github/ISSUE_TEMPLATE/language_request.yml
vendored
@@ -1,5 +1,5 @@
|
||||
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
|
||||
@@ -23,7 +23,7 @@ body:
|
||||
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:
|
||||
|
||||
15
.github/translators.txt
vendored
15
.github/translators.txt
vendored
@@ -243,18 +243,3 @@ Shukrullo (vodiylik) :: Uzbek
|
||||
William W. (Nevnt) :: Chinese Traditional
|
||||
eamaro :: Portuguese
|
||||
Ypsilon-dev :: Arabic
|
||||
Hieu Vuong Trung (vuongtrunghieu) :: Vietnamese
|
||||
David Clubb (davidoclubb) :: Welsh
|
||||
welles freire (wellesximenes) :: Portuguese, Brazilian
|
||||
Magnus Jensen (MagnusHJensen) :: Danish
|
||||
Hesley Magno (hesleymagno) :: Portuguese, Brazilian
|
||||
Éric Gaspar (erga) :: French
|
||||
Fr3shlama :: German
|
||||
DSR :: Spanish, Argentina
|
||||
Andrii Bodnar (andrii-bodnar) :: Ukrainian
|
||||
Younes el Anjri (younesea28) :: Dutch
|
||||
Guclu Ozturk (gucluoz) :: Turkish
|
||||
Atmis :: French
|
||||
redjack666 :: Chinese Traditional
|
||||
Ashita007 :: Russian
|
||||
lihaorr :: Chinese Simplified
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -5,10 +5,10 @@ Homestead.yaml
|
||||
.idea
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
/public/dist/*.map
|
||||
/public/dist
|
||||
/public/plugins
|
||||
/public/css/*.map
|
||||
/public/js/*.map
|
||||
/public/css
|
||||
/public/js
|
||||
/public/bower
|
||||
/public/build/
|
||||
/storage/images
|
||||
|
||||
@@ -16,13 +16,11 @@ class ActivityType
|
||||
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';
|
||||
|
||||
|
||||
@@ -28,8 +28,10 @@ class GroupSyncService
|
||||
*/
|
||||
protected function externalIdMatchesGroupNames(string $externalId, array $groupNames): bool
|
||||
{
|
||||
foreach ($this->parseRoleExternalAuthId($externalId) as $externalAuthId) {
|
||||
if (in_array($externalAuthId, $groupNames)) {
|
||||
$externalAuthIds = explode(',', strtolower($externalId));
|
||||
|
||||
foreach ($externalAuthIds as $externalAuthId) {
|
||||
if (in_array(trim($externalAuthId), $groupNames)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -37,18 +39,6 @@ class GroupSyncService
|
||||
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.
|
||||
|
||||
@@ -71,7 +71,7 @@ return [
|
||||
'locale' => env('APP_LANG', 'en'),
|
||||
|
||||
// Locales available
|
||||
'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'cy', 'da', 'de', 'de_informal', 'es', 'es_AR', 'et', 'eu', 'fa', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lt', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'uz', 'vi', 'zh_CN', 'zh_TW'],
|
||||
'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'de_informal', 'es', 'es_AR', 'et', 'eu', 'fa', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lt', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'uz', 'vi', 'zh_CN', 'zh_TW'],
|
||||
|
||||
// Application Fallback Locale
|
||||
'fallback_locale' => 'en',
|
||||
|
||||
@@ -13,10 +13,6 @@ return [
|
||||
// Options: standard, ldap, saml2, oidc
|
||||
'method' => env('AUTH_METHOD', 'standard'),
|
||||
|
||||
// Automatically initiate login via external auth system if it's the sole auth method.
|
||||
// Works with saml2 or oidc auth methods.
|
||||
'auto_initiate' => env('AUTH_AUTO_INITIATE', false),
|
||||
|
||||
// Authentication Defaults
|
||||
// This option controls the default authentication "guard" and password
|
||||
// reset options for your application.
|
||||
|
||||
@@ -91,7 +91,6 @@ class BookRepo
|
||||
{
|
||||
$book = new Book();
|
||||
$this->baseRepo->create($book, $input);
|
||||
$this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
|
||||
Activity::add(ActivityType::BOOK_CREATE, $book);
|
||||
|
||||
return $book;
|
||||
@@ -103,11 +102,6 @@ class BookRepo
|
||||
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;
|
||||
|
||||
@@ -6,10 +6,12 @@ use BookStack\Actions\ActivityType;
|
||||
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
|
||||
@@ -87,7 +89,6 @@ 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);
|
||||
|
||||
@@ -105,17 +106,14 @@ class BookshelfRepo
|
||||
$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)
|
||||
@@ -134,6 +132,17 @@ class BookshelfRepo
|
||||
$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.
|
||||
*/
|
||||
|
||||
@@ -392,6 +392,23 @@ class PageRepo
|
||||
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.
|
||||
|
||||
@@ -16,10 +16,25 @@ use Illuminate\Http\UploadedFile;
|
||||
|
||||
class Cloner
|
||||
{
|
||||
protected PageRepo $pageRepo;
|
||||
protected ChapterRepo $chapterRepo;
|
||||
protected BookRepo $bookRepo;
|
||||
protected ImageService $imageService;
|
||||
/**
|
||||
* @var PageRepo
|
||||
*/
|
||||
protected $pageRepo;
|
||||
|
||||
/**
|
||||
* @var ChapterRepo
|
||||
*/
|
||||
protected $chapterRepo;
|
||||
|
||||
/**
|
||||
* @var BookRepo
|
||||
*/
|
||||
protected $bookRepo;
|
||||
|
||||
/**
|
||||
* @var ImageService
|
||||
*/
|
||||
protected $imageService;
|
||||
|
||||
public function __construct(PageRepo $pageRepo, ChapterRepo $chapterRepo, BookRepo $bookRepo, ImageService $imageService)
|
||||
{
|
||||
@@ -35,8 +50,11 @@ class Cloner
|
||||
public function clonePage(Page $original, Entity $parent, string $newName): Page
|
||||
{
|
||||
$copyPage = $this->pageRepo->getNewDraftPage($parent);
|
||||
$pageData = $this->entityToInputData($original);
|
||||
$pageData = $original->getAttributes();
|
||||
|
||||
// Update name & tags
|
||||
$pageData['name'] = $newName;
|
||||
$pageData['tags'] = $this->entityTagsToInputArray($original);
|
||||
|
||||
return $this->pageRepo->publishDraft($copyPage, $pageData);
|
||||
}
|
||||
@@ -47,8 +65,9 @@ class Cloner
|
||||
*/
|
||||
public function cloneChapter(Chapter $original, Book $parent, string $newName): Chapter
|
||||
{
|
||||
$chapterDetails = $this->entityToInputData($original);
|
||||
$chapterDetails = $original->getAttributes();
|
||||
$chapterDetails['name'] = $newName;
|
||||
$chapterDetails['tags'] = $this->entityTagsToInputArray($original);
|
||||
|
||||
$copyChapter = $this->chapterRepo->create($chapterDetails, $parent);
|
||||
|
||||
@@ -68,8 +87,9 @@ class Cloner
|
||||
*/
|
||||
public function cloneBook(Book $original, string $newName): Book
|
||||
{
|
||||
$bookDetails = $this->entityToInputData($original);
|
||||
$bookDetails = $original->getAttributes();
|
||||
$bookDetails['name'] = $newName;
|
||||
$bookDetails['tags'] = $this->entityTagsToInputArray($original);
|
||||
|
||||
$copyBook = $this->bookRepo->create($bookDetails);
|
||||
|
||||
@@ -84,48 +104,26 @@ class Cloner
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if ($original->cover) {
|
||||
try {
|
||||
$tmpImgFile = tmpfile();
|
||||
$uploadedFile = $this->imageToUploadedFile($original->cover, $tmpImgFile);
|
||||
$this->bookRepo->updateCoverImage($copyBook, $uploadedFile, false);
|
||||
} catch (\Exception $exception) {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
return $copyBook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an image instance to an UploadedFile instance to mimic
|
||||
* a file being uploaded.
|
||||
*/
|
||||
protected function imageToUploadedFile(Image $image): ?UploadedFile
|
||||
protected function imageToUploadedFile(Image $image, &$tmpFile): ?UploadedFile
|
||||
{
|
||||
$imgData = $this->imageService->getImageData($image);
|
||||
$tmpImgFilePath = tempnam(sys_get_temp_dir(), 'bs_cover_clone_');
|
||||
$tmpImgFilePath = stream_get_meta_data($tmpFile)['uri'];
|
||||
file_put_contents($tmpImgFilePath, $imgData);
|
||||
|
||||
return new UploadedFile($tmpImgFilePath, basename($image->path));
|
||||
|
||||
@@ -39,7 +39,7 @@ class ExportFormatter
|
||||
public function pageToContainedHtml(Page $page)
|
||||
{
|
||||
$page->html = (new PageContent($page))->render();
|
||||
$pageHtml = view('exports.page', [
|
||||
$pageHtml = view('pages.export', [
|
||||
'page' => $page,
|
||||
'format' => 'html',
|
||||
'cspContent' => $this->cspService->getCspMetaTagValue(),
|
||||
@@ -59,7 +59,7 @@ class ExportFormatter
|
||||
$pages->each(function ($page) {
|
||||
$page->html = (new PageContent($page))->render();
|
||||
});
|
||||
$html = view('exports.chapter', [
|
||||
$html = view('chapters.export', [
|
||||
'chapter' => $chapter,
|
||||
'pages' => $pages,
|
||||
'format' => 'html',
|
||||
@@ -77,7 +77,7 @@ class ExportFormatter
|
||||
public function bookToContainedHtml(Book $book)
|
||||
{
|
||||
$bookTree = (new BookContents($book))->getTree(false, true);
|
||||
$html = view('exports.book', [
|
||||
$html = view('books.export', [
|
||||
'book' => $book,
|
||||
'bookChildren' => $bookTree,
|
||||
'format' => 'html',
|
||||
@@ -95,7 +95,7 @@ class ExportFormatter
|
||||
public function pageToPdf(Page $page)
|
||||
{
|
||||
$page->html = (new PageContent($page))->render();
|
||||
$html = view('exports.page', [
|
||||
$html = view('pages.export', [
|
||||
'page' => $page,
|
||||
'format' => 'pdf',
|
||||
'engine' => $this->pdfGenerator->getActiveEngine(),
|
||||
@@ -116,7 +116,7 @@ class ExportFormatter
|
||||
$page->html = (new PageContent($page))->render();
|
||||
});
|
||||
|
||||
$html = view('exports.chapter', [
|
||||
$html = view('chapters.export', [
|
||||
'chapter' => $chapter,
|
||||
'pages' => $pages,
|
||||
'format' => 'pdf',
|
||||
@@ -134,7 +134,7 @@ class ExportFormatter
|
||||
public function bookToPdf(Book $book)
|
||||
{
|
||||
$bookTree = (new BookContents($book))->getTree(false, true);
|
||||
$html = view('exports.book', [
|
||||
$html = view('books.export', [
|
||||
'book' => $book,
|
||||
'bookChildren' => $bookTree,
|
||||
'format' => 'pdf',
|
||||
@@ -215,14 +215,16 @@ class ExportFormatter
|
||||
*/
|
||||
protected function containHtml(string $htmlContent): string
|
||||
{
|
||||
$imageTagsOutput = [];
|
||||
preg_match_all("/\<img.*?src\=(\'|\")(.*?)(\'|\").*?\>/i", $htmlContent, $imageTagsOutput);
|
||||
// Replace embed tags with images
|
||||
$htmlContent = preg_replace("/<embed (.*?)>/i", '<img $1>', $htmlContent);
|
||||
|
||||
// Replace image src with base64 encoded image strings
|
||||
// Replace image & embed src attributes with base64 encoded data strings
|
||||
$imageTagsOutput = [];
|
||||
preg_match_all("/<img .*?src=['\"](.*?)['\"].*?>/i", $htmlContent, $imageTagsOutput);
|
||||
if (isset($imageTagsOutput[0]) && count($imageTagsOutput[0]) > 0) {
|
||||
foreach ($imageTagsOutput[0] as $index => $imgMatch) {
|
||||
$oldImgTagString = $imgMatch;
|
||||
$srcString = $imageTagsOutput[2][$index];
|
||||
$srcString = $imageTagsOutput[1][$index];
|
||||
$imageEncoded = $this->imageService->imageUriToBase64($srcString);
|
||||
if ($imageEncoded === null) {
|
||||
$imageEncoded = $srcString;
|
||||
@@ -232,14 +234,13 @@ class ExportFormatter
|
||||
}
|
||||
}
|
||||
|
||||
// Replace any relative links with full system URL
|
||||
$linksOutput = [];
|
||||
preg_match_all("/\<a.*href\=(\'|\")(.*?)(\'|\").*?\>/i", $htmlContent, $linksOutput);
|
||||
|
||||
// Replace image src with base64 encoded image strings
|
||||
preg_match_all("/<a .*href=['\"](.*?)['\"].*?>/i", $htmlContent, $linksOutput);
|
||||
if (isset($linksOutput[0]) && count($linksOutput[0]) > 0) {
|
||||
foreach ($linksOutput[0] as $index => $linkMatch) {
|
||||
$oldLinkString = $linkMatch;
|
||||
$srcString = $linksOutput[2][$index];
|
||||
$srcString = $linksOutput[1][$index];
|
||||
if (strpos(trim($srcString), 'http') !== 0) {
|
||||
$newSrcString = url($srcString);
|
||||
$newLinkString = str_replace($srcString, $newSrcString, $oldLinkString);
|
||||
@@ -248,7 +249,6 @@ class ExportFormatter
|
||||
}
|
||||
}
|
||||
|
||||
// Replace any relative links with system domain
|
||||
return $htmlContent;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
@@ -147,8 +147,6 @@ class SearchIndex
|
||||
];
|
||||
|
||||
$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'));
|
||||
|
||||
@@ -344,7 +344,7 @@ class TrashCan
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function destroyEntity(Entity $entity): int
|
||||
protected function destroyEntity(Entity $entity): int
|
||||
{
|
||||
if ($entity instanceof Page) {
|
||||
return $this->destroyPage($entity);
|
||||
|
||||
@@ -21,7 +21,6 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
protected $dontReport = [
|
||||
NotFoundException::class,
|
||||
StoppedAuthenticationException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,19 @@ class BookApiController extends ApiController
|
||||
{
|
||||
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;
|
||||
@@ -24,21 +37,19 @@ class BookApiController extends ApiController
|
||||
$books = Book::visible();
|
||||
|
||||
return $this->apiListingResponse($books, [
|
||||
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
|
||||
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by', 'image_id',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -57,8 +68,6 @@ class BookApiController extends ApiController
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -67,7 +76,7 @@ class BookApiController extends ApiController
|
||||
$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);
|
||||
@@ -88,22 +97,4 @@ class BookApiController extends ApiController
|
||||
|
||||
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()),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class BookExportApiController extends ApiController
|
||||
$book = Book::visible()->findOrFail($id);
|
||||
$pdfContent = $this->exportFormatter->bookToPdf($book);
|
||||
|
||||
return $this->download()->directly($pdfContent, $book->slug . '.pdf');
|
||||
return $this->downloadResponse($pdfContent, $book->slug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ class BookExportApiController extends ApiController
|
||||
$book = Book::visible()->findOrFail($id);
|
||||
$htmlContent = $this->exportFormatter->bookToContainedHtml($book);
|
||||
|
||||
return $this->download()->directly($htmlContent, $book->slug . '.html');
|
||||
return $this->downloadResponse($htmlContent, $book->slug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,7 +50,7 @@ class BookExportApiController extends ApiController
|
||||
$book = Book::visible()->findOrFail($id);
|
||||
$textContent = $this->exportFormatter->bookToPlainText($book);
|
||||
|
||||
return $this->download()->directly($textContent, $book->slug . '.txt');
|
||||
return $this->downloadResponse($textContent, $book->slug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,6 +61,6 @@ class BookExportApiController extends ApiController
|
||||
$book = Book::visible()->findOrFail($id);
|
||||
$markdown = $this->exportFormatter->bookToMarkdown($book);
|
||||
|
||||
return $this->download()->directly($markdown, $book->slug . '.md');
|
||||
return $this->downloadResponse($markdown, $book->slug . '.md');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,21 @@ class BookshelfApiController extends ApiController
|
||||
{
|
||||
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.
|
||||
*/
|
||||
@@ -29,7 +44,7 @@ class BookshelfApiController extends ApiController
|
||||
$shelves = Bookshelf::visible();
|
||||
|
||||
return $this->apiListingResponse($shelves, [
|
||||
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
|
||||
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by', 'image_id',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -37,15 +52,13 @@ class BookshelfApiController extends ApiController
|
||||
* 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);
|
||||
@@ -73,8 +86,6 @@ class BookshelfApiController extends ApiController
|
||||
* 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
|
||||
*/
|
||||
@@ -83,7 +94,7 @@ class BookshelfApiController extends ApiController
|
||||
$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);
|
||||
@@ -106,24 +117,4 @@ class BookshelfApiController extends ApiController
|
||||
|
||||
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()),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = Chapter::visible()->findOrFail($id);
|
||||
$pdfContent = $this->exportFormatter->chapterToPdf($chapter);
|
||||
|
||||
return $this->download()->directly($pdfContent, $chapter->slug . '.pdf');
|
||||
return $this->downloadResponse($pdfContent, $chapter->slug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,7 +42,7 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = Chapter::visible()->findOrFail($id);
|
||||
$htmlContent = $this->exportFormatter->chapterToContainedHtml($chapter);
|
||||
|
||||
return $this->download()->directly($htmlContent, $chapter->slug . '.html');
|
||||
return $this->downloadResponse($htmlContent, $chapter->slug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = Chapter::visible()->findOrFail($id);
|
||||
$textContent = $this->exportFormatter->chapterToPlainText($chapter);
|
||||
|
||||
return $this->download()->directly($textContent, $chapter->slug . '.txt');
|
||||
return $this->downloadResponse($textContent, $chapter->slug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,6 +64,6 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = Chapter::visible()->findOrFail($id);
|
||||
$markdown = $this->exportFormatter->chapterToMarkdown($chapter);
|
||||
|
||||
return $this->download()->directly($markdown, $chapter->slug . '.md');
|
||||
return $this->downloadResponse($markdown, $chapter->slug . '.md');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class PageExportApiController extends ApiController
|
||||
$page = Page::visible()->findOrFail($id);
|
||||
$pdfContent = $this->exportFormatter->pageToPdf($page);
|
||||
|
||||
return $this->download()->directly($pdfContent, $page->slug . '.pdf');
|
||||
return $this->downloadResponse($pdfContent, $page->slug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ class PageExportApiController extends ApiController
|
||||
$page = Page::visible()->findOrFail($id);
|
||||
$htmlContent = $this->exportFormatter->pageToContainedHtml($page);
|
||||
|
||||
return $this->download()->directly($htmlContent, $page->slug . '.html');
|
||||
return $this->downloadResponse($htmlContent, $page->slug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,7 +50,7 @@ class PageExportApiController extends ApiController
|
||||
$page = Page::visible()->findOrFail($id);
|
||||
$textContent = $this->exportFormatter->pageToPlainText($page);
|
||||
|
||||
return $this->download()->directly($textContent, $page->slug . '.txt');
|
||||
return $this->downloadResponse($textContent, $page->slug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,6 +61,6 @@ class PageExportApiController extends ApiController
|
||||
$page = Page::visible()->findOrFail($id);
|
||||
$markdown = $this->exportFormatter->pageToMarkdown($page);
|
||||
|
||||
return $this->download()->directly($markdown, $page->slug . '.md');
|
||||
return $this->downloadResponse($markdown, $page->slug . '.md');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,10 +233,10 @@ class AttachmentController extends Controller
|
||||
$attachmentStream = $this->attachmentService->streamAttachmentFromStorage($attachment);
|
||||
|
||||
if ($request->get('open') === 'true') {
|
||||
return $this->download()->streamedInline($attachmentStream, $fileName);
|
||||
return $this->streamedInlineDownloadResponse($attachmentStream, $fileName);
|
||||
}
|
||||
|
||||
return $this->download()->streamedDirectly($attachmentStream, $fileName);
|
||||
return $this->streamedDownloadResponse($attachmentStream, $fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,16 +25,17 @@ class LoginController extends Controller
|
||||
|
|
||||
*/
|
||||
|
||||
use AuthenticatesUsers { logout as traitLogout; }
|
||||
use AuthenticatesUsers;
|
||||
|
||||
/**
|
||||
* Redirection paths.
|
||||
*/
|
||||
protected $redirectTo = '/';
|
||||
protected $redirectPath = '/';
|
||||
protected $redirectAfterLogout = '/login';
|
||||
|
||||
protected SocialAuthService $socialAuthService;
|
||||
protected LoginService $loginService;
|
||||
protected $socialAuthService;
|
||||
protected $loginService;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
@@ -49,6 +50,7 @@ class LoginController extends Controller
|
||||
$this->loginService = $loginService;
|
||||
|
||||
$this->redirectPath = url('/');
|
||||
$this->redirectAfterLogout = url('/login');
|
||||
}
|
||||
|
||||
public function username()
|
||||
@@ -71,7 +73,6 @@ class LoginController extends Controller
|
||||
{
|
||||
$socialDrivers = $this->socialAuthService->getActiveDrivers();
|
||||
$authMethod = config('auth.method');
|
||||
$preventInitiation = $request->get('prevent_auto_init') === 'true';
|
||||
|
||||
if ($request->has('email')) {
|
||||
session()->flashInput([
|
||||
@@ -83,12 +84,6 @@ class LoginController extends Controller
|
||||
// Store the previous location for redirect after login
|
||||
$this->updateIntendedFromPrevious();
|
||||
|
||||
if (!$preventInitiation && $this->shouldAutoInitiate()) {
|
||||
return view('auth.login-initiate', [
|
||||
'authMethod' => $authMethod,
|
||||
]);
|
||||
}
|
||||
|
||||
return view('auth.login', [
|
||||
'socialDrivers' => $socialDrivers,
|
||||
'authMethod' => $authMethod,
|
||||
@@ -256,32 +251,4 @@ class LoginController extends Controller
|
||||
|
||||
redirect()->setIntendedUrl($previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if login auto-initiate should be valid based upon authentication config.
|
||||
*/
|
||||
protected function shouldAutoInitiate(): bool
|
||||
{
|
||||
$socialDrivers = $this->socialAuthService->getActiveDrivers();
|
||||
$authMethod = config('auth.method');
|
||||
$autoRedirect = config('auth.auto_initiate');
|
||||
|
||||
return $autoRedirect && count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout user and perform subsequent redirect.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
{
|
||||
$this->traitLogout($request);
|
||||
|
||||
$redirectUri = $this->shouldAutoInitiate() ? '/login?prevent_auto_init=true' : '/';
|
||||
|
||||
return redirect($redirectUri);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ use BookStack\Entities\Models\Bookshelf;
|
||||
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;
|
||||
@@ -88,11 +87,10 @@ class BookController extends Controller
|
||||
public function store(Request $request, string $shelfSlug = null)
|
||||
{
|
||||
$this->checkPermission('book-create-all');
|
||||
$validated = $this->validate($request, [
|
||||
$this->validate($request, [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'description' => ['string', 'max:1000'],
|
||||
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
|
||||
'tags' => ['array'],
|
||||
]);
|
||||
|
||||
$bookshelf = null;
|
||||
@@ -101,7 +99,8 @@ class BookController extends Controller
|
||||
$this->checkOwnablePermission('bookshelf-update', $bookshelf);
|
||||
}
|
||||
|
||||
$book = $this->bookRepo->create($validated);
|
||||
$book = $this->bookRepo->create($request->all());
|
||||
$this->bookRepo->updateCoverImage($book, $request->file('image', null));
|
||||
|
||||
if ($bookshelf) {
|
||||
$bookshelf->appendBook($book);
|
||||
@@ -159,21 +158,15 @@ class BookController extends Controller
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('book-update', $book);
|
||||
|
||||
$validated = $this->validate($request, [
|
||||
$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']);
|
||||
}
|
||||
|
||||
$book = $this->bookRepo->update($book, $validated);
|
||||
$book = $this->bookRepo->update($book, $request->all());
|
||||
$resetCover = $request->has('image_reset');
|
||||
$this->bookRepo->updateCoverImage($book, $request->file('image', null), $resetCover);
|
||||
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
@@ -269,20 +262,4 @@ class BookController extends Controller
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class BookExportController extends Controller
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$pdfContent = $this->exportFormatter->bookToPdf($book);
|
||||
|
||||
return $this->download()->directly($pdfContent, $bookSlug . '.pdf');
|
||||
return $this->downloadResponse($pdfContent, $bookSlug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +44,7 @@ class BookExportController extends Controller
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$htmlContent = $this->exportFormatter->bookToContainedHtml($book);
|
||||
|
||||
return $this->download()->directly($htmlContent, $bookSlug . '.html');
|
||||
return $this->downloadResponse($htmlContent, $bookSlug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +55,7 @@ class BookExportController extends Controller
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$textContent = $this->exportFormatter->bookToPlainText($book);
|
||||
|
||||
return $this->download()->directly($textContent, $bookSlug . '.txt');
|
||||
return $this->downloadResponse($textContent, $bookSlug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,6 +66,6 @@ class BookExportController extends Controller
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$textContent = $this->exportFormatter->bookToMarkdown($book);
|
||||
|
||||
return $this->download()->directly($textContent, $bookSlug . '.md');
|
||||
return $this->downloadResponse($textContent, $bookSlug . '.md');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,15 +83,15 @@ class BookshelfController extends Controller
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->checkPermission('bookshelf-create-all');
|
||||
$validated = $this->validate($request, [
|
||||
$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($validated, $bookIds);
|
||||
$shelf = $this->bookshelfRepo->create($request->all(), $bookIds);
|
||||
$this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null));
|
||||
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
@@ -160,21 +160,16 @@ class BookshelfController extends Controller
|
||||
{
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('bookshelf-update', $shelf);
|
||||
$validated = $this->validate($request, [
|
||||
$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, $validated, $bookIds);
|
||||
$shelf = $this->bookshelfRepo->update($shelf, $request->all(), $bookIds);
|
||||
$resetCover = $request->has('image_reset');
|
||||
$this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null), $resetCover);
|
||||
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use BookStack\Entities\Models\Book;
|
||||
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;
|
||||
@@ -273,19 +272,4 @@ class ChapterController extends Controller
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class ChapterExportController extends Controller
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$pdfContent = $this->exportFormatter->chapterToPdf($chapter);
|
||||
|
||||
return $this->download()->directly($pdfContent, $chapterSlug . '.pdf');
|
||||
return $this->downloadResponse($pdfContent, $chapterSlug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ class ChapterExportController extends Controller
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$containedHtml = $this->exportFormatter->chapterToContainedHtml($chapter);
|
||||
|
||||
return $this->download()->directly($containedHtml, $chapterSlug . '.html');
|
||||
return $this->downloadResponse($containedHtml, $chapterSlug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ class ChapterExportController extends Controller
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$chapterText = $this->exportFormatter->chapterToPlainText($chapter);
|
||||
|
||||
return $this->download()->directly($chapterText, $chapterSlug . '.txt');
|
||||
return $this->downloadResponse($chapterText, $chapterSlug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,9 +70,10 @@ class ChapterExportController extends Controller
|
||||
*/
|
||||
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->download()->directly($chapterText, $chapterSlug . '.md');
|
||||
return $this->downloadResponse($chapterText, $chapterSlug . '.md');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,15 @@ namespace BookStack\Http\Controllers;
|
||||
|
||||
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
|
||||
{
|
||||
@@ -108,11 +110,74 @@ abstract class Controller extends BaseController
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new download response factory using the current request.
|
||||
* Create a response that forces a download in the browser.
|
||||
*/
|
||||
protected function download(): DownloadResponseFactory
|
||||
protected function downloadResponse(string $content, string $fileName): Response
|
||||
{
|
||||
return new DownloadResponseFactory(request());
|
||||
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, 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, [
|
||||
'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',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,6 +219,6 @@ abstract class Controller extends BaseController
|
||||
*/
|
||||
protected function getImageValidationRules(): array
|
||||
{
|
||||
return ['image_extension', 'mimes:jpeg,png,gif,webp', 'max:' . (config('app.upload_limit') * 1000)];
|
||||
return ['image_extension', 'mimes:jpeg,png,gif,webp,svg', 'max:' . (config('app.upload_limit') * 1000)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,8 +76,11 @@ class DrawioImageController extends Controller
|
||||
return $this->jsonError('Image data could not be found');
|
||||
}
|
||||
|
||||
$isSvg = strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'svg';
|
||||
$uriPrefix = $isSvg ? 'data:image/svg+xml;base64,' : 'data:image/png;base64,';
|
||||
|
||||
return response()->json([
|
||||
'content' => base64_encode($imageData),
|
||||
'content' => $uriPrefix . base64_encode($imageData),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class PageExportController extends Controller
|
||||
$page->html = (new PageContent($page))->render();
|
||||
$pdfContent = $this->exportFormatter->pageToPdf($page);
|
||||
|
||||
return $this->download()->directly($pdfContent, $pageSlug . '.pdf');
|
||||
return $this->downloadResponse($pdfContent, $pageSlug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +51,7 @@ class PageExportController extends Controller
|
||||
$page->html = (new PageContent($page))->render();
|
||||
$containedHtml = $this->exportFormatter->pageToContainedHtml($page);
|
||||
|
||||
return $this->download()->directly($containedHtml, $pageSlug . '.html');
|
||||
return $this->downloadResponse($containedHtml, $pageSlug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ class PageExportController extends Controller
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$pageText = $this->exportFormatter->pageToPlainText($page);
|
||||
|
||||
return $this->download()->directly($pageText, $pageSlug . '.txt');
|
||||
return $this->downloadResponse($pageText, $pageSlug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,6 +77,6 @@ class PageExportController extends Controller
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$pageText = $this->exportFormatter->pageToMarkdown($page);
|
||||
|
||||
return $this->download()->directly($pageText, $pageSlug . '.md');
|
||||
return $this->downloadResponse($pageText, $pageSlug . '.md');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
<?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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,16 @@ class AttachmentService
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -148,7 +148,8 @@ class ImageRepo
|
||||
*/
|
||||
public function saveDrawing(string $base64Uri, int $uploadedTo): Image
|
||||
{
|
||||
$name = 'Drawing-' . user()->id . '-' . time() . '.png';
|
||||
$isSvg = strpos($base64Uri, 'data:image/svg+xml;') === 0;
|
||||
$name = 'Drawing-' . user()->id . '-' . time() . ($isSvg ? '.svg' : '.png');
|
||||
|
||||
return $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawio', $uploadedTo);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class ImageService
|
||||
protected $image;
|
||||
protected $fileSystem;
|
||||
|
||||
protected static $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
protected static $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'];
|
||||
|
||||
/**
|
||||
* ImageService constructor.
|
||||
@@ -230,6 +230,14 @@ class ImageService
|
||||
return strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'gif';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given image is an SVG image file.
|
||||
*/
|
||||
protected function isSvg(Image $image): bool
|
||||
{
|
||||
return strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'svg';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given image and image data is apng.
|
||||
*/
|
||||
@@ -255,8 +263,8 @@ class ImageService
|
||||
*/
|
||||
public function getThumbnail(Image $image, ?int $width, ?int $height, bool $keepRatio = false): string
|
||||
{
|
||||
// Do not resize GIF images where we're not cropping
|
||||
if ($keepRatio && $this->isGif($image)) {
|
||||
// Do not resize GIF images where we're not cropping or SVG images.
|
||||
if (($keepRatio && $this->isGif($image)) || $this->isSvg($image)) {
|
||||
return $this->getPublicUrl($image->path);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,14 +17,6 @@ class WebSafeMimeSniffer
|
||||
'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',
|
||||
|
||||
587
composer.lock
generated
587
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -21,9 +21,8 @@ class RoleFactory extends Factory
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'display_name' => $this->faker->sentence(3),
|
||||
'description' => $this->faker->sentence(10),
|
||||
'external_auth_id' => '',
|
||||
'display_name' => $this->faker->sentence(3),
|
||||
'description' => $this->faker->sentence(10),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"updated_at": "2019-12-11T20:57:31.000000Z",
|
||||
"created_by": 1,
|
||||
"updated_by": 1,
|
||||
"owned_by": 1
|
||||
"owned_by": 1,
|
||||
"image_id": 3
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
@@ -20,7 +21,8 @@
|
||||
"updated_at": "2019-12-11T20:57:23.000000Z",
|
||||
"created_by": 4,
|
||||
"updated_by": 3,
|
||||
"owned_by": 3
|
||||
"owned_by": 3,
|
||||
"image_id": 34
|
||||
}
|
||||
],
|
||||
"total": 14
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
"updated_at": "2020-01-12T14:16:10.000000Z",
|
||||
"created_by": 1,
|
||||
"updated_by": 1,
|
||||
"owned_by": 1
|
||||
"owned_by": 1,
|
||||
"image_id": 452
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
"updated_at": "2020-04-10T13:00:45.000000Z",
|
||||
"created_by": 4,
|
||||
"updated_by": 1,
|
||||
"owned_by": 1
|
||||
"owned_by": 1,
|
||||
"image_id": 31
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
@@ -20,7 +21,8 @@
|
||||
"updated_at": "2020-04-10T13:00:58.000000Z",
|
||||
"created_by": 4,
|
||||
"updated_by": 1,
|
||||
"owned_by": 1
|
||||
"owned_by": 1,
|
||||
"image_id": 28
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
@@ -31,7 +33,8 @@
|
||||
"updated_at": "2020-04-10T13:00:53.000000Z",
|
||||
"created_by": 4,
|
||||
"updated_by": 1,
|
||||
"owned_by": 4
|
||||
"owned_by": 4,
|
||||
"image_id": 30
|
||||
}
|
||||
],
|
||||
"total": 3
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"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"
|
||||
}
|
||||
439
package-lock.json
generated
439
package-lock.json
generated
@@ -5,21 +5,20 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"clipboard": "^2.0.11",
|
||||
"codemirror": "^5.65.5",
|
||||
"clipboard": "^2.0.10",
|
||||
"codemirror": "^5.65.2",
|
||||
"dropzone": "^5.9.3",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it": "^12.3.2",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"snabbdom": "^3.5.0",
|
||||
"sortablejs": "^1.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chokidar-cli": "^3.0",
|
||||
"esbuild": "0.14.42",
|
||||
"esbuild": "0.14.36",
|
||||
"livereload": "^0.9.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"punycode": "^2.1.1",
|
||||
"sass": "^1.52.1"
|
||||
"sass": "^1.50.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
@@ -174,9 +173,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/clipboard": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
|
||||
"integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.10.tgz",
|
||||
"integrity": "sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g==",
|
||||
"dependencies": {
|
||||
"good-listener": "^1.2.2",
|
||||
"select": "^1.1.2",
|
||||
@@ -195,9 +194,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/codemirror": {
|
||||
"version": "5.65.5",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.5.tgz",
|
||||
"integrity": "sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w=="
|
||||
"version": "5.65.2",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz",
|
||||
"integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA=="
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
@@ -274,12 +273,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
|
||||
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
@@ -345,9 +341,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz",
|
||||
"integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.36.tgz",
|
||||
"integrity": "sha512-HhFHPiRXGYOCRlrhpiVDYKcFJRdO0sBElZ668M4lh2ER0YgnkLxECuFe7uWCf23FrcLc59Pqr7dHkTqmRPDHmw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
@@ -357,32 +353,32 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"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": "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"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz",
|
||||
"integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -396,9 +392,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-arm64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz",
|
||||
"integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.36.tgz",
|
||||
"integrity": "sha512-/hYkyFe7x7Yapmfv4X/tBmyKnggUmdQmlvZ8ZlBnV4+PjisrEhAvC3yWpURuD9XoB8Wa1d5dGkTsF53pIvpjsg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -412,9 +408,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz",
|
||||
"integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.36.tgz",
|
||||
"integrity": "sha512-kkl6qmV0dTpyIMKagluzYqlc1vO0ecgpviK/7jwPbRDEv5fejRTaBBEE2KxEQbTHcLhiiDbhG7d5UybZWo/1zQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -428,9 +424,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.36.tgz",
|
||||
"integrity": "sha512-q8fY4r2Sx6P0Pr3VUm//eFYKVk07C5MHcEinU1BjyFnuYz4IxR/03uBbDwluR6ILIHnZTE7AkTUWIdidRi1Jjw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -444,9 +440,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz",
|
||||
"integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.36.tgz",
|
||||
"integrity": "sha512-Hn8AYuxXXRptybPqoMkga4HRFE7/XmhtlQjXFHoAIhKUPPMeJH35GYEUWGbjteai9FLFvBAjEAlwEtSGxnqWww==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -460,9 +456,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-arm64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz",
|
||||
"integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -476,9 +472,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-32": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz",
|
||||
"integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.36.tgz",
|
||||
"integrity": "sha512-Eh9OkyTrEZn9WGO4xkI3OPPpUX7p/3QYvdG0lL4rfr73Ap2HAr6D9lP59VMF64Ex01LhHSXwIsFG/8AQjh6eNw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -492,9 +488,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.36.tgz",
|
||||
"integrity": "sha512-vFVFS5ve7PuwlfgoWNyRccGDi2QTNkQo/2k5U5ttVD0jRFaMlc8UQee708fOZA6zTCDy5RWsT5MJw3sl2X6KDg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -508,9 +504,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm": {
|
||||
"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==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -524,9 +520,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz",
|
||||
"integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -540,9 +536,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-mips64le": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz",
|
||||
"integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
@@ -556,9 +552,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-ppc64le": {
|
||||
"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==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -572,9 +568,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-riscv64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz",
|
||||
"integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.36.tgz",
|
||||
"integrity": "sha512-dOE5pt3cOdqEhaufDRzNCHf5BSwxgygVak9UR7PH7KPVHwSTDAZHDoEjblxLqjJYpc5XaU9+gKJ9F8mp9r5I4A==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -588,9 +584,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-s390x": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.36.tgz",
|
||||
"integrity": "sha512-g4FMdh//BBGTfVHjF6MO7Cz8gqRoDPzXWxRvWkJoGroKA18G9m0wddvPbEqcQf5Tbt2vSc1CIgag7cXwTmoTXg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -604,9 +600,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-netbsd-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.36.tgz",
|
||||
"integrity": "sha512-UB2bVImxkWk4vjnP62ehFNZ73lQY1xcnL5ZNYF3x0AG+j8HgdkNF05v67YJdCIuUJpBuTyCK8LORCYo9onSW+A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -620,9 +616,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-openbsd-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.36.tgz",
|
||||
"integrity": "sha512-NvGB2Chf8GxuleXRGk8e9zD3aSdRO5kLt9coTQbCg7WMGXeX471sBgh4kSg8pjx0yTXRt0MlrUDnjVYnetyivg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -636,9 +632,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sunos-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.36.tgz",
|
||||
"integrity": "sha512-VkUZS5ftTSjhRjuRLp+v78auMO3PZBXu6xl4ajomGenEm2/rGuWlhFSjB7YbBNErOchj51Jb2OK8lKAo8qdmsQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -652,9 +648,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-32": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz",
|
||||
"integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -668,9 +664,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.36.tgz",
|
||||
"integrity": "sha512-+p4MuRZekVChAeueT1Y9LGkxrT5x7YYJxYE8ZOTcEfeUUN43vktSn6hUNsvxzzATrSgq5QqRdllkVBxWZg7KqQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -684,9 +680,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-arm64": {
|
||||
"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==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1131,9 +1127,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
|
||||
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
|
||||
"integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
|
||||
"dependencies": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
@@ -1203,13 +1199,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
|
||||
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
|
||||
"version": "12.3.2",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
|
||||
"integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "~3.0.1",
|
||||
"linkify-it": "^4.0.1",
|
||||
"entities": "~2.1.0",
|
||||
"linkify-it": "^3.0.1",
|
||||
"mdurl": "^1.0.1",
|
||||
"uc.micro": "^1.0.5"
|
||||
},
|
||||
@@ -1524,9 +1520,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.52.1",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz",
|
||||
"integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==",
|
||||
"version": "1.50.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz",
|
||||
"integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": ">=3.0.0 <4.0.0",
|
||||
@@ -1601,14 +1597,6 @@
|
||||
"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",
|
||||
@@ -2014,9 +2002,9 @@
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
|
||||
"integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.10.tgz",
|
||||
"integrity": "sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g==",
|
||||
"requires": {
|
||||
"good-listener": "^1.2.2",
|
||||
"select": "^1.1.2",
|
||||
@@ -2035,9 +2023,9 @@
|
||||
}
|
||||
},
|
||||
"codemirror": {
|
||||
"version": "5.65.5",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.5.tgz",
|
||||
"integrity": "sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w=="
|
||||
"version": "5.65.2",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz",
|
||||
"integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA=="
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
@@ -2105,9 +2093,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"entities": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
|
||||
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.2",
|
||||
@@ -2158,170 +2146,170 @@
|
||||
}
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz",
|
||||
"integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==",
|
||||
"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.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": "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": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz",
|
||||
"integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==",
|
||||
"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==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-android-arm64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz",
|
||||
"integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.36.tgz",
|
||||
"integrity": "sha512-/hYkyFe7x7Yapmfv4X/tBmyKnggUmdQmlvZ8ZlBnV4+PjisrEhAvC3yWpURuD9XoB8Wa1d5dGkTsF53pIvpjsg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-darwin-64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz",
|
||||
"integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.36.tgz",
|
||||
"integrity": "sha512-kkl6qmV0dTpyIMKagluzYqlc1vO0ecgpviK/7jwPbRDEv5fejRTaBBEE2KxEQbTHcLhiiDbhG7d5UybZWo/1zQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-darwin-arm64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.36.tgz",
|
||||
"integrity": "sha512-q8fY4r2Sx6P0Pr3VUm//eFYKVk07C5MHcEinU1BjyFnuYz4IxR/03uBbDwluR6ILIHnZTE7AkTUWIdidRi1Jjw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-freebsd-64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz",
|
||||
"integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.36.tgz",
|
||||
"integrity": "sha512-Hn8AYuxXXRptybPqoMkga4HRFE7/XmhtlQjXFHoAIhKUPPMeJH35GYEUWGbjteai9FLFvBAjEAlwEtSGxnqWww==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-freebsd-arm64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz",
|
||||
"integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==",
|
||||
"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==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-32": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz",
|
||||
"integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.36.tgz",
|
||||
"integrity": "sha512-Eh9OkyTrEZn9WGO4xkI3OPPpUX7p/3QYvdG0lL4rfr73Ap2HAr6D9lP59VMF64Ex01LhHSXwIsFG/8AQjh6eNw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.36.tgz",
|
||||
"integrity": "sha512-vFVFS5ve7PuwlfgoWNyRccGDi2QTNkQo/2k5U5ttVD0jRFaMlc8UQee708fOZA6zTCDy5RWsT5MJw3sl2X6KDg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-arm": {
|
||||
"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==",
|
||||
"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==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-arm64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz",
|
||||
"integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==",
|
||||
"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==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-mips64le": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz",
|
||||
"integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==",
|
||||
"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==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-ppc64le": {
|
||||
"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==",
|
||||
"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==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-riscv64": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz",
|
||||
"integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.36.tgz",
|
||||
"integrity": "sha512-dOE5pt3cOdqEhaufDRzNCHf5BSwxgygVak9UR7PH7KPVHwSTDAZHDoEjblxLqjJYpc5XaU9+gKJ9F8mp9r5I4A==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-s390x": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.36.tgz",
|
||||
"integrity": "sha512-g4FMdh//BBGTfVHjF6MO7Cz8gqRoDPzXWxRvWkJoGroKA18G9m0wddvPbEqcQf5Tbt2vSc1CIgag7cXwTmoTXg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-netbsd-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.36.tgz",
|
||||
"integrity": "sha512-UB2bVImxkWk4vjnP62ehFNZ73lQY1xcnL5ZNYF3x0AG+j8HgdkNF05v67YJdCIuUJpBuTyCK8LORCYo9onSW+A==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-openbsd-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.36.tgz",
|
||||
"integrity": "sha512-NvGB2Chf8GxuleXRGk8e9zD3aSdRO5kLt9coTQbCg7WMGXeX471sBgh4kSg8pjx0yTXRt0MlrUDnjVYnetyivg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-sunos-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.36.tgz",
|
||||
"integrity": "sha512-VkUZS5ftTSjhRjuRLp+v78auMO3PZBXu6xl4ajomGenEm2/rGuWlhFSjB7YbBNErOchj51Jb2OK8lKAo8qdmsQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-32": {
|
||||
"version": "0.14.42",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz",
|
||||
"integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==",
|
||||
"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==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-64": {
|
||||
"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==",
|
||||
"version": "0.14.36",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.36.tgz",
|
||||
"integrity": "sha512-+p4MuRZekVChAeueT1Y9LGkxrT5x7YYJxYE8ZOTcEfeUUN43vktSn6hUNsvxzzATrSgq5QqRdllkVBxWZg7KqQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-arm64": {
|
||||
"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==",
|
||||
"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==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@@ -2627,9 +2615,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"linkify-it": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
|
||||
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
|
||||
"integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
|
||||
"requires": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
@@ -2687,13 +2675,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
|
||||
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
|
||||
"version": "12.3.2",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
|
||||
"integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "~3.0.1",
|
||||
"linkify-it": "^4.0.1",
|
||||
"entities": "~2.1.0",
|
||||
"linkify-it": "^3.0.1",
|
||||
"mdurl": "^1.0.1",
|
||||
"uc.micro": "^1.0.5"
|
||||
}
|
||||
@@ -2922,9 +2910,9 @@
|
||||
}
|
||||
},
|
||||
"sass": {
|
||||
"version": "1.52.1",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz",
|
||||
"integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==",
|
||||
"version": "1.50.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz",
|
||||
"integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": ">=3.0.0 <4.0.0",
|
||||
@@ -2981,11 +2969,6 @@
|
||||
"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",
|
||||
|
||||
15
package.json
15
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build:css:dev": "sass ./resources/sass:./public/dist --embed-sources",
|
||||
"build:css:watch": "sass ./resources/sass:./public/dist --watch --embed-sources",
|
||||
"build:css:dev": "sass ./resources/sass:./public/dist",
|
||||
"build:css:watch": "sass ./resources/sass:./public/dist --watch",
|
||||
"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\"",
|
||||
@@ -16,19 +16,18 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"chokidar-cli": "^3.0",
|
||||
"esbuild": "0.14.42",
|
||||
"esbuild": "0.14.36",
|
||||
"livereload": "^0.9.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"punycode": "^2.1.1",
|
||||
"sass": "^1.52.1"
|
||||
"sass": "^1.50.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"clipboard": "^2.0.11",
|
||||
"codemirror": "^5.65.5",
|
||||
"clipboard": "^2.0.10",
|
||||
"codemirror": "^5.65.2",
|
||||
"dropzone": "^5.9.3",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it": "^12.3.2",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"snabbdom": "^3.5.0",
|
||||
"sortablejs": "^1.15.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
<server name="MAIL_DRIVER" value="array"/>
|
||||
<server name="LOG_CHANNEL" value="single"/>
|
||||
<server name="AUTH_METHOD" value="standard"/>
|
||||
<server name="AUTH_AUTO_INITIATE" value="false"/>
|
||||
<server name="DISABLE_EXTERNAL_SERVICES" value="true"/>
|
||||
<server name="ALLOW_UNTRUSTED_SERVER_FETCHING" value="false"/>
|
||||
<server name="AVATAR_URL" value=""/>
|
||||
|
||||
62
public/dist/app.js
vendored
62
public/dist/app.js
vendored
File diff suppressed because one or more lines are too long
32
public/dist/code.js
vendored
32
public/dist/code.js
vendored
File diff suppressed because one or more lines are too long
1
public/dist/export-styles.css
vendored
1
public/dist/export-styles.css
vendored
File diff suppressed because one or more lines are too long
1
public/dist/print-styles.css
vendored
1
public/dist/print-styles.css
vendored
@@ -1 +0,0 @@
|
||||
:root{--color-primary: #206ea7;--color-primary-light: rgba(32,110,167,0.15);--color-page: #206ea7;--color-page-draft: #7e50b1;--color-chapter: #af4d0d;--color-book: #077b70;--color-bookshelf: #a94747}header{display:none}html,body{font-size:12px;background-color:#fff}.page-content{margin:0 auto}.print-hidden{display:none !important}.tri-layout-container{grid-template-columns:1fr;grid-template-areas:"b";margin-inline-start:0;margin-inline-end:0;display:block}.card{box-shadow:none}.content-wrap.card{padding-inline-start:0;padding-inline-end:0}/*# sourceMappingURL=print-styles.css.map */
|
||||
1
public/dist/styles.css
vendored
1
public/dist/styles.css
vendored
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 297 B |
@@ -25,7 +25,6 @@ import 'codemirror/mode/ruby/ruby';
|
||||
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';
|
||||
@@ -50,19 +49,16 @@ const modeMap = {
|
||||
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: 'text/javascript',
|
||||
json: 'application/json',
|
||||
js: 'text/javascript',
|
||||
jl: 'text/x-julia',
|
||||
julia: 'text/x-julia',
|
||||
latex: 'text/x-stex',
|
||||
javascript: 'javascript',
|
||||
json: {name: 'javascript', json: true},
|
||||
js: 'javascript',
|
||||
jl: 'julia',
|
||||
julia: 'julia',
|
||||
lua: 'lua',
|
||||
md: 'markdown',
|
||||
mdown: 'markdown',
|
||||
@@ -73,7 +69,7 @@ const modeMap = {
|
||||
pl: 'perl',
|
||||
powershell: 'powershell',
|
||||
properties: 'properties',
|
||||
ocaml: 'text/x-ocaml',
|
||||
ocaml: 'mllike',
|
||||
pascal: 'text/x-pascal',
|
||||
pas: 'text/x-pascal',
|
||||
php: (content) => {
|
||||
@@ -87,11 +83,8 @@ const modeMap = {
|
||||
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',
|
||||
@@ -249,21 +242,6 @@ export function popupEditor(elem, modeSuggestion) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
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;
|
||||
33
resources/js/components/chapter-toggle.js
Normal file
33
resources/js/components/chapter-toggle.js
Normal file
@@ -0,0 +1,33 @@
|
||||
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;
|
||||
@@ -33,11 +33,10 @@ class CodeEditor {
|
||||
onSelect(this.languageLinks, event => {
|
||||
const language = event.target.dataset.lang;
|
||||
this.languageInput.value = language;
|
||||
this.languageInputChange(language);
|
||||
this.updateEditorMode(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) => {
|
||||
@@ -61,7 +60,7 @@ class CodeEditor {
|
||||
this.callback = callback;
|
||||
|
||||
this.show()
|
||||
.then(() => this.languageInputChange(language))
|
||||
.then(() => this.updateEditorMode(language))
|
||||
.then(() => window.importVersioned('code'))
|
||||
.then(Code => Code.setContent(this.editor, code));
|
||||
}
|
||||
@@ -91,22 +90,6 @@ class CodeEditor {
|
||||
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();
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
@@ -1,5 +1,4 @@
|
||||
import {debounce} from "../services/util";
|
||||
import {transitionHeight} from "../services/animations";
|
||||
|
||||
class DropdownSearch {
|
||||
|
||||
@@ -52,9 +51,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -28,31 +28,18 @@ class DropDown {
|
||||
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 = `${(menuOriginalRect.right - menuOriginalRect.width)}px`;
|
||||
this.menu.style.right = `${(this.rect.right - this.rect.width)}px`;
|
||||
} else {
|
||||
this.menu.style.left = `${menuOriginalRect.left}px`;
|
||||
this.menu.style.left = `${this.rect.left}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';
|
||||
this.menu.style.top = `${this.rect.top}px`;
|
||||
this.menu.style.width = `${this.rect.width}px`;
|
||||
}
|
||||
|
||||
// Set listener to hide on mouse leave or window click
|
||||
@@ -87,21 +74,18 @@ class DropDown {
|
||||
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]:not([tabindex="-1"]),[href],button,input:not([type=hidden])'));
|
||||
return Array.from(this.menu.querySelectorAll('[tabindex],[href],button,input:not([type=hidden])'));
|
||||
}
|
||||
|
||||
focusNext() {
|
||||
|
||||
@@ -7,9 +7,9 @@ class EntitySelectorPopup {
|
||||
setup() {
|
||||
this.elem = this.$el;
|
||||
this.selectButton = this.$refs.select;
|
||||
this.searchInput = this.$refs.searchInput;
|
||||
|
||||
window.EntitySelectorPopup = this;
|
||||
this.selectorEl = this.$refs.selector;
|
||||
|
||||
this.callback = null;
|
||||
this.selection = null;
|
||||
@@ -22,17 +22,13 @@ class EntitySelectorPopup {
|
||||
show(callback) {
|
||||
this.callback = callback;
|
||||
this.elem.components.popup.show();
|
||||
this.getSelector().focusSearch();
|
||||
this.searchInput.focus();
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.elem.components.popup.hide();
|
||||
}
|
||||
|
||||
getSelector() {
|
||||
return this.selectorEl.components['entity-selector'];
|
||||
}
|
||||
|
||||
onSelectButtonClick() {
|
||||
this.hide();
|
||||
if (this.selection !== null && this.callback) this.callback(this.selection);
|
||||
@@ -40,7 +36,6 @@ class EntitySelectorPopup {
|
||||
|
||||
onSelectionConfirm(entity) {
|
||||
this.hide();
|
||||
this.getSelector().reset();
|
||||
if (this.callback && entity) this.callback(entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,16 +87,6 @@ class EntitySelector {
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.searchInput.value = '';
|
||||
this.showLoading();
|
||||
this.initialLoad();
|
||||
}
|
||||
|
||||
focusSearch() {
|
||||
this.searchInput.focus();
|
||||
}
|
||||
|
||||
showLoading() {
|
||||
this.loading.style.display = 'block';
|
||||
this.resultsContainer.style.display = 'none';
|
||||
|
||||
@@ -6,10 +6,9 @@ import attachmentsList from "./attachments-list.js"
|
||||
import autoSuggest from "./auto-suggest.js"
|
||||
import backToTop from "./back-to-top.js"
|
||||
import bookSort from "./book-sort.js"
|
||||
import chapterContents from "./chapter-contents.js"
|
||||
import chapterToggle from "./chapter-toggle.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"
|
||||
@@ -63,10 +62,9 @@ const componentMapping = {
|
||||
"auto-suggest": autoSuggest,
|
||||
"back-to-top": backToTop,
|
||||
"book-sort": bookSort,
|
||||
"chapter-contents": chapterContents,
|
||||
"chapter-toggle": chapterToggle,
|
||||
"code-editor": codeEditor,
|
||||
"code-highlighter": codeHighlighter,
|
||||
"code-textarea": codeTextarea,
|
||||
"collapsible": collapsible,
|
||||
"confirm-dialog": confirmDialog,
|
||||
"custom-checkbox": customCheckbox,
|
||||
|
||||
@@ -2,7 +2,7 @@ import MarkdownIt from "markdown-it";
|
||||
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 {
|
||||
@@ -18,10 +18,8 @@ class MarkdownEditor {
|
||||
this.markdown = new MarkdownIt({html: true});
|
||||
this.markdown.use(mdTasksLists, {label: true});
|
||||
|
||||
this.display = this.elem.querySelector('.markdown-display');
|
||||
|
||||
this.displayStylesLoaded = false;
|
||||
this.input = this.elem.querySelector('textarea');
|
||||
this.display = this.$refs.display;
|
||||
this.input = this.$refs.input;
|
||||
|
||||
this.cm = null;
|
||||
this.Code = null;
|
||||
@@ -32,23 +30,13 @@ class MarkdownEditor {
|
||||
});
|
||||
|
||||
this.onMarkdownScroll = this.onMarkdownScroll.bind(this);
|
||||
|
||||
const displayLoad = () => {
|
||||
this.displayDoc = this.display.contentDocument;
|
||||
this.init(cmLoadPromise);
|
||||
};
|
||||
|
||||
if (this.display.contentDocument.readyState === 'complete') {
|
||||
displayLoad();
|
||||
} else {
|
||||
this.display.addEventListener('load', displayLoad.bind(this));
|
||||
}
|
||||
|
||||
window.$events.emitPublic(this.elem, 'editor-markdown::setup', {
|
||||
markdownIt: this.markdown,
|
||||
displayEl: this.display,
|
||||
codeMirrorInstance: this.cm,
|
||||
});
|
||||
|
||||
this.init(cmLoadPromise);
|
||||
}
|
||||
|
||||
init(cmLoadPromise) {
|
||||
@@ -56,17 +44,17 @@ class MarkdownEditor {
|
||||
let lastClick = 0;
|
||||
|
||||
// Prevent markdown display link click redirect
|
||||
this.displayDoc.addEventListener('click', event => {
|
||||
let isDblClick = Date.now() - lastClick < 300;
|
||||
this.display.addEventListener('click', event => {
|
||||
const isDblClick = Date.now() - lastClick < 300;
|
||||
|
||||
let link = event.target.closest('a');
|
||||
const link = event.target.closest('a');
|
||||
if (link !== null) {
|
||||
event.preventDefault();
|
||||
window.open(link.getAttribute('href'));
|
||||
return;
|
||||
}
|
||||
|
||||
let drawing = event.target.closest('[drawio-diagram]');
|
||||
const drawing = event.target.closest('[drawio-diagram]');
|
||||
if (drawing !== null && isDblClick) {
|
||||
this.actionEditDrawing(drawing);
|
||||
return;
|
||||
@@ -77,10 +65,10 @@ class MarkdownEditor {
|
||||
|
||||
// Button actions
|
||||
this.elem.addEventListener('click', event => {
|
||||
let button = event.target.closest('button[data-action]');
|
||||
const button = event.target.closest('button[data-action]');
|
||||
if (button === null) return;
|
||||
|
||||
let action = button.getAttribute('data-action');
|
||||
const action = button.getAttribute('data-action');
|
||||
if (action === 'insertImage') this.actionInsertImage();
|
||||
if (action === 'insertLink') this.actionShowLinkSelector();
|
||||
if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) {
|
||||
@@ -127,53 +115,16 @@ 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';
|
||||
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');
|
||||
// Set display to be dark mode if parent is
|
||||
|
||||
if (document.documentElement.classList.contains('dark-mode')) {
|
||||
this.displayDoc.documentElement.style.backgroundColor = '#222';
|
||||
this.displayDoc.documentElement.classList.add('dark-mode');
|
||||
}
|
||||
|
||||
this.displayDoc.head.innerHTML = '';
|
||||
const styles = document.head.querySelectorAll('style,link[rel=stylesheet]');
|
||||
for (let style of styles) {
|
||||
const copy = style.cloneNode(true);
|
||||
this.displayDoc.head.appendChild(copy);
|
||||
}
|
||||
|
||||
this.displayStylesLoaded = true;
|
||||
this.display.innerHTML = html;
|
||||
}
|
||||
|
||||
onMarkdownScroll(lineCount) {
|
||||
const elems = this.displayDoc.body.children;
|
||||
const elems = this.display.children;
|
||||
if (elems.length <= lineCount) return;
|
||||
|
||||
const topElem = (lineCount === -1) ? elems[elems.length-1] : elems[lineCount];
|
||||
@@ -330,7 +281,7 @@ class MarkdownEditor {
|
||||
let cursor = cm.getCursor();
|
||||
let lineContent = cm.getLine(cursor.line);
|
||||
let lineLen = lineContent.length;
|
||||
let newLineContent = lineContent;
|
||||
let newLineContent;
|
||||
|
||||
if (lineContent.indexOf(start) === 0 && lineContent.slice(-end.length) === end) {
|
||||
newLineContent = lineContent.slice(start.length, lineContent.length - end.length);
|
||||
@@ -346,9 +297,9 @@ class MarkdownEditor {
|
||||
let selection = cm.getSelection();
|
||||
if (selection === '') return wrapLine(start, end);
|
||||
|
||||
let newSelection = selection;
|
||||
let newSelection;
|
||||
let frontDiff = 0;
|
||||
let endDiff = 0;
|
||||
let endDiff;
|
||||
|
||||
if (selection.indexOf(start) === 0 && selection.slice(-end.length) === end) {
|
||||
newSelection = selection.slice(start.length, selection.length - end.length);
|
||||
@@ -458,10 +409,10 @@ class MarkdownEditor {
|
||||
|
||||
DrawIO.show(url,() => {
|
||||
return Promise.resolve('');
|
||||
}, (pngData) => {
|
||||
}, (drawingData) => {
|
||||
|
||||
const data = {
|
||||
image: pngData,
|
||||
image: drawingData,
|
||||
uploaded_to: Number(this.pageId),
|
||||
};
|
||||
|
||||
@@ -475,7 +426,7 @@ class MarkdownEditor {
|
||||
}
|
||||
|
||||
insertDrawing(image, originalCursor) {
|
||||
const newText = `<div drawio-diagram="${image.id}"><img src="${image.url}"></div>`;
|
||||
const newText = DrawIO.buildDrawingContentHtml(image);
|
||||
this.cm.focus();
|
||||
this.cm.replaceSelection(newText);
|
||||
this.cm.setCursor(originalCursor.line, originalCursor.ch + newText.length);
|
||||
@@ -493,21 +444,22 @@ class MarkdownEditor {
|
||||
|
||||
DrawIO.show(drawioUrl, () => {
|
||||
return DrawIO.load(drawingId);
|
||||
}, (pngData) => {
|
||||
}, (drawingData) => {
|
||||
|
||||
let data = {
|
||||
image: pngData,
|
||||
image: drawingData,
|
||||
uploaded_to: Number(this.pageId),
|
||||
};
|
||||
|
||||
window.$http.post("/images/drawio", data).then(resp => {
|
||||
let newText = `<div drawio-diagram="${resp.data.id}"><img src="${resp.data.url}"></div>`;
|
||||
let newContent = this.cm.getValue().split('\n').map(line => {
|
||||
if (line.indexOf(`drawio-diagram="${drawingId}"`) !== -1) {
|
||||
return newText;
|
||||
}
|
||||
return line;
|
||||
const image = resp.data;
|
||||
const newText = DrawIO.buildDrawingContentHtml(image);
|
||||
|
||||
const newContent = this.cm.getValue().split('\n').map(line => {
|
||||
const isDrawing = line.includes(`drawio-diagram="${drawingId}"`);
|
||||
return isDrawing ? newText : line;
|
||||
}).join('\n');
|
||||
|
||||
this.cm.setValue(newContent);
|
||||
this.cm.setCursor(cursorPos);
|
||||
this.cm.focus();
|
||||
|
||||
@@ -24,7 +24,7 @@ class PageEditor {
|
||||
this.draftDisplayIcon = this.$refs.draftDisplayIcon;
|
||||
this.changelogInput = this.$refs.changelogInput;
|
||||
this.changelogDisplay = this.$refs.changelogDisplay;
|
||||
this.changeEditorButtons = this.$manyRefs.changeEditor;
|
||||
this.changeEditorButtons = this.$manyRefs.changeEditor || [];
|
||||
this.switchDialogContainer = this.$refs.switchDialog;
|
||||
|
||||
// Translations
|
||||
|
||||
@@ -49,7 +49,7 @@ export function slideUp(element, animTime = 400) {
|
||||
const currentPaddingTop = computedStyles.getPropertyValue('padding-top');
|
||||
const currentPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
|
||||
const animStyles = {
|
||||
maxHeight: [`${currentHeight}px`, '0px'],
|
||||
height: [`${currentHeight}px`, '0px'],
|
||||
overflow: ['hidden', 'hidden'],
|
||||
paddingTop: [currentPaddingTop, '0px'],
|
||||
paddingBottom: [currentPaddingBottom, '0px'],
|
||||
@@ -73,7 +73,7 @@ export function slideDown(element, animTime = 400) {
|
||||
const targetPaddingTop = computedStyles.getPropertyValue('padding-top');
|
||||
const targetPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
|
||||
const animStyles = {
|
||||
maxHeight: ['0px', `${targetHeight}px`],
|
||||
height: ['0px', `${targetHeight}px`],
|
||||
overflow: ['hidden', 'hidden'],
|
||||
paddingTop: ['0px', targetPaddingTop],
|
||||
paddingBottom: ['0px', targetPaddingBottom],
|
||||
@@ -82,38 +82,6 @@ export function slideDown(element, animTime = 400) {
|
||||
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
|
||||
|
||||
@@ -55,7 +55,7 @@ function drawEventExport(message) {
|
||||
}
|
||||
|
||||
function drawEventSave(message) {
|
||||
drawPostMessage({action: 'export', format: 'xmlpng', xml: message.xml, spin: 'Updating drawing'});
|
||||
drawPostMessage({action: 'export', format: 'xmlsvg', xml: message.xml, spin: 'Updating drawing'});
|
||||
}
|
||||
|
||||
function drawEventInit() {
|
||||
@@ -96,7 +96,21 @@ async function upload(imageData, pageUploadedToId) {
|
||||
*/
|
||||
async function load(drawingId) {
|
||||
const resp = await window.$http.get(window.baseUrl(`/images/drawio/base64/${drawingId}`));
|
||||
return `data:image/png;base64,${resp.data.content}`;
|
||||
return resp.data.content;
|
||||
}
|
||||
|
||||
export default {show, close, upload, load};
|
||||
|
||||
function buildDrawingContentHtml(drawing) {
|
||||
const isSvg = drawing.url.split('.').pop().toLowerCase() === 'svg';
|
||||
const image = `<img src="${drawing.url}">`;
|
||||
const embed = `<embed src="${drawing.url}" type="image/svg+xml">`;
|
||||
return `<div drawio-diagram="${drawing.id}">${isSvg ? embed : image}</div>`
|
||||
}
|
||||
|
||||
function buildDrawingContentNode(drawing) {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = buildDrawingContentHtml(drawing);
|
||||
return div.children[0];
|
||||
}
|
||||
|
||||
export default {show, close, upload, load, buildDrawingContentHtml, buildDrawingContentNode};
|
||||
@@ -1,31 +0,0 @@
|
||||
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));
|
||||
}
|
||||
@@ -60,7 +60,13 @@ async function uploadImageFile(file, pageId) {
|
||||
throw new Error(`Not an image file`);
|
||||
}
|
||||
|
||||
const remoteFilename = file.name || `image-${Date.now()}.png`;
|
||||
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 formData = new FormData();
|
||||
formData.append('file', file, remoteFilename);
|
||||
formData.append('uploaded_to', pageId);
|
||||
|
||||
@@ -86,13 +86,7 @@ function defineCodeBlockCustomElement(editor) {
|
||||
getContent() {
|
||||
const code = this.querySelector('code') || this.querySelector('pre');
|
||||
const tempEl = document.createElement('pre');
|
||||
tempEl.innerHTML = code.innerHTML.replace(/\ufeff/g, '');
|
||||
|
||||
const brs = tempEl.querySelectorAll('br');
|
||||
for (const br of brs) {
|
||||
br.replaceWith('\n');
|
||||
}
|
||||
|
||||
tempEl.innerHTML = code.innerHTML.replace().replace(/<br\s*[\/]?>/gi ,'\n').replace(/\ufeff/g, '');
|
||||
return tempEl.textContent;
|
||||
}
|
||||
|
||||
@@ -110,7 +104,6 @@ function defineCodeBlockCustomElement(editor) {
|
||||
|
||||
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(() => {
|
||||
@@ -166,7 +159,6 @@ function register(editor, url) {
|
||||
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);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import DrawIO from "../services/drawio";
|
||||
import {build} from "./config";
|
||||
|
||||
let pageEditor = null;
|
||||
let currentNode = null;
|
||||
@@ -15,15 +16,14 @@ function isDrawing(node) {
|
||||
function showDrawingManager(mceEditor, selectedNode = null) {
|
||||
pageEditor = mceEditor;
|
||||
currentNode = selectedNode;
|
||||
|
||||
// Show image manager
|
||||
window.ImageManager.show(function (image) {
|
||||
if (selectedNode) {
|
||||
let imgElem = selectedNode.querySelector('img');
|
||||
pageEditor.dom.setAttrib(imgElem, 'src', image.url);
|
||||
pageEditor.dom.setAttrib(selectedNode, 'drawio-diagram', image.id);
|
||||
pageEditor.dom.replace(buildDrawingNode(image), selectedNode);
|
||||
} else {
|
||||
let imgHTML = `<div drawio-diagram="${image.id}" contenteditable="false"><img src="${image.url}"></div>`;
|
||||
pageEditor.insertContent(imgHTML);
|
||||
const drawingHtml = DrawIO.buildDrawingContentHtml(image);
|
||||
pageEditor.insertContent(drawingHtml);
|
||||
}
|
||||
}, 'drawio');
|
||||
}
|
||||
@@ -34,7 +34,14 @@ function showDrawingEditor(mceEditor, selectedNode = null) {
|
||||
DrawIO.show(options.drawioUrl, drawingInit, updateContent);
|
||||
}
|
||||
|
||||
async function updateContent(pngData) {
|
||||
function buildDrawingNode(drawing) {
|
||||
const drawingEl = DrawIO.buildDrawingContentNode(drawing);
|
||||
drawingEl.setAttribute('contenteditable', 'false');
|
||||
drawingEl.setAttribute('data-ephox-embed-iri', 'true');
|
||||
return drawingEl;
|
||||
}
|
||||
|
||||
async function updateContent(drawingData) {
|
||||
const id = "image-" + Math.random().toString(16).slice(2);
|
||||
const loadingImage = window.baseUrl('/loading.gif');
|
||||
|
||||
@@ -50,11 +57,9 @@ async function updateContent(pngData) {
|
||||
// Handle updating an existing image
|
||||
if (currentNode) {
|
||||
DrawIO.close();
|
||||
let imgElem = currentNode.querySelector('img');
|
||||
try {
|
||||
const img = await DrawIO.upload(pngData, options.pageId);
|
||||
pageEditor.dom.setAttrib(imgElem, 'src', img.url);
|
||||
pageEditor.dom.setAttrib(currentNode, 'drawio-diagram', img.id);
|
||||
const img = await DrawIO.upload(drawingData, options.pageId);
|
||||
pageEditor.dom.replace(buildDrawingNode(img), currentNode);
|
||||
} catch (err) {
|
||||
handleUploadError(err);
|
||||
}
|
||||
@@ -62,12 +67,11 @@ async function updateContent(pngData) {
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
pageEditor.insertContent(`<div drawio-diagram contenteditable="false"><img src="${loadingImage}" id="${id}"></div>`);
|
||||
pageEditor.insertContent(`<div drawio-diagram contenteditable="false"><img src="${loadingImage}" alt="Loading" id="${id}"></div>`);
|
||||
DrawIO.close();
|
||||
try {
|
||||
const img = await DrawIO.upload(pngData, options.pageId);
|
||||
pageEditor.dom.setAttrib(id, 'src', img.url);
|
||||
pageEditor.dom.get(id).parentNode.setAttribute('drawio-diagram', img.id);
|
||||
const img = await DrawIO.upload(drawingData, options.pageId);
|
||||
pageEditor.dom.replace(buildDrawingNode(img), pageEditor.dom.get(id).parentNode);
|
||||
} catch (err) {
|
||||
pageEditor.dom.remove(id);
|
||||
handleUploadError(err);
|
||||
@@ -86,7 +90,6 @@ function drawingInit() {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {WysiwygConfigOptions} providedOptions
|
||||
* @return {function(Editor, string)}
|
||||
*/
|
||||
@@ -130,14 +133,28 @@ export function getPlugin(providedOptions) {
|
||||
showDrawingEditor(editor, selectedNode);
|
||||
});
|
||||
|
||||
editor.on('SetContent', function () {
|
||||
const drawings = editor.$('body > div[drawio-diagram]');
|
||||
if (!drawings.length) return;
|
||||
editor.on('PreInit', () => {
|
||||
editor.parser.addNodeFilter('div', function(nodes) {
|
||||
for (const node of nodes) {
|
||||
if (node.attr('drawio-diagram')) {
|
||||
// Set content editable to be false to prevent direct editing of child content.
|
||||
node.attr('contenteditable', 'false');
|
||||
// Set this attribute to prevent drawing contents being parsed as media embeds
|
||||
// to avoid contents being replaced with placeholder images.
|
||||
// TinyMCE embed plugin sources looks for this attribute in its logic.
|
||||
node.attr('data-ephox-embed-iri', 'true');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
editor.undoManager.transact(function () {
|
||||
drawings.each((index, elem) => {
|
||||
elem.setAttribute('contenteditable', 'false');
|
||||
});
|
||||
editor.serializer.addNodeFilter('div', function(nodes) {
|
||||
for (const node of nodes) {
|
||||
// Clean up content attributes
|
||||
if (node.attr('drawio-diagram')) {
|
||||
node.attr('contenteditable', null);
|
||||
node.attr('data-ephox-embed-iri', null);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ return [
|
||||
// Books
|
||||
'book_create' => 'تم إنشاء كتاب',
|
||||
'book_create_notification' => 'تم إنشاء الكتاب بنجاح',
|
||||
'book_create_from_chapter' => 'converted chapter to book',
|
||||
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
|
||||
'book_update' => 'تم تحديث الكتاب',
|
||||
'book_update_notification' => 'تم تحديث الكتاب بنجاح',
|
||||
'book_delete' => 'تم حذف الكتاب',
|
||||
@@ -40,8 +38,6 @@ return [
|
||||
// Bookshelves
|
||||
'bookshelf_create' => 'تم إنشاء رف كتب',
|
||||
'bookshelf_create_notification' => 'تم إنشاء الرف بنجاح',
|
||||
'bookshelf_create_from_book' => 'converted book to bookshelf',
|
||||
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
|
||||
'bookshelf_update' => 'تم تحديث الرف',
|
||||
'bookshelf_update_notification' => 'تم تحديث الرف بنجاح',
|
||||
'bookshelf_delete' => 'تم تحديث الرف',
|
||||
|
||||
@@ -38,11 +38,6 @@ return [
|
||||
'registration_email_domain_invalid' => 'المجال الخاص بالبريد الإلكتروني لا يملك حق الوصول لهذا التطبيق',
|
||||
'register_success' => 'شكراً لإنشاء حسابكم! تم تسجيلكم ودخولكم للحساب الخاص بكم.',
|
||||
|
||||
// Login auto-initiation
|
||||
'auto_init_starting' => 'Attempting Login',
|
||||
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
|
||||
'auto_init_start_link' => 'Proceed with authentication',
|
||||
|
||||
// Password Reset
|
||||
'reset_password' => 'استعادة كلمة المرور',
|
||||
'reset_password_send_instructions' => 'أدخل بريدك الإلكتروني بالأسفل وسيتم إرسال رسالة برابط لاستعادة كلمة المرور.',
|
||||
|
||||
@@ -47,8 +47,6 @@ return [
|
||||
'previous' => 'Previous',
|
||||
'filter_active' => 'Active Filter:',
|
||||
'filter_clear' => 'Clear Filter',
|
||||
'download' => 'Download',
|
||||
'open_in_tab' => 'Open in Tab',
|
||||
|
||||
// Sort Options
|
||||
'sort_options' => 'خيارات الفرز',
|
||||
|
||||
@@ -355,16 +355,4 @@ return [
|
||||
'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?',
|
||||
];
|
||||
|
||||
@@ -28,8 +28,6 @@ return [
|
||||
// Books
|
||||
'book_create' => 'създадена книга',
|
||||
'book_create_notification' => 'Книгата е създадена успешно',
|
||||
'book_create_from_chapter' => 'converted chapter to book',
|
||||
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
|
||||
'book_update' => 'обновена книга',
|
||||
'book_update_notification' => 'Книгата е обновена успешно',
|
||||
'book_delete' => 'изтрита книга',
|
||||
@@ -40,8 +38,6 @@ return [
|
||||
// Bookshelves
|
||||
'bookshelf_create' => 'създаден рафт',
|
||||
'bookshelf_create_notification' => 'Рафтът е създаден успешно',
|
||||
'bookshelf_create_from_book' => 'converted book to bookshelf',
|
||||
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
|
||||
'bookshelf_update' => 'обновен рафт',
|
||||
'bookshelf_update_notification' => 'Рафтът е обновен успешно',
|
||||
'bookshelf_delete' => 'изтрит рафт',
|
||||
|
||||
@@ -38,11 +38,6 @@ return [
|
||||
'registration_email_domain_invalid' => 'Този емейл домейн към момента няма достъп до приложението',
|
||||
'register_success' => 'Благодарим Ви за регистрацията! В момента сте регистриран и сте вписани в приложението.',
|
||||
|
||||
// Login auto-initiation
|
||||
'auto_init_starting' => 'Attempting Login',
|
||||
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
|
||||
'auto_init_start_link' => 'Proceed with authentication',
|
||||
|
||||
// Password Reset
|
||||
'reset_password' => 'Нулиране на паролата',
|
||||
'reset_password_send_instructions' => 'Въведете емейла си и ще ви бъде изпратен емейл с линк за нулиране на паролата.',
|
||||
|
||||
@@ -47,8 +47,6 @@ return [
|
||||
'previous' => 'Предишен',
|
||||
'filter_active' => 'Активен филтър:',
|
||||
'filter_clear' => 'Изчисти филтъра',
|
||||
'download' => 'Download',
|
||||
'open_in_tab' => 'Open in Tab',
|
||||
|
||||
// Sort Options
|
||||
'sort_options' => 'Опции за сортиране',
|
||||
|
||||
@@ -355,16 +355,4 @@ return [
|
||||
'copy_consider_images' => 'Файловете на изображенията в страницата няма да бъдат дубликирани и оригиналните изображения ще запазят връзката си със страницата, на която са били качени първоначално.',
|
||||
'copy_consider_attachments' => 'Прикачените към страницата обекти няма да бъдат копирани.',
|
||||
'copy_consider_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?',
|
||||
];
|
||||
|
||||
@@ -28,8 +28,6 @@ return [
|
||||
// Books
|
||||
'book_create' => 'je kreirao/la knjigu',
|
||||
'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' => 'je ažurirao/la knjigu',
|
||||
'book_update_notification' => 'Book successfully updated',
|
||||
'book_delete' => 'je izbrisao/la knjigu',
|
||||
@@ -40,8 +38,6 @@ return [
|
||||
// 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' => 'je ažurirao/la policu za knjige',
|
||||
'bookshelf_update_notification' => 'Bookshelf successfully updated',
|
||||
'bookshelf_delete' => 'je izbrisao/la policu za knjige',
|
||||
|
||||
@@ -38,11 +38,6 @@ return [
|
||||
'registration_email_domain_invalid' => 'Ta e-mail domena nema pristup ovoj aplikaciji',
|
||||
'register_success' => 'Hvala na registraciji! Sada ste registrovani i prijavljeni.',
|
||||
|
||||
// Login auto-initiation
|
||||
'auto_init_starting' => 'Attempting Login',
|
||||
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
|
||||
'auto_init_start_link' => 'Proceed with authentication',
|
||||
|
||||
// Password Reset
|
||||
'reset_password' => 'Resetuj Lozinku',
|
||||
'reset_password_send_instructions' => 'Unesite vašu e-mail adresu ispod i na nju ćemo vam poslati e-mail sa linkom za promjenu lozinke.',
|
||||
|
||||
@@ -47,8 +47,6 @@ return [
|
||||
'previous' => 'Prethodno',
|
||||
'filter_active' => 'Active Filter:',
|
||||
'filter_clear' => 'Clear Filter',
|
||||
'download' => 'Download',
|
||||
'open_in_tab' => 'Open in Tab',
|
||||
|
||||
// Sort Options
|
||||
'sort_options' => 'Opcije sortiranja',
|
||||
|
||||
@@ -355,16 +355,4 @@ return [
|
||||
'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?',
|
||||
];
|
||||
|
||||
@@ -28,8 +28,6 @@ return [
|
||||
// Books
|
||||
'book_create' => 'ha creat el llibre',
|
||||
'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' => 'ha actualitzat el llibre',
|
||||
'book_update_notification' => 'Book successfully updated',
|
||||
'book_delete' => 'ha suprimit un llibre',
|
||||
@@ -40,8 +38,6 @@ return [
|
||||
// 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' => 'ha actualitzat el prestatge',
|
||||
'bookshelf_update_notification' => 'Bookshelf successfully updated',
|
||||
'bookshelf_delete' => 'ha suprimit un prestatge',
|
||||
|
||||
@@ -38,11 +38,6 @@ return [
|
||||
'registration_email_domain_invalid' => 'Aquest domini de correu electrònic no té accés a aquesta aplicació',
|
||||
'register_success' => 'Gràcies per registrar-vos! Ja us hi heu registrat i heu iniciat la sessió.',
|
||||
|
||||
// Login auto-initiation
|
||||
'auto_init_starting' => 'Attempting Login',
|
||||
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
|
||||
'auto_init_start_link' => 'Proceed with authentication',
|
||||
|
||||
// Password Reset
|
||||
'reset_password' => 'Restableix la contrasenya',
|
||||
'reset_password_send_instructions' => 'Introduïu la vostra adreça electrònica a continuació i us enviarem un correu electrònic amb un enllaç per a restablir la contrasenya.',
|
||||
|
||||
@@ -47,8 +47,6 @@ return [
|
||||
'previous' => 'Previous',
|
||||
'filter_active' => 'Active Filter:',
|
||||
'filter_clear' => 'Clear Filter',
|
||||
'download' => 'Download',
|
||||
'open_in_tab' => 'Open in Tab',
|
||||
|
||||
// Sort Options
|
||||
'sort_options' => 'Opcions d\'ordenació',
|
||||
|
||||
@@ -355,16 +355,4 @@ return [
|
||||
'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?',
|
||||
];
|
||||
|
||||
@@ -28,8 +28,6 @@ return [
|
||||
// Books
|
||||
'book_create' => 'vytvořil/a knihu',
|
||||
'book_create_notification' => 'Kniha byla úspěšně vytvořena',
|
||||
'book_create_from_chapter' => 'converted chapter to book',
|
||||
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
|
||||
'book_update' => 'aktualizoval/a knihu',
|
||||
'book_update_notification' => 'Kniha byla úspěšně aktualizována',
|
||||
'book_delete' => 'odstranil/a knihu',
|
||||
@@ -40,8 +38,6 @@ return [
|
||||
// Bookshelves
|
||||
'bookshelf_create' => 'vytvořil/a knihovnu',
|
||||
'bookshelf_create_notification' => 'Knihovna byla úspěšně vytvořena',
|
||||
'bookshelf_create_from_book' => 'converted book to bookshelf',
|
||||
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
|
||||
'bookshelf_update' => 'aktualizoval/a knihovnu',
|
||||
'bookshelf_update_notification' => 'Knihovna byla úspěšně aktualizována',
|
||||
'bookshelf_delete' => 'odstranil/a knihovnu',
|
||||
|
||||
@@ -38,11 +38,6 @@ return [
|
||||
'registration_email_domain_invalid' => 'Registrace z této e-mailové domény nejsou povoleny',
|
||||
'register_success' => 'Děkujeme za registraci! Nyní jste zaregistrováni a přihlášeni.',
|
||||
|
||||
// Login auto-initiation
|
||||
'auto_init_starting' => 'Attempting Login',
|
||||
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
|
||||
'auto_init_start_link' => 'Proceed with authentication',
|
||||
|
||||
// Password Reset
|
||||
'reset_password' => 'Obnovit heslo',
|
||||
'reset_password_send_instructions' => 'Níže zadejte svou e-mailovou adresu a bude vám zaslán e-mail s odkazem na obnovení hesla.',
|
||||
|
||||
@@ -47,8 +47,6 @@ return [
|
||||
'previous' => 'Předchozí',
|
||||
'filter_active' => 'Aktivní filtr:',
|
||||
'filter_clear' => 'Zrušit filtr',
|
||||
'download' => 'Download',
|
||||
'open_in_tab' => 'Open in Tab',
|
||||
|
||||
// Sort Options
|
||||
'sort_options' => 'Možnosti řazení',
|
||||
|
||||
@@ -247,7 +247,7 @@ return [
|
||||
'pages_permissions_active' => 'Oprávnění stránky byla aktivována',
|
||||
'pages_initial_revision' => 'První vydání',
|
||||
'pages_initial_name' => 'Nová stránka',
|
||||
'pages_editing_draft_notification' => 'Právě upravujete koncept, který byl uložen :timeDiff.',
|
||||
'pages_editing_draft_notification' => 'Právě upravujete koncept, který byl uložen před :timeDiff.',
|
||||
'pages_draft_edited_notification' => 'Tato stránka se od té doby změnila. Je doporučeno aktuální koncept zahodit.',
|
||||
'pages_draft_page_changed_since_creation' => 'Tato stránka byla aktualizována od vytvoření tohoto konceptu. Doporučuje se zrušit tento koncept nebo se postarat o to, abyste si nepřepsali žádné již zadané změny.',
|
||||
'pages_draft_edit_active' => [
|
||||
@@ -355,16 +355,4 @@ return [
|
||||
'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' => 'Přílohy stránky nebudou zkopírovány.',
|
||||
'copy_consider_access' => 'Po změně umístění, vlastníka nebo oprávnění může dojít k tomu, že obsah může být přístupný těm, kteří přístup dříve něměli.',
|
||||
|
||||
// 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?',
|
||||
];
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Activity text strings.
|
||||
* Is used for all the text within activity logs & notifications.
|
||||
*/
|
||||
return [
|
||||
|
||||
// Pages
|
||||
'page_create' => 'tudalen wedi\'i chreu',
|
||||
'page_create_notification' => 'Tudalen wedi\'i chreu\'n llwyddiannus',
|
||||
'page_update' => 'tudalen wedi\'i diweddaru',
|
||||
'page_update_notification' => 'Tudalen wedi\'i diweddaru\'n llwyddiannus',
|
||||
'page_delete' => 'tudalen wedi\'i dileu',
|
||||
'page_delete_notification' => 'Cafodd y dudalen ei dileu yn llwyddiannus',
|
||||
'page_restore' => 'tudalen wedi\'i hadfer',
|
||||
'page_restore_notification' => 'Cafodd y dudalen ei hadfer yn llwyddiannus',
|
||||
'page_move' => 'symwyd tudalen',
|
||||
|
||||
// Chapters
|
||||
'chapter_create' => 'pennod creu',
|
||||
'chapter_create_notification' => 'Pennod wedi\'i chreu\'n llwyddiannus',
|
||||
'chapter_update' => 'pennod wedi diweddaru',
|
||||
'chapter_update_notification' => 'Pennod wedi\'i diweddaru\'n llwyddiannus',
|
||||
'chapter_delete' => 'pennod wedi dileu',
|
||||
'chapter_delete_notification' => 'Pennod wedi\'i dileu\'n llwyddiannus',
|
||||
'chapter_move' => 'pennod wedi symud',
|
||||
|
||||
// Books
|
||||
'book_create' => 'llyfr wedi creu',
|
||||
'book_create_notification' => 'Llyfr wedi\'i creu\'n llwyddiannus',
|
||||
'book_create_from_chapter' => 'converted chapter to book',
|
||||
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
|
||||
'book_update' => 'llyfr wedi diweddaru',
|
||||
'book_update_notification' => 'Llyfr wedi\'i diweddaru\'n llwyddiannus',
|
||||
'book_delete' => 'llyfr wedi\'i dileu',
|
||||
'book_delete_notification' => 'Cafodd y llyfr ei dileu yn llwyddiannus',
|
||||
'book_sort' => 'llyfr wedi\'i ddidoli',
|
||||
'book_sort_notification' => 'Ail-archebwyd y llyfr yn llwyddiannus',
|
||||
|
||||
// Bookshelves
|
||||
'bookshelf_create' => 'creu silff lyfrau',
|
||||
'bookshelf_create_notification' => 'Silff lyfrau wedi\'i chreu\'n llwyddiannus',
|
||||
'bookshelf_create_from_book' => 'converted book to bookshelf',
|
||||
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
|
||||
'bookshelf_update' => 'silff lyfrau wedi\'i diweddaru',
|
||||
'bookshelf_update_notification' => 'Diweddarwyd y silff lyfrau yn llwyddiannus',
|
||||
'bookshelf_delete' => 'silff lyfrau wedi\'i dileu',
|
||||
'bookshelf_delete_notification' => 'Silff lyfrau wedi\'i dileu\'n llwyddiannus',
|
||||
|
||||
// Favourites
|
||||
'favourite_add_notification' => 'Mae ":name" wedi\'i ychwanegu at eich ffefrynnau',
|
||||
'favourite_remove_notification' => 'Mae ":name" wedi\'i tynnu o\'ch ffefrynnau',
|
||||
|
||||
// MFA
|
||||
'mfa_setup_method_notification' => 'Dull aml-ffactor wedi\'i ffurfweddu\'n llwyddiannus',
|
||||
'mfa_remove_method_notification' => 'Llwyddwyd i ddileu dull aml-ffactor',
|
||||
|
||||
// Webhooks
|
||||
'webhook_create' => 'webhook wedi creu',
|
||||
'webhook_create_notification' => 'Webhook wedi\'i creu\'n llwyddiannus',
|
||||
'webhook_update' => 'webhook wedi\'i diweddaru',
|
||||
'webhook_update_notification' => 'Webhook wedi\'i diweddaru\'n llwyddiannus',
|
||||
'webhook_delete' => 'webhook wedi\'i dileu',
|
||||
'webhook_delete_notification' => 'Webhook wedi\'i dileu\'n llwyddiannus',
|
||||
|
||||
// Users
|
||||
'user_update_notification' => 'Diweddarwyd y defnyddiwr yn llwyddiannus',
|
||||
'user_delete_notification' => 'Tynnwyd y defnyddiwr yn llwyddiannus',
|
||||
|
||||
// Other
|
||||
'commented_on' => 'gwnaeth sylwadau ar',
|
||||
'permissions_update' => 'caniatadau wedi\'u diweddaru',
|
||||
];
|
||||
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Authentication Language Lines
|
||||
* The following language lines are used during authentication for various
|
||||
* messages that we need to display to the user.
|
||||
*/
|
||||
return [
|
||||
|
||||
'failed' => 'Nid yw\'r manylion hyn yn cyfateb i\'n cofnodion.',
|
||||
'throttle' => 'Gormod o ymdrechion mewngofnodi. Rhowch gynnig arall arni o gwmpas :seconds eiliadau.',
|
||||
|
||||
// Login & Register
|
||||
'sign_up' => 'Cofrestru',
|
||||
'log_in' => 'Mewngofnodi',
|
||||
'log_in_with' => 'Mewngofnodi efo :socialDriver',
|
||||
'sign_up_with' => 'Cofrestru efo :socialDriver',
|
||||
'logout' => 'Allgofnodi',
|
||||
|
||||
'name' => 'Enw',
|
||||
'username' => 'Enw defnyddiwr',
|
||||
'email' => 'Ebost',
|
||||
'password' => 'Cyfrinair',
|
||||
'password_confirm' => 'Cadarnhau cyfrinair',
|
||||
'password_hint' => 'Rhaid bod o leiaf 8 nod',
|
||||
'forgot_password' => 'Wedi anghofio cyfrinair?',
|
||||
'remember_me' => 'Cofiwch fi',
|
||||
'ldap_email_hint' => 'Rhowch e-bost i\'w ddefnyddio ar gyfer y cyfrif hwn.',
|
||||
'create_account' => 'Creu cyfrif',
|
||||
'already_have_account' => 'Oes gennych chi gyfrif yn barod?',
|
||||
'dont_have_account' => 'Dim cyfrif?',
|
||||
'social_login' => 'Mewngofnodi cymdeithasol',
|
||||
'social_registration' => 'Cofrestru cymdeithasol',
|
||||
'social_registration_text' => 'Cofrestru a mewngofnodi gan ddefnyddio dyfais arall.',
|
||||
|
||||
'register_thanks' => 'Diolch am cofrestru!',
|
||||
'register_confirm' => 'Gwiriwch eich e-bost a chliciwch ar y botwm cadarnhau i gael mynediad i: appName.',
|
||||
'registrations_disabled' => 'Mae cofrestriadau wedi\'u hanalluogi ar hyn o bryd',
|
||||
'registration_email_domain_invalid' => 'Nid oes gan y parth e-bost hwnnw fynediad i\'r rhaglen hon',
|
||||
'register_success' => 'Diolch am arwyddo! Rydych bellach wedi cofrestru ac wedi mewngofnodi.',
|
||||
|
||||
// Login auto-initiation
|
||||
'auto_init_starting' => 'Attempting Login',
|
||||
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
|
||||
'auto_init_start_link' => 'Proceed with authentication',
|
||||
|
||||
// Password Reset
|
||||
'reset_password' => 'Ailosod cyfrinair',
|
||||
'reset_password_send_instructions' => 'Rhowch eich e-bost isod ac anfonir e-bost atoch gyda dolen ailosod cyfrinair.',
|
||||
'reset_password_send_button' => 'Anfon Dolen Ailosod',
|
||||
'reset_password_sent' => 'A password reset link will be sent to :email if that email address is found in the system.',
|
||||
'reset_password_success' => 'Your password has been successfully reset.',
|
||||
'email_reset_subject' => 'Reset your :appName password',
|
||||
'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.',
|
||||
'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.',
|
||||
|
||||
// Email Confirmation
|
||||
'email_confirm_subject' => 'Confirm your email on :appName',
|
||||
'email_confirm_greeting' => 'Thanks for joining :appName!',
|
||||
'email_confirm_text' => 'Please confirm your email address by clicking the button below:',
|
||||
'email_confirm_action' => 'Confirm Email',
|
||||
'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.',
|
||||
'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.',
|
||||
'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.',
|
||||
|
||||
'email_not_confirmed' => 'Email Address Not Confirmed',
|
||||
'email_not_confirmed_text' => 'Your email address has not yet been confirmed.',
|
||||
'email_not_confirmed_click_link' => 'Please click the link in the email that was sent shortly after you registered.',
|
||||
'email_not_confirmed_resend' => 'If you cannot find the email you can re-send the confirmation email by submitting the form below.',
|
||||
'email_not_confirmed_resend_button' => 'Resend Confirmation Email',
|
||||
|
||||
// User Invite
|
||||
'user_invite_email_subject' => 'You have been invited to join :appName!',
|
||||
'user_invite_email_greeting' => 'An account has been created for you on :appName.',
|
||||
'user_invite_email_text' => 'Click the button below to set an account password and gain access:',
|
||||
'user_invite_email_action' => 'Set Account Password',
|
||||
'user_invite_page_welcome' => 'Welcome to :appName!',
|
||||
'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.',
|
||||
'user_invite_page_confirm_button' => 'Confirm Password',
|
||||
'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!',
|
||||
|
||||
// Multi-factor Authentication
|
||||
'mfa_setup' => 'Setup Multi-Factor Authentication',
|
||||
'mfa_setup_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.',
|
||||
'mfa_setup_configured' => 'Already configured',
|
||||
'mfa_setup_reconfigure' => 'Reconfigure',
|
||||
'mfa_setup_remove_confirmation' => 'Are you sure you want to remove this multi-factor authentication method?',
|
||||
'mfa_setup_action' => 'Setup',
|
||||
'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.',
|
||||
'mfa_option_totp_title' => 'Mobile App',
|
||||
'mfa_option_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
|
||||
'mfa_option_backup_codes_title' => 'Backup Codes',
|
||||
'mfa_option_backup_codes_desc' => 'Securely store a set of one-time-use backup codes which you can enter to verify your identity.',
|
||||
'mfa_gen_confirm_and_enable' => 'Confirm and Enable',
|
||||
'mfa_gen_backup_codes_title' => 'Backup Codes Setup',
|
||||
'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.',
|
||||
'mfa_gen_backup_codes_download' => 'Download Codes',
|
||||
'mfa_gen_backup_codes_usage_warning' => 'Each code can only be used once',
|
||||
'mfa_gen_totp_title' => 'Mobile App Setup',
|
||||
'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
|
||||
'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.',
|
||||
'mfa_gen_totp_verify_setup' => 'Verify Setup',
|
||||
'mfa_gen_totp_verify_setup_desc' => 'Verify that all is working by entering a code, generated within your authentication app, in the input box below:',
|
||||
'mfa_gen_totp_provide_code_here' => 'Provide your app generated code here',
|
||||
'mfa_verify_access' => 'Verify Access',
|
||||
'mfa_verify_access_desc' => 'Your user account requires you to confirm your identity via an additional level of verification before you\'re granted access. Verify using one of your configured methods to continue.',
|
||||
'mfa_verify_no_methods' => 'No Methods Configured',
|
||||
'mfa_verify_no_methods_desc' => 'No multi-factor authentication methods could be found for your account. You\'ll need to set up at least one method before you gain access.',
|
||||
'mfa_verify_use_totp' => 'Verify using a mobile app',
|
||||
'mfa_verify_use_backup_codes' => 'Verify using a backup code',
|
||||
'mfa_verify_backup_code' => 'Backup Code',
|
||||
'mfa_verify_backup_code_desc' => 'Enter one of your remaining backup codes below:',
|
||||
'mfa_verify_backup_code_enter_here' => 'Enter backup code here',
|
||||
'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:',
|
||||
'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.',
|
||||
];
|
||||
@@ -1,104 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Common elements found throughout many areas of BookStack.
|
||||
*/
|
||||
return [
|
||||
|
||||
// Buttons
|
||||
'cancel' => 'Cancel',
|
||||
'confirm' => 'Confirm',
|
||||
'back' => 'Back',
|
||||
'save' => 'Save',
|
||||
'continue' => 'Continue',
|
||||
'select' => 'Select',
|
||||
'toggle_all' => 'Toggle All',
|
||||
'more' => 'More',
|
||||
|
||||
// Form Labels
|
||||
'name' => 'Name',
|
||||
'description' => 'Description',
|
||||
'role' => 'Role',
|
||||
'cover_image' => 'Cover image',
|
||||
'cover_image_description' => 'This image should be approx 440x250px.',
|
||||
|
||||
// Actions
|
||||
'actions' => 'Actions',
|
||||
'view' => 'View',
|
||||
'view_all' => 'View All',
|
||||
'create' => 'Create',
|
||||
'update' => 'Update',
|
||||
'edit' => 'Edit',
|
||||
'sort' => 'Sort',
|
||||
'move' => 'Move',
|
||||
'copy' => 'Copy',
|
||||
'reply' => 'Reply',
|
||||
'delete' => 'Delete',
|
||||
'delete_confirm' => 'Confirm Deletion',
|
||||
'search' => 'Search',
|
||||
'search_clear' => 'Clear Search',
|
||||
'reset' => 'Reset',
|
||||
'remove' => 'Remove',
|
||||
'add' => 'Add',
|
||||
'configure' => 'Configure',
|
||||
'fullscreen' => 'Fullscreen',
|
||||
'favourite' => 'Favourite',
|
||||
'unfavourite' => 'Unfavourite',
|
||||
'next' => 'Next',
|
||||
'previous' => 'Previous',
|
||||
'filter_active' => 'Active Filter:',
|
||||
'filter_clear' => 'Clear Filter',
|
||||
'download' => 'Download',
|
||||
'open_in_tab' => 'Open in Tab',
|
||||
|
||||
// Sort Options
|
||||
'sort_options' => 'Sort Options',
|
||||
'sort_direction_toggle' => 'Sort Direction Toggle',
|
||||
'sort_ascending' => 'Sort Ascending',
|
||||
'sort_descending' => 'Sort Descending',
|
||||
'sort_name' => 'Name',
|
||||
'sort_default' => 'Default',
|
||||
'sort_created_at' => 'Created Date',
|
||||
'sort_updated_at' => 'Updated Date',
|
||||
|
||||
// Misc
|
||||
'deleted_user' => 'Deleted User',
|
||||
'no_activity' => 'No activity to show',
|
||||
'no_items' => 'No items available',
|
||||
'back_to_top' => 'Back to top',
|
||||
'skip_to_main_content' => 'Skip to main content',
|
||||
'toggle_details' => 'Toggle Details',
|
||||
'toggle_thumbnails' => 'Toggle Thumbnails',
|
||||
'details' => 'Details',
|
||||
'grid_view' => 'Grid View',
|
||||
'list_view' => 'List View',
|
||||
'default' => 'Default',
|
||||
'breadcrumb' => 'Breadcrumb',
|
||||
'status' => 'Status',
|
||||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
'profile_menu' => 'Profile Menu',
|
||||
'view_profile' => 'View Profile',
|
||||
'edit_profile' => 'Edit Profile',
|
||||
'dark_mode' => 'Dark Mode',
|
||||
'light_mode' => 'Light Mode',
|
||||
|
||||
// Layout tabs
|
||||
'tab_info' => 'Info',
|
||||
'tab_info_label' => 'Tab: Show Secondary Information',
|
||||
'tab_content' => 'Content',
|
||||
'tab_content_label' => 'Tab: Show Primary Content',
|
||||
|
||||
// Email Content
|
||||
'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:',
|
||||
'email_rights' => 'All rights reserved',
|
||||
|
||||
// Footer Link Options
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privacy Policy',
|
||||
'terms_of_service' => 'Terms of Service',
|
||||
];
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Text used in custom JavaScript driven components.
|
||||
*/
|
||||
return [
|
||||
|
||||
// Image Manager
|
||||
'image_select' => 'Image Select',
|
||||
'image_all' => 'All',
|
||||
'image_all_title' => 'View all images',
|
||||
'image_book_title' => 'View images uploaded to this book',
|
||||
'image_page_title' => 'View images uploaded to this page',
|
||||
'image_search_hint' => 'Search by image name',
|
||||
'image_uploaded' => 'Uploaded :uploadedDate',
|
||||
'image_load_more' => 'Load More',
|
||||
'image_image_name' => 'Image Name',
|
||||
'image_delete_used' => 'This image is used in the pages below.',
|
||||
'image_delete_confirm_text' => 'Are you sure you want to delete this image?',
|
||||
'image_select_image' => 'Select Image',
|
||||
'image_dropzone' => 'Drop images or click here to upload',
|
||||
'images_deleted' => 'Images Deleted',
|
||||
'image_preview' => 'Image Preview',
|
||||
'image_upload_success' => 'Image uploaded successfully',
|
||||
'image_update_success' => 'Image details successfully updated',
|
||||
'image_delete_success' => 'Image successfully deleted',
|
||||
'image_upload_remove' => 'Remove',
|
||||
|
||||
// Code Editor
|
||||
'code_editor' => 'Edit Code',
|
||||
'code_language' => 'Code Language',
|
||||
'code_content' => 'Code Content',
|
||||
'code_session_history' => 'Session History',
|
||||
'code_save' => 'Save Code',
|
||||
];
|
||||
@@ -1,171 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Page Editor Lines
|
||||
* Contains text strings used within the user interface of the
|
||||
* WYSIWYG page editor. Some Markdown editor strings may still
|
||||
* exist in the 'entities' file instead since this was added later.
|
||||
*/
|
||||
return [
|
||||
// General editor terms
|
||||
'general' => 'General',
|
||||
'advanced' => 'Advanced',
|
||||
'none' => 'None',
|
||||
'cancel' => 'Cancel',
|
||||
'save' => 'Save',
|
||||
'close' => 'Close',
|
||||
'undo' => 'Undo',
|
||||
'redo' => 'Redo',
|
||||
'left' => 'Left',
|
||||
'center' => 'Center',
|
||||
'right' => 'Right',
|
||||
'top' => 'Top',
|
||||
'middle' => 'Middle',
|
||||
'bottom' => 'Bottom',
|
||||
'width' => 'Width',
|
||||
'height' => 'Height',
|
||||
'More' => 'More',
|
||||
'select' => 'Select...',
|
||||
|
||||
// Toolbar
|
||||
'formats' => 'Formats',
|
||||
'header_large' => 'Large Header',
|
||||
'header_medium' => 'Medium Header',
|
||||
'header_small' => 'Small Header',
|
||||
'header_tiny' => 'Tiny Header',
|
||||
'paragraph' => 'Paragraph',
|
||||
'blockquote' => 'Blockquote',
|
||||
'inline_code' => 'Inline code',
|
||||
'callouts' => 'Callouts',
|
||||
'callout_information' => 'Information',
|
||||
'callout_success' => 'Success',
|
||||
'callout_warning' => 'Warning',
|
||||
'callout_danger' => 'Danger',
|
||||
'bold' => 'Bold',
|
||||
'italic' => 'Italic',
|
||||
'underline' => 'Underline',
|
||||
'strikethrough' => 'Strikethrough',
|
||||
'superscript' => 'Superscript',
|
||||
'subscript' => 'Subscript',
|
||||
'text_color' => 'Text color',
|
||||
'custom_color' => 'Custom color',
|
||||
'remove_color' => 'Remove color',
|
||||
'background_color' => 'Background color',
|
||||
'align_left' => 'Align left',
|
||||
'align_center' => 'Align center',
|
||||
'align_right' => 'Align right',
|
||||
'align_justify' => 'Justify',
|
||||
'list_bullet' => 'Bullet list',
|
||||
'list_numbered' => 'Numbered list',
|
||||
'list_task' => 'Task list',
|
||||
'indent_increase' => 'Increase indent',
|
||||
'indent_decrease' => 'Decrease indent',
|
||||
'table' => 'Table',
|
||||
'insert_image' => 'Insert image',
|
||||
'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',
|
||||
|
||||
// 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_cell' => 'Cell',
|
||||
'table_row' => 'Row',
|
||||
'table_column' => 'Column',
|
||||
'cell_properties' => 'Cell properties',
|
||||
'cell_properties_title' => 'Cell Properties',
|
||||
'cell_type' => 'Cell type',
|
||||
'cell_type_cell' => 'Cell',
|
||||
'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',
|
||||
|
||||
// Images, links, details/summary & embed
|
||||
'source' => 'Source',
|
||||
'alt_desc' => 'Alternative description',
|
||||
'embed' => 'Embed',
|
||||
'paste_embed' => 'Paste your embed code below:',
|
||||
'url' => 'URL',
|
||||
'text_to_display' => 'Text to display',
|
||||
'title' => 'Title',
|
||||
'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',
|
||||
|
||||
// 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',
|
||||
'shortcuts' => 'Shortcuts',
|
||||
'shortcut' => 'Shortcut',
|
||||
'shortcuts_intro' => 'The following shortcuts are available in the editor:',
|
||||
'windows_linux' => '(Windows/Linux)',
|
||||
'mac' => '(Mac)',
|
||||
'description' => 'Description',
|
||||
];
|
||||
@@ -1,370 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Text used for 'Entities' (Document Structure Elements) such as
|
||||
* Books, Shelves, Chapters & Pages
|
||||
*/
|
||||
return [
|
||||
|
||||
// Shared
|
||||
'recently_created' => 'Recently Created',
|
||||
'recently_created_pages' => 'Recently Created Pages',
|
||||
'recently_updated_pages' => 'Recently Updated Pages',
|
||||
'recently_created_chapters' => 'Recently Created Chapters',
|
||||
'recently_created_books' => 'Recently Created Books',
|
||||
'recently_created_shelves' => 'Recently Created Shelves',
|
||||
'recently_update' => 'Recently Updated',
|
||||
'recently_viewed' => 'Recently Viewed',
|
||||
'recent_activity' => 'Recent Activity',
|
||||
'create_now' => 'Create one now',
|
||||
'revisions' => 'Revisions',
|
||||
'meta_revision' => 'Revision #:revisionCount',
|
||||
'meta_created' => 'Created :timeLength',
|
||||
'meta_created_name' => 'Created :timeLength by :user',
|
||||
'meta_updated' => 'Updated :timeLength',
|
||||
'meta_updated_name' => 'Updated :timeLength by :user',
|
||||
'meta_owned_name' => 'Owned by :user',
|
||||
'entity_select' => 'Entity Select',
|
||||
'images' => 'Images',
|
||||
'my_recent_drafts' => 'My Recent Drafts',
|
||||
'my_recently_viewed' => 'My Recently Viewed',
|
||||
'my_most_viewed_favourites' => 'My Most Viewed Favourites',
|
||||
'my_favourites' => 'My Favourites',
|
||||
'no_pages_viewed' => 'You have not viewed any pages',
|
||||
'no_pages_recently_created' => 'No pages have been recently created',
|
||||
'no_pages_recently_updated' => 'No pages have been recently updated',
|
||||
'export' => 'Export',
|
||||
'export_html' => 'Contained Web File',
|
||||
'export_pdf' => 'PDF File',
|
||||
'export_text' => 'Plain Text File',
|
||||
'export_md' => 'Markdown File',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Permissions',
|
||||
'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.',
|
||||
'permissions_enable' => 'Enable Custom Permissions',
|
||||
'permissions_save' => 'Save Permissions',
|
||||
'permissions_owner' => 'Owner',
|
||||
|
||||
// Search
|
||||
'search_results' => 'Search Results',
|
||||
'search_total_results_found' => ':count result found|:count total results found',
|
||||
'search_clear' => 'Clear Search',
|
||||
'search_no_pages' => 'No pages matched this search',
|
||||
'search_for_term' => 'Search for :term',
|
||||
'search_more' => 'More Results',
|
||||
'search_advanced' => 'Advanced Search',
|
||||
'search_terms' => 'Search Terms',
|
||||
'search_content_type' => 'Content Type',
|
||||
'search_exact_matches' => 'Exact Matches',
|
||||
'search_tags' => 'Tag Searches',
|
||||
'search_options' => 'Options',
|
||||
'search_viewed_by_me' => 'Viewed by me',
|
||||
'search_not_viewed_by_me' => 'Not viewed by me',
|
||||
'search_permissions_set' => 'Permissions set',
|
||||
'search_created_by_me' => 'Created by me',
|
||||
'search_updated_by_me' => 'Updated by me',
|
||||
'search_owned_by_me' => 'Owned by me',
|
||||
'search_date_options' => 'Date Options',
|
||||
'search_updated_before' => 'Updated before',
|
||||
'search_updated_after' => 'Updated after',
|
||||
'search_created_before' => 'Created before',
|
||||
'search_created_after' => 'Created after',
|
||||
'search_set_date' => 'Set Date',
|
||||
'search_update' => 'Update Search',
|
||||
|
||||
// Shelves
|
||||
'shelf' => 'Shelf',
|
||||
'shelves' => 'Shelves',
|
||||
'x_shelves' => ':count Shelf|:count Shelves',
|
||||
'shelves_long' => 'Bookshelves',
|
||||
'shelves_empty' => 'No shelves have been created',
|
||||
'shelves_create' => 'Create New Shelf',
|
||||
'shelves_popular' => 'Popular Shelves',
|
||||
'shelves_new' => 'New Shelves',
|
||||
'shelves_new_action' => 'New Shelf',
|
||||
'shelves_popular_empty' => 'The most popular shelves will appear here.',
|
||||
'shelves_new_empty' => 'The most recently created shelves will appear here.',
|
||||
'shelves_save' => 'Save Shelf',
|
||||
'shelves_books' => 'Books on this shelf',
|
||||
'shelves_add_books' => 'Add books to this shelf',
|
||||
'shelves_drag_books' => 'Drag books here to add them to this shelf',
|
||||
'shelves_empty_contents' => 'This shelf has no books assigned to it',
|
||||
'shelves_edit_and_assign' => 'Edit shelf to assign books',
|
||||
'shelves_edit_named' => 'Edit Bookshelf :name',
|
||||
'shelves_edit' => 'Edit Bookshelf',
|
||||
'shelves_delete' => 'Delete Bookshelf',
|
||||
'shelves_delete_named' => 'Delete Bookshelf :name',
|
||||
'shelves_delete_explain' => "This will delete the bookshelf with the name ':name'. Contained books will not be deleted.",
|
||||
'shelves_delete_confirmation' => 'Are you sure you want to delete this bookshelf?',
|
||||
'shelves_permissions' => 'Bookshelf Permissions',
|
||||
'shelves_permissions_updated' => 'Bookshelf Permissions Updated',
|
||||
'shelves_permissions_active' => 'Bookshelf Permissions Active',
|
||||
'shelves_permissions_cascade_warning' => 'Permissions on bookshelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.',
|
||||
'shelves_copy_permissions_to_books' => 'Copy Permissions to Books',
|
||||
'shelves_copy_permissions' => 'Copy Permissions',
|
||||
'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this bookshelf to all books contained within. Before activating, ensure any changes to the permissions of this bookshelf have been saved.',
|
||||
'shelves_copy_permission_success' => 'Bookshelf permissions copied to :count books',
|
||||
|
||||
// Books
|
||||
'book' => 'Book',
|
||||
'books' => 'Books',
|
||||
'x_books' => ':count Book|:count Books',
|
||||
'books_empty' => 'No books have been created',
|
||||
'books_popular' => 'Popular Books',
|
||||
'books_recent' => 'Recent Books',
|
||||
'books_new' => 'New Books',
|
||||
'books_new_action' => 'New Book',
|
||||
'books_popular_empty' => 'The most popular books will appear here.',
|
||||
'books_new_empty' => 'The most recently created books will appear here.',
|
||||
'books_create' => 'Create New Book',
|
||||
'books_delete' => 'Delete Book',
|
||||
'books_delete_named' => 'Delete Book :bookName',
|
||||
'books_delete_explain' => 'This will delete the book with the name \':bookName\'. All pages and chapters will be removed.',
|
||||
'books_delete_confirmation' => 'Are you sure you want to delete this book?',
|
||||
'books_edit' => 'Edit Book',
|
||||
'books_edit_named' => 'Edit Book :bookName',
|
||||
'books_form_book_name' => 'Book Name',
|
||||
'books_save' => 'Save Book',
|
||||
'books_permissions' => 'Book Permissions',
|
||||
'books_permissions_updated' => 'Book Permissions Updated',
|
||||
'books_empty_contents' => 'No pages or chapters have been created for this book.',
|
||||
'books_empty_create_page' => 'Create a new page',
|
||||
'books_empty_sort_current_book' => 'Sort the current book',
|
||||
'books_empty_add_chapter' => 'Add a chapter',
|
||||
'books_permissions_active' => 'Book Permissions Active',
|
||||
'books_search_this' => 'Search this book',
|
||||
'books_navigation' => 'Book Navigation',
|
||||
'books_sort' => 'Sort Book Contents',
|
||||
'books_sort_named' => 'Sort Book :bookName',
|
||||
'books_sort_name' => 'Sort by Name',
|
||||
'books_sort_created' => 'Sort by Created Date',
|
||||
'books_sort_updated' => 'Sort by Updated Date',
|
||||
'books_sort_chapters_first' => 'Chapters First',
|
||||
'books_sort_chapters_last' => 'Chapters Last',
|
||||
'books_sort_show_other' => 'Show Other Books',
|
||||
'books_sort_save' => 'Save New Order',
|
||||
'books_copy' => 'Copy Book',
|
||||
'books_copy_success' => 'Book successfully copied',
|
||||
|
||||
// Chapters
|
||||
'chapter' => 'Chapter',
|
||||
'chapters' => 'Chapters',
|
||||
'x_chapters' => ':count Chapter|:count Chapters',
|
||||
'chapters_popular' => 'Popular Chapters',
|
||||
'chapters_new' => 'New Chapter',
|
||||
'chapters_create' => 'Create New Chapter',
|
||||
'chapters_delete' => 'Delete Chapter',
|
||||
'chapters_delete_named' => 'Delete Chapter :chapterName',
|
||||
'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages that exist within this chapter will also be deleted.',
|
||||
'chapters_delete_confirm' => 'Are you sure you want to delete this chapter?',
|
||||
'chapters_edit' => 'Edit Chapter',
|
||||
'chapters_edit_named' => 'Edit Chapter :chapterName',
|
||||
'chapters_save' => 'Save Chapter',
|
||||
'chapters_move' => 'Move Chapter',
|
||||
'chapters_move_named' => 'Move Chapter :chapterName',
|
||||
'chapter_move_success' => 'Chapter moved to :bookName',
|
||||
'chapters_copy' => 'Copy Chapter',
|
||||
'chapters_copy_success' => 'Chapter successfully copied',
|
||||
'chapters_permissions' => 'Chapter Permissions',
|
||||
'chapters_empty' => 'No pages are currently in this chapter.',
|
||||
'chapters_permissions_active' => 'Chapter Permissions Active',
|
||||
'chapters_permissions_success' => 'Chapter Permissions Updated',
|
||||
'chapters_search_this' => 'Search this chapter',
|
||||
|
||||
// Pages
|
||||
'page' => 'Page',
|
||||
'pages' => 'Pages',
|
||||
'x_pages' => ':count Page|:count Pages',
|
||||
'pages_popular' => 'Popular Pages',
|
||||
'pages_new' => 'New Page',
|
||||
'pages_attachments' => 'Attachments',
|
||||
'pages_navigation' => 'Page Navigation',
|
||||
'pages_delete' => 'Delete Page',
|
||||
'pages_delete_named' => 'Delete Page :pageName',
|
||||
'pages_delete_draft_named' => 'Delete Draft Page :pageName',
|
||||
'pages_delete_draft' => 'Delete Draft Page',
|
||||
'pages_delete_success' => 'Page deleted',
|
||||
'pages_delete_draft_success' => 'Draft page deleted',
|
||||
'pages_delete_confirm' => 'Are you sure you want to delete this page?',
|
||||
'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?',
|
||||
'pages_editing_named' => 'Editing Page :pageName',
|
||||
'pages_edit_draft_options' => 'Draft Options',
|
||||
'pages_edit_save_draft' => 'Save Draft',
|
||||
'pages_edit_draft' => 'Edit Page Draft',
|
||||
'pages_editing_draft' => 'Editing Draft',
|
||||
'pages_editing_page' => 'Editing Page',
|
||||
'pages_edit_draft_save_at' => 'Draft saved at ',
|
||||
'pages_edit_delete_draft' => 'Delete Draft',
|
||||
'pages_edit_discard_draft' => '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_set_changelog' => 'Set Changelog',
|
||||
'pages_edit_enter_changelog_desc' => 'Enter a brief description of the changes you\'ve made',
|
||||
'pages_edit_enter_changelog' => '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_save' => 'Save Page',
|
||||
'pages_title' => 'Page Title',
|
||||
'pages_name' => 'Page Name',
|
||||
'pages_md_editor' => 'Editor',
|
||||
'pages_md_preview' => 'Preview',
|
||||
'pages_md_insert_image' => 'Insert Image',
|
||||
'pages_md_insert_link' => 'Insert Entity Link',
|
||||
'pages_md_insert_drawing' => 'Insert Drawing',
|
||||
'pages_not_in_chapter' => 'Page is not in a chapter',
|
||||
'pages_move' => 'Move Page',
|
||||
'pages_move_success' => 'Page moved to ":parentName"',
|
||||
'pages_copy' => 'Copy Page',
|
||||
'pages_copy_desination' => 'Copy Destination',
|
||||
'pages_copy_success' => 'Page successfully copied',
|
||||
'pages_permissions' => 'Page Permissions',
|
||||
'pages_permissions_success' => 'Page permissions updated',
|
||||
'pages_revision' => 'Revision',
|
||||
'pages_revisions' => 'Page Revisions',
|
||||
'pages_revisions_named' => 'Page Revisions for :pageName',
|
||||
'pages_revision_named' => 'Page Revision for :pageName',
|
||||
'pages_revision_restored_from' => 'Restored from #:id; :summary',
|
||||
'pages_revisions_created_by' => 'Created By',
|
||||
'pages_revisions_date' => 'Revision Date',
|
||||
'pages_revisions_number' => '#',
|
||||
'pages_revisions_numbered' => 'Revision #:id',
|
||||
'pages_revisions_numbered_changes' => 'Revision #:id Changes',
|
||||
'pages_revisions_editor' => 'Editor Type',
|
||||
'pages_revisions_changelog' => 'Changelog',
|
||||
'pages_revisions_changes' => 'Changes',
|
||||
'pages_revisions_current' => 'Current Version',
|
||||
'pages_revisions_preview' => 'Preview',
|
||||
'pages_revisions_restore' => 'Restore',
|
||||
'pages_revisions_none' => 'This page has no revisions',
|
||||
'pages_copy_link' => 'Copy Link',
|
||||
'pages_edit_content_link' => 'Edit Content',
|
||||
'pages_permissions_active' => 'Page Permissions Active',
|
||||
'pages_initial_revision' => 'Initial publish',
|
||||
'pages_initial_name' => 'New Page',
|
||||
'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.',
|
||||
'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.',
|
||||
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
|
||||
'pages_draft_edit_active' => [
|
||||
'start_a' => ':count users have started editing this page',
|
||||
'start_b' => ':userName has started editing this page',
|
||||
'time_a' => 'since the page was last updated',
|
||||
'time_b' => 'in the last :minCount minutes',
|
||||
'message' => ':start :time. Take care not to overwrite each other\'s updates!',
|
||||
],
|
||||
'pages_draft_discarded' => 'Draft discarded, The editor has been updated with the current page content',
|
||||
'pages_specific' => 'Specific Page',
|
||||
'pages_is_template' => 'Page Template',
|
||||
|
||||
// Editor Sidebar
|
||||
'page_tags' => 'Page Tags',
|
||||
'chapter_tags' => 'Chapter Tags',
|
||||
'book_tags' => 'Book Tags',
|
||||
'shelf_tags' => 'Shelf Tags',
|
||||
'tag' => 'Tag',
|
||||
'tags' => 'Tags',
|
||||
'tag_name' => 'Tag Name',
|
||||
'tag_value' => 'Tag Value (Optional)',
|
||||
'tags_explain' => "Add some tags to better categorise your content. \n You can assign a value to a tag for more in-depth organisation.",
|
||||
'tags_add' => 'Add another tag',
|
||||
'tags_remove' => 'Remove this tag',
|
||||
'tags_usages' => 'Total tag usages',
|
||||
'tags_assigned_pages' => 'Assigned to Pages',
|
||||
'tags_assigned_chapters' => 'Assigned to Chapters',
|
||||
'tags_assigned_books' => 'Assigned to Books',
|
||||
'tags_assigned_shelves' => 'Assigned to Shelves',
|
||||
'tags_x_unique_values' => ':count unique values',
|
||||
'tags_all_values' => 'All values',
|
||||
'tags_view_tags' => 'View Tags',
|
||||
'tags_view_existing_tags' => 'View existing tags',
|
||||
'tags_list_empty_hint' => 'Tags can be assigned via the page editor sidebar or while editing the details of a book, chapter or shelf.',
|
||||
'attachments' => 'Attachments',
|
||||
'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.',
|
||||
'attachments_explain_instant_save' => 'Changes here are saved instantly.',
|
||||
'attachments_items' => 'Attached Items',
|
||||
'attachments_upload' => 'Upload File',
|
||||
'attachments_link' => 'Attach Link',
|
||||
'attachments_set_link' => 'Set Link',
|
||||
'attachments_delete' => 'Are you sure you want to delete this attachment?',
|
||||
'attachments_dropzone' => 'Drop files or click here to attach a file',
|
||||
'attachments_no_files' => 'No files have been uploaded',
|
||||
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
|
||||
'attachments_link_name' => 'Link Name',
|
||||
'attachment_link' => 'Attachment link',
|
||||
'attachments_link_url' => 'Link to file',
|
||||
'attachments_link_url_hint' => 'Url of site or file',
|
||||
'attach' => 'Attach',
|
||||
'attachments_insert_link' => 'Add Attachment Link to Page',
|
||||
'attachments_edit_file' => 'Edit File',
|
||||
'attachments_edit_file_name' => 'File Name',
|
||||
'attachments_edit_drop_upload' => 'Drop files or click here to upload and overwrite',
|
||||
'attachments_order_updated' => 'Attachment order updated',
|
||||
'attachments_updated_success' => 'Attachment details updated',
|
||||
'attachments_deleted' => 'Attachment deleted',
|
||||
'attachments_file_uploaded' => 'File successfully uploaded',
|
||||
'attachments_file_updated' => 'File successfully updated',
|
||||
'attachments_link_attached' => 'Link successfully attached to page',
|
||||
'templates' => 'Templates',
|
||||
'templates_set_as_template' => 'Page is a template',
|
||||
'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.',
|
||||
'templates_replace_content' => 'Replace page content',
|
||||
'templates_append_content' => 'Append to page content',
|
||||
'templates_prepend_content' => 'Prepend to page content',
|
||||
|
||||
// Profile View
|
||||
'profile_user_for_x' => 'User for :time',
|
||||
'profile_created_content' => 'Created Content',
|
||||
'profile_not_created_pages' => ':userName has not created any pages',
|
||||
'profile_not_created_chapters' => ':userName has not created any chapters',
|
||||
'profile_not_created_books' => ':userName has not created any books',
|
||||
'profile_not_created_shelves' => ':userName has not created any shelves',
|
||||
|
||||
// Comments
|
||||
'comment' => 'Comment',
|
||||
'comments' => 'Comments',
|
||||
'comment_add' => 'Add Comment',
|
||||
'comment_placeholder' => 'Leave a comment here',
|
||||
'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments',
|
||||
'comment_save' => 'Save Comment',
|
||||
'comment_saving' => 'Saving comment...',
|
||||
'comment_deleting' => 'Deleting comment...',
|
||||
'comment_new' => 'New Comment',
|
||||
'comment_created' => 'commented :createDiff',
|
||||
'comment_updated' => 'Updated :updateDiff by :username',
|
||||
'comment_deleted_success' => 'Comment deleted',
|
||||
'comment_created_success' => 'Comment added',
|
||||
'comment_updated_success' => 'Comment updated',
|
||||
'comment_delete_confirm' => 'Are you sure you want to delete this comment?',
|
||||
'comment_in_reply_to' => 'In reply to :commentId',
|
||||
|
||||
// Revision
|
||||
'revision_delete_confirm' => 'Are you sure you want to delete this revision?',
|
||||
'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.',
|
||||
'revision_delete_success' => 'Revision deleted',
|
||||
'revision_cannot_delete_latest' => 'Cannot delete the latest revision.',
|
||||
|
||||
// Copy view
|
||||
'copy_consider' => 'Please consider the below when copying content.',
|
||||
'copy_consider_permissions' => 'Custom permission settings will not be copied.',
|
||||
'copy_consider_owner' => 'You will become the owner of all copied content.',
|
||||
'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?',
|
||||
];
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Text shown in error messaging.
|
||||
*/
|
||||
return [
|
||||
|
||||
// Permissions
|
||||
'permission' => 'Nid oes gennych ganiatâd i gael mynediad i\'r dudalen y gofynnwyd amdani.',
|
||||
'permissionJson' => 'Nid oes gennych ganiatâd i gyflawni\'r weithred y gofynnwyd amdani.',
|
||||
|
||||
// Auth
|
||||
'error_user_exists_different_creds' => 'Mae defnyddiwr gyda\'r e-bost :email eisoes yn bodoli ond gyda nodweddion gwahanol.',
|
||||
'email_already_confirmed' => 'E-bost eisoes wedi\'i gadarnhau, Ceisiwch fewngofnodi.',
|
||||
'email_confirmation_invalid' => 'Nid yw\'r tocyn cadarnhau hwn yn ddilys neu mae eisoes wedi\'i ddefnyddio. Ceisiwch gofrestru eto.',
|
||||
'email_confirmation_expired' => 'Mae\'r tocyn cadarnhad wedi dod i ben, Mae e-bost cadarnhau newydd wedi\'i anfon.',
|
||||
'email_confirmation_awaiting' => 'Mae angen cadarnhau cyfeiriad e-bost y cyfrif a ddefnyddir',
|
||||
'ldap_fail_anonymous' => 'Methodd mynediad LDAP gan ddefnyddio rhwymiad dienw',
|
||||
'ldap_fail_authed' => 'Methodd mynediad LDAP gan ddefnyddio\'r manylion dn a chyfrinair a roddwyd',
|
||||
'ldap_extension_not_installed' => 'Estyniad PHP LDAP heb ei osod',
|
||||
'ldap_cannot_connect' => 'Methu cysylltu i weinydd ldap, cysylltiad cychwynnol wedi methu',
|
||||
'saml_already_logged_in' => 'Wedi mewngofnodi yn barod',
|
||||
'saml_user_not_registered' => 'Nid yw\'r defnyddiwr :name wedi\'i gofrestru ac mae cofrestriad awtomatig wedi\'i analluogi',
|
||||
'saml_no_email_address' => 'Methu dod o hyd i gyfeiriad e-bost, ar gyfer y defnyddiwr hwn, yn y data a ddarparwyd gan y system ddilysu allanol',
|
||||
'saml_invalid_response_id' => 'Nid yw\'r cais o\'r system ddilysu allanol yn cael ei gydnabod gan broses a ddechreuwyd gan y cais hwn. Gallai llywio yn ôl ar ôl mewngofnodi achosi\'r broblem hon.',
|
||||
'saml_fail_authed' => 'Wedi methu mewngofnodi gan ddefnyddio :system, ni roddodd y system awdurdodiad llwyddiannus',
|
||||
'oidc_already_logged_in' => 'Wedi mewngofnodi yn barod',
|
||||
'oidc_user_not_registered' => 'Nid yw\'r defnyddiwr :name wedi\'i gofrestru ac mae cofrestriad awtomatig wedi\'i analluogi',
|
||||
'oidc_no_email_address' => 'Methu dod o hyd i gyfeiriad e-bost, ar gyfer y defnyddiwr hwn, yn y data a ddarparwyd gan y system ddilysu allanol',
|
||||
'oidc_fail_authed' => 'Wedi methu mewngofnodi gan ddefnyddio :system, ni roddodd y system awdurdodiad llwyddiannus',
|
||||
'social_no_action_defined' => 'Dim gweithred wedi\'i diffinio',
|
||||
'social_login_bad_response' => "Gwall a dderbyniwyd yn ystod mewngofnodi :socialAccount:\n:error",
|
||||
'social_account_in_use' => 'Mae\'r cyfrif :socialAccount hwn eisoes yn cael ei ddefnyddio, Ceisiwch fewngofnodi trwy\'r opsiwn :socialAccount.',
|
||||
'social_account_email_in_use' => 'Mae\'r e-bost :email eisoes yn cael ei ddefnyddio. Os oes gennych gyfrif yn barod gallwch gysylltu eich cyfrif :socialAccount o osodiadau eich proffil.',
|
||||
'social_account_existing' => 'Mae\'r :socialAccount hwn eisoes ynghlwm wrth eich proffil.',
|
||||
'social_account_already_used_existing' => 'Mae\'r cyfrif :socialAccount hwn eisoes yn cael ei ddefnyddio gan ddefnyddiwr arall.',
|
||||
'social_account_not_used' => 'Nid yw\'r cyfrif :socialAccount hwn yn gysylltiedig ag unrhyw ddefnyddwyr. Atodwch ef yn eich gosodiadau proffil. ',
|
||||
'social_account_register_instructions' => 'Os nad oes gennych gyfrif eto, gallwch gofrestru cyfrif gan ddefnyddio\'r opsiwn :socialAccount.',
|
||||
'social_driver_not_found' => 'Gyrrwr cymdeithasol heb ei ganfod',
|
||||
'social_driver_not_configured' => 'Nid yw eich gosodiadau cymdeithasol :socialAccount wedi\'u ffurfweddu\'n gywir.',
|
||||
'invite_token_expired' => 'Mae\'r ddolen wahoddiad hon wedi dod i ben. Yn lle hynny, gallwch chi geisio ailosod cyfrinair eich cyfrif.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'Nid oedd modd uwchlwytho llwybr ffeil :filePath. Sicrhewch ei fod yn ysgrifenadwy i\'r gweinydd.',
|
||||
'cannot_get_image_from_url' => 'Methu cael delwedd o :url',
|
||||
'cannot_create_thumbs' => 'Ni all y gweinydd greu mân-luniau. Gwiriwch fod gennych yr estyniad GD PHP wedi\'i osod.',
|
||||
'server_upload_limit' => 'Nid yw\'r gweinydd yn caniatáu uwchlwythiadau o\'r maint hwn. Rhowch gynnig ar faint ffeil llai.',
|
||||
'uploaded' => 'Nid yw\'r gweinydd yn caniatáu uwchlwythiadau o\'r maint hwn. Rhowch gynnig ar faint ffeil llai.',
|
||||
'image_upload_error' => 'Bu gwall wrth uwchlwytho\'r ddelwedd',
|
||||
'image_upload_type_error' => 'Mae\'r math o ddelwedd sy\'n cael ei huwchlwytho yn annilys',
|
||||
'file_upload_timeout' => 'Mae\'r amser uwchlwytho ffeil wedi dod i ben.',
|
||||
|
||||
// Attachments
|
||||
'attachment_not_found' => 'Ni chanfuwyd yr atodiad',
|
||||
|
||||
// Pages
|
||||
'page_draft_autosave_fail' => 'Wedi methu cadw\'r drafft. Sicrhewch fod gennych gysylltiad rhyngrwyd cyn cadw\'r dudalen hon',
|
||||
'page_custom_home_deletion' => 'Methu dileu tudalen tra ei bod wedi\'i gosod fel hafan',
|
||||
|
||||
// Entities
|
||||
'entity_not_found' => 'Endid heb ei ganfod',
|
||||
'bookshelf_not_found' => 'Heb ddod o hyd i\'r silff lyfrau',
|
||||
'book_not_found' => 'Ni chanfuwyd y llyfr',
|
||||
'page_not_found' => 'Heb ganfod y dudalen',
|
||||
'chapter_not_found' => 'Pennod heb ei chanfod',
|
||||
'selected_book_not_found' => 'Ni ddaethpwyd o hyd i\'r llyfr a ddewiswyd',
|
||||
'selected_book_chapter_not_found' => 'Ni ddaethpwyd o hyd i\'r Llyfr neu\'r Bennod a ddewiswyd',
|
||||
'guests_cannot_save_drafts' => 'Ni all gwesteion arbed drafftiau',
|
||||
|
||||
// Users
|
||||
'users_cannot_delete_only_admin' => 'Ni allwch ddileu\'r unig weinyddwr',
|
||||
'users_cannot_delete_guest' => 'Ni allwch ddileu\'r defnyddiwr gwadd',
|
||||
|
||||
// Roles
|
||||
'role_cannot_be_edited' => 'Nid oes modd golygu\'r rôl hon',
|
||||
'role_system_cannot_be_deleted' => 'Rôl system yw\'r rôl hon ac ni ellir ei dileu',
|
||||
'role_registration_default_cannot_delete' => 'Ni ellir dileu\'r rôl hon tra ei bod wedi\'i gosod fel y rôl gofrestru ddiofyn',
|
||||
'role_cannot_remove_only_admin' => 'Y defnyddiwr hwn yw\'r unig ddefnyddiwr sydd wedi\'i neilltuo i rôl y gweinyddwr. Neilltuo rôl y gweinyddwr i ddefnyddiwr arall cyn ceisio ei dynnu yma.',
|
||||
|
||||
// Comments
|
||||
'comment_list' => 'Digwyddodd gwall wrth nôl y sylwadau.',
|
||||
'cannot_add_comment_to_draft' => 'Ni allwch ychwanegu sylwadau at ddrafft.',
|
||||
'comment_add' => 'Digwyddodd gwall wrth ychwanegu / diweddaru\'r sylw.',
|
||||
'comment_delete' => 'Digwyddodd gwall wrth dileu\'r sylwad.',
|
||||
'empty_comment' => 'Methu ychwanegu sylw gwag.',
|
||||
|
||||
// Error pages
|
||||
'404_page_not_found' => 'Heb ganfod y dudalen',
|
||||
'sorry_page_not_found' => 'Mae\'n ddrwg gennym, nid oedd modd dod o hyd i\'r dudalen roeddech yn chwilio amdani.',
|
||||
'sorry_page_not_found_permission_warning' => 'Os oeddech yn disgwyl i\'r dudalen hon fodoli, efallai na fyddai gennych ganiatâd i\'w gweld.',
|
||||
'image_not_found' => 'Heb ganfod y delwedd',
|
||||
'image_not_found_subtitle' => 'Mae\'n ddrwg gennym, ni fu modd dod o hyd i\'r ffeil delwedd roeddech yn chwilio amdani.',
|
||||
'image_not_found_details' => 'Os oeddech chi\'n disgwyl i\'r ddelwedd hon fodoli efallai ei bod wedi\'i dileu.',
|
||||
'return_home' => 'Dychwelyd i gartref',
|
||||
'error_occurred' => 'Digwyddodd Gwall',
|
||||
'app_down' => 'Mae :appName i lawr ar hyn o bryd',
|
||||
'back_soon' => 'Bydd yn ôl i fyny yn fuan.',
|
||||
|
||||
// API errors
|
||||
'api_no_authorization_found' => 'Ni chanfuwyd tocyn awdurdodi ar y cais',
|
||||
'api_bad_authorization_format' => 'Canfuwyd tocyn awdurdodi ar y cais ond roedd yn ymddangos bod y fformat yn anghywir',
|
||||
'api_user_token_not_found' => 'Ni chanfuwyd tocyn API cyfatebol ar gyfer y tocyn awdurdodi a ddarparwyd',
|
||||
'api_incorrect_token_secret' => 'Mae\'r gyfrinach a ddarparwyd ar gyfer y tocyn API defnyddiedig a roddwyd yn anghywir',
|
||||
'api_user_no_api_permission' => 'Nid oes gan berchennog y tocyn API a ddefnyddiwyd ganiatâd i wneud galwadau API',
|
||||
'api_user_token_expired' => 'Mae\'r tocyn awdurdodi a ddefnyddiwyd wedi dod i ben',
|
||||
|
||||
// Settings & Maintenance
|
||||
'maintenance_test_email_failure' => 'Gwall a daflwyd wrth anfon e-bost prawf:',
|
||||
|
||||
];
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Pagination Language Lines
|
||||
* The following language lines are used by the paginator library to build
|
||||
* the simple pagination links.
|
||||
*/
|
||||
return [
|
||||
|
||||
'previous' => '« Previous',
|
||||
'next' => 'Next »',
|
||||
|
||||
];
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Password Reminder Language Lines
|
||||
* The following language lines are the default lines which match reasons
|
||||
* that are given by the password broker for a password update attempt has failed.
|
||||
*/
|
||||
return [
|
||||
|
||||
'password' => 'Passwords must be at least eight characters and match the confirmation.',
|
||||
'user' => "We can't find a user with that e-mail address.",
|
||||
'token' => 'The password reset token is invalid for this email address.',
|
||||
'sent' => 'We have e-mailed your password reset link!',
|
||||
'reset' => 'Your password has been reset!',
|
||||
|
||||
];
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user