]> BookStack Code Mirror - bookstack/commitdiff
Merge branch 'master' into release
authorDan Brown <redacted>
Sun, 13 Jun 2021 13:25:39 +0000 (14:25 +0100)
committerDan Brown <redacted>
Sun, 13 Jun 2021 13:25:39 +0000 (14:25 +0100)
25 files changed:
app/Entities/Tools/PageContent.php
app/Http/Controllers/AttachmentController.php
app/Http/Controllers/Controller.php
app/Uploads/Attachment.php
app/Uploads/AttachmentService.php
app/Util/HtmlContentFilter.php
composer.json
composer.lock
package-lock.json
package.json
resources/js/components/attachments-list.js [new file with mode: 0644]
resources/js/components/index.js
resources/lang/es_AR/settings.php
resources/lang/id/common.php
resources/lang/id/entities.php
resources/lang/id/errors.php
resources/lang/id/settings.php
resources/lang/id/validation.php
resources/lang/zh_CN/auth.php
resources/views/attachments/list.blade.php
resources/views/errors/404.blade.php
resources/views/errors/parts/not-found-text.blade.php [new file with mode: 0644]
tests/Entity/ExportTest.php
tests/Entity/PageContentTest.php
tests/Uploads/AttachmentTest.php

index 5e3ef98d0fa7b336d2195cd3eaf3a4550516827b..381ef172b47105939740a31ae807a7fbff865f10 100644 (file)
@@ -332,7 +332,7 @@ class PageContent
     protected function fetchSectionOfPage(Page $page, string $sectionId): string
     {
         $topLevelTags = ['table', 'ul', 'ol'];
-        $doc = $this->loadDocumentFromHtml('<body>' . $page->html . '</body>');
+        $doc = $this->loadDocumentFromHtml($page->html);
 
         // Search included content for the id given and blank out if not exists.
         $matchingElem = $doc->getElementById($sectionId);
@@ -363,6 +363,7 @@ class PageContent
     {
         libxml_use_internal_errors(true);
         $doc = new DOMDocument();
+        $html = '<body>' . $html . '</body>';
         $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
         return $doc;
     }
index 04e89ac5d1a0db18407398aabd3689951822eee8..be20cda93de55506206f6305f5c07b414de5b6e9 100644 (file)
@@ -14,16 +14,14 @@ use Illuminate\Validation\ValidationException;
 class AttachmentController extends Controller
 {
     protected $attachmentService;
-    protected $attachment;
     protected $pageRepo;
 
     /**
      * AttachmentController constructor.
      */
-    public function __construct(AttachmentService $attachmentService, Attachment $attachment, PageRepo $pageRepo)
+    public function __construct(AttachmentService $attachmentService, PageRepo $pageRepo)
     {
         $this->attachmentService = $attachmentService;
-        $this->attachment = $attachment;
         $this->pageRepo = $pageRepo;
     }
 
@@ -67,7 +65,7 @@ class AttachmentController extends Controller
             'file' => 'required|file'
         ]);
 
-        $attachment = $this->attachment->newQuery()->findOrFail($attachmentId);
+        $attachment = Attachment::query()->findOrFail($attachmentId);
         $this->checkOwnablePermission('view', $attachment->page);
         $this->checkOwnablePermission('page-update', $attachment->page);
         $this->checkOwnablePermission('attachment-create', $attachment);
@@ -89,7 +87,7 @@ class AttachmentController extends Controller
      */
     public function getUpdateForm(string $attachmentId)
     {
-        $attachment = $this->attachment->findOrFail($attachmentId);
+        $attachment = Attachment::query()->findOrFail($attachmentId);
 
         $this->checkOwnablePermission('page-update', $attachment->page);
         $this->checkOwnablePermission('attachment-create', $attachment);
@@ -104,8 +102,8 @@ class AttachmentController extends Controller
      */
     public function update(Request $request, string $attachmentId)
     {
-        $attachment = $this->attachment->newQuery()->findOrFail($attachmentId);
-
+        /** @var Attachment $attachment */
+        $attachment = Attachment::query()->findOrFail($attachmentId);
         try {
             $this->validate($request, [
                 'attachment_edit_name' => 'required|string|min:1|max:255',
@@ -160,7 +158,7 @@ class AttachmentController extends Controller
 
         $attachmentName = $request->get('attachment_link_name');
         $link = $request->get('attachment_link_url');
-        $attachment = $this->attachmentService->saveNewFromLink($attachmentName, $link, intval($pageId));
+        $this->attachmentService->saveNewFromLink($attachmentName, $link, intval($pageId));
 
         return view('attachments.manager-link-form', [
             'pageId' => $pageId,
@@ -202,9 +200,10 @@ class AttachmentController extends Controller
      * @throws FileNotFoundException
      * @throws NotFoundException
      */
-    public function get(string $attachmentId)
+    public function get(Request $request, string $attachmentId)
     {
-        $attachment = $this->attachment->findOrFail($attachmentId);
+        /** @var Attachment $attachment */
+        $attachment = Attachment::query()->findOrFail($attachmentId);
         try {
             $page = $this->pageRepo->getById($attachment->uploaded_to);
         } catch (NotFoundException $exception) {
@@ -217,8 +216,13 @@ class AttachmentController extends Controller
             return redirect($attachment->path);
         }
 
+        $fileName = $attachment->getFileName();
         $attachmentContents = $this->attachmentService->getAttachmentFromStorage($attachment);
-        return $this->downloadResponse($attachmentContents, $attachment->getFileName());
+
+        if ($request->get('open') === 'true') {
+            return $this->inlineDownloadResponse($attachmentContents, $fileName);
+        }
+        return $this->downloadResponse($attachmentContents, $fileName);
     }
 
     /**
@@ -227,7 +231,8 @@ class AttachmentController extends Controller
      */
     public function delete(string $attachmentId)
     {
-        $attachment = $this->attachment->findOrFail($attachmentId);
+        /** @var Attachment $attachment */
+        $attachment = Attachment::query()->findOrFail($attachmentId);
         $this->checkOwnablePermission('attachment-delete', $attachment);
         $this->attachmentService->deleteFile($attachment);
         return response()->json(['message' => trans('entities.attachments_deleted')]);
index 034dfa524192013b4766880ebb878176ef95d496..47b03b28d48aaa29610ef562635670af6adbb630 100644 (file)
@@ -6,6 +6,7 @@ use BookStack\Facades\Activity;
 use BookStack\Interfaces\Loggable;
 use BookStack\HasCreatorAndUpdater;
 use BookStack\Model;
+use finfo;
 use Illuminate\Foundation\Bus\DispatchesJobs;
 use Illuminate\Foundation\Validation\ValidatesRequests;
 use Illuminate\Http\Exceptions\HttpResponseException;
@@ -121,6 +122,20 @@ abstract class Controller extends BaseController
         ]);
     }
 
+    /**
+     * Create a file download response that provides the file with a content-type
+     * correct for the file, in a way so the browser can show the content in browser.
+     */
+    protected function inlineDownloadResponse(string $content, string $fileName): Response
+    {
+        $finfo = new finfo(FILEINFO_MIME_TYPE);
+        $mime = $finfo->buffer($content) ?: 'application/octet-stream';
+        return response()->make($content, 200, [
+            'Content-Type'        => $mime,
+            'Content-Disposition' => 'inline; filename="' . $fileName . '"'
+        ]);
+    }
+
     /**
      * Show a positive, successful notification to the user on next view load.
      */
index d1060477d085d3cda5c23b7363c5d54067de7b3d..383af9537d34a20590e1609bcaddeaa8a9b11a67 100644 (file)
@@ -3,12 +3,14 @@
 use BookStack\Entities\Models\Page;
 use BookStack\Model;
 use BookStack\Traits\HasCreatorAndUpdater;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * @property int id
  * @property string name
  * @property string path
  * @property string extension
+ * @property ?Page page
  * @property bool external
  */
 class Attachment extends Model
@@ -31,9 +33,8 @@ class Attachment extends Model
 
     /**
      * Get the page this file was uploaded to.
-     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
      */
-    public function page()
+    public function page(): BelongsTo
     {
         return $this->belongsTo(Page::class, 'uploaded_to');
     }
@@ -41,12 +42,12 @@ class Attachment extends Model
     /**
      * Get the url of this file.
      */
-    public function getUrl(): string
+    public function getUrl($openInline = false): string
     {
         if ($this->external && strpos($this->path, 'http') !== 0) {
             return $this->path;
         }
-        return url('/attachments/' . $this->id);
+        return url('/attachments/' . $this->id . ($openInline ? '?open=true' : ''));
     }
 
     /**
index 4437897c711e49527035d78478e0a95625b2bcbb..37adb4f8368f0c355fcad8ae3bfd37037876c402 100644 (file)
@@ -3,8 +3,10 @@
 use BookStack\Exceptions\FileUploadException;
 use Exception;
 use Illuminate\Contracts\Filesystem\Factory as FileSystem;
+use Illuminate\Contracts\Filesystem\FileNotFoundException;
 use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
 use Illuminate\Support\Str;
+use Log;
 use Symfony\Component\HttpFoundation\File\UploadedFile;
 
 class AttachmentService
@@ -38,11 +40,9 @@ class AttachmentService
 
     /**
      * Get an attachment from storage.
-     * @param Attachment $attachment
-     * @return string
-     * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
+     * @throws FileNotFoundException
      */
-    public function getAttachmentFromStorage(Attachment $attachment)
+    public function getAttachmentFromStorage(Attachment $attachment): string
     {
         return $this->getStorage()->get($attachment->path);
     }
@@ -202,7 +202,7 @@ class AttachmentService
         try {
             $storage->put($attachmentPath, $attachmentData);
         } catch (Exception $e) {
-            \Log::error('Error when attempting file upload:' . $e->getMessage());
+            Log::error('Error when attempting file upload:' . $e->getMessage());
             throw new FileUploadException(trans('errors.path_not_writable', ['filePath' => $attachmentPath]));
         }
 
index cec927a3cef7d4ee5651ed226401bfcc3ccca4c9..11be5a0995c3dde7ec047c5a5c9290a1f8135a2e 100644 (file)
@@ -1,7 +1,6 @@
 <?php namespace BookStack\Util;
 
 use DOMDocument;
-use DOMNode;
 use DOMNodeList;
 use DOMXPath;
 
@@ -16,6 +15,7 @@ class HtmlContentFilter
             return $html;
         }
 
+        $html = '<body>' . $html . '</body>';
         libxml_use_internal_errors(true);
         $doc = new DOMDocument();
         $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
@@ -61,11 +61,10 @@ class HtmlContentFilter
     /**
      * Removed all of the given DOMNodes.
      */
-    static protected function removeNodes(DOMNodeList $nodes): void
+    protected static function removeNodes(DOMNodeList $nodes): void
     {
         foreach ($nodes as $node) {
             $node->parentNode->removeChild($node);
         }
     }
-
-}
\ No newline at end of file
+}
index 3e604b8fdfb29dd13cef6be681971ecdad0a9a9b..8450a2f9250205109ecaeebdca2ac3538c86fc69 100644 (file)
@@ -8,6 +8,7 @@
         "php": "^7.3|^8.0",
         "ext-curl": "*",
         "ext-dom": "*",
+        "ext-fileinfo": "*",
         "ext-gd": "*",
         "ext-json": "*",
         "ext-mbstring": "*",
index 35fa1e703c85f7a86366e90a074d6cc84eb8d25f..d0d75a32ce2f350a4581b7d24464a64e9a806ef8 100644 (file)
@@ -4,20 +4,20 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "b26d29958d84c91b164a8234d1a7e9e9",
+    "content-hash": "eb3108f1a3a757df9b9a3a4f82b5db3b",
     "packages": [
         {
             "name": "aws/aws-sdk-php",
-            "version": "3.183.9",
+            "version": "3.184.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/aws/aws-sdk-php.git",
-                "reference": "3b3aafdceac4cb820e2ae65a8785e4d07db471a7"
+                "reference": "78fe691ab466fecf195209672f6c00c5d4ed219a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3b3aafdceac4cb820e2ae65a8785e4d07db471a7",
-                "reference": "3b3aafdceac4cb820e2ae65a8785e4d07db471a7",
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/78fe691ab466fecf195209672f6c00c5d4ed219a",
+                "reference": "78fe691ab466fecf195209672f6c00c5d4ed219a",
                 "shasum": ""
             },
             "require": {
@@ -92,9 +92,9 @@
             "support": {
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.183.9"
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.184.2"
             },
-            "time": "2021-05-28T18:28:19+00:00"
+            "time": "2021-06-11T18:20:15+00:00"
         },
         {
             "name": "barryvdh/laravel-dompdf",
         },
         {
             "name": "facade/flare-client-php",
-            "version": "1.8.0",
+            "version": "1.8.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/facade/flare-client-php.git",
-                "reference": "69742118c037f34ee1ef86dc605be4a105d9e984"
+                "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/facade/flare-client-php/zipball/69742118c037f34ee1ef86dc605be4a105d9e984",
-                "reference": "69742118c037f34ee1ef86dc605be4a105d9e984",
+                "url": "https://api.github.com/repos/facade/flare-client-php/zipball/47b639dc02bcfdfc4ebb83de703856fa01e35f5f",
+                "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f",
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/facade/flare-client-php/issues",
-                "source": "https://github.com/facade/flare-client-php/tree/1.8.0"
+                "source": "https://github.com/facade/flare-client-php/tree/1.8.1"
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
-            "time": "2021-04-30T11:11:50+00:00"
+            "time": "2021-05-31T19:23:29+00:00"
         },
         {
             "name": "facade/ignition",
         },
         {
             "name": "filp/whoops",
-            "version": "2.12.1",
+            "version": "2.13.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/filp/whoops.git",
-                "reference": "c13c0be93cff50f88bbd70827d993026821914dd"
+                "reference": "2edbc73a4687d9085c8f20f398eebade844e8424"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/filp/whoops/zipball/c13c0be93cff50f88bbd70827d993026821914dd",
-                "reference": "c13c0be93cff50f88bbd70827d993026821914dd",
+                "url": "https://api.github.com/repos/filp/whoops/zipball/2edbc73a4687d9085c8f20f398eebade844e8424",
+                "reference": "2edbc73a4687d9085c8f20f398eebade844e8424",
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/filp/whoops/issues",
-                "source": "https://github.com/filp/whoops/tree/2.12.1"
+                "source": "https://github.com/filp/whoops/tree/2.13.0"
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
-            "time": "2021-04-25T12:00:00+00:00"
+            "time": "2021-06-04T12:00:00+00:00"
         },
         {
             "name": "guzzlehttp/guzzle",
         },
         {
             "name": "nesbot/carbon",
-            "version": "2.48.1",
+            "version": "2.49.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "8d1f50f1436fb4b05e7127360483dd9c6e73da16"
+                "reference": "93d9db91c0235c486875d22f1e08b50bdf3e6eee"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8d1f50f1436fb4b05e7127360483dd9c6e73da16",
-                "reference": "8d1f50f1436fb4b05e7127360483dd9c6e73da16",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/93d9db91c0235c486875d22f1e08b50bdf3e6eee",
+                "reference": "93d9db91c0235c486875d22f1e08b50bdf3e6eee",
                 "shasum": ""
             },
             "require": {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-26T22:08:38+00:00"
+            "time": "2021-06-02T07:31:40+00:00"
         },
         {
             "name": "nunomaduro/collision",
         },
         {
             "name": "symfony/console",
-            "version": "v4.4.24",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "1b15ca1b1bedda86f98064da9ff5d800560d4c6d"
+                "reference": "a62acecdf5b50e314a4f305cd01b5282126f3095"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/1b15ca1b1bedda86f98064da9ff5d800560d4c6d",
-                "reference": "1b15ca1b1bedda86f98064da9ff5d800560d4c6d",
+                "url": "https://api.github.com/repos/symfony/console/zipball/a62acecdf5b50e314a4f305cd01b5282126f3095",
+                "reference": "a62acecdf5b50e314a4f305cd01b5282126f3095",
                 "shasum": ""
             },
             "require": {
             "description": "Eases the creation of beautiful and testable command line interfaces",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/console/tree/v4.4.24"
+                "source": "https://github.com/symfony/console/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-13T06:28:07+00:00"
+            "time": "2021-05-26T11:20:16+00:00"
         },
         {
             "name": "symfony/css-selector",
-            "version": "v4.4.24",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/css-selector.git",
-                "reference": "947cacaf1b3a2af6f13a435392873d5ddaba5f70"
+                "reference": "c1e29de6dc893b130b45d20d8051efbb040560a9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/css-selector/zipball/947cacaf1b3a2af6f13a435392873d5ddaba5f70",
-                "reference": "947cacaf1b3a2af6f13a435392873d5ddaba5f70",
+                "url": "https://api.github.com/repos/symfony/css-selector/zipball/c1e29de6dc893b130b45d20d8051efbb040560a9",
+                "reference": "c1e29de6dc893b130b45d20d8051efbb040560a9",
                 "shasum": ""
             },
             "require": {
             "description": "Converts CSS selectors to XPath expressions",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/css-selector/tree/v4.4.24"
+                "source": "https://github.com/symfony/css-selector/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-16T09:52:47+00:00"
+            "time": "2021-05-26T17:39:37+00:00"
         },
         {
             "name": "symfony/debug",
-            "version": "v4.4.22",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/debug.git",
-                "reference": "45b2136377cca5f10af858968d6079a482bca473"
+                "reference": "a8d2d5c94438548bff9f998ca874e202bb29d07f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/debug/zipball/45b2136377cca5f10af858968d6079a482bca473",
-                "reference": "45b2136377cca5f10af858968d6079a482bca473",
+                "url": "https://api.github.com/repos/symfony/debug/zipball/a8d2d5c94438548bff9f998ca874e202bb29d07f",
+                "reference": "a8d2d5c94438548bff9f998ca874e202bb29d07f",
                 "shasum": ""
             },
             "require": {
             "description": "Provides tools to ease debugging PHP code",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/debug/tree/v4.4.22"
+                "source": "https://github.com/symfony/debug/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-04-02T07:50:12+00:00"
+            "time": "2021-05-26T17:39:37+00:00"
         },
         {
             "name": "symfony/deprecation-contracts",
         },
         {
             "name": "symfony/error-handler",
-            "version": "v4.4.23",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/error-handler.git",
-                "reference": "21d75bfbdfdd3581a7f97080deb98926987f14a7"
+                "reference": "310a756cec00d29d89a08518405aded046a54a8b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/error-handler/zipball/21d75bfbdfdd3581a7f97080deb98926987f14a7",
-                "reference": "21d75bfbdfdd3581a7f97080deb98926987f14a7",
+                "url": "https://api.github.com/repos/symfony/error-handler/zipball/310a756cec00d29d89a08518405aded046a54a8b",
+                "reference": "310a756cec00d29d89a08518405aded046a54a8b",
                 "shasum": ""
             },
             "require": {
             "description": "Provides tools to manage errors and ease debugging PHP code",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/error-handler/tree/v4.4.23"
+                "source": "https://github.com/symfony/error-handler/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-02T20:47:26+00:00"
+            "time": "2021-05-26T17:39:37+00:00"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v4.4.20",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c"
+                "reference": "047773e7016e4fd45102cedf4bd2558ae0d0c32f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c352647244bd376bf7d31efbd5401f13f50dad0c",
-                "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/047773e7016e4fd45102cedf4bd2558ae0d0c32f",
+                "reference": "047773e7016e4fd45102cedf4bd2558ae0d0c32f",
                 "shasum": ""
             },
             "require": {
             "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20"
+                "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-01-27T09:09:26+00:00"
+            "time": "2021-05-26T17:39:37+00:00"
         },
         {
             "name": "symfony/event-dispatcher-contracts",
         },
         {
             "name": "symfony/finder",
-            "version": "v4.4.24",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "a96bc19ed87c88eec78e1a4c803bdc1446952983"
+                "reference": "ed33314396d968a8936c95f5bd1b88bd3b3e94a3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/a96bc19ed87c88eec78e1a4c803bdc1446952983",
-                "reference": "a96bc19ed87c88eec78e1a4c803bdc1446952983",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/ed33314396d968a8936c95f5bd1b88bd3b3e94a3",
+                "reference": "ed33314396d968a8936c95f5bd1b88bd3b3e94a3",
                 "shasum": ""
             },
             "require": {
             "description": "Finds files and directories via an intuitive fluent interface",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/finder/tree/v4.4.24"
+                "source": "https://github.com/symfony/finder/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-16T12:27:45+00:00"
+            "time": "2021-05-26T11:20:16+00:00"
         },
         {
             "name": "symfony/http-client-contracts",
         },
         {
             "name": "symfony/http-foundation",
-            "version": "v4.4.23",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "2ffb43bd6c589a274ee1e93a5fd6b7ef1577b9c5"
+                "reference": "0c79d5a65ace4fe66e49702658c024a419d2438b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/2ffb43bd6c589a274ee1e93a5fd6b7ef1577b9c5",
-                "reference": "2ffb43bd6c589a274ee1e93a5fd6b7ef1577b9c5",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0c79d5a65ace4fe66e49702658c024a419d2438b",
+                "reference": "0c79d5a65ace4fe66e49702658c024a419d2438b",
                 "shasum": ""
             },
             "require": {
             "description": "Defines an object-oriented layer for the HTTP specification",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-foundation/tree/v4.4.23"
+                "source": "https://github.com/symfony/http-foundation/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-05T07:40:41+00:00"
+            "time": "2021-05-26T11:20:16+00:00"
         },
         {
             "name": "symfony/http-kernel",
-            "version": "v4.4.24",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-kernel.git",
-                "reference": "59925ee79f2541b4c6e990843e1a42768e898254"
+                "reference": "3795165596fe81a52296b78c9aae938d434069cc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/59925ee79f2541b4c6e990843e1a42768e898254",
-                "reference": "59925ee79f2541b4c6e990843e1a42768e898254",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/3795165596fe81a52296b78c9aae938d434069cc",
+                "reference": "3795165596fe81a52296b78c9aae938d434069cc",
                 "shasum": ""
             },
             "require": {
             "description": "Provides a structured process for converting a Request into a Response",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-kernel/tree/v4.4.24"
+                "source": "https://github.com/symfony/http-kernel/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-19T12:12:19+00:00"
+            "time": "2021-06-01T07:12:08+00:00"
         },
         {
             "name": "symfony/mime",
-            "version": "v5.2.9",
+            "version": "v5.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/mime.git",
-                "reference": "64258e870f8cc75c3dae986201ea2df58c210b52"
+                "reference": "ed710d297b181f6a7194d8172c9c2423d58e4852"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/mime/zipball/64258e870f8cc75c3dae986201ea2df58c210b52",
-                "reference": "64258e870f8cc75c3dae986201ea2df58c210b52",
+                "url": "https://api.github.com/repos/symfony/mime/zipball/ed710d297b181f6a7194d8172c9c2423d58e4852",
+                "reference": "ed710d297b181f6a7194d8172c9c2423d58e4852",
                 "shasum": ""
             },
             "require": {
                 "mime-type"
             ],
             "support": {
-                "source": "https://github.com/symfony/mime/tree/v5.2.9"
+                "source": "https://github.com/symfony/mime/tree/v5.3.0"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-16T13:07:46+00:00"
+            "time": "2021-05-26T17:43:10+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
         },
         {
             "name": "symfony/process",
-            "version": "v4.4.22",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "f5481b22729d465acb1cea3455fc04ce84b0148b"
+                "reference": "cd61e6dd273975c6625316de9d141ebd197f93c9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/f5481b22729d465acb1cea3455fc04ce84b0148b",
-                "reference": "f5481b22729d465acb1cea3455fc04ce84b0148b",
+                "url": "https://api.github.com/repos/symfony/process/zipball/cd61e6dd273975c6625316de9d141ebd197f93c9",
+                "reference": "cd61e6dd273975c6625316de9d141ebd197f93c9",
                 "shasum": ""
             },
             "require": {
             "description": "Executes commands in sub-processes",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/process/tree/v4.4.22"
+                "source": "https://github.com/symfony/process/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-04-07T16:22:29+00:00"
+            "time": "2021-05-26T11:20:16+00:00"
         },
         {
             "name": "symfony/routing",
-            "version": "v4.4.24",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/routing.git",
-                "reference": "b42c3631fd9e3511610afb2ba081ea7e38d9fa38"
+                "reference": "3a3c2f197ad0846ac6413225fc78868ba1c61434"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/routing/zipball/b42c3631fd9e3511610afb2ba081ea7e38d9fa38",
-                "reference": "b42c3631fd9e3511610afb2ba081ea7e38d9fa38",
+                "url": "https://api.github.com/repos/symfony/routing/zipball/3a3c2f197ad0846ac6413225fc78868ba1c61434",
+                "reference": "3a3c2f197ad0846ac6413225fc78868ba1c61434",
                 "shasum": ""
             },
             "require": {
                 "url"
             ],
             "support": {
-                "source": "https://github.com/symfony/routing/tree/v4.4.24"
+                "source": "https://github.com/symfony/routing/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-16T09:52:47+00:00"
+            "time": "2021-05-26T17:39:37+00:00"
         },
         {
             "name": "symfony/service-contracts",
         },
         {
             "name": "symfony/translation",
-            "version": "v4.4.24",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation.git",
-                "reference": "424d29dfcc15575af05196de0100d7b52f650602"
+                "reference": "dfe132c5c6d89f90ce7f961742cc532e9ca16dd4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/translation/zipball/424d29dfcc15575af05196de0100d7b52f650602",
-                "reference": "424d29dfcc15575af05196de0100d7b52f650602",
+                "url": "https://api.github.com/repos/symfony/translation/zipball/dfe132c5c6d89f90ce7f961742cc532e9ca16dd4",
+                "reference": "dfe132c5c6d89f90ce7f961742cc532e9ca16dd4",
                 "shasum": ""
             },
             "require": {
             "description": "Provides tools to internationalize your application",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/translation/tree/v4.4.24"
+                "source": "https://github.com/symfony/translation/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-16T09:52:47+00:00"
+            "time": "2021-05-26T17:39:37+00:00"
         },
         {
             "name": "symfony/translation-contracts",
         },
         {
             "name": "symfony/var-dumper",
-            "version": "v4.4.22",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/var-dumper.git",
-                "reference": "c194bcedde6295f3ec3e9eba1f5d484ea97c41a7"
+                "reference": "31ea689a8e7d2410016b0d25fc15a1ba05a6e2e0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c194bcedde6295f3ec3e9eba1f5d484ea97c41a7",
-                "reference": "c194bcedde6295f3ec3e9eba1f5d484ea97c41a7",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/31ea689a8e7d2410016b0d25fc15a1ba05a6e2e0",
+                "reference": "31ea689a8e7d2410016b0d25fc15a1ba05a6e2e0",
                 "shasum": ""
             },
             "require": {
                 "dump"
             ],
             "support": {
-                "source": "https://github.com/symfony/var-dumper/tree/v4.4.22"
+                "source": "https://github.com/symfony/var-dumper/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-04-19T13:36:17+00:00"
+            "time": "2021-05-27T09:48:32+00:00"
         },
         {
             "name": "tijsverkoyen/css-to-inline-styles",
     "packages-dev": [
         {
             "name": "barryvdh/laravel-debugbar",
-            "version": "v3.5.7",
+            "version": "v3.6.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/barryvdh/laravel-debugbar.git",
-                "reference": "88fd9cfa144b06b2549e9d487fdaec68265e791e"
+                "reference": "f6f0f895a33cac801286a74355d146bb5384a5da"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/88fd9cfa144b06b2549e9d487fdaec68265e791e",
-                "reference": "88fd9cfa144b06b2549e9d487fdaec68265e791e",
+                "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/f6f0f895a33cac801286a74355d146bb5384a5da",
+                "reference": "f6f0f895a33cac801286a74355d146bb5384a5da",
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/barryvdh/laravel-debugbar/issues",
-                "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.5.7"
+                "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.1"
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T20:18:35+00:00"
+            "time": "2021-06-02T06:42:22+00:00"
         },
         {
             "name": "barryvdh/laravel-ide-helper",
         },
         {
             "name": "composer/ca-bundle",
-            "version": "1.2.9",
+            "version": "1.2.10",
             "source": {
                 "type": "git",
                 "url": "https://github.com/composer/ca-bundle.git",
-                "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5"
+                "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5",
-                "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5",
+                "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8",
+                "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8",
                 "shasum": ""
             },
             "require": {
             "support": {
                 "irc": "irc://irc.freenode.org/composer",
                 "issues": "https://github.com/composer/ca-bundle/issues",
-                "source": "https://github.com/composer/ca-bundle/tree/1.2.9"
+                "source": "https://github.com/composer/ca-bundle/tree/1.2.10"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-01-12T12:10:35+00:00"
+            "time": "2021-06-07T13:58:28+00:00"
         },
         {
             "name": "composer/composer",
-            "version": "2.0.14",
+            "version": "2.1.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/composer/composer.git",
-                "reference": "92b2ccbef65292ba9f2004271ef47c7231e2eed5"
+                "reference": "fc5c4573aafce3a018eb7f1f8f91cea423970f2e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/composer/composer/zipball/92b2ccbef65292ba9f2004271ef47c7231e2eed5",
-                "reference": "92b2ccbef65292ba9f2004271ef47c7231e2eed5",
+                "url": "https://api.github.com/repos/composer/composer/zipball/fc5c4573aafce3a018eb7f1f8f91cea423970f2e",
+                "reference": "fc5c4573aafce3a018eb7f1f8f91cea423970f2e",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-master": "2.1-dev"
                 }
             },
             "autoload": {
             "support": {
                 "irc": "irc://irc.freenode.org/composer",
                 "issues": "https://github.com/composer/composer/issues",
-                "source": "https://github.com/composer/composer/tree/2.0.14"
+                "source": "https://github.com/composer/composer/tree/2.1.3"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-21T15:03:37+00:00"
+            "time": "2021-06-09T14:31:20+00:00"
         },
         {
             "name": "composer/metadata-minifier",
         },
         {
             "name": "phpunit/phpunit",
-            "version": "9.5.4",
+            "version": "9.5.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "c73c6737305e779771147af66c96ca6a7ed8a741"
+                "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c73c6737305e779771147af66c96ca6a7ed8a741",
-                "reference": "c73c6737305e779771147af66c96ca6a7ed8a741",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/89ff45ea9d70e35522fb6654a2ebc221158de276",
+                "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276",
                 "shasum": ""
             },
             "require": {
                 "sebastian/global-state": "^5.0.1",
                 "sebastian/object-enumerator": "^4.0.3",
                 "sebastian/resource-operations": "^3.0.3",
-                "sebastian/type": "^2.3",
+                "sebastian/type": "^2.3.2",
                 "sebastian/version": "^3.0.2"
             },
             "require-dev": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.4"
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.5"
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
-            "time": "2021-03-23T07:16:29+00:00"
+            "time": "2021-06-05T04:49:07+00:00"
         },
         {
             "name": "react/promise",
         },
         {
             "name": "sebastian/global-state",
-            "version": "5.0.2",
+            "version": "5.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "a90ccbddffa067b51f574dea6eb25d5680839455"
+                "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455",
-                "reference": "a90ccbddffa067b51f574dea6eb25d5680839455",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49",
+                "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49",
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/global-state/issues",
-                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2"
+                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3"
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T15:55:19+00:00"
+            "time": "2021-06-11T13:31:12+00:00"
         },
         {
             "name": "sebastian/lines-of-code",
         },
         {
             "name": "sebastian/type",
-            "version": "2.3.1",
+            "version": "2.3.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/type.git",
-                "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2"
+                "reference": "0d1c587401514d17e8f9258a27e23527cb1b06c1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2",
-                "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2",
+                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0d1c587401514d17e8f9258a27e23527cb1b06c1",
+                "reference": "0d1c587401514d17e8f9258a27e23527cb1b06c1",
                 "shasum": ""
             },
             "require": {
             "homepage": "https://github.com/sebastianbergmann/type",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/type/issues",
-                "source": "https://github.com/sebastianbergmann/type/tree/2.3.1"
+                "source": "https://github.com/sebastianbergmann/type/tree/2.3.2"
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:18:59+00:00"
+            "time": "2021-06-04T13:02:07+00:00"
         },
         {
             "name": "sebastian/version",
         },
         {
             "name": "symfony/dom-crawler",
-            "version": "v4.4.24",
+            "version": "v4.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dom-crawler.git",
-                "reference": "fc0bd1f215b0cd9f4efdc63bb66808f3417331bc"
+                "reference": "41d15bb6d6b95d2be763c514bb2494215d9c5eef"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/fc0bd1f215b0cd9f4efdc63bb66808f3417331bc",
-                "reference": "fc0bd1f215b0cd9f4efdc63bb66808f3417331bc",
+                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/41d15bb6d6b95d2be763c514bb2494215d9c5eef",
+                "reference": "41d15bb6d6b95d2be763c514bb2494215d9c5eef",
                 "shasum": ""
             },
             "require": {
             "description": "Eases DOM navigation for HTML and XML documents",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/dom-crawler/tree/v4.4.24"
+                "source": "https://github.com/symfony/dom-crawler/tree/v4.4.25"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-05-16T09:52:47+00:00"
+            "time": "2021-05-26T11:20:16+00:00"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v5.2.7",
+            "version": "v5.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0"
+                "reference": "348116319d7fb7d1faa781d26a48922428013eb2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/056e92acc21d977c37e6ea8e97374b2a6c8551b0",
-                "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/348116319d7fb7d1faa781d26a48922428013eb2",
+                "reference": "348116319d7fb7d1faa781d26a48922428013eb2",
                 "shasum": ""
             },
             "require": {
             "description": "Provides basic utilities for the filesystem",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/filesystem/tree/v5.2.7"
+                "source": "https://github.com/symfony/filesystem/tree/v5.3.0"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-04-01T10:42:13+00:00"
+            "time": "2021-05-26T17:43:10+00:00"
         },
         {
             "name": "theseer/tokenizer",
         "php": "^7.3|^8.0",
         "ext-curl": "*",
         "ext-dom": "*",
+        "ext-fileinfo": "*",
         "ext-gd": "*",
         "ext-json": "*",
         "ext-mbstring": "*",
index 64b3751287f76eddbbda1dc505c4584cd685d64a..7d9318363a51f5e8da1d8d811859efa24473416a 100644 (file)
       },
       "devDependencies": {
         "chokidar-cli": "^2.1.0",
-        "esbuild": "0.12.5",
+        "esbuild": "0.12.8",
         "livereload": "^0.9.3",
         "npm-run-all": "^4.1.5",
         "punycode": "^2.1.1",
-        "sass": "^1.34.0"
+        "sass": "^1.34.1"
       }
     },
     "node_modules/ansi-regex": {
       }
     },
     "node_modules/esbuild": {
-      "version": "0.12.5",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.5.tgz",
-      "integrity": "sha512-vcuP53pA5XiwUU4FnlXM+2PnVjTfHGthM7uP1gtp+9yfheGvFFbq/KyuESThmtoHPUrfZH5JpxGVJIFDVD1Egw==",
+      "version": "0.12.8",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.8.tgz",
+      "integrity": "sha512-sx/LwlP/SWTGsd9G4RlOPrXnIihAJ2xwBUmzoqe2nWwbXORMQWtAGNJNYLBJJqa3e9PWvVzxdrtyFZJcr7D87g==",
       "dev": true,
       "hasInstallScript": true,
       "bin": {
       }
     },
     "node_modules/glob-parent": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
-      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
       "dev": true,
       "dependencies": {
         "is-glob": "^4.0.1"
       }
     },
     "node_modules/sass": {
-      "version": "1.34.0",
-      "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.0.tgz",
-      "integrity": "sha512-rHEN0BscqjUYuomUEaqq3BMgsXqQfkcMVR7UhscsAVub0/spUrZGBMxQXFS2kfiDsPLZw5yuU9iJEFNC2x38Qw==",
+      "version": "1.34.1",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.1.tgz",
+      "integrity": "sha512-scLA7EIZM+MmYlej6sdVr0HRbZX5caX5ofDT9asWnUJj21oqgsC+1LuNfm0eg+vM0fCTZHhwImTiCU0sx9h9CQ==",
       "dev": true,
       "dependencies": {
         "chokidar": ">=3.0.0 <4.0.0"
       }
     },
     "esbuild": {
-      "version": "0.12.5",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.5.tgz",
-      "integrity": "sha512-vcuP53pA5XiwUU4FnlXM+2PnVjTfHGthM7uP1gtp+9yfheGvFFbq/KyuESThmtoHPUrfZH5JpxGVJIFDVD1Egw==",
+      "version": "0.12.8",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.8.tgz",
+      "integrity": "sha512-sx/LwlP/SWTGsd9G4RlOPrXnIihAJ2xwBUmzoqe2nWwbXORMQWtAGNJNYLBJJqa3e9PWvVzxdrtyFZJcr7D87g==",
       "dev": true
     },
     "escape-string-regexp": {
       "dev": true
     },
     "glob-parent": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
-      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
       "dev": true,
       "requires": {
         "is-glob": "^4.0.1"
       }
     },
     "sass": {
-      "version": "1.34.0",
-      "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.0.tgz",
-      "integrity": "sha512-rHEN0BscqjUYuomUEaqq3BMgsXqQfkcMVR7UhscsAVub0/spUrZGBMxQXFS2kfiDsPLZw5yuU9iJEFNC2x38Qw==",
+      "version": "1.34.1",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.1.tgz",
+      "integrity": "sha512-scLA7EIZM+MmYlej6sdVr0HRbZX5caX5ofDT9asWnUJj21oqgsC+1LuNfm0eg+vM0fCTZHhwImTiCU0sx9h9CQ==",
       "dev": true,
       "requires": {
         "chokidar": ">=3.0.0 <4.0.0"
index 9c800616e5f9531b9e19127543dcece478cdc5f9..f4b7bf5dc6f0358a3fc895e62999c1ee7aa08ab0 100644 (file)
   },
   "devDependencies": {
     "chokidar-cli": "^2.1.0",
-    "esbuild": "0.12.5",
+    "esbuild": "0.12.8",
     "livereload": "^0.9.3",
     "npm-run-all": "^4.1.5",
     "punycode": "^2.1.1",
-    "sass": "^1.34.0"
+    "sass": "^1.34.1"
   },
   "dependencies": {
     "clipboard": "^2.0.8",
diff --git a/resources/js/components/attachments-list.js b/resources/js/components/attachments-list.js
new file mode 100644 (file)
index 0000000..34979c2
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * Attachments List
+ * Adds '?open=true' query to file attachment links
+ * when ctrl/cmd is pressed down.
+ * @extends {Component}
+ */
+class AttachmentsList {
+
+    setup() {
+        this.container = this.$el;
+        this.setupListeners();
+    }
+
+    setupListeners() {
+        const isExpectedKey = (event) => event.key === 'Control' || event.key === 'Meta';
+        window.addEventListener('keydown', event => {
+             if (isExpectedKey(event)) {
+                this.addOpenQueryToLinks();
+             }
+        }, {passive: true});
+        window.addEventListener('keyup', event => {
+            if (isExpectedKey(event)) {
+                this.removeOpenQueryFromLinks();
+            }
+        }, {passive: true});
+    }
+
+    addOpenQueryToLinks() {
+        const links = this.container.querySelectorAll('a.attachment-file');
+        for (const link of links) {
+            if (link.href.split('?')[1] !== 'open=true') {
+                link.href = link.href + '?open=true';
+                link.setAttribute('target', '_blank');
+            }
+        }
+    }
+
+    removeOpenQueryFromLinks() {
+        const links = this.container.querySelectorAll('a.attachment-file');
+        for (const link of links) {
+            link.href = link.href.split('?')[0];
+            link.removeAttribute('target');
+        }
+    }
+}
+
+export default AttachmentsList;
\ No newline at end of file
index 91ccdaf3aa6f23fca3a923283634c75eb42a0265..010ee04bae01f349a95ccf9d0eb8dac3f86ce051 100644 (file)
@@ -2,6 +2,7 @@ import addRemoveRows from "./add-remove-rows.js"
 import ajaxDeleteRow from "./ajax-delete-row.js"
 import ajaxForm from "./ajax-form.js"
 import attachments from "./attachments.js"
+import attachmentsList from "./attachments-list.js"
 import autoSuggest from "./auto-suggest.js"
 import backToTop from "./back-to-top.js"
 import bookSort from "./book-sort.js"
@@ -56,6 +57,7 @@ const componentMapping = {
     "ajax-delete-row": ajaxDeleteRow,
     "ajax-form": ajaxForm,
     "attachments": attachments,
+    "attachments-list": attachmentsList,
     "auto-suggest": autoSuggest,
     "back-to-top": backToTop,
     "book-sort": bookSort,
index 93d64ab3b0eeb248e8b147d134caa2237be4b42e..962ef89a4d213a8b964a16d9ec1f0349bc5559f4 100644 (file)
@@ -31,7 +31,7 @@ return [
     'app_custom_html_desc' => 'Cualquier contenido agregado aquí será agregado al final de la sección <head> de cada página. Esto es útil para sobreescribir estilos o agregar código para analíticas.',
     'app_custom_html_disabled_notice' => 'El contenido personailzado para la cabecera HTML está deshabilitado en esta configuración para garantizar que cualquier cambio importante se pueda revertir.',
     'app_logo' => 'Logo de la aplicación',
-    'app_logo_desc' => 'Esta imagen debería ser de 43px en altura. <br>Las imágenes grandes seán escaladas.',
+    'app_logo_desc' => 'Esta imagen debería ser de 43px en altura. <br>Las imágenes grandes serán achicadas.',
     'app_primary_color' => 'Color primario de la aplicación',
     'app_primary_color_desc' => 'Esto debería ser un valor hexadecimal. <br>Deje el valor vacío para reiniciar al valor por defecto.',
     'app_homepage' => 'Página de inicio de la Aplicación',
index 81424b9204b9856acc1ef7da983c28e1f0780942..893ff76032b998cb56b62edb7fe6b3a68156f8dd 100644 (file)
@@ -40,10 +40,10 @@ return [
     'remove' => 'Hapus',
     'add' => 'Tambah',
     'fullscreen' => 'Layar Penuh',
-    'favourite' => 'Favourite',
-    'unfavourite' => 'Unfavourite',
-    'next' => 'Next',
-    'previous' => 'Previous',
+    'favourite' => 'Favorit',
+    'unfavourite' => 'Tidak favorit',
+    'next' => 'Lanjut',
+    'previous' => 'Sebelumnya',
 
     // Sort Options
     'sort_options' => 'Sortir Pilihan',
index 4bfc20b6c4fcebfee83cd97826308ab899b6fe67..5f6afb807a34dc4c4ef39bf27b9d3ae8a33c4c57 100644 (file)
@@ -27,8 +27,8 @@ return [
     'images' => 'Gambar-gambar',
     'my_recent_drafts' => 'Draf Terbaru Saya',
     'my_recently_viewed' => 'Baru saja saya lihat',
-    'my_most_viewed_favourites' => 'My Most Viewed Favourites',
-    'my_favourites' => 'My Favourites',
+    'my_most_viewed_favourites' => 'Favorit Saya yang Paling Banyak Dilihat',
+    'my_favourites' => 'Favoritku',
     'no_pages_viewed' => 'Anda belum melihat halaman apa pun',
     'no_pages_recently_created' => 'Tidak ada halaman yang baru saja dibuat',
     'no_pages_recently_updated' => 'Tidak ada halaman yang baru-baru ini diperbarui',
@@ -120,7 +120,7 @@ return [
     'books_delete_explain' => 'Ini akan menghapus buku dengan nama \': bookName\'. Semua halaman dan bab akan dihapus.',
     'books_delete_confirmation' => 'Apakah Anda yakin ingin menghapus buku ini?',
     'books_edit' => 'Edit Buku',
-    'books_edit_named' => 'Edit Buku :bookName',
+    'books_edit_named' => 'Sunting Buku :bookName',
     'books_form_book_name' => 'Nama Buku',
     'books_save' => 'Simpan Buku',
     'books_permissions' => 'Izin Buku',
@@ -154,7 +154,7 @@ return [
     'chapters_delete_explain' => 'Ini akan menghapus chapter dengan nama \':chapterName\'. Semua halaman yang ada dalam bab ini juga akan dihapus.',
     'chapters_delete_confirm' => 'Anda yakin ingin menghapus bab ini?',
     'chapters_edit' => 'Edit Bab',
-    'chapters_edit_named' => 'Edit Bab :chapterName',
+    'chapters_edit_named' => 'Sunting Bab :chapterName',
     'chapters_save' => 'Simpan Bab',
     'chapters_move' => 'Pindahkan Bab',
     'chapters_move_named' => 'Pindahkan Bab :chapterName',
@@ -181,7 +181,7 @@ return [
     'pages_delete_draft_success' => 'Halaman draf dihapus',
     'pages_delete_confirm' => 'Anda yakin ingin menghapus halaman ini?',
     'pages_delete_draft_confirm' => 'Anda yakin ingin menghapus halaman draf ini?',
-    'pages_editing_named' => 'Mengedit Halaman :pageName',
+    'pages_editing_named' => 'Menyunting Halaman :pageName',
     'pages_edit_draft_options' => 'Opsi Draf',
     'pages_edit_save_draft' => 'Simpan Draf',
     'pages_edit_draft' => 'Edit Halaman Draf',
@@ -190,7 +190,7 @@ return [
     'pages_edit_draft_save_at' => 'Draf disimpan pada ',
     'pages_edit_delete_draft' => 'Hapus Draf',
     'pages_edit_discard_draft' => 'Buang Draf',
-    'pages_edit_set_changelog' => 'Setel Changelog',
+    'pages_edit_set_changelog' => 'Atur Changelog',
     'pages_edit_enter_changelog_desc' => 'Masukkan deskripsi singkat tentang perubahan yang Anda buat',
     'pages_edit_enter_changelog' => 'Masuk ke Changelog',
     'pages_save' => 'Simpan Halaman',
@@ -226,20 +226,20 @@ return [
     'pages_revisions_restore' => 'Mengembalikan',
     'pages_revisions_none' => 'Halaman ini tidak memiliki revisi',
     'pages_copy_link' => 'Salin tautan',
-    'pages_edit_content_link' => 'Edit Konten',
+    'pages_edit_content_link' => 'Sunting Konten',
     'pages_permissions_active' => 'Izin Halaman Aktif',
     'pages_initial_revision' => 'Penerbitan awal',
     'pages_initial_name' => 'Halaman Baru',
-    'pages_editing_draft_notification' => 'Anda sedang mengedit draf yang terakhir disimpan :timeDiff.',
+    'pages_editing_draft_notification' => 'Anda sedang menyunting konsep yang terakhir disimpan :timeDiff.',
     'pages_draft_edited_notification' => 'Halaman ini telah diperbarui sejak saat itu. Anda disarankan untuk membuang draf ini.',
     'pages_draft_edit_active' => [
         'start_a' => ':count pengguna sudah mulai mengedit halaman ini',
-        'start_b' => ':userName sudah mulai mengedit halaman ini',
-        'time_a' => 'perubahan di sini disimpan secara instan',
+        'start_b' => ':userName telah memulai menyunting halaman ini',
+        'time_a' => 'semenjak halaman terakhir diperbarui',
         'time_b' => 'di akhir :minCount menit',
         'message' => ':start :time. Berhati-hatilah untuk tidak menimpa pembaruan satu sama lain!',
     ],
-    'pages_draft_discarded' => 'Draf dibuang, Editor telah diperbarui dengan konten halaman saat ini',
+    'pages_draft_discarded' => 'Konsep dibuang, Penyunting telah diperbarui dengan konten halaman saat ini',
     'pages_specific' => 'Halaman Tertentu',
     'pages_is_template' => 'Template Halaman',
 
@@ -256,29 +256,29 @@ return [
     'tags_add' => 'Tambahkan tag lain',
     'tags_remove' => 'Hapus tag ini',
     'attachments' => 'Lampiran',
-    'attachments_explain' => 'Unggah beberapa file atau lampirkan beberapa tautan untuk ditampilkan di laman Anda. Ini terlihat di sidebar halaman.',
+    'attachments_explain' => 'Unggah beberapa berkas atau lampirkan beberapa tautan untuk ditampilkan di laman Anda. Ini terlihat di sidebar halaman.',
     'attachments_explain_instant_save' => 'Perubahan di sini disimpan secara instan.',
     'attachments_items' => 'Item Terlampir',
-    'attachments_upload' => 'Unggah File',
+    'attachments_upload' => 'Unggah Berkas',
     'attachments_link' => 'Lampirkan Tautan',
     'attachments_set_link' => 'Setel Tautan',
     'attachments_delete' => 'Anda yakin ingin menghapus lampiran ini?',
     'attachments_dropzone' => 'Jatuhkan file atau klik di sini untuk melampirkan file',
-    'attachments_no_files' => 'Tidak ada file yang telah diunggah',
-    'attachments_explain_link' => 'Anda dapat melampirkan link jika Anda memilih untuk tidak mengupload file. Ini bisa berupa tautan ke halaman lain atau tautan ke file di cloud.',
+    'attachments_no_files' => 'Tidak ada berkas yang telah diunggah',
+    'attachments_explain_link' => 'Anda dapat melampirkan sebuah tautan jika Anda memilih untuk tidak mengunggah berkas. Ini bisa berupa sebuah tautan ke halaman lain atau tautan ke sebuah berkas di cloud.',
     'attachments_link_name' => 'Nama Tautan',
     'attachment_link' => 'Lampiran Tautan',
     'attachments_link_url' => 'Tautan ke file',
-    'attachments_link_url_hint' => 'Url situs atau file',
+    'attachments_link_url_hint' => 'Alamat url situs atau berkas',
     'attach' => 'Melampirkan',
     'attachments_insert_link' => 'Tambahkan Tautan Lampiran ke Halaman',
     'attachments_edit_file' => 'Edit File',
     'attachments_edit_file_name' => 'Nama file',
-    'attachments_edit_drop_upload' => 'Lepaskan file atau klik di sini untuk mengupload dan menimpa',
+    'attachments_edit_drop_upload' => 'Jatuhkan berkas atau klik di sini untuk mengunggah dan menimpa',
     'attachments_order_updated' => 'Urutan lampiran diperbarui',
     'attachments_updated_success' => 'Detail lampiran diperbarui',
     'attachments_deleted' => 'Lampiran dihapus',
-    'attachments_file_uploaded' => 'File berhasil diunggah',
+    'attachments_file_uploaded' => 'Berkas berhasil diunggah',
     'attachments_file_updated' => 'File berhasil diperbarui',
     'attachments_link_attached' => 'Tautan berhasil dilampirkan ke halaman',
     'templates' => 'Template',
index a153c333de8548af8e23070c99bef314e62127a0..9244c96e17de2823d4aef3c82429dea2cacad76b 100644 (file)
@@ -15,42 +15,42 @@ return [
     'email_confirmation_expired' => 'Token konfirmasi telah kedaluwarsa, Email konfirmasi baru telah dikirim.',
     'email_confirmation_awaiting' => 'Alamat email untuk akun yang digunakan perlu dikonfirmasi',
     'ldap_fail_anonymous' => 'Akses LDAP gagal menggunakan pengikatan anonim',
-    'ldap_fail_authed' => 'Akses LDAP gagal menggunakan detail dn & sandi yang diberikan',
+    'ldap_fail_authed' => 'Akses LDAP gagal menggunakan rincian dn & sandi yang diberikan',
     'ldap_extension_not_installed' => 'Ekstensi LDAP PHP tidak terpasang',
     'ldap_cannot_connect' => 'Tidak dapat terhubung ke server ldap, Koneksi awal gagal',
     'saml_already_logged_in' => 'Telah masuk',
     'saml_user_not_registered' => 'Pengguna :name tidak terdaftar dan pendaftaran otomatis dinonaktifkan',
-    'saml_no_email_address' => 'Tidak dapat menemukan alamat email untuk pengguna ini dalam data yang diberikan oleh sistem autentikasi eksternal',
-    'saml_invalid_response_id' => 'Permintaan dari sistem otentikasi eksternal tidak dikenali oleh proses yang dimulai oleh aplikasi ini. Menavigasi kembali setelah masuk dapat menyebabkan masalah ini.',
-    'saml_fail_authed' => 'Login menggunakan :system gagal, sistem tidak memberikan otorisasi yang berhasil',
+    'saml_no_email_address' => 'Tidak dapat menemukan sebuah alamat email untuk pengguna ini, dalam data yang diberikan oleh sistem autentikasi eksternal',
+    'saml_invalid_response_id' => 'Permintaan dari sistem otentikasi eksternal tidak dikenali oleh sebuah proses yang dimulai oleh aplikasi ini. Menavigasi kembali setelah masuk dapat menyebabkan masalah ini.',
+    'saml_fail_authed' => 'Masuk menggunakan :system gagal, sistem tidak memberikan otorisasi yang berhasil',
     'social_no_action_defined' => 'Tidak ada tindakan yang ditentukan',
-    'social_login_bad_response' => "Kesalahan diterima selama :socialAccount :\n:error",
-    'social_account_in_use' => 'Ini:socialAccount sudah digunakan, Coba masuk melalui opsi :socialAccount.',
+    'social_login_bad_response' => "Kesalahan yang diterima selama masuk menggunakan :socialAccount : \n:error",
+    'social_account_in_use' => 'Akun :socialAccount ini sudah digunakan, Coba masuk melalui opsi :socialAccount.',
     'social_account_email_in_use' => 'Email :email sudah digunakan. Jika Anda sudah memiliki akun, Anda dapat menghubungkan :socialAccount Anda dari pengaturan profil Anda.',
-    'social_account_existing' => 'Akun ini :socialAccount sudah dilampirkan ke profil Anda.',
-    'social_account_already_used_existing' => 'Akun ini :socialAccount sudah digunakan oleh pengguna lain.',
-    'social_account_not_used' => 'Akun :socialAccount tidak ditautkan ke pengguna mana pun. Harap lampirkan di pengaturan profil Anda. ',
+    'social_account_existing' => 'Akun :socialAccount ini sudah dilampirkan ke profil Anda.',
+    'social_account_already_used_existing' => 'Akun :socialAccount ini sudah digunakan oleh pengguna lain.',
+    'social_account_not_used' => 'Akun :socialAccount ini tidak ditautkan ke pengguna mana pun. Harap lampirkan di dalam pengaturan profil Anda. ',
     'social_account_register_instructions' => 'Jika Anda belum memiliki akun, Anda dapat mendaftarkan akun menggunakan opsi :socialAccount.',
     'social_driver_not_found' => 'Pengemudi sosial tidak ditemukan',
     'social_driver_not_configured' => 'Pengaturan sosial :socialAccount Anda tidak dikonfigurasi dengan benar.',
     'invite_token_expired' => 'Tautan undangan ini telah kedaluwarsa. Sebagai gantinya, Anda dapat mencoba mengatur ulang kata sandi akun Anda.',
 
     // System
-    'path_not_writable' => 'Jalur file :filePath tidak dapat diunggah ke. Pastikan itu dapat ditulis ke server.',
-    'cannot_get_image_from_url' => 'Tidak bisa mendapatkan gambar dari :url',
+    'path_not_writable' => 'Jalur berkas :filePath tidak dapat diunggah. Pastikan berkas tersebut dapat ditulis ke server.',
+    'cannot_get_image_from_url' => 'Tidak dapat mengambil gambar dari :url',
     'cannot_create_thumbs' => 'Server tidak dapat membuat thumbnail. Harap periksa apakah Anda telah memasang ekstensi GD PHP.',
-    'server_upload_limit' => 'Server tidak mengizinkan unggahan dengan ukuran ini. Harap coba ukuran file yang lebih kecil.',
-    'uploaded'  => 'Server tidak mengizinkan unggahan dengan ukuran ini. Harap coba ukuran file yang lebih kecil.',
-    'image_upload_error' => 'Terjadi kesalahan saat mengupload gambar',
+    'server_upload_limit' => 'Server tidak mengizinkan unggahan dengan ukuran ini. Harap coba ukuran berkas yang lebih kecil.',
+    'uploaded'  => 'Server tidak mengizinkan unggahan dengan ukuran ini. Harap coba ukuran berkas yang lebih kecil.',
+    'image_upload_error' => 'Terjadi kesalahan saat mengunggah gambar',
     'image_upload_type_error' => 'Jenis gambar yang diunggah tidak valid',
-    'file_upload_timeout' => 'Waktu unggah file telah habis.',
+    'file_upload_timeout' => 'Unggahan berkas telah habis waktu.',
 
     // Attachments
     'attachment_not_found' => 'Lampiran tidak ditemukan',
 
     // Pages
     'page_draft_autosave_fail' => 'Gagal menyimpan draf. Pastikan Anda memiliki koneksi internet sebelum menyimpan halaman ini',
-    'page_custom_home_deletion' => 'Tidak dapat menghapus halaman saat disetel sebagai beranda',
+    'page_custom_home_deletion' => 'Tidak dapat menghapus sebuah halaman saat diatur sebagai sebuah halaman beranda',
 
     // Entities
     'entity_not_found' => 'Entitas tidak ditemukan',
@@ -67,7 +67,7 @@ return [
     'users_cannot_delete_guest' => 'Anda tidak dapat menghapus pengguna tamu',
 
     // Roles
-    'role_cannot_be_edited' => 'Peran ini tidak dapat diedit',
+    'role_cannot_be_edited' => 'Peran ini tidak dapat disunting',
     'role_system_cannot_be_deleted' => 'Peran ini adalah peran sistem dan tidak dapat dihapus',
     'role_registration_default_cannot_delete' => 'Peran ini tidak dapat dihapus jika disetel sebagai peran pendaftaran default',
     'role_cannot_remove_only_admin' => 'Pengguna ini adalah satu-satunya pengguna yang ditetapkan ke peran administrator. Tetapkan peran administrator untuk pengguna lain sebelum mencoba untuk menghapusnya di sini.',
@@ -83,9 +83,9 @@ return [
     '404_page_not_found' => 'Halaman tidak ditemukan',
     'sorry_page_not_found' => 'Maaf, Halaman yang Anda cari tidak dapat ditemukan.',
     'sorry_page_not_found_permission_warning' => 'Jika Anda mengharapkan halaman ini ada, Anda mungkin tidak memiliki izin untuk melihatnya.',
-    'image_not_found' => 'Image Not Found',
-    'image_not_found_subtitle' => 'Sorry, The image file you were looking for could not be found.',
-    'image_not_found_details' => 'If you expected this image to exist it might have been deleted.',
+    'image_not_found' => 'Gambar tidak ditemukan',
+    'image_not_found_subtitle' => 'Maaf, Berkas gambar yang Anda cari tidak dapat ditemukan.',
+    'image_not_found_details' => 'Jika Anda mengharapkan gambar ini ada, gambar itu mungkin telah dihapus.',
     'return_home' => 'Kembali ke home',
     'error_occurred' => 'Terjadi kesalahan',
     'app_down' => ':appName sedang down sekarang',
index 7c45a700487618764fbd15fb3f6c24d61edc72ec..80e8d38e15776f7df9c1f89f68472ac909d05949 100644 (file)
@@ -214,7 +214,7 @@ return [
     'user_api_token_update_success' => 'Token API berhasil diperbarui',
     'user_api_token' => 'Token API',
     'user_api_token_id' => 'Token ID',
-    'user_api_token_id_desc' => 'Ini adalah pengenal yang dibuat oleh sistem yang tidak dapat diedit untuk token ini yang perlu disediakan dalam permintaan API.',
+    'user_api_token_id_desc' => 'Ini adalah sebuah pengenal yang dihasilkan oleh sistem yang tidak dapat disunting untuk token ini yang perlu untuk disediakan dalam permintaan API.',
     'user_api_token_secret' => 'Token Secret',
     'user_api_token_secret_desc' => 'Ini adalah rahasia yang dihasilkan sistem untuk token ini yang perlu disediakan dalam permintaan API. Ini hanya akan ditampilkan kali ini jadi salin nilai ini ke tempat yang aman dan terlindungi.',
     'user_api_token_created' => 'Token dibuat :timeAgo',
index 10ac2900ece859b63ee09c08ac36cbca3715ebcd..2bd5cf7331a3373ae2ed3bdf88268961130c6038 100644 (file)
@@ -100,7 +100,7 @@ return [
     'timezone'             => ':attribute harus menjadi zona yang valid.',
     'unique'               => ':attribute sudah diambil.',
     'url'                  => ':attribute format tidak valid.',
-    'uploaded'             => 'File tidak dapat diunggah. Server mungkin tidak menerima file dengan ukuran ini.',
+    'uploaded'             => 'Berkas tidak dapat diunggah. Server mungkin tidak menerima berkas dengan ukuran ini.',
 
     // Custom validation lines
     'custom' => [
index dcceb3c6a58ed75876e9a003d1a75256d3653916..b883e0b6c4535cfe9a5d495780f0f7b1077e5f6c 100644 (file)
@@ -13,7 +13,7 @@ return [
     'sign_up' => '注册',
     'log_in' => '登录',
     'log_in_with' => '以:socialDriver登录',
-    'sign_up_with' => '注册:socialDriver',
+    'sign_up_with' => '通过 :socialDriver 账号登录',
     'logout' => '注销',
 
     'name' => '名称',
@@ -27,10 +27,10 @@ return [
     'ldap_email_hint' => '请输入用于此帐户的电子邮件。',
     'create_account' => '创建账户',
     'already_have_account' => '您已经有账号?',
-    'dont_have_account' => 'æ\82¨è¿\98没注å\86\8c?',
+    'dont_have_account' => 'æ\82¨è¿\98没æ\9c\89è´¦å\8f·å\90\97?',
     'social_login' => 'SNS登录',
-    'social_registration' => 'SNS注册',
-    'social_registration_text' => '其他服务注册/登录。',
+    'social_registration' => '使用社交网站账号注册',
+    'social_registration_text' => '使用其他服务注册并登录。',
 
     'register_thanks' => '注册完成!',
     'register_confirm' => '请点击查收您的Email,并点击确认。',
index 8c9be8290025932277c6f1c1436e67faa7479381..f0a1354ea1e513adda8ad44b1c8e03ed63c0a2a2 100644 (file)
@@ -1,8 +1,10 @@
-@foreach($attachments as $attachment)
-    <div class="attachment icon-list">
-        <a class="icon-list-item py-xs" href="{{ $attachment->getUrl() }}" @if($attachment->external) target="_blank" @endif>
-            <span class="icon">@icon($attachment->external ? 'export' : 'file')</span>
-            <span>{{ $attachment->name }}</span>
-        </a>
-    </div>
-@endforeach
\ No newline at end of file
+<div component="attachments-list">
+    @foreach($attachments as $attachment)
+        <div class="attachment icon-list">
+            <a class="icon-list-item py-xs attachment-{{ $attachment->external ? 'link' : 'file' }}" href="{{ $attachment->getUrl() }}" @if($attachment->external) target="_blank" @endif>
+                <span class="icon">@icon($attachment->external ? 'export' : 'file')</span>
+                <span>{{ $attachment->name }}</span>
+            </a>
+        </div>
+    @endforeach
+</div>
\ No newline at end of file
index d4d8ed76ba50bd47b83832ea8f04e17ebadca98a..c4a5dc78276b27be5f6ac1470b73caeb1e8fa624 100644 (file)
@@ -6,9 +6,11 @@
     <div class="card mb-xl px-l pb-l pt-l">
         <div class="grid half v-center">
             <div>
-                <h1 class="list-heading">{{ $message ?? trans('errors.404_page_not_found') }}</h1>
-                <h5>{{ $subtitle ?? trans('errors.sorry_page_not_found') }}</h5>
-                <p>{{ $details ?? trans('errors.sorry_page_not_found_permission_warning') }}</p>
+                @include('errors.parts.not-found-text', [
+                    'title' => $message ?? trans('errors.404_page_not_found'),
+                    'subtitle' => $subtitle ?? trans('errors.sorry_page_not_found'),
+                    'details' => $details ?? trans('errors.sorry_page_not_found_permission_warning'),
+                ])
             </div>
             <div class="text-right">
                 @if(!signedInUser())
diff --git a/resources/views/errors/parts/not-found-text.blade.php b/resources/views/errors/parts/not-found-text.blade.php
new file mode 100644 (file)
index 0000000..5b107b2
--- /dev/null
@@ -0,0 +1,5 @@
+{{--The below text may be dynamic based upon language and scenario.--}}
+{{--It's safer to add new text sections here rather than altering existing ones.--}}
+<h1 class="list-heading">{{ $title }}</h1>
+<h5>{{ $subtitle }}</h5>
+<p>{{ $details }}</p>
\ No newline at end of file
index 5858c3a79a775c972719353f6cdd1463cd245640..f9ba3d90e3b1d066bb05bc3c843c96d39df73b1e 100644 (file)
@@ -12,7 +12,7 @@ class ExportTest extends TestCase
 
     public function test_page_text_export()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asEditor();
 
         $resp = $this->get($page->getUrl('/export/plaintext'));
@@ -23,7 +23,7 @@ class ExportTest extends TestCase
 
     public function test_page_pdf_export()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asEditor();
 
         $resp = $this->get($page->getUrl('/export/pdf'));
@@ -33,7 +33,7 @@ class ExportTest extends TestCase
 
     public function test_page_html_export()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asEditor();
 
         $resp = $this->get($page->getUrl('/export/html'));
@@ -44,7 +44,7 @@ class ExportTest extends TestCase
 
     public function test_book_text_export()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $book = $page->book;
         $this->asEditor();
 
@@ -57,7 +57,7 @@ class ExportTest extends TestCase
 
     public function test_book_pdf_export()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $book = $page->book;
         $this->asEditor();
 
@@ -68,7 +68,7 @@ class ExportTest extends TestCase
 
     public function test_book_html_export()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $book = $page->book;
         $this->asEditor();
 
@@ -95,7 +95,7 @@ class ExportTest extends TestCase
 
     public function test_chapter_text_export()
     {
-        $chapter = Chapter::first();
+        $chapter = Chapter::query()->first();
         $page = $chapter->pages[0];
         $this->asEditor();
 
@@ -108,7 +108,7 @@ class ExportTest extends TestCase
 
     public function test_chapter_pdf_export()
     {
-        $chapter = Chapter::first();
+        $chapter = Chapter::query()->first();
         $this->asEditor();
 
         $resp = $this->get($chapter->getUrl('/export/pdf'));
@@ -118,7 +118,7 @@ class ExportTest extends TestCase
 
     public function test_chapter_html_export()
     {
-        $chapter = Chapter::first();
+        $chapter = Chapter::query()->first();
         $page = $chapter->pages[0];
         $this->asEditor();
 
@@ -131,7 +131,7 @@ class ExportTest extends TestCase
 
     public function test_page_html_export_contains_custom_head_if_set()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
 
         $customHeadContent = "<style>p{color: red;}</style>";
         $this->setSettings(['app-custom-head' => $customHeadContent]);
@@ -140,9 +140,21 @@ class ExportTest extends TestCase
         $resp->assertSee($customHeadContent);
     }
 
+    public function test_page_html_export_does_not_break_with_only_comments_in_custom_head()
+    {
+        $page = Page::query()->first();
+
+        $customHeadContent = "<!-- A comment -->";
+        $this->setSettings(['app-custom-head' => $customHeadContent]);
+
+        $resp = $this->asEditor()->get($page->getUrl('/export/html'));
+        $resp->assertStatus(200);
+        $resp->assertSee($customHeadContent);
+    }
+
     public function test_page_html_export_use_absolute_dates()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
 
         $resp = $this->asEditor()->get($page->getUrl('/export/html'));
         $resp->assertSee($page->created_at->formatLocalized('%e %B %Y %H:%M:%S'));
@@ -153,7 +165,7 @@ class ExportTest extends TestCase
 
     public function test_page_export_does_not_include_user_or_revision_links()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
 
         $resp = $this->asEditor()->get($page->getUrl('/export/html'));
         $resp->assertDontSee($page->getUrl('/revisions'));
@@ -163,7 +175,7 @@ class ExportTest extends TestCase
 
     public function test_page_export_sets_right_data_type_for_svg_embeds()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         Storage::disk('local')->makeDirectory('uploads/images/gallery');
         Storage::disk('local')->put('uploads/images/gallery/svg_test.svg', '<svg></svg>');
         $page->html = '<img src="http://localhost/uploads/images/gallery/svg_test.svg">';
@@ -179,7 +191,7 @@ class ExportTest extends TestCase
 
     public function test_page_image_containment_works_on_multiple_images_within_a_single_line()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         Storage::disk('local')->makeDirectory('uploads/images/gallery');
         Storage::disk('local')->put('uploads/images/gallery/svg_test.svg', '<svg></svg>');
         Storage::disk('local')->put('uploads/images/gallery/svg_test2.svg', '<svg></svg>');
@@ -195,7 +207,7 @@ class ExportTest extends TestCase
 
     public function test_page_export_contained_html_image_fetches_only_run_when_url_points_to_image_upload_folder()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $page->html = '<img src="http://localhost/uploads/images/gallery/svg_test.svg"/>'
             .'<img src="http://localhost/uploads/svg_test.svg"/>'
             .'<img src="/uploads/svg_test.svg"/>';
@@ -233,7 +245,7 @@ class ExportTest extends TestCase
     public function test_page_export_with_deleted_creator_and_updater()
     {
         $user = $this->getViewer(['name' => 'ExportWizardTheFifth']);
-        $page = Page::first();
+        $page = Page::query()->first();
         $page->created_by = $user->id;
         $page->updated_by = $user->id;
         $page->save();
index 1b3af97c7c836de91dec418c5e78de57ecbd6233..f1462dbd08a61ecd07770a47d612e546368b3ddf 100644 (file)
@@ -13,8 +13,8 @@ class PageContentTest extends TestCase
 
     public function test_page_includes()
     {
-        $page = Page::first();
-        $secondPage = Page::where('id', '!=', $page->id)->first();
+        $page = Page::query()->first();
+        $secondPage = Page::query()->where('id', '!=', $page->id)->first();
 
         $secondPage->html = "<p id='section1'>Hello, This is a test</p><p id='section2'>This is a second block of content</p>";
         $secondPage->save();
@@ -42,8 +42,8 @@ class PageContentTest extends TestCase
 
     public function test_saving_page_with_includes()
     {
-        $page = Page::first();
-        $secondPage = Page::where('id', '!=', $page->id)->first();
+        $page = Page::query()->first();
+        $secondPage = Page::query()->where('id', '!=', $page->id)->first();
 
         $this->asEditor();
         $includeTag = '{{@' . $secondPage->id . '}}';
@@ -60,8 +60,8 @@ class PageContentTest extends TestCase
 
     public function test_page_includes_do_not_break_tables()
     {
-        $page = Page::first();
-        $secondPage = Page::where('id', '!=', $page->id)->first();
+        $page = Page::query()->first();
+        $secondPage = Page::query()->where('id', '!=', $page->id)->first();
 
         $content = '<table id="table"><tbody><tr><td>test</td></tr></tbody></table>';
         $secondPage->html = $content;
@@ -97,7 +97,7 @@ class PageContentTest extends TestCase
     public function test_page_content_scripts_removed_by_default()
     {
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
         $script = 'abc123<script>console.log("hello-test")</script>abc123';
         $page->html = "escape {$script}";
         $page->save();
@@ -120,7 +120,7 @@ class PageContentTest extends TestCase
         ];
 
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
 
         foreach ($checks as $check) {
             $page->html = $check;
@@ -145,7 +145,7 @@ class PageContentTest extends TestCase
         ];
 
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
 
         foreach ($checks as $check) {
             $page->html = $check;
@@ -171,7 +171,7 @@ class PageContentTest extends TestCase
         ];
 
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
 
         foreach ($checks as $check) {
             $page->html = $check;
@@ -192,7 +192,7 @@ class PageContentTest extends TestCase
         ];
 
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
 
         foreach ($checks as $check) {
             $page->html = $check;
@@ -215,7 +215,7 @@ class PageContentTest extends TestCase
         ];
 
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
 
         foreach ($checks as $check) {
             $page->html = $check;
@@ -232,7 +232,7 @@ class PageContentTest extends TestCase
     public function test_page_inline_on_attributes_removed_by_default()
     {
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
         $script = '<p onmouseenter="console.log(\'test\')">Hello</p>';
         $page->html = "escape {$script}";
         $page->save();
@@ -255,7 +255,7 @@ class PageContentTest extends TestCase
         ];
 
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
 
         foreach ($checks as $check) {
             $page->html = $check;
@@ -271,7 +271,7 @@ class PageContentTest extends TestCase
     public function test_page_content_scripts_show_when_configured()
     {
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
         config()->push('app.allow_content_scripts', 'true');
 
         $script = 'abc123<script>console.log("hello-test")</script>abc123';
@@ -286,7 +286,7 @@ class PageContentTest extends TestCase
     public function test_page_inline_on_attributes_show_if_configured()
     {
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
         config()->push('app.allow_content_scripts', 'true');
 
         $script = '<p onmouseenter="console.log(\'test\')">Hello</p>';
@@ -301,7 +301,7 @@ class PageContentTest extends TestCase
     public function test_duplicate_ids_does_not_break_page_render()
     {
         $this->asEditor();
-        $pageA = Page::first();
+        $pageA = Page::query()->first();
         $pageB = Page::query()->where('id', '!=', $pageA->id)->first();
 
         $content = '<ul id="bkmrk-xxx-%28"></ul> <ul id="bkmrk-xxx-%28"></ul>';
@@ -318,7 +318,7 @@ class PageContentTest extends TestCase
     public function test_duplicate_ids_fixed_on_page_save()
     {
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
 
         $content = '<ul id="bkmrk-test"><li>test a</li><li><ul id="bkmrk-test"><li>test b</li></ul></li></ul>';
         $pageSave = $this->put($page->getUrl(), [
@@ -328,14 +328,14 @@ class PageContentTest extends TestCase
         ]);
         $pageSave->assertRedirect();
 
-        $updatedPage = Page::where('id', '=', $page->id)->first();
+        $updatedPage = Page::query()->where('id', '=', $page->id)->first();
         $this->assertEquals(substr_count($updatedPage->html, "bkmrk-test\""), 1);
     }
 
     public function test_anchors_referencing_non_bkmrk_ids_rewritten_after_save()
     {
         $this->asEditor();
-        $page = Page::first();
+        $page = Page::query()->first();
 
         $content = '<h1 id="non-standard-id">test</h1><p><a href="#non-standard-id">link</a></p>';
         $this->put($page->getUrl(), [
@@ -344,7 +344,7 @@ class PageContentTest extends TestCase
             'summary' => ''
         ]);
 
-        $updatedPage = Page::where('id', '=', $page->id)->first();
+        $updatedPage = Page::query()->where('id', '=', $page->id)->first();
         $this->assertStringContainsString('id="bkmrk-test"', $updatedPage->html);
         $this->assertStringContainsString('href="#bkmrk-test"', $updatedPage->html);
     }
@@ -484,6 +484,25 @@ class PageContentTest extends TestCase
         $pageView->assertElementExists('.page-content p > s');
     }
 
+    public function test_page_markdown_single_html_comment_saving()
+    {
+        $this->asEditor();
+        $page = Page::query()->first();
+
+        $content = '<!-- Test Comment -->';
+        $this->put($page->getUrl(), [
+            'name' => $page->name,  'markdown' => $content,
+            'html' => '', 'summary' => ''
+        ]);
+
+        $page->refresh();
+        $this->assertStringMatchesFormat($content, $page->html);
+
+        $pageView = $this->get($page->getUrl());
+        $pageView->assertStatus(200);
+        $pageView->assertSee($content);
+    }
+
     public function test_base64_images_get_extracted_from_page_content()
     {
         $this->asEditor();
index 1ca9ea23b17d5d04101c2203173d394b3455b379..55a5aa84fed023e82f2c384d8b13327231dae8c2 100644 (file)
@@ -4,11 +4,9 @@ use BookStack\Entities\Tools\TrashCan;
 use BookStack\Entities\Repos\PageRepo;
 use BookStack\Uploads\Attachment;
 use BookStack\Entities\Models\Page;
-use BookStack\Auth\Permissions\PermissionService;
 use BookStack\Uploads\AttachmentService;
 use Illuminate\Http\UploadedFile;
 use Tests\TestCase;
-use Tests\TestResponse;
 
 class AttachmentTest extends TestCase
 {
@@ -57,7 +55,7 @@ class AttachmentTest extends TestCase
 
     public function test_file_upload()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asAdmin();
         $admin = $this->getAdmin();
         $fileName = 'upload_test_file.txt';
@@ -85,7 +83,7 @@ class AttachmentTest extends TestCase
 
     public function test_file_upload_does_not_use_filename()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $fileName = 'upload_test_file.txt';
 
 
@@ -99,7 +97,7 @@ class AttachmentTest extends TestCase
 
     public function test_file_display_and_access()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asAdmin();
         $fileName = 'upload_test_file.txt';
 
@@ -119,7 +117,7 @@ class AttachmentTest extends TestCase
 
     public function test_attaching_link_to_page()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $admin = $this->getAdmin();
         $this->asAdmin();
 
@@ -156,7 +154,7 @@ class AttachmentTest extends TestCase
 
     public function test_attachment_updating()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asAdmin();
 
         $attachment = $this->createAttachment($page);
@@ -180,7 +178,7 @@ class AttachmentTest extends TestCase
 
     public function test_file_deletion()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asAdmin();
         $fileName = 'deletion_test.txt';
         $this->uploadFile($fileName, $page->id);
@@ -202,7 +200,7 @@ class AttachmentTest extends TestCase
 
     public function test_attachment_deletion_on_page_deletion()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asAdmin();
         $fileName = 'deletion_test.txt';
         $this->uploadFile($fileName, $page->id);
@@ -230,7 +228,7 @@ class AttachmentTest extends TestCase
     {
         $admin = $this->getAdmin();
         $viewer = $this->getViewer();
-        $page = Page::first(); /** @var Page $page */
+        $page = Page::query()->first(); /** @var Page $page */
 
         $this->actingAs($admin);
         $fileName = 'permission_test.txt';
@@ -253,7 +251,7 @@ class AttachmentTest extends TestCase
 
     public function test_data_and_js_links_cannot_be_attached_to_a_page()
     {
-        $page = Page::first();
+        $page = Page::query()->first();
         $this->asAdmin();
 
         $badLinks = [
@@ -291,4 +289,22 @@ class AttachmentTest extends TestCase
             ]);
         }
     }
+
+    public function test_file_access_with_open_query_param_provides_inline_response_with_correct_content_type()
+    {
+        $page = Page::query()->first();
+        $this->asAdmin();
+        $fileName = 'upload_test_file.txt';
+
+        $upload = $this->uploadFile($fileName, $page->id);
+        $upload->assertStatus(200);
+        $attachment = Attachment::query()->orderBy('id', 'desc')->take(1)->first();
+
+        $attachmentGet = $this->get($attachment->getUrl(true));
+        // http-foundation/Response does some 'fixing' of responses to add charsets to text responses.
+        $attachmentGet->assertHeader('Content-Type', 'text/plain; charset=UTF-8');
+        $attachmentGet->assertHeader('Content-Disposition', "inline; filename=\"upload_test_file.txt\"");
+
+        $this->deleteUploads();
+    }
 }