]> BookStack Code Mirror - bookstack/commitdiff
Merge branch 'master' of git://github.com/BookStackApp/BookStack into BookStackApp...
authorBharadwaja G <redacted>
Tue, 29 Aug 2017 06:49:00 +0000 (12:19 +0530)
committerBharadwaja G <redacted>
Tue, 29 Aug 2017 06:49:00 +0000 (12:19 +0530)
Conflicts:
app/Http/Controllers/BookController.php
resources/lang/en/common.php
resources/views/books/create.blade.php
resources/views/books/form.blade.php
resources/views/books/index.blade.php
resources/views/users/edit.blade.php
tests/Entity/EntityTest.php

1  2 
app/Http/Controllers/BookController.php
resources/assets/js/global.js
resources/assets/sass/styles.scss
resources/lang/en/common.php
resources/lang/en/settings.php
resources/views/books/create.blade.php
resources/views/books/edit.blade.php
resources/views/books/form.blade.php
resources/views/users/edit.blade.php

index eecb7839f378439519a57a2c526f845fab22d958,5342ece6bafbc60be02d6053b1b4cbd36c14ee9f..d515d83a3ac921a19fa98e6752aa1e61222eabe5
@@@ -36,12 -36,17 +36,17 @@@ class BookController extends Controlle
       */
      public function index()
      {
-         $books = $this->entityRepo->getAllPaginated('book', 16);
+         $books = $this->entityRepo->getAllPaginated('book', 20);
          $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
-         $popular = $this->entityRepo->getPopular('book', 3, 0);
-         $books_display = $this->currentUser->books_display;
+         $popular = $this->entityRepo->getPopular('book', 4, 0);
+         $new = $this->entityRepo->getRecentlyCreated('book', 4, 0);
          $this->setPageTitle('Books');
-         return view('books/index', ['books' => $books, 'recents' => $recents, 'popular' => $popular, 'books_display' => $books_display] );
+         return view('books/index', [
+             'books' => $books,
+             'recents' => $recents,
+             'popular' => $popular,
+             'new' => $new
+         ]);
      }
  
      /**
          $bookChildren = $this->entityRepo->getBookChildren($book);
          Views::add($book);
          $this->setPageTitle($book->getShortName());
-         return view('books/show', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]);
+         return view('books/show', [
+             'book' => $book,
+             'current' => $book,
+             'bookChildren' => $bookChildren,
+             'activity' => Activity::entityActivity($book, 20, 0)
+         ]);
      }
  
      /**
              'name' => 'required|string|max:255',
              'description' => 'string|max:1000'
          ]);
 -        $book = $this->entityRepo->updateFromInput('book', $book, $request->all());
 -        Activity::add($book, 'book_update', $book->id);
 -        return redirect($book->getUrl());
 +         $book = $this->entityRepo->updateFromInput('book', $book, $request->all());
 +         Activity::add($book, 'book_update', $book->id);
 +         return redirect($book->getUrl());
      }
  
      /**
index 966adb75d9f6b37b66e6df2bdc8315c3df33becd,85f9f77a6867504572d4ba206f83a255c648ea21..176aff7330014f77e655e57c5375e29189606be5
@@@ -1,5 -1,6 +1,6 @@@
  "use strict";
  require("babel-polyfill");
+ require('./dom-polyfills');
  
  // Url retrieval function
  window.baseUrl = function(path) {
  class EventManager {
      constructor() {
          this.listeners = {};
+         this.stack = [];
      }
  
      emit(eventName, eventData) {
+         this.stack.push({name: eventName, data: eventData});
          if (typeof this.listeners[eventName] === 'undefined') return this;
          let eventsToStart = this.listeners[eventName];
          for (let i = 0; i < eventsToStart.length; i++) {
@@@ -32,7 -35,7 +35,7 @@@
      }
  }
  
- window.Events = new EventManager();
+ window.$events = new EventManager();
  
  const Vue = require("vue");
  const axios = require("axios");
@@@ -47,13 -50,13 +50,13 @@@ axiosInstance.interceptors.request.use(
      return resp;
  }, err => {
      if (typeof err.response === "undefined" || typeof err.response.data === "undefined") return Promise.reject(err);
-     if (typeof err.response.data.error !== "undefined") window.Events.emit('error', err.response.data.error);
-     if (typeof err.response.data.message !== "undefined") window.Events.emit('error', err.response.data.message);
+     if (typeof err.response.data.error !== "undefined") window.$events.emit('error', err.response.data.error);
+     if (typeof err.response.data.message !== "undefined") window.$events.emit('error', err.response.data.message);
  });
  window.$http = axiosInstance;
  
  Vue.prototype.$http = axiosInstance;
- Vue.prototype.$events = window.Events;
+ Vue.prototype.$events = window.$events;
  
  
  // AngularJS - Create application and load components
@@@ -78,8 -81,8 +81,8 @@@ require("./components")
  // Load in angular specific items
  const Directives = require('./directives');
  const Controllers = require('./controllers');
- Directives(ngApp, window.Events);
- Controllers(ngApp, window.Events);
+ Directives(ngApp, window.$events);
+ Controllers(ngApp, window.$events);
  
  //Global jQuery Config & Extensions
  
@@@ -99,85 -102,6 +102,85 @@@ jQuery.expr[":"].contains = $.expr.crea
      };
  });
  
 +// 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);
 +});
 +
 +// Toggle thumbnail::hide image and reduce grid size
 +$(document).ready(function(){
 +   $('[data-action="expand-thumbnail"]').click(function(){
 +     $('.gallery-item').toggleClass("collapse").find('img').slideToggle(50);
 +   });
 +});
 +
 +// 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
      || navigator.appVersion.indexOf('Trident/') > 0
index 51e47ea7487f8fdc776b02abd5277cba230f5955,3a6f9e06249e369e7241f541054b30031b8b162b..b0b41afc77a4eb88e5a47d3bb94a204413afba6e
@@@ -217,57 -217,16 +217,50 @@@ $btt-size: 40px
  }
  
  .center-box {
-   margin: $-xl auto 0 auto;
-   padding: $-m $-xxl $-xl $-xxl;
+   margin: $-xxl auto 0 auto;
    width: 420px;
    max-width: 100%;
    display: inline-block;
    text-align: left;
    vertical-align: top;
-   //border: 1px solid #DDD;
    input {
      width: 100%;
    }
-   &.login {
-     background-color: #EEE;
-     box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
-     border: 1px solid #DDD;
-   }
  }
  
  
  
 +.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;
 +  }
 +}
 +
 +.gallery-image {
 +  margin-top: 5%;
 +  text-align: center;
 +  img {
 +    border-radius: 3px;
 +  }
 +}
 +
 +.cover {
 +    height: 192px;
 +    width: 120px;
 +    border-radius: 3px;
 +  }
index 9f35ddac7ed50f9f1704b2230121bcda7882e17c,06b98097072c61f8b704370f19b8150b15b655c5..8af2e4b2c0ccaa19331dc85e7a045e0cff509e7a
@@@ -10,6 -10,7 +10,7 @@@ return 
      'save' => 'Save',
      'continue' => 'Continue',
      'select' => 'Select',
+     'more' => 'More',
  
      /**
       * Form Labels
@@@ -17,8 -18,7 +18,8 @@@
      'name' => 'Name',
      'description' => 'Description',
      'role' => 'Role',
 -
 +    'cover_image' => 'Cover image',
 +    'cover_image_description' => 'The image should be in a height/width ratio of 1.6:1.',
      /**
       * Actions
       */
@@@ -36,7 -36,6 +37,6 @@@
      'remove' => 'Remove',
      'add' => 'Add',
  
      /**
       * Misc
       */
@@@ -45,8 -44,8 +45,8 @@@
      'no_items' => 'No items available',
      'back_to_top' => 'Back to top',
      'toggle_details' => 'Toggle Details',
 +    'toggle_thumbnails' => 'Toggle Thumbnails',
 -
+     'details' => 'Details',
      /**
       * Header
       */
index 0a7547a584aa7002a1f936122a3ee44b78aaa0de,c4c8bfc785463833ab3a447bcf70491918fef51f..14b5371ffa4d46ec0d4e6598bbfc11e80d1b35a7
@@@ -31,6 -31,9 +31,9 @@@ return 
      'app_logo_desc' => 'This image should be 43px in height. <br>Large images will be scaled down.',
      'app_primary_color' => 'Application primary color',
      'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.',
+     'app_homepage' => 'Application Homepage',
+     'app_homepage_desc' => 'Select a page to show on the homepage instead of the default view. Page permissions are ignored for selected pages.',
+     'app_homepage_default' => 'Default homepage view chosen',
  
      /**
       * Registration settings
@@@ -91,7 -94,6 +94,7 @@@
      '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_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.',
index 4d1edf78bf4cfa204bc19d73e92b2fa55011fbb5,385e6b9d7a4e868f4a5b42acf4585c287068c8cd..4798459c21672b2068ecb1d2bb63c5ac932da595
@@@ -1,13 -1,27 +1,28 @@@
- @extends('base')
+ @extends('simple-layout')
  
- @section('content')
+ @section('toolbar')
+     <div class="col-sm-8 faded">
+         <div class="breadcrumbs">
+             <a href="{{ baseUrl('/books') }}" class="text-button"><i class="zmdi zmdi-book"></i>{{ trans('entities.books') }}</a>
+             <span class="sep">&raquo;</span>
+             <a href="{{ baseUrl('/books/create') }}" class="text-button"><i class="zmdi zmdi-plus"></i>{{ trans('entities.books_create') }}</a>
+         </div>
+     </div>
+ @stop
  
- <div class="container small" ng-non-bindable>
-     <h1>{{ trans('entities.books_create') }}</h1>
-     <form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data">
-         @include('books/form')
-     </form>
+ @section('body')
+ <div ng-non-bindable class="container small">
+     <p>&nbsp;</p>
+     <div class="card">
+         <h3><i class="zmdi zmdi-plus"></i> {{ trans('entities.books_create') }}</h3>
+         <div class="body">
 -            <form action="{{ baseUrl("/books") }}" method="POST">
++            <form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data">
+                 @include('books/form')
+             </form>
+         </div>
+     </div>
  </div>
 -
 +<p class="margin-top large"><br></p>
 +    @include('components.image-manager', ['imageType' => 'cover'])
  @stop
index 322f3d7001d54bf55e83ed1cf37ad9d817802f3a,9d9c54fec6e521e909c6e5ce159c640c975dc3e5..6bf285f95f2f8fcbe2c76499370eec2e860f046f
@@@ -1,23 -1,24 +1,24 @@@
- @extends('base')
+ @extends('simple-layout')
  
- @section('content')
-     <div class="faded-small toolbar">
-         <div class="container">
-             <div class="row">
-                 <div class="col-sm-12 faded">
-                     @include('books._breadcrumbs', ['book' => $book])
-                 </div>
-             </div>
-         </div>
+ @section('toolbar')
+     <div class="col-sm-12 faded">
+         @include('books._breadcrumbs', ['book' => $book])
      </div>
+ @stop
+ @section('body')
  
      <div class="container small" ng-non-bindable>
-         <h1>{{ trans('entities.books_edit') }}</h1>
-         <form action="{{ $book->getUrl() }}" method="POST">
-             <input type="hidden" name="_method" value="PUT">
-             @include('books/form', ['model' => $book])
-         </form>
+         <p>&nbsp;</p>
+         <div class="card">
+             <h3><i class="zmdi zmdi-edit"></i> {{ trans('entities.books_edit') }}</h3>
+             <div class="body">
+                 <form action="{{ $book->getUrl() }}" method="POST">
+                     <input type="hidden" name="_method" value="PUT">
+                     @include('books/form', ['model' => $book])
+                 </form>
+             </div>
+         </div>
      </div>
 -
 +@include('components.image-manager', ['imageType' => 'cover'])
  @stop
index e26edac4b8881da26ff2874e03dcbfb102101272,84a30e7e9982a40e7e0c5ecfe9c1bf752c9693b3..fc30093d2e05fc6e5d0b553a5ba74fb38c2be264
@@@ -9,22 -9,8 +9,23 @@@
      <label for="description">{{ trans('common.description') }}</label>
      @include('form/textarea', ['name' => 'description'])
  </div>
- <div class="form-group">
-     <a href="{{ isset($book) ? $book->getUrl() : baseUrl('/books') }}" class="button muted">{{ trans('common.cancel') }}</a>
 +<div class="form-group" id="logo-control">
 +        <label for="user-avatar">{{ trans('common.cover_image') }}</label>
 +        <p class="small">{{ trans('common.cover_image_description') }}</p>
 +
 +        @include('components.image-picker', [
 +            'resizeHeight' => '192',
 +            'resizeWidth' => '120',
 +            'showRemove' => true,
 +            'defaultImage' => baseUrl('/default.png'),
 +            'currentImage' => @isset($model) ? $model->getBookCover(80) : baseUrl('/default.png') ,
 +            'currentId' => @isset($model) ? $model->image : 0,
 +            'name' => 'image',
 +            'imageClass' => 'cover'
 +        ])
 +</div>
+ <div class="form-group text-right">
+     <a href="{{ isset($book) ? $book->getUrl() : baseUrl('/books') }}" class="button outline">{{ trans('common.cancel') }}</a>
      <button type="submit" class="button pos">{{ trans('entities.books_save') }}</button>
  </div>
index c15e34974666346447ee533e5bfa60dc349ddffc,f860d12fd96a27dbb110f1a6705b9966f99a6e98..fc75593b824b7221e869437727c59768a1d42d46
@@@ -1,87 -1,84 +1,84 @@@
- @extends('base')
- @section('content')
+ @extends('simple-layout')
  
+ @section('toolbar')
      @include('settings/navbar', ['selected' => 'users'])
+ @stop
+ @section('body')
  
      <div class="container small">
-         <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
-             <div class="row">
-                 <div class="col-sm-8">
-                     <h1>{{ $user->id === $currentUser->id ? trans('settings.users_edit_profile') : trans('settings.users_edit') }}</h1>
-                 </div>
-                 <div class="col-sm-4">
-                     <p></p>
-                     @if($authMethod !== 'system')
-                         <a href="{{ baseUrl("/settings/users/{$user->id}/delete") }}" class="neg button float right">{{ trans('settings.users_delete') }}</a>
-                     @endif
-                 </div>
-             </div>
-             <div class="row">
-                 <div class="col-sm-6" ng-non-bindable>
-                     {!! csrf_field() !!}
-                     <input type="hidden" name="_method" value="put">
-                     @include('users.forms.' . $authMethod, ['model' => $user])
+         <p>&nbsp;</p>
+         <div class="card">
+             <h3><i class="zmdi-edit zmdi"></i> {{ $user->id === $currentUser->id ? trans('settings.users_edit_profile') : trans('settings.users_edit') }}</h3>
+             <div class="body">
+                 <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
+                     <div class="row">
+                         <div class="col-sm-6" ng-non-bindable>
+                             {!! csrf_field() !!}
+                             <input type="hidden" name="_method" value="put">
+                             @include('users.forms.' . $authMethod, ['model' => $user])
  
-                 </div>
-                 <div class="col-sm-6">
-                     <div class="form-group" id="logo-control">
-                         <label for="user-avatar">{{ trans('settings.users_avatar') }}</label>
-                         <p class="small">{{ trans('settings.users_avatar_desc') }}</p>
+                         </div>
+                         <div class="col-sm-6">
+                             <div class="form-group" id="logo-control">
+                                 <label for="user-avatar">{{ trans('settings.users_avatar') }}</label>
+                                 <p class="small">{{ trans('settings.users_avatar_desc') }}</p>
  
-                         @include('components.image-picker', [
-                               'resizeHeight' => '512',
-                               'resizeWidth' => '512',
-                               'showRemove' => false,
-                               'defaultImage' => baseUrl('/user_avatar.png'),
-                               'currentImage' => $user->getAvatar(80),
-                               'currentId' => $user->image_id,
-                               'name' => 'image_id',
-                               'imageClass' => 'avatar large'
-                           ])
-                     </div>
-                     <div class="form-group">
-                         <label for="user-language">{{ trans('settings.users_preferred_language') }}</label>
-                         <select name="setting[language]" id="user-language">
-                             @foreach(trans('settings.language_select') as $lang => $label)
-                                 <option @if(setting()->getUser($user, 'language') === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
-                             @endforeach
-                         </select>
+                                 @include('components.image-picker', [
+                                       'resizeHeight' => '512',
+                                       'resizeWidth' => '512',
+                                       'showRemove' => false,
+                                       'defaultImage' => baseUrl('/user_avatar.png'),
+                                       'currentImage' => $user->getAvatar(80),
+                                       'currentId' => $user->image_id,
+                                       'name' => 'image_id',
+                                       'imageClass' => 'avatar large'
+                                   ])
+                             </div>
+                             <div class="form-group">
+                                 <label for="user-language">{{ trans('settings.users_preferred_language') }}</label>
+                                 <select name="setting[language]" id="user-language">
+                                     @foreach(trans('settings.language_select') as $lang => $label)
+                                         <option @if(setting()->getUser($user, 'language') === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
+                                     @endforeach
+                                 </select>
+                             </div>
+                         </div>
                      </div>
-                     <div class="form-group">
-                         <label for="books_display">{{ trans('settings.users_books_display_type') }}</label>
-                         <select name="books_display" id="books_display">
-                             <option @if($user->books_display === 'grid') selected @endif value="grid">Grid</option>
-                             <option @if($user->books_display === 'list') selected @endif value="list">List</option>
-                         </select>
+                     <div class="form-group text-right">
+                         <a href="{{  baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
+                         @if($authMethod !== 'system')
+                             <a href="{{ baseUrl("/settings/users/{$user->id}/delete") }}" class="neg button">{{ trans('settings.users_delete') }}</a>
+                         @endif
+                         <button class="button pos" type="submit">{{ trans('common.save') }}</button>
                      </div>
-                 </div>
-             </div>
-             <div class="form-group">
-                 <a href="{{  baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button muted">{{ trans('common.cancel') }}</a>
-                 <button class="button pos" type="submit">{{ trans('common.save') }}</button>
+                 </form>
              </div>
-         </form>
-         <hr class="margin-top large">
+         </div>
  
          @if($currentUser->id === $user->id && count($activeSocialDrivers) > 0)
-             <h3>{{ trans('settings.users_social_accounts') }}</h3>
-             <p class="text-muted">{{ trans('settings.users_social_accounts_info') }}</p>
-             <div class="row">
-                 @foreach($activeSocialDrivers as $driver => $enabled)
-                     <div class="col-sm-3 col-xs-6 text-center">
-                         <div>@icon($driver, ['width' => 56])</div>
-                         <div>
-                             @if($user->hasSocialAccount($driver))
-                                 <a href="{{ baseUrl("/login/service/{$driver}/detach") }}" class="button neg">{{ trans('settings.users_social_disconnect') }}</a>
-                             @else
-                                 <a href="{{ baseUrl("/login/service/{$driver}") }}" class="button pos">{{ trans('settings.users_social_connect') }}</a>
-                             @endif
+             <div class="card">
+                 <h3><i class="zmdi zmdi-sign-in"></i> {{ trans('settings.users_social_accounts') }}</h3>
+                 <div class="body">
+                     <p class="text-muted">{{ trans('settings.users_social_accounts_info') }}</p>
+                     <div class="container">
+                         <div class="row">
+                             @foreach($activeSocialDrivers as $driver => $enabled)
+                                 <div class="col-sm-4 col-xs-6 text-center">
+                                     <div>@icon($driver, ['width' => 56])</div>
+                                     <div>
+                                         @if($user->hasSocialAccount($driver))
+                                             <a href="{{ baseUrl("/login/service/{$driver}/detach") }}" class="button neg">{{ trans('settings.users_social_disconnect') }}</a>
+                                         @else
+                                             <a href="{{ baseUrl("/login/service/{$driver}") }}" class="button pos">{{ trans('settings.users_social_connect') }}</a>
+                                         @endif
+                                     </div>
+                                     <div>&nbsp;</div>
+                                 </div>
+                             @endforeach
                          </div>
                      </div>
-                 @endforeach
+                 </div>
              </div>
          @endif
  
@@@ -90,4 -87,4 +87,4 @@@
  
      <p class="margin-top large"><br></p>
      @include('components.image-manager', ['imageType' => 'user'])
--@stop
++@stop