Started working on chapters

This commit is contained in:
Dan Brown 2015-07-27 20:17:08 +01:00
parent ef77c10a70
commit b9df3c647a
17 changed files with 317 additions and 40 deletions

View file

@ -24,4 +24,17 @@ class Book extends Model
return $this->hasMany('Oxbow\Page');
}
public function chapters()
{
return $this->hasMany('Oxbow\Chapter');
}
public function children()
{
$pages = $this->pages()->get();
$chapters = $this->chapters()->get();
$children = $pages->merge($chapters);
return $children->sortBy('priority');
}
}

25
app/Chapter.php Normal file
View file

@ -0,0 +1,25 @@
<?php namespace Oxbow;
use Illuminate\Database\Eloquent\Model;
class Chapter extends Model
{
protected $fillable = ['name', 'description', 'priority', 'book_id'];
public function book()
{
return $this->belongsTo('Oxbow\Book');
}
public function children()
{
return $this->hasMany('Oxbow\Page')->orderBy('priority', 'ASC');
}
public function getUrl()
{
return '/books/' . $this->book->slug . '/chapter/' . $this->slug;
}
}

View file

@ -79,7 +79,6 @@ class BookController extends Controller
{
$book = $this->bookRepo->getBySlug($slug);
$pageTree = $this->pageRepo->getTreeByBookId($book->id);
// dd($pageTree);
return view('books/show', ['book' => $book, 'pageTree' => $pageTree]);
}

View file

@ -0,0 +1,116 @@
<?php
namespace Oxbow\Http\Controllers;
use Illuminate\Http\Request;
use Oxbow\Http\Requests;
use Oxbow\Http\Controllers\Controller;
use Oxbow\Repos\BookRepo;
use Oxbow\Repos\ChapterRepo;
class ChapterController extends Controller
{
protected $bookRepo;
protected $chapterRepo;
/**
* ChapterController constructor.
* @param $bookRepo
* @param $chapterRepo
*/
public function __construct(BookRepo $bookRepo,ChapterRepo $chapterRepo)
{
$this->bookRepo = $bookRepo;
$this->chapterRepo = $chapterRepo;
}
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* @param $bookSlug
* @return Response
*/
public function create($bookSlug)
{
$book = $this->bookRepo->getBySlug($bookSlug);
return view('chapters/create', ['book' => $book]);
}
/**
* Store a newly created resource in storage.
*
* @param $bookSlug
* @param Request $request
* @return Response
*/
public function store($bookSlug, Request $request)
{
$this->validate($request, [
'name' => 'required|string|max:255'
]);
$book = $this->bookRepo->getBySlug($bookSlug);
$chapter = $this->chapterRepo->newFromInput($request->all());
$chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id);
$book->chapters()->save($chapter);
return redirect($book->getUrl());
}
/**
* Display the specified resource.
*
* @param int $id
* @return Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return Response
*/
public function destroy($id)
{
//
}
}

View file

@ -26,10 +26,14 @@ Route::group(['prefix' => 'books'], function() {
Route::post('/{bookSlug}/page', 'PageController@store');
Route::get('/{bookSlug}/sort', 'PageController@sortPages');
Route::put('/{bookSlug}/sort', 'PageController@savePageSort');
Route::get('/{bookSlug}/{pageSlug}', 'PageController@show');
Route::get('/{bookSlug}/{pageSlug}/create', 'PageController@create');
Route::get('/{bookSlug}/{pageSlug}/edit', 'PageController@edit');
Route::put('/{bookSlug}/{pageSlug}', 'PageController@update');
Route::get('/{bookSlug}/page/{pageSlug}', 'PageController@show');
Route::get('/{bookSlug}/page/{pageSlug}/create', 'PageController@create');
Route::get('/{bookSlug}/page/{pageSlug}/edit', 'PageController@edit');
Route::put('/{bookSlug}/page/{pageSlug}', 'PageController@update');
Route::get('/{bookSlug}/chapter/create', 'ChapterController@create');
Route::post('/{bookSlug}/chapter/create', 'ChapterController@store');
});
Route::post('/upload/image', 'ImageController@upload');

View file

@ -34,7 +34,7 @@ class Page extends Model
public function getUrl()
{
return '/books/' . $this->book->slug . '/' . $this->slug;
return '/books/' . $this->book->slug . '/page/' . $this->slug;
}
}

65
app/Repos/ChapterRepo.php Normal file
View file

@ -0,0 +1,65 @@
<?php namespace Oxbow\Repos;
use Illuminate\Support\Str;
use Oxbow\Chapter;
class ChapterRepo
{
protected $chapter;
/**
* ChapterRepo constructor.
* @param $chapter
*/
public function __construct(Chapter $chapter)
{
$this->chapter = $chapter;
}
public function getById($id)
{
return $this->chapter->findOrFail($id);
}
public function getAll()
{
return $this->chapter->all();
}
public function getBySlug($slug, $bookId)
{
return $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
}
public function newFromInput($input)
{
return $this->chapter->fill($input);
}
public function destroyById($id)
{
$page = $this->getById($id);
$page->delete();
}
public function doesSlugExist($slug, $bookId, $currentId = false)
{
$query = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId);
if($currentId) {
$query = $query->where('id', '!=', $currentId);
}
return $query->count() > 0;
}
public function findSuitableSlug($name, $bookId)
{
$slug = Str::slug($name);
while($this->doesSlugExist($slug, $bookId)) {
$slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
}
return $slug;
}
}

View file

@ -114,7 +114,7 @@ class PageRepo
*/
private function getTopLevelPages($bookId)
{
return $this->page->where('book_id', '=', $bookId)->where('page_id', '=', 0)->orderBy('priority')->get();
return $this->page->where('book_id', '=', $bookId)->where('chapter_id', '=', 0)->orderBy('priority')->get();
}
/**

View file

@ -15,7 +15,7 @@ class CreatePagesTable extends Migration
Schema::create('pages', function (Blueprint $table) {
$table->increments('id');
$table->integer('book_id');
$table->integer('page_id');
$table->integer('chapter_id');
$table->string('name');
$table->string('slug')->indexed();
$table->longText('html');

View file

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateChaptersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('chapters', function (Blueprint $table) {
$table->increments('id');
$table->integer('book_id');
$table->string('slug')->indexed();
$table->text('name');
$table->text('description');
$table->integer('priority');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('chapters');
}
}

View file

@ -1,5 +1,5 @@
var elixir = require('laravel-elixir');
require('laravel-elixir-livereload');
//require('laravel-elixir-livereload');
/*
|--------------------------------------------------------------------------
@ -13,5 +13,5 @@ require('laravel-elixir-livereload');
*/
elixir(function(mix) {
mix.sass('styles.scss').livereload();
mix.sass('styles.scss');//.livereload();
});

View file

@ -1,27 +1,3 @@
## Laravel PHP Framework
# BookStack
[![Build Status](https://travis-ci.org/laravel/framework.svg)](https://travis-ci.org/laravel/framework)
[![Total Downloads](https://poser.pugx.org/laravel/framework/d/total.svg)](https://packagist.org/packages/laravel/framework)
[![Latest Stable Version](https://poser.pugx.org/laravel/framework/v/stable.svg)](https://packagist.org/packages/laravel/framework)
[![Latest Unstable Version](https://poser.pugx.org/laravel/framework/v/unstable.svg)](https://packagist.org/packages/laravel/framework)
[![License](https://poser.pugx.org/laravel/framework/license.svg)](https://packagist.org/packages/laravel/framework)
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable, creative experience to be truly fulfilling. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as authentication, routing, sessions, queueing, and caching.
Laravel is accessible, yet powerful, providing powerful tools needed for large, robust applications. A superb inversion of control container, expressive migration system, and tightly integrated unit testing support give you the tools you need to build any application with which you are tasked.
## Official Documentation
Documentation for the framework can be found on the [Laravel website](http://laravel.com/docs).
## Contributing
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](http://laravel.com/docs/contributions).
## Security Vulnerabilities
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed.
### License
The Laravel framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
A platform to create documentation/wiki content.

View file

@ -379,4 +379,9 @@ body.dragging, body.dragging * {
}
.sortable-page-list li.placeholder:before {
position: absolute;
}
.material-icons {
font-size: 1em;
line-height: 1.4em;
}

View file

@ -4,7 +4,7 @@
<title>BookStack</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="/css/app.css">
<link href='http://fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'>
<link href='//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="/bower/bootstrap/dist/js/bootstrap.js"></script>

View file

@ -17,11 +17,27 @@
<p class="text-muted">{{$book->description}}</p>
<div class="clearfix header-group">
<h4 class="float">Pages</h4>
<a href="{{$book->getUrl() . '/page/create'}}" class="text-pos float right">+ New Page</a>
<h4 class="float">Contents</h4>
<div class="float right">
<a href="{{$book->getUrl() . '/page/create'}}" class="text-pos">+ New Page</a>
<a href="{{$book->getUrl() . '/chapter/create'}}" class="text-pos">+ New Chapter</a>
</div>
</div>
@include('pages/page-tree-list', ['pageTree' => $pageTree])
<div class="page-list">
@foreach($book->children() as $childElement)
<div class="page-list-item">
@if(is_a($childElement, 'Oxbow\Chapter'))
<i class="fa fa-archive"></i>
@else
<i class="fa fa-file"></i>
@endif
{{$childElement->name}}
</div>
@endforeach
</div>
{{--@include('pages/page-tree-list', ['pageTree' => $pageTree])--}}
</div>

View file

@ -0,0 +1,12 @@
@extends('base')
@section('content')
<div class="page-content">
<h1>Create New Chapter</h1>
<form action="{{$book->getUrl()}}/chapter/create" method="POST">
@include('chapters/form')
</form>
</div>
@stop

View file

@ -0,0 +1,11 @@
{{ csrf_field() }}
<div class="form-group title-input">
<label for="name">Chapter Name</label>
@include('form/text', ['name' => 'name'])
</div>
<div class="form-group description-input">
<label for="description">Description</label>
@include('form/textarea', ['name' => 'description'])
</div>
<button type="submit" class="button pos">Save</button>