FEATURE: add page ordering

This commit is contained in:
Michal Kváček
2017-09-13 14:02:07 +02:00
parent d90ca08ba6
commit 3fdae2669b
13 changed files with 293 additions and 215 deletions
@@ -117,4 +117,24 @@ class EditContent extends Controller
->route('content.overview')
->with('success', trans('admin/contents.successfullyEdited'));
}
public function order() {
$pages = $this->content->getOverview()->get();
return view('admin.content.order', compact('pages'));
}
public function setOrder(Request $request) {
$data = $request->get('page');
foreach ($data as $id => $order) {
Content::where('id', $id)->update(['order' => $order]);
}
// something was changed, inform user
return redirect()
->route('content.overview')
->with('success', trans('admin/contents.orderSuccessfullySet'));
}
}
+8 -2
View File
@@ -7,6 +7,7 @@ use App\CMS\Helpers\Traits\Nullable;
use App\CMS\Observers\Content as ContentObserver;
use App\Models\FileManager\File;
use App\Models\Module;
use App\Models\Templates\Template;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -33,6 +34,7 @@ class Content extends Model
'isHomepage',
'title',
'url',
'order',
'metaKeywords',
'metaDescription',
'pageContent',
@@ -63,6 +65,10 @@ class Content extends Model
return $this->hasMany(ContentHistory::class);
}
public function templateModel() {
return $this->belongsTo(Template::class, 'template', 'template_name');
}
/**
* Mark relationship with users table
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
@@ -100,7 +106,7 @@ class Content extends Model
*/
public function subpages()
{
return $this->hasMany(Content::class, 'parentId');
return $this->hasMany(Content::class, 'parentId')->orderBy('order')->orderBy('created_at', 'DESC');
}
/**
@@ -109,7 +115,7 @@ class Content extends Model
*/
public function publishedSubpages()
{
$query = $this->hasMany(Content::class, 'parentId');
$query = $this->subpages();
if (\Auth::check()) {
$query = $query->where('status', '!=', ContentContract::STATUS_DRAFT);
@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddOrderToContent extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::table('contents', function (Blueprint $table) {
$table->integer('order')
->after('viewed')
->default(0);
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::table('contents', function (Blueprint $table) {
$table->dropColumn('order');
});
}
}
+6 -74
View File
@@ -340,79 +340,11 @@ img {
width: 100%;
}
/*.tag {*/
/*display: inline-block;*/
/*padding: 0.25em 0.4em;*/
/*font-size: 75%;*/
/*font-weight: bold;*/
/*line-height: 1;*/
/*color: #FFF;*/
/*text-align: center;*/
/*white-space: nowrap;*/
/*vertical-align: baseline;*/
/*border-radius: 0.25rem;*/
/*}*/
/*.tag:empty {*/
/*display: none;*/
/*}*/
/*.btn .tag {*/
/*position: relative;*/
/*top: -1px;*/
/*}*/
/*a.tag:focus, a.tag:hover {*/
/*color: #FFF;*/
/*text-decoration: none;*/
/*cursor: pointer;*/
/*}*/
/*.tag-pill {*/
/*padding-right: 0.6em;*/
/*padding-left: 0.6em;*/
/*border-radius: 10rem;*/
/*}*/
/*.tag-default {*/
/*background-color: #818A91;*/
/*}*/
/*.tag-default[href]:focus, .tag-default[href]:hover {*/
/*background-color: #687077;*/
/*}*/
/*.tag-success {*/
/*background-color: #5CB85C;*/
/*}*/
/*.tag-success[href]:focus, .tag-success[href]:hover {*/
/*background-color: #449D44;*/
/*}*/
/*.tag-info {*/
/*background-color: #5BC0DE;*/
/*}*/
/*.tag-info[href]:focus, .tag-info[href]:hover {*/
/*background-color: #31B0D5;*/
/*}*/
/*.tag-warning {*/
/*background-color: #F0AD4E;*/
/*}*/
/*.tag-warning[href]:focus, .tag-warning[href]:hover {*/
/*background-color: #EC971F;*/
/*}*/
/*.tag-danger {*/
/*background-color: #D9534F;*/
/*}*/
/*.tag-danger[href]:focus, .tag-danger[href]:hover {*/
/*background-color: #C9302C;*/
/*}*/
.has-subpages:hover {
cursor: pointer;
}
#orderSetup .subpage td:first-child {
padding-left: 35px;
}
+10 -2
View File
@@ -386,9 +386,9 @@ $ (document).ready (function () {
$ ('#confirm-button').attr ('href', href);
} else if (tag === 'BUTTON') {
var form = $(this).closest('form');
var form = $ (this).closest ('form');
$ ('#confirm-button').click (function () {
form.submit();
form.submit ();
})
}
@@ -462,3 +462,11 @@ $ ('.checkbox').change (function () {
$ ('#checkbox-parent-' + parent).prop ('checked', true);
}
});
$ ('.has-subpages').click (function (e) {
if (!$ (e.target).is ("div"))
return;
var id = $ (this).data ('id');
$ ('.parent-page-' + id).toggleClass ('hidden-xs-up');
})
@@ -49,6 +49,19 @@
********************************************** */
.item-list {
.subpage {
padding-left: 35px;
}
.thumbnail {
width: 100%;
height: 80px;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
}
.item {
display: flex;
flex-direction: column;
+2
View File
@@ -56,4 +56,6 @@ return [
"title" => "Titulek",
"uploadTitleImage" => "Nahrát titulní obrázek",
"viewPage" => "Zobrazit",
'setOrder' => 'Nastavení pořadí stránek',
'orderSuccessfullySet' => 'Pořadí stránek úspěšně nastaveno',
];
+2 -1
View File
@@ -27,5 +27,6 @@ return [
"widgetAreas" => "Plochy pro widgety",
"widgets" => "Widgety",
"widgetsOverview" => "Všechny widgety",
'permissions' => 'Přístupová práva'
'permissions' => 'Přístupová práva',
'contentOrder' => 'Pořadí stránek'
];
@@ -0,0 +1,16 @@
<tr class="{{$extraClass or ''}}">
<td>
<label class="label-control" for="order-{{$page->id}}">
{{$page->title}}
</label>
</td>
<td>
<input class="form-control" id="order-{{$page->id}}" type="text"
name="page[{{$page->id}}]"
value="{{old('page['.$page->id.']', $page->order)}}" />
@include('admin.snippets.hasError', ['field' => 'page['.$page->id.']'])
</td>
</tr>
@@ -0,0 +1,137 @@
<div data-id="{{$page->id}}" class="row p-tb-15 parent-page-{{$page->parentId or 'none'}} {{$extraClass or ''}}">
<div class="col-md-1 hidden-sm-down text-center with-placeholder">
@can('update', $page)
<a href="{{route('content.edit', ['page' => $page])}}">
@if(!view()->exists(template_name($page->template, false)))
<i class="fa fa-2x text-warning fa-warning" data-toggle="tooltip"
title="@lang('admin/contents.invalidTemplateSelected')"></i>
@else
@if(!empty($page->titlePhoto))
<div class="thumbnail" style="background-image: url(@thumbnail($page->titlePhoto))"></div>
@else
<img src="{{asset('resources/assets/admin/img/placeholder.png')}}"
class="placeholder"
alt="{{$page->title}}" />
@endif
@endif
</a>
@else
@if(!empty($page->titlePhoto))
<img src="@thumbnail($page->titlePhoto)" class="placeholder"
alt="{{$page->title}}" />
@endif
@endcan
</div>
<div class="col-xs-10 col-md-3 col-lg-4">
@can('update', $page)
<a href="{{route('content.edit', ['page' => $page])}}">
{{$page->title}}
</a>
@else
{{$page->title}}
@endcan
@if($page->isHomepage) <span
class="m-l-10 tag tag-primary">@lang('admin/contents.homepage')</span> @endif
</div>
<div class="col-lg-2 col-md-3 hidden-sm-down">
<span class="tag @if($page->isPublic()) tag-success
@elseif ($page->isDraft()) tag-danger
@else tag-warning @endif">{{$statuses[$page->status]}}</span>
</div>
<div class="col-lg-2 col-md-3 hidden-sm-down">
<a href="{{route('content.overview', ['module' => $page->module->alias])}}">
@lang($page->module->name)
</a>
<br>
<small>({{$page->templateModel->name}})</small>
</div>
<div class="col-lg-2 hidden-md-down">@date($page->created_at)</div>
<div class="col-xs-2 col-lg-1 text-center">
<div class="item-actions-dropdown">
<a class="item-actions-toggle-btn">
<span class="inactive">
<i class="fa fa-cog"></i>
</span>
<span class="active">
<i class="fa fa-chevron-circle-right"></i>
</span>
</a>
<div class="item-actions-block">
<ul class="item-actions-list">
@if(!$page->isHomepage)
@can('set-homepage', $page)
<li>
<a href="{{route('content.setHomepage', ['page' => $page])}}"
data-toggle="tooltip"
title="@lang('admin/contents.setHomepage')">
<i class="fa fa-home"></i>
</a>
</li>
@endcan
@endif
@can('update', $page)
<li>
<a class="edit" href="{{route('content.edit', ['page' => $page])}}"
data-toggle="tooltip" title="@lang('admin/contents.editPlain')">
<i class="fa fa-pencil"></i>
</a>
</li>
@endcan
@if($page->isDraft())
@can('publish', $page)
<li>
<a href="{{route('content.changeStatus', ['page' => $page, 'status' => 'public'])}}"
class="confirm" data-toggle="tooltip"
title="@lang('admin/contents.makePublic')">
<i class="fa fa-eye"></i>
</a>
</li>
@endcan
@can('protect', $page)
<li>
<a href="{{route('content.changeStatus', ['page' => $page, 'status' => 'protected'])}}"
class="confirm" data-toggle="tooltip"
title="@lang('admin/contents.makeProtected')">
<i class="fa fa-lock"></i>
</a>
</li>
@endcan
@else
<li>
<a href="{{route('page.content', ['url' => $page->url])}}"
target="_blank"
data-toggle="tooltip" title="@lang('admin/contents.viewPage')"
class="button tiny secondary"><i class="fa fa-globe"></i>
</a>
</li>
@can('draft', $page)
<li>
<a href="{{route('content.changeStatus', ['page' => $page, 'status' => 'draft'])}}"
class="button tiny warning confirm" data-toggle="tooltip"
title="@lang('admin/contents.makeDraft')">
<i class="fa fa-eye-slash"></i>
</a>
</li>
@endcan
@endif
@can('delete', $page)
<li>
<a href="{{route('content.delete', ['page' => $page])}}"
class="button tiny alert remove confirm" data-toggle="tooltip"
title="@lang('admin/contents.deletePage')"><i
class="fa fa-trash-o"></i>
</a>
</li>
@endcan
</ul>
</div>
</div>
</div>
</div>
@@ -0,0 +1,39 @@
@extends('admin.layoutWithNavigation')
@section('pageHeading', trans('admin/contents.setOrder'))
@section('content')
@if (count($pages) > 0)
<div class="card items" id="orderSetup">
<div class="card-block">
<form method="POST" enctype="multipart/form-data" class="form-inline"
action="{{route('content.setOrder')}}">
{!! csrf_field() !!}
<table>
@foreach($pages as $page)
@include('admin.content._partials.orderSetupRow')
@foreach($page->subpages as $subpage)
@include('admin.content._partials.orderSetupRow', ['page' => $subpage, 'extraClass' => 'subpage'])
@endforeach
@endforeach
</table>
<button type="submit" class="btn btn-primary">@lang('admin/contents.save')</button>
</form>
</div>
<div class="card-footer">
</div>
</div>
@else
<div class="alert alert-info">
@lang('admin/contents.noPagesAvailable')
</div>
@endif
@endsection
@@ -46,142 +46,11 @@
<div class="col-xs-2 col-lg-1">@lang('admin/contents.actions')</div>
</div>
@foreach($pages as $page)
<div class="row p-tb-15">
<div class="col-md-1 hidden-sm-down text-center with-placeholder">
@can('update', $page)
<a href="{{route('content.edit', ['page' => $page])}}">
@if(!view()->exists(template_name($page->template, false)))
<i class="fa fa-2x text-warning fa-warning" data-toggle="tooltip"
title="@lang('admin/contents.invalidTemplateSelected')"></i>
@else
@if(!empty($page->titlePhoto))
<img src="@thumbnail($page->titlePhoto)" class="placeholder"
alt="{{$page->title}}" />
@else
<img src="{{asset('resources/assets/admin/img/placeholder.png')}}"
class="placeholder"
alt="{{$page->title}}" />
@endif
@endif
</a>
@else
@if(!empty($page->titlePhoto))
<img src="@thumbnail($page->titlePhoto)" class="placeholder"
alt="{{$page->title}}" />
@endif
@endcan
</div>
<div class="col-xs-10 col-md-3 col-lg-4">
@can('update', $page)
<a href="{{route('content.edit', ['page' => $page])}}">
{{$page->title}}
</a>
@else
{{$page->title}}
@endcan
@include('admin.content._partials.overviewRow', ['extraClass' => $page->subpages->isEmpty() ?: 'has-subpages'])
@if($page->isHomepage) <span
class="m-l-10 tag tag-primary">@lang('admin/contents.homepage')</span> @endif
</div>
<div class="col-lg-2 col-md-3 hidden-sm-down">
<span class="tag @if($page->isPublic()) tag-success
@elseif ($page->isDraft()) tag-danger
@else tag-warning @endif">{{$statuses[$page->status]}}</span>
</div>
<div class="col-lg-2 col-md-3 hidden-sm-down">
<a href="{{route('content.overview', ['module' => $page->module->alias])}}">
{{trans($page->module_name)}}
</a>
</div>
<div class="col-lg-2 hidden-md-down">@date($page->created_at)</div>
<div class="col-xs-2 col-lg-1 text-center">
<div class="item-actions-dropdown">
<a class="item-actions-toggle-btn">
<span class="inactive">
<i class="fa fa-cog"></i>
</span>
<span class="active">
<i class="fa fa-chevron-circle-right"></i>
</span>
</a>
<div class="item-actions-block">
<ul class="item-actions-list">
@if(!$page->isHomepage)
@can('set-homepage', $page)
<li>
<a href="{{route('content.setHomepage', ['page' => $page])}}"
data-toggle="tooltip"
title="@lang('admin/contents.setHomepage')">
<i class="fa fa-home"></i>
</a>
</li>
@endcan
@endif
@can('update', $page)
<li>
<a class="edit" href="{{route('content.edit', ['page' => $page])}}"
data-toggle="tooltip" title="@lang('admin/contents.editPlain')">
<i class="fa fa-pencil"></i>
</a>
</li>
@endcan
@if($page->isDraft())
@can('publish', $page)
<li>
<a href="{{route('content.changeStatus', ['page' => $page, 'status' => 'public'])}}"
class="confirm" data-toggle="tooltip"
title="@lang('admin/contents.makePublic')">
<i class="fa fa-eye"></i>
</a>
</li>
@endcan
@can('protect', $page)
<li>
<a href="{{route('content.changeStatus', ['page' => $page, 'status' => 'protected'])}}"
class="confirm" data-toggle="tooltip"
title="@lang('admin/contents.makeProtected')">
<i class="fa fa-lock"></i>
</a>
</li>
@endcan
@else
<li>
<a href="{{route('page.content', ['url' => $page->url])}}"
target="_blank"
data-toggle="tooltip" title="@lang('admin/contents.viewPage')"
class="button tiny secondary"><i class="fa fa-globe"></i>
</a>
</li>
@can('draft', $page)
<li>
<a href="{{route('content.changeStatus', ['page' => $page, 'status' => 'draft'])}}"
class="button tiny warning confirm" data-toggle="tooltip"
title="@lang('admin/contents.makeDraft')">
<i class="fa fa-eye-slash"></i>
</a>
</li>
@endcan
@endif
@can('delete', $page)
<li>
<a href="{{route('content.delete', ['page' => $page])}}"
class="button tiny alert remove confirm" data-toggle="tooltip"
title="@lang('admin/contents.deletePage')"><i
class="fa fa-trash-o"></i>
</a>
</li>
@endcan
</ul>
</div>
</div>
</div>
</div>
@foreach($page->subpages as $subpage)
@include('admin.content._partials.overviewRow', ['page' => $subpage, 'extraClass' => 'subpage hidden-xs-up'])
@endforeach
@endforeach
</div>
</div>
+3
View File
@@ -50,4 +50,7 @@ Route::group(['namespace' => 'Contents'], function () {
Route::get('history/diff/{revision}', 'History@getDiff')
->name('history.diff')
->middleware('can:viewHistory,'.\App\Models\Content\Content::class);
Route::get('content/order', 'EditContent@order')->name('content.order');
Route::post('content/order', 'EditContent@setOrder')->name('content.setOrder');
});