class Book extends Entity
{
- protected $fillable = ['name', 'description'];
+ protected $fillable = ['name', 'description', 'image_id'];
/**
* Get the url for this book.
return baseUrl('/books/' . urlencode($this->slug));
}
+ /**
+ * Returns book cover image, if book cover not exists return default cover image.
+ * @param int $width - Width of the image
+ * @param int $height - Height of the image
+ * @return string
+ */
+ public function getBookCover($width = 440, $height = 250)
+ {
+ $default = baseUrl('/book_default_cover.png');
+ if (!$this->image_id) return $default;
+
+ try {
+ $cover = $this->cover ? baseUrl($this->cover->getThumb($width, $height, false)) : $default;
+ } catch (\Exception $err) {
+ $cover = $default;
+ }
+ return $cover;
+ }
+
+ /**
+ * Get the cover image of the book
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
+ */
+ public function cover()
+ {
+ return $this->belongsTo(Image::class, 'image_id');
+ }
/*
* Get the edit url for this book.
* @return string
/**
* Report or log an exception.
- *
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
+ * @return mixed
*/
public function report(Exception $e)
{
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
$popular = $this->entityRepo->getPopular('book', 4, 0);
$new = $this->entityRepo->getRecentlyCreated('book', 4, 0);
- $this->setPageTitle('Books');
+ $booksViewType = setting()->getUser($this->currentUser, 'books_view_type', 'list');
+ $this->setPageTitle(trans('entities.books'));
return view('books/index', [
'books' => $books,
'recents' => $recents,
'popular' => $popular,
- 'new' => $new
+ 'new' => $new,
+ 'booksViewType' => $booksViewType
]);
}
'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());
}
/**
/**
* Get a js representation of the current translations
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
+ * @throws \Exception
*/
public function getTranslations() {
$locale = app()->getLocale();
]);
}
+ /**
+ * Get custom head HTML, Used in ajax calls to show in editor.
+ * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+ */
+ public function customHeadContent()
+ {
+ return view('partials/custom-head-content');
+ }
+
}
$page->html = $this->entityRepo->renderPage($page);
$sidebarTree = $this->entityRepo->getBookChildren($page->book);
$pageNav = $this->entityRepo->getPageNav($page->html);
- $page->load(['comments.createdBy']);
+
+ // check if the comment's are enabled
+ $commentsEnabled = !setting('app-disable-comments');
+ if ($commentsEnabled) {
+ $page->load(['comments.createdBy']);
+ }
Views::add($page);
$this->setPageTitle($page->getShortName());
return view('pages/show', [
'page' => $page,'book' => $page->book,
- 'current' => $page, 'sidebarTree' => $sidebarTree,
- 'pageNav' => $pageNav]);
+ 'current' => $page,
+ 'sidebarTree' => $sidebarTree,
+ 'commentsEnabled' => $commentsEnabled,
+ 'pageNav' => $pageNav
+ ]);
}
/**
namespace BookStack\Http\Middleware;
+use Closure;
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;
Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
];
+
+ /**
+ * Handle the request, Set the correct user-configured proxy information.
+ * @param Request $request
+ * @param Closure $next
+ * @return mixed
+ */
+ public function handle($request, Closure $next)
+ {
+ $setProxies = config('app.proxies');
+ if ($setProxies !== '**' && $setProxies !== '*' && $setProxies !== '') {
+ $setProxies = explode(',', $setProxies);
+ }
+ $this->proxies = $setProxies;
+
+ return parent::handle($request, $next);
+ }
}
$pdf = \SnappyPDF::loadHTML($containedHtml);
$pdf->setOption('print-media-type', true);
} else {
- $pdf = \PDF::loadHTML($containedHtml);
+ $pdf = \DomPDF::loadHTML($containedHtml);
}
return $pdf->output();
}
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
- "php": "7.0"
+ "platform": {
+ "php": "7.0"
+ }
}
}
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "384c1805a51b16b9304ab3ac58f9554d",
+ "content-hash": "7d60f09393b99551e9ffdb6622ed7ade",
"packages": [
{
"name": "aws/aws-sdk-php",
- "version": "3.38.5",
+ "version": "3.45.3",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "13ffa481127c08e04244f116ae85a64b4172479c"
+ "reference": "d0abb0b1194fa64973b135191f56df991bc5787c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/13ffa481127c08e04244f116ae85a64b4172479c",
- "reference": "13ffa481127c08e04244f116ae85a64b4172479c",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d0abb0b1194fa64973b135191f56df991bc5787c",
+ "reference": "d0abb0b1194fa64973b135191f56df991bc5787c",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-openssl": "*",
"nette/neon": "^2.3",
- "phpunit/phpunit": "^4.8.35|^5.4.0",
+ "phpunit/phpunit": "^4.8.35|^5.4.3",
"psr/cache": "^1.0"
},
"suggest": {
"s3",
"sdk"
],
- "time": "2017-11-17T22:08:25+00:00"
+ "time": "2017-12-08T21:36:50+00:00"
},
{
"name": "barryvdh/laravel-dompdf",
},
{
"name": "dompdf/dompdf",
- "version": "v0.8.1",
+ "version": "v0.8.2",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
- "reference": "9ea852c4bdc74fac5def165e6cd52353f7ca3b3f"
+ "reference": "5113accd9ae5d466077cce5208dcf3fb871bf8f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/dompdf/dompdf/zipball/9ea852c4bdc74fac5def165e6cd52353f7ca3b3f",
- "reference": "9ea852c4bdc74fac5def165e6cd52353f7ca3b3f",
+ "url": "https://api.github.com/repos/dompdf/dompdf/zipball/5113accd9ae5d466077cce5208dcf3fb871bf8f6",
+ "reference": "5113accd9ae5d466077cce5208dcf3fb871bf8f6",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"phenx/php-font-lib": "0.5.*",
"phenx/php-svg-lib": "0.3.*",
- "php": ">=5.3.0"
+ "php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "4.8.*",
],
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
- "time": "2017-09-14T01:36:24+00:00"
+ "time": "2017-11-26T14:49:08+00:00"
},
{
"name": "egulias/email-validator",
},
{
"name": "knplabs/knp-snappy",
- "version": "v1.0.2",
+ "version": "v1.0.3",
"source": {
"type": "git",
"url": "https://github.com/KnpLabs/snappy.git",
- "reference": "e6a29846ca759ea268a1bca4455b8a14815a3976"
+ "reference": "68590ef3aa94425b1c0019cc28ce471729f51fcb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/e6a29846ca759ea268a1bca4455b8a14815a3976",
- "reference": "e6a29846ca759ea268a1bca4455b8a14815a3976",
+ "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/68590ef3aa94425b1c0019cc28ce471729f51fcb",
+ "reference": "68590ef3aa94425b1c0019cc28ce471729f51fcb",
"shasum": ""
},
"require": {
"php": ">=5.6",
"psr/log": "^1.0",
- "symfony/process": "~2.3|~3.0"
+ "symfony/process": "~2.3 || ~3.0 || ~4.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.7"
+ "phpunit/phpunit": "~4.8.36"
},
"suggest": {
"h4cc/wkhtmltoimage-amd64": "Provides wkhtmltoimage-amd64 binary for Linux-compatible machines, use version `~0.12` as dependency",
"thumbnail",
"wkhtmltopdf"
],
- "time": "2017-10-04T19:39:41+00:00"
+ "time": "2017-12-03T23:18:18+00:00"
},
{
"name": "laravel/framework",
- "version": "v5.5.21",
+ "version": "v5.5.24",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "6321069a75723d88103526903d3192f0b231544a"
+ "reference": "06135405bb1f736dac5e9529ed1541fc446c9c0f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/6321069a75723d88103526903d3192f0b231544a",
- "reference": "6321069a75723d88103526903d3192f0b231544a",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/06135405bb1f736dac5e9529ed1541fc446c9c0f",
+ "reference": "06135405bb1f736dac5e9529ed1541fc446c9c0f",
"shasum": ""
},
"require": {
"framework",
"laravel"
],
- "time": "2017-11-14T15:08:13+00:00"
+ "time": "2017-12-07T01:28:21+00:00"
},
{
"name": "laravel/socialite",
},
{
"name": "symfony/console",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "63cd7960a0a522c3537f6326706d7f3b8de65805"
+ "reference": "b0878233cb5c4391347e5495089c7af11b8e6201"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/63cd7960a0a522c3537f6326706d7f3b8de65805",
- "reference": "63cd7960a0a522c3537f6326706d7f3b8de65805",
+ "url": "https://api.github.com/repos/symfony/console/zipball/b0878233cb5c4391347e5495089c7af11b8e6201",
+ "reference": "b0878233cb5c4391347e5495089c7af11b8e6201",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8",
+ "php": ">=5.5.9",
"symfony/debug": "~2.8|~3.0",
"symfony/polyfill-mbstring": "~1.0"
},
"symfony/dependency-injection": "~3.3",
"symfony/event-dispatcher": "~2.8|~3.0",
"symfony/filesystem": "~2.8|~3.0",
+ "symfony/http-kernel": "~2.8|~3.0",
"symfony/process": "~2.8|~3.0"
},
"suggest": {
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2017-11-16T15:24:32+00:00"
+ "time": "2017-07-29T21:27:59+00:00"
},
{
"name": "symfony/css-selector",
},
{
"name": "symfony/debug",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
- "reference": "74557880e2846b5c84029faa96b834da37e29810"
+ "reference": "7c13ae8ce1e2adbbd574fc39de7be498e1284e13"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/debug/zipball/74557880e2846b5c84029faa96b834da37e29810",
- "reference": "74557880e2846b5c84029faa96b834da37e29810",
+ "url": "https://api.github.com/repos/symfony/debug/zipball/7c13ae8ce1e2adbbd574fc39de7be498e1284e13",
+ "reference": "7c13ae8ce1e2adbbd574fc39de7be498e1284e13",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8",
+ "php": ">=5.5.9",
"psr/log": "~1.0"
},
"conflict": {
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
- "time": "2017-11-10T16:38:39+00:00"
+ "time": "2017-07-28T15:27:31+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9"
+ "reference": "67535f1e3fd662bdc68d7ba317c93eecd973617e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/271d8c27c3ec5ecee6e2ac06016232e249d638d9",
- "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/67535f1e3fd662bdc68d7ba317c93eecd973617e",
+ "reference": "67535f1e3fd662bdc68d7ba317c93eecd973617e",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": ">=5.5.9"
},
"conflict": {
"symfony/dependency-injection": "<3.3"
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
- "time": "2017-11-05T15:47:03+00:00"
+ "time": "2017-06-09T14:53:08+00:00"
},
{
"name": "symfony/finder",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "138af5ec075d4b1d1bd19de08c38a34bb2d7d880"
+ "reference": "baea7f66d30854ad32988c11a09d7ffd485810c4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/138af5ec075d4b1d1bd19de08c38a34bb2d7d880",
- "reference": "138af5ec075d4b1d1bd19de08c38a34bb2d7d880",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/baea7f66d30854ad32988c11a09d7ffd485810c4",
+ "reference": "baea7f66d30854ad32988c11a09d7ffd485810c4",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": ">=5.5.9"
},
"type": "library",
"extra": {
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2017-11-05T15:47:03+00:00"
+ "time": "2017-06-01T21:01:25+00:00"
},
{
"name": "symfony/http-foundation",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "5943f0f19817a7e05992d20a90729b0dc93faf36"
+ "reference": "49e8cd2d59a7aa9bfab19e46de680c76e500a031"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5943f0f19817a7e05992d20a90729b0dc93faf36",
- "reference": "5943f0f19817a7e05992d20a90729b0dc93faf36",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/49e8cd2d59a7aa9bfab19e46de680c76e500a031",
+ "reference": "49e8cd2d59a7aa9bfab19e46de680c76e500a031",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8",
+ "php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.1"
},
"require-dev": {
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
- "time": "2017-11-13T18:13:16+00:00"
+ "time": "2017-07-21T11:04:46+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "a2a942172b742217ab2ccd9399494af2aa17c766"
+ "reference": "db10d05f1d95e4168e638db7a81c79616f568ea5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a2a942172b742217ab2ccd9399494af2aa17c766",
- "reference": "a2a942172b742217ab2ccd9399494af2aa17c766",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/db10d05f1d95e4168e638db7a81c79616f568ea5",
+ "reference": "db10d05f1d95e4168e638db7a81c79616f568ea5",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8",
+ "php": ">=5.5.9",
"psr/log": "~1.0",
"symfony/debug": "~2.8|~3.0",
"symfony/event-dispatcher": "~2.8|~3.0",
- "symfony/http-foundation": "^3.3.11"
+ "symfony/http-foundation": "~3.3"
},
"conflict": {
"symfony/config": "<2.8",
],
"description": "Symfony HttpKernel Component",
"homepage": "https://symfony.com",
- "time": "2017-11-16T18:14:43+00:00"
+ "time": "2017-08-01T10:25:59+00:00"
},
{
"name": "symfony/polyfill-mbstring",
},
{
"name": "symfony/process",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "a56a3989fb762d7b19a0cf8e7693ee99a6ffb78d"
+ "reference": "07432804942b9f6dd7b7377faf9920af5f95d70a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/a56a3989fb762d7b19a0cf8e7693ee99a6ffb78d",
- "reference": "a56a3989fb762d7b19a0cf8e7693ee99a6ffb78d",
+ "url": "https://api.github.com/repos/symfony/process/zipball/07432804942b9f6dd7b7377faf9920af5f95d70a",
+ "reference": "07432804942b9f6dd7b7377faf9920af5f95d70a",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": ">=5.5.9"
},
"type": "library",
"extra": {
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "time": "2017-11-13T15:31:11+00:00"
+ "time": "2017-07-13T13:05:09+00:00"
},
{
"name": "symfony/routing",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
- "reference": "cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95"
+ "reference": "4aee1a917fd4859ff8b51b9fd1dfb790a5ecfa26"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/routing/zipball/cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95",
- "reference": "cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/4aee1a917fd4859ff8b51b9fd1dfb790a5ecfa26",
+ "reference": "4aee1a917fd4859ff8b51b9fd1dfb790a5ecfa26",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": ">=5.5.9"
},
"conflict": {
"symfony/config": "<2.8",
"uri",
"url"
],
- "time": "2017-11-07T14:16:22+00:00"
+ "time": "2017-07-21T17:43:13+00:00"
},
{
"name": "symfony/translation",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "373e553477e55cd08f8b86b74db766c75b987fdb"
+ "reference": "35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/373e553477e55cd08f8b86b74db766c75b987fdb",
- "reference": "373e553477e55cd08f8b86b74db766c75b987fdb",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3",
+ "reference": "35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8",
+ "php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
- "time": "2017-11-07T14:12:55+00:00"
+ "time": "2017-06-24T16:45:30+00:00"
},
{
"name": "symfony/var-dumper",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "805de6bd6869073e60610df1b14ab7d969c61b01"
+ "reference": "b2623bccb969ad595c2090f9be498b74670d0663"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/805de6bd6869073e60610df1b14ab7d969c61b01",
- "reference": "805de6bd6869073e60610df1b14ab7d969c61b01",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b2623bccb969ad595c2090f9be498b74670d0663",
+ "reference": "b2623bccb969ad595c2090f9be498b74670d0663",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8",
+ "php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"debug",
"dump"
],
- "time": "2017-11-07T14:16:22+00:00"
+ "time": "2017-07-28T06:06:09+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
},
{
"name": "doctrine/instantiator",
- "version": "1.1.0",
+ "version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
- "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
- "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "php": ">=5.3,<8.0-DEV"
},
"require-dev": {
"athletic/athletic": "~0.1.8",
"ext-pdo": "*",
"ext-phar": "*",
- "phpunit/phpunit": "^6.2.3",
- "squizlabs/php_codesniffer": "^3.0.2"
+ "phpunit/phpunit": "~4.0",
+ "squizlabs/php_codesniffer": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2.x-dev"
+ "dev-master": "1.0.x-dev"
}
},
"autoload": {
"constructor",
"instantiate"
],
- "time": "2017-07-22T11:58:36+00:00"
+ "time": "2015-06-14T21:17:01+00:00"
},
{
"name": "filp/whoops",
- "version": "2.1.13",
+ "version": "2.1.14",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
- "reference": "9f640a4f129e57d3537887f840380109a4dd182b"
+ "reference": "c6081b8838686aa04f1e83ba7e91f78b7b2a23e6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/filp/whoops/zipball/9f640a4f129e57d3537887f840380109a4dd182b",
- "reference": "9f640a4f129e57d3537887f840380109a4dd182b",
+ "url": "https://api.github.com/repos/filp/whoops/zipball/c6081b8838686aa04f1e83ba7e91f78b7b2a23e6",
+ "reference": "c6081b8838686aa04f1e83ba7e91f78b7b2a23e6",
"shasum": ""
},
"require": {
"throwable",
"whoops"
],
- "time": "2017-11-17T08:15:51+00:00"
+ "time": "2017-11-23T18:22:44+00:00"
},
{
"name": "fzaninotto/faker",
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "4.1.1",
+ "version": "4.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2"
+ "reference": "66465776cfc249844bde6d117abff1d22e06c2da"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2d3d238c433cf69caeb4842e97a3223a116f94b2",
- "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/66465776cfc249844bde6d117abff1d22e06c2da",
+ "reference": "66465776cfc249844bde6d117abff1d22e06c2da",
"shasum": ""
},
"require": {
"php": "^7.0",
- "phpdocumentor/reflection-common": "^1.0@dev",
+ "phpdocumentor/reflection-common": "^1.0.0",
"phpdocumentor/type-resolver": "^0.4.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
- "mockery/mockery": "^0.9.4",
- "phpunit/phpunit": "^4.4"
+ "doctrine/instantiator": "~1.0.5",
+ "mockery/mockery": "^1.0",
+ "phpunit/phpunit": "^6.4"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.x-dev"
+ }
+ },
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "time": "2017-08-30T18:51:59+00:00"
+ "time": "2017-11-27T17:38:31+00:00"
},
{
"name": "phpdocumentor/type-resolver",
},
{
"name": "phpspec/prophecy",
- "version": "v1.7.2",
+ "version": "1.7.3",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6"
+ "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
- "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
+ "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
"shasum": ""
},
"require": {
},
"require-dev": {
"phpspec/phpspec": "^2.5|^3.2",
- "phpunit/phpunit": "^4.8 || ^5.6.5"
+ "phpunit/phpunit": "^4.8.35 || ^5.7"
},
"type": "library",
"extra": {
"spy",
"stub"
],
- "time": "2017-09-04T11:05:03+00:00"
+ "time": "2017-11-24T13:59:53+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "5.2.3",
+ "version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d"
+ "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d",
- "reference": "8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/661f34d0bd3f1a7225ef491a70a020ad23a057a1",
+ "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1",
"shasum": ""
},
"require": {
"php": "^7.0",
"phpunit/php-file-iterator": "^1.4.2",
"phpunit/php-text-template": "^1.2.1",
- "phpunit/php-token-stream": "^2.0",
+ "phpunit/php-token-stream": "^2.0.1",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.0",
"sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1"
},
"require-dev": {
- "ext-xdebug": "^2.5",
"phpunit/phpunit": "^6.0"
},
"suggest": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.2.x-dev"
+ "dev-master": "5.3.x-dev"
}
},
"autoload": {
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
+ "email": "sebastian@phpunit.de",
"role": "lead"
}
],
"testing",
"xunit"
],
- "time": "2017-11-03T13:47:33+00:00"
+ "time": "2017-12-06T09:29:45+00:00"
},
{
"name": "phpunit/php-file-iterator",
- "version": "1.4.2",
+ "version": "1.4.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
- "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
"shasum": ""
},
"require": {
"filesystem",
"iterator"
],
- "time": "2016-10-03T07:40:28+00:00"
+ "time": "2017-11-27T13:52:08+00:00"
},
{
"name": "phpunit/php-text-template",
},
{
"name": "phpunit/php-token-stream",
- "version": "2.0.1",
+ "version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0"
+ "reference": "791198a2c6254db10131eecfe8c06670700904db"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9a02332089ac48e704c70f6cefed30c224e3c0b0",
- "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
+ "reference": "791198a2c6254db10131eecfe8c06670700904db",
"shasum": ""
},
"require": {
"keywords": [
"tokenizer"
],
- "time": "2017-08-20T05:47:52+00:00"
+ "time": "2017-11-27T05:48:46+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "6.4.4",
+ "version": "6.5.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932"
+ "reference": "882e886cc928a0abd3c61282b2a64026237d14a4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/562f7dc75d46510a4ed5d16189ae57fbe45a9932",
- "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/882e886cc928a0abd3c61282b2a64026237d14a4",
+ "reference": "882e886cc928a0abd3c61282b2a64026237d14a4",
"shasum": ""
},
"require": {
"phar-io/version": "^1.0",
"php": "^7.0",
"phpspec/prophecy": "^1.7",
- "phpunit/php-code-coverage": "^5.2.2",
- "phpunit/php-file-iterator": "^1.4.2",
+ "phpunit/php-code-coverage": "^5.3",
+ "phpunit/php-file-iterator": "^1.4.3",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^1.0.9",
- "phpunit/phpunit-mock-objects": "^4.0.3",
- "sebastian/comparator": "^2.0.2",
+ "phpunit/phpunit-mock-objects": "^5.0.4",
+ "sebastian/comparator": "^2.1",
"sebastian/diff": "^2.0",
"sebastian/environment": "^3.1",
"sebastian/exporter": "^3.1",
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "6.4.x-dev"
+ "dev-master": "6.5.x-dev"
}
},
"autoload": {
"testing",
"xunit"
],
- "time": "2017-11-08T11:26:09+00:00"
+ "time": "2017-12-06T09:42:03+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
- "version": "4.0.4",
+ "version": "5.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
- "reference": "2f789b59ab89669015ad984afa350c4ec577ade0"
+ "reference": "16b50f4167e5e85e81ca8a3dd105d0a5fd32009a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/2f789b59ab89669015ad984afa350c4ec577ade0",
- "reference": "2f789b59ab89669015ad984afa350c4ec577ade0",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/16b50f4167e5e85e81ca8a3dd105d0a5fd32009a",
+ "reference": "16b50f4167e5e85e81ca8a3dd105d0a5fd32009a",
"shasum": ""
},
"require": {
"phpunit/phpunit": "<6.0"
},
"require-dev": {
- "phpunit/phpunit": "^6.0"
+ "phpunit/phpunit": "^6.5"
},
"suggest": {
"ext-soap": "*"
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0.x-dev"
+ "dev-master": "5.0.x-dev"
}
},
"autoload": {
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
+ "email": "sebastian@phpunit.de",
"role": "lead"
}
],
"mock",
"xunit"
],
- "time": "2017-08-03T14:08:16+00:00"
+ "time": "2017-12-02T05:31:19+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
},
{
"name": "symfony/class-loader",
- "version": "v3.3.13",
+ "version": "v3.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
- "reference": "df173ac2af96ce202bf8bb5a3fc0bec8a4fdd4d1"
+ "reference": "386a294d621576302e7cc36965d6ed53b8c73c4f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/class-loader/zipball/df173ac2af96ce202bf8bb5a3fc0bec8a4fdd4d1",
- "reference": "df173ac2af96ce202bf8bb5a3fc0bec8a4fdd4d1",
+ "url": "https://api.github.com/repos/symfony/class-loader/zipball/386a294d621576302e7cc36965d6ed53b8c73c4f",
+ "reference": "386a294d621576302e7cc36965d6ed53b8c73c4f",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": ">=5.5.9"
},
"require-dev": {
"symfony/finder": "~2.8|~3.0",
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
- "time": "2017-11-05T15:47:03+00:00"
+ "time": "2017-06-02T09:51:43+00:00"
},
{
"name": "symfony/dom-crawler",
"php": ">=7.0.0",
"ext-tidy": "*"
},
- "platform-dev": []
+ "platform-dev": [],
+ "platform-overrides": {
+ "php": "7.0"
+ }
}
*/
'ImageTool' => Intervention\Image\Facades\Image::class,
- 'PDF' => Barryvdh\DomPDF\Facade::class,
+ 'DomPDF' => Barryvdh\DomPDF\Facade::class,
'SnappyPDF' => Barryvdh\Snappy\Facades\SnappyPdf::class,
'Debugbar' => Barryvdh\Debugbar\Facade::class,
],
+ 'proxies' => env('APP_PROXIES', ''),
+
];
--- /dev/null
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class AddCoverImageDisplay extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::table('books', function (Blueprint $table) {
+ $table->integer('image_id')->nullable()->default(null);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('books', function (Blueprint $table) {
+ $table->dropColumn('image_id');
+ });
+ }
+}
As part of BookStack v0.14 support for translations has been built in. All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`.
You will also need to add the language to the `locales` array in the `config/app.php` file.
+
+There is a script available which compares translation content to `en` files to see what items are missing or redundant. This can be ran like so from your BookStack install folder:
+
+```bash
+# Syntax
+php resources/lang/check.php <lang>
+
+# Examples
+php resources/lang/check.php fr
+php resources/lang/check.php pt_BR
+```
- Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time.
+Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time.
## Contributing
--- /dev/null
+
+class ImagePicker {
+
+ constructor(elem) {
+ this.elem = elem;
+ this.imageElem = elem.querySelector('img');
+ this.input = elem.querySelector('input');
+
+ this.isUsingIds = elem.getAttribute('data-current-id') !== '';
+ this.isResizing = elem.getAttribute('data-resize-height') && elem.getAttribute('data-resize-width');
+ this.isResizeCropping = elem.getAttribute('data-resize-crop') !== '';
+
+ let selectButton = elem.querySelector('button[data-action="show-image-manager"]');
+ selectButton.addEventListener('click', this.selectImage.bind(this));
+
+ let resetButton = elem.querySelector('button[data-action="reset-image"]');
+ resetButton.addEventListener('click', this.reset.bind(this));
+
+ let removeButton = elem.querySelector('button[data-action="remove-image"]');
+ if (removeButton) {
+ removeButton.addEventListener('click', this.removeImage.bind(this));
+ }
+ }
+
+ selectImage() {
+ window.ImageManager.show(image => {
+ if (!this.isResizing) {
+ this.setImage(image);
+ return;
+ }
+
+ let requestString = '/images/thumb/' + image.id + '/' + this.elem.getAttribute('data-resize-width') + '/' + this.elem.getAttribute('data-resize-height') + '/' + (this.isResizeCropping ? 'true' : 'false');
+
+ window.$http.get(window.baseUrl(requestString)).then(resp => {
+ image.url = resp.data.url;
+ this.setImage(image);
+ });
+ });
+ }
+
+ reset() {
+ this.setImage({id: 0, url: this.elem.getAttribute('data-default-image')});
+ }
+
+ setImage(image) {
+ this.imageElem.src = image.url;
+ this.input.value = this.isUsingIds ? image.id : image.url;
+ this.imageElem.classList.remove('none');
+ }
+
+ removeImage() {
+ this.imageElem.src = this.elem.getAttribute('data-default-image');
+ this.imageElem.classList.add('none');
+ this.input.value = 'none';
+ }
+
+}
+
+module.exports = ImagePicker;
\ No newline at end of file
'wysiwyg-editor': require('./wysiwyg-editor'),
'markdown-editor': require('./markdown-editor'),
'editor-toolbox': require('./editor-toolbox'),
+ 'image-picker': require('./image-picker'),
};
window.components = {};
};
// Save draft
extraKeys[`${metaKey}-S`] = cm => {window.$events.emit('editor-save-draft')};
+ // Save page
+ extraKeys[`${metaKey}-Enter`] = cm => {window.$events.emit('editor-save-page')};
// Show link selector
extraKeys[`Shift-${metaKey}-K`] = cm => {this.actionShowLinkSelector()};
// Insert Link
window.$events.emit('editor-save-draft');
});
+ // Save page shortcut
+ editor.shortcuts.add('meta+13', '', () => {
+ window.$events.emit('editor-save-page');
+ });
+
// Loop through callout styles
editor.shortcuts.add('meta+9', '', function() {
let selectedNode = editor.selection.getNode();
}
+/**
+ * Load custom HTML head content from the settings into the editor.
+ * @param editor
+ */
+function loadCustomHeadContent(editor) {
+ window.$http.get(window.baseUrl('/custom-head-content')).then(resp => {
+ if (!resp.data) return;
+ let head = editor.getDoc().querySelector('head');
+ head.innerHTML += resp.data;
+ });
+}
/**
* Create and enable our custom code plugin
args.content = '';
}
},
+ init_instance_callback: function(editor) {
+ loadCustomHeadContent(editor);
+ },
setup: function (editor) {
editor.on('init ExecCommand change input NodeChange ObjectResized', editorChange);
let $window = $(window);
let $sidebar = $("#sidebar .scroll-body");
let $bookTreeParent = $sidebar.parent();
+
// Check the page is scrollable and the content is taller than the tree
let pageScrollable = ($(document).height() > $window.height()) && ($sidebar.height() < $('.page-content').height());
+
// Get current tree's width and header height
let headerHeight = $("#header").height() + $(".toolbar").height();
let isFixed = $window.scrollTop() > headerHeight;
- // Function to fix the tree as a sidebar
+
+ // Fix the tree as a sidebar
function stickTree() {
$sidebar.width($bookTreeParent.width() + 15);
$sidebar.addClass("fixed");
isFixed = true;
}
- // Function to un-fix the tree back into position
+
+ // Un-fix the tree back into position
function unstickTree() {
$sidebar.css('width', 'auto');
$sidebar.removeClass("fixed");
isFixed = false;
}
+
// Checks if the tree stickiness state should change
function checkTreeStickiness(skipCheck) {
let shouldBeFixed = $window.scrollTop() > headerHeight;
unstickTree();
}
});
+
+
+ // Check if support is present for IntersectionObserver
+ if ('IntersectionObserver' in window &&
+ 'IntersectionObserverEntry' in window &&
+ 'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
+ addPageHighlighting();
+ }
+
+ function addPageHighlighting() {
+ let pageNav = document.querySelector('.sidebar-page-nav');
+
+ // fetch all the headings.
+ let headings = document.querySelector('.page-content').querySelectorAll('h1, h2, h3, h4, h5, h6');
+ // if headings are present, add observers.
+ if (headings.length > 0 && pageNav !== null) {
+ addNavObserver(headings);
+ }
+
+ function addNavObserver(headings) {
+ // Setup the intersection observer.
+ let intersectOpts = {
+ rootMargin: '0px 0px 0px 0px',
+ threshold: 1.0
+ };
+ let pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
+
+ // observe each heading
+ for (let i = 0; i !== headings.length; ++i) {
+ pageNavObserver.observe(headings[i]);
+ }
+ }
+
+ function headingVisibilityChange(entries, observer) {
+ for (let i = 0; i < entries.length; i++) {
+ let currentEntry = entries[i];
+ let isVisible = (currentEntry.intersectionRatio === 1);
+ toggleAnchorHighlighting(currentEntry.target.id, isVisible);
+ }
+ }
+
+ function toggleAnchorHighlighting(elementId, shouldHighlight) {
+ let anchorsToHighlight = pageNav.querySelectorAll('a[href="#' + elementId + '"]');
+ for (let i = 0; i < anchorsToHighlight.length; i++) {
+ // Change below to use classList.toggle when IE support is dropped.
+ if (shouldHighlight) {
+ anchorsToHighlight[i].classList.add('current-heading');
+ } else {
+ anchorsToHighlight[i].classList.remove('current-heading');
+ }
+ }
+ }
+ }
};
module.exports = setupPageShow;
\ No newline at end of file
this.draftText = trans('entities.pages_editing_page');
}
- // Listen to save draft events from editor
+ // Listen to save events from editor
window.$events.listen('editor-save-draft', this.saveDraft);
+ window.$events.listen('editor-save-page', this.savePage);
// Listen to content changes from the editor
window.$events.listen('editor-html-change', html => {
});
},
+ savePage() {
+ this.$el.closest('form').submit();
+ },
draftNotifyChange(text) {
this.draftText = text;
padding: 0 $-m 0;
margin-left: -1px;
overflow-y: scroll;
- .page-content {
- margin: 0 auto;
- }
+ }
+ .markdown-display.page-content {
+ margin: 0 auto;
+ max-width: 100%;
}
}
.editor-toolbar {
width: 30%;
left: 0;
height: 100%;
- overflow-y: scroll;
+ overflow-y: auto;
-ms-overflow-style: none;
//background-color: $primary-faded;
border-left: 1px solid #DDD;
display: inline-block;
}
+@include larger-than(991px) {
+ .row.auto-clear .col-md-4:nth-child(3n+1){clear:left;}
+}
+
+@include smaller-than(992px) {
+ .row.auto-clear .col-xs-6:nth-child(2n+1){clear:left;}
+}
+
.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
position: relative;
min-height: 1px;
.h6 {
margin-left: $nav-indent*4;
}
+ .current-heading {
+ font-weight: bold;
+ }
}
// Sidebar list
border-bottom: 1px solid #DDD;
}
}
+
+// Books grid view
+.featured-image-container {
+ position: relative;
+ overflow: hidden;
+ background: #F2F2F2;
+ border: 1px solid #ddd;
+ border-bottom: 0;
+ img {
+ display: block;
+ max-width: 100%;
+ height: auto;
+ transition: all .5s ease;
+ }
+ img:hover {
+ transform: scale(1.15);
+ opacity: .5;
+ }
+}
+
+.book-grid-content {
+ padding: 30px;
+ border: 1px solid #ddd;
+ border-top: 0;
+ border-bottom-width: 2px;
+ h2 {
+ font-size: 1.5em;
+ margin: 0 0 10px;
+ }
+ h2 a {
+ display: block;
+ line-height: 1.2;
+ color: #009688;;
+ text-decoration: none;
+ }
+ p {
+ font-size: .85em;
+ margin: 0 0 10px;
+ line-height: 1.6em;
+ }
+ p.small {
+ font-size: .8em;
+ }
+}
+
+.book-grid-item {
+ margin-bottom : 20px;
+}
-
-.mce-tinymce.mce-container.fullscreen {
+.mce-tinymce.mce-container.mce-fullscreen {
position: fixed;
top: 0;
height: 100%;
- width: 825px;
+ width: 100%;
max-width: 100%;
- margin-left: -$-s;
- box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.08);
+ z-index: 100;
}
-
.mce-tinymce {
.mce-panel {
background-color: #FFF;
input {
width: 100%;
}
-}
-
-
-
+}
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env php
+<?php
+
+/**
+ * Compares translation files to find missing and redundant content.
+ */
+
+$args = array_slice($argv, 1);
+
+if (count($args) === 0) {
+ errorOut("Please provide a language code as the first argument (./check.php fr)");
+}
+
+
+// Get content from files
+$lang = formatLang($args[0]);
+$enContent = loadLang('en');
+$langContent = loadLang($lang);
+
+if (count($langContent) === 0) {
+ errorOut("No language content found for '{$lang}'");
+}
+
+info("Checking '{$lang}' translation content against 'en'");
+
+// Track missing lang strings
+$missingLangStrings = [];
+foreach ($enContent as $enKey => $enStr) {
+ if (strpos($enKey, 'settings.language_select.') === 0) {
+ unset($langContent[$enKey]);
+ continue;
+ }
+ if (!isset($langContent[$enKey])) {
+ $missingLangStrings[$enKey] = $enStr;
+ continue;
+ }
+ unset($langContent[$enKey]);
+}
+
+if (count($missingLangStrings) > 0) {
+ info("\n========================");
+ info("Missing language content");
+ info("========================");
+ outputFlatArray($missingLangStrings, $lang);
+}
+
+if (count($langContent) > 0) {
+ info("\n==========================");
+ info("Redundant language content");
+ info("==========================");
+ outputFlatArray($langContent, $lang);
+}
+
+function outputFlatArray($arr, $lang) {
+ $grouped = [];
+ foreach ($arr as $key => $val) {
+ $explodedKey = explode('.', $key);
+ $group = $explodedKey[0];
+ $path = implode('.', array_slice($explodedKey, 1));
+ if (!isset($grouped[$group])) $grouped[$group] = [];
+ $grouped[$group][$path] = $val;
+ }
+ foreach ($grouped as $filename => $arr) {
+ echo "\e[36m" . $lang . '/' . $filename . ".php\e[0m\n";
+ echo json_encode($arr, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . "\n";
+ }
+}
+
+function formatLang($lang) {
+ $langParts = explode('_', strtoupper($lang));
+ $langParts[0] = strtolower($langParts[0]);
+ return implode('_', $langParts);
+}
+
+function loadLang(string $lang) {
+ $dir = __DIR__ . "/{$lang}";
+ if (!file_exists($dir)) {
+ errorOut("Expected directory '{$dir}' does not exist");
+ }
+ $files = scandir($dir);
+ $data = [];
+ foreach ($files as $file) {
+ if (substr($file, -4) !== '.php') continue;
+ $fileData = include ($dir . '/' . $file);
+ $name = substr($file, 0, -4);
+ $data[$name] = $fileData;
+ }
+ return flattenArray($data);
+}
+
+function flattenArray(array $arr) {
+ $data = [];
+ foreach ($arr as $key => $arrItem) {
+ if (!is_array($arrItem)) {
+ $data[$key] = $arrItem;
+ continue;
+ }
+
+ $toUse = flattenArray($arrItem);
+ foreach ($toUse as $innerKey => $item) {
+ $data[$key . '.' . $innerKey] = $item;
+ }
+ }
+ return $data;
+}
+
+function info($text) {
+ echo "\e[34m" . $text . "\e[0m\n";
+}
+
+function errorOut($text) {
+ echo "\e[31m" . $text . "\e[0m\n";
+ exit(1);
+}
\ No newline at end of file
'name' => 'Name',
'description' => 'Beschreibung',
'role' => 'Rolle',
+ 'cover_image' => 'Titelbild',
+ 'cover_image_description' => 'Das Bild sollte eine Auflösung von 300x170px haben.',
/**
* Actions
'no_items' => 'Keine Einträge gefunden.',
'back_to_top' => 'nach oben',
'toggle_details' => 'Details zeigen/verstecken',
-
+ 'toggle_thumbnails' => 'Thumbnails zeigen/verstecken',
/**
* Header
*/
'app_logo_desc' => "Dieses Bild sollte 43px hoch sein.\nGrößere Bilder werden verkleinert.",
'app_primary_color' => 'Primäre Anwendungsfarbe',
'app_primary_color_desc' => "Dies sollte ein HEX Wert sein.\nWenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt.",
+ 'app_disable_comments' => 'Kommentare deaktivieren',
+ 'app_disable_comments_desc' => 'Deaktiviert Kommentare über alle Seiten in der Anwendung. Vorhandene Kommentare werden nicht angezeigt.',
/**
* Registration settings
'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_view_type' => 'Bevorzugtes Display-Layout für Bücher',
'users_edit' => 'Benutzer bearbeiten',
'users_edit_profile' => 'Profil bearbeiten',
'users_edit_success' => 'Benutzer erfolgreich aktualisisert',
'name' => 'Name',
'description' => 'Description',
'role' => 'Role',
-
+ 'cover_image' => 'Cover image',
+ 'cover_image_description' => 'This image should be approx 440x250px.',
+
/**
* Actions
*/
'no_items' => 'No items available',
'back_to_top' => 'Back to top',
'toggle_details' => 'Toggle Details',
+ 'toggle_thumbnails' => 'Toggle Thumbnails',
'details' => 'Details',
/**
'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',
+ 'app_disable_comments' => 'Disable comments',
+ 'app_disable_comments_desc' => 'Disable comments across all pages in the application. Existing comments are not shown.',
/**
* Registration settings
'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_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.',
'name' => 'Nombre',
'description' => 'Descripción',
'role' => 'Rol',
-
+ 'cover_image' => 'Imagen de portada',
+ 'cover_image_description' => 'Esta imagen debe ser aproximadamente 300x170px.',
/**
* Actions
*/
'no_items' => 'No hay items disponibles',
'back_to_top' => 'Volver arriba',
'toggle_details' => 'Alternar detalles',
+ 'toggle_thumbnails' => 'Alternar miniaturas',
/**
* Header
'app_logo_desc' => 'Esta imagen debería de ser 43px en altura. <br>Iágenes grandes seán escaladas.',
'app_primary_color' => 'Color primario de la aplicación',
'app_primary_color_desc' => 'Esto debería ser un valor hexadecimal. <br>Deje el valor vaío para reiniciar al valor por defecto.',
+ 'app_disable_comments' => 'Deshabilitar comentarios',
+ 'app_disable_comments_desc' => 'Deshabilita los comentarios en todas las páginas de la aplicación. Los comentarios existentes no se muestran. ',
/**
* Registration settings
'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_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.',
'name' => 'Nom',
'description' => 'Description',
'role' => 'Rôle',
-
+ 'cover_image' => 'Image de couverture',
+ 'cover_image_description' => 'Cette image doit être environ 300x170px.',
/**
* Actions
*/
'no_items' => 'Aucun élément',
'back_to_top' => 'Retour en haut',
'toggle_details' => 'Afficher les détails',
+ 'toggle_thumbnails' => 'Afficher les vignettes',
/**
* Header
'app_logo_desc' => 'Cette image doit faire 43px de hauteur. <br>Les images plus larges seront réduites.',
'app_primary_color' => 'Couleur principale de l\'application',
'app_primary_color_desc' => 'Cela devrait être une valeur hexadécimale. <br>Laisser vide pour rétablir la couleur par défaut.',
-
+ 'app_disable_comments' => 'Désactiver les commentaires',
+ 'app_disable_comments_desc' => 'Désactive les commentaires sur toutes les pages de l\'application. Les commentaires existants ne sont pas affichés.',
/**
* Registration settings
*/
'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_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.',
'app_homepage' => 'Homepage Applicazione',
'app_homepage_desc' => 'Seleziona una pagina da mostrare nella home anzichè quella di default. I permessi della pagina sono ignorati per quella selezionata.',
'app_homepage_default' => 'Homepage di default scelta',
+ 'app_disable_comments' => 'Disattiva commenti',
+ 'app_disable_comments_desc' => 'Disabilita i commenti su tutte le pagine nell\'applicazione. I commenti esistenti non sono mostrati. ',
/**
* Registration settings
*/
-
'reg_settings' => 'Impostazioni Registrazione',
'reg_allow' => 'Consentire Registrazione?',
'reg_default_role' => 'Ruolo predefinito dopo la registrazione',
'name' => '名称',
'description' => '概要',
'role' => '権限',
-
+ 'cover_image_description' => 'この画像は約 300x170px をする必要があります。',
/**
* Actions
*/
'app_logo_desc' => '高さ43pxで表示されます。これを上回る場合、自動で縮小されます。',
'app_primary_color' => 'プライマリカラー',
'app_primary_color_desc' => '16進数カラーコードで入力します。空にした場合、デフォルトの色にリセットされます。',
+ 'app_disable_comments' => 'コメントを無効にする',
+ 'app_disable_comments_desc' => 'アプリケーション内のすべてのページのコメントを無効にします。既存のコメントは表示されません。',
/**
* Registration settings
'users_social_disconnect' => 'アカウントを接続解除',
'users_social_connected' => '「:socialAccount」がプロフィールに接続されました。',
'users_social_disconnected' => '「:socialAccount」がプロフィールから接続解除されました。'
-
+
];
'name' => 'Naam',
'description' => 'Beschrijving',
'role' => 'Rol',
-
+ 'cover_image' => 'Omslagfoto',
+ 'cover_image_description' => 'Deze afbeelding moet ongeveer 300x170px zijn.',
/**
* Actions
*/
'no_items' => 'Geen items beschikbaar',
'back_to_top' => 'Terug naar boven',
'toggle_details' => 'Details Weergeven',
+ 'toggle_thumbnails' => 'Thumbnails Weergeven',
/**
* Header
'app_logo_desc' => 'De afbeelding moet 43px hoog zijn. <br>Grotere afbeeldingen worden geschaald.',
'app_primary_color' => 'Applicatie hoofdkleur',
'app_primary_color_desc' => 'Geef een hexadecimale waarde. <br>Als je niks invult wordt de standaardkleur gebruikt.',
+ 'app_disable_comments' => 'Reacties uitschakelen',
+ 'app_disable_comments_desc' => 'Schakel opmerkingen uit op alle pagina\'s in de applicatie. Bestaande opmerkingen worden niet getoond.',
/**
* Registration settings
'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_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.',
'name' => 'Nazwa',
'description' => 'Opis',
'role' => 'Rola',
-
+ 'cover_image' => 'Zdjęcie z okładki',
+ 'cover_image_description' => 'Ten obraz powinien wynosić około 300 x 170 piksli.',
+
/**
* Actions
*/
'app_logo_desc' => 'Ten obrazek powinien mieć nie więcej niż 43px w pionie. <br>Większe obrazki będą skalowane w dół.',
'app_primary_color' => 'Podstawowy kolor aplikacji',
'app_primary_color_desc' => 'To powinna być wartość HEX. <br>Zostaw to pole puste, by powrócić do podstawowego koloru.',
+ 'app_disable_comments' => 'Wyłącz komentarze',
+ 'app_disable_comments_desc' => 'Wyłącz komentarze na wszystkich stronach w aplikacji. Istniejące komentarze nie są pokazywane.',
/**
* Registration settings
'name' => 'Nome',
'description' => 'Descrição',
'role' => 'Regra',
-
+ 'cover_image' => 'Imagem de capa',
+ 'cover_image_description' => 'Esta imagem deve ser aproximadamente 300x170px.',
/**
* Actions
*/
'no_items' => 'Nenhum item disponível',
'back_to_top' => 'Voltar ao topo',
'toggle_details' => 'Alternar Detalhes',
+ 'toggle_thumbnails' => 'Alternar Miniaturas',
'details' => 'Detalhes',
/**
'app_homepage' => 'Página incial',
'app_homepage_desc' => 'Selecione a página para ser usada como página inicial em vez da padrão. Permissões da página serão ignoradas.',
'app_homepage_default' => 'Escolhida página inicial padrão',
+ 'app_disable_comments' => 'Desativar comentários',
+ 'app_disable_comments_desc' => 'Desativar comentários em todas as páginas no aplicativo. Os comentários existentes não são exibidos.',
/**
* Registration settings
'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_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.',
'app_homepage' => 'Домашняя страница приложения',
'app_homepage_desc' => 'Выберите страницу, которая будет отображаться на главной странице вместо стандартной. Права на страницы игнорируются для выбранных страниц.',
'app_homepage_default' => 'Выбрана домашняя страница по-умолчанию',
+ 'app_disable_comments' => 'Отключить комментарии',
+ 'app_disable_comments_desc' => 'Отключить комментарии на всех страницах приложения. Существующие комментарии не отображаются.',
/**
* Registration
'name' => 'Meno',
'description' => 'Popis',
'role' => 'Rola',
-
+ 'cover_image' => 'Obal knihy',
+ 'cover_image_description' => 'Tento obrázok by mal byť približne 300 x 170 pixelov.',
/**
* Actions
*/
'no_items' => 'Žiadne položky nie sú dostupné',
'back_to_top' => 'Späť nahor',
'toggle_details' => 'Prepnúť detaily',
+ 'toggle_thumbnails' => 'Prepnúť náhľady',
/**
* Header
'app_logo_desc' => 'Tento obrázok by mal mať 43px na výšku. <br>Veľké obrázky budú preškálované na menší rozmer.',
'app_primary_color' => 'Primárna farba pre aplikáciu',
'app_primary_color_desc' => 'Toto by mala byť hodnota v hex tvare. <br>Nechajte prázdne ak chcete použiť prednastavenú farbu.',
+ 'app_disable_comments' => 'Zakázať komentáre',
+ 'app_disable_comments_desc' => 'Zakázať komentáre na všetkých stránkach aplikácie. Existujúce komentáre sa nezobrazujú.',
/**
* Registration settings
'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_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.',
<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
\ No newline at end of file
</div>
</div>
</div>
-
+@include('components.image-manager', ['imageType' => 'cover'])
@stop
\ No newline at end of file
<label for="description">{{ trans('common.description') }}</label>
@include('form/textarea', ['name' => 'description'])
</div>
+<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' => '512',
+ 'resizeWidth' => '512',
+ 'showRemove' => false,
+ 'defaultImage' => baseUrl('/book_default_cover.png'),
+ 'currentImage' => @isset($model) ? $model->getBookCover() : baseUrl('/book_default_cover.png') ,
+ 'currentId' => @isset($model) ? $model->image_id : 0,
+ 'name' => 'image_id',
+ 'imageClass' => 'cover'
+ ])
+</div>
<div class="form-group text-right">
<a href="{{ isset($book) ? $book->getUrl() : baseUrl('/books') }}" class="button outline">{{ trans('common.cancel') }}</a>
--- /dev/null
+<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 book-grid-item" 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>
+ <div class="book-grid-content">
+ <h2><a href="{{$book->getUrl()}}" title="{{$book->name}}" > {{$book->getShortName(35)}} </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
<button class="text-button neg" data-action="remove-image" type="button">{{ trans('common.remove') }}</button>
@endif
- <input type="hidden" name="{{$name}}" id="{{$name}}" value="{{ isset($currentId) && ($currentId !== '' && $currentId !== false) ? $currentId : $currentImage}}">
-</div>
-
-<script>
- (function(){
-
- var picker = document.querySelector('[image-picker="{{$name}}"]');
- picker.addEventListener('click', function(event) {
- if (event.target.nodeName.toLowerCase() !== 'button') return;
- var button = event.target;
- var action = button.getAttribute('data-action');
- var resize = picker.getAttribute('data-resize-height') && picker.getAttribute('data-resize-width');
- var usingIds = picker.getAttribute('data-current-id') !== '';
- var resizeCrop = picker.getAttribute('data-resize-crop') !== '';
- var imageElem = picker.querySelector('img');
- var input = picker.querySelector('input');
-
- function setImage(image) {
- if (image === 'none') {
- imageElem.src = picker.getAttribute('data-default-image');
- imageElem.classList.add('none');
- input.value = 'none';
- return;
- }
- imageElem.src = image.url;
- input.value = usingIds ? image.id : image.url;
- imageElem.classList.remove('none');
- }
-
- if (action === 'show-image-manager') {
- window.ImageManager.show((image) => {
- if (!resize) {
- setImage(image);
- return;
- }
- var requestString = '/images/thumb/' + image.id + '/' + picker.getAttribute('data-resize-width') + '/' + picker.getAttribute('data-resize-height') + '/' + (resizeCrop ? 'true' : 'false');
- $.get(window.baseUrl(requestString), resp => {
- image.url = resp.url;
- setImage(image);
- });
- });
- } else if (action === 'reset-image') {
- setImage({id: 0, url: picker.getAttribute('data-default-image')});
- } else if (action === 'remove-image') {
- setImage('none');
- }
-
- });
-
- })();
-</script>
\ No newline at end of file
+ <input type="hidden" name="{{$name}}" id="{{$name}}" value="{{ isset($currentId) && ($currentId !== 0 && $currentId !== false) ? $currentId : $currentImage}}">
+</div>
\ No newline at end of file
<div class="editor-toolbar">
<div class="">{{ trans('entities.pages_md_preview') }}</div>
</div>
- <div class="markdown-display">
- <div class="page-content"></div>
+ <div class="markdown-display page-content">
</div>
</div>
<input type="hidden" name="html"/>
</div>
@include('partials/book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
-
+
@stop
@section('body')
@include('pages/page-display')
</div>
-
- <div class="container small nopad">
- @include('comments/comments', ['page' => $page])
- </div>
+ @if ($commentsEnabled)
+ <div class="container small nopad">
+ @include('comments/comments', ['page' => $page])
+ </div>
+ @endif
@stop
@section('scripts')
--- /dev/null
+@if(setting('app-custom-head', false))
+ <!-- Custom user content -->
+ {!! setting('app-custom-head') !!}
+ <!-- End custom user content -->
+@endif
\ No newline at end of file
}
.button-base, .button, input[type="button"], input[type="submit"] {
background-color: {{ setting('app-color') }};
+ border-color: {{ setting('app-color') }};
}
.button-base:hover, .button:hover, input[type="button"]:hover, input[type="submit"]:hover, .button:focus {
background-color: {{ setting('app-color') }};
<p class="small">{{ trans('settings.app_secure_images_desc') }}</p>
@include('components.toggle-switch', ['name' => 'setting-app-secure-images', 'value' => setting('app-secure-images')])
</div>
+ <div class="form-group">
+ <label>{{ trans('settings.app_disable_comments') }}</label>
+ <p class="small">{{ trans('settings.app_disable_comments_desc') }}</p>
+ @include('components.toggle-switch', ['name' => 'setting-app-disable-comments', 'value' => setting('app-disable-comments')])
+ </div>
<div class="form-group">
<label for="setting-app-editor">{{ trans('settings.app_editor') }}</label>
<p class="small">{{ trans('settings.app_editor_desc') }}</p>
@endforeach
</select>
</div>
+ <div class="form-group">
+ <label for="books-view-type">{{ trans('settings.users_books_view_type') }}</label>
+ <select name="setting[books_view_type]" id="books-view-type">
+ <option @if(setting()->getUser($user, 'books_view_type', 'list') === 'list') selected @endif value="list">List</option>
+ <option @if(setting()->getUser($user, 'books_view_type', 'list') === 'grid') selected @endif value="grid">Grid</option>
+ </select>
+ </div>
</div>
</div>
<div class="form-group text-right">
<p class="margin-top large"><br></p>
@include('components.image-manager', ['imageType' => 'user'])
-@stop
+@stop
\ No newline at end of file
// Other Pages
Route::get('/', 'HomeController@index');
Route::get('/home', 'HomeController@index');
+ Route::get('/custom-head-content', 'HomeController@customHeadContent');
// Settings
Route::group(['prefix' => 'settings'], function() {
--- /dev/null
+<?php namespace Tests;
+
+class CommentSettingTest extends BrowserKitTest {
+ protected $page;
+
+ public function setUp() {
+ parent::setUp();
+ $this->page = \BookStack\Page::first();
+ }
+
+ public function test_comment_disable () {
+ $this->asAdmin();
+
+ $this->setSettings(['app-disable-comments' => 'true']);
+
+ $this->asAdmin()->visit($this->page->getUrl())
+ ->pageNotHasElement('.comments-list');
+ }
+
+ public function test_comment_enable () {
+ $this->asAdmin();
+
+ $this->setSettings(['app-disable-comments' => 'false']);
+
+ $this->asAdmin()->visit($this->page->getUrl())
+ ->pageHasElement('.comments-list');
+ }
+}
\ No newline at end of file
public function setUp()
{
parent::setUp();
- $this->langs = array_diff(scandir(resource_path('lang')), ['..', '.']);
+ $this->langs = array_diff(scandir(resource_path('lang')), ['..', '.', 'check.php']);
}
public function test_locales_config_key_set_properly()
->seePageIs('/settings/users/' . $guestUser->id)
->see('cannot delete the guest user');
}
-
+
+ public function test_books_view_is_list()
+ {
+ $editor = $this->getEditor();
+ setting()->putUser($editor, 'books_view_type', 'list');
+
+ $this->actingAs($editor)
+ ->visit('/books')
+ ->pageNotHasElement('.featured-image-container')
+ ->pageHasElement('.entity-list-item');
+ }
+
+ public function test_books_view_is_grid()
+ {
+ $editor = $this->getEditor();
+ setting()->putUser($editor, 'books_view_type', 'grid');
+
+ $this->actingAs($editor)
+ ->visit('/books')
+ ->pageHasElement('.featured-image-container');
+ }
}