use Activity;
use BookStack\Repos\EntityRepo;
use BookStack\Repos\UserRepo;
+use BookStack\Services\ExportService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Views;
protected $userRepo;
protected $entityRepo;
+ protected $exportService;
/**
* ChapterController constructor.
* @param EntityRepo $entityRepo
* @param UserRepo $userRepo
+ * @param ExportService $exportService
*/
- public function __construct(EntityRepo $entityRepo, UserRepo $userRepo)
+ public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
{
$this->entityRepo = $entityRepo;
$this->userRepo = $userRepo;
+ $this->exportService = $exportService;
parent::__construct();
}
session()->flash('success', trans('entities.chapters_permissions_success'));
return redirect($chapter->getUrl());
}
+
+ /**
+ * Exports a chapter to pdf .
+ * @param string $bookSlug
+ * @param string $chapterSlug
+ * @return \Illuminate\Http\Response
+ */
+ public function exportPdf($bookSlug, $chapterSlug)
+ {
+ $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
+ $pdfContent = $this->exportService->chapterToPdf($chapter);
+ return response()->make($pdfContent, 200, [
+ 'Content-Type' => 'application/octet-stream',
+ 'Content-Disposition' => 'attachment; filename="' . $chapterSlug . '.pdf'
+ ]);
+ }
+
+ /**
+ * Export a chapter to a self-contained HTML file.
+ * @param string $bookSlug
+ * @param string $chapterSlug
+ * @return \Illuminate\Http\Response
+ */
+ public function exportHtml($bookSlug, $chapterSlug)
+ {
+ $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
+ $containedHtml = $this->exportService->chapterToContainedHtml($chapter);
+ return response()->make($containedHtml, 200, [
+ 'Content-Type' => 'application/octet-stream',
+ 'Content-Disposition' => 'attachment; filename="' . $chapterSlug . '.html'
+ ]);
+ }
+
+ /**
+ * Export a chapter to a simple plaintext .txt file.
+ * @param string $bookSlug
+ * @param string $chapterSlug
+ * @return \Illuminate\Http\Response
+ */
+ public function exportPlainText($bookSlug, $chapterSlug)
+ {
+ $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
+ $containedHtml = $this->exportService->chapterToPlainText($chapter);
+ return response()->make($containedHtml, 200, [
+ 'Content-Type' => 'application/octet-stream',
+ 'Content-Disposition' => 'attachment; filename="' . $chapterSlug . '.txt'
+ ]);
+ }
}
}
/**
- * Exports a page to pdf format using barryvdh/laravel-dompdf wrapper.
+ * Exports a page to a PDF.
* https://github.com/barryvdh/laravel-dompdf
* @param string $bookSlug
* @param string $pageSlug
<?php namespace BookStack\Services;
use BookStack\Book;
+use BookStack\Chapter;
use BookStack\Page;
use BookStack\Repos\EntityRepo;
return $this->containHtml($pageHtml);
}
+ /**
+ * Convert a chapter to a self-contained HTML file.
+ * @param Chapter $chapter
+ * @return mixed|string
+ */
+ public function chapterToContainedHtml(Chapter $chapter)
+ {
+ $pages = $this->entityRepo->getChapterChildren($chapter);
+ $pages->each(function($page) {
+ $page->html = $this->entityRepo->renderPage($page);
+ });
+ $html = view('chapters/export', [
+ 'chapter' => $chapter,
+ 'pages' => $pages
+ ])->render();
+ return $this->containHtml($html);
+ }
+
/**
* Convert a book to a self-contained HTML file.
* @param Book $book
return $this->htmlToPdf($html);
}
+ /**
+ * Convert a chapter to a PDF file.
+ * @param Chapter $chapter
+ * @return mixed|string
+ */
+ public function chapterToPdf(Chapter $chapter)
+ {
+ $pages = $this->entityRepo->getChapterChildren($chapter);
+ $pages->each(function($page) {
+ $page->html = $this->entityRepo->renderPage($page);
+ });
+ $html = view('chapters/export', [
+ 'chapter' => $chapter,
+ 'pages' => $pages
+ ])->render();
+ return $this->htmlToPdf($html);
+ }
+
/**
* Convert a book to a PDF file
* @param Book $book
return $text;
}
+ /**
+ * Convert a chapter into a plain text string.
+ * @param Chapter $chapter
+ * @return string
+ */
+ public function chapterToPlainText(Chapter $chapter)
+ {
+ $text = $chapter->name . "\n\n";
+ $text .= $chapter->description . "\n\n";
+ foreach ($chapter->pages as $page) {
+ $text .= $this->pageToPlainText($page);
+ }
+ return $text;
+ }
+
/**
* Convert a book into a plain text string.
* @param Book $book
$text = $book->name . "\n\n";
foreach ($bookTree as $bookChild) {
if ($bookChild->isA('chapter')) {
- $text .= $bookChild->name . "\n\n";
- $text .= $bookChild->description . "\n\n";
- foreach ($bookChild->pages as $page) {
- $text .= $this->pageToPlainText($page);
- }
+ $text .= $this->chapterToPlainText($bookChild);
} else {
$text .= $this->pageToPlainText($bookChild);
}
--- /dev/null
+<!doctype html>
+<html lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <title>{{ $chapter->name }}</title>
+
+ <style>
+ {!! file_get_contents(public_path('/css/export-styles.css')) !!}
+ .page-break {
+ page-break-after: always;
+ }
+ ul.contents ul li {
+ list-style: circle;
+ }
+ @media screen {
+ .page-break {
+ border-top: 1px solid #DDD;
+ }
+ }
+ </style>
+ @yield('head')
+</head>
+<body>
+<div class="container">
+ <div class="row">
+ <div class="col-md-8 col-md-offset-2">
+ <div class="page-content">
+
+ <h1 style="font-size: 4.8em">{{$chapter->name}}</h1>
+
+ <p>{{ $chapter->description }}</p>
+
+ @if(count($pages) > 0)
+ <ul class="contents">
+ @foreach($pages as $page)
+ <li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
+ @endforeach
+ </ul>
+ @endif
+
+ @foreach($pages as $page)
+ <div class="page-break"></div>
+ <h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
+ {!! $page->html !!}
+ @endforeach
+
+ </div>
+ </div>
+ </div>
+</div>
+</body>
+</html>
</div>
<div class="col-sm-4 faded">
<div class="action-buttons">
+ <span dropdown class="dropdown-container">
+ <div dropdown-toggle class="text-button text-primary"><i class="zmdi zmdi-open-in-new"></i>{{ trans('entities.pages_export') }}</div>
+ <ul class="wide">
+ <li><a href="{{ $chapter->getUrl('/export/html') }}" target="_blank">{{ trans('entities.pages_export_html') }} <span class="text-muted float right">.html</span></a></li>
+ <li><a href="{{ $chapter->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.pages_export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
+ <li><a href="{{ $chapter->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.pages_export_text') }} <span class="text-muted float right">.txt</span></a></li>
+ </ul>
+ </span>
@if(userCan('page-create', $chapter))
<a href="{{ $chapter->getUrl('/create-page') }}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>{{ trans('entities.pages_new') }}</a>
@endif
Route::put('/{bookSlug}/chapter/{chapterSlug}/move', 'ChapterController@move');
Route::get('/{bookSlug}/chapter/{chapterSlug}/edit', 'ChapterController@edit');
Route::get('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@showRestrict');
+ Route::get('/{bookSlug}/chapter/{chapterSlug}/export/pdf', 'ChapterController@exportPdf');
+ Route::get('/{bookSlug}/chapter/{chapterSlug}/export/html', 'ChapterController@exportHtml');
+ Route::get('/{bookSlug}/chapter/{chapterSlug}/export/plaintext', 'ChapterController@exportPlainText');
Route::put('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@restrict');
Route::get('/{bookSlug}/chapter/{chapterSlug}/delete', 'ChapterController@showDelete');
Route::delete('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@destroy');
<?php namespace Tests;
+use BookStack\Chapter;
use BookStack\Page;
class ExportTest extends TestCase
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $book->slug . '.html');
}
+ public function test_chapter_text_export()
+ {
+ $chapter = Chapter::first();
+ $page = $chapter->pages[0];
+ $this->asEditor();
+
+ $resp = $this->get($chapter->getUrl('/export/plaintext'));
+ $resp->assertStatus(200);
+ $resp->assertSee($chapter->name);
+ $resp->assertSee($page->name);
+ $resp->assertHeader('Content-Disposition', 'attachment; filename="' . $chapter->slug . '.txt');
+ }
+
+ public function test_chapter_pdf_export()
+ {
+ $chapter = Chapter::first();
+ $this->asEditor();
+
+ $resp = $this->get($chapter->getUrl('/export/pdf'));
+ $resp->assertStatus(200);
+ $resp->assertHeader('Content-Disposition', 'attachment; filename="' . $chapter->slug . '.pdf');
+ }
+
+ public function test_chapter_html_export()
+ {
+ $chapter = Chapter::first();
+ $page = $chapter->pages[0];
+ $this->asEditor();
+
+ $resp = $this->get($chapter->getUrl('/export/html'));
+ $resp->assertStatus(200);
+ $resp->assertSee($chapter->name);
+ $resp->assertSee($page->name);
+ $resp->assertHeader('Content-Disposition', 'attachment; filename="' . $chapter->slug . '.html');
+ }
+
}
\ No newline at end of file