From 3599a962a38692e2704804827f461997aafeba6e Mon Sep 17 00:00:00 2001 From: Lennert Daniels Date: Fri, 2 Dec 2022 13:10:57 +0100 Subject: [PATCH 0001/1295] search-box-cancel placement --- resources/sass/_forms.scss | 2 +- resources/views/pages/parts/template-manager.blade.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index ef14f62210f..6f1a81d12ea 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -454,7 +454,7 @@ div[editor-type="markdown"] .title-input.page-title input[type="text"] { &.flexible input { width: 100%; } - .search-box-cancel { + button.search-box-cancel { left: auto; right: 0; } diff --git a/resources/views/pages/parts/template-manager.blade.php b/resources/views/pages/parts/template-manager.blade.php index c209626cdbf..ee4467552e4 100644 --- a/resources/views/pages/parts/template-manager.blade.php +++ b/resources/views/pages/parts/template-manager.blade.php @@ -14,7 +14,7 @@
From 1dbc3588cf11c12fde3da0ca4cb951c55ce810d9 Mon Sep 17 00:00:00 2001 From: Lennert Daniels Date: Fri, 2 Dec 2022 18:41:59 +0100 Subject: [PATCH 0002/1295] Add default_template as Book setting --- app/Entities/Models/Book.php | 10 +++++- app/Http/Controllers/BookController.php | 16 +++++++++- ...2_104541_add_default_template_to_books.php | 32 +++++++++++++++++++ resources/lang/en/entities.php | 2 ++ resources/views/books/create.blade.php | 5 ++- resources/views/books/edit.blade.php | 6 +++- resources/views/books/parts/form.blade.php | 9 ++++++ .../views/entities/template-manager.blade.php | 10 ++++++ 8 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 database/migrations/2022_12_02_104541_add_default_template_to_books.php create mode 100644 resources/views/entities/template-manager.blade.php diff --git a/app/Entities/Models/Book.php b/app/Entities/Models/Book.php index fc4556857c7..b84a351f841 100644 --- a/app/Entities/Models/Book.php +++ b/app/Entities/Models/Book.php @@ -27,7 +27,7 @@ class Book extends Entity implements HasCoverImage public $searchFactor = 1.2; - protected $fillable = ['name', 'description']; + protected $fillable = ['name', 'description', 'default_template']; protected $hidden = ['pivot', 'image_id', 'deleted_at']; /** @@ -78,6 +78,14 @@ public function coverImageTypeKey(): string return 'cover_book'; } + /** + * Get the Page that is used as default template for newly created pages within this Book. + */ + public function defaultTemplate(): BelongsTo + { + return $this->belongsTo(Page::class, 'default_template'); + } + /** * Get all pages within this book. */ diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 14c3af1cc5c..9d8db27e93c 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -6,6 +6,7 @@ use BookStack\Actions\ActivityType; use BookStack\Actions\View; use BookStack\Entities\Models\Bookshelf; +use BookStack\Entities\Models\Page; use BookStack\Entities\Repos\BookRepo; use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\Cloner; @@ -79,8 +80,14 @@ public function create(string $shelfSlug = null) $this->setPageTitle(trans('entities.books_create')); + $templates = Page::visible() + ->where('template', '=', true) + ->orderBy('name', 'asc') + ->get(); + return view('books.create', [ 'bookshelf' => $bookshelf, + 'templates' => $templates, ]); } @@ -98,6 +105,7 @@ public function store(Request $request, string $shelfSlug = null) 'description' => ['string', 'max:1000'], 'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'tags' => ['array'], + 'default_template' => ['nullable', 'exists:pages,id'], ]); $bookshelf = null; @@ -151,7 +159,12 @@ public function edit(string $slug) $this->checkOwnablePermission('book-update', $book); $this->setPageTitle(trans('entities.books_edit_named', ['bookName' => $book->getShortName()])); - return view('books.edit', ['book' => $book, 'current' => $book]); + $templates = Page::visible() + ->where('template', '=', true) + ->orderBy('name', 'asc') + ->get(); + + return view('books.edit', ['book' => $book, 'current' => $book, 'templates' => $templates]); } /** @@ -171,6 +184,7 @@ public function update(Request $request, string $slug) 'description' => ['string', 'max:1000'], 'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'tags' => ['array'], + 'default_template' => ['nullable', 'exists:pages,id'], ]); if ($request->has('image_reset')) { diff --git a/database/migrations/2022_12_02_104541_add_default_template_to_books.php b/database/migrations/2022_12_02_104541_add_default_template_to_books.php new file mode 100644 index 00000000000..755f83b5c0b --- /dev/null +++ b/database/migrations/2022_12_02_104541_add_default_template_to_books.php @@ -0,0 +1,32 @@ +integer('default_template')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('books', function (Blueprint $table) { + $table->dropColumn('default_template'); + }); + } +} diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index fa2586f8d75..38c2f2ae391 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -328,6 +328,8 @@ 'templates_replace_content' => 'Replace page content', 'templates_append_content' => 'Append to page content', 'templates_prepend_content' => 'Prepend to page content', + 'default_template' => 'Default Page Template', + 'default_template_explain' => "Assign a default template that will be used for all new pages in this book.", // Profile View 'profile_user_for_x' => 'User for :time', diff --git a/resources/views/books/create.blade.php b/resources/views/books/create.blade.php index eead4191c34..6253a49bbb9 100644 --- a/resources/views/books/create.blade.php +++ b/resources/views/books/create.blade.php @@ -28,7 +28,10 @@

{{ trans('entities.books_create') }}

- @include('books.parts.form', ['returnLocation' => isset($bookshelf) ? $bookshelf->getUrl() : url('/books')]) + @include('books.parts.form', [ + 'templates' => $templates, + 'returnLocation' => isset($bookshelf) ? $bookshelf->getUrl() : url('/books') + ])
diff --git a/resources/views/books/edit.blade.php b/resources/views/books/edit.blade.php index 180500e0a04..9ec47293509 100644 --- a/resources/views/books/edit.blade.php +++ b/resources/views/books/edit.blade.php @@ -18,7 +18,11 @@

{{ trans('entities.books_edit') }}

- @include('books.parts.form', ['model' => $book, 'returnLocation' => $book->getUrl()]) + @include('books.parts.form', [ + 'model' => $book, + 'templates' => $templates, + 'returnLocation' => $book->getUrl() + ])
diff --git a/resources/views/books/parts/form.blade.php b/resources/views/books/parts/form.blade.php index e893bceadc5..c6ef7d171f1 100644 --- a/resources/views/books/parts/form.blade.php +++ b/resources/views/books/parts/form.blade.php @@ -35,6 +35,15 @@ +
+ +
+ @include('entities.template-manager', ['entity' => $book ?? null, 'templates' => $templates]) +
+
+
{{ trans('common.cancel') }} diff --git a/resources/views/entities/template-manager.blade.php b/resources/views/entities/template-manager.blade.php new file mode 100644 index 00000000000..fe04d9389ef --- /dev/null +++ b/resources/views/entities/template-manager.blade.php @@ -0,0 +1,10 @@ +

+ {!! nl2br(e(trans('entities.default_template_explain'))) !!} +

+ + \ No newline at end of file From 99ae759effb709694ab934ae640a104e59a1a509 Mon Sep 17 00:00:00 2001 From: Lennert Daniels Date: Fri, 2 Dec 2022 18:42:58 +0100 Subject: [PATCH 0003/1295] Prefill new pages with book's default template --- app/Entities/Repos/PageRepo.php | 6 ++++++ app/Http/Controllers/PageController.php | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index c8eddc398ca..a1558b85db8 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -148,6 +148,12 @@ public function getNewDraftPage(Entity $parent) $page->book_id = $parent->id; } + if ($page->book->defaultTemplate) { + $page->forceFill([ + 'html' => $page->book->defaultTemplate->html, + ]); + } + $page->save(); $page->refresh()->rebuildPermissions(); diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index 9e09aed16c1..394147ce224 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -74,7 +74,6 @@ public function createAsGuest(Request $request, string $bookSlug, string $chapte $page = $this->pageRepo->getNewDraftPage($parent); $this->pageRepo->publishDraft($page, [ 'name' => $request->get('name'), - 'html' => '', ]); return redirect($page->getUrl('/edit')); From ec3b06d83f660a90036edd76e0a0c3de52645252 Mon Sep 17 00:00:00 2001 From: Lennert Daniels Date: Fri, 2 Dec 2022 18:43:51 +0100 Subject: [PATCH 0004/1295] Add notice to Page delete confirmation when in use as a template --- app/Http/Controllers/PageController.php | 3 +++ resources/lang/en/entities.php | 1 + resources/views/pages/delete.blade.php | 3 +++ 3 files changed, 7 insertions(+) diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index 394147ce224..8b131c4f3d8 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -3,6 +3,7 @@ namespace BookStack\Http\Controllers; use BookStack\Actions\View; +use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Page; use BookStack\Entities\Repos\PageRepo; use BookStack\Entities\Tools\BookContents; @@ -265,11 +266,13 @@ public function showDelete(string $bookSlug, string $pageSlug) $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-delete', $page); $this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()])); + $times_used_as_template = Book::where('default_template', '=', $page->id)->count(); return view('pages.delete', [ 'book' => $page->book, 'page' => $page, 'current' => $page, + 'times_used_as_template' => $times_used_as_template, ]); } diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 38c2f2ae391..4af6120f820 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -192,6 +192,7 @@ 'pages_delete_draft' => 'Delete Draft Page', 'pages_delete_success' => 'Page deleted', 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_warning_template' => '{0}|{1}Be careful: this page is used as a template for :count book.|[2,*]Be careful: this page is used as a template for :count books.', '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', diff --git a/resources/views/pages/delete.blade.php b/resources/views/pages/delete.blade.php index 39cd07bbb1c..9ce50d48b13 100644 --- a/resources/views/pages/delete.blade.php +++ b/resources/views/pages/delete.blade.php @@ -19,6 +19,9 @@

{{ $page->draft ? trans('entities.pages_delete_draft') : trans('entities.pages_delete') }}

+ @if ($times_used_as_template > 0) +

{{ trans_choice('entities.pages_delete_warning_template', $times_used_as_template) }}

+ @endif
From ac519b3009e353448fc0541d21c08422d77dc57d Mon Sep 17 00:00:00 2001 From: Lennert Daniels Date: Fri, 2 Dec 2022 18:44:17 +0100 Subject: [PATCH 0005/1295] Guest create page: name field autofocus --- resources/views/pages/guest-create.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/pages/guest-create.blade.php b/resources/views/pages/guest-create.blade.php index d6e1cae446a..11970b8b6e3 100644 --- a/resources/views/pages/guest-create.blade.php +++ b/resources/views/pages/guest-create.blade.php @@ -22,7 +22,7 @@
- @include('form.text', ['name' => 'name']) + @include('form.text', ['name' => 'name', 'autofocus' => true])
From ce0b75294fb22a69219a8c8d4aac1f69825422d5 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 2 May 2023 12:44:55 +0100 Subject: [PATCH 0006/1295] Set page include limit to be 3 as expected instead of 4 --- app/Entities/Tools/PageContent.php | 2 +- tests/Entity/PageContentTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Entities/Tools/PageContent.php b/app/Entities/Tools/PageContent.php index a12a19c661e..949816eff57 100644 --- a/app/Entities/Tools/PageContent.php +++ b/app/Entities/Tools/PageContent.php @@ -304,7 +304,7 @@ public function render(bool $blankIncludes = false): string if ($blankIncludes) { $content = $this->blankPageIncludes($content); } else { - for ($includeDepth = 0; $includeDepth <= 3; $includeDepth++) { + for ($includeDepth = 0; $includeDepth < 3; $includeDepth++) { $content = $this->parsePageIncludes($content); } } diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php index cf67e27e24a..d8845fe1276 100644 --- a/tests/Entity/PageContentTest.php +++ b/tests/Entity/PageContentTest.php @@ -116,7 +116,8 @@ public function test_page_includes_can_be_nested_up_to_three_times() $page->save(); $pageResp = $this->asEditor()->get($page->getUrl()); - $this->withHtml($pageResp)->assertElementContains('#bkmrk-test', 'Hello Barry Hello Barry Hello Barry ' . $tag); + $this->withHtml($pageResp)->assertElementContains('#bkmrk-test', 'Hello Barry Hello Barry Hello Barry Hello Barry ' . $tag); + $this->withHtml($pageResp)->assertElementNotContains('#bkmrk-test', 'Hello Barry Hello Barry Hello Barry Hello Barry Hello Barry ' . $tag); } public function test_page_content_scripts_removed_by_default() From 57bdd83d8c0e529ccc3095c54fba0ca4cd1e02fe Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 3 May 2023 10:56:36 +0100 Subject: [PATCH 0007/1295] Added mostodon badge in readme, updated CLI --- bookstack-system-cli | Bin 354257 -> 354449 bytes readme.md | 1 + 2 files changed, 1 insertion(+) diff --git a/bookstack-system-cli b/bookstack-system-cli index dd229a155c9727c24c7188a3b9733cb93c754be4..ef82d04d66099a5e606196455c62eccf05bb8cc5 100755 GIT binary patch delta 9674 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 delta 9499 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 Date: Sat, 6 May 2023 23:05:25 +0100 Subject: [PATCH 0008/1295] Added force option for update-url command Includes test to cover. Closes #4223 --- app/Console/Commands/UpdateUrl.php | 45 ++++++++++++------------- tests/Commands/UpdateUrlCommandTest.php | 8 +++++ 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/app/Console/Commands/UpdateUrl.php b/app/Console/Commands/UpdateUrl.php index a4bb6cf2288..facb4cc41ea 100644 --- a/app/Console/Commands/UpdateUrl.php +++ b/app/Console/Commands/UpdateUrl.php @@ -14,7 +14,8 @@ class UpdateUrl extends Command */ protected $signature = 'bookstack:update-url {oldUrl : URL to replace} - {newUrl : URL to use as the replacement}'; + {newUrl : URL to use as the replacement} + {--force : Force the operation to run, ignoring confirmations}'; /** * The console command description. @@ -23,25 +24,12 @@ class UpdateUrl extends Command */ protected $description = 'Find and replace the given URLs in your BookStack database'; - protected $db; - - /** - * Create a new command instance. - * - * @return void - */ - public function __construct(Connection $db) - { - $this->db = $db; - parent::__construct(); - } - /** * Execute the console command. * * @return mixed */ - public function handle() + public function handle(Connection $db) { $oldUrl = str_replace("'", '', $this->argument('oldUrl')); $newUrl = str_replace("'", '', $this->argument('newUrl')); @@ -67,7 +55,7 @@ public function handle() foreach ($columnsToUpdateByTable as $table => $columns) { foreach ($columns as $column) { - $changeCount = $this->replaceValueInTable($table, $column, $oldUrl, $newUrl); + $changeCount = $this->replaceValueInTable($db, $table, $column, $oldUrl, $newUrl); $this->info("Updated {$changeCount} rows in {$table}->{$column}"); } } @@ -80,7 +68,7 @@ public function handle() foreach ($columns as $column) { $oldJson = trim(json_encode($oldUrl), '"'); $newJson = trim(json_encode($newUrl), '"'); - $changeCount = $this->replaceValueInTable($table, $column, $oldJson, $newJson); + $changeCount = $this->replaceValueInTable($db, $table, $column, $oldJson, $newJson); $this->info("Updated {$changeCount} JSON encoded rows in {$table}->{$column}"); } } @@ -97,13 +85,18 @@ public function handle() * Perform a find+replace operations in the provided table and column. * Returns the count of rows changed. */ - protected function replaceValueInTable(string $table, string $column, string $oldUrl, string $newUrl): int - { - $oldQuoted = $this->db->getPdo()->quote($oldUrl); - $newQuoted = $this->db->getPdo()->quote($newUrl); - - return $this->db->table($table)->update([ - $column => $this->db->raw("REPLACE({$column}, {$oldQuoted}, {$newQuoted})"), + protected function replaceValueInTable( + Connection $db, + string $table, + string $column, + string $oldUrl, + string $newUrl + ): int { + $oldQuoted = $db->getPdo()->quote($oldUrl); + $newQuoted = $db->getPdo()->quote($newUrl); + + return $db->table($table)->update([ + $column => $db->raw("REPLACE({$column}, {$oldQuoted}, {$newQuoted})"), ]); } @@ -113,6 +106,10 @@ protected function replaceValueInTable(string $table, string $column, string $ol */ protected function checkUserOkayToProceed(string $oldUrl, string $newUrl): bool { + if ($this->option('force')) { + return true; + } + $dangerWarning = "This will search for \"{$oldUrl}\" in your database and replace it with \"{$newUrl}\".\n"; $dangerWarning .= 'Are you sure you want to proceed?'; $backupConfirmation = 'This operation could cause issues if used incorrectly. Have you made a backup of your existing database?'; diff --git a/tests/Commands/UpdateUrlCommandTest.php b/tests/Commands/UpdateUrlCommandTest.php index 1788e9452a6..280c81febd1 100644 --- a/tests/Commands/UpdateUrlCommandTest.php +++ b/tests/Commands/UpdateUrlCommandTest.php @@ -2,6 +2,7 @@ namespace Tests\Commands; +use Illuminate\Support\Facades\Artisan; use Symfony\Component\Console\Exception\RuntimeException; use Tests\TestCase; @@ -34,6 +35,13 @@ public function test_command_requires_valid_url() $this->artisan('bookstack:update-url https://cats.example.com'); } + public function test_command_force_option_skips_prompt() + { + $this->artisan('bookstack:update-url --force https://cats.example.com/donkey https://cats.example.com/monkey') + ->expectsOutputToContain('URL update procedure complete') + ->assertSuccessful(); + } + public function test_command_updates_settings() { setting()->put('my-custom-item', 'https://example.com/donkey/cat'); From 3bcbf6b9c55c9988b04835473053d514a1cb5df3 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 7 May 2023 19:36:10 +0100 Subject: [PATCH 0009/1295] Added WYSWIYG editor code editor cancel focus return Focus now returns to the editor properly when you quit out the code editor without saving. This also sets the return location to be correct on normal saving (Would sometimes jump to the end of the document). For #4109. --- resources/js/components/code-editor.js | 22 +++++++++++++++++----- resources/js/wysiwyg/plugin-codeeditor.js | 9 ++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/resources/js/components/code-editor.js b/resources/js/components/code-editor.js index f9dc2b69ff9..1c68c2048d2 100644 --- a/resources/js/components/code-editor.js +++ b/resources/js/components/code-editor.js @@ -8,7 +8,15 @@ export class CodeEditor extends Component { */ editor = null; - callback = null; + /** + * @type {?Function} + */ + saveCallback = null; + + /** + * @type {?Function} + */ + cancelCallback = null; history = {}; @@ -115,15 +123,16 @@ export class CodeEditor extends Component { } save() { - if (this.callback) { - this.callback(this.editor.getContent(), this.languageInput.value); + if (this.saveCallback) { + this.saveCallback(this.editor.getContent(), this.languageInput.value); } this.hide(); } - async open(code, language, callback) { + async open(code, language, saveCallback, cancelCallback) { this.languageInput.value = language; - this.callback = callback; + this.saveCallback = saveCallback; + this.cancelCallback = cancelCallback; await this.show(); this.languageInputChange(language); @@ -141,6 +150,9 @@ export class CodeEditor extends Component { this.editor.focus(); }, () => { this.addHistory(); + if (this.cancelCallback) { + this.cancelCallback(); + } }); } diff --git a/resources/js/wysiwyg/plugin-codeeditor.js b/resources/js/wysiwyg/plugin-codeeditor.js index fa3804ea836..25f774baabd 100644 --- a/resources/js/wysiwyg/plugin-codeeditor.js +++ b/resources/js/wysiwyg/plugin-codeeditor.js @@ -9,9 +9,16 @@ function elemIsCodeBlock(elem) { * @param {function(string, string)} callback (Receives (code: string,language: string) */ function showPopup(editor, code, language, callback) { - window.$components.first('code-editor').open(code, language, (newCode, newLang) => { + /** @var {CodeEditor} codeEditor * */ + const codeEditor = window.$components.first('code-editor'); + const bookMark = editor.selection.getBookmark(); + codeEditor.open(code, language, (newCode, newLang) => { callback(newCode, newLang); editor.focus(); + editor.selection.moveToBookmark(bookMark); + }, () => { + editor.focus(); + editor.selection.moveToBookmark(bookMark); }); } From b5cc0a8e38848043295e3d1960b5a347432532dd Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 8 May 2023 12:01:52 +0100 Subject: [PATCH 0010/1295] Fixed added padding around hr tags in details blocks Due to manual handling & wrapping of non-block content in details block not taking hr elements into account. For #3963 --- resources/js/wysiwyg/config.js | 2 +- resources/js/wysiwyg/util.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/js/wysiwyg/config.js b/resources/js/wysiwyg/config.js index a0e7156ee68..37b810718f8 100644 --- a/resources/js/wysiwyg/config.js +++ b/resources/js/wysiwyg/config.js @@ -268,7 +268,7 @@ export function build(options) { '-doc-root[doc-root|#text]', '-li[details]', '+code-block[pre]', - '+doc-root[p|h1|h2|h3|h4|h5|h6|blockquote|code-block|div]', + '+doc-root[p|h1|h2|h3|h4|h5|h6|blockquote|code-block|div|hr]', ].join(','), plugins: gatherPlugins(options), contextmenu: false, diff --git a/resources/js/wysiwyg/util.js b/resources/js/wysiwyg/util.js index 68b6aabfce5..2422da7813e 100644 --- a/resources/js/wysiwyg/util.js +++ b/resources/js/wysiwyg/util.js @@ -14,4 +14,5 @@ export const blockElementTypes = [ 'ul', 'ol', 'table', + 'hr', ]; From 2523cee0e2b7a1eb31feec65b6448ccaa45d27f4 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 8 May 2023 12:21:53 +0100 Subject: [PATCH 0011/1295] WYSWIYG code blocks: copied head styles into shadow root Currently only link-based styles are made available in the shadow root code editor environment, this adds normal styles to apply any user-added via custom head content. Fixes #4228 --- resources/js/wysiwyg/plugin-codeeditor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/wysiwyg/plugin-codeeditor.js b/resources/js/wysiwyg/plugin-codeeditor.js index 25f774baabd..2fe2ac26a6b 100644 --- a/resources/js/wysiwyg/plugin-codeeditor.js +++ b/resources/js/wysiwyg/plugin-codeeditor.js @@ -53,8 +53,8 @@ function defineCodeBlockCustomElement(editor) { super(); this.attachShadow({mode: 'open'}); - const stylesToCopy = document.querySelectorAll('link[rel="stylesheet"]:not([media="print"])'); - const copiedStyles = Array.from(stylesToCopy).map(styleEl => styleEl.cloneNode(false)); + const stylesToCopy = document.head.querySelectorAll('link[rel="stylesheet"]:not([media="print"]),style'); + const copiedStyles = Array.from(stylesToCopy).map(styleEl => styleEl.cloneNode(true)); const cmContainer = document.createElement('div'); cmContainer.style.pointerEvents = 'none'; From 8846f7d255d9d2f9d6b997d57aff9a511074796f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 8 May 2023 14:28:03 +0100 Subject: [PATCH 0012/1295] Prevented shorcuts activating when in codemirror areas For #4227 --- resources/js/components/shortcuts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/shortcuts.js b/resources/js/components/shortcuts.js index 1d5bd51d784..85a7c3da711 100644 --- a/resources/js/components/shortcuts.js +++ b/resources/js/components/shortcuts.js @@ -25,7 +25,7 @@ export class Shortcuts extends Component { setupListeners() { window.addEventListener('keydown', event => { - if (event.target.closest('input, select, textarea')) { + if (event.target.closest('input, select, textarea, .cm-editor')) { return; } From ee1e047964e53348c22bbc37a2b4187abd4e2d86 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 8 May 2023 14:37:01 +0100 Subject: [PATCH 0013/1295] Updated php deps, formatted command changes --- app/Console/Commands/UpdateUrl.php | 8 +-- composer.lock | 109 ++++++++++++++++++++++------- 2 files changed, 89 insertions(+), 28 deletions(-) diff --git a/app/Console/Commands/UpdateUrl.php b/app/Console/Commands/UpdateUrl.php index facb4cc41ea..0d218b380ae 100644 --- a/app/Console/Commands/UpdateUrl.php +++ b/app/Console/Commands/UpdateUrl.php @@ -87,10 +87,10 @@ public function handle(Connection $db) */ protected function replaceValueInTable( Connection $db, - string $table, - string $column, - string $oldUrl, - string $newUrl + string $table, + string $column, + string $oldUrl, + string $newUrl ): int { $oldQuoted = $db->getPdo()->quote($oldUrl); $newQuoted = $db->getPdo()->quote($newUrl); diff --git a/composer.lock b/composer.lock index 1f3d95683d3..5157a43c6ec 100644 --- a/composer.lock +++ b/composer.lock @@ -2531,19 +2531,20 @@ }, { "name": "league/flysystem", - "version": "3.14.0", + "version": "3.15.1", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "e2a279d7f47d9098e479e8b21f7fb8b8de230158" + "reference": "a141d430414fcb8bf797a18716b09f759a385bed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e2a279d7f47d9098e479e8b21f7fb8b8de230158", - "reference": "e2a279d7f47d9098e479e8b21f7fb8b8de230158", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a141d430414fcb8bf797a18716b09f759a385bed", + "reference": "a141d430414fcb8bf797a18716b09f759a385bed", "shasum": "" }, "require": { + "league/flysystem-local": "^3.0.0", "league/mime-type-detection": "^1.0.0", "php": "^8.0.2" }, @@ -2602,7 +2603,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.14.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.15.1" }, "funding": [ { @@ -2614,20 +2615,20 @@ "type": "github" } ], - "time": "2023-04-11T18:11:47+00:00" + "time": "2023-05-04T09:04:26+00:00" }, { "name": "league/flysystem-aws-s3-v3", - "version": "3.13.0", + "version": "3.15.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "8e04cbb403d4dfd5b73a2f8685f1df395bd177eb" + "reference": "d8de61ee10b6a607e7996cff388c5a3a663e8c8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/8e04cbb403d4dfd5b73a2f8685f1df395bd177eb", - "reference": "8e04cbb403d4dfd5b73a2f8685f1df395bd177eb", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/d8de61ee10b6a607e7996cff388c5a3a663e8c8a", + "reference": "d8de61ee10b6a607e7996cff388c5a3a663e8c8a", "shasum": "" }, "require": { @@ -2668,7 +2669,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues", - "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.13.0" + "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.15.0" }, "funding": [ { @@ -2680,7 +2681,67 @@ "type": "github" } ], - "time": "2023-03-16T14:29:01+00:00" + "time": "2023-05-02T20:02:14+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.15.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "543f64c397fefdf9cfeac443ffb6beff602796b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/543f64c397fefdf9cfeac443ffb6beff602796b3", + "reference": "543f64c397fefdf9cfeac443ffb6beff602796b3", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem-local/issues", + "source": "https://github.com/thephpleague/flysystem-local/tree/3.15.0" + }, + "funding": [ + { + "url": "https://ecologi.com/frankdejonge", + "type": "custom" + }, + { + "url": "https://github.com/frankdejonge", + "type": "github" + } + ], + "time": "2023-05-02T20:02:14+00:00" }, { "name": "league/html-to-markdown", @@ -4569,16 +4630,16 @@ }, { "name": "psy/psysh", - "version": "v0.11.16", + "version": "v0.11.17", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "151b145906804eea8e5d71fea23bfb470c904bfb" + "reference": "3dc5d4018dabd80bceb8fe1e3191ba8460569f0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/151b145906804eea8e5d71fea23bfb470c904bfb", - "reference": "151b145906804eea8e5d71fea23bfb470c904bfb", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/3dc5d4018dabd80bceb8fe1e3191ba8460569f0a", + "reference": "3dc5d4018dabd80bceb8fe1e3191ba8460569f0a", "shasum": "" }, "require": { @@ -4639,9 +4700,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.16" + "source": "https://github.com/bobthecow/psysh/tree/v0.11.17" }, - "time": "2023-04-26T12:53:57+00:00" + "time": "2023-05-05T20:02:42+00:00" }, { "name": "ralouphie/getallheaders", @@ -9509,16 +9570,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -9563,7 +9624,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -9571,7 +9632,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", From 4489f6537111521fe7d6f8c96527ae23b68cde7c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 8 May 2023 14:45:45 +0100 Subject: [PATCH 0014/1295] Fixed code block line-number bar showing in exports Also fixed in print view. Likely crept in during CM6 changes. For #4215 --- resources/sass/_text.scss | 2 +- resources/sass/export-styles.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/sass/_text.scss b/resources/sass/_text.scss index 6745d2a546e..adfc87ad15a 100644 --- a/resources/sass/_text.scss +++ b/resources/sass/_text.scss @@ -202,7 +202,7 @@ pre { pre { padding-left: 12px; } - pre:after { + pre:before { display: none; } } diff --git a/resources/sass/export-styles.scss b/resources/sass/export-styles.scss index b8160b4c2df..1e39bd0564e 100644 --- a/resources/sass/export-styles.scss +++ b/resources/sass/export-styles.scss @@ -33,7 +33,7 @@ table { pre { padding-left: 12px; } -pre:after { +pre:before { display: none; } pre code { From ae90776927b59990131ef33e87813fd1ff89f71d Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 8 May 2023 14:49:01 +0100 Subject: [PATCH 0015/1295] Updated translations with latest Crowdin changes (#4211) --- lang/ca/activities.php | 16 ++--- lang/fr/components.php | 8 +-- lang/fr/entities.php | 10 +-- lang/fr/errors.php | 2 +- lang/it/components.php | 8 +-- lang/it/entities.php | 4 +- lang/it/errors.php | 2 +- lang/ja/common.php | 2 +- lang/ja/components.php | 8 +-- lang/ja/entities.php | 4 +- lang/ja/errors.php | 2 +- lang/nl/activities.php | 12 ++-- lang/nl/auth.php | 20 +++--- lang/nl/components.php | 8 +-- lang/nl/entities.php | 4 +- lang/nl/errors.php | 2 +- lang/pl/components.php | 8 +-- lang/pl/entities.php | 4 +- lang/pl/errors.php | 2 +- lang/vi/activities.php | 6 +- lang/vi/common.php | 2 +- lang/vi/components.php | 12 ++-- lang/vi/editor.php | 140 ++++++++++++++++++++-------------------- lang/zh_CN/entities.php | 4 +- lang/zh_CN/errors.php | 2 +- 25 files changed, 146 insertions(+), 146 deletions(-) diff --git a/lang/ca/activities.php b/lang/ca/activities.php index 45ccb45e4c3..cf360d9b548 100644 --- a/lang/ca/activities.php +++ b/lang/ca/activities.php @@ -7,27 +7,27 @@ // Pages 'page_create' => 'ha creat la pàgina', - 'page_create_notification' => 'Page successfully created', + 'page_create_notification' => 'Pàgina creada correctament', 'page_update' => 'ha actualitzat la pàgina', - 'page_update_notification' => 'Page successfully updated', + 'page_update_notification' => 'Pàgina actualitzada correctament', 'page_delete' => 'ha suprimit una pàgina', - 'page_delete_notification' => 'Page successfully deleted', + 'page_delete_notification' => 'Imatge esborrada correctament', 'page_restore' => 'ha restaurat la pàgina', - 'page_restore_notification' => 'Page successfully restored', + 'page_restore_notification' => 'Pàgina restaurada correctament', 'page_move' => 'ha mogut la pàgina', // Chapters 'chapter_create' => 'ha creat el capítol', - 'chapter_create_notification' => 'Chapter successfully created', + 'chapter_create_notification' => 'Capítol creat correctament', 'chapter_update' => 'ha actualitzat el capítol', - 'chapter_update_notification' => 'Chapter successfully updated', + 'chapter_update_notification' => 'Capítol actualitzat correctament', 'chapter_delete' => 'ha suprimit un capítol', - 'chapter_delete_notification' => 'Chapter successfully deleted', + 'chapter_delete_notification' => 'Capítol esborrat correctament', 'chapter_move' => 'ha mogut el capítol', // Books 'book_create' => 'ha creat el llibre', - 'book_create_notification' => 'Book successfully created', + 'book_create_notification' => 'Llibre creat correctament', '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', diff --git a/lang/fr/components.php b/lang/fr/components.php index 310ec071be2..04bedf7d8aa 100644 --- a/lang/fr/components.php +++ b/lang/fr/components.php @@ -6,9 +6,9 @@ // Image Manager 'image_select' => 'Sélectionner une image', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_upload' => 'Téléverser une image', + 'image_intro' => 'Ici, vous pouvez sélectionner et gérer les images qui ont été précédemment téléversées sur le système.', + 'image_intro_upload' => 'Téléverser une nouvelle image en glissant un fichier image dans cette fenêtre, ou en utilisant le bouton "Téléverser une image" ci-dessus.', 'image_all' => 'Toutes', 'image_all_title' => 'Voir toutes les images', 'image_book_title' => 'Voir les images ajoutées à ce livre', @@ -21,7 +21,7 @@ 'image_delete_confirm_text' => 'Êtes-vous sûr de vouloir supprimer cette image ?', 'image_select_image' => 'Sélectionner l\'image', 'image_dropzone' => 'Glissez les images ici ou cliquez pour les ajouter', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'Déposer des images ici pour les téléverser', 'images_deleted' => 'Images supprimées', 'image_preview' => 'Prévisualiser l\'image', 'image_upload_success' => 'Image ajoutée avec succès', diff --git a/lang/fr/entities.php b/lang/fr/entities.php index c750600640e..2fb803bafe0 100644 --- a/lang/fr/entities.php +++ b/lang/fr/entities.php @@ -309,16 +309,16 @@ 'tags_view_existing_tags' => 'Voir les mots-clés existants', 'tags_list_empty_hint' => 'Les mots-clés peuvent être assignés via la barre latérale de l\'éditeur de page ou lors de l\'édition des détails d\'un livre, d\'un chapitre ou d\'une étagère.', 'attachments' => 'Fichiers joints', - 'attachments_explain' => 'Ajouter des fichiers ou des liens pour les afficher sur votre page. Ils seront affichés dans la barre latérale', + 'attachments_explain' => 'Ajouter des fichiers ou des liens pour les afficher sur votre page. Ils seront affichés dans la barre latérale.', 'attachments_explain_instant_save' => 'Ces changements sont enregistrés immédiatement.', - 'attachments_upload' => 'Uploader un fichier', + 'attachments_upload' => 'Téléverser un fichier', 'attachments_link' => 'Attacher un lien', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', + 'attachments_upload_drop' => 'Vous pouvez également glisser-déposer un fichier ici pour le téléverser en tant que pièce jointe.', 'attachments_set_link' => 'Définir un lien', 'attachments_delete' => 'Êtes-vous sûr de vouloir supprimer la pièce jointe ?', - 'attachments_dropzone' => 'Drop files here to upload', + 'attachments_dropzone' => 'Déposer des fichiers ici pour les téléverser', 'attachments_no_files' => 'Aucun fichier ajouté', - 'attachments_explain_link' => 'Vous pouvez ajouter un lien si vous ne souhaitez pas uploader un fichier.', + 'attachments_explain_link' => 'Vous pouvez ajouter un lien si vous ne souhaitez pas téléverser un fichier.', 'attachments_link_name' => 'Nom du lien', 'attachment_link' => 'Lien de l\'attachement', 'attachments_link_url' => 'Lien sur un fichier', diff --git a/lang/fr/errors.php b/lang/fr/errors.php index 976655ae3d5..ade5b656354 100644 --- a/lang/fr/errors.php +++ b/lang/fr/errors.php @@ -53,7 +53,7 @@ // Attachments 'attachment_not_found' => 'Fichier joint non trouvé', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_upload_error' => 'Une erreur s\'est produite avec le téléversement du fichier joint', // Pages 'page_draft_autosave_fail' => 'Le brouillon n\'a pas pu être enregistré. Vérifiez votre connexion internet', diff --git a/lang/it/components.php b/lang/it/components.php index ad0b404263d..882213bb176 100644 --- a/lang/it/components.php +++ b/lang/it/components.php @@ -6,9 +6,9 @@ // Image Manager 'image_select' => 'Selezione Immagine', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_upload' => 'Carica Immagine', + 'image_intro' => 'Qui è possibile selezionare e gestire le immagini che sono state precedentemente caricate nel sistema.', + 'image_intro_upload' => 'Carica una nuova immagine trascinando un file immagine in questa finestra oppure utilizzando il pulsante "Carica immagine" in alto.', 'image_all' => 'Tutte', 'image_all_title' => 'Visualizza tutte le immagini', 'image_book_title' => 'Visualizza immagini caricate in questo libro', @@ -21,7 +21,7 @@ 'image_delete_confirm_text' => 'Sei sicuro di voler eliminare questa immagine?', 'image_select_image' => 'Seleziona Immagine', 'image_dropzone' => 'Rilascia immagini o clicca qui per caricarle', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'Trascina qui le immagini da caricare', 'images_deleted' => 'Immagini Eliminate', 'image_preview' => 'Anteprima Immagine', 'image_upload_success' => 'Immagine caricata correttamente', diff --git a/lang/it/entities.php b/lang/it/entities.php index 1d81f5ae0df..07f7bbda14e 100644 --- a/lang/it/entities.php +++ b/lang/it/entities.php @@ -313,10 +313,10 @@ 'attachments_explain_instant_save' => 'I cambiamenti qui sono salvati istantaneamente.', 'attachments_upload' => 'Carica File', 'attachments_link' => 'Allega Link', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', + 'attachments_upload_drop' => 'In alternativa puoi trascinare un file qui per caricarlo come allegato.', 'attachments_set_link' => 'Imposta Link', 'attachments_delete' => 'Sei sicuro di voler eliminare questo allegato?', - 'attachments_dropzone' => 'Drop files here to upload', + 'attachments_dropzone' => 'Trascina qui i file da caricare', 'attachments_no_files' => 'Nessun file è stato caricato', 'attachments_explain_link' => 'Puoi allegare un link se preferisci non caricare un file. Questo può essere un link a un\'altra pagina o a un file nel cloud.', 'attachments_link_name' => 'Nome Link', diff --git a/lang/it/errors.php b/lang/it/errors.php index e2e7d49cd1a..ad3e5f8cf76 100644 --- a/lang/it/errors.php +++ b/lang/it/errors.php @@ -53,7 +53,7 @@ // Attachments 'attachment_not_found' => 'Allegato non trovato', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_upload_error' => 'Si è verificato un errore durante il caricamento del file allegato', // Pages 'page_draft_autosave_fail' => 'Impossibile salvare la bozza. Controlla di essere connesso ad internet prima di salvare questa pagina', diff --git a/lang/ja/common.php b/lang/ja/common.php index 78454bfd840..bc3c8befe29 100644 --- a/lang/ja/common.php +++ b/lang/ja/common.php @@ -68,7 +68,7 @@ 'back_to_top' => '上に戻る', 'skip_to_main_content' => 'メインコンテンツへスキップ', 'toggle_details' => '概要の表示切替', - 'toggle_thumbnails' => 'Toggle Thumbnails', + 'toggle_thumbnails' => 'サムネイルの切り替え', 'details' => '詳細', 'grid_view' => 'グリッド形式', 'list_view' => 'リスト形式', diff --git a/lang/ja/components.php b/lang/ja/components.php index 7fcc87d1d95..f492c74142e 100644 --- a/lang/ja/components.php +++ b/lang/ja/components.php @@ -6,9 +6,9 @@ // Image Manager 'image_select' => '画像を選択', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_upload' => '画像をアップロード', + 'image_intro' => 'ここでは、システムに以前アップロードされた画像を選択して管理できます。', + 'image_intro_upload' => 'このウィンドウに画像ファイルをドラッグするか、上の「画像をアップロード」ボタンを使用して新しい画像をアップロードします。', 'image_all' => 'すべて', 'image_all_title' => '全ての画像を表示', 'image_book_title' => 'このブックにアップロードされた画像を表示', @@ -21,7 +21,7 @@ 'image_delete_confirm_text' => 'この画像を削除してもよろしいですか?', 'image_select_image' => '画像を選択', 'image_dropzone' => '画像をドロップするか、クリックしてアップロード', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'アップロードする画像をここにドロップ', 'images_deleted' => '画像を削除しました', 'image_preview' => '画像プレビュー', 'image_upload_success' => '画像がアップロードされました', diff --git a/lang/ja/entities.php b/lang/ja/entities.php index ae952cd02be..599d1835df9 100644 --- a/lang/ja/entities.php +++ b/lang/ja/entities.php @@ -313,10 +313,10 @@ 'attachments_explain_instant_save' => 'この変更は即座に保存されます。', 'attachments_upload' => 'アップロード', 'attachments_link' => 'リンクを添付', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', + 'attachments_upload_drop' => 'ファイルをここにドラッグアンドドロップして添付ファイルとしてアップロードすることもできます。', 'attachments_set_link' => 'リンクを設定', 'attachments_delete' => 'この添付ファイルを削除してよろしいですか?', - 'attachments_dropzone' => 'Drop files here to upload', + 'attachments_dropzone' => 'アップロードするファイルをここにドロップ', 'attachments_no_files' => 'ファイルはアップロードされていません', 'attachments_explain_link' => 'ファイルをアップロードしたくない場合、他のページやクラウド上のファイルへのリンクを添付できます。', 'attachments_link_name' => 'リンク名', diff --git a/lang/ja/errors.php b/lang/ja/errors.php index 945a02ab0ed..fe6126fdca5 100644 --- a/lang/ja/errors.php +++ b/lang/ja/errors.php @@ -53,7 +53,7 @@ // Attachments 'attachment_not_found' => '添付ファイルが見つかりません', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_upload_error' => '添付ファイルのアップロード中にエラーが発生しました', // Pages 'page_draft_autosave_fail' => '下書きの保存に失敗しました。インターネットへ接続してください。', diff --git a/lang/nl/activities.php b/lang/nl/activities.php index 310be612b9f..29a2482c67d 100644 --- a/lang/nl/activities.php +++ b/lang/nl/activities.php @@ -12,9 +12,9 @@ 'page_update_notification' => 'Pagina succesvol bijgewerkt', 'page_delete' => 'verwijderde pagina', 'page_delete_notification' => 'Pagina succesvol verwijderd', - 'page_restore' => 'pagina hersteld', + 'page_restore' => 'herstelde pagina', 'page_restore_notification' => 'Pagina succesvol hersteld', - 'page_move' => 'pagina verplaatst', + 'page_move' => 'verplaatste pagina', // Chapters 'chapter_create' => 'maakte hoofdstuk', @@ -23,18 +23,18 @@ 'chapter_update_notification' => 'Hoofdstuk succesvol bijgewerkt', 'chapter_delete' => 'verwijderde hoofdstuk', 'chapter_delete_notification' => 'Hoofdstuk succesvol verwijderd', - 'chapter_move' => 'hoofdstuk verplaatst', + 'chapter_move' => 'verplaatste hoofdstuk', // Books 'book_create' => 'maakte boek', 'book_create_notification' => 'Boek succesvol aangemaakt', - 'book_create_from_chapter' => 'hoofdstuk omzetten naar boek', - 'book_create_from_chapter_notification' => 'Hoofdstuk is omgezet naar een boek', + 'book_create_from_chapter' => 'heeft hoofdstuk geconverteerd naar boek', + 'book_create_from_chapter_notification' => 'Hoofdstuk is succesvol geconverteerd naar boekenplank', 'book_update' => 'wijzigde boek', 'book_update_notification' => 'Boek succesvol bijgewerkt', 'book_delete' => 'verwijderde boek', 'book_delete_notification' => 'Boek succesvol verwijderd', - 'book_sort' => 'boek gesorteerd', + 'book_sort' => 'sorteerde boek', 'book_sort_notification' => 'Boek succesvol opnieuw gesorteerd', // Bookshelves diff --git a/lang/nl/auth.php b/lang/nl/auth.php index e0bbe36a746..dab15caca2a 100644 --- a/lang/nl/auth.php +++ b/lang/nl/auth.php @@ -20,22 +20,22 @@ 'username' => 'Gebruikersnaam', 'email' => 'E-mail', 'password' => 'Wachtwoord', - 'password_confirm' => 'Wachtwoord bevestigen', + 'password_confirm' => 'Wachtwoord Bevestigen', 'password_hint' => 'Moet uit minstens 8 tekens bestaan', 'forgot_password' => 'Wachtwoord vergeten?', 'remember_me' => 'Mij onthouden', - 'ldap_email_hint' => 'Geef een emailadres op voor dit account.', + 'ldap_email_hint' => 'Geef een e-mailadres op voor dit account.', 'create_account' => 'Account aanmaken', 'already_have_account' => 'Heb je al een account?', 'dont_have_account' => 'Nog geen account?', 'social_login' => 'Aanmelden via een sociaal netwerk', - 'social_registration' => 'Social registratie', + 'social_registration' => 'Registratie via een sociaal netwerk', 'social_registration_text' => 'Registreer en log in met een andere service.', 'register_thanks' => 'Bedankt voor het registreren!', - 'register_confirm' => 'Controleer je e-mail en bevestig je registratie om in te loggen op :appName.', + 'register_confirm' => 'Controleer je e-mail en klik op de bevestigingsknop om toegang te krijgen tot :appName.', 'registrations_disabled' => 'Registratie is momenteel niet mogelijk', - 'registration_email_domain_invalid' => 'Dit e-maildomein is niet toegestaan', + 'registration_email_domain_invalid' => 'Dit e-maildomein wordt niet toegelaten tot deze applicatie', 'register_success' => 'Bedankt voor het aanmelden! Je bent nu geregistreerd en aangemeld.', // Login auto-initiation @@ -45,22 +45,22 @@ // Password Reset 'reset_password' => 'Wachtwoord herstellen', - 'reset_password_send_instructions' => 'Geef je e-mail en we sturen je een link om je wachtwoord te herstellen', + 'reset_password_send_instructions' => 'Geef je e-mailadres op en er wordt een link gestuurd om je wachtwoord te herstellen.', 'reset_password_send_button' => 'Link sturen', 'reset_password_sent' => 'Een link om het wachtwoord te resetten zal verstuurd worden naar :email als dat e-mailadres in het systeem gevonden is.', 'reset_password_success' => 'Je wachtwoord is succesvol hersteld.', 'email_reset_subject' => 'Herstel je wachtwoord van :appName', - 'email_reset_text' => 'Je ontvangt deze e-mail omdat je een wachtwoord herstel verzoek had verzonden.', + 'email_reset_text' => 'Je ontvangt deze e-mail omdat we een wachtwoordresetverzoek voor uw account hebben ontvangen.', 'email_reset_not_requested' => 'Als je geen wachtwoord herstel hebt aangevraagd, hoef je niets te doen.', // Email Confirmation 'email_confirm_subject' => 'Bevestig je e-mailadres op :appName', 'email_confirm_greeting' => 'Bedankt voor je aanmelding op :appName!', - 'email_confirm_text' => 'Bevestig je registratie door op onderstaande knop te drukken:', + 'email_confirm_text' => 'Bevestig je e-mailadres door op onderstaande knop te drukken:', 'email_confirm_action' => 'Bevestig je e-mail', - 'email_confirm_send_error' => 'E-mail bevestiging is vereisd maar het systeem kon geen mail verzenden. Neem contact op met de beheerder.', + 'email_confirm_send_error' => 'Een e-mailbevestiging is vereist, maar het systeem kon de e-mail niet verzenden. Neem contact op met de beheerder.', 'email_confirm_success' => 'Uw e-mailadres is bevestigd! U zou nu moeten kunnen inloggen met dit e-mailadres.', - 'email_confirm_resent' => 'De bevestigingse-mails is opnieuw verzonden. Controleer je inbox.', + 'email_confirm_resent' => 'Bevestigingsmail opnieuw verzonden, controleer je inbox.', 'email_confirm_thanks' => 'Bedankt voor de bevestiging!', 'email_confirm_thanks_desc' => 'Wacht even terwijl uw bevestiging wordt behandeld. Als u na 3 seconden niet wordt doorverwezen, drukt u op de onderstaande link "Doorgaan" om verder te gaan.', diff --git a/lang/nl/components.php b/lang/nl/components.php index 1a210c6488d..a3f98b41dd0 100644 --- a/lang/nl/components.php +++ b/lang/nl/components.php @@ -6,9 +6,9 @@ // Image Manager 'image_select' => 'Selecteer Afbeelding', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_upload' => 'Upload afbeelding', + 'image_intro' => 'Hier kan je eerder geüploade afbeeldingen selecteren en beheren.', + 'image_intro_upload' => 'Sleep een afbeeldingsbestand naar dit venster of gebruik de "Upload afbeelding"-knop om een afbeelding te uploaden.', 'image_all' => 'Alles', 'image_all_title' => 'Alle afbeeldingen weergeven', 'image_book_title' => 'Bekijk afbeeldingen die naar dit boek zijn geüpload', @@ -21,7 +21,7 @@ 'image_delete_confirm_text' => 'Weet u zeker dat u deze afbeelding wilt verwijderen?', 'image_select_image' => 'Kies afbeelding', 'image_dropzone' => 'Sleep afbeeldingen naar hier of klik hier om te uploaden', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'Sleep hier de afbeeldingen naar toe', 'images_deleted' => 'Afbeeldingen verwijderd', 'image_preview' => 'Afbeelding voorbeeld', 'image_upload_success' => 'Afbeelding succesvol geüpload', diff --git a/lang/nl/entities.php b/lang/nl/entities.php index 2d67a3dc083..b2c50135cf7 100644 --- a/lang/nl/entities.php +++ b/lang/nl/entities.php @@ -313,10 +313,10 @@ 'attachments_explain_instant_save' => 'Wijzigingen worden meteen opgeslagen.', 'attachments_upload' => 'Bestand uploaden', 'attachments_link' => 'Link toevoegen', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', + 'attachments_upload_drop' => 'Of je kan een bestand hiernaartoe slepen om het als bijlage te uploaden.', 'attachments_set_link' => 'Zet link', 'attachments_delete' => 'Weet u zeker dat u deze bijlage wilt verwijderen?', - 'attachments_dropzone' => 'Drop files here to upload', + 'attachments_dropzone' => 'Sleep hier de bestanden naar toe', 'attachments_no_files' => 'Er zijn geen bestanden geüpload', 'attachments_explain_link' => 'Je kunt een hyperlink toevoegen als je geen bestanden wilt uploaden. Dit kan een link naar een andere pagina op deze website zijn, maar ook een link naar een andere website.', 'attachments_link_name' => 'Link naam', diff --git a/lang/nl/errors.php b/lang/nl/errors.php index 04a0200654d..6ced15dc3dc 100644 --- a/lang/nl/errors.php +++ b/lang/nl/errors.php @@ -53,7 +53,7 @@ // Attachments 'attachment_not_found' => 'Bijlage niet gevonden', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_upload_error' => 'Er is een fout opgetreden bij het uploaden van het bestand', // Pages 'page_draft_autosave_fail' => 'Kon het concept niet opslaan. Zorg ervoor dat je een werkende internetverbinding hebt', diff --git a/lang/pl/components.php b/lang/pl/components.php index 2de01266b7d..e822059ce56 100644 --- a/lang/pl/components.php +++ b/lang/pl/components.php @@ -6,9 +6,9 @@ // Image Manager 'image_select' => 'Wybór obrazka', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_upload' => 'Prześlij obraz', + 'image_intro' => 'Tutaj możesz wybrać i zarządzać obrazami, które zostały wcześniej przesłane do systemu.', + 'image_intro_upload' => 'Prześlij nowy obraz przeciągając plik obrazu do tego okna lub używając przycisku "Prześlij obraz" powyżej.', 'image_all' => 'Wszystkie', 'image_all_title' => 'Zobacz wszystkie obrazki', 'image_book_title' => 'Zobacz obrazki zapisane w tej książce', @@ -21,7 +21,7 @@ 'image_delete_confirm_text' => 'Czy na pewno chcesz usunąć ten obraz?', 'image_select_image' => 'Wybierz obrazek', 'image_dropzone' => 'Upuść obrazki tutaj lub kliknij by wybrać obrazki do przesłania', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'Upuść obrazy tutaj, aby przesłać', 'images_deleted' => 'Usunięte obrazki', 'image_preview' => 'Podgląd obrazka', 'image_upload_success' => 'Obrazek przesłany pomyślnie', diff --git a/lang/pl/entities.php b/lang/pl/entities.php index 1f3e242f4c9..bcdf9951ea9 100644 --- a/lang/pl/entities.php +++ b/lang/pl/entities.php @@ -313,10 +313,10 @@ 'attachments_explain_instant_save' => 'Zmiany są zapisywane natychmiastowo.', 'attachments_upload' => 'Dodaj plik', 'attachments_link' => 'Dodaj link', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', + 'attachments_upload_drop' => 'Alternatywnie możesz przeciągnąć i upuścić plik tutaj, aby przesłać go jako załącznik.', 'attachments_set_link' => 'Ustaw link', 'attachments_delete' => 'Jesteś pewien, że chcesz usunąć ten załącznik?', - 'attachments_dropzone' => 'Drop files here to upload', + 'attachments_dropzone' => 'Upuść pliki tutaj, aby przesłać', 'attachments_no_files' => 'Nie przesłano żadnych plików', 'attachments_explain_link' => 'Możesz załączyć link jeśli nie chcesz przesyłać pliku. Może być to link do innej strony lub link do pliku w chmurze.', 'attachments_link_name' => 'Nazwa linku', diff --git a/lang/pl/errors.php b/lang/pl/errors.php index baea4f6aaa1..bbadfac58c5 100644 --- a/lang/pl/errors.php +++ b/lang/pl/errors.php @@ -53,7 +53,7 @@ // Attachments 'attachment_not_found' => 'Nie znaleziono załącznika', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_upload_error' => 'Wystąpił błąd podczas przesyłania pliku załącznika', // Pages 'page_draft_autosave_fail' => 'Zapis wersji roboczej nie powiódł się. Upewnij się, że posiadasz połączenie z internetem.', diff --git a/lang/vi/activities.php b/lang/vi/activities.php index 23ae35f7f48..280da03df2c 100644 --- a/lang/vi/activities.php +++ b/lang/vi/activities.php @@ -68,9 +68,9 @@ 'user_delete_notification' => 'Người dùng đã được xóa thành công', // Roles - 'role_create_notification' => 'Role successfully created', - 'role_update_notification' => 'Role successfully updated', - 'role_delete_notification' => 'Role successfully deleted', + 'role_create_notification' => 'Vai trò mới đã được tạo thành công', + 'role_update_notification' => 'Vai trò đã được cập nhật thành công', + 'role_delete_notification' => 'Vai trò đã được xóa thành công', // Other 'commented_on' => 'đã bình luận về', diff --git a/lang/vi/common.php b/lang/vi/common.php index dab9e09756f..eda90a7697c 100644 --- a/lang/vi/common.php +++ b/lang/vi/common.php @@ -17,7 +17,7 @@ // Form Labels 'name' => 'Tên', 'description' => 'Mô tả', - 'role' => 'Quyền', + 'role' => 'Vai trò', 'cover_image' => 'Ảnh bìa', 'cover_image_description' => 'Ảnh nên có kích thước 440x250px.', diff --git a/lang/vi/components.php b/lang/vi/components.php index 4af522517d2..2c4e52e846a 100644 --- a/lang/vi/components.php +++ b/lang/vi/components.php @@ -6,13 +6,13 @@ // Image Manager 'image_select' => 'Chọn Ảnh', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_upload' => 'Tải ảnh lên', + 'image_intro' => 'Bạn có thể lựa chọn và quản lý các hình ảnh đã được tải lên hệ thống từ trước ở đây.', + 'image_intro_upload' => 'Tải lên ảnh mới bằng cách kéo và thả nó vào cửa sổ này, hoặc sử dụng nút tải ảnh ở bên trên.', 'image_all' => 'Tất cả', 'image_all_title' => 'Xem tất cả các ảnh', - 'image_book_title' => 'Xem các ảnh đã được tải lên sách này', - 'image_page_title' => 'Xem các ảnh đã được tải lên trang này', + 'image_book_title' => 'Xem các ảnh đã được tải lên trong sách này', + 'image_page_title' => 'Xem các ảnh đã được tải lên trong trang này', 'image_search_hint' => 'Tìm kiếm ảnh bằng tên', 'image_uploaded' => 'Đã tải lên :uploadedDate', 'image_load_more' => 'Hiện thêm', @@ -21,7 +21,7 @@ 'image_delete_confirm_text' => 'Bạn có chắc chắn muốn xóa hình ảnh này?', 'image_select_image' => 'Chọn Ảnh', 'image_dropzone' => 'Thả các ảnh hoặc bấm vào đây để tải lên', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'Kéo các tệp vào đây để tải lên', 'images_deleted' => 'Các ảnh đã được xóa', 'image_preview' => 'Xem trước Ảnh', 'image_upload_success' => 'Ảnh đã tải lên thành công', diff --git a/lang/vi/editor.php b/lang/vi/editor.php index 47803ee5df0..d1eebd0b3e1 100644 --- a/lang/vi/editor.php +++ b/lang/vi/editor.php @@ -62,58 +62,58 @@ 'table' => 'Bảng', 'insert_image' => 'Chèn hình ảnh', 'insert_image_title' => 'Chèn/Sửa hình ảnh', - 'insert_link' => 'Insert/edit link', - 'insert_link_title' => 'Insert/Edit Link', - 'insert_horizontal_line' => 'Insert horizontal line', - 'insert_code_block' => 'Insert code block', - 'edit_code_block' => 'Edit code block', - 'insert_drawing' => 'Insert/edit drawing', - 'drawing_manager' => 'Drawing manager', - 'insert_media' => 'Insert/edit media', - 'insert_media_title' => 'Insert/Edit Media', - 'clear_formatting' => 'Clear formatting', - 'source_code' => 'Source code', - 'source_code_title' => 'Source Code', - 'fullscreen' => 'Fullscreen', - 'image_options' => 'Image options', + 'insert_link' => 'Chèn/sửa liên kết', + 'insert_link_title' => 'Chèn/sửa liên kết', + 'insert_horizontal_line' => 'Chèn đường ngang', + 'insert_code_block' => 'Chèn khối mã', + 'edit_code_block' => 'Chỉnh sửa khối mã', + 'insert_drawing' => 'Chèn/chỉnh sửa bản vẻ', + 'drawing_manager' => 'Quản lý hình vẽ', + 'insert_media' => 'Chèn/chỉnh sửa media', + 'insert_media_title' => 'Chèn/chỉnh sửa media', + 'clear_formatting' => 'Xóa định dạng', + 'source_code' => 'Mã nguồn', + 'source_code_title' => 'Mã Nguồn', + 'fullscreen' => 'Toàn màn hình', + 'image_options' => 'Tuỳ chọn hình ảnh', // 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', + 'table_properties' => 'Thuộc tính bảng', + 'table_properties_title' => 'Thuộc tính bảng', + 'delete_table' => 'Xóa bảng', + 'insert_row_before' => 'Chèn thêm hàng ở trên', + 'insert_row_after' => 'Chèn thêm hàng ở dưới', + 'delete_row' => 'Xóa hàng', + 'insert_column_before' => 'Chèn cột mới vào bên trái', + 'insert_column_after' => 'Chèn cột mới vào bên phải', + 'delete_column' => 'Xóa cột', + 'table_cell' => 'Ô', + 'table_row' => 'Hàng', + 'table_column' => 'Cột', + 'cell_properties' => 'Đặt thuộc tính ô', + 'cell_properties_title' => 'Đặt thuộc tính ô', + 'cell_type' => 'Kiểu ô', + 'cell_type_cell' => 'Ô', + 'cell_scope' => 'Phạm vi', + 'cell_type_header' => 'Ô tiêu đề', + 'merge_cells' => 'Sát nhập các ô', + 'split_cell' => 'Chia tách ô', + 'table_row_group' => 'Nhóm hàng', + 'table_column_group' => 'Nhóm cột', + 'horizontal_align' => 'Căn chỉnh theo chiều ngang', + 'vertical_align' => 'Căn chỉnh theo chiều dọc', + 'border_width' => 'Chiều rộng viền', + 'border_style' => 'Kiểu đường viền', + 'border_color' => 'Màu viền', + 'row_properties' => 'Đặt thuộc tính hàng', + 'row_properties_title' => 'Đặt thuộc tính hàng', + 'cut_row' => 'Tách cột', + 'copy_row' => 'Sao chép cột', + 'paste_row_before' => 'Dán cột vào bên trái', + 'paste_row_after' => 'Dán cột vào bên phải', + 'row_type' => 'Kiểu hàng', + 'row_type_header' => 'Tiêu đề', + 'row_type_body' => 'Nội dung', 'row_type_footer' => 'Cuối trang', 'alignment' => 'Canh lề', 'cut_column' => 'Cắt cột', @@ -134,39 +134,39 @@ 'cell_border_inset' => 'Inset', 'cell_border_outset' => 'Outset', 'cell_border_none' => 'None', - 'cell_border_hidden' => 'Hidden', + 'cell_border_hidden' => 'Ẩn', // Images, links, details/summary & embed - 'source' => 'Source', - 'alt_desc' => 'Alternative description', + 'source' => 'Nguồn', + 'alt_desc' => 'Mô tả thay thế', 'embed' => 'Mã nhúng', - 'paste_embed' => 'Paste your embed code below:', + 'paste_embed' => 'Dán mã đính kèm của bạn vào bên dưới:', 'url' => 'Đường dẫn', 'text_to_display' => 'Các văn bản hiển thị', - 'title' => 'Title', - 'open_link' => 'Open link', - 'open_link_in' => 'Open link in...', - 'open_link_current' => 'Current window', - 'open_link_new' => 'New window', - 'remove_link' => 'Remove link', + 'title' => 'Tiêu đề', + 'open_link' => 'Mở liên kết', + 'open_link_in' => 'Mở liên kết trong...', + 'open_link_current' => 'Cửa sổ hiện tại', + 'open_link_new' => 'Cửa sổ mới', + 'remove_link' => 'Loại bỏ liên kết', 'insert_collapsible' => 'Insert collapsible block', 'collapsible_unwrap' => 'Unwrap', - 'edit_label' => 'Edit label', + 'edit_label' => 'Chỉnh sửa nhãn', '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 the MIT license.', - 'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.', - 'save_continue' => 'Save Page & Continue', + 'about' => 'Giới thiệu về trình soạn thảo', + 'about_title' => 'Giới thiệu về trình soạn thảo WYSIWYG', + 'editor_license' => 'Giáy phép & Bản quyền của trình soạn thảo', + 'editor_tiny_license' => 'Trình soạn thảo này được xây dựng bằng các sử dụng :tinyLink theo giấy phép MIT.', + 'editor_tiny_license_link' => 'Chi tiết về bản quyền và giấy phép của TinyMCE có thể được tìm thấy tại đây.', + 'save_continue' => 'Lưu trang & Tiếp tục', 'callouts_cycle' => '(Keep pressing to toggle through types)', - 'link_selector' => 'Link to content', - 'shortcuts' => 'Shortcuts', - 'shortcut' => 'Shortcut', + 'link_selector' => 'Liên kết đến nội dung', + 'shortcuts' => 'Phím tắt', + 'shortcut' => 'Phím tắt', 'shortcuts_intro' => 'The following shortcuts are available in the editor:', 'windows_linux' => '(Windows/Linux)', 'mac' => '(Mac)', diff --git a/lang/zh_CN/entities.php b/lang/zh_CN/entities.php index 66c4a215882..46710674278 100644 --- a/lang/zh_CN/entities.php +++ b/lang/zh_CN/entities.php @@ -313,10 +313,10 @@ 'attachments_explain_instant_save' => '这里的更改将立即保存。', 'attachments_upload' => '上传文件', 'attachments_link' => '附加链接', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', + 'attachments_upload_drop' => '或者,您可以拖放一个文件到此处上传它作为附件。', 'attachments_set_link' => '设置链接', 'attachments_delete' => '您确定要删除此附件吗?', - 'attachments_dropzone' => 'Drop files here to upload', + 'attachments_dropzone' => '将文件拖放在此处上传', 'attachments_no_files' => '尚未上传文件', 'attachments_explain_link' => '如果您不想上传文件,则可以附加链接,这可以是指向其他页面的链接,也可以是指向云端文件的链接。', 'attachments_link_name' => '链接名', diff --git a/lang/zh_CN/errors.php b/lang/zh_CN/errors.php index 7ca1a9a087f..c2739036302 100644 --- a/lang/zh_CN/errors.php +++ b/lang/zh_CN/errors.php @@ -53,7 +53,7 @@ // Attachments 'attachment_not_found' => '找不到附件', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_upload_error' => '上传附件时出错', // Pages 'page_draft_autosave_fail' => '无法保存草稿,确保您在保存页面之前已经连接到互联网', From 9f1a6947ab0b462217cacb87b1226c757d133dcb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 8 May 2023 15:16:30 +0100 Subject: [PATCH 0016/1295] Updated system CLI - Fixed wrong env details being used on restore. - Updated update-url on restore actually work. - Added better support for symlinked locations. - Added warning against updating in docker-like (non git controlled) environments. --- bookstack-system-cli | Bin 354449 -> 355466 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bookstack-system-cli b/bookstack-system-cli index ef82d04d66099a5e606196455c62eccf05bb8cc5..dbb16470a6bd746918037d14ae4aacb4d418e5b5 100755 GIT binary patch delta 23163 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 Date: Mon, 8 May 2023 16:04:02 +0100 Subject: [PATCH 0017/1295] Updated translator attribution before release v23.05.1 --- .github/translators.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/translators.txt b/.github/translators.txt index a448c4a0e44..5d4752c9417 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -327,3 +327,5 @@ H.-H. Peng (Hsins) :: Chinese Traditional Mosi Wang (mosiwang) :: Chinese Traditional 骆言 (LawssssCat) :: Chinese Simplified Stickers Gaming Shøw (StickerSGSHOW) :: French +Le Van Chinh (Chino) (lvanchinh86) :: Vietnamese +Rubens nagios (rubenix) :: Catalan From 295cd0160525125bbd7756d7ad07392ae7201cb8 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 17 May 2023 17:56:55 +0100 Subject: [PATCH 0018/1295] Played around with a new app structure --- .../Controllers}/ConfirmEmailController.php | 8 +- .../Controllers}/ForgotPasswordController.php | 4 +- .../Controllers}/HandlesPartialLogins.php | 6 +- .../Controllers}/LoginController.php | 6 +- .../Controllers}/MfaBackupCodesController.php | 12 +- .../Controllers}/MfaController.php | 6 +- .../Controllers}/MfaTotpController.php | 16 +- .../Controllers}/OidcController.php | 6 +- .../Controllers}/RegisterController.php | 8 +- .../Controllers}/ResetPasswordController.php | 8 +- .../Controllers}/Saml2Controller.php | 4 +- .../Controllers}/SocialController.php | 8 +- .../Controllers}/ThrottlesLogins.php | 2 +- .../Controllers}/UserInviteController.php | 6 +- .../Access/EmailConfirmationService.php | 4 +- .../Access/ExternalBaseUserProvider.php | 2 +- app/{Auth => }/Access/GroupSyncService.php | 6 +- .../Guards/AsyncExternalBaseSessionGuard.php | 2 +- .../Guards/ExternalBaseSessionGuard.php | 4 +- .../Access/Guards/LdapSessionGuard.php | 8 +- app/{Auth => }/Access/Ldap.php | 2 +- app/{Auth => }/Access/LdapService.php | 4 +- app/{Auth => }/Access/LoginService.php | 8 +- .../Access/Mfa/BackupCodeService.php | 2 +- app/{Auth => }/Access/Mfa/MfaSession.php | 4 +- app/{Auth => }/Access/Mfa/MfaValue.php | 4 +- app/{Auth => }/Access/Mfa/TotpService.php | 4 +- .../Access/Mfa/TotpValidationRule.php | 2 +- .../Access/Oidc/OidcAccessToken.php | 2 +- app/{Auth => }/Access/Oidc/OidcException.php | 2 +- app/{Auth => }/Access/Oidc/OidcIdToken.php | 2 +- .../Access/Oidc/OidcInvalidKeyException.php | 2 +- .../Access/Oidc/OidcInvalidTokenException.php | 2 +- .../Oidc/OidcIssuerDiscoveryException.php | 2 +- .../Access/Oidc/OidcJwtSigningKey.php | 2 +- .../Access/Oidc/OidcOAuthProvider.php | 2 +- .../Access/Oidc/OidcProviderSettings.php | 2 +- app/{Auth => }/Access/Oidc/OidcService.php | 10 +- app/{Auth => }/Access/RegistrationService.php | 9 +- app/{Auth => }/Access/Saml2Service.php | 4 +- app/{Auth => Access}/SocialAccount.php | 7 +- app/{Auth => }/Access/SocialAuthService.php | 6 +- app/{Auth => }/Access/UserInviteService.php | 4 +- app/{Auth => }/Access/UserTokenService.php | 4 +- app/{Actions => Activity}/ActivityQueries.php | 7 +- app/{Actions => Activity}/ActivityType.php | 2 +- app/{Actions => Activity}/CommentRepo.php | 3 +- .../Controllers/AuditLogController.php | 8 +- .../Controllers/CommentController.php | 5 +- .../Controllers/FavouriteController.php | 7 +- .../Controllers/TagController.php | 5 +- .../Controllers/WebhookController.php | 9 +- .../DispatchWebhookJob.php | 8 +- app/{Actions => Activity/Models}/Activity.php | 8 +- app/{Actions => Activity/Models}/Comment.php | 6 +- .../Models}/Favouritable.php | 2 +- .../Models}/Favourite.php | 6 +- .../Models}/Loggable.php | 2 +- app/{Actions => Activity/Models}/Tag.php | 6 +- app/{Actions => Activity/Models}/View.php | 7 +- .../Models}/Viewable.php | 2 +- app/{Actions => Activity/Models}/Webhook.php | 3 +- .../Models}/WebhookTrackedEvent.php | 2 +- .../Queries/WebhooksAllPaginatedAndSorted.php | 4 +- app/{Actions => Activity}/TagRepo.php | 5 +- .../Tools}/ActivityLogger.php | 6 +- .../Tools}/IpFormatter.php | 2 +- .../Tools}/TagClassGenerator.php | 4 +- .../Tools}/WebhookFormatter.php | 10 +- .../Api/ApiDocsController.php | 4 +- app/Api/ApiDocsGenerator.php | 2 +- app/Api/ApiToken.php | 4 +- app/Api/ApiTokenGuard.php | 2 +- .../UserApiTokenController.php | 8 +- app/{ => App}/Application.php | 2 +- app/{ => App}/Model.php | 2 +- .../Providers/AppServiceProvider.php | 6 +- .../Providers/AuthServiceProvider.php | 14 +- .../Providers/EventServiceProvider.php | 2 +- .../Providers/RouteServiceProvider.php | 2 +- .../Providers/ThemeServiceProvider.php | 2 +- .../Providers/TranslationServiceProvider.php | 2 +- .../ValidationRuleServiceProvider.php | 2 +- .../Providers/ViewTweaksServiceProvider.php | 2 +- app/{Interfaces => App}/Sluggable.php | 2 +- app/{ => App}/helpers.php | 6 +- app/Config/app.php | 16 +- app/Config/auth.php | 4 +- app/Console/Commands/ClearActivity.php | 2 +- app/Console/Commands/ClearViews.php | 2 +- app/Console/Commands/CreateAdmin.php | 4 +- app/Console/Commands/DeleteUsers.php | 4 +- .../Commands/RegenerateCommentContent.php | 4 +- .../Commands/RegeneratePermissions.php | 2 +- app/Console/Commands/ResetMfa.php | 2 +- .../Controllers}/BookApiController.php | 3 +- .../Controllers/BookController.php | 9 +- .../Controllers}/BookExportApiController.php | 3 +- .../Controllers/BookExportController.php | 3 +- .../Controllers/BookSortController.php | 5 +- .../Controllers}/BookshelfApiController.php | 3 +- .../Controllers/BookshelfController.php | 7 +- .../Controllers}/ChapterApiController.php | 3 +- .../Controllers/ChapterController.php | 5 +- .../ChapterExportApiController.php | 3 +- .../Controllers/ChapterExportController.php | 3 +- .../Controllers}/PageApiController.php | 3 +- .../Controllers/PageController.php | 5 +- .../Controllers}/PageExportApiController.php | 3 +- .../Controllers/PageExportController.php | 3 +- .../Controllers/PageRevisionController.php | 5 +- .../Controllers/PageTemplateController.php | 3 +- .../Controllers}/RecycleBinApiController.php | 3 +- .../Controllers/RecycleBinController.php | 5 +- .../Models}/Deletable.php | 2 +- app/Entities/Models/Deletion.php | 5 +- app/Entities/Models/Entity.php | 33 ++- app/Entities/Models/Page.php | 2 +- app/Entities/Models/PageRevision.php | 6 +- app/Entities/Queries/EntityQuery.php | 2 +- app/Entities/Queries/Popular.php | 2 +- app/Entities/Queries/RecentlyViewed.php | 2 +- app/Entities/Queries/TopFavourites.php | 2 +- app/Entities/Repos/BaseRepo.php | 2 +- app/Entities/Repos/BookRepo.php | 4 +- app/Entities/Repos/BookshelfRepo.php | 2 +- app/Entities/Repos/ChapterRepo.php | 2 +- app/Entities/Repos/DeletionRepo.php | 2 +- app/Entities/Repos/PageRepo.php | 2 +- app/Entities/Tools/Cloner.php | 2 +- app/Entities/Tools/HierarchyTransformer.php | 2 +- app/Entities/Tools/PermissionsUpdater.php | 8 +- app/Entities/Tools/SlugGenerator.php | 4 +- .../StoppedAuthenticationException.php | 4 +- app/Facades/Activity.php | 2 +- .../Controllers/{Api => }/ApiController.php | 3 +- app/Http/Controllers/Controller.php | 4 +- app/Http/Controllers/HomeController.php | 2 +- .../Middleware/AuthenticatedOrPendingMfa.php | 4 +- app/Http/Middleware/CheckEmailConfirmed.php | 4 +- app/Http/Middleware/Localization.php | 2 +- .../Middleware/RedirectIfAuthenticated.php | 2 +- app/Http/Requests/Request.php | 10 - app/Notifications/UserInvite.php | 2 +- .../ContentPermissionApiController.php | 3 +- .../Permissions/EntityPermissionEvaluator.php | 5 +- .../Permissions/JointPermissionBuilder.php | 5 +- .../MassEntityPermissionEvaluator.php | 4 +- .../Models}/EntityPermission.php | 6 +- .../Models}/JointPermission.php | 6 +- .../Models}/RolePermission.php | 6 +- .../Permissions/PermissionApplicator.php | 13 +- .../Permissions/PermissionFormData.php | 5 +- .../Permissions/PermissionStatus.php | 2 +- .../PermissionsController.php | 8 +- .../Permissions/PermissionsRepo.php | 7 +- .../Permissions/SimpleEntityData.php | 2 +- app/References/CrossLinkParser.php | 2 +- .../ModelResolvers/BookLinkModelResolver.php | 2 +- .../BookshelfLinkModelResolver.php | 2 +- .../ChapterLinkModelResolver.php | 2 +- .../ModelResolvers/CrossLinkModelResolver.php | 2 +- .../ModelResolvers/PageLinkModelResolver.php | 2 +- .../PagePermalinkModelResolver.php | 2 +- app/References/Reference.php | 2 +- .../ReferenceController.php | 4 +- app/References/ReferenceFetcher.php | 2 +- .../Api => Search}/SearchApiController.php | 6 +- .../SearchController.php | 6 +- app/Search/SearchIndex.php | 2 +- app/Search/SearchResultsFormatter.php | 2 +- app/Search/SearchRunner.php | 4 +- app/Search/SearchTerm.php | 2 +- .../MaintenanceController.php | 5 +- app/Settings/Setting.php | 2 +- .../SettingController.php | 9 +- app/Settings/SettingService.php | 2 +- .../StatusController.php | 3 +- app/Theming/ThemeEvents.php | 14 +- app/Theming/ThemeService.php | 2 +- app/{Util => Translation}/LanguageManager.php | 2 +- app/Uploads/Attachment.php | 10 +- .../Controllers}/AttachmentApiController.php | 3 +- .../Controllers/AttachmentController.php | 3 +- .../Controllers}/DrawioImageController.php | 2 +- .../Controllers}/GalleryImageController.php | 2 +- .../Controllers}/ImageController.php | 2 +- .../ImageGalleryApiController.php | 3 +- app/Uploads/Image.php | 8 +- app/Uploads/ImageRepo.php | 2 +- app/Uploads/UserAvatars.php | 2 +- .../Controllers}/RoleApiController.php | 7 +- .../Controllers/RoleController.php | 10 +- .../Controllers}/UserApiController.php | 7 +- .../Controllers/UserController.php | 11 +- .../Controllers/UserPreferencesController.php | 5 +- .../Controllers/UserProfileController.php | 11 +- .../Controllers/UserSearchController.php | 5 +- .../Models}/HasCreatorAndUpdater.php | 3 +- app/{Traits => Users/Models}/HasOwner.php | 3 +- app/{Auth => Users/Models}/Role.php | 12 +- app/{Auth => Users/Models}/User.php | 13 +- .../Queries/RolesAllPaginatedAndSorted.php | 4 +- .../Queries/UserContentCounts.php | 4 +- .../Queries/UserRecentlyCreatedContent.php | 4 +- .../Queries/UsersAllPaginatedAndSorted.php | 4 +- app/{Auth => Users}/UserRepo.php | 8 +- bootstrap/app.php | 2 +- composer.json | 2 +- database/factories/Actions/CommentFactory.php | 2 +- database/factories/Actions/TagFactory.php | 2 +- database/factories/Actions/WebhookFactory.php | 2 +- .../Actions/WebhookTrackedEventFactory.php | 4 +- database/factories/Auth/RoleFactory.php | 2 +- database/factories/Auth/UserFactory.php | 2 +- .../factories/Uploads/AttachmentFactory.php | 2 +- ...625_refactor_joint_permissions_storage.php | 2 +- database/seeders/DummyContentSeeder.php | 8 +- database/seeders/LargeContentSeeder.php | 6 +- .../views/entities/body-tag-classes.blade.php | 2 +- .../views/form/entity-permissions.blade.php | 5 +- resources/views/settings/audit.blade.php | 214 +++++++++--------- .../views/settings/registration.blade.php | 16 +- .../settings/webhooks/parts/form.blade.php | 2 +- resources/views/tags/index.blade.php | 2 +- routes/api.php | 30 +-- routes/web.php | 153 +++++++------ tests/Actions/AuditLogTest.php | 8 +- tests/Actions/WebhookCallTest.php | 10 +- tests/Actions/WebhookFormatTesting.php | 6 +- tests/Actions/WebhookManagementTest.php | 4 +- tests/Api/ApiAuthTest.php | 6 +- tests/Api/RolesApiTest.php | 6 +- tests/Api/TestsApi.php | 2 +- tests/Api/UsersApiTest.php | 6 +- tests/Auth/AuthTest.php | 2 +- tests/Auth/GroupSyncServiceTest.php | 6 +- tests/Auth/LdapTest.php | 8 +- tests/Auth/MfaConfigurationTest.php | 8 +- tests/Auth/MfaVerificationTest.php | 10 +- tests/Auth/OidcTest.php | 6 +- tests/Auth/RegistrationTest.php | 4 +- tests/Auth/ResetPasswordTest.php | 2 +- tests/Auth/Saml2Test.php | 4 +- tests/Auth/SocialAuthTest.php | 6 +- tests/Auth/UserInviteTest.php | 4 +- tests/Commands/ClearActivityCommandTest.php | 2 +- tests/Commands/CreateAdminCommandTest.php | 2 +- .../RegenerateCommentContentCommandTest.php | 2 +- .../RegeneratePermissionsCommandTest.php | 3 +- tests/Commands/ResetMfaCommandTest.php | 4 +- tests/DebugViewTest.php | 2 +- tests/Entity/BookShelfTest.php | 2 +- tests/Entity/CommentTest.php | 2 +- tests/Entity/ConvertTest.php | 4 +- tests/Entity/EntityAccessTest.php | 2 +- tests/Entity/EntitySearchTest.php | 2 +- tests/Entity/ExportTest.php | 1 - tests/Entity/PageRevisionTest.php | 2 +- tests/Entity/TagTest.php | 2 +- tests/FavouriteTest.php | 4 +- tests/Helpers/EntityProvider.php | 2 +- tests/Helpers/PermissionsProvider.php | 8 +- tests/Helpers/UserRoleProvider.php | 6 +- tests/HomepageTest.php | 4 +- tests/Permissions/EntityOwnerChangeTest.php | 2 +- tests/Permissions/EntityPermissionsTest.php | 4 +- tests/Permissions/RolesTest.php | 8 +- .../Scenarios/PermissionScenarioTestCase.php | 2 +- tests/PublicActionTest.php | 6 +- tests/References/ReferencesTest.php | 2 +- tests/Settings/RegenerateReferencesTest.php | 2 +- tests/ThemeTest.php | 8 +- tests/Unit/IpFormatterTest.php | 2 +- tests/Unit/OidcIdTokenTest.php | 4 +- tests/Uploads/AvatarTest.php | 2 +- tests/User/UserApiTokenTest.php | 2 +- tests/User/UserManagementTest.php | 8 +- tests/User/UserProfileTest.php | 4 +- tests/User/UserSearchTest.php | 2 +- 280 files changed, 844 insertions(+), 794 deletions(-) rename app/{Http/Controllers/Auth => Access/Controllers}/ConfirmEmailController.php (95%) rename app/{Http/Controllers/Auth => Access/Controllers}/ForgotPasswordController.php (96%) rename app/{Http/Controllers/Auth => Access/Controllers}/HandlesPartialLogins.php (81%) rename app/{Http/Controllers/Auth => Access/Controllers}/LoginController.php (98%) rename app/{Http/Controllers/Auth => Access/Controllers}/MfaBackupCodesController.php (92%) rename app/{Http/Controllers/Auth => Access/Controllers}/MfaController.php (94%) rename app/{Http/Controllers/Auth => Access/Controllers}/MfaTotpController.php (90%) rename app/{Http/Controllers/Auth => Access/Controllers}/OidcController.php (92%) rename app/{Http/Controllers/Auth => Access/Controllers}/RegisterController.php (93%) rename app/{Http/Controllers/Auth => Access/Controllers}/ResetPasswordController.php (95%) rename app/{Http/Controllers/Auth => Access/Controllers}/Saml2Controller.php (97%) rename app/{Http/Controllers/Auth => Access/Controllers}/SocialController.php (96%) rename app/{Http/Controllers/Auth => Access/Controllers}/ThrottlesLogins.php (98%) rename app/{Http/Controllers/Auth => Access/Controllers}/UserInviteController.php (95%) rename app/{Auth => }/Access/EmailConfirmationService.php (94%) rename app/{Auth => }/Access/ExternalBaseUserProvider.php (98%) rename app/{Auth => }/Access/GroupSyncService.php (96%) rename app/{Auth => }/Access/Guards/AsyncExternalBaseSessionGuard.php (95%) rename app/{Auth => }/Access/Guards/ExternalBaseSessionGuard.php (98%) rename app/{Auth => }/Access/Guards/LdapSessionGuard.php (96%) rename app/{Auth => }/Access/Ldap.php (99%) rename app/{Auth => }/Access/LdapService.php (99%) rename app/{Auth => }/Access/LoginService.php (97%) rename app/{Auth => }/Access/Mfa/BackupCodeService.php (97%) rename app/{Auth => }/Access/Mfa/MfaSession.php (95%) rename app/{Auth => }/Access/Mfa/MfaValue.php (96%) rename app/{Auth => }/Access/Mfa/TotpService.php (96%) rename app/{Auth => }/Access/Mfa/TotpValidationRule.php (95%) rename app/{Auth => }/Access/Oidc/OidcAccessToken.php (97%) rename app/{Auth => }/Access/Oidc/OidcException.php (63%) rename app/{Auth => }/Access/Oidc/OidcIdToken.php (99%) rename app/{Auth => }/Access/Oidc/OidcInvalidKeyException.php (61%) rename app/{Auth => }/Access/Oidc/OidcInvalidTokenException.php (67%) rename app/{Auth => }/Access/Oidc/OidcIssuerDiscoveryException.php (68%) rename app/{Auth => }/Access/Oidc/OidcJwtSigningKey.php (99%) rename app/{Auth => }/Access/Oidc/OidcOAuthProvider.php (99%) rename app/{Auth => }/Access/Oidc/OidcProviderSettings.php (99%) rename app/{Auth => }/Access/Oidc/OidcService.php (97%) rename app/{Auth => }/Access/RegistrationService.php (96%) rename app/{Auth => }/Access/Saml2Service.php (99%) rename app/{Auth => Access}/SocialAccount.php (79%) rename app/{Auth => }/Access/SocialAuthService.php (99%) rename app/{Auth => }/Access/UserInviteService.php (89%) rename app/{Auth => }/Access/UserTokenService.php (97%) rename app/{Actions => Activity}/ActivityQueries.php (95%) rename app/{Actions => Activity}/ActivityType.php (98%) rename app/{Actions => Activity}/CommentRepo.php (97%) rename app/{Http => Activity}/Controllers/AuditLogController.php (92%) rename app/{Http => Activity}/Controllers/CommentController.php (94%) rename app/{Http => Activity}/Controllers/FavouriteController.php (94%) rename app/{Http => Activity}/Controllers/TagController.php (93%) rename app/{Http => Activity}/Controllers/WebhookController.php (94%) rename app/{Actions => Activity}/DispatchWebhookJob.php (92%) rename app/{Actions => Activity/Models}/Activity.php (92%) rename app/{Actions => Activity/Models}/Comment.php (91%) rename app/{Interfaces => Activity/Models}/Favouritable.php (84%) rename app/{Actions => Activity/Models}/Favourite.php (84%) rename app/{Interfaces => Activity/Models}/Loggable.php (79%) rename app/{Actions => Activity/Models}/Tag.php (92%) rename app/{Actions => Activity/Models}/View.php (92%) rename app/{Interfaces => Activity/Models}/Viewable.php (84%) rename app/{Actions => Activity/Models}/Webhook.php (97%) rename app/{Actions => Activity/Models}/WebhookTrackedEvent.php (88%) rename app/{Actions => Activity}/Queries/WebhooksAllPaginatedAndSorted.php (91%) rename app/{Actions => Activity}/TagRepo.php (97%) rename app/{Actions => Activity/Tools}/ActivityLogger.php (95%) rename app/{Actions => Activity/Tools}/IpFormatter.php (98%) rename app/{Actions => Activity/Tools}/TagClassGenerator.php (93%) rename app/{Actions => Activity/Tools}/WebhookFormatter.php (94%) rename app/{Http/Controllers => }/Api/ApiDocsController.php (88%) rename app/{Http/Controllers => Api}/UserApiTokenController.php (97%) rename app/{ => App}/Application.php (95%) rename app/{ => App}/Model.php (94%) rename app/{ => App}/Providers/AppServiceProvider.php (94%) rename app/{ => App}/Providers/AuthServiceProvider.php (84%) rename app/{ => App}/Providers/EventServiceProvider.php (97%) rename app/{ => App}/Providers/RouteServiceProvider.php (98%) rename app/{ => App}/Providers/ThemeServiceProvider.php (95%) rename app/{ => App}/Providers/TranslationServiceProvider.php (97%) rename app/{ => App}/Providers/ValidationRuleServiceProvider.php (96%) rename app/{ => App}/Providers/ViewTweaksServiceProvider.php (95%) rename app/{Interfaces => App}/Sluggable.php (89%) rename app/{ => App}/helpers.php (97%) rename app/{Http/Controllers/Api => Entities/Controllers}/BookApiController.php (97%) rename app/{Http => Entities}/Controllers/BookController.php (97%) rename app/{Http/Controllers/Api => Entities/Controllers}/BookExportApiController.php (95%) rename app/{Http => Entities}/Controllers/BookExportController.php (95%) rename app/{Http => Entities}/Controllers/BookSortController.php (94%) rename app/{Http/Controllers/Api => Entities/Controllers}/BookshelfApiController.php (97%) rename app/{Http => Entities}/Controllers/BookshelfController.php (97%) rename app/{Http/Controllers/Api => Entities/Controllers}/ChapterApiController.php (97%) rename app/{Http => Entities}/Controllers/ChapterController.php (98%) rename app/{Http/Controllers/Api => Entities/Controllers}/ChapterExportApiController.php (95%) rename app/{Http => Entities}/Controllers/ChapterExportController.php (96%) rename app/{Http/Controllers/Api => Entities/Controllers}/PageApiController.php (98%) rename app/{Http => Entities}/Controllers/PageController.php (99%) rename app/{Http/Controllers/Api => Entities/Controllers}/PageExportApiController.php (95%) rename app/{Http => Entities}/Controllers/PageExportController.php (96%) rename app/{Http => Entities}/Controllers/PageRevisionController.php (97%) rename app/{Http => Entities}/Controllers/PageTemplateController.php (93%) rename app/{Http/Controllers/Api => Entities/Controllers}/RecycleBinApiController.php (97%) rename app/{Http => Entities}/Controllers/RecycleBinController.php (96%) rename app/{Interfaces => Entities/Models}/Deletable.php (87%) rename app/Http/Controllers/{Api => }/ApiController.php (93%) delete mode 100644 app/Http/Requests/Request.php rename app/{Http/Controllers/Api => Permissions}/ContentPermissionApiController.php (98%) rename app/{Auth => }/Permissions/EntityPermissionEvaluator.php (97%) rename app/{Auth => }/Permissions/JointPermissionBuilder.php (98%) rename app/{Auth => }/Permissions/MassEntityPermissionEvaluator.php (96%) rename app/{Auth/Permissions => Permissions/Models}/EntityPermission.php (90%) rename app/{Auth/Permissions => Permissions/Models}/JointPermission.php (85%) rename app/{Auth/Permissions => Permissions/Models}/RolePermission.php (86%) rename app/{Auth => }/Permissions/PermissionApplicator.php (96%) rename app/{Auth => }/Permissions/PermissionFormData.php (93%) rename app/{Auth => }/Permissions/PermissionStatus.php (80%) rename app/{Http/Controllers => Permissions}/PermissionsController.php (97%) rename app/{Auth => }/Permissions/PermissionsRepo.php (96%) rename app/{Auth => }/Permissions/SimpleEntityData.php (94%) rename app/{Http/Controllers => References}/ReferenceController.php (96%) rename app/{Http/Controllers/Api => Search}/SearchApiController.php (93%) rename app/{Http/Controllers => Search}/SearchController.php (96%) rename app/{Http/Controllers => Settings}/MaintenanceController.php (96%) rename app/{Http/Controllers => Settings}/SettingController.php (91%) rename app/{Http/Controllers => Settings}/StatusController.php (94%) rename app/{Util => Translation}/LanguageManager.php (99%) rename app/{Http/Controllers/Api => Uploads/Controllers}/AttachmentApiController.php (98%) rename app/{Http => Uploads}/Controllers/AttachmentController.php (99%) rename app/{Http/Controllers/Images => Uploads/Controllers}/DrawioImageController.php (98%) rename app/{Http/Controllers/Images => Uploads/Controllers}/GalleryImageController.php (97%) rename app/{Http/Controllers/Images => Uploads/Controllers}/ImageController.php (98%) rename app/{Http/Controllers/Api => Uploads/Controllers}/ImageGalleryApiController.php (98%) rename app/{Http/Controllers/Api => Users/Controllers}/RoleApiController.php (96%) rename app/{Http => Users}/Controllers/RoleController.php (95%) rename app/{Http/Controllers/Api => Users/Controllers}/UserApiController.php (97%) rename app/{Http => Users}/Controllers/UserController.php (96%) rename app/{Http => Users}/Controllers/UserPreferencesController.php (97%) rename app/{Http => Users}/Controllers/UserProfileController.php (74%) rename app/{Http => Users}/Controllers/UserSearchController.php (88%) rename app/{Traits => Users/Models}/HasCreatorAndUpdater.php (90%) rename app/{Traits => Users/Models}/HasOwner.php (84%) rename app/{Auth => Users/Models}/Role.php (92%) rename app/{Auth => Users/Models}/User.php (97%) rename app/{Auth => Users}/Queries/RolesAllPaginatedAndSorted.php (93%) rename app/{Auth => Users}/Queries/UserContentCounts.php (91%) rename app/{Auth => Users}/Queries/UserRecentlyCreatedContent.php (93%) rename app/{Auth => Users}/Queries/UsersAllPaginatedAndSorted.php (94%) rename app/{Auth => Users}/UserRepo.php (97%) diff --git a/app/Http/Controllers/Auth/ConfirmEmailController.php b/app/Access/Controllers/ConfirmEmailController.php similarity index 95% rename from app/Http/Controllers/Auth/ConfirmEmailController.php rename to app/Access/Controllers/ConfirmEmailController.php index fdde8e70c1b..3fda0586e0c 100644 --- a/app/Http/Controllers/Auth/ConfirmEmailController.php +++ b/app/Access/Controllers/ConfirmEmailController.php @@ -1,14 +1,14 @@ [ 'users' => [ 'driver' => 'eloquent', - 'model' => \BookStack\Auth\User::class, + 'model' => \BookStack\Users\Models\User::class, ], 'external' => [ 'driver' => 'external-users', - 'model' => \BookStack\Auth\User::class, + 'model' => \BookStack\Users\Models\User::class, ], // 'users' => [ diff --git a/app/Console/Commands/ClearActivity.php b/app/Console/Commands/ClearActivity.php index 932ba7ddd19..5ccf6e972b5 100644 --- a/app/Console/Commands/ClearActivity.php +++ b/app/Console/Commands/ClearActivity.php @@ -2,7 +2,7 @@ namespace BookStack\Console\Commands; -use BookStack\Actions\Activity; +use BookStack\Activity\Models\Activity; use Illuminate\Console\Command; class ClearActivity extends Command diff --git a/app/Console/Commands/ClearViews.php b/app/Console/Commands/ClearViews.php index 0fc6c019566..c76b78d231d 100644 --- a/app/Console/Commands/ClearViews.php +++ b/app/Console/Commands/ClearViews.php @@ -2,7 +2,7 @@ namespace BookStack\Console\Commands; -use BookStack\Actions\View; +use BookStack\Activity\Models\View; use Illuminate\Console\Command; class ClearViews extends Command diff --git a/app/Console/Commands/CreateAdmin.php b/app/Console/Commands/CreateAdmin.php index e4660314d6e..377207ed781 100644 --- a/app/Console/Commands/CreateAdmin.php +++ b/app/Console/Commands/CreateAdmin.php @@ -2,9 +2,9 @@ namespace BookStack\Console\Commands; -use BookStack\Auth\Role; -use BookStack\Auth\UserRepo; use BookStack\Exceptions\NotFoundException; +use BookStack\Users\Models\Role; +use BookStack\Users\UserRepo; use Illuminate\Console\Command; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; diff --git a/app/Console/Commands/DeleteUsers.php b/app/Console/Commands/DeleteUsers.php index bc7263c7742..c16a5d9a694 100644 --- a/app/Console/Commands/DeleteUsers.php +++ b/app/Console/Commands/DeleteUsers.php @@ -2,8 +2,8 @@ namespace BookStack\Console\Commands; -use BookStack\Auth\User; -use BookStack\Auth\UserRepo; +use BookStack\Users\Models\User; +use BookStack\Users\UserRepo; use Illuminate\Console\Command; class DeleteUsers extends Command diff --git a/app/Console/Commands/RegenerateCommentContent.php b/app/Console/Commands/RegenerateCommentContent.php index 3e25dc8a395..3052559e305 100644 --- a/app/Console/Commands/RegenerateCommentContent.php +++ b/app/Console/Commands/RegenerateCommentContent.php @@ -2,8 +2,8 @@ namespace BookStack\Console\Commands; -use BookStack\Actions\Comment; -use BookStack\Actions\CommentRepo; +use BookStack\Activity\CommentRepo; +use BookStack\Activity\Models\Comment; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; diff --git a/app/Console/Commands/RegeneratePermissions.php b/app/Console/Commands/RegeneratePermissions.php index efb3535d648..27dd8ea6530 100644 --- a/app/Console/Commands/RegeneratePermissions.php +++ b/app/Console/Commands/RegeneratePermissions.php @@ -2,7 +2,7 @@ namespace BookStack\Console\Commands; -use BookStack\Auth\Permissions\JointPermissionBuilder; +use BookStack\Permissions\JointPermissionBuilder; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; diff --git a/app/Console/Commands/ResetMfa.php b/app/Console/Commands/ResetMfa.php index 9074a4a46f2..4b181309902 100644 --- a/app/Console/Commands/ResetMfa.php +++ b/app/Console/Commands/ResetMfa.php @@ -2,7 +2,7 @@ namespace BookStack\Console\Commands; -use BookStack\Auth\User; +use BookStack\Users\Models\User; use Illuminate\Console\Command; class ResetMfa extends Command diff --git a/app/Http/Controllers/Api/BookApiController.php b/app/Entities/Controllers/BookApiController.php similarity index 97% rename from app/Http/Controllers/Api/BookApiController.php rename to app/Entities/Controllers/BookApiController.php index d57b48a43fc..5abac12fbb3 100644 --- a/app/Http/Controllers/Api/BookApiController.php +++ b/app/Entities/Controllers/BookApiController.php @@ -1,6 +1,6 @@ tags->all()))->generateAsString() . ' ')) \ No newline at end of file +@push('body-class', e((new \BookStack\Activity\Tools\TagClassGenerator($entity->tags->all()))->generateAsString() . ' ')) \ No newline at end of file diff --git a/resources/views/form/entity-permissions.blade.php b/resources/views/form/entity-permissions.blade.php index 9bf309fb802..8eddac8dea0 100644 --- a/resources/views/form/entity-permissions.blade.php +++ b/resources/views/form/entity-permissions.blade.php @@ -1,5 +1,5 @@

- + - @endforeach - - - - @if(!empty($filters['event'])) - - @endif - - @foreach(['date_from', 'date_to'] as $filterKey) -
- - +
+ + @include('settings.parts.navbar', ['selected' => 'audit']) + +
+

{{ trans('settings.audit') }}

+

{{ trans('settings.audit_desc') }}

+ + + + @foreach(request()->only(['order', 'sort']) as $key => $val) + + @endforeach + + - @endforeach -
- - @include('form.user-select', ['user' => $filters['user'] ? \BookStack\Auth\User::query()->find($filters['user']) : null, 'name' => 'user']) -
+ @if(!empty($filters['event'])) + + @endif + + @foreach(['date_from', 'date_to'] as $filterKey) +
+ + +
+ @endforeach +
+ + @include('form.user-select', ['user' => $filters['user'] ? \BookStack\Users\Models\User::query()->find($filters['user']) : null, 'name' => 'user']) +
-
- - @include('form.text', ['name' => 'ip', 'model' => (object) $filters]) - -
- -
+
+ + @include('form.text', ['name' => 'ip', 'model' => (object) $filters]) + +
+ -
-
{{ $activities->links() }}
-
- @include('common.sort', array_merge($listOptions->getSortControlData(), ['useQuery' => true])) -
-
+
-
-
-
{{ trans('settings.audit_table_user') }}
-
{{ trans('settings.audit_table_event') }}
-
{{ trans('settings.audit_table_related') }}
-
-
{{ trans('settings.audit_table_ip') }}
-
{{ trans('settings.audit_table_date') }}
+
+
{{ $activities->links() }}
+
+ @include('common.sort', array_merge($listOptions->getSortControlData(), ['useQuery' => true]))
- @foreach($activities as $activity) -
-
- @include('settings.parts.table-user', ['user' => $activity->user, 'user_id' => $activity->user_id]) -
-
{{ trans('settings.audit_table_event') }}: {{ $activity->type }}
-
- @if($activity->entity) - - @icon($activity->entity->getType()) -
- {{ $activity->entity->name }} -
-
- @elseif($activity->detail && $activity->isForEntity()) -
- {{ trans('settings.audit_deleted_item') }}
- {{ trans('settings.audit_deleted_item_name', ['name' => $activity->detail]) }} -
- @elseif($activity->detail) -
{{ $activity->detail }}
- @endif -
+ +
+
+
{{ trans('settings.audit_table_user') }}
+
{{ trans('settings.audit_table_event') }}
+
{{ trans('settings.audit_table_related') }}
-
{{ trans('settings.audit_table_ip') }}:
{{ $activity->ip }}
-
{{ trans('settings.audit_table_date') }}:
{{ $activity->created_at }}
+
{{ trans('settings.audit_table_ip') }}
+
{{ trans('settings.audit_table_date') }}
- @endforeach -
+ @foreach($activities as $activity) +
+
+ @include('settings.parts.table-user', ['user' => $activity->user, 'user_id' => $activity->user_id]) +
+
{{ trans('settings.audit_table_event') }} + : {{ $activity->type }}
+
+ @if($activity->entity) + + @icon($activity->entity->getType()) +
+ {{ $activity->entity->name }} +
+
+ @elseif($activity->detail && $activity->isForEntity()) +
+ {{ trans('settings.audit_deleted_item') }}
+ {{ trans('settings.audit_deleted_item_name', ['name' => $activity->detail]) }} +
+ @elseif($activity->detail) +
{{ $activity->detail }}
+ @endif +
+
+
{{ trans('settings.audit_table_ip') }} + :
{{ $activity->ip }}
+
{{ trans('settings.audit_table_date') }} + :
{{ $activity->created_at }}
+
+
+ @endforeach +
-
- {{ $activities->links() }} +
+ {{ $activities->links() }} +
-
-
+
@stop diff --git a/resources/views/settings/registration.blade.php b/resources/views/settings/registration.blade.php index e60704aeb3c..1666cef53cd 100644 --- a/resources/views/settings/registration.blade.php +++ b/resources/views/settings/registration.blade.php @@ -24,9 +24,12 @@ @endif - has('setting-registration-role')) class="neg" @endif> + + @foreach(\BookStack\Users\Models\Role::all() as $role)