Dan Brown

Addded sorting logic to pages

...@@ -135,12 +135,23 @@ class PageController extends Controller ...@@ -135,12 +135,23 @@ class PageController extends Controller
135 return redirect($page->getUrl()); 135 return redirect($page->getUrl());
136 } 136 }
137 137
138 + /**
139 + * Redirect from a special link url which
140 + * uses the page id rather than the name.
141 + * @param $pageId
142 + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
143 + */
138 public function redirectFromLink($pageId) 144 public function redirectFromLink($pageId)
139 { 145 {
140 $page = $this->pageRepo->getById($pageId); 146 $page = $this->pageRepo->getById($pageId);
141 return redirect($page->getUrl()); 147 return redirect($page->getUrl());
142 } 148 }
143 149
150 + /**
151 + * Search all available pages, Across all books.
152 + * @param Request $request
153 + * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
154 + */
144 public function searchAll(Request $request) 155 public function searchAll(Request $request)
145 { 156 {
146 $searchTerm = $request->get('term'); 157 $searchTerm = $request->get('term');
...@@ -151,6 +162,30 @@ class PageController extends Controller ...@@ -151,6 +162,30 @@ class PageController extends Controller
151 } 162 }
152 163
153 /** 164 /**
165 + * Shows the view which allows pages to be re-ordered and sorted.
166 + * @param $bookSlug
167 + * @return \Illuminate\View\View
168 + */
169 + public function sortPages($bookSlug)
170 + {
171 + $book = $this->bookRepo->getBySlug($bookSlug);
172 + $tree = $this->bookRepo->getTree($book);
173 + return view('pages/sort', ['book' => $book, 'tree' => $tree]);
174 + }
175 +
176 + public function savePageSort($bookSlug, Request $request)
177 + {
178 + $book = $this->bookRepo->getBySlug($bookSlug);
179 + if(!$request->has('sort-tree')) {
180 + return redirect($book->getUrl());
181 + }
182 +
183 + $sortMap = json_decode($request->get('sort-tree'));
184 + $this->pageRepo->applySortMap($sortMap, $book->id);
185 + return redirect($book->getUrl());
186 + }
187 +
188 + /**
154 * Remove the specified resource from storage. 189 * Remove the specified resource from storage.
155 * 190 *
156 * @param int $id 191 * @param int $id
......
...@@ -24,6 +24,8 @@ Route::group(['prefix' => 'books'], function() { ...@@ -24,6 +24,8 @@ Route::group(['prefix' => 'books'], function() {
24 24
25 Route::get('/{bookSlug}/page/create', 'PageController@create'); 25 Route::get('/{bookSlug}/page/create', 'PageController@create');
26 Route::post('/{bookSlug}/page', 'PageController@store'); 26 Route::post('/{bookSlug}/page', 'PageController@store');
27 + Route::get('/{bookSlug}/sort', 'PageController@sortPages');
28 + Route::put('/{bookSlug}/sort', 'PageController@savePageSort');
27 Route::get('/{bookSlug}/{pageSlug}', 'PageController@show'); 29 Route::get('/{bookSlug}/{pageSlug}', 'PageController@show');
28 Route::get('/{bookSlug}/{pageSlug}/create', 'PageController@create'); 30 Route::get('/{bookSlug}/{pageSlug}/create', 'PageController@create');
29 Route::get('/{bookSlug}/{pageSlug}/edit', 'PageController@edit'); 31 Route::get('/{bookSlug}/{pageSlug}/edit', 'PageController@edit');
......
...@@ -24,7 +24,7 @@ class Page extends Model ...@@ -24,7 +24,7 @@ class Page extends Model
24 24
25 public function children() 25 public function children()
26 { 26 {
27 - return $this->hasMany('Oxbow\Page'); 27 + return $this->hasMany('Oxbow\Page')->orderBy('priority', 'ASC');
28 } 28 }
29 29
30 public function parent() 30 public function parent()
......
...@@ -57,6 +57,7 @@ class BookRepo ...@@ -57,6 +57,7 @@ class BookRepo
57 { 57 {
58 $tree = $book->toArray(); 58 $tree = $book->toArray();
59 $tree['pages'] = $this->pageRepo->getTreeByBookId($book->id); 59 $tree['pages'] = $this->pageRepo->getTreeByBookId($book->id);
60 + $tree['hasChildren'] = count($tree['pages']) > 0;
60 return $tree; 61 return $tree;
61 } 62 }
62 63
......
...@@ -114,7 +114,24 @@ class PageRepo ...@@ -114,7 +114,24 @@ class PageRepo
114 */ 114 */
115 private function getTopLevelPages($bookId) 115 private function getTopLevelPages($bookId)
116 { 116 {
117 - return $this->page->where('book_id', '=', $bookId)->where('page_id', '=', 0)->get(); 117 + return $this->page->where('book_id', '=', $bookId)->where('page_id', '=', 0)->orderBy('priority')->get();
118 + }
119 +
120 + /**
121 + * Applies a sort map to all applicable pages.
122 + * @param $sortMap
123 + * @param $bookId
124 + */
125 + public function applySortMap($sortMap, $bookId)
126 + {
127 + foreach($sortMap as $index => $map) {
128 + $page = $this->getById($map->id);
129 + if($page->book_id === $bookId) {
130 + $page->page_id = $map->parent;
131 + $page->priority = $index;
132 + $page->save();
133 + }
134 + }
118 } 135 }
119 136
120 } 137 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -94,6 +94,9 @@ header .menu { ...@@ -94,6 +94,9 @@ header .menu {
94 &:hover { 94 &:hover {
95 opacity: 1; 95 opacity: 1;
96 } 96 }
97 + .buttons a {
98 + display: block;
99 + }
97 } 100 }
98 101
99 .page-nav-list { 102 .page-nav-list {
...@@ -269,3 +272,43 @@ h1, h2, h3, h4, h5, h6 { ...@@ -269,3 +272,43 @@ h1, h2, h3, h4, h5, h6 {
269 } 272 }
270 } 273 }
271 } 274 }
275 +
276 +.sortable-page-list, .sortable-page-list ul {
277 + list-style: none;
278 + //background-color: rgba(0, 0, 0, 0.04);
279 +}
280 +.sortable-page-list {
281 + margin-left: 0;
282 + ul {
283 + margin-bottom: 0;
284 + margin-top: 0;
285 + }
286 + li {
287 + border-bottom: 1px solid #BBB;
288 + border-left: 1px solid #BBB;
289 + border-right: 1px solid #BBB;
290 + padding: $-xs $-s;
291 + }
292 + li:first-child {
293 + margin-top: $-xs;
294 + border-top: 1px solid #BBB;
295 + }
296 +}
297 +
298 +// Jquery Sortable Styles
299 +.dragged {
300 + position: absolute;
301 + opacity: 0.5;
302 + z-index: 2000;
303 +}
304 +
305 +body.dragging, body.dragging * {
306 + cursor: move !important;
307 +}
308 +
309 +.sortable-page-list li.placeholder {
310 + position: relative;
311 +}
312 +.sortable-page-list li.placeholder:before {
313 + position: absolute;
314 +}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
8 <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"> 8 <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
9 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> 9 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
10 <script src="/bower/bootstrap/dist/js/bootstrap.js"></script> 10 <script src="/bower/bootstrap/dist/js/bootstrap.js"></script>
11 + <script src="/bower/jquery-sortable/source/js/jquery-sortable.js"></script>
11 <script> 12 <script>
12 $.fn.smoothScrollTo = function() { 13 $.fn.smoothScrollTo = function() {
13 if(this.length === 0) return; 14 if(this.length === 0) return;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
9 <h4>Book Actions</h4> 9 <h4>Book Actions</h4>
10 <div class="buttons"> 10 <div class="buttons">
11 <a href="{{$book->getEditUrl()}}"><i class="fa fa-pencil"></i>Edit Book</a> 11 <a href="{{$book->getEditUrl()}}"><i class="fa fa-pencil"></i>Edit Book</a>
12 + <a href="{{ $book->getUrl() }}/sort"><i class="fa fa-sort"></i>Sort Pages</a>
12 </div> 13 </div>
13 </div> 14 </div>
14 15
......
1 +
2 +<li data-id="{{$page['id']}}">{{ $page['name'] }}
3 + <ul>
4 + @if($page['hasChildren'])
5 + @foreach($page['pages'] as $childPage)
6 + @include('pages/page-tree-sort', ['page'=>$childPage])
7 + @endforeach
8 + @endif
9 + </ul>
10 +</li>
...@@ -28,10 +28,10 @@ ...@@ -28,10 +28,10 @@
28 @endif 28 @endif
29 </div> 29 </div>
30 <h1>{{$page->name}}</h1> 30 <h1>{{$page->name}}</h1>
31 - @if(count($page->pages) > 0) 31 + @if(count($page->children) > 0)
32 <h4 class="text-muted">Sub-pages</h4> 32 <h4 class="text-muted">Sub-pages</h4>
33 <div class="page-list"> 33 <div class="page-list">
34 - @foreach($page->pages as $childPage) 34 + @foreach($page->children as $childPage)
35 <a href="{{ $childPage->getUrl() }}">{{ $childPage->name }}</a> 35 <a href="{{ $childPage->getUrl() }}">{{ $childPage->name }}</a>
36 @endforeach 36 @endforeach
37 </div> 37 </div>
......
1 +@extends('base')
2 +
3 +@section('content')
4 +
5 + <div class="row">
6 + <div class="page-menu col-md-3">
7 + <div class="page-actions">
8 + <form action="{{$book->getUrl()}}/sort" method="POST">
9 + {!! csrf_field() !!}
10 + <input type="hidden" name="_method" value="PUT">
11 + <input type="hidden" id="sort-tree-input" name="sort-tree">
12 + <h4>Actions</h4>
13 + <div class="list">
14 + <button class="button pos" type="submit">Save Ordering</button>
15 + </div>
16 + </form>
17 + </div>
18 + </div>
19 +
20 + <div class="page-content right col-md-9">
21 + <h1>{{ $book->name }} <span class="subheader">Sort Pages</span></h1>
22 +
23 + <ul class="sortable-page-list" id="sort-list">
24 + @foreach($tree['pages'] as $treePage)
25 + @include('pages/page-tree-sort', ['page' => $treePage])
26 + @endforeach
27 + </ul>
28 +
29 + </div>
30 + </div>
31 +
32 + <script>
33 + $(document).ready(function() {
34 +
35 + var group = $('#sort-list').sortable({
36 + group: 'serialization',
37 + onDrop: function($item, container, _super) {
38 + var data = group.sortable('serialize').get();
39 + console.log(data);
40 + var pageMap = [];
41 + var parent = 0;
42 + buildPageMap(pageMap, parent, data[0]);
43 + $('#sort-tree-input').val(JSON.stringify(pageMap));
44 + _super($item, container);
45 + }
46 + });
47 +
48 + function buildPageMap(pageMap, parent, data) {
49 + for(var i = 0; i < data.length; i++) {
50 + var page = data[i];
51 + pageMap.push({
52 + id: page.id,
53 + parent: parent
54 + });
55 + buildPageMap(pageMap, page.id, page.children[0]);
56 + }
57 + }
58 +
59 + });
60 + </script>
61 +@stop