class Book extends Entity
{
- protected $fillable = ['name', 'description', 'image'];
+ protected $fillable = ['name', 'description', 'image_id'];
/**
* Get the url for this book.
}
return baseUrl('/books/' . urlencode($this->slug));
}
-
- public function getBookCover()
+
+ /**
+ * Returns book cover image, if book cover not exists return default cover image.
+ * @param int $height - Height of the image
+ * @param type $width - Width of the image
+ * @return type string
+ */
+ public function getBookCover($height = 170, $width = 300)
{
- $default = baseUrl('/default.png');
- $image = $this->image;
+ $default = baseUrl('/book_default_cover.png');
+ $image = $this->image_id;
if ($image === 0 || $image === '0' || $image === null)
return $default;
try {
- $cover = $this->cover ? baseUrl($this->cover->getThumb(120, 192, false)) : $default;
+ $cover = $this->cover ? baseUrl($this->cover->getThumb($width, $height, false)) : $default;
} catch (\Exception $err) {
$cover = $default;
}
return $cover;
}
-
+
+ /**
+ * Get an excerpt of this book's name to the specified length or less.
+ * @param int $length
+ * @return string
+ */
public function getHeadingExcerpt($length = 35)
{
$bookHeading = $this->name;
return strlen($bookHeading) > $length ? substr($bookHeading, 0, $length-3) . '...' : $bookHeading;
}
+ /**
+ * Get the cover image of the book
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
+ */
public function cover()
{
- return $this->belongsTo(Image::class, 'image');
+ return $this->belongsTo(Image::class, 'image_id');
}
/*
* Get the edit url for this book.
{
return "'BookStack\\\\Book' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text,'' as html, '0' as book_id, '0' as priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at";
}
+
+ /**
+ * Get the user that created the page revision
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
+ */
+ public function createdBy()
+ {
+ return $this->belongsTo(User::class, 'created_by');
+ }
}
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
$popular = $this->entityRepo->getPopular('book', 4, 0);
$new = $this->entityRepo->getRecentlyCreated('book', 4, 0);
+ $booksViewType = $this->currentUser->books_view_type;
$this->setPageTitle('Books');
return view('books/index', [
'books' => $books,
'recents' => $recents,
'popular' => $popular,
- 'new' => $new
+ 'new' => $new,
+ 'booksViewType' => $booksViewType
]);
}
* The attributes that are mass assignable.
* @var array
*/
- protected $fillable = ['name', 'email', 'image_id', 'books_display' ];
+ protected $fillable = ['name', 'email', 'image_id', 'books_view_type' ];
/**
* The attributes excluded from the model's JSON form.
<?php
define('LARAVEL_START', microtime(true));
+ini_set('xdebug.max_nesting_level', 120);
/*
|--------------------------------------------------------------------------
|
*/
- 'debug' => env('APP_DEBUG', false),
+ 'debug' => env('APP_DEBUG', true),
/*
|--------------------------------------------------------------------------
};
});
-// Global jQuery Elements
-let notifications = $('.notification');
-let successNotification = notifications.filter('.pos');
-let errorNotification = notifications.filter('.neg');
-let warningNotification = notifications.filter('.warning');
-// Notification Events
-window.Events.listen('success', function (text) {
- successNotification.hide();
- successNotification.find('span').text(text);
- setTimeout(() => {
- successNotification.show();
- }, 1);
-});
-window.Events.listen('warning', function (text) {
- warningNotification.find('span').text(text);
- warningNotification.show();
-});
-window.Events.listen('error', function (text) {
- errorNotification.find('span').text(text);
- errorNotification.show();
-});
-
-// Notification hiding
-notifications.click(function () {
- $(this).fadeOut(100);
-});
-
-// Chapter page list toggles
-$('.chapter-toggle').click(function (e) {
- e.preventDefault();
- $(this).toggleClass('open');
- $(this).closest('.chapter').find('.inset-list').slideToggle(180);
-});
-
-// Back to top button
-$('#back-to-top').click(function() {
- $('#header').smoothScrollTo();
-});
-let scrollTopShowing = false;
-let scrollTop = document.getElementById('back-to-top');
-let scrollTopBreakpoint = 1200;
-window.addEventListener('scroll', function() {
- let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0;
- if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) {
- scrollTop.style.display = 'block';
- scrollTopShowing = true;
- setTimeout(() => {
- scrollTop.style.opacity = 0.4;
- }, 1);
- } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) {
- scrollTop.style.opacity = 0;
- scrollTopShowing = false;
- setTimeout(() => {
- scrollTop.style.display = 'none';
- }, 500);
- }
-});
-
// Common jQuery actions
$('[data-action="expand-entity-list-details"]').click(function() {
$('.entity-list.compact').find('p').not('.empty-text').slideToggle(240);
});
});
-// Popup close
-$('.popup-close').click(function() {
- $(this).closest('.overlay').fadeOut(240);
-});
-$('.overlay').click(function(event) {
- if (!$(event.target).hasClass('overlay')) return;
- $(this).fadeOut(240);
-});
// Detect IE for css
if(navigator.userAgent.indexOf('MSIE')!==-1
}
}
+// styles for Books grid view
+.cover {
+ width: 290px;
+ border-radius: 3px;
+ }
+.featured-image-container {
+ position: relative;
+ overflow: hidden;
+ background: #F2F2F2;
+ border: 1px solid #ddd;
+ border-bottom: 0px;
+}
-.gallery-item {
- margin-bottom: 32px;
- height: 350px;
- overflow: hidden;
- border: 1px solid #ccc;
- h4 {
- font-size: 1.2em;
- text-align: center;
- height: 55px;
- padding: 0px 12px;
- }
- p {
- font-size: 0.8em;
- text-align: center;
- padding: 0px 12px;
- }
- &.collapse {
- height: 150px;
- }
+.featured-image-container img {
+ display: block;
+ max-width: 100%;
+ height: auto;
+ -webkit-transition: all .5s ease;
+ -moz-transition: all .5s ease;
+ -ms-transition: all .5s ease;
+ -o-transition: all .5s ease;
+ transition: all .5s ease;
}
-.gallery-image {
- margin-top: 5%;
- text-align: center;
- img {
- border-radius: 3px;
- }
+.book-content {
+ padding: 30px;
+ border: 1px solid #ddd;
+ border-top: 0px;
+ border-bottom-width: 2px;
+}
+.book-content h2 {
+ font-size: 1.5em;
+ line-height: 1.2;
+ margin: 0 0 10px;
}
-.cover {
- height: 192px;
- width: 120px;
- border-radius: 3px;
- }
\ No newline at end of file
+.book-content h2 a {
+ display: block;
+ color: #009688;;
+ text-decoration: none;
+}
+
+.book-content p {
+ font-size: .85em;
+ margin: 0 0 10px;
+ line-height: 1.6em;
+}
+
+.featured-image-container img:hover {
+ -webkit-transform: scale(1.15);
+ -moz-transform: scale(1.15);
+ -ms-transform: scale(1.15);
+ -o-transform: scale(1.15);
+ transform: scale(1.15);
+ opacity: .5;
+}
+.books-grid-div {
+ margin-bottom : 20px;
+}
+
+@media (min-width:992px){
+ .row.auto-clear .col-md-4:nth-child(3n+1){clear:left;}
+}
+@media (min-width:992px){
+ .row.auto-clear .col-md-4:nth-child(3n+1){clear:left;}
+}
+@media (max-width:991px){
+ .row.auto-clear .col-xs-6:nth-child(2n+1){clear:left;}
+}
\ No newline at end of file
'users_delete_warning' => 'Der Benutzer ":userName" wird aus dem System gelöscht.',
'users_delete_confirm' => 'Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?',
'users_delete_success' => 'Benutzer erfolgreich gelöscht.',
- 'users_books_display_type' => 'Bevorzugtes Display-Layout für Bücher',
+ 'users_books_view_type' => 'Bevorzugtes Display-Layout für Bücher',
'users_edit' => 'Benutzer bearbeiten',
'users_edit_profile' => 'Profil bearbeiten',
'users_edit_success' => 'Benutzer erfolgreich aktualisisert',
'users_external_auth_id' => 'External Authentication ID',
'users_password_warning' => 'Only fill the below if you would like to change your password:',
'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.',
- 'users_books_display_type' => 'Preferred layout for books viewing',
+ 'users_books_view_type' => 'Preferred layout for books viewing',
'users_delete' => 'Delete User',
'users_delete_named' => 'Delete user :userName',
'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.',
'users_external_auth_id' => 'ID externo de autenticación',
'users_password_warning' => 'Solo rellene a continuación si desea cambiar su password:',
'users_system_public' => 'Este usuario representa cualquier usuario invitado que visita la aplicación. No puede utilizarse para hacer login sio que es asignado automáticamente.',
- 'users_books_display_type' => 'Diseño de pantalla preferido para libros',
+ 'users_books_view_type' => 'Diseño de pantalla preferido para libros',
'users_delete' => 'Borrar usuario',
'users_delete_named' => 'Borrar usuario :userName',
'users_delete_warning' => 'Se borrará completamente el usuario con el nombre \':userName\' del sistema.',
'users_external_auth_id' => 'Identifiant d\'authentification externe',
'users_password_warning' => 'Remplissez ce fomulaire uniquement si vous souhaitez changer de mot de passe:',
'users_system_public' => 'Cet utilisateur représente les invités visitant votre instance. Il est assigné automatiquement aux invités.',
- 'users_books_display_type' => 'Disposition d\'affichage préférée pour les livres',
+ 'users_books_view_type' => 'Disposition d\'affichage préférée pour les livres',
'users_delete' => 'Supprimer un utilisateur',
'users_delete_named' => 'Supprimer l\'utilisateur :userName',
'users_delete_warning' => 'Ceci va supprimer \':userName\' du système.',
'users_external_auth_id' => 'External Authentication ID',
'users_password_warning' => 'Vul onderstaande formulier alleen in als je het wachtwoord wilt aanpassen:',
'users_system_public' => 'De eigenschappen van deze gebruiker worden voor elke gastbezoeker gebruikt. Er kan niet mee ingelogd worden en wordt automatisch toegewezen.',
- 'users_books_display_type' => 'Voorkeursuitleg voor het weergeven van boeken',
+ 'users_books_view_type' => 'Voorkeursuitleg voor het weergeven van boeken',
'users_delete' => 'Verwijder gebruiker',
'users_delete_named' => 'Verwijder gebruiker :userName',
'users_delete_warning' => 'Dit zal de gebruiker \':userName\' volledig uit het systeem verwijderen.',
'users_external_auth_id' => 'ID de Autenticação Externa',
'users_password_warning' => 'Preencha os dados abaixo caso queira modificar a sua senha:',
'users_system_public' => 'Esse usuário representa quaisquer convidados que visitam o aplicativo. Ele não pode ser usado para login.',
- 'users_books_display_type' => 'Layout preferido para mostrar livros',
+ 'users_books_view_type' => 'Layout preferido para mostrar livros',
'users_delete' => 'Excluir Usuário',
'users_delete_named' => 'Excluir :userName',
'users_delete_warning' => 'A ação vai excluir completamente o usuário de nome \':userName\' do sistema.',
'users_external_auth_id' => 'Externé autentifikačné ID',
'users_password_warning' => 'Pole nižšie vyplňte iba ak chcete zmeniť heslo:',
'users_system_public' => 'Tento účet reprezentuje každého hosťovského používateľa, ktorý navštívi Vašu inštanciu. Nedá sa pomocou neho prihlásiť a je priradený automaticky.',
- 'users_books_display_type' => 'Preferované rozloženie pre prezeranie kníh',
+ 'users_books_view_type' => 'Preferované rozloženie pre prezeranie kníh',
'users_delete' => 'Zmazať používateľa',
'users_delete_named' => 'Zmazať používateľa :userName',
'users_delete_warning' => ' Toto úplne odstráni používateľa menom \':userName\' zo systému.',
<p class="small">{{ trans('common.cover_image_description') }}</p>
@include('components.image-picker', [
- 'resizeHeight' => '192',
- 'resizeWidth' => '120',
+ 'resizeHeight' => '512',
+ 'resizeWidth' => '512',
'showRemove' => true,
'defaultImage' => baseUrl('/default.png'),
- 'currentImage' => @isset($model) ? $model->getBookCover(80) : baseUrl('/default.png') ,
- 'currentId' => @isset($model) ? $model->image : 0,
- 'name' => 'image',
+ 'currentImage' => @isset($model) ? $model->getBookCover() : baseUrl('/default.png') ,
+ 'currentId' => @isset($model) ? $model->image_id : 0,
+ 'name' => 'image_id',
'imageClass' => 'cover'
])
</div>
-<div class="col-xs-6 col-sm-4 col-md-4 col-lg-3" data-entity-type="book" data-entity-id="{{$book->id}}">
- <div class="gallery-item">
- <h4>
- <a class="text-book entity-list-item-link" href="{{$book->getUrl()}}" title="{{$book->name}}"><i class="zmdi zmdi-book"></i><span class="entity-list-item-name">{{$book->getHeadingExcerpt()}}</span>
- <br>
- </a>
- </h4>
- <div class="gallery-image">
- <a class="text-book entity-list-item-link" href="{{$book->getUrl()}}">
- <img src="{{$book->getBookCover()}}" alt="{{$book->name}}">
+<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 books-grid-div" data-entity-type="book" data-entity-id="{{$book->id}}">
+ <div class="featured-image-container">
+ <a href="{{$book->getUrl()}}" title="{{$book->name}}">
+ <img width="1600" height="900" src="{{$book->getBookCover()}}" alt="{{$book->name}}">
</a>
</div>
- @if(isset($book->searchSnippet))
- <p class="text-muted">{!! $book->searchSnippet !!}</p>
- @else
- <p class="text-muted">{{ $book->getExcerpt(80) }}</p>
- @endif
-</div>
+ <div class="book-content">
+ <h2><a href="{{$book->getUrl()}}" title="{{$book->name}}" > {{$book->getHeadingExcerpt()}} </a></h2>
+ @if(isset($book->searchSnippet))
+ <p >{{!! $book->searchSnippet !!}}</p>
+ @else
+ <p >{{ $book->getExcerpt(130) }}</p>
+ @endif
+ <div >
+ <span>@include('partials.entity-meta', ['entity' => $book])</span>
+ </div>
+ </div>
</div>
\ No newline at end of file
@stop
@section('body')
-
- <div class="container small" ng-non-bindable>
+ @if($booksViewType === 'list')
+ <div class="container small" ng-non-bindable>
+ @else
+ <div class="container" ng-non-bindable>
+ @endif
<h1>{{ trans('entities.books') }}</h1>
@if(count($books) > 0)
- @foreach($books as $book)
- @include('books/list-item', ['book' => $book])
- <hr>
- @endforeach
- {!! $books->render() !!}
+ @if($booksViewType === 'list')
+ @foreach($books as $book)
+ @include('books/list-item', ['book' => $book])
+ <hr>
+ @endforeach
+ {!! $books->render() !!}
+ @else
+ <div class="row auto-clear">
+ @foreach($books as $key => $book)
+ @include('books/grid-item', ['book' => $book])
+ @endforeach
+ <div class="col-xs-12">
+ {!! $books->render() !!}
+ </div>
+ </div>
+ @endif
@else
<p class="text-muted">{{ trans('entities.books_empty') }}</p>
@if(userCan('books-create-all'))
@endif
@endif
</div>
-
@stop
\ No newline at end of file
@endforeach
</select>
</div>
+ <div class="form-group">
+ <label for="books-view-type">{{ trans('settings.users_books_view_type') }}</label>
+ <select name="books_view_type" id="books-view-type">
+ <option @if($user->books_view_type === 'grid') selected @endif value="grid">Grid</option>
+ <option @if($user->books_view_type === 'list') selected @endif value="list">List</option>
+ </select>
+ </div>
</div>
</div>
<div class="form-group text-right">
->see('cannot delete the guest user');
}
- public function test_books_display_is_list()
+ public function test_books_view_is_list()
{
$editor = $this->getEditor([
- 'books_display' => 'list'
+ 'books_view_type' => 'list'
]);
$this->actingAs($editor)
->visit('/books')
- ->pageNotHasElement('.gallery-item')
+ ->pageNotHasElement('.featured-image-container')
->pageHasElement('.entity-list-item');
}
- public function test_books_display_is_grid()
+ public function test_books_view_is_grid()
{
$editor = $this->getEditor([
- 'books_display' => 'grid'
+ 'books_view_type' => 'grid'
]);
$this->actingAs($editor)
->visit('/books')
- ->pageHasElement('.gallery-item');
+ ->pageHasElement('.featured-image-container');
}
}