From 5af6656fae43c5dec565f300d2b9216a0679953f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 10 Oct 2015 18:57:52 +0100 Subject: [PATCH] Extracted page form js and added better page content linking --- app/Http/Controllers/PageController.php | 18 +--- app/Repos/PageRepo.php | 102 +++++++++++++++++-- package.json | 3 +- public/ZeroClipboard.swf | Bin 0 -> 6580 bytes resources/assets/js/global.js | 10 ++ resources/assets/js/pages/page-form.js | 39 +++++++ resources/assets/sass/_animations.scss | 17 ++++ resources/assets/sass/_buttons.scss | 32 ++---- resources/assets/sass/_pages.scss | 79 +++++++++----- resources/views/pages/form.blade.php | 66 +----------- resources/views/pages/page-display.blade.php | 11 +- resources/views/pages/show.blade.php | 89 ++++++++-------- resources/views/public.blade.php | 4 +- 13 files changed, 279 insertions(+), 191 deletions(-) create mode 100644 public/ZeroClipboard.swf create mode 100644 resources/assets/js/pages/page-form.js diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index c2867caa8..56ea6992c 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -63,22 +63,14 @@ class PageController extends Controller 'html' => 'required|string', 'parent' => 'integer|exists:pages,id' ]); + + $input = $request->all(); $book = $this->bookRepo->getBySlug($bookSlug); - $page = $this->pageRepo->newFromInput($request->all()); + $chapterId = ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) ? $request->get('chapter') : null; + $input['priority'] = $this->bookRepo->getNewPriority($book); - $page->slug = $this->pageRepo->findSuitableSlug($page->name, $book->id); - $page->priority = $this->bookRepo->getNewPriority($book); + $page = $this->pageRepo->saveNew($input, $book, $chapterId); - if ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) { - $page->chapter_id = $request->get('chapter'); - } - - $page->book_id = $book->id; - $page->text = strip_tags($page->html); - $page->created_by = Auth::user()->id; - $page->updated_by = Auth::user()->id; - $page->save(); - $this->pageRepo->saveRevision($page); Activity::add($page, 'page_create', $book->id); return redirect($page->getUrl()); } diff --git a/app/Repos/PageRepo.php b/app/Repos/PageRepo.php index 441d5980e..1f0c61819 100644 --- a/app/Repos/PageRepo.php +++ b/app/Repos/PageRepo.php @@ -1,7 +1,11 @@ page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first(); } + /** + * @param $input + * @return Page + */ public function newFromInput($input) { $page = $this->page->fill($input); @@ -53,6 +61,83 @@ class PageRepo return $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->count(); } + /** + * Save a new page into the system. + * Input validation must be done beforehand. + * @param array $input + * @param Book $book + * @param int $chapterId + * @return Page + */ + public function saveNew(array $input, Book $book, $chapterId = null) + { + $page = $this->newFromInput($input); + $page->slug = $this->findSuitableSlug($page->name, $book->id); + + if ($chapterId) $page->chapter_id = $chapterId; + + $page->html = $this->formatHtml($input['html']); + $page->text = strip_tags($page->html); + $page->created_by = auth()->user()->id; + $page->updated_by = auth()->user()->id; + + $book->pages()->save($page); + $this->saveRevision($page); + return $page; + } + + /** + * Formats a page's html to be tagged correctly + * within the system. + * @param string $htmlText + * @return string + */ + protected function formatHtml($htmlText) + { + libxml_use_internal_errors(true); + $doc = new \DOMDocument(); + $doc->loadHTML($htmlText); + + $container = $doc->documentElement; + $body = $container->childNodes[0]; + $childNodes = $body->childNodes; + + // Ensure no duplicate ids are used + $lastId = false; + $idArray = []; + + foreach ($childNodes as $index => $childNode) { + /** @var \DOMElement $childNode */ + if (get_class($childNode) !== 'DOMElement') continue; + + // Overwrite id if not a bookstack custom id + if ($childNode->hasAttribute('id')) { + $id = $childNode->getAttribute('id'); + if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) { + $idArray[] = $id; + continue; + }; + } + + // Create an unique id for the element + do { + $id = 'bkmrk-' . substr(uniqid(), -5); + } while ($id == $lastId); + $lastId = $id; + + $childNode->setAttribute('id', $id); + $idArray[] = $id; + } + + // Generate inner html as a string + $html = ''; + foreach ($childNodes as $childNode) { + $html .= $doc->saveHTML($childNode); + } + + return $html; + } + public function destroyById($id) { $page = $this->getById($id); @@ -99,8 +184,8 @@ class PageRepo */ public function searchForImage($imageString) { - $pages = $this->page->where('html', 'like', '%'.$imageString.'%')->get(); - foreach($pages as $page) { + $pages = $this->page->where('html', 'like', '%' . $imageString . '%')->get(); + foreach ($pages as $page) { $page->url = $page->getUrl(); $page->html = ''; $page->text = ''; @@ -110,15 +195,16 @@ class PageRepo /** * Updates a page with any fillable data and saves it into the database. - * @param Page $page - * @param $book_id - * @param $data + * @param Page $page + * @param int $book_id + * @param string $input * @return Page */ - public function updatePage(Page $page, $book_id, $data) + public function updatePage(Page $page, $book_id, $input) { - $page->fill($data); + $page->fill($input); $page->slug = $this->findSuitableSlug($page->name, $book_id, $page->id); + $page->html = $this->formatHtml($input['html']); $page->text = strip_tags($page->html); $page->updated_by = Auth::user()->id; $page->save(); @@ -189,7 +275,7 @@ class PageRepo public function setBookId($bookId, Page $page) { $page->book_id = $bookId; - foreach($page->activity as $activity) { + foreach ($page->activity as $activity) { $activity->book_id = $bookId; $activity->save(); } diff --git a/package.json b/package.json index af40e256f..09edc2b20 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dropzone": "^4.0.1", "laravel-elixir": "^3.3.1", "vue": "^0.12.16", - "vue-resource": "^0.1.16" + "vue-resource": "^0.1.16", + "zeroclipboard": "^2.2.0" } } diff --git a/public/ZeroClipboard.swf b/public/ZeroClipboard.swf new file mode 100644 index 0000000000000000000000000000000000000000..8bad6a3e34f1b0b055da3ee8e506fe627cf75987 GIT binary patch literal 6580 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 T%VW6zM}L!R`D4$0 i { + color: #888; + font-size: 18px; + padding-top: 4px; + } + .button { + line-height: 1; + margin: 0 0 0 -4px; + box-shadow: none; } } + h1, h2, h3, h4, h5, h6 { &:hover a.link-hook { opacity: 1; transform: translate3d(0, 0, 0); } } - -// Side Navigation -.side-nav { - position: fixed; - padding-left: $-m; - opacity: 0.8; - margin-top: $-xxl; - margin-left: 0; - max-width: 240px; - display: none; -} \ No newline at end of file diff --git a/resources/views/pages/form.blade.php b/resources/views/pages/form.blade.php index 44e396c84..de88dec0a 100644 --- a/resources/views/pages/form.blade.php +++ b/resources/views/pages/form.blade.php @@ -28,7 +28,7 @@
- @if($errors->has('html'))
{{ $errors->first('html') }}
@@ -36,68 +36,4 @@
- - - - - - \ No newline at end of file diff --git a/resources/views/pages/page-display.blade.php b/resources/views/pages/page-display.blade.php index 6eb623b39..8d3625db8 100644 --- a/resources/views/pages/page-display.blade.php +++ b/resources/views/pages/page-display.blade.php @@ -1,10 +1,3 @@ -

{{$page->name}}

-@if(count($page->children) > 0) -

Sub-pages

-
- @foreach($page->children as $childPage) - {{ $childPage->name }} - @endforeach -
-@endif +

{{$page->name}}

+ {!! $page->html !!} \ No newline at end of file diff --git a/resources/views/pages/show.blade.php b/resources/views/pages/show.blade.php index 5fa41eff8..e30cfef82 100644 --- a/resources/views/pages/show.blade.php +++ b/resources/views/pages/show.blade.php @@ -37,22 +37,31 @@
+ +
+
+ + + +
+
+ @include('pages/page-display') +
+

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

+
+ @include('pages/sidebar-tree-list', ['book' => $book]) -
-

Page Navigation

- -
+
@@ -64,45 +73,46 @@ diff --git a/resources/views/public.blade.php b/resources/views/public.blade.php index 7606f936a..39bdab1ef 100644 --- a/resources/views/public.blade.php +++ b/resources/views/public.blade.php @@ -3,14 +3,12 @@ BookStack - + - -