From 07c7d5af176a2071b2151737567283eb22c485ef Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 13 Aug 2016 10:02:54 +0100 Subject: [PATCH 1/6] Updated elixr and fixed table th element borders Fixes #164. --- package.json | 2 +- resources/assets/sass/_html.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c387d1317..fde090beb 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "babel-runtime": "^5.8.29", "bootstrap-sass": "^3.0.0", "dropzone": "^4.0.1", - "laravel-elixir": "^3.4.0", + "laravel-elixir": "^5.0.0", "marked": "^0.3.5", "moment": "^2.12.0", "zeroclipboard": "^2.2.0" diff --git a/resources/assets/sass/_html.scss b/resources/assets/sass/_html.scss index ea97a4dd2..2b91f9dc6 100644 --- a/resources/assets/sass/_html.scss +++ b/resources/assets/sass/_html.scss @@ -23,7 +23,7 @@ button { table { min-width: 100px; - td { + td, th { min-width: 10px; padding: 4px 6px; border: 1px solid #DDD; From 2d958e88bfc5a24e91223e328322b6d21d74215d Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 13 Aug 2016 13:53:04 +0100 Subject: [PATCH 2/6] Fixed entities created with blank slugs. Fixes #156. --- app/Repos/BookRepo.php | 16 +++++++--------- app/Repos/ChapterRepo.php | 3 ++- app/Repos/PageRepo.php | 11 ++++++----- tests/Entity/EntityTest.php | 6 ++++-- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/Repos/BookRepo.php b/app/Repos/BookRepo.php index a11ed2763..58816d738 100644 --- a/app/Repos/BookRepo.php +++ b/app/Repos/BookRepo.php @@ -216,12 +216,10 @@ class BookRepo extends EntityRepo */ public function findSuitableSlug($name, $currentId = false) { - $originalSlug = Str::slug($name); - $slug = $originalSlug; - $count = 2; + $slug = Str::slug($name); + if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5); while ($this->doesSlugExist($slug, $currentId)) { - $slug = $originalSlug . '-' . $count; - $count++; + $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); } return $slug; } @@ -229,7 +227,7 @@ class BookRepo extends EntityRepo /** * Get all child objects of a book. * Returns a sorted collection of Pages and Chapters. - * Loads the bookslug onto child elements to prevent access database access for getting the slug. + * Loads the book slug onto child elements to prevent access database access for getting the slug. * @param Book $book * @param bool $filterDrafts * @return mixed @@ -245,7 +243,7 @@ class BookRepo extends EntityRepo $pages = $pageQuery->get(); - $chapterQuery = $book->chapters()->with(['pages' => function($query) use ($filterDrafts) { + $chapterQuery = $book->chapters()->with(['pages' => function ($query) use ($filterDrafts) { $this->permissionService->enforcePageRestrictions($query, 'view'); if ($filterDrafts) $query->where('draft', '=', false); }]); @@ -263,7 +261,7 @@ class BookRepo extends EntityRepo $child->pages->each(function ($page) use ($bookSlug) { $page->setAttribute('bookSlug', $bookSlug); }); - $child->pages = $child->pages->sortBy(function($child, $key) { + $child->pages = $child->pages->sortBy(function ($child, $key) { $score = $child->priority; if ($child->draft) $score -= 100; return $score; @@ -272,7 +270,7 @@ class BookRepo extends EntityRepo }); // Sort items with drafts first then by priority. - return $children->sortBy(function($child, $key) { + return $children->sortBy(function ($child, $key) { $score = $child->priority; if ($child->isA('page') && $child->draft) $score -= 100; return $score; diff --git a/app/Repos/ChapterRepo.php b/app/Repos/ChapterRepo.php index 3c518bde9..1a8cbdf0f 100644 --- a/app/Repos/ChapterRepo.php +++ b/app/Repos/ChapterRepo.php @@ -81,7 +81,7 @@ class ChapterRepo extends EntityRepo { $pages = $this->permissionService->enforcePageRestrictions($chapter->pages())->get(); // Sort items with drafts first then by priority. - return $pages->sortBy(function($child, $key) { + return $pages->sortBy(function ($child, $key) { $score = $child->priority; if ($child->draft) $score -= 100; return $score; @@ -151,6 +151,7 @@ class ChapterRepo extends EntityRepo public function findSuitableSlug($name, $bookId, $currentId = false) { $slug = Str::slug($name); + if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5); while ($this->doesSlugExist($slug, $bookId, $currentId)) { $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); } diff --git a/app/Repos/PageRepo.php b/app/Repos/PageRepo.php index de050e1c7..3698e5efb 100644 --- a/app/Repos/PageRepo.php +++ b/app/Repos/PageRepo.php @@ -147,7 +147,7 @@ class PageRepo extends EntityRepo $draftPage->fill($input); // Save page tags if present - if(isset($input['tags'])) { + if (isset($input['tags'])) { $this->tagRepo->saveTagsToEntity($draftPage, $input['tags']); } @@ -319,7 +319,7 @@ class PageRepo extends EntityRepo } // Save page tags if present - if(isset($input['tags'])) { + if (isset($input['tags'])) { $this->tagRepo->saveTagsToEntity($page, $input['tags']); } @@ -405,7 +405,7 @@ class PageRepo extends EntityRepo $draft->fill($data); if (setting('app-editor') !== 'markdown') $draft->markdown = ''; - + $draft->save(); return $draft; } @@ -591,14 +591,15 @@ class PageRepo extends EntityRepo /** * Gets a suitable slug for the resource - * @param $name - * @param $bookId + * @param string $name + * @param int $bookId * @param bool|false $currentId * @return string */ public function findSuitableSlug($name, $bookId, $currentId = false) { $slug = Str::slug($name); + if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5); while ($this->doesSlugExist($slug, $bookId, $currentId)) { $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); } diff --git a/tests/Entity/EntityTest.php b/tests/Entity/EntityTest.php index 3bf6a3f2a..71d83dd47 100644 --- a/tests/Entity/EntityTest.php +++ b/tests/Entity/EntityTest.php @@ -151,8 +151,10 @@ class EntityTest extends TestCase ->visit('/books/create') ->type($book->name, '#name') ->type($book->description, '#description') - ->press('Save Book') - ->seePageIs('/books/my-first-book-2'); + ->press('Save Book'); + + $expectedPattern = '/\/books\/my-first-book-[0-9a-zA-Z]{3}/'; + $this->assertRegExp($expectedPattern, $this->currentUri, "Did not land on expected page [$expectedPattern].\n"); $book = \BookStack\Book::where('slug', '=', 'my-first-book')->first(); return $book; From b246a67e8a10311337f34dc751f3676011e9ef29 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 13 Aug 2016 14:18:31 +0100 Subject: [PATCH 3/6] Fixed double brace issues in both editors. Double braces were being parsed by angular in both the WYSIWYG and markdown editor. Fixes #150 and fixes #155. --- resources/assets/js/directives.js | 9 ++++++--- resources/assets/sass/_tinymce.scss | 2 +- resources/views/pages/form.blade.php | 15 +++++++++++---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js index 0119ded42..8554da9f8 100644 --- a/resources/assets/js/directives.js +++ b/resources/assets/js/directives.js @@ -252,11 +252,14 @@ module.exports = function (ngApp, events) { link: function (scope, element, attrs) { // Set initial model content - var content = element.val(); + element = element.find('textarea').first(); + let content = element.val(); scope.mdModel = content; scope.mdChange(markdown(content)); - element.on('change input', (e) => { + console.log('test'); + + element.on('change input', (event) => { content = element.val(); $timeout(() => { scope.mdModel = content; @@ -284,7 +287,7 @@ module.exports = function (ngApp, events) { link: function (scope, element, attrs) { // Elements - const input = element.find('textarea[markdown-input]'); + const input = element.find('[markdown-input] textarea').first(); const display = element.find('.markdown-display').first(); const insertImage = element.find('button[data-action="insertImage"]'); diff --git a/resources/assets/sass/_tinymce.scss b/resources/assets/sass/_tinymce.scss index 2c3571d4b..dd0bf7950 100644 --- a/resources/assets/sass/_tinymce.scss +++ b/resources/assets/sass/_tinymce.scss @@ -24,7 +24,7 @@ text-align: center; } -.edit-area.flex > .mce-tinymce.mce-container.mce-panel { +.edit-area.flex > div > .mce-tinymce.mce-container.mce-panel { height: 100%; max-height: 100%; flex: 1; diff --git a/resources/views/pages/form.blade.php b/resources/views/pages/form.blade.php index 4196e946f..6529f044b 100644 --- a/resources/views/pages/form.blade.php +++ b/resources/views/pages/form.blade.php @@ -44,8 +44,11 @@
@if(setting('app-editor') === 'wysiwyg') - +
+ +
+ @if($errors->has('html'))
{{ $errors->first('html') }}
@endif @@ -61,8 +64,12 @@
- + +
+ +
+
From b157a9927ac4a56024bed38c62bc861af4fe9eac Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 13 Aug 2016 14:54:23 +0100 Subject: [PATCH 4/6] Fixed tag section and editor safari rendering. Fixes #152. --- resources/assets/sass/_pages.scss | 4 ++-- resources/assets/sass/_tinymce.scss | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/resources/assets/sass/_pages.scss b/resources/assets/sass/_pages.scss index 49b701dda..d70e0cb3c 100644 --- a/resources/assets/sass/_pages.scss +++ b/resources/assets/sass/_pages.scss @@ -158,8 +158,8 @@ .tabs { display: block; border-right: 1px solid #DDD; - width: 54px; - flex: 0; + width: 48px; + flex: 0 1 auto; } .tabs i { color: rgba(0, 0, 0, 0.5); diff --git a/resources/assets/sass/_tinymce.scss b/resources/assets/sass/_tinymce.scss index dd0bf7950..969bbc968 100644 --- a/resources/assets/sass/_tinymce.scss +++ b/resources/assets/sass/_tinymce.scss @@ -25,20 +25,21 @@ } .edit-area.flex > div > .mce-tinymce.mce-container.mce-panel { - height: 100%; - max-height: 100%; - flex: 1; + flex: 1 1 auto; display: flex !important; flex-direction: column; align-items: stretch; margin: 0 -1px; > .mce-container-body { - flex: 1; + flex: 1 1 auto; display: flex !important; flex-direction: column; align-items: stretch; + > .mce-toolbar-grp { + flex: 0 1 auto; + } > .mce-edit-area { - flex: 1; + flex: 1 1 auto; display: flex !important; flex-direction: column; align-items: stretch; From baa260a03d872c59e8dd086a0969522df5e492d4 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 13 Aug 2016 17:56:20 +0100 Subject: [PATCH 5/6] Started work on subdirectory support --- app/Book.php | 2 +- app/Chapter.php | 2 +- app/Page.php | 2 +- app/User.php | 6 +++--- app/helpers.php | 15 +++++++++++++-- config/app.php | 2 +- resources/views/base.blade.php | 24 ++++++++++++------------ 7 files changed, 32 insertions(+), 21 deletions(-) diff --git a/app/Book.php b/app/Book.php index 919af80a5..af6d59bfd 100644 --- a/app/Book.php +++ b/app/Book.php @@ -11,7 +11,7 @@ class Book extends Entity */ public function getUrl() { - return '/books/' . $this->slug; + return baseUrl('/books/' . $this->slug); } /* diff --git a/app/Chapter.php b/app/Chapter.php index 08faef68e..250e323f5 100644 --- a/app/Chapter.php +++ b/app/Chapter.php @@ -30,7 +30,7 @@ class Chapter extends Entity public function getUrl() { $bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug; - return '/books/' . $bookSlug. '/chapter/' . $this->slug; + return baseUrl('/books/' . $bookSlug. '/chapter/' . $this->slug); } /** diff --git a/app/Page.php b/app/Page.php index c6978d34b..5902f4f5a 100644 --- a/app/Page.php +++ b/app/Page.php @@ -63,7 +63,7 @@ class Page extends Entity $bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug; $midText = $this->draft ? '/draft/' : '/page/'; $idComponent = $this->draft ? $this->id : $this->slug; - return '/books/' . $bookSlug . $midText . $idComponent; + return baseUrl('/books/' . $bookSlug . $midText . $idComponent); } /** diff --git a/app/User.php b/app/User.php index 74aec7e3a..6ab7ad3bf 100644 --- a/app/User.php +++ b/app/User.php @@ -138,8 +138,8 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ public function getAvatar($size = 50) { - if ($this->image_id === 0 || $this->image_id === '0' || $this->image_id === null) return '/user_avatar.png'; - return $this->avatar->getThumb($size, $size, false); + if ($this->image_id === 0 || $this->image_id === '0' || $this->image_id === null) return baseUrl('/user_avatar.png'); + return baseUrl($this->avatar->getThumb($size, $size, false)); } /** @@ -157,7 +157,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ public function getEditUrl() { - return '/settings/users/' . $this->id; + return baseUrl('/settings/users/' . $this->id); } /** diff --git a/app/helpers.php b/app/helpers.php index 42e4c1894..0b9a6afc6 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -20,11 +20,11 @@ if (!function_exists('versioned_asset')) { } if (isset($manifest[$file])) { - return '/' . $manifest[$file]; + return baseUrl($manifest[$file]); } if (file_exists(public_path($file))) { - return '/' . $file; + return baseUrl($file); } throw new InvalidArgumentException("File {$file} not defined in asset manifest."); @@ -62,6 +62,17 @@ function setting($key, $default = false) return $settingService->get($key, $default); } +/** + * Helper to create url's relative to the applications root path. + * @param $path + * @return string + */ +function baseUrl($path) +{ + $path = trim($path, '/'); + return rtrim(config('app.url'), '/') . '/' . $path; +} + /** * Generate a url with multiple parameters for sorting purposes. * Works out the logic to set the correct sorting direction diff --git a/config/app.php b/config/app.php index d305af3c0..6819fa481 100644 --- a/config/app.php +++ b/config/app.php @@ -31,7 +31,7 @@ return [ | */ - 'url' => env('APP_URL', 'http://localhost'), + 'url' => env('APP_URL', '') === 'http://bookstack.dev' ? '' : env('APP_URL', ''), /* |-------------------------------------------------------------------------- diff --git a/resources/views/base.blade.php b/resources/views/base.blade.php index d09912c37..e9ed436c5 100644 --- a/resources/views/base.blade.php +++ b/resources/views/base.blade.php @@ -11,11 +11,11 @@ - + - - + + @yield('head') @@ -34,15 +34,15 @@
- @@ -50,12 +50,12 @@
@if(isset($signedIn) && $signedIn) @@ -66,13 +66,13 @@
From 43d9d2eba76528dc1bcaccb6896b110faa920cff Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 14 Aug 2016 12:29:35 +0100 Subject: [PATCH 6/6] Updated all application urls to allow path prefix. Allows BookStack to be installed at a non-root location on a domain. Closes #40. --- .env.example | 6 +- app/Book.php | 6 +- app/Chapter.php | 6 +- app/Exceptions/Handler.php | 4 +- app/Http/Controllers/Auth/AuthController.php | 8 +- app/Http/Controllers/PageController.php | 4 +- app/Http/Middleware/Authenticate.php | 2 +- app/Page.php | 8 +- app/Providers/PaginationServiceProvider.php | 30 +++ app/Repos/ImageRepo.php | 6 +- app/Services/ImageService.php | 2 +- app/Services/SocialAuthService.php | 7 +- app/User.php | 9 + app/helpers.php | 25 +- bootstrap/autoload.php | 1 + composer.json | 5 +- config/app.php | 3 +- config/setting-defaults.php | 5 +- readme.md | 1 + resources/assets/js/controllers.js | 28 ++- resources/assets/js/directives.js | 33 +-- resources/assets/js/global.js | 9 + resources/assets/js/pages/page-form.js | 6 +- resources/assets/js/pages/page-show.js | 5 +- resources/assets/sass/_fonts.scss | 44 ++-- .../views/auth/forms/login/standard.blade.php | 2 +- resources/views/auth/login.blade.php | 10 +- resources/views/auth/password.blade.php | 4 +- .../views/auth/register-confirm.blade.php | 4 +- resources/views/auth/register.blade.php | 8 +- resources/views/auth/reset.blade.php | 2 +- .../views/auth/user-unconfirmed.blade.php | 2 +- resources/views/base.blade.php | 5 +- resources/views/books/create.blade.php | 2 +- resources/views/books/edit.blade.php | 2 +- resources/views/books/index.blade.php | 4 +- resources/views/books/show.blade.php | 20 +- resources/views/books/sort.blade.php | 8 +- resources/views/chapters/create.blade.php | 2 +- resources/views/chapters/delete.blade.php | 4 +- resources/views/chapters/edit.blade.php | 2 +- resources/views/chapters/list-item.blade.php | 2 +- resources/views/chapters/move.blade.php | 6 +- .../views/chapters/restrictions.blade.php | 2 +- resources/views/chapters/show.blade.php | 24 +- .../views/emails/email-confirmation.blade.php | 218 ++++++++++-------- resources/views/emails/password.blade.php | 2 +- resources/views/errors/404.blade.php | 2 +- resources/views/errors/503.blade.php | 51 +--- .../views/form/restriction-form.blade.php | 2 +- resources/views/home.blade.php | 4 +- resources/views/pages/delete.blade.php | 4 +- resources/views/pages/edit.blade.php | 4 +- resources/views/pages/form-toolbox.blade.php | 4 +- resources/views/pages/form.blade.php | 2 +- resources/views/pages/move.blade.php | 8 +- resources/views/pages/page-display.blade.php | 4 +- resources/views/pages/restrictions.blade.php | 6 +- resources/views/pages/revisions.blade.php | 6 +- resources/views/pages/show.blade.php | 33 +-- .../views/pages/sidebar-tree-list.blade.php | 6 +- .../views/partials/activity-item.blade.php | 6 +- .../views/partials/custom-styles.blade.php | 12 +- resources/views/partials/highlight.blade.php | 2 +- resources/views/public.blade.php | 30 ++- resources/views/search/all.blade.php | 14 +- .../views/search/entity-search-list.blade.php | 2 +- resources/views/settings/index.blade.php | 10 +- resources/views/settings/navbar.blade.php | 6 +- .../views/settings/roles/create.blade.php | 2 +- .../views/settings/roles/delete.blade.php | 6 +- resources/views/settings/roles/edit.blade.php | 4 +- resources/views/settings/roles/form.blade.php | 6 +- .../views/settings/roles/index.blade.php | 4 +- resources/views/users/create.blade.php | 4 +- resources/views/users/delete.blade.php | 6 +- resources/views/users/edit.blade.php | 14 +- resources/views/users/forms/ldap.blade.php | 2 +- .../views/users/forms/standard.blade.php | 2 +- resources/views/users/index.blade.php | 14 +- resources/views/users/profile.blade.php | 2 +- 81 files changed, 479 insertions(+), 403 deletions(-) create mode 100644 app/Providers/PaginationServiceProvider.php diff --git a/.env.example b/.env.example index 5661cda22..e44a46ef3 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,10 @@ APP_ENV=production APP_DEBUG=false APP_KEY=SomeRandomString +# The below url has to be set if using social auth options +# or if you are not using BookStack at the root path of your domain. +# APP_URL=http://bookstack.dev + # Database details DB_HOST=localhost DB_DATABASE=database_database @@ -42,8 +46,6 @@ GITHUB_APP_ID=false GITHUB_APP_SECRET=false GOOGLE_APP_ID=false GOOGLE_APP_SECRET=false -# URL used for social login redirects, NO TRAILING SLASH -APP_URL=http://bookstack.dev # External services such as Gravatar DISABLE_EXTERNAL_SERVICES=false diff --git a/app/Book.php b/app/Book.php index af6d59bfd..aa2dee9c0 100644 --- a/app/Book.php +++ b/app/Book.php @@ -7,10 +7,14 @@ class Book extends Entity /** * Get the url for this book. + * @param string|bool $path * @return string */ - public function getUrl() + public function getUrl($path = false) { + if ($path !== false) { + return baseUrl('/books/' . $this->slug . '/' . trim($path, '/')); + } return baseUrl('/books/' . $this->slug); } diff --git a/app/Chapter.php b/app/Chapter.php index 250e323f5..8f0453172 100644 --- a/app/Chapter.php +++ b/app/Chapter.php @@ -25,11 +25,15 @@ class Chapter extends Entity /** * Get the url of this chapter. + * @param string|bool $path * @return string */ - public function getUrl() + public function getUrl($path = false) { $bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug; + if ($path !== false) { + return baseUrl('/books/' . $bookSlug. '/chapter/' . $this->slug . '/' . trim($path, '/')); + } return baseUrl('/books/' . $bookSlug. '/chapter/' . $this->slug); } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 14d553ed0..40dd1ec10 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -48,8 +48,8 @@ class Handler extends ExceptionHandler // Handle notify exceptions which will redirect to the // specified location then show a notification message. if ($e instanceof NotifyException) { - \Session::flash('error', $e->message); - return response()->redirectTo($e->redirectLocation); + session()->flash('error', $e->message); + return redirect($e->redirectLocation); } // Handle pretty exceptions which will show a friendly application-fitting page diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php index beb191d62..2cbc047ce 100644 --- a/app/Http/Controllers/Auth/AuthController.php +++ b/app/Http/Controllers/Auth/AuthController.php @@ -1,9 +1,6 @@ -socialAuthService = $socialAuthService; $this->emailConfirmationService = $emailConfirmationService; $this->userRepo = $userRepo; + $this->redirectPath = baseUrl('/'); + $this->redirectAfterLogout = baseUrl('/login'); $this->username = config('auth.method') === 'standard' ? 'email' : 'username'; parent::__construct(); } diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index f35834e62..1509ace95 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -412,7 +412,7 @@ class PageController extends Controller */ public function showRecentlyCreated() { - $pages = $this->pageRepo->getRecentlyCreatedPaginated(20); + $pages = $this->pageRepo->getRecentlyCreatedPaginated(20)->setPath(baseUrl('/pages/recently-created')); return view('pages/detailed-listing', [ 'title' => 'Recently Created Pages', 'pages' => $pages @@ -425,7 +425,7 @@ class PageController extends Controller */ public function showRecentlyUpdated() { - $pages = $this->pageRepo->getRecentlyUpdatedPaginated(20); + $pages = $this->pageRepo->getRecentlyUpdatedPaginated(20)->setPath(baseUrl('/pages/recently-updated')); return view('pages/detailed-listing', [ 'title' => 'Recently Updated Pages', 'pages' => $pages diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index 599f40c84..ee5144e6c 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -33,7 +33,7 @@ class Authenticate public function handle($request, Closure $next) { if ($this->auth->check() && setting('registration-confirmation') && !$this->auth->user()->email_confirmed) { - return redirect()->guest('/register/confirm/awaiting'); + return redirect()->guest(baseUrl('/register/confirm/awaiting')); } if ($this->auth->guest() && !setting('app-public')) { diff --git a/app/Page.php b/app/Page.php index 5902f4f5a..1961a4f7f 100644 --- a/app/Page.php +++ b/app/Page.php @@ -56,13 +56,19 @@ class Page extends Entity /** * Get the url for this page. + * @param string|bool $path * @return string */ - public function getUrl() + public function getUrl($path = false) { $bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug; $midText = $this->draft ? '/draft/' : '/page/'; $idComponent = $this->draft ? $this->id : $this->slug; + + if ($path !== false) { + return baseUrl('/books/' . $bookSlug . $midText . $idComponent . '/' . trim($path, '/')); + } + return baseUrl('/books/' . $bookSlug . $midText . $idComponent); } diff --git a/app/Providers/PaginationServiceProvider.php b/app/Providers/PaginationServiceProvider.php new file mode 100644 index 000000000..a0e97f70d --- /dev/null +++ b/app/Providers/PaginationServiceProvider.php @@ -0,0 +1,30 @@ +app['request']->path()); + }); + + Paginator::currentPageResolver(function ($pageName = 'page') { + $page = $this->app['request']->input($pageName); + + if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { + return $page; + } + + return 1; + }); + } +} \ No newline at end of file diff --git a/app/Repos/ImageRepo.php b/app/Repos/ImageRepo.php index 916ebd3e1..435b8bbd7 100644 --- a/app/Repos/ImageRepo.php +++ b/app/Repos/ImageRepo.php @@ -13,7 +13,7 @@ class ImageRepo protected $image; protected $imageService; - protected $restictionService; + protected $restrictionService; protected $page; /** @@ -27,7 +27,7 @@ class ImageRepo { $this->image = $image; $this->imageService = $imageService; - $this->restictionService = $permissionService; + $this->restrictionService = $permissionService; $this->page = $page; } @@ -52,7 +52,7 @@ class ImageRepo */ private function returnPaginated($query, $page = 0, $pageSize = 24) { - $images = $this->restictionService->filterRelatedPages($query, 'images', 'uploaded_to'); + $images = $this->restrictionService->filterRelatedPages($query, 'images', 'uploaded_to'); $images = $images->orderBy('created_at', 'desc')->skip($pageSize * $page)->take($pageSize + 1)->get(); $hasMore = count($images) > $pageSize; diff --git a/app/Services/ImageService.php b/app/Services/ImageService.php index dd965c90f..d9bd61e9f 100644 --- a/app/Services/ImageService.php +++ b/app/Services/ImageService.php @@ -265,7 +265,7 @@ class ImageService $this->storageUrl = $storageUrl; } - return ($this->storageUrl == false ? '' : rtrim($this->storageUrl, '/')) . $filePath; + return ($this->storageUrl == false ? rtrim(baseUrl(''), '/') : rtrim($this->storageUrl, '/')) . $filePath; } diff --git a/app/Services/SocialAuthService.php b/app/Services/SocialAuthService.php index ba3479349..4b99df789 100644 --- a/app/Services/SocialAuthService.php +++ b/app/Services/SocialAuthService.php @@ -113,20 +113,20 @@ class SocialAuthService if ($isLoggedIn && $socialAccount === null) { $this->fillSocialAccount($socialDriver, $socialUser); $currentUser->socialAccounts()->save($this->socialAccount); - \Session::flash('success', title_case($socialDriver) . ' account was successfully attached to your profile.'); + session()->flash('success', title_case($socialDriver) . ' account was successfully attached to your profile.'); return redirect($currentUser->getEditUrl()); } // When a user is logged in and the social account exists and is already linked to the current user. if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id === $currentUser->id) { - \Session::flash('error', 'This ' . title_case($socialDriver) . ' account is already attached to your profile.'); + session()->flash('error', 'This ' . title_case($socialDriver) . ' account is already attached to your profile.'); return redirect($currentUser->getEditUrl()); } // When a user is logged in, A social account exists but the users do not match. // Change the user that the social account is assigned to. if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id != $currentUser->id) { - \Session::flash('success', 'This ' . title_case($socialDriver) . ' account is already used by another user.'); + session()->flash('success', 'This ' . title_case($socialDriver) . ' account is already used by another user.'); return redirect($currentUser->getEditUrl()); } @@ -135,6 +135,7 @@ class SocialAuthService if (setting('registration-enabled')) { $message .= ' or, If you do not yet have an account, You can register an account using the ' . $socialDriver . ' option'; } + throw new SocialSignInException($message . '.', '/login'); } diff --git a/app/User.php b/app/User.php index 6ab7ad3bf..32449971d 100644 --- a/app/User.php +++ b/app/User.php @@ -160,6 +160,15 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon return baseUrl('/settings/users/' . $this->id); } + /** + * Get the url that links to this user's profile. + * @return mixed + */ + public function getProfileUrl() + { + return baseUrl('/user/' . $this->id); + } + /** * Get a shortened version of the user's name. * @param int $chars diff --git a/app/helpers.php b/app/helpers.php index 0b9a6afc6..541f23fbe 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -69,10 +69,33 @@ function setting($key, $default = false) */ function baseUrl($path) { + if (strpos($path, 'http') === 0) return $path; $path = trim($path, '/'); return rtrim(config('app.url'), '/') . '/' . $path; } +/** + * Get an instance of the redirector. + * Overrides the default laravel redirect helper. + * Ensures it redirects even when the app is in a subdirectory. + * + * @param string|null $to + * @param int $status + * @param array $headers + * @param bool $secure + * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse + */ +function redirect($to = null, $status = 302, $headers = [], $secure = null) +{ + if (is_null($to)) { + return app('redirect'); + } + + $to = baseUrl($to); + + return app('redirect')->to($to, $status, $headers, $secure); +} + /** * Generate a url with multiple parameters for sorting purposes. * Works out the logic to set the correct sorting direction @@ -102,5 +125,5 @@ function sortUrl($path, $data, $overrideData = []) if (count($queryStringSections) === 0) return $path; - return $path . '?' . implode('&', $queryStringSections); + return baseUrl($path . '?' . implode('&', $queryStringSections)); } \ No newline at end of file diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php index 383013796..29f66ace4 100644 --- a/bootstrap/autoload.php +++ b/bootstrap/autoload.php @@ -14,6 +14,7 @@ define('LARAVEL_START', microtime(true)); | */ +require __DIR__.'/../app/helpers.php'; require __DIR__.'/../vendor/autoload.php'; /* diff --git a/composer.json b/composer.json index 8f375a279..5c77a68c4 100644 --- a/composer.json +++ b/composer.json @@ -29,10 +29,7 @@ ], "psr-4": { "BookStack\\": "app/" - }, - "files": [ - "app/helpers.php" - ] + } }, "autoload-dev": { "classmap": [ diff --git a/config/app.php b/config/app.php index 6819fa481..0d6f6f2b0 100644 --- a/config/app.php +++ b/config/app.php @@ -130,7 +130,6 @@ return [ Illuminate\Foundation\Providers\FoundationServiceProvider::class, Illuminate\Hashing\HashServiceProvider::class, Illuminate\Mail\MailServiceProvider::class, - Illuminate\Pagination\PaginationServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, @@ -153,6 +152,8 @@ return [ /* * Application Service Providers... */ + BookStack\Providers\PaginationServiceProvider::class, + BookStack\Providers\AuthServiceProvider::class, BookStack\Providers\AppServiceProvider::class, BookStack\Providers\EventServiceProvider::class, diff --git a/config/setting-defaults.php b/config/setting-defaults.php index 6a55a0dc3..24a49c364 100644 --- a/config/setting-defaults.php +++ b/config/setting-defaults.php @@ -5,8 +5,9 @@ */ return [ - 'app-editor' => 'wysiwyg', - 'app-color' => '#0288D1', + 'app-name' => 'BookStack', + 'app-editor' => 'wysiwyg', + 'app-color' => '#0288D1', 'app-color-light' => 'rgba(21, 101, 192, 0.15)' ]; \ No newline at end of file diff --git a/readme.md b/readme.md index 29ac44f5e..3a745beb1 100644 --- a/readme.md +++ b/readme.md @@ -50,3 +50,4 @@ These are the great projects used to help build BookStack: * [ZeroClipboard](http://zeroclipboard.org/) * [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html) * [Marked](https://github.com/chjj/marked) +* [Moment.js](http://momentjs.com/) diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js index 406fd7e77..9067f6ca4 100644 --- a/resources/assets/js/controllers.js +++ b/resources/assets/js/controllers.js @@ -1,6 +1,6 @@ "use strict"; -var moment = require('moment'); +const moment = require('moment'); module.exports = function (ngApp, events) { @@ -35,7 +35,7 @@ module.exports = function (ngApp, events) { * @returns {string} */ $scope.getUploadUrl = function () { - return '/images/' + $scope.imageType + '/upload'; + return window.baseUrl('/images/' + $scope.imageType + '/upload'); }; /** @@ -133,7 +133,7 @@ module.exports = function (ngApp, events) { $scope.showing = false; }; - var baseUrl = '/images/' + $scope.imageType + '/all/' + var baseUrl = window.baseUrl('/images/' + $scope.imageType + '/all/'); /** * Fetch the list image data from the server. @@ -178,7 +178,7 @@ module.exports = function (ngApp, events) { $scope.images = []; $scope.hasMore = false; page = 0; - baseUrl = '/images/' + $scope.imageType + '/search/'; + baseUrl = window.baseUrl('/images/' + $scope.imageType + '/search/'); fetchData(); }; @@ -192,7 +192,7 @@ module.exports = function (ngApp, events) { $scope.hasMore = false; page = 0; $scope.view = viewName; - baseUrl = '/images/' + $scope.imageType + '/' + viewName + '/'; + baseUrl = window.baseUrl('/images/' + $scope.imageType + '/' + viewName + '/'); fetchData(); } @@ -202,7 +202,7 @@ module.exports = function (ngApp, events) { */ $scope.saveImageDetails = function (event) { event.preventDefault(); - var url = '/images/update/' + $scope.selectedImage.id; + var url = window.baseUrl('/images/update/' + $scope.selectedImage.id); $http.put(url, this.selectedImage).then((response) => { events.emit('success', 'Image details updated'); }, (response) => { @@ -228,7 +228,7 @@ module.exports = function (ngApp, events) { $scope.deleteImage = function (event) { event.preventDefault(); var force = $scope.dependantPages !== false; - var url = '/images/' + $scope.selectedImage.id; + var url = window.baseUrl('/images/' + $scope.selectedImage.id); if (force) url += '?force=true'; $http.delete(url).then((response) => { $scope.images.splice($scope.images.indexOf($scope.selectedImage), 1); @@ -267,7 +267,7 @@ module.exports = function (ngApp, events) { if (term.length == 0) return; $scope.searching = true; $scope.searchResults = ''; - var searchUrl = '/search/book/' + $attrs.bookId; + var searchUrl = window.baseUrl('/search/book/' + $attrs.bookId); searchUrl += '?term=' + encodeURIComponent(term); $http.get(searchUrl).then((response) => { $scope.searchResults = $sce.trustAsHtml(response.data); @@ -368,7 +368,8 @@ module.exports = function (ngApp, events) { if (isMarkdown) data.markdown = $scope.editContent; - $http.put('/ajax/page/' + pageId + '/save-draft', data).then((responseData) => { + let url = window.baseUrl('/ajax/page/' + pageId + '/save-draft'); + $http.put(url, data).then((responseData) => { var updateTime = moment.utc(moment.unix(responseData.data.timestamp)).toDate(); $scope.draftText = responseData.data.message + moment(updateTime).format('HH:mm'); if (!$scope.isNewPageDraft) $scope.isUpdateDraft = true; @@ -393,7 +394,8 @@ module.exports = function (ngApp, events) { * content from the system via an AJAX request. */ $scope.discardDraft = function () { - $http.get('/ajax/page/' + pageId).then((responseData) => { + let url = window.baseUrl('/ajax/page/' + pageId); + $http.get(url).then((responseData) => { if (autoSave) $interval.cancel(autoSave); $scope.draftText = 'Editing Page'; $scope.isUpdateDraft = false; @@ -437,7 +439,8 @@ module.exports = function (ngApp, events) { * Get all tags for the current book and add into scope. */ function getTags() { - $http.get('/ajax/tags/get/page/' + pageId).then((responseData) => { + let url = window.baseUrl('/ajax/tags/get/page/' + pageId); + $http.get(url).then((responseData) => { $scope.tags = responseData.data; addEmptyTag(); }); @@ -486,7 +489,8 @@ module.exports = function (ngApp, events) { $scope.saveTags = function() { setTagOrder(); let postData = {tags: $scope.tags}; - $http.post('/ajax/tags/update/page/' + pageId, postData).then((responseData) => { + let url = window.baseUrl('/ajax/tags/update/page/' + pageId); + $http.post(url, postData).then((responseData) => { $scope.tags = responseData.data.tags; addEmptyTag(); events.emit('success', responseData.data.message); diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js index 8554da9f8..897707af5 100644 --- a/resources/assets/js/directives.js +++ b/resources/assets/js/directives.js @@ -1,10 +1,10 @@ "use strict"; -var DropZone = require('dropzone'); -var markdown = require('marked'); +const DropZone = require('dropzone'); +const markdown = require('marked'); -var toggleSwitchTemplate = require('./components/toggle-switch.html'); -var imagePickerTemplate = require('./components/image-picker.html'); -var dropZoneTemplate = require('./components/drop-zone.html'); +const toggleSwitchTemplate = require('./components/toggle-switch.html'); +const imagePickerTemplate = require('./components/image-picker.html'); +const dropZoneTemplate = require('./components/drop-zone.html'); module.exports = function (ngApp, events) { @@ -54,7 +54,7 @@ module.exports = function (ngApp, events) { imageClass: '@' }, link: function (scope, element, attrs) { - var usingIds = typeof scope.currentId !== 'undefined' || scope.currentId === 'false'; + let usingIds = typeof scope.currentId !== 'undefined' || scope.currentId === 'false'; scope.image = scope.currentImage; scope.value = scope.currentImage || ''; if (usingIds) scope.value = scope.currentId; @@ -80,7 +80,7 @@ module.exports = function (ngApp, events) { }; scope.updateImageFromModel = function (model) { - var isResized = scope.resizeWidth && scope.resizeHeight; + let isResized = scope.resizeWidth && scope.resizeHeight; if (!isResized) { scope.$apply(() => { @@ -89,8 +89,9 @@ module.exports = function (ngApp, events) { return; } - var cropped = scope.resizeCrop ? 'true' : 'false'; - var requestString = '/images/thumb/' + model.id + '/' + scope.resizeWidth + '/' + scope.resizeHeight + '/' + cropped; + let cropped = scope.resizeCrop ? 'true' : 'false'; + let requestString = '/images/thumb/' + model.id + '/' + scope.resizeWidth + '/' + scope.resizeHeight + '/' + cropped; + requestString = window.baseUrl(requestString); $http.get(requestString).then((response) => { setImage(model, response.data.url); }); @@ -332,9 +333,9 @@ module.exports = function (ngApp, events) { // Insert image shortcut if (event.which === 73 && event.ctrlKey && event.shiftKey) { event.preventDefault(); - var caretPos = input[0].selectionStart; - var currentContent = input.val(); - var mdImageText = "![](http://)"; + let caretPos = input[0].selectionStart; + let currentContent = input.val(); + const mdImageText = "![](http://)"; input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); input.focus(); input[0].selectionStart = caretPos + ("![](".length); @@ -348,9 +349,9 @@ module.exports = function (ngApp, events) { // Insert image from image manager insertImage.click(event => { window.ImageManager.showExternal(image => { - var caretPos = currentCaretPos; - var currentContent = input.val(); - var mdImageText = "![" + image.name + "](" + image.url + ")"; + let caretPos = currentCaretPos; + let currentContent = input.val(); + let mdImageText = "![" + image.name + "](" + image.url + ")"; input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); input.change(); }); @@ -624,7 +625,7 @@ module.exports = function (ngApp, events) { // Get search url with correct types function getSearchUrl() { let types = (attrs.entityTypes) ? encodeURIComponent(attrs.entityTypes) : encodeURIComponent('page,book,chapter'); - return `/ajax/search/entities?types=${types}`; + return window.baseUrl(`/ajax/search/entities?types=${types}`); } // Get initial contents diff --git a/resources/assets/js/global.js b/resources/assets/js/global.js index 44562abd0..1c300ad26 100644 --- a/resources/assets/js/global.js +++ b/resources/assets/js/global.js @@ -7,6 +7,14 @@ var ngAnimate = require('angular-animate'); var ngSanitize = require('angular-sanitize'); require('angular-ui-sortable'); +// Url retrieval function +window.baseUrl = function(path) { + let basePath = document.querySelector('meta[name="base-url"]').getAttribute('content'); + if (basePath[basePath.length-1] === '/') basePath = basePath.slice(0, basePath.length-1); + if (path[0] === '/') path = path.slice(1); + return basePath + '/' + path; +}; + var ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); // Global Event System @@ -29,6 +37,7 @@ var Events = { }; window.Events = Events; + var services = require('./services')(ngApp, Events); var directives = require('./directives')(ngApp, Events); var controllers = require('./controllers')(ngApp, Events); diff --git a/resources/assets/js/pages/page-form.js b/resources/assets/js/pages/page-form.js index 611d2e782..f8b314e9c 100644 --- a/resources/assets/js/pages/page-form.js +++ b/resources/assets/js/pages/page-form.js @@ -1,8 +1,8 @@ var mceOptions = module.exports = { selector: '#html-editor', content_css: [ - '/css/styles.css', - '/libs/material-design-iconic-font/css/material-design-iconic-font.min.css' + window.baseUrl('/css/styles.css'), + window.baseUrl('/libs/material-design-iconic-font/css/material-design-iconic-font.min.css') ], body_class: 'page-content', relative_urls: false, @@ -148,7 +148,7 @@ var mceOptions = module.exports = { formData.append('file', file, remoteFilename); formData.append('_token', document.querySelector('meta[name="token"]').getAttribute('content')); - xhr.open('POST', '/images/gallery/upload'); + xhr.open('POST', window.baseUrl('/images/gallery/upload')); xhr.onload = function () { if (xhr.status === 200 || xhr.status === 201) { var result = JSON.parse(xhr.responseText); diff --git a/resources/assets/js/pages/page-show.js b/resources/assets/js/pages/page-show.js index b037612be..41b92453f 100644 --- a/resources/assets/js/pages/page-show.js +++ b/resources/assets/js/pages/page-show.js @@ -2,7 +2,7 @@ // Configure ZeroClipboard var zeroClipBoard = require('zeroclipboard'); zeroClipBoard.config({ - swfPath: '/ZeroClipboard.swf' + swfPath: window.baseUrl('/ZeroClipboard.swf') }); window.setupPageShow = module.exports = function (pageId) { @@ -36,7 +36,8 @@ window.setupPageShow = module.exports = function (pageId) { // Show pointer and set link var $elem = $(this); - var link = window.location.protocol + "//" + window.location.host + '/link/' + pageId + '#' + $elem.attr('id'); + let link = window.baseUrl('/link/' + pageId + '#' + $elem.attr('id')); + if (link.indexOf('http') !== 0) link = window.location.protocol + "//" + window.location.host + link; $pointer.find('input').val(link); $pointer.find('button').first().attr('data-clipboard-text', link); $elem.before($pointer); diff --git a/resources/assets/sass/_fonts.scss b/resources/assets/sass/_fonts.scss index c9dff31e1..c8e8ea833 100644 --- a/resources/assets/sass/_fonts.scss +++ b/resources/assets/sass/_fonts.scss @@ -6,8 +6,8 @@ font-style: normal; font-weight: 100; src: local('Roboto Thin'), local('Roboto-Thin'), - url('/fonts/roboto-v15-cyrillic_latin-100.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-100.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-100.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-100.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-100italic - cyrillic_latin */ @font-face { @@ -15,8 +15,8 @@ font-style: italic; font-weight: 100; src: local('Roboto Thin Italic'), local('Roboto-ThinItalic'), - url('/fonts/roboto-v15-cyrillic_latin-100italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-100italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-100italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-100italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-300 - cyrillic_latin */ @font-face { @@ -24,8 +24,8 @@ font-style: normal; font-weight: 300; src: local('Roboto Light'), local('Roboto-Light'), - url('/fonts/roboto-v15-cyrillic_latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-300italic - cyrillic_latin */ @font-face { @@ -33,8 +33,8 @@ font-style: italic; font-weight: 300; src: local('Roboto Light Italic'), local('Roboto-LightItalic'), - url('/fonts/roboto-v15-cyrillic_latin-300italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-300italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-300italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-300italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-regular - cyrillic_latin */ @font-face { @@ -42,8 +42,8 @@ font-style: normal; font-weight: 400; src: local('Roboto'), local('Roboto-Regular'), - url('/fonts/roboto-v15-cyrillic_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-italic - cyrillic_latin */ @font-face { @@ -51,8 +51,8 @@ font-style: italic; font-weight: 400; src: local('Roboto Italic'), local('Roboto-Italic'), - url('/fonts/roboto-v15-cyrillic_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-500 - cyrillic_latin */ @font-face { @@ -60,8 +60,8 @@ font-style: normal; font-weight: 500; src: local('Roboto Medium'), local('Roboto-Medium'), - url('/fonts/roboto-v15-cyrillic_latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-500italic - cyrillic_latin */ @font-face { @@ -69,8 +69,8 @@ font-style: italic; font-weight: 500; src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), - url('/fonts/roboto-v15-cyrillic_latin-500italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-500italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-500italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-500italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-700 - cyrillic_latin */ @font-face { @@ -78,8 +78,8 @@ font-style: normal; font-weight: 700; src: local('Roboto Bold'), local('Roboto-Bold'), - url('/fonts/roboto-v15-cyrillic_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-700italic - cyrillic_latin */ @font-face { @@ -87,8 +87,8 @@ font-style: italic; font-weight: 700; src: local('Roboto Bold Italic'), local('Roboto-BoldItalic'), - url('/fonts/roboto-v15-cyrillic_latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-v15-cyrillic_latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-v15-cyrillic_latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-v15-cyrillic_latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* roboto-mono-regular - latin */ @@ -97,6 +97,6 @@ font-style: normal; font-weight: 400; src: local('Roboto Mono'), local('RobotoMono-Regular'), - url('/fonts/roboto-mono-v4-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ - url('/fonts/roboto-mono-v4-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url('../fonts/roboto-mono-v4-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */ + url('../fonts/roboto-mono-v4-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } \ No newline at end of file diff --git a/resources/views/auth/forms/login/standard.blade.php b/resources/views/auth/forms/login/standard.blade.php index d9be2935a..abefd21a1 100644 --- a/resources/views/auth/forms/login/standard.blade.php +++ b/resources/views/auth/forms/login/standard.blade.php @@ -6,5 +6,5 @@
@include('form/password', ['name' => 'password', 'tabindex' => 2]) - Forgot Password? + Forgot Password?
\ No newline at end of file diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index d1239b52c..4fa97c1d5 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -1,8 +1,8 @@ @extends('public') @section('header-buttons') - @if(Setting::get('registration-enabled')) - Sign up + @if(setting('registration-enabled', false)) + Sign up @endif @stop @@ -12,7 +12,7 @@

Log In

-
+ {!! csrf_field() !!} @@ -34,10 +34,10 @@

Social Login

@if(isset($socialDrivers['google'])) - + @endif @if(isset($socialDrivers['github'])) - + @endif @endif
diff --git a/resources/views/auth/password.blade.php b/resources/views/auth/password.blade.php index d3ea08e1c..d8536efa7 100644 --- a/resources/views/auth/password.blade.php +++ b/resources/views/auth/password.blade.php @@ -1,7 +1,5 @@ @extends('public') -@section('body-class', 'image-cover login') - @section('content') @@ -11,7 +9,7 @@

Enter your email below and you will be sent an email with a password reset link.

- + {!! csrf_field() !!}
diff --git a/resources/views/auth/register-confirm.blade.php b/resources/views/auth/register-confirm.blade.php index 2f70b9ffd..97fd65ab5 100644 --- a/resources/views/auth/register-confirm.blade.php +++ b/resources/views/auth/register-confirm.blade.php @@ -2,7 +2,7 @@ @section('header-buttons') @if(!$signedIn) - Sign in + Sign in @endif @stop @@ -11,7 +11,7 @@

Thanks for registering!

-

Please check your email and click the confirmation button to access {{ \Setting::get('app-name') }}.

+

Please check your email and click the confirmation button to access {{ setting('app-name', 'BookStack') }}.

diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index f85440e7f..8ae5fcf50 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -1,7 +1,7 @@ @extends('public') @section('header-buttons') - Sign in + Sign in @stop @section('content') @@ -10,7 +10,7 @@

Sign Up

- + {!! csrf_field() !!}
@@ -38,10 +38,10 @@

Social Registration

Register and sign in using another service.

@if(isset($socialDrivers['google'])) - + @endif @if(isset($socialDrivers['github'])) - + @endif @endif
diff --git a/resources/views/auth/reset.blade.php b/resources/views/auth/reset.blade.php index c440f64e7..9a9a65ff0 100644 --- a/resources/views/auth/reset.blade.php +++ b/resources/views/auth/reset.blade.php @@ -9,7 +9,7 @@

Reset Password

- + {!! csrf_field() !!} diff --git a/resources/views/auth/user-unconfirmed.blade.php b/resources/views/auth/user-unconfirmed.blade.php index 1b0a20a69..08178e891 100644 --- a/resources/views/auth/user-unconfirmed.blade.php +++ b/resources/views/auth/user-unconfirmed.blade.php @@ -10,7 +10,7 @@ If you cannot find the email you can re-send the confirmation email by submitting the form below.


- + {!! csrf_field() !!}
diff --git a/resources/views/base.blade.php b/resources/views/base.blade.php index e9ed436c5..be47abdca 100644 --- a/resources/views/base.blade.php +++ b/resources/views/base.blade.php @@ -1,11 +1,12 @@ - {{ isset($pageTitle) ? $pageTitle . ' | ' : '' }}{{ setting('app-name', 'BookStack') }} + {{ isset($pageTitle) ? $pageTitle . ' | ' : '' }}{{ setting('app-name') }} + @@ -38,7 +39,7 @@ @if(setting('app-logo', '') !== 'none') Logo @endif - {{ setting('app-name', 'BookStack') }} + {{ setting('app-name') }}
diff --git a/resources/views/books/create.blade.php b/resources/views/books/create.blade.php index dd2de574d..60f4f65bd 100644 --- a/resources/views/books/create.blade.php +++ b/resources/views/books/create.blade.php @@ -4,7 +4,7 @@

Create New Book

- + @include('books/form')
diff --git a/resources/views/books/edit.blade.php b/resources/views/books/edit.blade.php index 5bd8917c7..e67e6f459 100644 --- a/resources/views/books/edit.blade.php +++ b/resources/views/books/edit.blade.php @@ -4,7 +4,7 @@

Edit Book

-
+ @include('books/form', ['model' => $book])
diff --git a/resources/views/books/index.blade.php b/resources/views/books/index.blade.php index 7b5c92b5a..91906e7b8 100644 --- a/resources/views/books/index.blade.php +++ b/resources/views/books/index.blade.php @@ -9,7 +9,7 @@
@if($currentUser->can('book-create-all')) - Add new book + Add new book @endif
@@ -31,7 +31,7 @@ @else

No books have been created.

@if(userCan('books-create-all')) - Create one now + Create one now @endif @endif
diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php index 12c36ba41..129851d5e 100644 --- a/resources/views/books/show.blade.php +++ b/resources/views/books/show.blade.php @@ -8,10 +8,10 @@
@if(userCan('page-create', $book)) - New Page + New Page @endif @if(userCan('chapter-create', $book)) - New Chapter + New Chapter @endif @if(userCan('book-update', $book)) Edit @@ -21,13 +21,13 @@
@@ -61,16 +61,16 @@ @else

No pages or chapters have been created for this book.

- Create a new page + Create a new page   -or-    - Add a chapter + Add a chapter


@endif

- Created {{$book->created_at->diffForHumans()}} @if($book->createdBy) by {{$book->createdBy->name}} @endif + Created {{$book->created_at->diffForHumans()}} @if($book->createdBy) by {{$book->createdBy->name}} @endif
- Last Updated {{$book->updated_at->diffForHumans()}} @if($book->updatedBy) by {{$book->updatedBy->name}} @endif + Last Updated {{$book->updated_at->diffForHumans()}} @if($book->updatedBy) by {{$book->updatedBy->name}} @endif

@@ -90,7 +90,7 @@ @if($book->restricted)

@if(userCan('restrictions-manage', $book)) - Book Permissions Active + Book Permissions Active @else Book Permissions Active @endif diff --git a/resources/views/books/sort.blade.php b/resources/views/books/sort.blade.php index af4f1825b..3849dfcfc 100644 --- a/resources/views/books/sort.blade.php +++ b/resources/views/books/sort.blade.php @@ -1,7 +1,7 @@ @extends('base') @section('head') - + @stop @section('content') @@ -22,7 +22,7 @@ @foreach($books as $otherBook) @if($otherBook->id !== $book->id)

@endif @endforeach @@ -32,12 +32,12 @@
-
+ {!! csrf_field() !!}
- Cancel + Cancel
diff --git a/resources/views/chapters/create.blade.php b/resources/views/chapters/create.blade.php index 7195e76fc..b81cb15d7 100644 --- a/resources/views/chapters/create.blade.php +++ b/resources/views/chapters/create.blade.php @@ -4,7 +4,7 @@

Create New Chapter

-
+ @include('chapters/form')
diff --git a/resources/views/chapters/delete.blade.php b/resources/views/chapters/delete.blade.php index ac7c7ccde..e9573f228 100644 --- a/resources/views/chapters/delete.blade.php +++ b/resources/views/chapters/delete.blade.php @@ -8,10 +8,10 @@ and added directly to the book.

Are you sure you want to delete this chapter?

-
+ {!! csrf_field() !!} - Cancel + Cancel
diff --git a/resources/views/chapters/edit.blade.php b/resources/views/chapters/edit.blade.php index aa76d5ca7..0363da96d 100644 --- a/resources/views/chapters/edit.blade.php +++ b/resources/views/chapters/edit.blade.php @@ -4,7 +4,7 @@

Edit Chapter

-
+ @include('chapters/form', ['model' => $chapter])
diff --git a/resources/views/chapters/list-item.blade.php b/resources/views/chapters/list-item.blade.php index 1567557d2..3677851df 100644 --- a/resources/views/chapters/list-item.blade.php +++ b/resources/views/chapters/list-item.blade.php @@ -20,7 +20,7 @@

{{ count($chapter->pages) }} Pages

@foreach($chapter->pages as $page) -

{{$page->name}}

+

{{$page->name}}

@endforeach
@endif diff --git a/resources/views/chapters/move.blade.php b/resources/views/chapters/move.blade.php index c14dd6923..37d56d30d 100644 --- a/resources/views/chapters/move.blade.php +++ b/resources/views/chapters/move.blade.php @@ -7,9 +7,9 @@ @@ -19,7 +19,7 @@

Move Chapter {{$chapter->name}}

-
+ {!! csrf_field() !!} diff --git a/resources/views/chapters/restrictions.blade.php b/resources/views/chapters/restrictions.blade.php index c25c0755d..771665037 100644 --- a/resources/views/chapters/restrictions.blade.php +++ b/resources/views/chapters/restrictions.blade.php @@ -7,7 +7,7 @@
diff --git a/resources/views/chapters/show.blade.php b/resources/views/chapters/show.blade.php index b79cd8415..70b09e9ce 100644 --- a/resources/views/chapters/show.blade.php +++ b/resources/views/chapters/show.blade.php @@ -7,29 +7,29 @@
@if(userCan('page-create', $chapter)) - New Page + New Page @endif @if(userCan('chapter-update', $chapter)) - Edit + Edit @endif @if(userCan('chapter-update', $chapter) || userCan('restrictions-manage', $chapter) || userCan('chapter-delete', $chapter)) @@ -60,22 +60,22 @@

No pages are currently in this chapter.

@if(userCan('page-create', $chapter)) - Create a new page + Create a new page @endif @if(userCan('page-create', $chapter) && userCan('book-update', $book))   -or-    @endif @if(userCan('book-update', $book)) - Sort the current book + Sort the current book @endif


@endif

- Created {{$chapter->created_at->diffForHumans()}} @if($chapter->createdBy) by {{ $chapter->createdBy->name}} @endif + Created {{ $chapter->created_at->diffForHumans() }} @if($chapter->createdBy) by {{ $chapter->createdBy->name}} @endif
- Last Updated {{$chapter->updated_at->diffForHumans()}} @if($chapter->updatedBy) by {{ $chapter->updatedBy->name}} @endif + Last Updated {{ $chapter->updated_at->diffForHumans() }} @if($chapter->updatedBy) by {{ $chapter->updatedBy->name}} @endif

@@ -85,7 +85,7 @@ @if($book->restricted) @if(userCan('restrictions-manage', $book)) - Book Permissions Active + Book Permissions Active @else Book Permissions Active @endif @@ -94,7 +94,7 @@ @if($chapter->restricted) @if(userCan('restrictions-manage', $chapter)) - Chapter Permissions Active + Chapter Permissions Active @else Chapter Permissions Active @endif diff --git a/resources/views/emails/email-confirmation.blade.php b/resources/views/emails/email-confirmation.blade.php index 618710041..6a0dc0378 100644 --- a/resources/views/emails/email-confirmation.blade.php +++ b/resources/views/emails/email-confirmation.blade.php @@ -1,176 +1,190 @@ - - + + - - - Confirm Your Email At {{ Setting::get('app-name')}} + + + Confirm Your Email At {{ setting('app-name')}} - + - - - + + +
- - - - -
- -
- - - - -
-

Email Confirmation

-

Thanks for joining {{ Setting::get('app-name')}}.
- Please confirm your email address by clicking the button below.

- - - - -
-

Confirm Email

-
-
-
- -
- - + + + +
+ + + + +
+

+ Email Confirmation

+

+ Thanks for joining {{ setting('app-name')}}.
+ Please confirm your email address by clicking the button below.

+ + + + +
+

+ Confirm + Email

+
+
+
+ + + + + + + - + diff --git a/resources/views/emails/password.blade.php b/resources/views/emails/password.blade.php index 95fe012eb..dfd8f3db5 100644 --- a/resources/views/emails/password.blade.php +++ b/resources/views/emails/password.blade.php @@ -1 +1 @@ - Password Reset From {{ Setting::get('app-name')}}

Password Reset

A password reset was requested for this email address on {{ Setting::get('app-name')}}. If you did not request a password change please ignore this email.

Click here to reset your password

\ No newline at end of file + Password Reset From {{ setting('app-name')}}

Password Reset

A password reset was requested for this email address on {{ setting('app-name')}}. If you did not request a password change please ignore this email.

Click here to reset your password

\ No newline at end of file diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php index a9294c7cf..19565bccb 100644 --- a/resources/views/errors/404.blade.php +++ b/resources/views/errors/404.blade.php @@ -6,7 +6,7 @@

{{ $message or 'Page Not Found' }}

Sorry, The page you were looking for could not be found.

- Return To Home + Return To Home
@stop \ No newline at end of file diff --git a/resources/views/errors/503.blade.php b/resources/views/errors/503.blade.php index 0380666a8..c79d0f68b 100644 --- a/resources/views/errors/503.blade.php +++ b/resources/views/errors/503.blade.php @@ -1,47 +1,10 @@ - - - - Be right back. +@extends('public') - +@section('content') - - - -
-
-
Be right back.
-
-
- - +@stop \ No newline at end of file diff --git a/resources/views/form/restriction-form.blade.php b/resources/views/form/restriction-form.blade.php index f61a535e7..7472fe65e 100644 --- a/resources/views/form/restriction-form.blade.php +++ b/resources/views/form/restriction-form.blade.php @@ -1,4 +1,4 @@ - + {!! csrf_field() !!} diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index 88319738e..2529c39c7 100644 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -42,7 +42,7 @@
-

Recently Created Pages

+

Recently Created Pages

@include('partials/entity-list', [ 'entities' => $recentlyCreatedPages, @@ -51,7 +51,7 @@ ])
-

Recently Updated Pages

+

Recently Updated Pages

@include('partials/entity-list', [ 'entities' => $recentlyUpdatedPages, diff --git a/resources/views/pages/delete.blade.php b/resources/views/pages/delete.blade.php index 5a9b32c06..57cc86054 100644 --- a/resources/views/pages/delete.blade.php +++ b/resources/views/pages/delete.blade.php @@ -6,10 +6,10 @@

Delete {{ $page->draft ? 'Draft' : '' }} Page

Are you sure you want to delete this {{ $page->draft ? 'draft' : '' }} page?

- + {!! csrf_field() !!} - Cancel + Cancel
diff --git a/resources/views/pages/edit.blade.php b/resources/views/pages/edit.blade.php index de6051118..9fe6a6a19 100644 --- a/resources/views/pages/edit.blade.php +++ b/resources/views/pages/edit.blade.php @@ -1,7 +1,7 @@ @extends('base') @section('head') - + @stop @section('body-class', 'flexbox') @@ -9,7 +9,7 @@ @section('content')
-
+ @if(!isset($isDraft)) @endif diff --git a/resources/views/pages/form-toolbox.blade.php b/resources/views/pages/form-toolbox.blade.php index b3fcd7c13..a03a208b6 100644 --- a/resources/views/pages/form-toolbox.blade.php +++ b/resources/views/pages/form-toolbox.blade.php @@ -14,8 +14,8 @@ - - + + diff --git a/resources/views/pages/form.blade.php b/resources/views/pages/form.blade.php index 6529f044b..18a9868c7 100644 --- a/resources/views/pages/form.blade.php +++ b/resources/views/pages/form.blade.php @@ -20,7 +20,7 @@ Save Draft
  • - Delete Draft + Delete Draft
  • diff --git a/resources/views/pages/move.blade.php b/resources/views/pages/move.blade.php index 27ee4cd92..d0fae60ca 100644 --- a/resources/views/pages/move.blade.php +++ b/resources/views/pages/move.blade.php @@ -7,16 +7,16 @@ @@ -26,7 +26,7 @@

    Move Page {{$page->name}}

    - + {!! csrf_field() !!} diff --git a/resources/views/pages/page-display.blade.php b/resources/views/pages/page-display.blade.php index d0bdcf880..11bcddcfc 100644 --- a/resources/views/pages/page-display.blade.php +++ b/resources/views/pages/page-display.blade.php @@ -8,8 +8,8 @@ @foreach($page->tags as $tag) - - @if($tag->value) @endif + + @if($tag->value) @endif @endforeach
    value) colspan="2" @endif>{{ $tag->name }}{{$tag->value}}value) colspan="2" @endif>{{ $tag->name }}{{$tag->value}}
    diff --git a/resources/views/pages/restrictions.blade.php b/resources/views/pages/restrictions.blade.php index 09eb8a65b..8eca486c3 100644 --- a/resources/views/pages/restrictions.blade.php +++ b/resources/views/pages/restrictions.blade.php @@ -7,16 +7,16 @@ diff --git a/resources/views/pages/revisions.blade.php b/resources/views/pages/revisions.blade.php index a73f16a4f..03fb23673 100644 --- a/resources/views/pages/revisions.blade.php +++ b/resources/views/pages/revisions.blade.php @@ -7,7 +7,7 @@
    @@ -40,9 +40,9 @@ @if($revision->createdBy) {{$revision->createdBy->name}} @else Deleted User @endif {{$revision->created_at->format('jS F, Y H:i:s')}}
    ({{$revision->created_at->diffForHumans()}})
    - Preview + Preview  |  - Restore + Restore @endforeach diff --git a/resources/views/pages/show.blade.php b/resources/views/pages/show.blade.php index f12ba58c6..9d6b74a03 100644 --- a/resources/views/pages/show.blade.php +++ b/resources/views/pages/show.blade.php @@ -7,12 +7,12 @@
    @@ -22,27 +22,27 @@
    Export
    @if(userCan('page-update', $page)) - Edit + Edit @endif @if(userCan('page-update', $page) || userCan('restrictions-manage', $page) || userCan('page-delete', $page)) @@ -73,13 +73,14 @@

    - Created {{$page->created_at->diffForHumans()}} @if($page->createdBy) by {{$page->createdBy->name}} @endif + Created {{ $page->created_at->diffForHumans() }} @if($page->createdBy) by {{$page->createdBy->name}} @endif
    - Last Updated {{$page->updated_at->diffForHumans()}} @if($page->updatedBy) by {{$page->updatedBy->name}} @endif + Last Updated {{ $page->updated_at->diffForHumans() }} @if($page->updatedBy) by {{$page->updatedBy->name}} @endif

    + @endif @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree]) -
    +
    diff --git a/resources/views/pages/sidebar-tree-list.blade.php b/resources/views/pages/sidebar-tree-list.blade.php index 3445acbdc..e40fdbf0f 100644 --- a/resources/views/pages/sidebar-tree-list.blade.php +++ b/resources/views/pages/sidebar-tree-list.blade.php @@ -2,12 +2,12 @@
    Book Navigation