mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Resolved conflicts
This commit is contained in:
commit
7f902e41c7
5
.gitignore
vendored
5
.gitignore
vendored
@ -8,16 +8,15 @@ Homestead.yaml
|
|||||||
/public/css
|
/public/css
|
||||||
/public/js
|
/public/js
|
||||||
/public/bower
|
/public/bower
|
||||||
|
/public/build/
|
||||||
/storage/images
|
/storage/images
|
||||||
_ide_helper.php
|
_ide_helper.php
|
||||||
/storage/debugbar
|
/storage/debugbar
|
||||||
.phpstorm.meta.php
|
.phpstorm.meta.php
|
||||||
yarn.lock
|
yarn.lock
|
||||||
/bin
|
/bin
|
||||||
|
nbproject
|
||||||
.buildpath
|
.buildpath
|
||||||
|
|
||||||
.project
|
.project
|
||||||
|
|
||||||
.settings/org.eclipse.wst.common.project.facet.core.xml
|
.settings/org.eclipse.wst.common.project.facet.core.xml
|
||||||
|
|
||||||
.settings/org.eclipse.php.core.prefs
|
.settings/org.eclipse.php.core.prefs
|
||||||
|
96
app/Comment.php
Normal file
96
app/Comment.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BookStack;
|
||||||
|
|
||||||
|
class Comment extends Ownable
|
||||||
|
{
|
||||||
|
public $sub_comments = [];
|
||||||
|
protected $fillable = ['text', 'html', 'parent_id'];
|
||||||
|
protected $appends = ['created', 'updated', 'sub_comments'];
|
||||||
|
/**
|
||||||
|
* Get the entity that this comment belongs to
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
|
||||||
|
*/
|
||||||
|
public function entity()
|
||||||
|
{
|
||||||
|
return $this->morphTo('entity');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the page that this comment is in.
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function page()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Page::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the owner of this comment.
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not being used, but left here because might be used in the future for performance reasons.
|
||||||
|
*/
|
||||||
|
public function getPageComments($pageId) {
|
||||||
|
$query = static::newQuery();
|
||||||
|
$query->join('users AS u', 'comments.created_by', '=', 'u.id');
|
||||||
|
$query->leftJoin('users AS u1', 'comments.updated_by', '=', 'u1.id');
|
||||||
|
$query->leftJoin('images AS i', 'i.id', '=', 'u.image_id');
|
||||||
|
$query->selectRaw('comments.id, text, html, comments.created_by, comments.updated_by, '
|
||||||
|
. 'comments.created_at, comments.updated_at, comments.parent_id, '
|
||||||
|
. 'u.name AS created_by_name, u1.name AS updated_by_name, '
|
||||||
|
. 'i.url AS avatar ');
|
||||||
|
$query->whereRaw('page_id = ?', [$pageId]);
|
||||||
|
$query->orderBy('created_at');
|
||||||
|
return $query->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllPageComments($pageId) {
|
||||||
|
return self::where('page_id', '=', $pageId)->with(['createdBy' => function($query) {
|
||||||
|
$query->select('id', 'name', 'image_id');
|
||||||
|
}, 'updatedBy' => function($query) {
|
||||||
|
$query->select('id', 'name');
|
||||||
|
}, 'createdBy.avatar' => function ($query) {
|
||||||
|
$query->select('id', 'path', 'url');
|
||||||
|
}])->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommentById($commentId) {
|
||||||
|
return self::where('id', '=', $commentId)->with(['createdBy' => function($query) {
|
||||||
|
$query->select('id', 'name', 'image_id');
|
||||||
|
}, 'updatedBy' => function($query) {
|
||||||
|
$query->select('id', 'name');
|
||||||
|
}, 'createdBy.avatar' => function ($query) {
|
||||||
|
$query->select('id', 'path', 'url');
|
||||||
|
}])->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCreatedAttribute() {
|
||||||
|
$created = [
|
||||||
|
'day_time_str' => $this->created_at->toDayDateTimeString(),
|
||||||
|
'diff' => $this->created_at->diffForHumans()
|
||||||
|
];
|
||||||
|
return $created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUpdatedAttribute() {
|
||||||
|
if (empty($this->updated_at)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$updated = [
|
||||||
|
'day_time_str' => $this->updated_at->toDayDateTimeString(),
|
||||||
|
'diff' => $this->updated_at->diffForHumans()
|
||||||
|
];
|
||||||
|
return $updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubCommentsAttribute() {
|
||||||
|
return $this->sub_comments;
|
||||||
|
}
|
||||||
|
}
|
57
app/Console/Commands/UpgradeDatabaseEncoding.php
Normal file
57
app/Console/Commands/UpgradeDatabaseEncoding.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BookStack\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class UpgradeDatabaseEncoding extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'bookstack:db-utf8mb4 {--database= : The database connection to use.}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Generate SQL commands to upgrade the database to UTF8mb4';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$connection = DB::getDefaultConnection();
|
||||||
|
if ($this->option('database') !== null) {
|
||||||
|
DB::setDefaultConnection($this->option('database'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$database = DB::getDatabaseName();
|
||||||
|
$tables = DB::select('SHOW TABLES');
|
||||||
|
$this->line('ALTER DATABASE `'.$database.'` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;');
|
||||||
|
$this->line('USE `'.$database.'`;');
|
||||||
|
$key = 'Tables_in_' . $database;
|
||||||
|
foreach ($tables as $table) {
|
||||||
|
$tableName = $table->$key;
|
||||||
|
$this->line('ALTER TABLE `'.$tableName.'` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;');
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::setDefaultConnection($connection);
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,8 @@ class Kernel extends ConsoleKernel
|
|||||||
Commands\ClearActivity::class,
|
Commands\ClearActivity::class,
|
||||||
Commands\ClearRevisions::class,
|
Commands\ClearRevisions::class,
|
||||||
Commands\RegeneratePermissions::class,
|
Commands\RegeneratePermissions::class,
|
||||||
Commands\RegenerateSearch::class
|
Commands\RegenerateSearch::class,
|
||||||
|
Commands\UpgradeDatabaseEncoding::class
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,6 +8,7 @@ use BookStack\Exceptions\UserRegistrationException;
|
|||||||
use BookStack\Repos\UserRepo;
|
use BookStack\Repos\UserRepo;
|
||||||
use BookStack\Services\EmailConfirmationService;
|
use BookStack\Services\EmailConfirmationService;
|
||||||
use BookStack\Services\SocialAuthService;
|
use BookStack\Services\SocialAuthService;
|
||||||
|
use BookStack\SocialAccount;
|
||||||
use BookStack\User;
|
use BookStack\User;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -103,7 +104,7 @@ class RegisterController extends Controller
|
|||||||
* @param Request|\Illuminate\Http\Request $request
|
* @param Request|\Illuminate\Http\Request $request
|
||||||
* @return Response
|
* @return Response
|
||||||
* @throws UserRegistrationException
|
* @throws UserRegistrationException
|
||||||
* @throws \Illuminate\Foundation\Validation\ValidationException
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
*/
|
*/
|
||||||
public function postRegister(Request $request)
|
public function postRegister(Request $request)
|
||||||
{
|
{
|
||||||
@ -255,16 +256,13 @@ class RegisterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function socialCallback($socialDriver)
|
public function socialCallback($socialDriver)
|
||||||
{
|
{
|
||||||
if (session()->has('social-callback')) {
|
if (!session()->has('social-callback')) {
|
||||||
$action = session()->pull('social-callback');
|
|
||||||
if ($action == 'login') {
|
|
||||||
return $this->socialAuthService->handleLoginCallback($socialDriver);
|
|
||||||
} elseif ($action == 'register') {
|
|
||||||
return $this->socialRegisterCallback($socialDriver);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
|
throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$action = session()->pull('social-callback');
|
||||||
|
if ($action == 'login') return $this->socialAuthService->handleLoginCallback($socialDriver);
|
||||||
|
if ($action == 'register') return $this->socialRegisterCallback($socialDriver);
|
||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
99
app/Http/Controllers/CommentController.php
Normal file
99
app/Http/Controllers/CommentController.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php namespace BookStack\Http\Controllers;
|
||||||
|
|
||||||
|
use BookStack\Repos\CommentRepo;
|
||||||
|
use BookStack\Repos\EntityRepo;
|
||||||
|
use BookStack\Comment;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class CommentController extends Controller
|
||||||
|
{
|
||||||
|
protected $entityRepo;
|
||||||
|
|
||||||
|
public function __construct(EntityRepo $entityRepo, CommentRepo $commentRepo, Comment $comment)
|
||||||
|
{
|
||||||
|
$this->entityRepo = $entityRepo;
|
||||||
|
$this->commentRepo = $commentRepo;
|
||||||
|
$this->comment = $comment;
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(Request $request, $pageId, $commentId = null)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'text' => 'required|string',
|
||||||
|
'html' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
return response('Not found', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($page->draft) {
|
||||||
|
// cannot add comments to drafts.
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => trans('errors.cannot_add_comment_to_draft'),
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->checkOwnablePermission('page-view', $page);
|
||||||
|
if (empty($commentId)) {
|
||||||
|
// create a new comment.
|
||||||
|
$this->checkPermission('comment-create-all');
|
||||||
|
$comment = $this->commentRepo->create($page, $request->only(['text', 'html', 'parent_id']));
|
||||||
|
$respMsg = trans('entities.comment_created');
|
||||||
|
} else {
|
||||||
|
// update existing comment
|
||||||
|
// get comment by ID and check if this user has permission to update.
|
||||||
|
$comment = $this->comment->findOrFail($commentId);
|
||||||
|
$this->checkOwnablePermission('comment-update', $comment);
|
||||||
|
$this->commentRepo->update($comment, $request->all());
|
||||||
|
$respMsg = trans('entities.comment_updated');
|
||||||
|
}
|
||||||
|
|
||||||
|
$comment = $this->commentRepo->getCommentById($comment->id);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => $respMsg,
|
||||||
|
'comment' => $comment
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id) {
|
||||||
|
$comment = $this->comment->findOrFail($id);
|
||||||
|
$this->checkOwnablePermission('comment-delete', $comment);
|
||||||
|
$this->commentRepo->delete($comment);
|
||||||
|
$updatedComment = $this->commentRepo->getCommentById($comment->id);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => trans('entities.comment_deleted'),
|
||||||
|
'comment' => $updatedComment
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getPageComments($pageId) {
|
||||||
|
try {
|
||||||
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
return response('Not found', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->checkOwnablePermission('page-view', $page);
|
||||||
|
|
||||||
|
$comments = $this->commentRepo->getPageComments($pageId);
|
||||||
|
return response()->json(['status' => 'success', 'comments'=> $comments['comments'],
|
||||||
|
'total' => $comments['total'], 'permissions' => [
|
||||||
|
'comment_create' => $this->currentUser->can('comment-create-all'),
|
||||||
|
'comment_update_own' => $this->currentUser->can('comment-update-own'),
|
||||||
|
'comment_update_all' => $this->currentUser->can('comment-update-all'),
|
||||||
|
'comment_delete_all' => $this->currentUser->can('comment-delete-all'),
|
||||||
|
'comment_delete_own' => $this->currentUser->can('comment-delete-own'),
|
||||||
|
], 'user_id' => $this->currentUser->id]);
|
||||||
|
}
|
||||||
|
}
|
@ -66,6 +66,10 @@ class Page extends Entity
|
|||||||
return $this->hasMany(Attachment::class, 'uploaded_to')->orderBy('order', 'asc');
|
return $this->hasMany(Attachment::class, 'uploaded_to')->orderBy('order', 'asc');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function comments() {
|
||||||
|
return $this->hasMany(Comment::class, 'page_id')->orderBy('created_on', 'asc');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the url for this page.
|
* Get the url for this page.
|
||||||
* @param string|bool $path
|
* @param string|bool $path
|
||||||
|
105
app/Repos/CommentRepo.php
Normal file
105
app/Repos/CommentRepo.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php namespace BookStack\Repos;
|
||||||
|
|
||||||
|
use BookStack\Comment;
|
||||||
|
use BookStack\Page;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TagRepo
|
||||||
|
* @package BookStack\Repos
|
||||||
|
*/
|
||||||
|
class CommentRepo {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var Comment $comment
|
||||||
|
*/
|
||||||
|
protected $comment;
|
||||||
|
|
||||||
|
public function __construct(Comment $comment)
|
||||||
|
{
|
||||||
|
$this->comment = $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create (Page $page, $data = []) {
|
||||||
|
$userId = user()->id;
|
||||||
|
$comment = $this->comment->newInstance();
|
||||||
|
$comment->fill($data);
|
||||||
|
// new comment
|
||||||
|
$comment->page_id = $page->id;
|
||||||
|
$comment->created_by = $userId;
|
||||||
|
$comment->updated_at = null;
|
||||||
|
$comment->save();
|
||||||
|
return $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($comment, $input, $activeOnly = true) {
|
||||||
|
$userId = user()->id;
|
||||||
|
$comment->updated_by = $userId;
|
||||||
|
$comment->fill($input);
|
||||||
|
|
||||||
|
// only update active comments by default.
|
||||||
|
$whereClause = ['active' => 1];
|
||||||
|
if (!$activeOnly) {
|
||||||
|
$whereClause = [];
|
||||||
|
}
|
||||||
|
$comment->update($whereClause);
|
||||||
|
return $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($comment) {
|
||||||
|
$comment->text = trans('entities.comment_deleted');
|
||||||
|
$comment->html = trans('entities.comment_deleted');
|
||||||
|
$comment->active = false;
|
||||||
|
$userId = user()->id;
|
||||||
|
$comment->updated_by = $userId;
|
||||||
|
$comment->save();
|
||||||
|
return $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageComments($pageId) {
|
||||||
|
$comments = $this->comment->getAllPageComments($pageId);
|
||||||
|
$index = [];
|
||||||
|
$totalComments = count($comments);
|
||||||
|
$finalCommentList = [];
|
||||||
|
|
||||||
|
// normalizing the response.
|
||||||
|
for ($i = 0; $i < count($comments); ++$i) {
|
||||||
|
$comment = $this->normalizeComment($comments[$i]);
|
||||||
|
$parentId = $comment->parent_id;
|
||||||
|
if (empty($parentId)) {
|
||||||
|
$finalCommentList[] = $comment;
|
||||||
|
$index[$comment->id] = $comment;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($index[$parentId])) {
|
||||||
|
// weird condition should not happen.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (empty($index[$parentId]->sub_comments)) {
|
||||||
|
$index[$parentId]->sub_comments = [];
|
||||||
|
}
|
||||||
|
array_push($index[$parentId]->sub_comments, $comment);
|
||||||
|
$index[$comment->id] = $comment;
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'comments' => $finalCommentList,
|
||||||
|
'total' => $totalComments
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommentById($commentId) {
|
||||||
|
return $this->normalizeComment($this->comment->getCommentById($commentId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeComment($comment) {
|
||||||
|
if (empty($comment)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$comment->createdBy->avatar_url = $comment->createdBy->getAvatar(50);
|
||||||
|
$comment->createdBy->profile_url = $comment->createdBy->getProfileUrl();
|
||||||
|
if (!empty($comment->updatedBy)) {
|
||||||
|
$comment->updatedBy->profile_url = $comment->updatedBy->getProfileUrl();
|
||||||
|
}
|
||||||
|
return $comment;
|
||||||
|
}
|
||||||
|
}
|
@ -571,7 +571,7 @@ class EntityRepo
|
|||||||
|
|
||||||
$draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id);
|
$draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id);
|
||||||
$draftPage->html = $this->formatHtml($input['html']);
|
$draftPage->html = $this->formatHtml($input['html']);
|
||||||
$draftPage->text = strip_tags($draftPage->html);
|
$draftPage->text = $this->pageToPlainText($draftPage);
|
||||||
$draftPage->draft = false;
|
$draftPage->draft = false;
|
||||||
$draftPage->revision_count = 1;
|
$draftPage->revision_count = 1;
|
||||||
|
|
||||||
@ -713,6 +713,17 @@ class EntityRepo
|
|||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the plain text version of a page's content.
|
||||||
|
* @param Page $page
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function pageToPlainText(Page $page)
|
||||||
|
{
|
||||||
|
$html = $this->renderPage($page);
|
||||||
|
return strip_tags($html);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a new draft page instance.
|
* Get a new draft page instance.
|
||||||
* @param Book $book
|
* @param Book $book
|
||||||
@ -816,7 +827,7 @@ class EntityRepo
|
|||||||
$userId = user()->id;
|
$userId = user()->id;
|
||||||
$page->fill($input);
|
$page->fill($input);
|
||||||
$page->html = $this->formatHtml($input['html']);
|
$page->html = $this->formatHtml($input['html']);
|
||||||
$page->text = strip_tags($page->html);
|
$page->text = $this->pageToPlainText($page);
|
||||||
if (setting('app-editor') !== 'markdown') $page->markdown = '';
|
if (setting('app-editor') !== 'markdown') $page->markdown = '';
|
||||||
$page->updated_by = $userId;
|
$page->updated_by = $userId;
|
||||||
$page->revision_count++;
|
$page->revision_count++;
|
||||||
@ -933,7 +944,7 @@ class EntityRepo
|
|||||||
$revision = $page->revisions()->where('id', '=', $revisionId)->first();
|
$revision = $page->revisions()->where('id', '=', $revisionId)->first();
|
||||||
$page->fill($revision->toArray());
|
$page->fill($revision->toArray());
|
||||||
$page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id);
|
$page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id);
|
||||||
$page->text = strip_tags($page->html);
|
$page->text = $this->pageToPlainText($page);
|
||||||
$page->updated_by = user()->id;
|
$page->updated_by = user()->id;
|
||||||
$page->save();
|
$page->save();
|
||||||
$this->searchService->indexEntity($page);
|
$this->searchService->indexEntity($page);
|
||||||
@ -953,7 +964,7 @@ class EntityRepo
|
|||||||
if ($page->draft) {
|
if ($page->draft) {
|
||||||
$page->fill($data);
|
$page->fill($data);
|
||||||
if (isset($data['html'])) {
|
if (isset($data['html'])) {
|
||||||
$page->text = strip_tags($data['html']);
|
$page->text = $this->pageToPlainText($page);
|
||||||
}
|
}
|
||||||
$page->save();
|
$page->save();
|
||||||
return $page;
|
return $page;
|
||||||
|
@ -468,7 +468,7 @@ class PermissionService
|
|||||||
$action = end($explodedPermission);
|
$action = end($explodedPermission);
|
||||||
$this->currentAction = $action;
|
$this->currentAction = $action;
|
||||||
|
|
||||||
$nonJointPermissions = ['restrictions', 'image', 'attachment'];
|
$nonJointPermissions = ['restrictions', 'image', 'attachment', 'comment'];
|
||||||
|
|
||||||
// Handle non entity specific jointPermissions
|
// Handle non entity specific jointPermissions
|
||||||
if (in_array($explodedPermission[0], $nonJointPermissions)) {
|
if (in_array($explodedPermission[0], $nonJointPermissions)) {
|
||||||
|
@ -58,7 +58,7 @@ return [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
'locale' => env('APP_LANG', 'en'),
|
'locale' => env('APP_LANG', 'en'),
|
||||||
'locales' => ['en', 'de', 'es', 'fr', 'nl', 'pt_BR', 'sk', 'ja'],
|
'locales' => ['en', 'de', 'es', 'fr', 'nl', 'pt_BR', 'sk', 'ja', 'pl'],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@ -71,3 +71,13 @@ $factory->define(BookStack\Image::class, function ($faker) {
|
|||||||
'uploaded_to' => 0
|
'uploaded_to' => 0
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$factory->define(BookStack\Comment::class, function($faker) {
|
||||||
|
$text = $faker->paragraph(3);
|
||||||
|
$html = '<p>' . $text. '</p>';
|
||||||
|
return [
|
||||||
|
'html' => $html,
|
||||||
|
'text' => $text,
|
||||||
|
'active' => 1
|
||||||
|
];
|
||||||
|
});
|
@ -1,7 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
class UpdateDbEncodingToUt8mb4 extends Migration
|
class UpdateDbEncodingToUt8mb4 extends Migration
|
||||||
@ -13,16 +11,9 @@ class UpdateDbEncodingToUt8mb4 extends Migration
|
|||||||
*/
|
*/
|
||||||
public function up()
|
public function up()
|
||||||
{
|
{
|
||||||
$database = DB::getDatabaseName();
|
// Migration removed due to issues during live migration.
|
||||||
$tables = DB::select('SHOW TABLES');
|
// Instead you can run the command `artisan bookstack:db-utf8mb4`
|
||||||
$pdo = DB::getPdo();
|
// which will generate out the SQL request to upgrade your DB to utf8mb4.
|
||||||
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
|
|
||||||
$pdo->exec('ALTER DATABASE `'.$database.'` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
|
|
||||||
$key = 'Tables_in_' . $database;
|
|
||||||
foreach ($tables as $table) {
|
|
||||||
$tableName = $table->$key;
|
|
||||||
$pdo->exec('ALTER TABLE `'.$tableName.'` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,15 +23,6 @@ class UpdateDbEncodingToUt8mb4 extends Migration
|
|||||||
*/
|
*/
|
||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
$database = DB::getDatabaseName();
|
//
|
||||||
$tables = DB::select('SHOW TABLES');
|
|
||||||
$pdo = DB::getPdo();
|
|
||||||
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
|
|
||||||
$pdo->exec('ALTER DATABASE `'.$database.'` CHARACTER SET utf8 COLLATE utf8_unicode_ci');
|
|
||||||
$key = 'Tables_in_' . $database;
|
|
||||||
foreach ($tables as $table) {
|
|
||||||
$tableName = $table->$key;
|
|
||||||
$pdo->exec('ALTER TABLE `'.$tableName.'` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateCommentsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('comments', function (Blueprint $table) {
|
||||||
|
$table->increments('id')->unsigned();
|
||||||
|
$table->integer('page_id')->unsigned();
|
||||||
|
$table->longText('text')->nullable();
|
||||||
|
$table->longText('html')->nullable();
|
||||||
|
$table->integer('parent_id')->unsigned()->nullable();
|
||||||
|
$table->integer('created_by')->unsigned();
|
||||||
|
$table->integer('updated_by')->unsigned()->nullable();
|
||||||
|
$table->boolean('active')->default(true);
|
||||||
|
|
||||||
|
$table->index(['page_id']);
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
// Assign new comment permissions to admin role
|
||||||
|
$adminRoleId = DB::table('roles')->where('system_name', '=', 'admin')->first()->id;
|
||||||
|
// Create & attach new entity permissions
|
||||||
|
$ops = ['Create All', 'Create Own', 'Update All', 'Update Own', 'Delete All', 'Delete Own'];
|
||||||
|
$entity = 'Comment';
|
||||||
|
foreach ($ops as $op) {
|
||||||
|
$permissionId = DB::table('role_permissions')->insertGetId([
|
||||||
|
'name' => strtolower($entity) . '-' . strtolower(str_replace(' ', '-', $op)),
|
||||||
|
'display_name' => $op . ' ' . $entity . 's',
|
||||||
|
'created_at' => \Carbon\Carbon::now()->toDateTimeString(),
|
||||||
|
'updated_at' => \Carbon\Carbon::now()->toDateTimeString()
|
||||||
|
]);
|
||||||
|
DB::table('permission_role')->insert([
|
||||||
|
'role_id' => $adminRoleId,
|
||||||
|
'permission_id' => $permissionId
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('comments');
|
||||||
|
// Delete comment role permissions
|
||||||
|
$ops = ['Create All', 'Create Own', 'Update All', 'Update Own', 'Delete All', 'Delete Own'];
|
||||||
|
$entity = 'Comment';
|
||||||
|
foreach ($ops as $op) {
|
||||||
|
$permName = strtolower($entity) . '-' . strtolower(str_replace(' ', '-', $op));
|
||||||
|
DB::table('role_permissions')->where('name', '=', $permName)->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,10 @@ class DummyContentSeeder extends Seeder
|
|||||||
->each(function($book) use ($user) {
|
->each(function($book) use ($user) {
|
||||||
$chapters = factory(\BookStack\Chapter::class, 5)->create(['created_by' => $user->id, 'updated_by' => $user->id])
|
$chapters = factory(\BookStack\Chapter::class, 5)->create(['created_by' => $user->id, 'updated_by' => $user->id])
|
||||||
->each(function($chapter) use ($user, $book){
|
->each(function($chapter) use ($user, $book){
|
||||||
$pages = factory(\BookStack\Page::class, 5)->make(['created_by' => $user->id, 'updated_by' => $user->id, 'book_id' => $book->id]);
|
$pages = factory(\BookStack\Page::class, 5)->create(['created_by' => $user->id, 'updated_by' => $user->id, 'book_id' => $book->id])->each(function($page) use ($user) {
|
||||||
|
$comments = factory(\BookStack\Comment::class, 3)->make(['created_by' => $user->id, 'updated_by' => $user->id, 'page_id' => $page->id]);
|
||||||
|
$page->comments()->saveMany($comments);
|
||||||
|
});
|
||||||
$chapter->pages()->saveMany($pages);
|
$chapter->pages()->saveMany($pages);
|
||||||
});
|
});
|
||||||
$pages = factory(\BookStack\Page::class, 3)->make(['created_by' => $user->id, 'updated_by' => $user->id]);
|
$pages = factory(\BookStack\Page::class, 3)->make(['created_by' => $user->id, 'updated_by' => $user->id]);
|
||||||
|
26
gulpfile.js
26
gulpfile.js
@ -1,3 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
const argv = require('yargs').argv;
|
const argv = require('yargs').argv;
|
||||||
const gulp = require('gulp'),
|
const gulp = require('gulp'),
|
||||||
plumber = require('gulp-plumber');
|
plumber = require('gulp-plumber');
|
||||||
@ -12,8 +14,10 @@ const babelify = require("babelify");
|
|||||||
const watchify = require("watchify");
|
const watchify = require("watchify");
|
||||||
const envify = require("envify");
|
const envify = require("envify");
|
||||||
const gutil = require("gulp-util");
|
const gutil = require("gulp-util");
|
||||||
|
const liveReload = require('gulp-livereload');
|
||||||
|
|
||||||
if (argv.production) process.env.NODE_ENV = 'production';
|
if (argv.production) process.env.NODE_ENV = 'production';
|
||||||
|
let isProduction = argv.production || process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
gulp.task('styles', () => {
|
gulp.task('styles', () => {
|
||||||
let chain = gulp.src(['resources/assets/sass/**/*.scss'])
|
let chain = gulp.src(['resources/assets/sass/**/*.scss'])
|
||||||
@ -24,8 +28,8 @@ gulp.task('styles', () => {
|
|||||||
}}))
|
}}))
|
||||||
.pipe(sass())
|
.pipe(sass())
|
||||||
.pipe(autoprefixer('last 2 versions'));
|
.pipe(autoprefixer('last 2 versions'));
|
||||||
if (argv.production) chain = chain.pipe(minifycss());
|
if (isProduction) chain = chain.pipe(minifycss());
|
||||||
return chain.pipe(gulp.dest('public/css/'));
|
return chain.pipe(gulp.dest('public/css/')).pipe(liveReload());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -34,21 +38,30 @@ function scriptTask(watch=false) {
|
|||||||
let props = {
|
let props = {
|
||||||
basedir: 'resources/assets/js',
|
basedir: 'resources/assets/js',
|
||||||
debug: true,
|
debug: true,
|
||||||
entries: ['global.js']
|
entries: ['global.js'],
|
||||||
|
fast: !isProduction,
|
||||||
|
cache: {},
|
||||||
|
packageCache: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
let bundler = watch ? watchify(browserify(props), { poll: true }) : browserify(props);
|
let bundler = watch ? watchify(browserify(props), { poll: true }) : browserify(props);
|
||||||
|
|
||||||
|
if (isProduction) {
|
||||||
bundler.transform(envify, {global: true}).transform(babelify, {presets: ['es2015']});
|
bundler.transform(envify, {global: true}).transform(babelify, {presets: ['es2015']});
|
||||||
|
}
|
||||||
|
|
||||||
function rebundle() {
|
function rebundle() {
|
||||||
let stream = bundler.bundle();
|
let stream = bundler.bundle();
|
||||||
stream = stream.pipe(source('common.js'));
|
stream = stream.pipe(source('common.js'));
|
||||||
if (argv.production) stream = stream.pipe(buffer()).pipe(uglify());
|
if (isProduction) stream = stream.pipe(buffer()).pipe(uglify());
|
||||||
return stream.pipe(gulp.dest('public/js/'));
|
return stream.pipe(gulp.dest('public/js/')).pipe(liveReload());
|
||||||
}
|
}
|
||||||
|
|
||||||
bundler.on('update', function() {
|
bundler.on('update', function() {
|
||||||
rebundle();
|
rebundle();
|
||||||
gutil.log('Rebundle...');
|
gutil.log('Rebundling assets...');
|
||||||
});
|
});
|
||||||
|
|
||||||
bundler.on('log', gutil.log);
|
bundler.on('log', gutil.log);
|
||||||
return rebundle();
|
return rebundle();
|
||||||
}
|
}
|
||||||
@ -57,6 +70,7 @@ gulp.task('scripts', () => {scriptTask(false)});
|
|||||||
gulp.task('scripts-watch', () => {scriptTask(true)});
|
gulp.task('scripts-watch', () => {scriptTask(true)});
|
||||||
|
|
||||||
gulp.task('default', ['styles', 'scripts-watch'], () => {
|
gulp.task('default', ['styles', 'scripts-watch'], () => {
|
||||||
|
liveReload.listen();
|
||||||
gulp.watch("resources/assets/sass/**/*.scss", ['styles']);
|
gulp.watch("resources/assets/sass/**/*.scss", ['styles']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
10
package.json
10
package.json
@ -4,7 +4,8 @@
|
|||||||
"build": "gulp build",
|
"build": "gulp build",
|
||||||
"production": "gulp build --production",
|
"production": "gulp build --production",
|
||||||
"dev": "gulp",
|
"dev": "gulp",
|
||||||
"watch": "gulp"
|
"watch": "gulp",
|
||||||
|
"permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babelify": "^7.3.0",
|
"babelify": "^7.3.0",
|
||||||
@ -13,6 +14,7 @@
|
|||||||
"gulp": "3.9.1",
|
"gulp": "3.9.1",
|
||||||
"gulp-autoprefixer": "3.1.1",
|
"gulp-autoprefixer": "3.1.1",
|
||||||
"gulp-clean-css": "^3.0.4",
|
"gulp-clean-css": "^3.0.4",
|
||||||
|
"gulp-livereload": "^3.8.1",
|
||||||
"gulp-minify-css": "1.2.4",
|
"gulp-minify-css": "1.2.4",
|
||||||
"gulp-plumber": "1.1.0",
|
"gulp-plumber": "1.1.0",
|
||||||
"gulp-sass": "3.1.0",
|
"gulp-sass": "3.1.0",
|
||||||
@ -29,15 +31,17 @@
|
|||||||
"angular-sanitize": "^1.5.5",
|
"angular-sanitize": "^1.5.5",
|
||||||
"angular-ui-sortable": "^0.17.0",
|
"angular-ui-sortable": "^0.17.0",
|
||||||
"axios": "^0.16.1",
|
"axios": "^0.16.1",
|
||||||
|
"babel-polyfill": "^6.23.0",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"clipboard": "^1.5.16",
|
"clipboard": "^1.7.1",
|
||||||
"codemirror": "^5.26.0",
|
"codemirror": "^5.26.0",
|
||||||
"dropzone": "^4.0.1",
|
"dropzone": "^4.0.1",
|
||||||
"gulp-util": "^3.0.8",
|
"gulp-util": "^3.0.8",
|
||||||
"markdown-it": "^8.3.1",
|
"markdown-it": "^8.3.1",
|
||||||
"markdown-it-task-lists": "^2.0.0",
|
"markdown-it-task-lists": "^2.0.0",
|
||||||
"moment": "^2.12.0",
|
"moment": "^2.12.0",
|
||||||
"vue": "^2.2.6"
|
"vue": "^2.2.6",
|
||||||
|
"vuedraggable": "^2.14.1"
|
||||||
},
|
},
|
||||||
"browser": {
|
"browser": {
|
||||||
"vue": "vue/dist/vue.common.js"
|
"vue": "vue/dist/vue.common.js"
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/logo.png
BIN
public/logo.png
Binary file not shown.
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 5.3 KiB |
@ -22,9 +22,12 @@ All development on BookStack is currently done on the master branch. When it's t
|
|||||||
SASS is used to help the CSS development and the JavaScript is run through browserify/babel to allow for writing ES6 code. Both of these are done using gulp. To run the build task you can use the following commands:
|
SASS is used to help the CSS development and the JavaScript is run through browserify/babel to allow for writing ES6 code. Both of these are done using gulp. To run the build task you can use the following commands:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
# Build and minify for production
|
# Build assets for development
|
||||||
npm run-script build
|
npm run-script build
|
||||||
|
|
||||||
|
# Build and minify assets for production
|
||||||
|
npm run-script production
|
||||||
|
|
||||||
# Build for dev (With sourcemaps) and watch for changes
|
# Build for dev (With sourcemaps) and watch for changes
|
||||||
npm run-script dev
|
npm run-script dev
|
||||||
```
|
```
|
||||||
@ -76,7 +79,7 @@ These are the great open-source projects used to help build BookStack:
|
|||||||
* [jQuery Sortable](https://johnny.github.io/jquery-sortable/)
|
* [jQuery Sortable](https://johnny.github.io/jquery-sortable/)
|
||||||
* [Material Design Iconic Font](http://zavoloklom.github.io/material-design-iconic-font/icons.html)
|
* [Material Design Iconic Font](http://zavoloklom.github.io/material-design-iconic-font/icons.html)
|
||||||
* [Dropzone.js](http://www.dropzonejs.com/)
|
* [Dropzone.js](http://www.dropzonejs.com/)
|
||||||
* [ZeroClipboard](http://zeroclipboard.org/)
|
* [clipboard.js](https://clipboardjs.com/)
|
||||||
* [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html)
|
* [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html)
|
||||||
* [markdown-it](https://github.com/markdown-it/markdown-it) and [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists)
|
* [markdown-it](https://github.com/markdown-it/markdown-it) and [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists)
|
||||||
* [Moment.js](http://momentjs.com/)
|
* [Moment.js](http://momentjs.com/)
|
||||||
|
53
resources/assets/js/components/back-top-top.js
Normal file
53
resources/assets/js/components/back-top-top.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
class BackToTop {
|
||||||
|
|
||||||
|
constructor(elem) {
|
||||||
|
this.elem = elem;
|
||||||
|
this.targetElem = document.getElementById('header');
|
||||||
|
this.showing = false;
|
||||||
|
this.breakPoint = 1200;
|
||||||
|
this.elem.addEventListener('click', this.scrollToTop.bind(this));
|
||||||
|
window.addEventListener('scroll', this.onPageScroll.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
onPageScroll() {
|
||||||
|
let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0;
|
||||||
|
if (!this.showing && scrollTopPos > this.breakPoint) {
|
||||||
|
this.elem.style.display = 'block';
|
||||||
|
this.showing = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.elem.style.opacity = 0.4;
|
||||||
|
}, 1);
|
||||||
|
} else if (this.showing && scrollTopPos < this.breakPoint) {
|
||||||
|
this.elem.style.opacity = 0;
|
||||||
|
this.showing = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.elem.style.display = 'none';
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToTop() {
|
||||||
|
let targetTop = this.targetElem.getBoundingClientRect().top;
|
||||||
|
let scrollElem = document.documentElement.scrollTop ? document.documentElement : document.body;
|
||||||
|
let duration = 300;
|
||||||
|
let start = Date.now();
|
||||||
|
let scrollStart = this.targetElem.getBoundingClientRect().top;
|
||||||
|
|
||||||
|
function setPos() {
|
||||||
|
let percentComplete = (1-((Date.now() - start) / duration));
|
||||||
|
let target = Math.abs(percentComplete * scrollStart);
|
||||||
|
if (percentComplete > 0) {
|
||||||
|
scrollElem.scrollTop = target;
|
||||||
|
requestAnimationFrame(setPos.bind(this));
|
||||||
|
} else {
|
||||||
|
scrollElem.scrollTop = targetTop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(setPos.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BackToTop;
|
67
resources/assets/js/components/chapter-toggle.js
Normal file
67
resources/assets/js/components/chapter-toggle.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
class ChapterToggle {
|
||||||
|
|
||||||
|
constructor(elem) {
|
||||||
|
this.elem = elem;
|
||||||
|
this.isOpen = elem.classList.contains('open');
|
||||||
|
elem.addEventListener('click', this.click.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
let list = this.elem.parentNode.querySelector('.inset-list');
|
||||||
|
|
||||||
|
this.elem.classList.add('open');
|
||||||
|
list.style.display = 'block';
|
||||||
|
list.style.height = '';
|
||||||
|
let height = list.getBoundingClientRect().height;
|
||||||
|
list.style.height = '0px';
|
||||||
|
list.style.overflow = 'hidden';
|
||||||
|
list.style.transition = 'height ease-in-out 240ms';
|
||||||
|
|
||||||
|
let transitionEndBound = onTransitionEnd.bind(this);
|
||||||
|
function onTransitionEnd() {
|
||||||
|
list.style.overflow = '';
|
||||||
|
list.style.height = '';
|
||||||
|
list.style.transition = '';
|
||||||
|
list.removeEventListener('transitionend', transitionEndBound);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
list.style.height = `${height}px`;
|
||||||
|
list.addEventListener('transitionend', transitionEndBound)
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
let list = this.elem.parentNode.querySelector('.inset-list');
|
||||||
|
|
||||||
|
this.elem.classList.remove('open');
|
||||||
|
list.style.display = 'block';
|
||||||
|
list.style.height = list.getBoundingClientRect().height + 'px';
|
||||||
|
list.style.overflow = 'hidden';
|
||||||
|
list.style.transition = 'height ease-in-out 240ms';
|
||||||
|
|
||||||
|
let transitionEndBound = onTransitionEnd.bind(this);
|
||||||
|
function onTransitionEnd() {
|
||||||
|
list.style.overflow = '';
|
||||||
|
list.style.height = '';
|
||||||
|
list.style.transition = '';
|
||||||
|
list.style.display = 'none';
|
||||||
|
list.removeEventListener('transitionend', transitionEndBound);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
list.style.height = `0px`;
|
||||||
|
list.addEventListener('transitionend', transitionEndBound)
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
click(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.isOpen ? this.close() : this.open();
|
||||||
|
this.isOpen = !this.isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ChapterToggle;
|
48
resources/assets/js/components/dropdown.js
Normal file
48
resources/assets/js/components/dropdown.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Dropdown
|
||||||
|
* Provides some simple logic to create simple dropdown menus.
|
||||||
|
*/
|
||||||
|
class DropDown {
|
||||||
|
|
||||||
|
constructor(elem) {
|
||||||
|
this.container = elem;
|
||||||
|
this.menu = elem.querySelector('ul');
|
||||||
|
this.toggle = elem.querySelector('[dropdown-toggle]');
|
||||||
|
this.setupListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.menu.style.display = 'block';
|
||||||
|
this.menu.classList.add('anim', 'menuIn');
|
||||||
|
this.container.addEventListener('mouseleave', this.hide.bind(this));
|
||||||
|
|
||||||
|
// Focus on first input if existing
|
||||||
|
let input = this.menu.querySelector('input');
|
||||||
|
if (input !== null) input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.menu.style.display = 'none';
|
||||||
|
this.menu.classList.remove('anim', 'menuIn');
|
||||||
|
}
|
||||||
|
|
||||||
|
setupListeners() {
|
||||||
|
// Hide menu on option click
|
||||||
|
this.container.addEventListener('click', event => {
|
||||||
|
let possibleChildren = Array.from(this.menu.querySelectorAll('a'));
|
||||||
|
if (possibleChildren.indexOf(event.target) !== -1) this.hide();
|
||||||
|
});
|
||||||
|
// Show dropdown on toggle click
|
||||||
|
this.toggle.addEventListener('click', this.show.bind(this));
|
||||||
|
// Hide menu on enter press
|
||||||
|
this.container.addEventListener('keypress', event => {
|
||||||
|
if (event.keyCode !== 13) return true;
|
||||||
|
event.preventDefault();
|
||||||
|
this.hide();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = DropDown;
|
65
resources/assets/js/components/expand-toggle.js
Normal file
65
resources/assets/js/components/expand-toggle.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
class ExpandToggle {
|
||||||
|
|
||||||
|
constructor(elem) {
|
||||||
|
this.elem = elem;
|
||||||
|
this.isOpen = false;
|
||||||
|
this.selector = elem.getAttribute('expand-toggle');
|
||||||
|
elem.addEventListener('click', this.click.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
open(elemToToggle) {
|
||||||
|
elemToToggle.style.display = 'block';
|
||||||
|
elemToToggle.style.height = '';
|
||||||
|
let height = elemToToggle.getBoundingClientRect().height;
|
||||||
|
elemToToggle.style.height = '0px';
|
||||||
|
elemToToggle.style.overflow = 'hidden';
|
||||||
|
elemToToggle.style.transition = 'height ease-in-out 240ms';
|
||||||
|
|
||||||
|
let transitionEndBound = onTransitionEnd.bind(this);
|
||||||
|
function onTransitionEnd() {
|
||||||
|
elemToToggle.style.overflow = '';
|
||||||
|
elemToToggle.style.height = '';
|
||||||
|
elemToToggle.style.transition = '';
|
||||||
|
elemToToggle.removeEventListener('transitionend', transitionEndBound);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
elemToToggle.style.height = `${height}px`;
|
||||||
|
elemToToggle.addEventListener('transitionend', transitionEndBound)
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(elemToToggle) {
|
||||||
|
elemToToggle.style.display = 'block';
|
||||||
|
elemToToggle.style.height = elemToToggle.getBoundingClientRect().height + 'px';
|
||||||
|
elemToToggle.style.overflow = 'hidden';
|
||||||
|
elemToToggle.style.transition = 'all ease-in-out 240ms';
|
||||||
|
|
||||||
|
let transitionEndBound = onTransitionEnd.bind(this);
|
||||||
|
function onTransitionEnd() {
|
||||||
|
elemToToggle.style.overflow = '';
|
||||||
|
elemToToggle.style.height = '';
|
||||||
|
elemToToggle.style.transition = '';
|
||||||
|
elemToToggle.style.display = 'none';
|
||||||
|
elemToToggle.removeEventListener('transitionend', transitionEndBound);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
elemToToggle.style.height = `0px`;
|
||||||
|
elemToToggle.addEventListener('transitionend', transitionEndBound)
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
click(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
let matchingElems = document.querySelectorAll(this.selector);
|
||||||
|
for (let i = 0, len = matchingElems.length; i < len; i++) {
|
||||||
|
this.isOpen ? this.close(matchingElems[i]) : this.open(matchingElems[i]);
|
||||||
|
}
|
||||||
|
this.isOpen = !this.isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ExpandToggle;
|
28
resources/assets/js/components/index.js
Normal file
28
resources/assets/js/components/index.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
let componentMapping = {
|
||||||
|
'dropdown': require('./dropdown'),
|
||||||
|
'overlay': require('./overlay'),
|
||||||
|
'back-to-top': require('./back-top-top'),
|
||||||
|
'notification': require('./notification'),
|
||||||
|
'chapter-toggle': require('./chapter-toggle'),
|
||||||
|
'expand-toggle': require('./expand-toggle'),
|
||||||
|
};
|
||||||
|
|
||||||
|
window.components = {};
|
||||||
|
|
||||||
|
let componentNames = Object.keys(componentMapping);
|
||||||
|
|
||||||
|
for (let i = 0, len = componentNames.length; i < len; i++) {
|
||||||
|
let name = componentNames[i];
|
||||||
|
let elems = document.querySelectorAll(`[${name}]`);
|
||||||
|
if (elems.length === 0) continue;
|
||||||
|
|
||||||
|
let component = componentMapping[name];
|
||||||
|
if (typeof window.components[name] === "undefined") window.components[name] = [];
|
||||||
|
for (let j = 0, jLen = elems.length; j < jLen; j++) {
|
||||||
|
let instance = new component(elems[j]);
|
||||||
|
if (typeof elems[j].components === 'undefined') elems[j].components = {};
|
||||||
|
elems[j].components[name] = instance;
|
||||||
|
window.components[name].push(instance);
|
||||||
|
}
|
||||||
|
}
|
41
resources/assets/js/components/notification.js
Normal file
41
resources/assets/js/components/notification.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
class Notification {
|
||||||
|
|
||||||
|
constructor(elem) {
|
||||||
|
this.elem = elem;
|
||||||
|
this.type = elem.getAttribute('notification');
|
||||||
|
this.textElem = elem.querySelector('span');
|
||||||
|
this.autohide = this.elem.hasAttribute('data-autohide');
|
||||||
|
window.Events.listen(this.type, text => {
|
||||||
|
this.show(text);
|
||||||
|
});
|
||||||
|
elem.addEventListener('click', this.hide.bind(this));
|
||||||
|
if (elem.hasAttribute('data-show')) this.show(this.textElem.textContent);
|
||||||
|
|
||||||
|
this.hideCleanup = this.hideCleanup.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
show(textToShow = '') {
|
||||||
|
this.elem.removeEventListener('transitionend', this.hideCleanup);
|
||||||
|
this.textElem.textContent = textToShow;
|
||||||
|
this.elem.style.display = 'block';
|
||||||
|
setTimeout(() => {
|
||||||
|
this.elem.classList.add('showing');
|
||||||
|
}, 1);
|
||||||
|
|
||||||
|
if (this.autohide) setTimeout(this.hide.bind(this), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.elem.classList.remove('showing');
|
||||||
|
this.elem.addEventListener('transitionend', this.hideCleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideCleanup() {
|
||||||
|
this.elem.style.display = 'none';
|
||||||
|
this.elem.removeEventListener('transitionend', this.hideCleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Notification;
|
39
resources/assets/js/components/overlay.js
Normal file
39
resources/assets/js/components/overlay.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
class Overlay {
|
||||||
|
|
||||||
|
constructor(elem) {
|
||||||
|
this.container = elem;
|
||||||
|
elem.addEventListener('click', event => {
|
||||||
|
if (event.target === elem) return this.hide();
|
||||||
|
});
|
||||||
|
let closeButtons = elem.querySelectorAll('.overlay-close');
|
||||||
|
for (let i=0; i < closeButtons.length; i++) {
|
||||||
|
closeButtons[i].addEventListener('click', this.hide.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(show = true) {
|
||||||
|
let start = Date.now();
|
||||||
|
let duration = 240;
|
||||||
|
|
||||||
|
function setOpacity() {
|
||||||
|
let elapsedTime = (Date.now() - start);
|
||||||
|
let targetOpacity = show ? (elapsedTime / duration) : 1-(elapsedTime / duration);
|
||||||
|
this.container.style.opacity = targetOpacity;
|
||||||
|
if (elapsedTime > duration) {
|
||||||
|
this.container.style.display = show ? 'flex' : 'none';
|
||||||
|
this.container.style.opacity = '';
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(setOpacity.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(setOpacity.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() { this.toggle(false); }
|
||||||
|
show() { this.toggle(true); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Overlay;
|
@ -8,256 +8,6 @@ moment.locale('en-gb');
|
|||||||
|
|
||||||
module.exports = function (ngApp, events) {
|
module.exports = function (ngApp, events) {
|
||||||
|
|
||||||
ngApp.controller('ImageManagerController', ['$scope', '$attrs', '$http', '$timeout', 'imageManagerService',
|
|
||||||
function ($scope, $attrs, $http, $timeout, imageManagerService) {
|
|
||||||
|
|
||||||
$scope.images = [];
|
|
||||||
$scope.imageType = $attrs.imageType;
|
|
||||||
$scope.selectedImage = false;
|
|
||||||
$scope.dependantPages = false;
|
|
||||||
$scope.showing = false;
|
|
||||||
$scope.hasMore = false;
|
|
||||||
$scope.imageUpdateSuccess = false;
|
|
||||||
$scope.imageDeleteSuccess = false;
|
|
||||||
$scope.uploadedTo = $attrs.uploadedTo;
|
|
||||||
$scope.view = 'all';
|
|
||||||
|
|
||||||
$scope.searching = false;
|
|
||||||
$scope.searchTerm = '';
|
|
||||||
|
|
||||||
let page = 0;
|
|
||||||
let previousClickTime = 0;
|
|
||||||
let previousClickImage = 0;
|
|
||||||
let dataLoaded = false;
|
|
||||||
let callback = false;
|
|
||||||
|
|
||||||
let preSearchImages = [];
|
|
||||||
let preSearchHasMore = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by dropzone to get the endpoint to upload to.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
$scope.getUploadUrl = function () {
|
|
||||||
return window.baseUrl('/images/' + $scope.imageType + '/upload');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel the current search operation.
|
|
||||||
*/
|
|
||||||
function cancelSearch() {
|
|
||||||
$scope.searching = false;
|
|
||||||
$scope.searchTerm = '';
|
|
||||||
$scope.images = preSearchImages;
|
|
||||||
$scope.hasMore = preSearchHasMore;
|
|
||||||
}
|
|
||||||
$scope.cancelSearch = cancelSearch;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on image upload, Adds an image to local list of images
|
|
||||||
* and shows a success message to the user.
|
|
||||||
* @param file
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
$scope.uploadSuccess = function (file, data) {
|
|
||||||
$scope.$apply(() => {
|
|
||||||
$scope.images.unshift(data);
|
|
||||||
});
|
|
||||||
events.emit('success', trans('components.image_upload_success'));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs the callback and hides the image manager.
|
|
||||||
* @param returnData
|
|
||||||
*/
|
|
||||||
function callbackAndHide(returnData) {
|
|
||||||
if (callback) callback(returnData);
|
|
||||||
$scope.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Image select action. Checks if a double-click was fired.
|
|
||||||
* @param image
|
|
||||||
*/
|
|
||||||
$scope.imageSelect = function (image) {
|
|
||||||
let dblClickTime = 300;
|
|
||||||
let currentTime = Date.now();
|
|
||||||
let timeDiff = currentTime - previousClickTime;
|
|
||||||
|
|
||||||
if (timeDiff < dblClickTime && image.id === previousClickImage) {
|
|
||||||
// If double click
|
|
||||||
callbackAndHide(image);
|
|
||||||
} else {
|
|
||||||
// If single
|
|
||||||
$scope.selectedImage = image;
|
|
||||||
$scope.dependantPages = false;
|
|
||||||
}
|
|
||||||
previousClickTime = currentTime;
|
|
||||||
previousClickImage = image.id;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action that runs when the 'Select image' button is clicked.
|
|
||||||
* Runs the callback and hides the image manager.
|
|
||||||
*/
|
|
||||||
$scope.selectButtonClick = function () {
|
|
||||||
callbackAndHide($scope.selectedImage);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the image manager.
|
|
||||||
* Takes a callback to execute later on.
|
|
||||||
* @param doneCallback
|
|
||||||
*/
|
|
||||||
function show(doneCallback) {
|
|
||||||
callback = doneCallback;
|
|
||||||
$scope.showing = true;
|
|
||||||
$('#image-manager').find('.overlay').css('display', 'flex').hide().fadeIn(240);
|
|
||||||
// Get initial images if they have not yet been loaded in.
|
|
||||||
if (!dataLoaded) {
|
|
||||||
fetchData();
|
|
||||||
dataLoaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connects up the image manger so it can be used externally
|
|
||||||
// such as from TinyMCE.
|
|
||||||
imageManagerService.show = show;
|
|
||||||
imageManagerService.showExternal = function (doneCallback) {
|
|
||||||
$scope.$apply(() => {
|
|
||||||
show(doneCallback);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
window.ImageManager = imageManagerService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hide the image manager
|
|
||||||
*/
|
|
||||||
$scope.hide = function () {
|
|
||||||
$scope.showing = false;
|
|
||||||
$('#image-manager').find('.overlay').fadeOut(240);
|
|
||||||
};
|
|
||||||
|
|
||||||
let baseUrl = window.baseUrl('/images/' + $scope.imageType + '/all/');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch the list image data from the server.
|
|
||||||
*/
|
|
||||||
function fetchData() {
|
|
||||||
let url = baseUrl + page + '?';
|
|
||||||
let components = {};
|
|
||||||
if ($scope.uploadedTo) components['page_id'] = $scope.uploadedTo;
|
|
||||||
if ($scope.searching) components['term'] = $scope.searchTerm;
|
|
||||||
|
|
||||||
|
|
||||||
url += Object.keys(components).map((key) => {
|
|
||||||
return key + '=' + encodeURIComponent(components[key]);
|
|
||||||
}).join('&');
|
|
||||||
|
|
||||||
$http.get(url).then((response) => {
|
|
||||||
$scope.images = $scope.images.concat(response.data.images);
|
|
||||||
$scope.hasMore = response.data.hasMore;
|
|
||||||
page++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$scope.fetchData = fetchData;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a search operation
|
|
||||||
*/
|
|
||||||
$scope.searchImages = function() {
|
|
||||||
|
|
||||||
if ($scope.searchTerm === '') {
|
|
||||||
cancelSearch();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$scope.searching) {
|
|
||||||
preSearchImages = $scope.images;
|
|
||||||
preSearchHasMore = $scope.hasMore;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.searching = true;
|
|
||||||
$scope.images = [];
|
|
||||||
$scope.hasMore = false;
|
|
||||||
page = 0;
|
|
||||||
baseUrl = window.baseUrl('/images/' + $scope.imageType + '/search/');
|
|
||||||
fetchData();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the current image listing view.
|
|
||||||
* @param viewName
|
|
||||||
*/
|
|
||||||
$scope.setView = function(viewName) {
|
|
||||||
cancelSearch();
|
|
||||||
$scope.images = [];
|
|
||||||
$scope.hasMore = false;
|
|
||||||
page = 0;
|
|
||||||
$scope.view = viewName;
|
|
||||||
baseUrl = window.baseUrl('/images/' + $scope.imageType + '/' + viewName + '/');
|
|
||||||
fetchData();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the details of an image.
|
|
||||||
* @param event
|
|
||||||
*/
|
|
||||||
$scope.saveImageDetails = function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
let url = window.baseUrl('/images/update/' + $scope.selectedImage.id);
|
|
||||||
$http.put(url, this.selectedImage).then(response => {
|
|
||||||
events.emit('success', trans('components.image_update_success'));
|
|
||||||
}, (response) => {
|
|
||||||
if (response.status === 422) {
|
|
||||||
let errors = response.data;
|
|
||||||
let message = '';
|
|
||||||
Object.keys(errors).forEach((key) => {
|
|
||||||
message += errors[key].join('\n');
|
|
||||||
});
|
|
||||||
events.emit('error', message);
|
|
||||||
} else if (response.status === 403) {
|
|
||||||
events.emit('error', response.data.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete an image from system and notify of success.
|
|
||||||
* Checks if it should force delete when an image
|
|
||||||
* has dependant pages.
|
|
||||||
* @param event
|
|
||||||
*/
|
|
||||||
$scope.deleteImage = function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
let force = $scope.dependantPages !== false;
|
|
||||||
let url = window.baseUrl('/images/' + $scope.selectedImage.id);
|
|
||||||
if (force) url += '?force=true';
|
|
||||||
$http.delete(url).then((response) => {
|
|
||||||
$scope.images.splice($scope.images.indexOf($scope.selectedImage), 1);
|
|
||||||
$scope.selectedImage = false;
|
|
||||||
events.emit('success', trans('components.image_delete_success'));
|
|
||||||
}, (response) => {
|
|
||||||
// Pages failure
|
|
||||||
if (response.status === 400) {
|
|
||||||
$scope.dependantPages = response.data;
|
|
||||||
} else if (response.status === 403) {
|
|
||||||
events.emit('error', response.data.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple date creator used to properly format dates.
|
|
||||||
* @param stringDate
|
|
||||||
* @returns {Date}
|
|
||||||
*/
|
|
||||||
$scope.getDate = function (stringDate) {
|
|
||||||
return new Date(stringDate);
|
|
||||||
};
|
|
||||||
|
|
||||||
}]);
|
|
||||||
|
|
||||||
ngApp.controller('PageEditController', ['$scope', '$http', '$attrs', '$interval', '$timeout', '$sce',
|
ngApp.controller('PageEditController', ['$scope', '$http', '$attrs', '$interval', '$timeout', '$sce',
|
||||||
function ($scope, $http, $attrs, $interval, $timeout, $sce) {
|
function ($scope, $http, $attrs, $interval, $timeout, $sce) {
|
||||||
@ -379,7 +129,7 @@ module.exports = function (ngApp, events) {
|
|||||||
*/
|
*/
|
||||||
$scope.discardDraft = function () {
|
$scope.discardDraft = function () {
|
||||||
let url = window.baseUrl('/ajax/page/' + pageId);
|
let url = window.baseUrl('/ajax/page/' + pageId);
|
||||||
$http.get(url).then((responseData) => {
|
$http.get(url).then(responseData => {
|
||||||
if (autoSave) $interval.cancel(autoSave);
|
if (autoSave) $interval.cancel(autoSave);
|
||||||
$scope.draftText = trans('entities.pages_editing_page');
|
$scope.draftText = trans('entities.pages_editing_page');
|
||||||
$scope.isUpdateDraft = false;
|
$scope.isUpdateDraft = false;
|
||||||
@ -395,284 +145,225 @@ module.exports = function (ngApp, events) {
|
|||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
ngApp.controller('PageTagController', ['$scope', '$http', '$attrs',
|
// Controller used to reply to and add new comments
|
||||||
function ($scope, $http, $attrs) {
|
ngApp.controller('CommentReplyController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
|
||||||
|
const MarkdownIt = require("markdown-it");
|
||||||
|
const md = new MarkdownIt({html: true});
|
||||||
|
let vm = this;
|
||||||
|
|
||||||
const pageId = Number($attrs.pageId);
|
vm.saveComment = function () {
|
||||||
$scope.tags = [];
|
let pageId = $scope.comment.pageId || $scope.pageId;
|
||||||
|
let comment = $scope.comment.text;
|
||||||
$scope.sortOptions = {
|
if (!comment) {
|
||||||
handle: '.handle',
|
return events.emit('warning', trans('errors.empty_comment'));
|
||||||
items: '> tr',
|
}
|
||||||
containment: "parent",
|
let commentHTML = md.render($scope.comment.text);
|
||||||
axis: "y"
|
let serviceUrl = `/ajax/page/${pageId}/comment/`;
|
||||||
|
let httpMethod = 'post';
|
||||||
|
let reqObj = {
|
||||||
|
text: comment,
|
||||||
|
html: commentHTML
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
if ($scope.isEdit === true) {
|
||||||
* Push an empty tag to the end of the scope tags.
|
// this will be set when editing the comment.
|
||||||
*/
|
serviceUrl = `/ajax/page/${pageId}/comment/${$scope.comment.id}`;
|
||||||
function addEmptyTag() {
|
httpMethod = 'put';
|
||||||
$scope.tags.push({
|
} else if ($scope.isReply === true) {
|
||||||
name: '',
|
// if its reply, get the parent comment id
|
||||||
value: ''
|
reqObj.parent_id = $scope.parentId;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
$scope.addEmptyTag = addEmptyTag;
|
$http[httpMethod](window.baseUrl(serviceUrl), reqObj).then(resp => {
|
||||||
|
if (!isCommentOpSuccess(resp)) {
|
||||||
/**
|
|
||||||
* Get all tags for the current book and add into scope.
|
|
||||||
*/
|
|
||||||
function getTags() {
|
|
||||||
let url = window.baseUrl(`/ajax/tags/get/page/${pageId}`);
|
|
||||||
$http.get(url).then((responseData) => {
|
|
||||||
$scope.tags = responseData.data;
|
|
||||||
addEmptyTag();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getTags();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the order property on all tags.
|
|
||||||
*/
|
|
||||||
function setTagOrder() {
|
|
||||||
for (let i = 0; i < $scope.tags.length; i++) {
|
|
||||||
$scope.tags[i].order = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When an tag changes check if another empty editable
|
|
||||||
* field needs to be added onto the end.
|
|
||||||
* @param tag
|
|
||||||
*/
|
|
||||||
$scope.tagChange = function(tag) {
|
|
||||||
let cPos = $scope.tags.indexOf(tag);
|
|
||||||
if (cPos !== $scope.tags.length-1) return;
|
|
||||||
|
|
||||||
if (tag.name !== '' || tag.value !== '') {
|
|
||||||
addEmptyTag();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When an tag field loses focus check the tag to see if its
|
|
||||||
* empty and therefore could be removed from the list.
|
|
||||||
* @param tag
|
|
||||||
*/
|
|
||||||
$scope.tagBlur = function(tag) {
|
|
||||||
let isLast = $scope.tags.length - 1 === $scope.tags.indexOf(tag);
|
|
||||||
if (tag.name === '' && tag.value === '' && !isLast) {
|
|
||||||
let cPos = $scope.tags.indexOf(tag);
|
|
||||||
$scope.tags.splice(cPos, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a tag from the current list.
|
|
||||||
* @param tag
|
|
||||||
*/
|
|
||||||
$scope.removeTag = function(tag) {
|
|
||||||
let cIndex = $scope.tags.indexOf(tag);
|
|
||||||
$scope.tags.splice(cIndex, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
}]);
|
|
||||||
|
|
||||||
|
|
||||||
ngApp.controller('PageAttachmentController', ['$scope', '$http', '$attrs',
|
|
||||||
function ($scope, $http, $attrs) {
|
|
||||||
|
|
||||||
const pageId = $scope.uploadedTo = $attrs.pageId;
|
|
||||||
let currentOrder = '';
|
|
||||||
$scope.files = [];
|
|
||||||
$scope.editFile = false;
|
|
||||||
$scope.file = getCleanFile();
|
|
||||||
$scope.errors = {
|
|
||||||
link: {},
|
|
||||||
edit: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
function getCleanFile() {
|
|
||||||
return {
|
|
||||||
page_id: pageId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angular-UI-Sort options
|
|
||||||
$scope.sortOptions = {
|
|
||||||
handle: '.handle',
|
|
||||||
items: '> tr',
|
|
||||||
containment: "parent",
|
|
||||||
axis: "y",
|
|
||||||
stop: sortUpdate,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event listener for sort changes.
|
|
||||||
* Updates the file ordering on the server.
|
|
||||||
* @param event
|
|
||||||
* @param ui
|
|
||||||
*/
|
|
||||||
function sortUpdate(event, ui) {
|
|
||||||
let newOrder = $scope.files.map(file => {return file.id}).join(':');
|
|
||||||
if (newOrder === currentOrder) return;
|
|
||||||
|
|
||||||
currentOrder = newOrder;
|
|
||||||
$http.put(window.baseUrl(`/attachments/sort/page/${pageId}`), {files: $scope.files}).then(resp => {
|
|
||||||
events.emit('success', resp.data.message);
|
|
||||||
}, checkError('sort'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by dropzone to get the endpoint to upload to.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
$scope.getUploadUrl = function (file) {
|
|
||||||
let suffix = (typeof file !== 'undefined') ? `/${file.id}` : '';
|
|
||||||
return window.baseUrl(`/attachments/upload${suffix}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get files for the current page from the server.
|
|
||||||
*/
|
|
||||||
function getFiles() {
|
|
||||||
let url = window.baseUrl(`/attachments/get/page/${pageId}`);
|
|
||||||
$http.get(url).then(resp => {
|
|
||||||
$scope.files = resp.data;
|
|
||||||
currentOrder = resp.data.map(file => {return file.id}).join(':');
|
|
||||||
}, checkError('get'));
|
|
||||||
}
|
|
||||||
getFiles();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on file upload, Adds an file to local file list
|
|
||||||
* and shows a success message to the user.
|
|
||||||
* @param file
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
$scope.uploadSuccess = function (file, data) {
|
|
||||||
$scope.$apply(() => {
|
|
||||||
$scope.files.push(data);
|
|
||||||
});
|
|
||||||
events.emit('success', trans('entities.attachments_file_uploaded'));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Upload and overwrite an existing file.
|
|
||||||
* @param file
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
$scope.uploadSuccessUpdate = function (file, data) {
|
|
||||||
$scope.$apply(() => {
|
|
||||||
let search = filesIndexOf(data);
|
|
||||||
if (search !== -1) $scope.files[search] = data;
|
|
||||||
|
|
||||||
if ($scope.editFile) {
|
|
||||||
$scope.editFile = angular.copy(data);
|
|
||||||
data.link = '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
events.emit('success', trans('entities.attachments_file_updated'));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a file from the server and, on success, the local listing.
|
|
||||||
* @param file
|
|
||||||
*/
|
|
||||||
$scope.deleteFile = function(file) {
|
|
||||||
if (!file.deleting) {
|
|
||||||
file.deleting = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$http.delete(window.baseUrl(`/attachments/${file.id}`)).then(resp => {
|
// hide the comments first, and then retrigger the refresh
|
||||||
events.emit('success', resp.data.message);
|
if ($scope.isEdit) {
|
||||||
$scope.files.splice($scope.files.indexOf(file), 1);
|
updateComment($scope.comment, resp.data);
|
||||||
}, checkError('delete'));
|
$scope.$emit('evt.comment-success', $scope.comment.id);
|
||||||
|
} else {
|
||||||
|
$scope.comment.text = '';
|
||||||
|
if ($scope.isReply === true && $scope.parent.sub_comments) {
|
||||||
|
$scope.parent.sub_comments.push(resp.data.comment);
|
||||||
|
} else {
|
||||||
|
$scope.$emit('evt.new-comment', resp.data.comment);
|
||||||
|
}
|
||||||
|
$scope.$emit('evt.comment-success', null, true);
|
||||||
|
}
|
||||||
|
$scope.comment.is_hidden = true;
|
||||||
|
$timeout(function() {
|
||||||
|
$scope.comment.is_hidden = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
events.emit('success', trans(resp.data.message));
|
||||||
|
|
||||||
|
}, checkError);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
function checkError(response) {
|
||||||
* Attach a link to a page.
|
let msg = null;
|
||||||
* @param file
|
if (isCommentOpSuccess(response)) {
|
||||||
*/
|
// all good
|
||||||
$scope.attachLinkSubmit = function(file) {
|
return;
|
||||||
file.uploaded_to = pageId;
|
} else if (response.data) {
|
||||||
$http.post(window.baseUrl('/attachments/link'), file).then(resp => {
|
msg = response.data.message;
|
||||||
$scope.files.push(resp.data);
|
} else {
|
||||||
events.emit('success', trans('entities.attachments_link_attached'));
|
msg = trans('errors.comment_add');
|
||||||
$scope.file = getCleanFile();
|
|
||||||
}, checkError('link'));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the edit mode for a file.
|
|
||||||
* @param file
|
|
||||||
*/
|
|
||||||
$scope.startEdit = function(file) {
|
|
||||||
$scope.editFile = angular.copy(file);
|
|
||||||
$scope.editFile.link = (file.external) ? file.path : '';
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel edit mode
|
|
||||||
*/
|
|
||||||
$scope.cancelEdit = function() {
|
|
||||||
$scope.editFile = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the name and link of a file.
|
|
||||||
* @param file
|
|
||||||
*/
|
|
||||||
$scope.updateFile = function(file) {
|
|
||||||
$http.put(window.baseUrl(`/attachments/${file.id}`), file).then(resp => {
|
|
||||||
let search = filesIndexOf(resp.data);
|
|
||||||
if (search !== -1) $scope.files[search] = resp.data;
|
|
||||||
|
|
||||||
if ($scope.editFile && !file.external) {
|
|
||||||
$scope.editFile.link = '';
|
|
||||||
}
|
}
|
||||||
$scope.editFile = false;
|
if (msg) {
|
||||||
events.emit('success', trans('entities.attachments_updated_success'));
|
events.emit('success', msg);
|
||||||
}, checkError('edit'));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the url of a file.
|
|
||||||
*/
|
|
||||||
$scope.getFileUrl = function(file) {
|
|
||||||
return window.baseUrl('/attachments/' + file.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search the local files via another file object.
|
|
||||||
* Used to search via object copies.
|
|
||||||
* @param file
|
|
||||||
* @returns int
|
|
||||||
*/
|
|
||||||
function filesIndexOf(file) {
|
|
||||||
for (let i = 0; i < $scope.files.length; i++) {
|
|
||||||
if ($scope.files[i].id == file.id) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for an error response in a ajax request.
|
|
||||||
* @param errorGroupName
|
|
||||||
*/
|
|
||||||
function checkError(errorGroupName) {
|
|
||||||
$scope.errors[errorGroupName] = {};
|
|
||||||
return function(response) {
|
|
||||||
if (typeof response.data !== 'undefined' && typeof response.data.error !== 'undefined') {
|
|
||||||
events.emit('error', response.data.error);
|
|
||||||
}
|
|
||||||
if (typeof response.data !== 'undefined' && typeof response.data.validation !== 'undefined') {
|
|
||||||
$scope.errors[errorGroupName] = response.data.validation;
|
|
||||||
console.log($scope.errors[errorGroupName])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
// Controller used to delete comments
|
||||||
|
ngApp.controller('CommentDeleteController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
|
||||||
|
let vm = this;
|
||||||
|
|
||||||
|
vm.delete = function(comment) {
|
||||||
|
$http.delete(window.baseUrl(`/ajax/comment/${comment.id}`)).then(resp => {
|
||||||
|
if (!isCommentOpSuccess(resp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateComment(comment, resp.data, $timeout, true);
|
||||||
|
}, function (resp) {
|
||||||
|
if (isCommentOpSuccess(resp)) {
|
||||||
|
events.emit('success', trans('entities.comment_deleted'));
|
||||||
|
} else {
|
||||||
|
events.emit('error', trans('error.comment_delete'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
// Controller used to fetch all comments for a page
|
||||||
|
ngApp.controller('CommentListController', ['$scope', '$http', '$timeout', '$location', function ($scope, $http, $timeout, $location) {
|
||||||
|
let vm = this;
|
||||||
|
$scope.errors = {};
|
||||||
|
// keep track of comment levels
|
||||||
|
$scope.level = 1;
|
||||||
|
vm.totalCommentsStr = trans('entities.comments_loading');
|
||||||
|
vm.permissions = {};
|
||||||
|
vm.trans = window.trans;
|
||||||
|
|
||||||
|
$scope.$on('evt.new-comment', function (event, comment) {
|
||||||
|
// add the comment to the comment list.
|
||||||
|
vm.comments.push(comment);
|
||||||
|
++vm.totalComments;
|
||||||
|
setTotalCommentMsg();
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.canEditDelete = function (comment, prop) {
|
||||||
|
if (!comment.active) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let propAll = prop + '_all';
|
||||||
|
let propOwn = prop + '_own';
|
||||||
|
|
||||||
|
if (vm.permissions[propAll]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm.permissions[propOwn] && comment.created_by.id === vm.current_user_id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.canComment = function () {
|
||||||
|
return vm.permissions.comment_create;
|
||||||
|
};
|
||||||
|
|
||||||
|
// check if there are is any direct linking
|
||||||
|
let linkedCommentId = $location.search().cm;
|
||||||
|
|
||||||
|
$timeout(function() {
|
||||||
|
$http.get(window.baseUrl(`/ajax/page/${$scope.pageId}/comments/`)).then(resp => {
|
||||||
|
if (!isCommentOpSuccess(resp)) {
|
||||||
|
// just show that no comments are available.
|
||||||
|
vm.totalComments = 0;
|
||||||
|
setTotalCommentMsg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vm.comments = resp.data.comments;
|
||||||
|
vm.totalComments = +resp.data.total;
|
||||||
|
vm.permissions = resp.data.permissions;
|
||||||
|
vm.current_user_id = resp.data.user_id;
|
||||||
|
setTotalCommentMsg();
|
||||||
|
if (!linkedCommentId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$timeout(function() {
|
||||||
|
// wait for the UI to render.
|
||||||
|
focusLinkedComment(linkedCommentId);
|
||||||
|
});
|
||||||
|
}, checkError);
|
||||||
|
});
|
||||||
|
|
||||||
|
function setTotalCommentMsg () {
|
||||||
|
if (vm.totalComments === 0) {
|
||||||
|
vm.totalCommentsStr = trans('entities.no_comments');
|
||||||
|
} else if (vm.totalComments === 1) {
|
||||||
|
vm.totalCommentsStr = trans('entities.one_comment');
|
||||||
|
} else {
|
||||||
|
vm.totalCommentsStr = trans('entities.x_comments', {
|
||||||
|
numComments: vm.totalComments
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function focusLinkedComment(linkedCommentId) {
|
||||||
|
let comment = angular.element('#' + linkedCommentId);
|
||||||
|
if (comment.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setupPageShow.goToText(linkedCommentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkError(response) {
|
||||||
|
let msg = null;
|
||||||
|
if (isCommentOpSuccess(response)) {
|
||||||
|
// all good
|
||||||
|
return;
|
||||||
|
} else if (response.data) {
|
||||||
|
msg = response.data.message;
|
||||||
|
} else {
|
||||||
|
msg = trans('errors.comment_list');
|
||||||
|
}
|
||||||
|
if (msg) {
|
||||||
|
events.emit('success', msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
function updateComment(comment, resp, $timeout, isDelete) {
|
||||||
|
comment.text = resp.comment.text;
|
||||||
|
comment.updated = resp.comment.updated;
|
||||||
|
comment.updated_by = resp.comment.updated_by;
|
||||||
|
comment.active = resp.comment.active;
|
||||||
|
if (isDelete && !resp.comment.active) {
|
||||||
|
comment.html = trans('entities.comment_deleted');
|
||||||
|
} else {
|
||||||
|
comment.html = resp.comment.html;
|
||||||
|
}
|
||||||
|
if (!$timeout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
comment.is_hidden = true;
|
||||||
|
$timeout(function() {
|
||||||
|
comment.is_hidden = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCommentOpSuccess(resp) {
|
||||||
|
if (resp && resp.data && resp.data.status === 'success') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,152 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const DropZone = require("dropzone");
|
|
||||||
const MarkdownIt = require("markdown-it");
|
const MarkdownIt = require("markdown-it");
|
||||||
const mdTasksLists = require('markdown-it-task-lists');
|
const mdTasksLists = require('markdown-it-task-lists');
|
||||||
const code = require('./code');
|
const code = require('./code');
|
||||||
|
|
||||||
module.exports = function (ngApp, events) {
|
module.exports = function (ngApp, events) {
|
||||||
|
|
||||||
/**
|
|
||||||
* Common tab controls using simple jQuery functions.
|
|
||||||
*/
|
|
||||||
ngApp.directive('tabContainer', function() {
|
|
||||||
return {
|
|
||||||
restrict: 'A',
|
|
||||||
link: function (scope, element, attrs) {
|
|
||||||
const $content = element.find('[tab-content]');
|
|
||||||
const $buttons = element.find('[tab-button]');
|
|
||||||
|
|
||||||
if (attrs.tabContainer) {
|
|
||||||
let initial = attrs.tabContainer;
|
|
||||||
$buttons.filter(`[tab-button="${initial}"]`).addClass('selected');
|
|
||||||
$content.hide().filter(`[tab-content="${initial}"]`).show();
|
|
||||||
} else {
|
|
||||||
$content.hide().first().show();
|
|
||||||
$buttons.first().addClass('selected');
|
|
||||||
}
|
|
||||||
|
|
||||||
$buttons.click(function() {
|
|
||||||
let clickedTab = $(this);
|
|
||||||
$buttons.removeClass('selected');
|
|
||||||
$content.hide();
|
|
||||||
let name = clickedTab.addClass('selected').attr('tab-button');
|
|
||||||
$content.filter(`[tab-content="${name}"]`).show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sub form component to allow inner-form sections to act like their own forms.
|
|
||||||
*/
|
|
||||||
ngApp.directive('subForm', function() {
|
|
||||||
return {
|
|
||||||
restrict: 'A',
|
|
||||||
link: function (scope, element, attrs) {
|
|
||||||
element.on('keypress', e => {
|
|
||||||
if (e.keyCode === 13) {
|
|
||||||
submitEvent(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
element.find('button[type="submit"]').click(submitEvent);
|
|
||||||
|
|
||||||
function submitEvent(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (attrs.subForm) scope.$eval(attrs.subForm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DropZone
|
|
||||||
* Used for uploading images
|
|
||||||
*/
|
|
||||||
ngApp.directive('dropZone', [function () {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
template: `
|
|
||||||
<div class="dropzone-container">
|
|
||||||
<div class="dz-message">{{message}}</div>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
scope: {
|
|
||||||
uploadUrl: '@',
|
|
||||||
eventSuccess: '=',
|
|
||||||
eventError: '=',
|
|
||||||
uploadedTo: '@',
|
|
||||||
},
|
|
||||||
link: function (scope, element, attrs) {
|
|
||||||
scope.message = attrs.message;
|
|
||||||
if (attrs.placeholder) element[0].querySelector('.dz-message').textContent = attrs.placeholder;
|
|
||||||
let dropZone = new DropZone(element[0].querySelector('.dropzone-container'), {
|
|
||||||
url: scope.uploadUrl,
|
|
||||||
init: function () {
|
|
||||||
let dz = this;
|
|
||||||
dz.on('sending', function (file, xhr, data) {
|
|
||||||
let token = window.document.querySelector('meta[name=token]').getAttribute('content');
|
|
||||||
data.append('_token', token);
|
|
||||||
let uploadedTo = typeof scope.uploadedTo === 'undefined' ? 0 : scope.uploadedTo;
|
|
||||||
data.append('uploaded_to', uploadedTo);
|
|
||||||
});
|
|
||||||
if (typeof scope.eventSuccess !== 'undefined') dz.on('success', scope.eventSuccess);
|
|
||||||
dz.on('success', function (file, data) {
|
|
||||||
$(file.previewElement).fadeOut(400, function () {
|
|
||||||
dz.removeFile(file);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (typeof scope.eventError !== 'undefined') dz.on('error', scope.eventError);
|
|
||||||
dz.on('error', function (file, errorMessage, xhr) {
|
|
||||||
console.log(errorMessage);
|
|
||||||
console.log(xhr);
|
|
||||||
function setMessage(message) {
|
|
||||||
$(file.previewElement).find('[data-dz-errormessage]').text(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xhr.status === 413) setMessage(trans('errors.server_upload_limit'));
|
|
||||||
if (errorMessage.file) setMessage(errorMessage.file[0]);
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dropdown
|
|
||||||
* Provides some simple logic to create small dropdown menus
|
|
||||||
*/
|
|
||||||
ngApp.directive('dropdown', [function () {
|
|
||||||
return {
|
|
||||||
restrict: 'A',
|
|
||||||
link: function (scope, element, attrs) {
|
|
||||||
const menu = element.find('ul');
|
|
||||||
element.find('[dropdown-toggle]').on('click', function () {
|
|
||||||
menu.show().addClass('anim menuIn');
|
|
||||||
let inputs = menu.find('input');
|
|
||||||
let hasInput = inputs.length > 0;
|
|
||||||
if (hasInput) {
|
|
||||||
inputs.first().focus();
|
|
||||||
element.on('keypress', 'input', event => {
|
|
||||||
if (event.keyCode === 13) {
|
|
||||||
event.preventDefault();
|
|
||||||
menu.hide();
|
|
||||||
menu.removeClass('anim menuIn');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
element.mouseleave(function () {
|
|
||||||
menu.hide();
|
|
||||||
menu.removeClass('anim menuIn');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TinyMCE
|
* TinyMCE
|
||||||
* An angular wrapper around the tinyMCE editor.
|
* An angular wrapper around the tinyMCE editor.
|
||||||
@ -187,30 +45,6 @@ module.exports = function (ngApp, events) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope.tinymce.extraSetups.push(tinyMceSetup);
|
scope.tinymce.extraSetups.push(tinyMceSetup);
|
||||||
|
|
||||||
// Custom tinyMCE plugins
|
|
||||||
tinymce.PluginManager.add('customhr', function (editor) {
|
|
||||||
editor.addCommand('InsertHorizontalRule', function () {
|
|
||||||
let hrElem = document.createElement('hr');
|
|
||||||
let cNode = editor.selection.getNode();
|
|
||||||
let parentNode = cNode.parentNode;
|
|
||||||
parentNode.insertBefore(hrElem, cNode);
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.addButton('hr', {
|
|
||||||
icon: 'hr',
|
|
||||||
tooltip: 'Horizontal line',
|
|
||||||
cmd: 'InsertHorizontalRule'
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.addMenuItem('hr', {
|
|
||||||
icon: 'hr',
|
|
||||||
text: 'Horizontal line',
|
|
||||||
cmd: 'InsertHorizontalRule',
|
|
||||||
context: 'insert'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
tinymce.init(scope.tinymce);
|
tinymce.init(scope.tinymce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,6 +85,21 @@ module.exports = function (ngApp, events) {
|
|||||||
extraKeys[`${metaKey}-S`] = function(cm) {scope.$emit('save-draft');};
|
extraKeys[`${metaKey}-S`] = function(cm) {scope.$emit('save-draft');};
|
||||||
// Show link selector
|
// Show link selector
|
||||||
extraKeys[`Shift-${metaKey}-K`] = function(cm) {showLinkSelector()};
|
extraKeys[`Shift-${metaKey}-K`] = function(cm) {showLinkSelector()};
|
||||||
|
// Insert Link
|
||||||
|
extraKeys[`${metaKey}-K`] = function(cm) {insertLink()};
|
||||||
|
// FormatShortcuts
|
||||||
|
extraKeys[`${metaKey}-1`] = function(cm) {replaceLineStart('##');};
|
||||||
|
extraKeys[`${metaKey}-2`] = function(cm) {replaceLineStart('###');};
|
||||||
|
extraKeys[`${metaKey}-3`] = function(cm) {replaceLineStart('####');};
|
||||||
|
extraKeys[`${metaKey}-4`] = function(cm) {replaceLineStart('#####');};
|
||||||
|
extraKeys[`${metaKey}-5`] = function(cm) {replaceLineStart('');};
|
||||||
|
extraKeys[`${metaKey}-d`] = function(cm) {replaceLineStart('');};
|
||||||
|
extraKeys[`${metaKey}-6`] = function(cm) {replaceLineStart('>');};
|
||||||
|
extraKeys[`${metaKey}-q`] = function(cm) {replaceLineStart('>');};
|
||||||
|
extraKeys[`${metaKey}-7`] = function(cm) {wrapSelection('\n```\n', '\n```');};
|
||||||
|
extraKeys[`${metaKey}-8`] = function(cm) {wrapSelection('`', '`');};
|
||||||
|
extraKeys[`Shift-${metaKey}-E`] = function(cm) {wrapSelection('`', '`');};
|
||||||
|
extraKeys[`${metaKey}-9`] = function(cm) {wrapSelection('<p class="callout info">', '</div>');};
|
||||||
cm.setOption('extraKeys', extraKeys);
|
cm.setOption('extraKeys', extraKeys);
|
||||||
|
|
||||||
// Update data on content change
|
// Update data on content change
|
||||||
@ -303,6 +152,73 @@ module.exports = function (ngApp, events) {
|
|||||||
cm.setSelections(cursor);
|
cm.setSelections(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to replace the start of the line
|
||||||
|
function replaceLineStart(newStart) {
|
||||||
|
let cursor = cm.getCursor();
|
||||||
|
let lineContent = cm.getLine(cursor.line);
|
||||||
|
let lineLen = lineContent.length;
|
||||||
|
let lineStart = lineContent.split(' ')[0];
|
||||||
|
|
||||||
|
// Remove symbol if already set
|
||||||
|
if (lineStart === newStart) {
|
||||||
|
lineContent = lineContent.replace(`${newStart} `, '');
|
||||||
|
cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
|
||||||
|
cm.setCursor({line: cursor.line, ch: cursor.ch - (newStart.length + 1)});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let alreadySymbol = /^[#>`]/.test(lineStart);
|
||||||
|
let posDif = 0;
|
||||||
|
if (alreadySymbol) {
|
||||||
|
posDif = newStart.length - lineStart.length;
|
||||||
|
lineContent = lineContent.replace(lineStart, newStart).trim();
|
||||||
|
} else if (newStart !== '') {
|
||||||
|
posDif = newStart.length + 1;
|
||||||
|
lineContent = newStart + ' ' + lineContent;
|
||||||
|
}
|
||||||
|
cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
|
||||||
|
cm.setCursor({line: cursor.line, ch: cursor.ch + posDif});
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapLine(start, end) {
|
||||||
|
let cursor = cm.getCursor();
|
||||||
|
let lineContent = cm.getLine(cursor.line);
|
||||||
|
let lineLen = lineContent.length;
|
||||||
|
let newLineContent = lineContent;
|
||||||
|
|
||||||
|
if (lineContent.indexOf(start) === 0 && lineContent.slice(-end.length) === end) {
|
||||||
|
newLineContent = lineContent.slice(start.length, lineContent.length - end.length);
|
||||||
|
} else {
|
||||||
|
newLineContent = `${start}${lineContent}${end}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
cm.replaceRange(newLineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
|
||||||
|
cm.setCursor({line: cursor.line, ch: cursor.ch + (newLineContent.length - lineLen)});
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapSelection(start, end) {
|
||||||
|
let selection = cm.getSelection();
|
||||||
|
if (selection === '') return wrapLine(start, end);
|
||||||
|
let newSelection = selection;
|
||||||
|
let frontDiff = 0;
|
||||||
|
let endDiff = 0;
|
||||||
|
|
||||||
|
if (selection.indexOf(start) === 0 && selection.slice(-end.length) === end) {
|
||||||
|
newSelection = selection.slice(start.length, selection.length - end.length);
|
||||||
|
endDiff = -(end.length + start.length);
|
||||||
|
} else {
|
||||||
|
newSelection = `${start}${selection}${end}`;
|
||||||
|
endDiff = start.length + end.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
let selections = cm.listSelections()[0];
|
||||||
|
cm.replaceSelection(newSelection);
|
||||||
|
let headFirst = selections.head.ch <= selections.anchor.ch;
|
||||||
|
selections.head.ch += headFirst ? frontDiff : endDiff;
|
||||||
|
selections.anchor.ch += headFirst ? endDiff : frontDiff;
|
||||||
|
cm.setSelections([selections]);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle image upload and add image into markdown content
|
// Handle image upload and add image into markdown content
|
||||||
function uploadImage(file) {
|
function uploadImage(file) {
|
||||||
if (file === null || file.type.indexOf('image') !== 0) return;
|
if (file === null || file.type.indexOf('image') !== 0) return;
|
||||||
@ -345,10 +261,20 @@ module.exports = function (ngApp, events) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function insertLink() {
|
||||||
|
let cursorPos = cm.getCursor('from');
|
||||||
|
let selectedText = cm.getSelection() || '';
|
||||||
|
let newText = `[${selectedText}]()`;
|
||||||
|
cm.focus();
|
||||||
|
cm.replaceSelection(newText);
|
||||||
|
let cursorPosDiff = (selectedText === '') ? -3 : -1;
|
||||||
|
cm.setCursor(cursorPos.line, cursorPos.ch + newText.length+cursorPosDiff);
|
||||||
|
}
|
||||||
|
|
||||||
// Show the image manager and handle image insertion
|
// Show the image manager and handle image insertion
|
||||||
function showImageManager() {
|
function showImageManager() {
|
||||||
let cursorPos = cm.getCursor('from');
|
let cursorPos = cm.getCursor('from');
|
||||||
window.ImageManager.showExternal(image => {
|
window.ImageManager.show(image => {
|
||||||
let selectedText = cm.getSelection();
|
let selectedText = cm.getSelection();
|
||||||
let newText = "![" + (selectedText || image.name) + "](" + image.thumbs.display + ")";
|
let newText = "![" + (selectedText || image.name) + "](" + image.thumbs.display + ")";
|
||||||
cm.focus();
|
cm.focus();
|
||||||
@ -461,188 +387,6 @@ module.exports = function (ngApp, events) {
|
|||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
/**
|
|
||||||
* Tag Autosuggestions
|
|
||||||
* Listens to child inputs and provides autosuggestions depending on field type
|
|
||||||
* and input. Suggestions provided by server.
|
|
||||||
*/
|
|
||||||
ngApp.directive('tagAutosuggestions', ['$http', function ($http) {
|
|
||||||
return {
|
|
||||||
restrict: 'A',
|
|
||||||
link: function (scope, elem, attrs) {
|
|
||||||
|
|
||||||
// Local storage for quick caching.
|
|
||||||
const localCache = {};
|
|
||||||
|
|
||||||
// Create suggestion element
|
|
||||||
const suggestionBox = document.createElement('ul');
|
|
||||||
suggestionBox.className = 'suggestion-box';
|
|
||||||
suggestionBox.style.position = 'absolute';
|
|
||||||
suggestionBox.style.display = 'none';
|
|
||||||
const $suggestionBox = $(suggestionBox);
|
|
||||||
|
|
||||||
// General state tracking
|
|
||||||
let isShowing = false;
|
|
||||||
let currentInput = false;
|
|
||||||
let active = 0;
|
|
||||||
|
|
||||||
// Listen to input events on autosuggest fields
|
|
||||||
elem.on('input focus', '[autosuggest]', function (event) {
|
|
||||||
let $input = $(this);
|
|
||||||
let val = $input.val();
|
|
||||||
let url = $input.attr('autosuggest');
|
|
||||||
let type = $input.attr('autosuggest-type');
|
|
||||||
|
|
||||||
// Add name param to request if for a value
|
|
||||||
if (type.toLowerCase() === 'value') {
|
|
||||||
let $nameInput = $input.closest('tr').find('[autosuggest-type="name"]').first();
|
|
||||||
let nameVal = $nameInput.val();
|
|
||||||
if (nameVal !== '') {
|
|
||||||
url += '?name=' + encodeURIComponent(nameVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let suggestionPromise = getSuggestions(val.slice(0, 3), url);
|
|
||||||
suggestionPromise.then(suggestions => {
|
|
||||||
if (val.length === 0) {
|
|
||||||
displaySuggestions($input, suggestions.slice(0, 6));
|
|
||||||
} else {
|
|
||||||
suggestions = suggestions.filter(item => {
|
|
||||||
return item.toLowerCase().indexOf(val.toLowerCase()) !== -1;
|
|
||||||
}).slice(0, 4);
|
|
||||||
displaySuggestions($input, suggestions);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Hide autosuggestions when input loses focus.
|
|
||||||
// Slight delay to allow clicks.
|
|
||||||
let lastFocusTime = 0;
|
|
||||||
elem.on('blur', '[autosuggest]', function (event) {
|
|
||||||
let startTime = Date.now();
|
|
||||||
setTimeout(() => {
|
|
||||||
if (lastFocusTime < startTime) {
|
|
||||||
$suggestionBox.hide();
|
|
||||||
isShowing = false;
|
|
||||||
}
|
|
||||||
}, 200)
|
|
||||||
});
|
|
||||||
elem.on('focus', '[autosuggest]', function (event) {
|
|
||||||
lastFocusTime = Date.now();
|
|
||||||
});
|
|
||||||
|
|
||||||
elem.on('keydown', '[autosuggest]', function (event) {
|
|
||||||
if (!isShowing) return;
|
|
||||||
|
|
||||||
let suggestionElems = suggestionBox.childNodes;
|
|
||||||
let suggestCount = suggestionElems.length;
|
|
||||||
|
|
||||||
// Down arrow
|
|
||||||
if (event.keyCode === 40) {
|
|
||||||
let newActive = (active === suggestCount - 1) ? 0 : active + 1;
|
|
||||||
changeActiveTo(newActive, suggestionElems);
|
|
||||||
}
|
|
||||||
// Up arrow
|
|
||||||
else if (event.keyCode === 38) {
|
|
||||||
let newActive = (active === 0) ? suggestCount - 1 : active - 1;
|
|
||||||
changeActiveTo(newActive, suggestionElems);
|
|
||||||
}
|
|
||||||
// Enter or tab key
|
|
||||||
else if ((event.keyCode === 13 || event.keyCode === 9) && !event.shiftKey) {
|
|
||||||
currentInput[0].value = suggestionElems[active].textContent;
|
|
||||||
currentInput.focus();
|
|
||||||
$suggestionBox.hide();
|
|
||||||
isShowing = false;
|
|
||||||
if (event.keyCode === 13) {
|
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Change the active suggestion to the given index
|
|
||||||
function changeActiveTo(index, suggestionElems) {
|
|
||||||
suggestionElems[active].className = '';
|
|
||||||
active = index;
|
|
||||||
suggestionElems[active].className = 'active';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display suggestions on a field
|
|
||||||
let prevSuggestions = [];
|
|
||||||
|
|
||||||
function displaySuggestions($input, suggestions) {
|
|
||||||
|
|
||||||
// Hide if no suggestions
|
|
||||||
if (suggestions.length === 0) {
|
|
||||||
$suggestionBox.hide();
|
|
||||||
isShowing = false;
|
|
||||||
prevSuggestions = suggestions;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise show and attach to input
|
|
||||||
if (!isShowing) {
|
|
||||||
$suggestionBox.show();
|
|
||||||
isShowing = true;
|
|
||||||
}
|
|
||||||
if ($input !== currentInput) {
|
|
||||||
$suggestionBox.detach();
|
|
||||||
$input.after($suggestionBox);
|
|
||||||
currentInput = $input;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return if no change
|
|
||||||
if (prevSuggestions.join() === suggestions.join()) {
|
|
||||||
prevSuggestions = suggestions;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build suggestions
|
|
||||||
$suggestionBox[0].innerHTML = '';
|
|
||||||
for (let i = 0; i < suggestions.length; i++) {
|
|
||||||
let suggestion = document.createElement('li');
|
|
||||||
suggestion.textContent = suggestions[i];
|
|
||||||
suggestion.onclick = suggestionClick;
|
|
||||||
if (i === 0) {
|
|
||||||
suggestion.className = 'active';
|
|
||||||
active = 0;
|
|
||||||
}
|
|
||||||
$suggestionBox[0].appendChild(suggestion);
|
|
||||||
}
|
|
||||||
|
|
||||||
prevSuggestions = suggestions;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Suggestion click event
|
|
||||||
function suggestionClick(event) {
|
|
||||||
currentInput[0].value = this.textContent;
|
|
||||||
currentInput.focus();
|
|
||||||
$suggestionBox.hide();
|
|
||||||
isShowing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get suggestions & cache
|
|
||||||
function getSuggestions(input, url) {
|
|
||||||
let hasQuery = url.indexOf('?') !== -1;
|
|
||||||
let searchUrl = url + (hasQuery ? '&' : '?') + 'search=' + encodeURIComponent(input);
|
|
||||||
|
|
||||||
// Get from local cache if exists
|
|
||||||
if (typeof localCache[searchUrl] !== 'undefined') {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
resolve(localCache[searchUrl]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return $http.get(searchUrl).then(response => {
|
|
||||||
localCache[searchUrl] = response.data;
|
|
||||||
return response.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
|
|
||||||
ngApp.directive('entityLinkSelector', [function($http) {
|
ngApp.directive('entityLinkSelector', [function($http) {
|
||||||
return {
|
return {
|
||||||
restrict: 'A',
|
restrict: 'A',
|
||||||
@ -678,6 +422,7 @@ module.exports = function (ngApp, events) {
|
|||||||
function hide() {
|
function hide() {
|
||||||
element.fadeOut(240);
|
element.fadeOut(240);
|
||||||
}
|
}
|
||||||
|
scope.hide = hide;
|
||||||
|
|
||||||
// Listen to confirmation of entity selections (doubleclick)
|
// Listen to confirmation of entity selections (doubleclick)
|
||||||
events.listen('entity-select-confirm', entity => {
|
events.listen('entity-select-confirm', entity => {
|
||||||
@ -789,4 +534,128 @@ module.exports = function (ngApp, events) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
ngApp.directive('commentReply', [function () {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
templateUrl: 'comment-reply.html',
|
||||||
|
scope: {
|
||||||
|
pageId: '=',
|
||||||
|
parentId: '=',
|
||||||
|
parent: '='
|
||||||
|
},
|
||||||
|
link: function (scope, element) {
|
||||||
|
scope.isReply = true;
|
||||||
|
element.find('textarea').focus();
|
||||||
|
scope.$on('evt.comment-success', function (event) {
|
||||||
|
// no need for the event to do anything more.
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
scope.closeBox();
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.closeBox = function () {
|
||||||
|
element.remove();
|
||||||
|
scope.$destroy();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
ngApp.directive('commentEdit', [function () {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
templateUrl: 'comment-reply.html',
|
||||||
|
scope: {
|
||||||
|
comment: '='
|
||||||
|
},
|
||||||
|
link: function (scope, element) {
|
||||||
|
scope.isEdit = true;
|
||||||
|
element.find('textarea').focus();
|
||||||
|
scope.$on('evt.comment-success', function (event, commentId) {
|
||||||
|
// no need for the event to do anything more.
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
if (commentId === scope.comment.id && !scope.isNew) {
|
||||||
|
scope.closeBox();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.closeBox = function () {
|
||||||
|
element.remove();
|
||||||
|
scope.$destroy();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
|
||||||
|
ngApp.directive('commentReplyLink', ['$document', '$compile', function ($document, $compile) {
|
||||||
|
return {
|
||||||
|
scope: {
|
||||||
|
comment: '='
|
||||||
|
},
|
||||||
|
link: function (scope, element, attr) {
|
||||||
|
element.on('$destroy', function () {
|
||||||
|
element.off('click');
|
||||||
|
scope.$destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
element.on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $container = element.parents('.comment-actions').first();
|
||||||
|
if (!$container.length) {
|
||||||
|
console.error('commentReplyLink directive should be placed inside a container with class comment-box!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (attr.noCommentReplyDupe) {
|
||||||
|
removeDupe();
|
||||||
|
}
|
||||||
|
|
||||||
|
compileHtml($container, scope, attr.isReply === 'true');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function compileHtml($container, scope, isReply) {
|
||||||
|
let lnkFunc = null;
|
||||||
|
if (isReply) {
|
||||||
|
lnkFunc = $compile('<comment-reply page-id="comment.pageId" parent-id="comment.id" parent="comment"></comment-reply>');
|
||||||
|
} else {
|
||||||
|
lnkFunc = $compile('<comment-edit comment="comment"></comment-add>');
|
||||||
|
}
|
||||||
|
var compiledHTML = lnkFunc(scope);
|
||||||
|
$container.append(compiledHTML);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDupe() {
|
||||||
|
let $existingElement = $document.find('.comments-list comment-reply, .comments-list comment-edit');
|
||||||
|
if (!$existingElement.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingElement.remove();
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
ngApp.directive('commentDeleteLink', ['$window', function ($window) {
|
||||||
|
return {
|
||||||
|
controller: 'CommentDeleteController',
|
||||||
|
scope: {
|
||||||
|
comment: '='
|
||||||
|
},
|
||||||
|
link: function (scope, element, attr, ctrl) {
|
||||||
|
|
||||||
|
element.on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var resp = $window.confirm(trans('entities.comment_delete_confirm'));
|
||||||
|
if (!resp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.delete(scope.comment);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
require("babel-polyfill");
|
||||||
|
|
||||||
// Url retrieval function
|
// Url retrieval function
|
||||||
window.baseUrl = function(path) {
|
window.baseUrl = function(path) {
|
||||||
@ -8,37 +9,6 @@ window.baseUrl = function(path) {
|
|||||||
return basePath + '/' + path;
|
return basePath + '/' + path;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Vue = require("vue");
|
|
||||||
const axios = require("axios");
|
|
||||||
|
|
||||||
let axiosInstance = axios.create({
|
|
||||||
headers: {
|
|
||||||
'X-CSRF-TOKEN': document.querySelector('meta[name=token]').getAttribute('content'),
|
|
||||||
'baseURL': window.baseUrl('')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.$http = axiosInstance;
|
|
||||||
|
|
||||||
Vue.prototype.$http = axiosInstance;
|
|
||||||
|
|
||||||
require("./vues/vues");
|
|
||||||
|
|
||||||
|
|
||||||
// AngularJS - Create application and load components
|
|
||||||
const angular = require("angular");
|
|
||||||
require("angular-resource");
|
|
||||||
require("angular-animate");
|
|
||||||
require("angular-sanitize");
|
|
||||||
require("angular-ui-sortable");
|
|
||||||
|
|
||||||
let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']);
|
|
||||||
|
|
||||||
// Translation setup
|
|
||||||
// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system
|
|
||||||
const Translations = require("./translations");
|
|
||||||
let translator = new Translations(window.translations);
|
|
||||||
window.trans = translator.get.bind(translator);
|
|
||||||
|
|
||||||
// Global Event System
|
// Global Event System
|
||||||
class EventManager {
|
class EventManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -63,13 +33,51 @@ class EventManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.Events = new EventManager();
|
window.Events = new EventManager();
|
||||||
|
|
||||||
|
const Vue = require("vue");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
let axiosInstance = axios.create({
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': document.querySelector('meta[name=token]').getAttribute('content'),
|
||||||
|
'baseURL': window.baseUrl('')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
axiosInstance.interceptors.request.use(resp => {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
window.$http = axiosInstance;
|
||||||
|
|
||||||
|
Vue.prototype.$http = axiosInstance;
|
||||||
Vue.prototype.$events = window.Events;
|
Vue.prototype.$events = window.Events;
|
||||||
|
|
||||||
|
|
||||||
|
// AngularJS - Create application and load components
|
||||||
|
const angular = require("angular");
|
||||||
|
require("angular-resource");
|
||||||
|
require("angular-animate");
|
||||||
|
require("angular-sanitize");
|
||||||
|
require("angular-ui-sortable");
|
||||||
|
|
||||||
|
let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']);
|
||||||
|
|
||||||
|
// Translation setup
|
||||||
|
// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system
|
||||||
|
const Translations = require("./translations");
|
||||||
|
let translator = new Translations(window.translations);
|
||||||
|
window.trans = translator.get.bind(translator);
|
||||||
|
|
||||||
|
|
||||||
|
require("./vues/vues");
|
||||||
|
require("./components");
|
||||||
|
|
||||||
// Load in angular specific items
|
// Load in angular specific items
|
||||||
const Services = require('./services');
|
|
||||||
const Directives = require('./directives');
|
const Directives = require('./directives');
|
||||||
const Controllers = require('./controllers');
|
const Controllers = require('./controllers');
|
||||||
Services(ngApp, window.Events);
|
|
||||||
Directives(ngApp, window.Events);
|
Directives(ngApp, window.Events);
|
||||||
Controllers(ngApp, window.Events);
|
Controllers(ngApp, window.Events);
|
||||||
|
|
||||||
@ -174,7 +182,7 @@ $('.overlay').click(function(event) {
|
|||||||
if(navigator.userAgent.indexOf('MSIE')!==-1
|
if(navigator.userAgent.indexOf('MSIE')!==-1
|
||||||
|| navigator.appVersion.indexOf('Trident/') > 0
|
|| navigator.appVersion.indexOf('Trident/') > 0
|
||||||
|| navigator.userAgent.indexOf('Safari') !== -1){
|
|| navigator.userAgent.indexOf('Safari') !== -1){
|
||||||
$('body').addClass('flexbox-support');
|
document.body.classList.add('flexbox-support');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Page specific items
|
// Page specific items
|
||||||
|
@ -52,14 +52,36 @@ function editorPaste(e, editor) {
|
|||||||
function registerEditorShortcuts(editor) {
|
function registerEditorShortcuts(editor) {
|
||||||
// Headers
|
// Headers
|
||||||
for (let i = 1; i < 5; i++) {
|
for (let i = 1; i < 5; i++) {
|
||||||
editor.addShortcut('meta+' + i, '', ['FormatBlock', false, 'h' + i]);
|
editor.shortcuts.add('meta+' + i, '', ['FormatBlock', false, 'h' + (i+1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other block shortcuts
|
// Other block shortcuts
|
||||||
editor.addShortcut('meta+q', '', ['FormatBlock', false, 'blockquote']);
|
editor.shortcuts.add('meta+5', '', ['FormatBlock', false, 'p']);
|
||||||
editor.addShortcut('meta+d', '', ['FormatBlock', false, 'p']);
|
editor.shortcuts.add('meta+d', '', ['FormatBlock', false, 'p']);
|
||||||
editor.addShortcut('meta+e', '', ['codeeditor', false, 'pre']);
|
editor.shortcuts.add('meta+6', '', ['FormatBlock', false, 'blockquote']);
|
||||||
editor.addShortcut('meta+shift+E', '', ['FormatBlock', false, 'code']);
|
editor.shortcuts.add('meta+q', '', ['FormatBlock', false, 'blockquote']);
|
||||||
|
editor.shortcuts.add('meta+7', '', ['codeeditor', false, 'pre']);
|
||||||
|
editor.shortcuts.add('meta+e', '', ['codeeditor', false, 'pre']);
|
||||||
|
editor.shortcuts.add('meta+8', '', ['FormatBlock', false, 'code']);
|
||||||
|
editor.shortcuts.add('meta+shift+E', '', ['FormatBlock', false, 'code']);
|
||||||
|
// Loop through callout styles
|
||||||
|
editor.shortcuts.add('meta+9', '', function() {
|
||||||
|
let selectedNode = editor.selection.getNode();
|
||||||
|
let formats = ['info', 'success', 'warning', 'danger'];
|
||||||
|
|
||||||
|
if (!selectedNode || selectedNode.className.indexOf('callout') === -1) {
|
||||||
|
editor.formatter.apply('calloutinfo');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < formats.length; i++) {
|
||||||
|
if (selectedNode.className.indexOf(formats[i]) === -1) continue;
|
||||||
|
let newFormat = (i === formats.length -1) ? formats[0] : formats[i+1];
|
||||||
|
editor.formatter.apply('callout' + newFormat);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editor.formatter.apply('p');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -120,7 +142,7 @@ function codePlugin() {
|
|||||||
$codeMirrorContainer.replaceWith($pre);
|
$codeMirrorContainer.replaceWith($pre);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.tinymce.PluginManager.add('codeeditor', (editor, url) => {
|
window.tinymce.PluginManager.add('codeeditor', function(editor, url) {
|
||||||
|
|
||||||
let $ = editor.$;
|
let $ = editor.$;
|
||||||
|
|
||||||
@ -173,7 +195,32 @@ function codePlugin() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hrPlugin() {
|
||||||
|
window.tinymce.PluginManager.add('customhr', function (editor) {
|
||||||
|
editor.addCommand('InsertHorizontalRule', function () {
|
||||||
|
let hrElem = document.createElement('hr');
|
||||||
|
let cNode = editor.selection.getNode();
|
||||||
|
let parentNode = cNode.parentNode;
|
||||||
|
parentNode.insertBefore(hrElem, cNode);
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.addButton('hr', {
|
||||||
|
icon: 'hr',
|
||||||
|
tooltip: 'Horizontal line',
|
||||||
|
cmd: 'InsertHorizontalRule'
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.addMenuItem('hr', {
|
||||||
|
icon: 'hr',
|
||||||
|
text: 'Horizontal line',
|
||||||
|
cmd: 'InsertHorizontalRule',
|
||||||
|
context: 'insert'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = function() {
|
module.exports = function() {
|
||||||
|
hrPlugin();
|
||||||
codePlugin();
|
codePlugin();
|
||||||
let settings = {
|
let settings = {
|
||||||
selector: '#html-editor',
|
selector: '#html-editor',
|
||||||
@ -207,10 +254,10 @@ module.exports = function() {
|
|||||||
{title: "Code Block", icon: "code", cmd: 'codeeditor', format: 'codeeditor'},
|
{title: "Code Block", icon: "code", cmd: 'codeeditor', format: 'codeeditor'},
|
||||||
{title: "Inline Code", icon: "code", inline: "code"},
|
{title: "Inline Code", icon: "code", inline: "code"},
|
||||||
{title: "Callouts", items: [
|
{title: "Callouts", items: [
|
||||||
{title: "Success", block: 'p', exact: true, attributes : {'class' : 'callout success'}},
|
{title: "Info", format: 'calloutinfo'},
|
||||||
{title: "Info", block: 'p', exact: true, attributes : {'class' : 'callout info'}},
|
{title: "Success", format: 'calloutsuccess'},
|
||||||
{title: "Warning", block: 'p', exact: true, attributes : {'class' : 'callout warning'}},
|
{title: "Warning", format: 'calloutwarning'},
|
||||||
{title: "Danger", block: 'p', exact: true, attributes : {'class' : 'callout danger'}}
|
{title: "Danger", format: 'calloutdanger'}
|
||||||
]},
|
]},
|
||||||
],
|
],
|
||||||
style_formats_merge: false,
|
style_formats_merge: false,
|
||||||
@ -219,6 +266,10 @@ module.exports = function() {
|
|||||||
alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
|
alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
|
||||||
aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
|
aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
|
||||||
alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
|
alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
|
||||||
|
calloutsuccess: {block: 'p', exact: true, attributes: {class: 'callout success'}},
|
||||||
|
calloutinfo: {block: 'p', exact: true, attributes: {class: 'callout info'}},
|
||||||
|
calloutwarning: {block: 'p', exact: true, attributes: {class: 'callout warning'}},
|
||||||
|
calloutdanger: {block: 'p', exact: true, attributes: {class: 'callout danger'}}
|
||||||
},
|
},
|
||||||
file_browser_callback: function (field_name, url, type, win) {
|
file_browser_callback: function (field_name, url, type, win) {
|
||||||
|
|
||||||
@ -232,7 +283,7 @@ module.exports = function() {
|
|||||||
|
|
||||||
if (type === 'image') {
|
if (type === 'image') {
|
||||||
// Show image manager
|
// Show image manager
|
||||||
window.ImageManager.showExternal(function (image) {
|
window.ImageManager.show(function (image) {
|
||||||
|
|
||||||
// Set popover link input to image url then fire change event
|
// Set popover link input to image url then fire change event
|
||||||
// to ensure the new value sticks
|
// to ensure the new value sticks
|
||||||
@ -314,7 +365,7 @@ module.exports = function() {
|
|||||||
icon: 'image',
|
icon: 'image',
|
||||||
tooltip: 'Insert an image',
|
tooltip: 'Insert an image',
|
||||||
onclick: function () {
|
onclick: function () {
|
||||||
window.ImageManager.showExternal(function (image) {
|
window.ImageManager.show(function (image) {
|
||||||
let html = `<a href="${image.url}" target="_blank">`;
|
let html = `<a href="${image.url}" target="_blank">`;
|
||||||
html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
|
html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
|
||||||
html += '</a>';
|
html += '</a>';
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
"use strict";
|
|
||||||
// Configure ZeroClipboard
|
|
||||||
const Clipboard = require("clipboard");
|
const Clipboard = require("clipboard");
|
||||||
const Code = require('../code');
|
const Code = require('../code');
|
||||||
|
|
||||||
@ -161,6 +159,8 @@ let setupPageShow = window.setupPageShow = function (pageId) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// in order to call from other places.
|
||||||
|
window.setupPageShow.goToText = goToText;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = setupPageShow;
|
module.exports = setupPageShow;
|
@ -1,12 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
module.exports = function(ngApp, events) {
|
|
||||||
|
|
||||||
ngApp.factory('imageManagerService', function() {
|
|
||||||
return {
|
|
||||||
show: false,
|
|
||||||
showExternal: false
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
138
resources/assets/js/vues/attachment-manager.js
Normal file
138
resources/assets/js/vues/attachment-manager.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
const draggable = require('vuedraggable');
|
||||||
|
const dropzone = require('./components/dropzone');
|
||||||
|
|
||||||
|
function mounted() {
|
||||||
|
this.pageId = this.$el.getAttribute('page-id');
|
||||||
|
this.file = this.newFile();
|
||||||
|
|
||||||
|
this.$http.get(window.baseUrl(`/attachments/get/page/${this.pageId}`)).then(resp => {
|
||||||
|
this.files = resp.data;
|
||||||
|
}).catch(err => {
|
||||||
|
this.checkValidationErrors('get', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
pageId: null,
|
||||||
|
files: [],
|
||||||
|
fileToEdit: null,
|
||||||
|
file: {},
|
||||||
|
tab: 'list',
|
||||||
|
editTab: 'file',
|
||||||
|
errors: {link: {}, edit: {}, delete: {}}
|
||||||
|
};
|
||||||
|
|
||||||
|
const components = {dropzone, draggable};
|
||||||
|
|
||||||
|
let methods = {
|
||||||
|
|
||||||
|
newFile() {
|
||||||
|
return {page_id: this.pageId};
|
||||||
|
},
|
||||||
|
|
||||||
|
getFileUrl(file) {
|
||||||
|
return window.baseUrl(`/attachments/${file.id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
fileSortUpdate() {
|
||||||
|
this.$http.put(window.baseUrl(`/attachments/sort/page/${this.pageId}`), {files: this.files}).then(resp => {
|
||||||
|
this.$events.emit('success', resp.data.message);
|
||||||
|
}).catch(err => {
|
||||||
|
this.checkValidationErrors('sort', err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
startEdit(file) {
|
||||||
|
this.fileToEdit = Object.assign({}, file);
|
||||||
|
this.fileToEdit.link = file.external ? file.path : '';
|
||||||
|
this.editTab = file.external ? 'link' : 'file';
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteFile(file) {
|
||||||
|
if (!file.deleting) return file.deleting = true;
|
||||||
|
|
||||||
|
this.$http.delete(window.baseUrl(`/attachments/${file.id}`)).then(resp => {
|
||||||
|
this.$events.emit('success', resp.data.message);
|
||||||
|
this.files.splice(this.files.indexOf(file), 1);
|
||||||
|
}).catch(err => {
|
||||||
|
this.checkValidationErrors('delete', err)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadSuccess(upload) {
|
||||||
|
this.files.push(upload.data);
|
||||||
|
this.$events.emit('success', trans('entities.attachments_file_uploaded'));
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadSuccessUpdate(upload) {
|
||||||
|
let fileIndex = this.filesIndex(upload.data);
|
||||||
|
if (fileIndex === -1) {
|
||||||
|
this.files.push(upload.data)
|
||||||
|
} else {
|
||||||
|
this.files.splice(fileIndex, 1, upload.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fileToEdit && this.fileToEdit.id === upload.data.id) {
|
||||||
|
this.fileToEdit = Object.assign({}, upload.data);
|
||||||
|
}
|
||||||
|
this.$events.emit('success', trans('entities.attachments_file_updated'));
|
||||||
|
},
|
||||||
|
|
||||||
|
checkValidationErrors(groupName, err) {
|
||||||
|
console.error(err);
|
||||||
|
if (typeof err.response.data === "undefined" && typeof err.response.data.validation === "undefined") return;
|
||||||
|
this.errors[groupName] = err.response.data.validation;
|
||||||
|
console.log(this.errors[groupName]);
|
||||||
|
},
|
||||||
|
|
||||||
|
getUploadUrl(file) {
|
||||||
|
let url = window.baseUrl(`/attachments/upload`);
|
||||||
|
if (typeof file !== 'undefined') url += `/${file.id}`;
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelEdit() {
|
||||||
|
this.fileToEdit = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
attachNewLink(file) {
|
||||||
|
file.uploaded_to = this.pageId;
|
||||||
|
this.$http.post(window.baseUrl('/attachments/link'), file).then(resp => {
|
||||||
|
this.files.push(resp.data);
|
||||||
|
this.file = this.newFile();
|
||||||
|
this.$events.emit('success', trans('entities.attachments_link_attached'));
|
||||||
|
}).catch(err => {
|
||||||
|
this.checkValidationErrors('link', err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateFile(file) {
|
||||||
|
$http.put(window.baseUrl(`/attachments/${file.id}`), file).then(resp => {
|
||||||
|
let search = this.filesIndex(resp.data);
|
||||||
|
if (search === -1) {
|
||||||
|
this.files.push(resp.data);
|
||||||
|
} else {
|
||||||
|
this.files.splice(search, 1, resp.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fileToEdit && !file.external) this.fileToEdit.link = '';
|
||||||
|
this.fileToEdit = false;
|
||||||
|
|
||||||
|
this.$events.emit('success', trans('entities.attachments_updated_success'));
|
||||||
|
}).catch(err => {
|
||||||
|
this.checkValidationErrors('edit', err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
filesIndex(file) {
|
||||||
|
for (let i = 0, len = this.files.length; i < len; i++) {
|
||||||
|
if (this.files[i].id === file.id) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data, methods, mounted, components,
|
||||||
|
};
|
130
resources/assets/js/vues/components/autosuggest.js
Normal file
130
resources/assets/js/vues/components/autosuggest.js
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
const template = `
|
||||||
|
<div>
|
||||||
|
<input :value="value" :autosuggest-type="type" ref="input"
|
||||||
|
:placeholder="placeholder" :name="name"
|
||||||
|
@input="inputUpdate($event.target.value)" @focus="inputUpdate($event.target.value)"
|
||||||
|
@blur="inputBlur"
|
||||||
|
@keydown="inputKeydown"
|
||||||
|
/>
|
||||||
|
<ul class="suggestion-box" v-if="showSuggestions">
|
||||||
|
<li v-for="(suggestion, i) in suggestions"
|
||||||
|
@click="selectSuggestion(suggestion)"
|
||||||
|
:class="{active: (i === active)}">{{suggestion}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
|
function data() {
|
||||||
|
return {
|
||||||
|
suggestions: [],
|
||||||
|
showSuggestions: false,
|
||||||
|
active: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const ajaxCache = {};
|
||||||
|
|
||||||
|
const props = ['url', 'type', 'value', 'placeholder', 'name'];
|
||||||
|
|
||||||
|
function getNameInputVal(valInput) {
|
||||||
|
let parentRow = valInput.parentNode.parentNode;
|
||||||
|
let nameInput = parentRow.querySelector('[autosuggest-type="name"]');
|
||||||
|
return (nameInput === null) ? '' : nameInput.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const methods = {
|
||||||
|
|
||||||
|
inputUpdate(inputValue) {
|
||||||
|
this.$emit('input', inputValue);
|
||||||
|
let params = {};
|
||||||
|
|
||||||
|
if (this.type === 'value') {
|
||||||
|
let nameVal = getNameInputVal(this.$el);
|
||||||
|
if (nameVal !== "") params.name = nameVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getSuggestions(inputValue.slice(0, 3), params).then(suggestions => {
|
||||||
|
if (inputValue.length === 0) {
|
||||||
|
this.displaySuggestions(suggestions.slice(0, 6));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Filter to suggestions containing searched term
|
||||||
|
suggestions = suggestions.filter(item => {
|
||||||
|
return item.toLowerCase().indexOf(inputValue.toLowerCase()) !== -1;
|
||||||
|
}).slice(0, 4);
|
||||||
|
this.displaySuggestions(suggestions);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
inputBlur() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$emit('blur');
|
||||||
|
this.showSuggestions = false;
|
||||||
|
}, 100);
|
||||||
|
},
|
||||||
|
|
||||||
|
inputKeydown(event) {
|
||||||
|
if (event.keyCode === 13) event.preventDefault();
|
||||||
|
if (!this.showSuggestions) return;
|
||||||
|
|
||||||
|
// Down arrow
|
||||||
|
if (event.keyCode === 40) {
|
||||||
|
this.active = (this.active === this.suggestions.length - 1) ? 0 : this.active+1;
|
||||||
|
}
|
||||||
|
// Up Arrow
|
||||||
|
else if (event.keyCode === 38) {
|
||||||
|
this.active = (this.active === 0) ? this.suggestions.length - 1 : this.active-1;
|
||||||
|
}
|
||||||
|
// Enter or tab keys
|
||||||
|
else if ((event.keyCode === 13 || event.keyCode === 9) && !event.shiftKey) {
|
||||||
|
this.selectSuggestion(this.suggestions[this.active]);
|
||||||
|
}
|
||||||
|
// Escape key
|
||||||
|
else if (event.keyCode === 27) {
|
||||||
|
this.showSuggestions = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
displaySuggestions(suggestions) {
|
||||||
|
if (suggestions.length === 0) {
|
||||||
|
this.suggestions = [];
|
||||||
|
this.showSuggestions = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.suggestions = suggestions;
|
||||||
|
this.showSuggestions = true;
|
||||||
|
this.active = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
selectSuggestion(suggestion) {
|
||||||
|
this.$refs.input.value = suggestion;
|
||||||
|
this.$refs.input.focus();
|
||||||
|
this.$emit('input', suggestion);
|
||||||
|
this.showSuggestions = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get suggestions from BookStack. Store and use local cache if already searched.
|
||||||
|
* @param {String} input
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
getSuggestions(input, params) {
|
||||||
|
params.search = input;
|
||||||
|
let cacheKey = `${this.url}:${JSON.stringify(params)}`;
|
||||||
|
|
||||||
|
if (typeof ajaxCache[cacheKey] !== "undefined") return Promise.resolve(ajaxCache[cacheKey]);
|
||||||
|
|
||||||
|
return this.$http.get(this.url, {params}).then(resp => {
|
||||||
|
ajaxCache[cacheKey] = resp.data;
|
||||||
|
return resp.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const computed = [];
|
||||||
|
|
||||||
|
module.exports = {template, data, props, methods, computed};
|
60
resources/assets/js/vues/components/dropzone.js
Normal file
60
resources/assets/js/vues/components/dropzone.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
const DropZone = require("dropzone");
|
||||||
|
|
||||||
|
const template = `
|
||||||
|
<div class="dropzone-container">
|
||||||
|
<div class="dz-message">{{placeholder}}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const props = ['placeholder', 'uploadUrl', 'uploadedTo'];
|
||||||
|
|
||||||
|
// TODO - Remove jQuery usage
|
||||||
|
function mounted() {
|
||||||
|
let container = this.$el;
|
||||||
|
let _this = this;
|
||||||
|
new DropZone(container, {
|
||||||
|
url: function() {
|
||||||
|
return _this.uploadUrl;
|
||||||
|
},
|
||||||
|
init: function () {
|
||||||
|
let dz = this;
|
||||||
|
|
||||||
|
dz.on('sending', function (file, xhr, data) {
|
||||||
|
let token = window.document.querySelector('meta[name=token]').getAttribute('content');
|
||||||
|
data.append('_token', token);
|
||||||
|
let uploadedTo = typeof _this.uploadedTo === 'undefined' ? 0 : _this.uploadedTo;
|
||||||
|
data.append('uploaded_to', uploadedTo);
|
||||||
|
});
|
||||||
|
|
||||||
|
dz.on('success', function (file, data) {
|
||||||
|
_this.$emit('success', {file, data});
|
||||||
|
$(file.previewElement).fadeOut(400, function () {
|
||||||
|
dz.removeFile(file);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dz.on('error', function (file, errorMessage, xhr) {
|
||||||
|
_this.$emit('error', {file, errorMessage, xhr});
|
||||||
|
console.log(errorMessage);
|
||||||
|
console.log(xhr);
|
||||||
|
function setMessage(message) {
|
||||||
|
$(file.previewElement).find('[data-dz-errormessage]').text(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xhr.status === 413) setMessage(trans('errors.server_upload_limit'));
|
||||||
|
if (errorMessage.file) setMessage(errorMessage.file[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function data() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
template,
|
||||||
|
props,
|
||||||
|
mounted,
|
||||||
|
data,
|
||||||
|
};
|
178
resources/assets/js/vues/image-manager.js
Normal file
178
resources/assets/js/vues/image-manager.js
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
const dropzone = require('./components/dropzone');
|
||||||
|
|
||||||
|
let page = 0;
|
||||||
|
let previousClickTime = 0;
|
||||||
|
let previousClickImage = 0;
|
||||||
|
let dataLoaded = false;
|
||||||
|
let callback = false;
|
||||||
|
let baseUrl = '';
|
||||||
|
|
||||||
|
let preSearchImages = [];
|
||||||
|
let preSearchHasMore = false;
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
images: [],
|
||||||
|
|
||||||
|
imageType: false,
|
||||||
|
uploadedTo: false,
|
||||||
|
|
||||||
|
selectedImage: false,
|
||||||
|
dependantPages: false,
|
||||||
|
showing: false,
|
||||||
|
view: 'all',
|
||||||
|
hasMore: false,
|
||||||
|
searching: false,
|
||||||
|
searchTerm: '',
|
||||||
|
|
||||||
|
imageUpdateSuccess: false,
|
||||||
|
imageDeleteSuccess: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const methods = {
|
||||||
|
|
||||||
|
show(providedCallback) {
|
||||||
|
callback = providedCallback;
|
||||||
|
this.showing = true;
|
||||||
|
this.$el.children[0].components.overlay.show();
|
||||||
|
|
||||||
|
// Get initial images if they have not yet been loaded in.
|
||||||
|
if (dataLoaded) return;
|
||||||
|
this.fetchData();
|
||||||
|
dataLoaded = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.showing = false;
|
||||||
|
this.$el.children[0].components.overlay.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchData() {
|
||||||
|
let url = baseUrl + page;
|
||||||
|
let query = {};
|
||||||
|
if (this.uploadedTo !== false) query.page_id = this.uploadedTo;
|
||||||
|
if (this.searching) query.term = this.searchTerm;
|
||||||
|
|
||||||
|
this.$http.get(url, {params: query}).then(response => {
|
||||||
|
this.images = this.images.concat(response.data.images);
|
||||||
|
this.hasMore = response.data.hasMore;
|
||||||
|
page++;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setView(viewName) {
|
||||||
|
this.cancelSearch();
|
||||||
|
this.images = [];
|
||||||
|
this.hasMore = false;
|
||||||
|
page = 0;
|
||||||
|
this.view = viewName;
|
||||||
|
baseUrl = window.baseUrl(`/images/${this.imageType}/${viewName}/`);
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
|
||||||
|
searchImages() {
|
||||||
|
if (this.searchTerm === '') return this.cancelSearch();
|
||||||
|
|
||||||
|
// Cache current settings for later
|
||||||
|
if (!this.searching) {
|
||||||
|
preSearchImages = this.images;
|
||||||
|
preSearchHasMore = this.hasMore;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.searching = true;
|
||||||
|
this.images = [];
|
||||||
|
this.hasMore = false;
|
||||||
|
page = 0;
|
||||||
|
baseUrl = window.baseUrl(`/images/${this.imageType}/search/`);
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelSearch() {
|
||||||
|
this.searching = false;
|
||||||
|
this.searchTerm = '';
|
||||||
|
this.images = preSearchImages;
|
||||||
|
this.hasMore = preSearchHasMore;
|
||||||
|
},
|
||||||
|
|
||||||
|
imageSelect(image) {
|
||||||
|
let dblClickTime = 300;
|
||||||
|
let currentTime = Date.now();
|
||||||
|
let timeDiff = currentTime - previousClickTime;
|
||||||
|
let isDblClick = timeDiff < dblClickTime && image.id === previousClickImage;
|
||||||
|
|
||||||
|
if (isDblClick) {
|
||||||
|
this.callbackAndHide(image);
|
||||||
|
} else {
|
||||||
|
this.selectedImage = image;
|
||||||
|
this.dependantPages = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
previousClickTime = currentTime;
|
||||||
|
previousClickImage = image.id;
|
||||||
|
},
|
||||||
|
|
||||||
|
callbackAndHide(imageResult) {
|
||||||
|
if (callback) callback(imageResult);
|
||||||
|
this.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
saveImageDetails() {
|
||||||
|
let url = window.baseUrl(`/images/update/${this.selectedImage.id}`);
|
||||||
|
this.$http.put(url, this.selectedImage).then(response => {
|
||||||
|
this.$events.emit('success', trans('components.image_update_success'));
|
||||||
|
}).catch(error => {
|
||||||
|
if (error.response.status === 422) {
|
||||||
|
let errors = error.response.data;
|
||||||
|
let message = '';
|
||||||
|
Object.keys(errors).forEach((key) => {
|
||||||
|
message += errors[key].join('\n');
|
||||||
|
});
|
||||||
|
this.$events.emit('error', message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteImage() {
|
||||||
|
let force = this.dependantPages !== false;
|
||||||
|
let url = window.baseUrl('/images/' + this.selectedImage.id);
|
||||||
|
if (force) url += '?force=true';
|
||||||
|
this.$http.delete(url).then(response => {
|
||||||
|
this.images.splice(this.images.indexOf(this.selectedImage), 1);
|
||||||
|
this.selectedImage = false;
|
||||||
|
this.$events.emit('success', trans('components.image_delete_success'));
|
||||||
|
}).catch(error=> {
|
||||||
|
if (error.response.status === 400) {
|
||||||
|
this.dependantPages = error.response.data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getDate(stringDate) {
|
||||||
|
return new Date(stringDate);
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadSuccess(event) {
|
||||||
|
this.images.unshift(event.data);
|
||||||
|
this.$events.emit('success', trans('components.image_upload_success'));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const computed = {
|
||||||
|
uploadUrl() {
|
||||||
|
return window.baseUrl(`/images/${this.imageType}/upload`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function mounted() {
|
||||||
|
window.ImageManager = this;
|
||||||
|
this.imageType = this.$el.getAttribute('image-type');
|
||||||
|
this.uploadedTo = this.$el.getAttribute('uploaded-to');
|
||||||
|
baseUrl = window.baseUrl('/images/' + this.imageType + '/all/')
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mounted,
|
||||||
|
methods,
|
||||||
|
data,
|
||||||
|
computed,
|
||||||
|
components: {dropzone},
|
||||||
|
};
|
@ -149,7 +149,7 @@ let methods = {
|
|||||||
|
|
||||||
updateSearch(e) {
|
updateSearch(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
window.location = '/search?term=' + encodeURIComponent(this.termString);
|
window.location = window.baseUrl('/search?term=' + encodeURIComponent(this.termString));
|
||||||
},
|
},
|
||||||
|
|
||||||
enableDate(optionName) {
|
enableDate(optionName) {
|
||||||
|
68
resources/assets/js/vues/tag-manager.js
Normal file
68
resources/assets/js/vues/tag-manager.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
const draggable = require('vuedraggable');
|
||||||
|
const autosuggest = require('./components/autosuggest');
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
pageId: false,
|
||||||
|
tags: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const components = {draggable, autosuggest};
|
||||||
|
const directives = {};
|
||||||
|
|
||||||
|
let computed = {};
|
||||||
|
|
||||||
|
let methods = {
|
||||||
|
|
||||||
|
addEmptyTag() {
|
||||||
|
this.tags.push({name: '', value: '', key: Math.random().toString(36).substring(7)});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an tag changes check if another empty editable field needs to be added onto the end.
|
||||||
|
* @param tag
|
||||||
|
*/
|
||||||
|
tagChange(tag) {
|
||||||
|
let tagPos = this.tags.indexOf(tag);
|
||||||
|
if (tagPos === this.tags.length-1 && (tag.name !== '' || tag.value !== '')) this.addEmptyTag();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an tag field loses focus check the tag to see if its
|
||||||
|
* empty and therefore could be removed from the list.
|
||||||
|
* @param tag
|
||||||
|
*/
|
||||||
|
tagBlur(tag) {
|
||||||
|
let isLast = (this.tags.indexOf(tag) === this.tags.length-1);
|
||||||
|
if (tag.name !== '' || tag.value !== '' || isLast) return;
|
||||||
|
let cPos = this.tags.indexOf(tag);
|
||||||
|
this.tags.splice(cPos, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeTag(tag) {
|
||||||
|
let tagPos = this.tags.indexOf(tag);
|
||||||
|
if (tagPos === -1) return;
|
||||||
|
this.tags.splice(tagPos, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
getTagFieldName(index, key) {
|
||||||
|
return `tags[${index}][${key}]`;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function mounted() {
|
||||||
|
this.pageId = Number(this.$el.getAttribute('page-id'));
|
||||||
|
|
||||||
|
let url = window.baseUrl(`/ajax/tags/get/page/${this.pageId}`);
|
||||||
|
this.$http.get(url).then(response => {
|
||||||
|
let tags = response.data;
|
||||||
|
for (let i = 0, len = tags.length; i < len; i++) {
|
||||||
|
tags[i].key = Math.random().toString(36).substring(7);
|
||||||
|
}
|
||||||
|
this.tags = tags;
|
||||||
|
this.addEmptyTag();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data, computed, methods, mounted, components, directives
|
||||||
|
};
|
@ -6,16 +6,19 @@ function exists(id) {
|
|||||||
|
|
||||||
let vueMapping = {
|
let vueMapping = {
|
||||||
'search-system': require('./search'),
|
'search-system': require('./search'),
|
||||||
'entity-dashboard': require('./entity-search'),
|
'entity-dashboard': require('./entity-dashboard'),
|
||||||
'code-editor': require('./code-editor')
|
'code-editor': require('./code-editor'),
|
||||||
|
'image-manager': require('./image-manager'),
|
||||||
|
'tag-manager': require('./tag-manager'),
|
||||||
|
'attachment-manager': require('./attachment-manager'),
|
||||||
};
|
};
|
||||||
|
|
||||||
window.vues = {};
|
window.vues = {};
|
||||||
|
|
||||||
Object.keys(vueMapping).forEach(id => {
|
let ids = Object.keys(vueMapping);
|
||||||
if (exists(id)) {
|
for (let i = 0, len = ids.length; i < len; i++) {
|
||||||
let config = vueMapping[id];
|
if (!exists(ids[i])) continue;
|
||||||
config.el = '#' + id;
|
let config = vueMapping[ids[i]];
|
||||||
window.vues[id] = new Vue(config);
|
config.el = '#' + ids[i];
|
||||||
|
window.vues[ids[i]] = new Vue(config);
|
||||||
}
|
}
|
||||||
});
|
|
@ -36,41 +36,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.anim.notification {
|
.anim.menuIn {
|
||||||
transform: translate3d(580px, 0, 0);
|
transform-origin: 100% 0%;
|
||||||
animation-name: notification;
|
animation-name: menuIn;
|
||||||
animation-duration: 3s;
|
animation-duration: 120ms;
|
||||||
animation-timing-function: ease-in-out;
|
animation-delay: 0s;
|
||||||
animation-fill-mode: forwards;
|
animation-timing-function: cubic-bezier(.62, .28, .23, .99);
|
||||||
&.stopped {
|
|
||||||
animation-name: notificationStopped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes notification {
|
|
||||||
0% {
|
|
||||||
transform: translate3d(580px, 0, 0);
|
|
||||||
}
|
|
||||||
10% {
|
|
||||||
transform: translate3d(0, 0, 0);
|
|
||||||
}
|
|
||||||
90% {
|
|
||||||
transform: translate3d(0, 0, 0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translate3d(580px, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes notificationStopped {
|
|
||||||
0% {
|
|
||||||
transform: translate3d(580px, 0, 0);
|
|
||||||
}
|
|
||||||
10% {
|
|
||||||
transform: translate3d(0, 0, 0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translate3d(0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes menuIn {
|
@keyframes menuIn {
|
||||||
@ -85,14 +56,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.anim.menuIn {
|
|
||||||
transform-origin: 100% 0%;
|
|
||||||
animation-name: menuIn;
|
|
||||||
animation-duration: 120ms;
|
|
||||||
animation-delay: 0s;
|
|
||||||
animation-timing-function: cubic-bezier(.62, .28, .23, .99);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loadingBob {
|
@keyframes loadingBob {
|
||||||
0% {
|
0% {
|
||||||
transform: translate3d(0, 0, 0);
|
transform: translate3d(0, 0, 0);
|
||||||
|
@ -134,8 +134,7 @@
|
|||||||
.callout {
|
.callout {
|
||||||
border-left: 3px solid #BBB;
|
border-left: 3px solid #BBB;
|
||||||
background-color: #EEE;
|
background-color: #EEE;
|
||||||
padding: $-s;
|
padding: $-s $-s $-s $-xl;
|
||||||
padding-left: $-xl;
|
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
&:before {
|
&:before {
|
||||||
|
@ -31,7 +31,6 @@ $button-border-radius: 2px;
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: none;
|
border: none;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-family: $text;
|
|
||||||
outline: 0;
|
outline: 0;
|
||||||
border-radius: $button-border-radius;
|
border-radius: $button-border-radius;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -65,6 +64,7 @@ $button-border-radius: 2px;
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: none;
|
border: none;
|
||||||
|
user-select: none;
|
||||||
&:focus, &:active {
|
&:focus, &:active {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
.CodeMirror {
|
.CodeMirror {
|
||||||
/* Set height, width, borders, and global font properties here */
|
/* Set height, width, borders, and global font properties here */
|
||||||
font-family: monospace;
|
|
||||||
height: 300px;
|
height: 300px;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
@ -235,7 +234,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
|||||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
|
82
resources/assets/sass/_comments.scss
Normal file
82
resources/assets/sass/_comments.scss
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
.comments-list {
|
||||||
|
.comment-box {
|
||||||
|
border-bottom: 1px solid $comment-border;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-box:last-child {
|
||||||
|
border-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.page-comment {
|
||||||
|
.comment-container {
|
||||||
|
margin-left: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-actions {
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-left: 0px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
float: left;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:after {
|
||||||
|
content: '•';
|
||||||
|
color: #707070;
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:last-child:after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-actions {
|
||||||
|
border-bottom: 1px solid #DDD;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-actions:last-child {
|
||||||
|
border-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-header {
|
||||||
|
font-size: 1.25em;
|
||||||
|
margin-top: 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-body p {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-inactive {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 0.85em;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-image {
|
||||||
|
float: left;
|
||||||
|
margin-right: 10px;
|
||||||
|
width: 32px;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-editor {
|
||||||
|
margin-top: 2em;
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-height: 120px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,65 @@
|
|||||||
.overlay {
|
// System wide notifications
|
||||||
|
[notification] {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: $-xl*2 $-xl;
|
||||||
|
padding: $-l $-xl;
|
||||||
|
background-color: #EEE;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: $bs-med;
|
||||||
|
z-index: 999999;
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
max-width: 480px;
|
||||||
|
transition: transform ease-in-out 360ms;
|
||||||
|
transform: translate3d(580px, 0, 0);
|
||||||
|
i, span {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
font-size: 2em;
|
||||||
|
padding-right: $-l;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
&.pos {
|
||||||
|
background-color: $positive;
|
||||||
|
color: #EEE;
|
||||||
|
}
|
||||||
|
&.neg {
|
||||||
|
background-color: $negative;
|
||||||
|
color: #EEE;
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
background-color: $secondary;
|
||||||
|
color: #EEE;
|
||||||
|
}
|
||||||
|
&.showing {
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[chapter-toggle] {
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0;
|
||||||
|
transition: all ease-in-out 180ms;
|
||||||
|
user-select: none;
|
||||||
|
i.zmdi-caret-right {
|
||||||
|
transition: all ease-in-out 180ms;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
transform-origin: 25% 50%;
|
||||||
|
}
|
||||||
|
&.open {
|
||||||
|
//margin-bottom: 0;
|
||||||
|
}
|
||||||
|
&.open i.zmdi-caret-right {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay] {
|
||||||
background-color: rgba(0, 0, 0, 0.333);
|
background-color: rgba(0, 0, 0, 0.333);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 95536;
|
z-index: 95536;
|
||||||
@ -451,7 +512,7 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[tab-container] .nav-tabs {
|
.tab-container .nav-tabs {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #DDD;
|
||||||
margin-bottom: $-m;
|
margin-bottom: $-m;
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
// Generated using https://google-webfonts-helper.herokuapp.com
|
|
||||||
|
|
||||||
/* roboto-100 - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100;
|
|
||||||
src: local('Roboto Thin'), local('Roboto-Thin'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-100.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-100.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-100italic - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 100;
|
|
||||||
src: local('Roboto Thin Italic'), local('Roboto-ThinItalic'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-100italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-100italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-300 - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: local('Roboto Light'), local('Roboto-Light'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-300italic - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
src: local('Roboto Light Italic'), local('Roboto-LightItalic'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-300italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-300italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-regular - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Roboto'), local('Roboto-Regular'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-italic - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Roboto Italic'), local('Roboto-Italic'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-500 - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-500italic - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 500;
|
|
||||||
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-500italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-500italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-700 - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
/* roboto-700italic - cyrillic_latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Roboto Bold Italic'), local('Roboto-BoldItalic'),
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-v15-cyrillic_latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* roboto-mono-regular - latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Roboto Mono'), local('RobotoMono-Regular'),
|
|
||||||
url('../fonts/roboto-mono-v4-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
|
|
||||||
url('../fonts/roboto-mono-v4-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
||||||
}
|
|
@ -5,7 +5,6 @@
|
|||||||
border: 1px solid #CCC;
|
border: 1px solid #CCC;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: $fs-s;
|
font-size: $fs-s;
|
||||||
font-family: $text;
|
|
||||||
padding: $-xs;
|
padding: $-xs;
|
||||||
color: #222;
|
color: #222;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
@ -33,7 +32,6 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
#markdown-editor-input {
|
#markdown-editor-input {
|
||||||
font-family: 'Roboto Mono', monospace;
|
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
padding: $-xs $-m;
|
padding: $-xs $-m;
|
||||||
@ -69,7 +67,6 @@
|
|||||||
.editor-toolbar {
|
.editor-toolbar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: $-xs $-m;
|
padding: $-xs $-m;
|
||||||
font-family: 'Roboto Mono', monospace;
|
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #DDD;
|
||||||
@ -251,21 +248,20 @@ div[editor-type="markdown"] .title-input.page-title input[type="text"] {
|
|||||||
border: none;
|
border: none;
|
||||||
color: $primary;
|
color: $primary;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-left: $-s;
|
position: absolute;
|
||||||
}
|
left: 7px;
|
||||||
button[type="submit"] {
|
top: 7px;
|
||||||
margin-left: -$-l;
|
|
||||||
}
|
}
|
||||||
input {
|
input {
|
||||||
padding-right: $-l;
|
display: block;
|
||||||
|
padding-left: $-l;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input.outline {
|
.outline > input {
|
||||||
border: 0;
|
border: 0;
|
||||||
border-bottom: 2px solid #DDD;
|
border-bottom: 2px solid #DDD;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
@ -12,7 +12,6 @@ header {
|
|||||||
padding: $-m;
|
padding: $-m;
|
||||||
}
|
}
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #DDD;
|
||||||
//margin-bottom: $-l;
|
|
||||||
.links {
|
.links {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
@ -23,26 +22,27 @@ header {
|
|||||||
}
|
}
|
||||||
.links a {
|
.links a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: $-l;
|
padding: $-m $-l;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
&:last-child {
|
&:last-child {
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
@include smaller-than($screen-md) {
|
@include smaller-than($screen-md) {
|
||||||
padding: $-l $-s;
|
padding: $-m $-s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.avatar, .user-name {
|
.avatar, .user-name {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
.avatar {
|
.avatar {
|
||||||
//margin-top: (45px/2);
|
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
.user-name {
|
.user-name {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding-top: $-l;
|
padding-top: $-m;
|
||||||
|
position: relative;
|
||||||
|
top: -3px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
> * {
|
> * {
|
||||||
@ -66,53 +66,57 @@ header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@include smaller-than($screen-md) {
|
@include smaller-than($screen-sm) {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
.float.right {
|
.float.right {
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@include smaller-than($screen-sm) {
|
|
||||||
.links a {
|
.links a {
|
||||||
padding: $-s;
|
padding: $-s;
|
||||||
}
|
}
|
||||||
form.search-box {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
.user-name {
|
.user-name {
|
||||||
padding-top: $-s;
|
padding-top: $-s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.dropdown-container {
|
}
|
||||||
font-size: 0.9em;
|
|
||||||
|
.header-search {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
header .search-box {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: $-s;
|
||||||
|
input {
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
color: #EEE;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
color: #EEE;
|
||||||
|
}
|
||||||
|
::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
||||||
|
color: #DDD;
|
||||||
|
}
|
||||||
|
::-moz-placeholder { /* Firefox 19+ */
|
||||||
|
color: #DDD;
|
||||||
|
}
|
||||||
|
:-ms-input-placeholder { /* IE 10+ */
|
||||||
|
color: #DDD;
|
||||||
|
}
|
||||||
|
:-moz-placeholder { /* Firefox 18- */
|
||||||
|
color: #DDD;
|
||||||
|
}
|
||||||
|
@include smaller-than($screen-lg) {
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
@include smaller-than($l) {
|
||||||
|
max-width: 200px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
form.search-box {
|
@include smaller-than($s) {
|
||||||
margin-top: $-l *0.9;
|
.header-search {
|
||||||
display: inline-block;
|
display: block;
|
||||||
position: relative;
|
|
||||||
text-align: left;
|
|
||||||
input {
|
|
||||||
background-color: transparent;
|
|
||||||
border-radius: 24px;
|
|
||||||
border: 2px solid #EEE;
|
|
||||||
color: #EEE;
|
|
||||||
padding-left: $-m;
|
|
||||||
padding-right: $-l;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
vertical-align: top;
|
|
||||||
margin-left: -$-l;
|
|
||||||
color: #FFF;
|
|
||||||
top: 6px;
|
|
||||||
right: 4px;
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
&:hover {
|
|
||||||
color: #FFF;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,12 +132,12 @@ form.search-box {
|
|||||||
font-size: 1.8em;
|
font-size: 1.8em;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
padding: $-l $-l $-l 0;
|
padding: 14px $-l 14px 0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
.logo-image {
|
.logo-image {
|
||||||
margin: $-m $-s $-m 0;
|
margin: $-xs $-s $-xs 0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
height: 43px;
|
height: 43px;
|
||||||
}
|
}
|
||||||
@ -142,7 +146,6 @@ form.search-box {
|
|||||||
color: #aaa;
|
color: #aaa;
|
||||||
padding: 0 $-xs;
|
padding: 0 $-xs;
|
||||||
}
|
}
|
||||||
|
|
||||||
.faded {
|
.faded {
|
||||||
a, button, span, span > div {
|
a, button, span, span > div {
|
||||||
color: #666;
|
color: #666;
|
||||||
@ -178,6 +181,8 @@ form.search-box {
|
|||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.action-buttons .dropdown-container:last-child a {
|
.action-buttons .dropdown-container:last-child a {
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
padding-left: $-s;
|
padding-left: $-s;
|
||||||
@ -196,6 +201,25 @@ form.search-box {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include smaller-than($m) {
|
||||||
|
.breadcrumbs .text-button, .action-buttons .text-button {
|
||||||
|
padding: $-s $-xs;
|
||||||
|
}
|
||||||
|
.action-buttons .dropdown-container:last-child a {
|
||||||
|
padding-left: $-xs;
|
||||||
|
}
|
||||||
|
.breadcrumbs .text-button {
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
.breadcrumbs a i {
|
||||||
|
font-size: $fs-m;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
.breadcrumbs span.sep {
|
||||||
|
padding: 0 $-xxs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.nav-tabs {
|
.nav-tabs {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
a, .tab-item {
|
a, .tab-item {
|
||||||
@ -208,3 +232,6 @@ form.search-box {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.faded-small .nav-tabs a {
|
||||||
|
padding: $-s $-m;
|
||||||
|
}
|
@ -12,7 +12,6 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: $text;
|
|
||||||
font-size: $fs-m;
|
font-size: $fs-m;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: #616161;
|
color: #616161;
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
.inset-list {
|
.inset-list {
|
||||||
display: none;
|
display: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-bottom: $-l;
|
|
||||||
}
|
}
|
||||||
h5 {
|
h5 {
|
||||||
display: block;
|
display: block;
|
||||||
@ -22,6 +21,9 @@
|
|||||||
border-left-color: $color-page-draft;
|
border-left-color: $color-page-draft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.entity-list-item {
|
||||||
|
margin-bottom: $-m;
|
||||||
|
}
|
||||||
hr {
|
hr {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
@ -51,23 +53,6 @@
|
|||||||
margin-right: $-s;
|
margin-right: $-s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.chapter-toggle {
|
|
||||||
cursor: pointer;
|
|
||||||
margin: 0 0 $-l 0;
|
|
||||||
transition: all ease-in-out 180ms;
|
|
||||||
user-select: none;
|
|
||||||
i.zmdi-caret-right {
|
|
||||||
transition: all ease-in-out 180ms;
|
|
||||||
transform: rotate(0deg);
|
|
||||||
transform-origin: 25% 50%;
|
|
||||||
}
|
|
||||||
&.open {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
&.open i.zmdi-caret-right {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-page-nav {
|
.sidebar-page-nav {
|
||||||
$nav-indent: $-s;
|
$nav-indent: $-s;
|
||||||
@ -171,7 +156,7 @@
|
|||||||
background-color: rgba($color-chapter, 0.12);
|
background-color: rgba($color-chapter, 0.12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.chapter-toggle {
|
[chapter-toggle] {
|
||||||
padding-left: $-s;
|
padding-left: $-s;
|
||||||
}
|
}
|
||||||
.list-item-chapter {
|
.list-item-chapter {
|
||||||
@ -336,8 +321,10 @@ ul.pagination {
|
|||||||
h4, a {
|
h4, a {
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
p {
|
.entity-item-snippet {
|
||||||
display: none;
|
display: none;
|
||||||
|
}
|
||||||
|
p {
|
||||||
font-size: $fs-m * 0.8;
|
font-size: $fs-m * 0.8;
|
||||||
padding-top: $-xs;
|
padding-top: $-xs;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -226,7 +226,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
}
|
}
|
||||||
.tags td {
|
.tags td, .tag-table > div > div > div {
|
||||||
padding-right: $-s;
|
padding-right: $-s;
|
||||||
padding-top: $-s;
|
padding-top: $-s;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -311,3 +311,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-editor .CodeMirror, .comment-editor .CodeMirror-scroll {
|
||||||
|
min-height: 175px;
|
||||||
|
}
|
@ -59,12 +59,16 @@ table.list-table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table.file-table {
|
.fake-table {
|
||||||
@extend .no-style;
|
|
||||||
td {
|
|
||||||
padding: $-xs;
|
|
||||||
}
|
|
||||||
.ui-sortable-helper {
|
|
||||||
display: table;
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
> div {
|
||||||
|
display: table-row-group;
|
||||||
|
}
|
||||||
|
> div > div {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
> div > div > div {
|
||||||
|
display: table-cell;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Fonts
|
||||||
|
*/
|
||||||
|
|
||||||
|
body, button, input, select, label {
|
||||||
|
font-family: $text;
|
||||||
|
}
|
||||||
|
.Codemirror, pre, #markdown-editor-input, .editor-toolbar, .code-base {
|
||||||
|
font-family: $mono;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Header Styles
|
* Header Styles
|
||||||
*/
|
*/
|
||||||
@ -58,7 +69,6 @@ a, .link {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: color ease-in-out 80ms;
|
transition: color ease-in-out 80ms;
|
||||||
font-family: $text;
|
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@ -131,7 +141,6 @@ sub, .subscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
font-family: monospace;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
border: 1px solid #DDD;
|
border: 1px solid #DDD;
|
||||||
@ -152,6 +161,14 @@ pre {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
pre {
|
||||||
|
padding-left: 12px;
|
||||||
|
}
|
||||||
|
pre:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
display: block;
|
display: block;
|
||||||
@ -172,7 +189,6 @@ blockquote {
|
|||||||
|
|
||||||
.code-base {
|
.code-base {
|
||||||
background-color: #F8F8F8;
|
background-color: #F8F8F8;
|
||||||
font-family: monospace;
|
|
||||||
font-size: 0.80em;
|
font-size: 0.80em;
|
||||||
border: 1px solid #DDD;
|
border: 1px solid #DDD;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
@ -27,8 +27,12 @@ $-xs: 6px;
|
|||||||
$-xxs: 3px;
|
$-xxs: 3px;
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
$heading: 'Roboto', 'DejaVu Sans', Helvetica, Arial, sans-serif;
|
$text: -apple-system, BlinkMacSystemFont,
|
||||||
$text: 'Roboto', 'DejaVu Sans', Helvetica, Arial, sans-serif;
|
"Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell",
|
||||||
|
"Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||||
|
sans-serif;
|
||||||
|
$mono: "Lucida Console", "DejaVu Sans Mono", "Ubunto Mono", Monaco, monospace;
|
||||||
|
$heading: $text;
|
||||||
$fs-m: 15px;
|
$fs-m: 15px;
|
||||||
$fs-s: 14px;
|
$fs-s: 14px;
|
||||||
|
|
||||||
@ -56,3 +60,6 @@ $text-light: #EEE;
|
|||||||
$bs-light: 0 0 4px 1px #CCC;
|
$bs-light: 0 0 4px 1px #CCC;
|
||||||
$bs-med: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
|
$bs-med: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
|
||||||
$bs-hover: 0 2px 2px 1px rgba(0,0,0,.13);
|
$bs-hover: 0 2px 2px 1px rgba(0,0,0,.13);
|
||||||
|
|
||||||
|
// comments
|
||||||
|
$comment-border: #DDD;
|
@ -1,4 +1,3 @@
|
|||||||
//@import "reset";
|
|
||||||
@import "variables";
|
@import "variables";
|
||||||
@import "mixins";
|
@import "mixins";
|
||||||
@import "html";
|
@import "html";
|
||||||
@ -10,6 +9,7 @@
|
|||||||
@import "header";
|
@import "header";
|
||||||
@import "lists";
|
@import "lists";
|
||||||
@import "pages";
|
@import "pages";
|
||||||
|
@import "comments";
|
||||||
|
|
||||||
table {
|
table {
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
@import "reset";
|
@import "reset";
|
||||||
@import "variables";
|
@import "variables";
|
||||||
@import "fonts";
|
|
||||||
@import "mixins";
|
@import "mixins";
|
||||||
@import "html";
|
@import "html";
|
||||||
@import "text";
|
@import "text";
|
||||||
@ -16,13 +15,13 @@
|
|||||||
@import "header";
|
@import "header";
|
||||||
@import "lists";
|
@import "lists";
|
||||||
@import "pages";
|
@import "pages";
|
||||||
|
@import "comments";
|
||||||
|
|
||||||
[v-cloak], [v-show] {
|
[v-cloak] {
|
||||||
display: none; opacity: 0;
|
display: none; opacity: 0;
|
||||||
animation-name: none !important;
|
animation-name: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[ng\:cloak], [ng-cloak], .ng-cloak {
|
[ng\:cloak], [ng-cloak], .ng-cloak {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@ -65,44 +64,6 @@ body.dragging, body.dragging * {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// System wide notifications
|
|
||||||
.notification {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
margin: $-xl*2 $-xl;
|
|
||||||
padding: $-l $-xl;
|
|
||||||
background-color: #EEE;
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: $bs-med;
|
|
||||||
z-index: 999999;
|
|
||||||
display: block;
|
|
||||||
cursor: pointer;
|
|
||||||
max-width: 480px;
|
|
||||||
i, span {
|
|
||||||
display: table-cell;
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
font-size: 2em;
|
|
||||||
padding-right: $-l;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
&.pos {
|
|
||||||
background-color: $positive;
|
|
||||||
color: #EEE;
|
|
||||||
}
|
|
||||||
&.neg {
|
|
||||||
background-color: $negative;
|
|
||||||
color: #EEE;
|
|
||||||
}
|
|
||||||
&.warning {
|
|
||||||
background-color: $secondary;
|
|
||||||
color: #EEE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loading icon
|
// Loading icon
|
||||||
$loadingSize: 10px;
|
$loadingSize: 10px;
|
||||||
.loading-container {
|
.loading-container {
|
||||||
@ -150,7 +111,7 @@ $loadingSize: 10px;
|
|||||||
|
|
||||||
// Back to top link
|
// Back to top link
|
||||||
$btt-size: 40px;
|
$btt-size: 40px;
|
||||||
#back-to-top {
|
[back-to-top] {
|
||||||
background-color: $primary;
|
background-color: $primary;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: $-m;
|
bottom: $-m;
|
||||||
|
@ -8,33 +8,33 @@ return [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
'page_create' => 'Seite erstellt',
|
'page_create' => 'hat Seite erstellt:',
|
||||||
'page_create_notification' => 'Seite erfolgreich erstellt',
|
'page_create_notification' => 'hat Seite erfolgreich erstellt:',
|
||||||
'page_update' => 'Seite aktualisiert',
|
'page_update' => 'hat Seite aktualisiert:',
|
||||||
'page_update_notification' => 'Seite erfolgreich aktualisiert',
|
'page_update_notification' => 'hat Seite erfolgreich aktualisiert:',
|
||||||
'page_delete' => 'Seite gelöscht',
|
'page_delete' => 'hat Seite gelöscht:',
|
||||||
'page_delete_notification' => 'Seite erfolgreich gelöscht',
|
'page_delete_notification' => 'hat Seite erfolgreich gelöscht:',
|
||||||
'page_restore' => 'Seite wiederhergstellt',
|
'page_restore' => 'hat Seite wiederhergstellt:',
|
||||||
'page_restore_notification' => 'Seite erfolgreich wiederhergstellt',
|
'page_restore_notification' => 'hat Seite erfolgreich wiederhergstellt:',
|
||||||
'page_move' => 'Seite verschoben',
|
'page_move' => 'hat Seite verschoben:',
|
||||||
|
|
||||||
// Chapters
|
// Chapters
|
||||||
'chapter_create' => 'Kapitel erstellt',
|
'chapter_create' => 'hat Kapitel erstellt:',
|
||||||
'chapter_create_notification' => 'Kapitel erfolgreich erstellt',
|
'chapter_create_notification' => 'hat Kapitel erfolgreich erstellt:',
|
||||||
'chapter_update' => 'Kapitel aktualisiert',
|
'chapter_update' => 'hat Kapitel aktualisiert:',
|
||||||
'chapter_update_notification' => 'Kapitel erfolgreich aktualisiert',
|
'chapter_update_notification' => 'hat Kapitel erfolgreich aktualisiert:',
|
||||||
'chapter_delete' => 'Kapitel gelöscht',
|
'chapter_delete' => 'hat Kapitel gelöscht',
|
||||||
'chapter_delete_notification' => 'Kapitel erfolgreich gelöscht',
|
'chapter_delete_notification' => 'hat Kapitel erfolgreich gelöscht:',
|
||||||
'chapter_move' => 'Kapitel verschoben',
|
'chapter_move' => 'hat Kapitel verschoben:',
|
||||||
|
|
||||||
// Books
|
// Books
|
||||||
'book_create' => 'Buch erstellt',
|
'book_create' => 'hat Buch erstellt:',
|
||||||
'book_create_notification' => 'Buch erfolgreich erstellt',
|
'book_create_notification' => 'hat Buch erfolgreich erstellt:',
|
||||||
'book_update' => 'Buch aktualisiert',
|
'book_update' => 'hat Buch aktualisiert:',
|
||||||
'book_update_notification' => 'Buch erfolgreich aktualisiert',
|
'book_update_notification' => 'hat Buch erfolgreich aktualisiert:',
|
||||||
'book_delete' => 'Buch gelöscht',
|
'book_delete' => 'hat Buch gelöscht:',
|
||||||
'book_delete_notification' => 'Buch erfolgreich gelöscht',
|
'book_delete_notification' => 'hat Buch erfolgreich gelöscht:',
|
||||||
'book_sort' => 'Buch sortiert',
|
'book_sort' => 'hat Buch sortiert:',
|
||||||
'book_sort_notification' => 'Buch erfolgreich neu sortiert',
|
'book_sort_notification' => 'hat Buch erfolgreich neu sortiert:',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -10,8 +10,8 @@ return [
|
|||||||
| these language lines according to your application's requirements.
|
| these language lines according to your application's requirements.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
'failed' => 'Dies sind keine gültigen Anmeldedaten.',
|
'failed' => 'Die eingegebenen Anmeldedaten sind ungültig.',
|
||||||
'throttle' => 'Zu viele Anmeldeversuche. Bitte versuchen sie es in :seconds Sekunden erneut.',
|
'throttle' => 'Zu viele Anmeldeversuche. Bitte versuchen Sie es in :seconds Sekunden erneut.',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login & Register
|
* Login & Register
|
||||||
@ -29,16 +29,16 @@ return [
|
|||||||
'forgot_password' => 'Passwort vergessen?',
|
'forgot_password' => 'Passwort vergessen?',
|
||||||
'remember_me' => 'Angemeldet bleiben',
|
'remember_me' => 'Angemeldet bleiben',
|
||||||
'ldap_email_hint' => 'Bitte geben Sie eine E-Mail-Adresse ein, um diese mit dem Account zu nutzen.',
|
'ldap_email_hint' => 'Bitte geben Sie eine E-Mail-Adresse ein, um diese mit dem Account zu nutzen.',
|
||||||
'create_account' => 'Account anlegen',
|
'create_account' => 'Account registrieren',
|
||||||
'social_login' => 'Social Login',
|
'social_login' => 'Mit Sozialem Netzwerk anmelden',
|
||||||
'social_registration' => 'Social Registrierung',
|
'social_registration' => 'Mit Sozialem Netzwerk registrieren',
|
||||||
'social_registration_text' => 'Mit einem dieser Möglichkeiten registrieren oder anmelden.',
|
'social_registration_text' => 'Mit einer dieser Dienste registrieren oder anmelden',
|
||||||
|
|
||||||
|
|
||||||
'register_thanks' => 'Vielen Dank für Ihre Registrierung!',
|
'register_thanks' => 'Vielen Dank für Ihre Registrierung!',
|
||||||
'register_confirm' => 'Bitte prüfen Sie Ihren E-Mail Eingang und klicken auf den Verifizieren-Button, um :appName nutzen zu können.',
|
'register_confirm' => 'Bitte prüfen Sie Ihren Posteingang und bestätigen Sie die Registrierung.',
|
||||||
'registrations_disabled' => 'Die Registrierung ist momentan nicht möglich',
|
'registrations_disabled' => 'Eine Registrierung ist momentan nicht möglich',
|
||||||
'registration_email_domain_invalid' => 'Diese E-Mail-Domain ist für die Benutzer der Applikation nicht freigeschaltet.',
|
'registration_email_domain_invalid' => 'Sie können sich mit dieser E-Mail nicht registrieren.',
|
||||||
'register_success' => 'Vielen Dank für Ihre Registrierung! Die Daten sind gespeichert und Sie sind angemeldet.',
|
'register_success' => 'Vielen Dank für Ihre Registrierung! Die Daten sind gespeichert und Sie sind angemeldet.',
|
||||||
|
|
||||||
|
|
||||||
@ -46,30 +46,30 @@ return [
|
|||||||
* Password Reset
|
* Password Reset
|
||||||
*/
|
*/
|
||||||
'reset_password' => 'Passwort vergessen',
|
'reset_password' => 'Passwort vergessen',
|
||||||
'reset_password_send_instructions' => 'Bitte geben Sie unten Ihre E-Mail-Adresse ein und Sie erhalten eine E-Mail, um Ihr Passwort zurück zu setzen.',
|
'reset_password_send_instructions' => 'Bitte geben Sie Ihre E-Mail-Adresse ein. Danach erhalten Sie eine E-Mail mit einem Link zum Zurücksetzen Ihres Passwortes.',
|
||||||
'reset_password_send_button' => 'Passwort zurücksetzen',
|
'reset_password_send_button' => 'Passwort zurücksetzen',
|
||||||
'reset_password_sent_success' => 'Eine E-Mail mit den Instruktionen, um Ihr Passwort zurückzusetzen wurde an :email gesendet.',
|
'reset_password_sent_success' => 'Eine E-Mail mit dem Link zum Zurücksetzen Ihres Passwortes wurde an :email gesendet.',
|
||||||
'reset_password_success' => 'Ihr Passwort wurde erfolgreich zurückgesetzt.',
|
'reset_password_success' => 'Ihr Passwort wurde erfolgreich zurückgesetzt.',
|
||||||
|
|
||||||
'email_reset_subject' => 'Passwort zurücksetzen für :appName',
|
'email_reset_subject' => 'Passwort zurücksetzen für :appName',
|
||||||
'email_reset_text' => 'Sie erhalten diese E-Mail, weil eine Passwort-Rücksetzung für Ihren Account beantragt wurde.',
|
'email_reset_text' => 'Sie erhalten diese E-Mail, weil jemand versucht hat, Ihr Passwort zurückzusetzen.',
|
||||||
'email_reset_not_requested' => 'Wenn Sie die Passwort-Rücksetzung nicht ausgelöst haben, ist kein weiteres Handeln notwendig.',
|
'email_reset_not_requested' => 'Wenn Sie das nicht waren, brauchen Sie nichts weiter zu tun.',
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Email Confirmation
|
* Email Confirmation
|
||||||
*/
|
*/
|
||||||
'email_confirm_subject' => 'Bestätigen sie ihre E-Mail Adresse bei :appName',
|
'email_confirm_subject' => 'Bestätigen Sie Ihre E-Mail-Adresse für :appName',
|
||||||
'email_confirm_greeting' => 'Danke, dass sie :appName beigetreten sind!',
|
'email_confirm_greeting' => 'Danke, dass Sie sich für :appName registriert haben!',
|
||||||
'email_confirm_text' => 'Bitte bestätigen sie ihre E-Mail Adresse, indem sie auf den Button klicken:',
|
'email_confirm_text' => 'Bitte bestätigen Sie Ihre E-Mail-Adresse, indem Sie auf die Schaltfläche klicken:',
|
||||||
'email_confirm_action' => 'E-Mail Adresse bestätigen',
|
'email_confirm_action' => 'E-Mail-Adresse bestätigen',
|
||||||
'email_confirm_send_error' => 'Bestätigungs-E-Mail benötigt, aber das System konnte die E-Mail nicht versenden. Kontaktieren sie den Administrator, um sicherzustellen, dass das Sytsem korrekt eingerichtet ist.',
|
'email_confirm_send_error' => 'Leider konnte die für die Registrierung notwendige E-Mail zur bestätigung Ihrer E-Mail-Adresse nicht versandt werden. Bitte kontaktieren Sie den Systemadministrator!',
|
||||||
'email_confirm_success' => 'Ihre E-Mail Adresse wurde bestätigt!',
|
'email_confirm_success' => 'Ihre E-Mail-Adresse wurde bestätigt!',
|
||||||
'email_confirm_resent' => 'Bestätigungs-E-Mail wurde erneut versendet, bitte überprüfen sie ihren Posteingang.',
|
'email_confirm_resent' => 'Bestätigungs-E-Mail wurde erneut versendet, bitte überprüfen Sie Ihren Posteingang.',
|
||||||
|
|
||||||
'email_not_confirmed' => 'E-Mail-Adresse ist nicht bestätigt',
|
'email_not_confirmed' => 'E-Mail-Adresse ist nicht bestätigt',
|
||||||
'email_not_confirmed_text' => 'Ihre E-Mail-Adresse ist bisher nicht bestätigt.',
|
'email_not_confirmed_text' => 'Ihre E-Mail-Adresse ist bisher nicht bestätigt.',
|
||||||
'email_not_confirmed_click_link' => 'Bitte klicken Sie auf den Link in der E-Mail, die Sie nach der Registrierung erhalten haben.',
|
'email_not_confirmed_click_link' => 'Bitte klicken Sie auf den Link in der E-Mail, die Sie nach der Registrierung erhalten haben.',
|
||||||
'email_not_confirmed_resend' => 'Wenn Sie die E-Mail nicht erhalten haben, können Sie die Nachricht erneut anfordern. Füllen Sie hierzu bitte das folgende Formular aus:',
|
'email_not_confirmed_resend' => 'Wenn Sie die E-Mail nicht erhalten haben, können Sie die Nachricht erneut anfordern. Füllen Sie hierzu bitte das folgende Formular aus:',
|
||||||
'email_not_confirmed_resend_button' => 'Bestätigungs E-Mail erneut senden',
|
'email_not_confirmed_resend_button' => 'Bestätigungs-E-Mail erneut senden',
|
||||||
];
|
];
|
||||||
|
@ -30,9 +30,9 @@ return [
|
|||||||
'edit' => 'Bearbeiten',
|
'edit' => 'Bearbeiten',
|
||||||
'sort' => 'Sortieren',
|
'sort' => 'Sortieren',
|
||||||
'move' => 'Verschieben',
|
'move' => 'Verschieben',
|
||||||
'delete' => 'Löschen',
|
'delete' => 'Löschen',
|
||||||
'search' => 'Suchen',
|
'search' => 'Suchen',
|
||||||
'search_clear' => 'Suche löschen',
|
'search_clear' => 'Suche löschen',
|
||||||
'reset' => 'Zurücksetzen',
|
'reset' => 'Zurücksetzen',
|
||||||
'remove' => 'Entfernen',
|
'remove' => 'Entfernen',
|
||||||
|
|
||||||
@ -40,9 +40,9 @@ return [
|
|||||||
/**
|
/**
|
||||||
* Misc
|
* Misc
|
||||||
*/
|
*/
|
||||||
'deleted_user' => 'Gelöschte Benutzer',
|
'deleted_user' => 'Gelöschte Benutzer',
|
||||||
'no_activity' => 'Keine Aktivitäten zum Anzeigen',
|
'no_activity' => 'Keine Aktivitäten zum Anzeigen',
|
||||||
'no_items' => 'Keine Einträge gefunden.',
|
'no_items' => 'Keine Einträge gefunden.',
|
||||||
'back_to_top' => 'nach oben',
|
'back_to_top' => 'nach oben',
|
||||||
'toggle_details' => 'Details zeigen/verstecken',
|
'toggle_details' => 'Details zeigen/verstecken',
|
||||||
'toggle_thumbnails' => 'Thumbnails zeigen/verstecken',
|
'toggle_thumbnails' => 'Thumbnails zeigen/verstecken',
|
||||||
@ -55,6 +55,6 @@ return [
|
|||||||
/**
|
/**
|
||||||
* Email Content
|
* Email Content
|
||||||
*/
|
*/
|
||||||
'email_action_help' => 'Sollte es beim Anklicken des ":actionText" Buttons Probleme geben, kopieren Sie folgende URL und fügen diese in Ihrem Webbrowser ein:',
|
'email_action_help' => 'Sollte es beim Anklicken der Schaltfläche ":action_text" Probleme geben, öffnen Sie folgende URL in Ihrem Browser:',
|
||||||
'email_rights' => 'Alle Rechte vorbehalten',
|
'email_rights' => 'Alle Rechte vorbehalten',
|
||||||
];
|
];
|
@ -13,9 +13,9 @@ return [
|
|||||||
'image_uploaded' => 'Hochgeladen am :uploadedDate',
|
'image_uploaded' => 'Hochgeladen am :uploadedDate',
|
||||||
'image_load_more' => 'Mehr',
|
'image_load_more' => 'Mehr',
|
||||||
'image_image_name' => 'Bildname',
|
'image_image_name' => 'Bildname',
|
||||||
'image_delete_confirm' => 'Dieses Bild wird auf den folgenden Seiten benutzt. Bitte klicken Sie erneut auf löschen, wenn Sie dieses Bild tatsächlich entfernen möchten.',
|
'image_delete_confirm' => 'Dieses Bild wird auf den folgenden Seiten benutzt. Bitte klicken Sie erneut auf löschen, wenn Sie dieses Bild wirklich entfernen möchten.',
|
||||||
'image_select_image' => 'Bild auswählen',
|
'image_select_image' => 'Bild auswählen',
|
||||||
'image_dropzone' => 'Ziehen Sie Bilder hier hinein oder klicken Sie hier, um ein Bild auszuwählen',
|
'image_dropzone' => 'Ziehen Sie Bilder hierher oder klicken Sie, um ein Bild auszuwählen',
|
||||||
'images_deleted' => 'Bilder gelöscht',
|
'images_deleted' => 'Bilder gelöscht',
|
||||||
'image_preview' => 'Bildvorschau',
|
'image_preview' => 'Bildvorschau',
|
||||||
'image_upload_success' => 'Bild erfolgreich hochgeladen',
|
'image_upload_success' => 'Bild erfolgreich hochgeladen',
|
||||||
|
@ -4,38 +4,39 @@ return [
|
|||||||
/**
|
/**
|
||||||
* Shared
|
* Shared
|
||||||
*/
|
*/
|
||||||
'recently_created' => 'Kürzlich angelegt',
|
'recently_created' => 'Kürzlich angelegt',
|
||||||
'recently_created_pages' => 'Kürzlich angelegte Seiten',
|
'recently_created_pages' => 'Kürzlich angelegte Seiten',
|
||||||
'recently_updated_pages' => 'Kürzlich aktualisierte Seiten',
|
'recently_updated_pages' => 'Kürzlich aktualisierte Seiten',
|
||||||
'recently_created_chapters' => 'Kürzlich angelegte Kapitel',
|
'recently_created_chapters' => 'Kürzlich angelegte Kapitel',
|
||||||
'recently_created_books' => 'Kürzlich angelegte Bücher',
|
'recently_created_books' => 'Kürzlich angelegte Bücher',
|
||||||
'recently_update' => 'Kürzlich aktualisiert',
|
'recently_update' => 'Kürzlich aktualisiert',
|
||||||
'recently_viewed' => 'Kürzlich angesehen',
|
'recently_viewed' => 'Kürzlich angesehen',
|
||||||
'recent_activity' => 'Kürzliche Aktivität',
|
'recent_activity' => 'Kürzliche Aktivität',
|
||||||
'create_now' => 'Jetzt anlegen',
|
'create_now' => 'Jetzt anlegen',
|
||||||
'revisions' => 'Revisionen',
|
'revisions' => 'Versionen',
|
||||||
'meta_created' => 'Angelegt am :timeLength',
|
'meta_revision' => 'Version #:revisionCount',
|
||||||
'meta_created_name' => 'Angelegt am :timeLength durch :user',
|
'meta_created' => 'Erstellt: :timeLength',
|
||||||
'meta_updated' => 'Aktualisiert am :timeLength',
|
'meta_created_name' => 'Erstellt: :timeLength von :user',
|
||||||
'meta_updated_name' => 'Aktualisiert am :timeLength durch :user',
|
'meta_updated' => 'Zuletzt aktualisiert: :timeLength',
|
||||||
|
'meta_updated_name' => 'Zuletzt aktualisiert: :timeLength von :user',
|
||||||
'x_pages' => ':count Seiten',
|
'x_pages' => ':count Seiten',
|
||||||
'entity_select' => 'Eintrag auswählen',
|
'entity_select' => 'Eintrag auswählen',
|
||||||
'images' => 'Bilder',
|
'images' => 'Bilder',
|
||||||
'my_recent_drafts' => 'Meine kürzlichen Entwürfe',
|
'my_recent_drafts' => 'Meine kürzlichen Entwürfe',
|
||||||
'my_recently_viewed' => 'Kürzlich von mir angesehen',
|
'my_recently_viewed' => 'Kürzlich von mir angesehen',
|
||||||
'no_pages_viewed' => 'Sie haben bisher keine Seiten angesehen.',
|
'no_pages_viewed' => 'Sie haben bisher keine Seiten angesehen.',
|
||||||
'no_pages_recently_created' => 'Sie haben bisher keine Seiten angelegt.',
|
'no_pages_recently_created' => 'Sie haben bisher keine Seiten angelegt.',
|
||||||
'no_pages_recently_updated' => 'Sie haben bisher keine Seiten aktualisiert.',
|
'no_pages_recently_updated' => 'Sie haben bisher keine Seiten aktualisiert.',
|
||||||
'export' => 'Exportieren',
|
'export' => 'Exportieren',
|
||||||
'export_html' => 'HTML-Datei',
|
'export_html' => 'HTML-Datei',
|
||||||
'export_pdf' => 'PDF-Datei',
|
'export_pdf' => 'PDF-Datei',
|
||||||
'export_text' => 'Text-Datei',
|
'export_text' => 'Textdatei',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permissions and restrictions
|
* Permissions and restrictions
|
||||||
*/
|
*/
|
||||||
'permissions' => 'Berechtigungen',
|
'permissions' => 'Berechtigungen',
|
||||||
'permissions_intro' => 'Wenn individuelle Berechtigungen aktiviert werden, überschreiben diese Einstellungen durch Rollen zugewiesene Berechtigungen.',
|
'permissions_intro' => 'Wenn individuelle Berechtigungen aktiviert werden, überschreiben diese Einstellungen durch Rollen zugewiesene Berechtigungen.',
|
||||||
'permissions_enable' => 'Individuelle Berechtigungen aktivieren',
|
'permissions_enable' => 'Individuelle Berechtigungen aktivieren',
|
||||||
'permissions_save' => 'Berechtigungen speichern',
|
'permissions_save' => 'Berechtigungen speichern',
|
||||||
|
|
||||||
@ -43,41 +44,58 @@ return [
|
|||||||
* Search
|
* Search
|
||||||
*/
|
*/
|
||||||
'search_results' => 'Suchergebnisse',
|
'search_results' => 'Suchergebnisse',
|
||||||
'search_clear' => 'Suche zurücksetzen',
|
'search_total_results_found' => ':count Ergebnis gefunden|:count Ergebnisse gesamt',
|
||||||
'search_no_pages' => 'Es wurden keine passenden Suchergebnisse gefunden',
|
'search_clear' => 'Filter löschen',
|
||||||
'search_for_term' => 'Suche nach :term',
|
'search_no_pages' => 'Keine Seiten gefunden',
|
||||||
|
'search_for_term' => 'Nach :term suchen',
|
||||||
|
'search_more' => 'Mehr Ergebnisse',
|
||||||
|
'search_filters' => 'Filter',
|
||||||
|
'search_content_type' => 'Inhaltstyp',
|
||||||
|
'search_exact_matches' => 'Exakte Treffer',
|
||||||
|
'search_tags' => 'Nach Schlagwort suchen',
|
||||||
|
'search_viewed_by_me' => 'Schon von mir angesehen',
|
||||||
|
'search_not_viewed_by_me' => 'Noch nicht von mir angesehen',
|
||||||
|
'search_permissions_set' => 'Berechtigungen gesetzt',
|
||||||
|
'search_created_by_me' => 'Von mir erstellt',
|
||||||
|
'search_updated_by_me' => 'Von mir aktualisiert',
|
||||||
|
'search_updated_before' => 'Aktualisiert vor',
|
||||||
|
'search_updated_after' => 'Aktualisiert nach',
|
||||||
|
'search_created_before' => 'Erstellt vor',
|
||||||
|
'search_created_after' => 'Erstellt nach',
|
||||||
|
'search_set_date' => 'Datum auswählen',
|
||||||
|
'search_update' => 'Suche aktualisieren',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Books
|
* Books
|
||||||
*/
|
*/
|
||||||
'book' => 'Buch',
|
'book' => 'Buch',
|
||||||
'books' => 'Bücher',
|
'books' => 'Bücher',
|
||||||
'books_empty' => 'Es wurden keine Bücher angelegt',
|
'books_empty' => 'Keine Bücher vorhanden',
|
||||||
'books_popular' => 'Populäre Bücher',
|
'books_popular' => 'Beliebte Bücher',
|
||||||
'books_recent' => 'Kürzlich genutzte Bücher',
|
'books_recent' => 'Kürzlich angesehene Bücher',
|
||||||
'books_popular_empty' => 'Die populärsten Bücher werden hier angezeigt.',
|
'books_popular_empty' => 'Die beliebtesten Bücher werden hier angezeigt.',
|
||||||
'books_create' => 'Neues Buch anlegen',
|
'books_create' => 'Neues Buch erstellen',
|
||||||
'books_delete' => 'Buch löschen',
|
'books_delete' => 'Buch löschen',
|
||||||
'books_delete_named' => 'Buch :bookName löschen',
|
'books_delete_named' => 'Buch ":bookName" löschen',
|
||||||
'books_delete_explain' => 'Sie möchten das Buch \':bookName\' löschen und alle Seiten und Kapitel entfernen.',
|
'books_delete_explain' => 'Das Buch ":bookName" wird gelöscht und alle zugehörigen Kapitel und Seiten entfernt.',
|
||||||
'books_delete_confirmation' => 'Sind Sie sicher, dass Sie dieses Buch löschen möchten?',
|
'books_delete_confirmation' => 'Sind Sie sicher, dass Sie dieses Buch löschen möchten?',
|
||||||
'books_edit' => 'Buch bearbeiten',
|
'books_edit' => 'Buch bearbeiten',
|
||||||
'books_edit_named' => 'Buch :bookName bearbeiten',
|
'books_edit_named' => 'Buch ":bookName" bearbeiten',
|
||||||
'books_form_book_name' => 'Buchname',
|
'books_form_book_name' => 'Name des Buches',
|
||||||
'books_save' => 'Buch speichern',
|
'books_save' => 'Buch speichern',
|
||||||
'books_permissions' => 'Buch-Berechtigungen',
|
'books_permissions' => 'Buch-Berechtigungen',
|
||||||
'books_permissions_updated' => 'Buch-Berechtigungen aktualisiert',
|
'books_permissions_updated' => 'Buch-Berechtigungen aktualisiert',
|
||||||
'books_empty_contents' => 'Es sind noch keine Seiten oder Kapitel für dieses Buch angelegt.',
|
'books_empty_contents' => 'Es sind noch keine Seiten oder Kapitel zu diesem Buch hinzugefügt worden.',
|
||||||
'books_empty_create_page' => 'Neue Seite anlegen',
|
'books_empty_create_page' => 'Neue Seite anlegen',
|
||||||
'books_empty_or' => 'oder',
|
'books_empty_or' => 'oder',
|
||||||
'books_empty_sort_current_book' => 'Aktuelles Buch sortieren',
|
'books_empty_sort_current_book' => 'Aktuelles Buch sortieren',
|
||||||
'books_empty_add_chapter' => 'Neues Kapitel hinzufügen',
|
'books_empty_add_chapter' => 'Neues Kapitel hinzufügen',
|
||||||
'books_permissions_active' => 'Buch-Berechtigungen aktiv',
|
'books_permissions_active' => 'Buch-Berechtigungen aktiv',
|
||||||
'books_search_this' => 'Dieses Buch durchsuchen',
|
'books_search_this' => 'Dieses Buch durchsuchen',
|
||||||
'books_navigation' => 'Buch-Navigation',
|
'books_navigation' => 'Buchnavigation',
|
||||||
'books_sort' => 'Buchinhalte sortieren',
|
'books_sort' => 'Buchinhalte sortieren',
|
||||||
'books_sort_named' => 'Buch :bookName sortieren',
|
'books_sort_named' => 'Buch ":bookName" sortieren',
|
||||||
'books_sort_show_other' => 'Andere Bücher zeigen',
|
'books_sort_show_other' => 'Andere Bücher anzeigen',
|
||||||
'books_sort_save' => 'Neue Reihenfolge speichern',
|
'books_sort_save' => 'Neue Reihenfolge speichern',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,132 +103,157 @@ return [
|
|||||||
*/
|
*/
|
||||||
'chapter' => 'Kapitel',
|
'chapter' => 'Kapitel',
|
||||||
'chapters' => 'Kapitel',
|
'chapters' => 'Kapitel',
|
||||||
'chapters_popular' => 'Populäre Kapitel',
|
'chapters_popular' => 'Beliebte Kapitel',
|
||||||
'chapters_new' => 'Neues Kapitel',
|
'chapters_new' => 'Neues Kapitel',
|
||||||
'chapters_create' => 'Neues Kapitel anlegen',
|
'chapters_create' => 'Neues Kapitel anlegen',
|
||||||
'chapters_delete' => 'Kapitel entfernen',
|
'chapters_delete' => 'Kapitel entfernen',
|
||||||
'chapters_delete_named' => 'Kapitel :chapterName entfernen',
|
'chapters_delete_named' => 'Kapitel ":chapterName" entfernen',
|
||||||
'chapters_delete_explain' => 'Sie möchten das Kapitel \':chapterName\' löschen und alle Seiten dem direkten Eltern-Buch hinzugefügen.',
|
'chapters_delete_explain' => 'Das Kapitel ":chapterName" wird gelöscht und alle zugehörigen Seiten dem übergeordneten Buch zugeordnet.',
|
||||||
'chapters_delete_confirm' => 'Sind Sie sicher, dass Sie dieses Kapitel löschen möchten?',
|
'chapters_delete_confirm' => 'Sind Sie sicher, dass Sie dieses Kapitel löschen möchten?',
|
||||||
'chapters_edit' => 'Kapitel bearbeiten',
|
'chapters_edit' => 'Kapitel bearbeiten',
|
||||||
'chapters_edit_named' => 'Kapitel :chapterName bearbeiten',
|
'chapters_edit_named' => 'Kapitel ":chapterName" bearbeiten',
|
||||||
'chapters_save' => 'Kapitel speichern',
|
'chapters_save' => 'Kapitel speichern',
|
||||||
'chapters_move' => 'Kapitel verschieben',
|
'chapters_move' => 'Kapitel verschieben',
|
||||||
'chapters_move_named' => 'Kapitel :chapterName verschieben',
|
'chapters_move_named' => 'Kapitel ":chapterName" verschieben',
|
||||||
'chapter_move_success' => 'Kapitel in das Buch :bookName verschoben.',
|
'chapter_move_success' => 'Das Kapitel wurde in das Buch ":bookName" verschoben.',
|
||||||
'chapters_permissions' => 'Kapitel-Berechtigungen',
|
'chapters_permissions' => 'Kapitel-Berechtigungen',
|
||||||
'chapters_empty' => 'Aktuell sind keine Kapitel in diesem Buch angelegt.',
|
'chapters_empty' => 'Aktuell sind keine Kapitel diesem Buch hinzugefügt worden.',
|
||||||
'chapters_permissions_active' => 'Kapitel-Berechtigungen aktiv',
|
'chapters_permissions_active' => 'Kapitel-Berechtigungen aktiv',
|
||||||
'chapters_permissions_success' => 'Kapitel-Berechtigungenen aktualisisert',
|
'chapters_permissions_success' => 'Kapitel-Berechtigungenen aktualisisert',
|
||||||
|
'chapters_search_this' => 'Dieses Kapitel durchsuchen',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pages
|
* Pages
|
||||||
*/
|
*/
|
||||||
'page' => 'Seite',
|
'page' => 'Seite',
|
||||||
'pages' => 'Seiten',
|
'pages' => 'Seiten',
|
||||||
'pages_popular' => 'Populäre Seiten',
|
'pages_popular' => 'Beliebte Seiten',
|
||||||
'pages_new' => 'Neue Seite',
|
'pages_new' => 'Neue Seite',
|
||||||
'pages_attachments' => 'Anhänge',
|
'pages_attachments' => 'Anhänge',
|
||||||
'pages_navigation' => 'Seitennavigation',
|
'pages_navigation' => 'Seitennavigation',
|
||||||
'pages_delete' => 'Seite löschen',
|
'pages_delete' => 'Seite löschen',
|
||||||
'pages_delete_named' => 'Seite :pageName löschen',
|
'pages_delete_named' => 'Seite ":pageName" löschen',
|
||||||
'pages_delete_draft_named' => 'Seitenentwurf von :pageName löschen',
|
'pages_delete_draft_named' => 'Seitenentwurf von ":pageName" löschen',
|
||||||
'pages_delete_draft' => 'Seitenentwurf löschen',
|
'pages_delete_draft' => 'Seitenentwurf löschen',
|
||||||
'pages_delete_success' => 'Seite gelöscht',
|
'pages_delete_success' => 'Seite gelöscht',
|
||||||
'pages_delete_draft_success' => 'Seitenentwurf gelöscht',
|
'pages_delete_draft_success' => 'Seitenentwurf gelöscht',
|
||||||
'pages_delete_confirm' => 'Sind Sie sicher, dass Sie diese Seite löschen möchen?',
|
'pages_delete_confirm' => 'Sind Sie sicher, dass Sie diese Seite löschen möchen?',
|
||||||
'pages_delete_draft_confirm' => 'Sind Sie sicher, dass Sie diesen Seitenentwurf löschen möchten?',
|
'pages_delete_draft_confirm' => 'Sind Sie sicher, dass Sie diesen Seitenentwurf löschen möchten?',
|
||||||
'pages_editing_named' => 'Seite :pageName bearbeiten',
|
'pages_editing_named' => 'Seite ":pageName" bearbeiten',
|
||||||
'pages_edit_toggle_header' => 'Toggle header',
|
'pages_edit_toggle_header' => 'Hauptmenü anzeigen/verstecken',
|
||||||
'pages_edit_save_draft' => 'Entwurf speichern',
|
'pages_edit_save_draft' => 'Entwurf speichern',
|
||||||
'pages_edit_draft' => 'Seitenentwurf bearbeiten',
|
'pages_edit_draft' => 'Seitenentwurf bearbeiten',
|
||||||
'pages_editing_draft' => 'Seitenentwurf bearbeiten',
|
'pages_editing_draft' => 'Seitenentwurf bearbeiten',
|
||||||
'pages_editing_page' => 'Seite bearbeiten',
|
'pages_editing_page' => 'Seite bearbeiten',
|
||||||
'pages_edit_draft_save_at' => 'Entwurf gespeichert um ',
|
'pages_edit_draft_save_at' => 'Entwurf gespeichert um ',
|
||||||
'pages_edit_delete_draft' => 'Entwurf löschen',
|
'pages_edit_delete_draft' => 'Entwurf löschen',
|
||||||
'pages_edit_discard_draft' => 'Entwurf verwerfen',
|
'pages_edit_discard_draft' => 'Entwurf verwerfen',
|
||||||
'pages_edit_set_changelog' => 'Veränderungshinweis setzen',
|
'pages_edit_set_changelog' => 'Änderungsprotokoll hinzufügen',
|
||||||
'pages_edit_enter_changelog_desc' => 'Bitte geben Sie eine kurze Zusammenfassung Ihrer Änderungen ein',
|
'pages_edit_enter_changelog_desc' => 'Bitte geben Sie eine kurze Zusammenfassung Ihrer Änderungen ein',
|
||||||
'pages_edit_enter_changelog' => 'Veränderungshinweis eingeben',
|
'pages_edit_enter_changelog' => 'Änderungsprotokoll eingeben',
|
||||||
'pages_save' => 'Seite speichern',
|
'pages_save' => 'Seite speichern',
|
||||||
'pages_title' => 'Seitentitel',
|
'pages_title' => 'Seitentitel',
|
||||||
'pages_name' => 'Seitenname',
|
'pages_name' => 'Seitenname',
|
||||||
'pages_md_editor' => 'Redakteur',
|
'pages_md_editor' => 'Redakteur',
|
||||||
'pages_md_preview' => 'Vorschau',
|
'pages_md_preview' => 'Vorschau',
|
||||||
'pages_md_insert_image' => 'Bild einfügen',
|
'pages_md_insert_image' => 'Bild einfügen',
|
||||||
'pages_md_insert_link' => 'Link zu einem Objekt einfügen',
|
'pages_md_insert_link' => 'Link zu einem Objekt einfügen',
|
||||||
'pages_not_in_chapter' => 'Seite ist in keinem Kapitel',
|
'pages_not_in_chapter' => 'Seite ist in keinem Kapitel',
|
||||||
'pages_move' => 'Seite verschieben',
|
'pages_move' => 'Seite verschieben',
|
||||||
'pages_move_success' => 'Seite nach ":parentName" verschoben',
|
'pages_move_success' => 'Seite nach ":parentName" verschoben',
|
||||||
'pages_permissions' => 'Seiten Berechtigungen',
|
'pages_permissions' => 'Seiten Berechtigungen',
|
||||||
'pages_permissions_success' => 'Seiten Berechtigungen aktualisiert',
|
'pages_permissions_success' => 'Seiten Berechtigungen aktualisiert',
|
||||||
'pages_revisions' => 'Seitenversionen',
|
'pages_revisions' => 'Seitenversionen',
|
||||||
'pages_revisions_named' => 'Seitenversionen von :pageName',
|
'pages_revisions_named' => 'Seitenversionen von ":pageName"',
|
||||||
'pages_revision_named' => 'Seitenversion von :pageName',
|
'pages_revision_named' => 'Seitenversion von ":pageName"',
|
||||||
'pages_revisions_created_by' => 'Angelegt von',
|
'pages_revisions_created_by' => 'Erstellt von',
|
||||||
'pages_revisions_date' => 'Versionsdatum',
|
'pages_revisions_date' => 'Versionsdatum',
|
||||||
'pages_revisions_changelog' => 'Veränderungshinweise',
|
'pages_revisions_number' => '#',
|
||||||
'pages_revisions_changes' => 'Veränderungen',
|
'pages_revisions_changelog' => 'Änderungsprotokoll',
|
||||||
|
'pages_revisions_changes' => 'Änderungen',
|
||||||
'pages_revisions_current' => 'Aktuelle Version',
|
'pages_revisions_current' => 'Aktuelle Version',
|
||||||
'pages_revisions_preview' => 'Vorschau',
|
'pages_revisions_preview' => 'Vorschau',
|
||||||
'pages_revisions_restore' => 'Zurück sichern',
|
'pages_revisions_restore' => 'Wiederherstellen',
|
||||||
'pages_revisions_none' => 'Diese Seite hat keine älteren Versionen.',
|
'pages_revisions_none' => 'Diese Seite hat keine älteren Versionen.',
|
||||||
'pages_copy_link' => 'Link kopieren',
|
'pages_copy_link' => 'Link kopieren',
|
||||||
'pages_permissions_active' => 'Seiten-Berechtigungen aktiv',
|
'pages_permissions_active' => 'Seiten-Berechtigungen aktiv',
|
||||||
'pages_initial_revision' => 'Erste Veröffentlichung',
|
'pages_initial_revision' => 'Erste Veröffentlichung',
|
||||||
'pages_initial_name' => 'Neue Seite',
|
'pages_initial_name' => 'Neue Seite',
|
||||||
'pages_editing_draft_notification' => 'Sie bearbeiten momenten einen Entwurf, der zuletzt um :timeDiff gespeichert wurde.',
|
'pages_editing_draft_notification' => 'Sie bearbeiten momenten einen Entwurf, der zuletzt :timeDiff gespeichert wurde.',
|
||||||
'pages_draft_edited_notification' => 'Diese Seite wurde seit diesem Zeitpunkt verändert. Wir empfehlen Ihnen, diesen Entwurf zu verwerfen.',
|
'pages_draft_edited_notification' => 'Diese Seite wurde seit diesem Zeitpunkt verändert. Wir empfehlen Ihnen, diesen Entwurf zu verwerfen.',
|
||||||
'pages_draft_edit_active' => [
|
'pages_draft_edit_active' => [
|
||||||
'start_a' => ':count Benutzer haben die Bearbeitung dieser Seite begonnen.',
|
'start_a' => ':count Benutzer bearbeiten derzeit diese Seite.',
|
||||||
'start_b' => ':userName hat die Bearbeitung dieser Seite begonnen.',
|
'start_b' => ':userName bearbeitet jetzt diese Seite.',
|
||||||
'time_a' => 'seit die Seiten zuletzt aktualisiert wurden.',
|
'time_a' => 'seit die Seiten zuletzt aktualisiert wurden.',
|
||||||
'time_b' => 'in den letzten :minCount Minuten',
|
'time_b' => 'in den letzten :minCount Minuten',
|
||||||
'message' => ':start :time. Achten Sie darauf keine Aktualisierungen von anderen Benutzern zu überschreiben!',
|
'message' => ':start :time. Achten Sie darauf, keine Änderungen von anderen Benutzern zu überschreiben!',
|
||||||
],
|
],
|
||||||
'pages_draft_discarded' => 'Entwurf verworfen. Der aktuelle Seiteninhalt wurde geladen.',
|
'pages_draft_discarded' => 'Entwurf verworfen. Der aktuelle Seiteninhalt wurde geladen.',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editor sidebar
|
* Editor sidebar
|
||||||
*/
|
*/
|
||||||
'page_tags' => 'Seiten-Schlagwörter',
|
'page_tags' => 'Seiten-Schlagwörter',
|
||||||
'tag' => 'Schlagwort',
|
'tag' => 'Schlagwort',
|
||||||
'tags' => 'Schlagworte',
|
'tags' => 'Schlagwörter',
|
||||||
'tag_value' => 'Schlagwortinhalt (Optional)',
|
'tag_value' => 'Inhalt (Optional)',
|
||||||
'tags_explain' => "Fügen Sie Schlagworte hinzu, um Ihren Inhalt zu kategorisieren. \n Sie können einen erklärenden Inhalt hinzufügen, um eine genauere Unterteilung vorzunehmen.",
|
'tags_explain' => "Fügen Sie Schlagwörter hinzu, um Ihren Inhalt zu kategorisieren.\nSie können einen erklärenden Inhalt hinzufügen, um eine genauere Unterteilung vorzunehmen.",
|
||||||
'tags_add' => 'Weiteres Schlagwort hinzufügen',
|
'tags_add' => 'Weiteres Schlagwort hinzufügen',
|
||||||
'attachments' => 'Anhänge',
|
'attachments' => 'Anhänge',
|
||||||
'attachments_explain' => 'Sie können auf Ihrer Seite Dateien hochladen oder Links anfügen. Diese werden in der seitlich angezeigt.',
|
'attachments_explain' => 'Sie können auf Ihrer Seite Dateien hochladen oder Links hinzufügen. Diese werden in der Seitenleiste angezeigt.',
|
||||||
'attachments_explain_instant_save' => 'Änderungen werden direkt gespeichert.',
|
'attachments_explain_instant_save' => 'Änderungen werden direkt gespeichert.',
|
||||||
'attachments_items' => 'Angefügte Elemente',
|
'attachments_items' => 'Angefügte Elemente',
|
||||||
'attachments_upload' => 'Datei hochladen',
|
'attachments_upload' => 'Datei hochladen',
|
||||||
'attachments_link' => 'Link anfügen',
|
'attachments_link' => 'Link hinzufügen',
|
||||||
'attachments_set_link' => 'Link setzen',
|
'attachments_set_link' => 'Link setzen',
|
||||||
'attachments_delete_confirm' => 'Klicken Sie erneut auf löschen, um diesen Anhang zu entfernen.',
|
'attachments_delete_confirm' => 'Klicken Sie erneut auf löschen, um diesen Anhang zu entfernen.',
|
||||||
'attachments_dropzone' => 'Ziehen Sie Dateien hier hinein oder klicken Sie hier, um eine Datei auszuwählen',
|
'attachments_dropzone' => 'Ziehen Sie Dateien hierher oder klicken Sie, um eine Datei auszuwählen',
|
||||||
'attachments_no_files' => 'Es wurden bisher keine Dateien hochgeladen.',
|
'attachments_no_files' => 'Es wurden bisher keine Dateien hochgeladen.',
|
||||||
'attachments_explain_link' => 'Wenn Sie keine Datei hochladen möchten, können Sie stattdessen einen Link anfügen. Dieser Link kann auf eine andere Seite oder zu einer Datei in der Cloud weisen.',
|
'attachments_explain_link' => 'Wenn Sie keine Datei hochladen möchten, können Sie stattdessen einen Link hinzufügen. Dieser Link kann auf eine andere Seite oder eine Datei im Internet weisen.',
|
||||||
'attachments_link_name' => 'Link-Name',
|
'attachments_link_name' => 'Link-Name',
|
||||||
'attachment_link' => 'Link zum Anhang',
|
'attachment_link' => 'Link zum Anhang',
|
||||||
'attachments_link_url' => 'Link zu einer Datei',
|
'attachments_link_url' => 'Link zu einer Datei',
|
||||||
'attachments_link_url_hint' => 'URL einer Seite oder Datei',
|
'attachments_link_url_hint' => 'URL einer Seite oder Datei',
|
||||||
'attach' => 'anfügen',
|
'attach' => 'Hinzufügen',
|
||||||
'attachments_edit_file' => 'Datei bearbeiten',
|
'attachments_edit_file' => 'Datei bearbeiten',
|
||||||
'attachments_edit_file_name' => 'Dateiname',
|
'attachments_edit_file_name' => 'Dateiname',
|
||||||
'attachments_edit_drop_upload' => 'Ziehen Sie Dateien hier hinein, um diese hochzuladen und zu überschreiben',
|
'attachments_edit_drop_upload' => 'Ziehen Sie Dateien hierher, um diese hochzuladen und zu überschreiben',
|
||||||
'attachments_order_updated' => 'Reihenfolge der Anhänge aktualisiert',
|
'attachments_order_updated' => 'Reihenfolge der Anhänge aktualisiert',
|
||||||
'attachments_updated_success' => 'Anhang-Details aktualisiert',
|
'attachments_updated_success' => 'Anhangdetails aktualisiert',
|
||||||
'attachments_deleted' => 'Anhang gelöscht',
|
'attachments_deleted' => 'Anhang gelöscht',
|
||||||
'attachments_file_uploaded' => 'Datei erfolgrecich hochgeladen',
|
'attachments_file_uploaded' => 'Datei erfolgreich hochgeladen',
|
||||||
'attachments_file_updated' => 'Datei erfolgreich aktualisisert',
|
'attachments_file_updated' => 'Datei erfolgreich aktualisiert',
|
||||||
'attachments_link_attached' => 'Link erfolgreich der Seite hinzugefügt',
|
'attachments_link_attached' => 'Link erfolgreich der Seite hinzugefügt',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Profile View
|
* Profile View
|
||||||
*/
|
*/
|
||||||
'profile_user_for_x' => 'Benutzer seit :time',
|
'profile_user_for_x' => 'Benutzer seit :time',
|
||||||
'profile_created_content' => 'Angelegte Inhalte',
|
'profile_created_content' => 'Erstellte Inhalte',
|
||||||
'profile_not_created_pages' => ':userName hat bisher keine Seiten angelegt.',
|
'profile_not_created_pages' => ':userName hat noch keine Seiten erstellt.',
|
||||||
'profile_not_created_chapters' => ':userName hat bisher keine Kapitel angelegt.',
|
'profile_not_created_chapters' => ':userName hat noch keine Kapitel erstellt.',
|
||||||
'profile_not_created_books' => ':userName hat bisher keine Bücher angelegt.',
|
'profile_not_created_books' => ':userName hat noch keine Bücher erstellt.',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comnents
|
||||||
|
*/
|
||||||
|
'comment' => 'Kommentar',
|
||||||
|
'comments' => 'Kommentare',
|
||||||
|
'comment_placeholder' => 'Geben Sie hier Ihre Kommentare ein (Markdown unterstützt)',
|
||||||
|
'no_comments' => 'Keine Kommentare',
|
||||||
|
'x_comments' => ':numComments Kommentare',
|
||||||
|
'one_comment' => '1 Kommentar',
|
||||||
|
'comments_loading' => 'Laden...',
|
||||||
|
'comment_save' => 'Kommentar speichern',
|
||||||
|
'comment_reply' => 'Antworten',
|
||||||
|
'comment_edit' => 'Bearbeiten',
|
||||||
|
'comment_delete' => 'Löschen',
|
||||||
|
'comment_cancel' => 'Abbrechen',
|
||||||
|
'comment_created' => 'Kommentar hinzugefügt',
|
||||||
|
'comment_updated' => 'Kommentar aktualisiert',
|
||||||
|
'comment_deleted' => 'Kommentar gelöscht',
|
||||||
|
'comment_updated_text' => 'Aktualisiert vor :updateDiff von',
|
||||||
|
'comment_delete_confirm' => 'Der Inhalt des Kommentars wird entfernt. Bist du sicher, dass du diesen Kommentar löschen möchtest?',
|
||||||
|
'comment_create' => 'Erstellt'
|
||||||
|
|
||||||
];
|
];
|
@ -7,37 +7,37 @@ return [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
'permission' => 'Sie haben keine Berechtigung auf diese Seite zuzugreifen.',
|
'permission' => 'Sie haben keine Berechtigung, auf diese Seite zuzugreifen.',
|
||||||
'permissionJson' => 'Sie haben keine Berechtigung die angeforderte Aktion auszuführen.',
|
'permissionJson' => 'Sie haben keine Berechtigung, die angeforderte Aktion auszuführen.',
|
||||||
|
|
||||||
// Auth
|
// Auth
|
||||||
'error_user_exists_different_creds' => 'Ein Benutzer mit der E-Mail-Adresse :email ist bereits mit anderen Anmeldedaten angelegt.',
|
'error_user_exists_different_creds' => 'Ein Benutzer mit der E-Mail-Adresse :email ist bereits mit anderen Anmeldedaten registriert.',
|
||||||
'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melden Sie sich an.',
|
'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melden Sie sich an.',
|
||||||
'email_confirmation_invalid' => 'Der Bestätigungs-Token ist nicht gültig oder wurde bereits verwendet. Bitte registrieren Sie sich erneut.',
|
'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registrieren Sie sich erneut.',
|
||||||
'email_confirmation_expired' => 'Der Bestätigungs-Token ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.',
|
'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.',
|
||||||
'ldap_fail_anonymous' => 'Anonymer LDAP Zugriff ist fehlgeschlafgen',
|
'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen',
|
||||||
'ldap_fail_authed' => 'LDAP Zugriff mit DN & Passwort ist fehlgeschlagen',
|
'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen',
|
||||||
'ldap_extension_not_installed' => 'LDAP PHP Erweiterung ist nicht installiert.',
|
'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.',
|
||||||
'ldap_cannot_connect' => 'Die Verbindung zu LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf.',
|
'ldap_cannot_connect' => 'Die Verbindung zum LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf.',
|
||||||
'social_no_action_defined' => 'Es ist keine Aktion definiert',
|
'social_no_action_defined' => 'Es ist keine Aktion definiert',
|
||||||
'social_account_in_use' => 'Dieses :socialAccount Konto wird bereits verwendet. Bitte melden Sie sich mit dem :socialAccount Konto an.',
|
'social_account_in_use' => 'Dieses :socialAccount-Konto wird bereits verwendet. Bitte melden Sie sich mit dem :socialAccount-Konto an.',
|
||||||
'social_account_email_in_use' => 'Die E-Mail-Adresse :email ist bereits registriert. Wenn Sie bereits registriert sind, können Sie Ihr :socialAccount Konto in Ihren Profil-Einstellungen verknüpfen.',
|
'social_account_email_in_use' => 'Die E-Mail-Adresse ":email" ist bereits registriert. Wenn Sie bereits registriert sind, können Sie Ihr :socialAccount-Konto in Ihren Profil-Einstellungen verknüpfen.',
|
||||||
'social_account_existing' => 'Dieses :socialAccount Konto ist bereits mit Ihrem Profil verknüpft.',
|
'social_account_existing' => 'Dieses :socialAccount-Konto ist bereits mit Ihrem Profil verknüpft.',
|
||||||
'social_account_already_used_existing' => 'Dieses :socialAccount Konto wird bereits durch einen anderen Benutzer verwendet.',
|
'social_account_already_used_existing' => 'Dieses :socialAccount-Konto wird bereits von einem anderen Benutzer verwendet.',
|
||||||
'social_account_not_used' => 'Dieses :socialAccount Konto ist bisher keinem Benutzer zugeordnet. Bitte verknüpfen Sie deses in Ihrem Profil-Einstellungen.',
|
'social_account_not_used' => 'Dieses :socialAccount-Konto ist bisher keinem Benutzer zugeordnet. Sie können es in Ihren Profil-Einstellung.',
|
||||||
'social_account_register_instructions' => 'Wenn Sie bisher keinen Social-Media Konto besitzen können Sie ein solches Konto mit der :socialAccount Option anlegen.',
|
'social_account_register_instructions' => 'Wenn Sie bisher keinen Social-Media Konto besitzen, können Sie ein solches Konto mit der :socialAccount Option anlegen.',
|
||||||
'social_driver_not_found' => 'Social-Media Konto Treiber nicht gefunden',
|
'social_driver_not_found' => 'Treiber für Social-Media-Konten nicht gefunden',
|
||||||
'social_driver_not_configured' => 'Ihr :socialAccount Konto ist nicht korrekt konfiguriert.',
|
'social_driver_not_configured' => 'Ihr :socialAccount-Konto ist nicht korrekt konfiguriert.',
|
||||||
|
|
||||||
// System
|
// System
|
||||||
'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stellen Sie sicher, dass dieser Ordner auf dem Server beschreibbar ist.',
|
'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stellen Sie sicher, dass dieser Ordner auf dem Server beschreibbar ist.',
|
||||||
'cannot_get_image_from_url' => 'Bild konnte nicht von der URL :url geladen werden.',
|
'cannot_get_image_from_url' => 'Bild konnte nicht von der URL :url geladen werden.',
|
||||||
'cannot_create_thumbs' => 'Der Server kann keine Vorschau-Bilder erzeugen. Bitte prüfen Sie, ob Sie die GD PHP Erweiterung installiert haben.',
|
'cannot_create_thumbs' => 'Der Server kann keine Vorschau-Bilder erzeugen. Bitte prüfen Sie, ob die GD PHP-Erweiterung installiert ist.',
|
||||||
'server_upload_limit' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuchen Sie es mit einer kleineren Datei.',
|
'server_upload_limit' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuchen Sie es mit einer kleineren Datei.',
|
||||||
'image_upload_error' => 'Beim Hochladen des Bildes trat ein Fehler auf.',
|
'image_upload_error' => 'Beim Hochladen des Bildes trat ein Fehler auf.',
|
||||||
|
|
||||||
// Attachments
|
// Attachments
|
||||||
'attachment_page_mismatch' => 'Die Seite stimmt nach dem Hochladen des Anhangs nicht überein.',
|
'attachment_page_mismatch' => 'Die Seite stimmte nach dem Hochladen des Anhangs nicht überein.',
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
'page_draft_autosave_fail' => 'Fehler beim Speichern des Entwurfs. Stellen Sie sicher, dass Sie mit dem Internet verbunden sind, bevor Sie den Entwurf dieser Seite speichern.',
|
'page_draft_autosave_fail' => 'Fehler beim Speichern des Entwurfs. Stellen Sie sicher, dass Sie mit dem Internet verbunden sind, bevor Sie den Entwurf dieser Seite speichern.',
|
||||||
@ -47,24 +47,31 @@ return [
|
|||||||
'book_not_found' => 'Buch nicht gefunden',
|
'book_not_found' => 'Buch nicht gefunden',
|
||||||
'page_not_found' => 'Seite nicht gefunden',
|
'page_not_found' => 'Seite nicht gefunden',
|
||||||
'chapter_not_found' => 'Kapitel nicht gefunden',
|
'chapter_not_found' => 'Kapitel nicht gefunden',
|
||||||
'selected_book_not_found' => 'Das gewählte Buch wurde nicht gefunden.',
|
'selected_book_not_found' => 'Das gewählte Buch wurde nicht gefunden.',
|
||||||
'selected_book_chapter_not_found' => 'Das gewählte Buch oder Kapitel wurde nicht gefunden.',
|
'selected_book_chapter_not_found' => 'Das gewählte Buch oder Kapitel wurde nicht gefunden.',
|
||||||
'guests_cannot_save_drafts' => 'Gäste können keine Entwürfe speichern',
|
'guests_cannot_save_drafts' => 'Gäste können keine Entwürfe speichern',
|
||||||
|
|
||||||
// Users
|
// Users
|
||||||
'users_cannot_delete_only_admin' => 'Sie können den einzigen Administrator nicht löschen.',
|
'users_cannot_delete_only_admin' => 'Sie können den einzigen Administrator nicht löschen.',
|
||||||
'users_cannot_delete_guest' => 'Sie können den Gast-Benutzer nicht löschen',
|
'users_cannot_delete_guest' => 'Sie können den Gast-Benutzer nicht löschen',
|
||||||
|
|
||||||
// Roles
|
// Roles
|
||||||
'role_cannot_be_edited' => 'Diese Rolle kann nicht bearbeitet werden.',
|
'role_cannot_be_edited' => 'Diese Rolle kann nicht bearbeitet werden.',
|
||||||
'role_system_cannot_be_deleted' => 'Dies ist eine Systemrolle und kann nicht gelöscht werden',
|
'role_system_cannot_be_deleted' => 'Dies ist eine Systemrolle und kann nicht gelöscht werden',
|
||||||
'role_registration_default_cannot_delete' => 'Diese Rolle kann nicht gelöscht werden solange sie als Standardrolle für neue Registrierungen gesetzt ist',
|
'role_registration_default_cannot_delete' => 'Diese Rolle kann nicht gelöscht werden, solange sie als Standardrolle für neue Registrierungen gesetzt ist',
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
'comment_list' => 'Beim Abrufen der Kommentare ist ein Fehler aufgetreten.',
|
||||||
|
'cannot_add_comment_to_draft' => 'Du kannst keine Kommentare zu einem Entwurf hinzufügen.',
|
||||||
|
'comment_add' => 'Beim Hinzufügen des Kommentars ist ein Fehler aufgetreten.',
|
||||||
|
'comment_delete' => 'Beim Löschen des Kommentars ist ein Fehler aufgetreten.',
|
||||||
|
'empty_comment' => 'Kann keinen leeren Kommentar hinzufügen',
|
||||||
|
|
||||||
// Error pages
|
// Error pages
|
||||||
'404_page_not_found' => 'Seite nicht gefunden',
|
'404_page_not_found' => 'Seite nicht gefunden',
|
||||||
'sorry_page_not_found' => 'Entschuldigung. Die Seite, die Sie angefordert haben wurde nicht gefunden.',
|
'sorry_page_not_found' => 'Entschuldigung. Die Seite, die Sie angefordert haben, wurde nicht gefunden.',
|
||||||
'return_home' => 'Zurück zur Startseite',
|
'return_home' => 'Zurück zur Startseite',
|
||||||
'error_occurred' => 'Es ist ein Fehler aufgetreten',
|
'error_occurred' => 'Es ist ein Fehler aufgetreten',
|
||||||
'app_down' => ':appName befindet sich aktuell im Wartungsmodus.',
|
'app_down' => ':appName befindet sich aktuell im Wartungsmodus.',
|
||||||
'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.',
|
'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.'
|
||||||
];
|
];
|
||||||
|
@ -14,6 +14,6 @@ return [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
'previous' => '« Vorherige',
|
'previous' => '« Vorherige',
|
||||||
'next' => 'Nächste »',
|
'next' => 'Nächste »',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -13,10 +13,10 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'password' => 'Passörter müssen mindestens sechs Zeichen enthalten und die Wiederholung muss identisch sein.',
|
'password' => 'Passörter müssen mindestens sechs Zeichen enthalten und die Wiederholung muss übereinstimmen.',
|
||||||
'user' => "Wir können keinen Benutzer mit dieser E-Mail Adresse finden.",
|
'user' => "Es konnte kein Benutzer mit dieser E-Mail-Adresse gefunden werden.",
|
||||||
'token' => 'Dieser Passwort-Reset-Token ist ungültig.',
|
'token' => 'Dieser Link zum Zurücksetzen des Passwortes ist ungültig.',
|
||||||
'sent' => 'Wir haben Ihnen eine E-Mail mit einem Link zum Zurücksetzen des Passworts zugesendet!',
|
'sent' => 'Wir haben Ihnen eine E-Mail mit einem Link zum Zurücksetzen des Passworts zugesendet!',
|
||||||
'reset' => 'Ihr Passwort wurde zurückgesetzt!',
|
'reset' => 'Ihr Passwort wurde zurückgesetzt!',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -20,17 +20,17 @@ return [
|
|||||||
'app_name' => 'Anwendungsname',
|
'app_name' => 'Anwendungsname',
|
||||||
'app_name_desc' => 'Dieser Name wird im Header und in E-Mails angezeigt.',
|
'app_name_desc' => 'Dieser Name wird im Header und in E-Mails angezeigt.',
|
||||||
'app_name_header' => 'Anwendungsname im Header anzeigen?',
|
'app_name_header' => 'Anwendungsname im Header anzeigen?',
|
||||||
'app_public_viewing' => 'Öffentliche Ansicht erlauben?',
|
'app_public_viewing' => 'Öffentliche Ansicht erlauben?',
|
||||||
'app_secure_images' => 'Erhöhte Sicherheit für Bilduploads aktivieren?',
|
'app_secure_images' => 'Erhöhte Sicherheit für hochgeladene Bilder aktivieren?',
|
||||||
'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten vor die Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnindexes deaktiviert sind, um einen einfachen Zugriff zu verhindern.',
|
'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten zu Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnisindizes deaktiviert sind, um einen einfachen Zugriff zu verhindern.',
|
||||||
'app_editor' => 'Seiteneditor',
|
'app_editor' => 'Seiteneditor',
|
||||||
'app_editor_desc' => 'Wählen sie den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.',
|
'app_editor_desc' => 'Wählen Sie den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.',
|
||||||
'app_custom_html' => 'Benutzerdefinierter HTML <head> Inhalt',
|
'app_custom_html' => 'Benutzerdefinierter HTML <head> Inhalt',
|
||||||
'app_custom_html_desc' => 'Jeder Inhalt, der hier hinzugefügt wird, wird am Ende der <head> Sektion jeder Seite eingefügt. Diese kann praktisch sein, um CSS Styles anzupassen oder Analytics Code hinzuzufügen.',
|
'app_custom_html_desc' => 'Jeder Inhalt, der hier hinzugefügt wird, wird am Ende der <head> Sektion jeder Seite eingefügt. Diese kann praktisch sein, um CSS Styles anzupassen oder Analytics-Code hinzuzufügen.',
|
||||||
'app_logo' => 'Anwendungslogo',
|
'app_logo' => 'Anwendungslogo',
|
||||||
'app_logo_desc' => 'Dieses Bild sollte 43px hoch sein. <br>Größere Bilder werden verkleinert.',
|
'app_logo_desc' => "Dieses Bild sollte 43px hoch sein.\nGrößere Bilder werden verkleinert.",
|
||||||
'app_primary_color' => 'Primäre Anwendungsfarbe',
|
'app_primary_color' => 'Primäre Anwendungsfarbe',
|
||||||
'app_primary_color_desc' => 'Dies sollte ein HEX Wert sein. <br>Wenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt.',
|
'app_primary_color_desc' => "Dies sollte ein HEX Wert sein.\nWenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt.",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registration settings
|
* Registration settings
|
||||||
@ -39,11 +39,11 @@ return [
|
|||||||
'reg_settings' => 'Registrierungseinstellungen',
|
'reg_settings' => 'Registrierungseinstellungen',
|
||||||
'reg_allow' => 'Registrierung erlauben?',
|
'reg_allow' => 'Registrierung erlauben?',
|
||||||
'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung',
|
'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung',
|
||||||
'reg_confirm_email' => 'Bestätigung per E-Mail erforderlich?',
|
'reg_confirm_email' => 'Bestätigung per E-Mail erforderlich?',
|
||||||
'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.',
|
'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.',
|
||||||
'reg_confirm_restrict_domain' => 'Registrierung auf bestimmte Domains einschränken',
|
'reg_confirm_restrict_domain' => 'Registrierung auf bestimmte Domains einschränken',
|
||||||
'reg_confirm_restrict_domain_desc' => 'Fügen sie eine, durch Komma getrennte, Liste von E-Mail Domains hinzu, auf die die Registrierung eingeschränkt werden soll. Benutzern wird eine E-Mail gesendet, um ihre E-Mail Adresse zu bestätigen, bevor sie diese Anwendung nutzen können. <br> Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung ändern.',
|
'reg_confirm_restrict_domain_desc' => "Fügen sie eine durch Komma getrennte Liste von Domains hinzu, auf die die Registrierung eingeschränkt werden soll. Benutzern wird eine E-Mail gesendet, um ihre E-Mail Adresse zu bestätigen, bevor sie diese Anwendung nutzen können.\nHinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung ändern.",
|
||||||
'reg_confirm_restrict_domain_placeholder' => 'Keine Einschränkung gesetzt',
|
'reg_confirm_restrict_domain_placeholder' => 'Keine Einschränkung gesetzt',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Role settings
|
* Role settings
|
||||||
@ -53,31 +53,31 @@ return [
|
|||||||
'role_user_roles' => 'Benutzer-Rollen',
|
'role_user_roles' => 'Benutzer-Rollen',
|
||||||
'role_create' => 'Neue Rolle anlegen',
|
'role_create' => 'Neue Rolle anlegen',
|
||||||
'role_create_success' => 'Rolle erfolgreich angelegt',
|
'role_create_success' => 'Rolle erfolgreich angelegt',
|
||||||
'role_delete' => 'Rolle löschen',
|
'role_delete' => 'Rolle löschen',
|
||||||
'role_delete_confirm' => 'Sie möchten die Rolle \':roleName\' löschen.',
|
'role_delete_confirm' => 'Sie möchten die Rolle ":roleName" löschen.',
|
||||||
'role_delete_users_assigned' => 'Diese Rolle ist :userCount Benutzern zugeordnet. Sie können unten eine neue Rolle auswählen, die Sie diesen Benutzern zuordnen möchten.',
|
'role_delete_users_assigned' => 'Diese Rolle ist :userCount Benutzern zugeordnet. Sie können unten eine neue Rolle auswählen, die Sie diesen Benutzern zuordnen möchten.',
|
||||||
'role_delete_no_migration' => "Den Benutzern keine andere Rolle zuordnen",
|
'role_delete_no_migration' => "Den Benutzern keine andere Rolle zuordnen",
|
||||||
'role_delete_sure' => 'Sind Sie sicher, dass Sie diese Rolle löschen möchten?',
|
'role_delete_sure' => 'Sind Sie sicher, dass Sie diese Rolle löschen möchten?',
|
||||||
'role_delete_success' => 'Rolle erfolgreich gelöscht',
|
'role_delete_success' => 'Rolle erfolgreich gelöscht',
|
||||||
'role_edit' => 'Rolle bearbeiten',
|
'role_edit' => 'Rolle bearbeiten',
|
||||||
'role_details' => 'Rollen-Details',
|
'role_details' => 'Rollendetails',
|
||||||
'role_name' => 'Rollenname',
|
'role_name' => 'Rollenname',
|
||||||
'role_desc' => 'Kurzbeschreibung der Rolle',
|
'role_desc' => 'Kurzbeschreibung der Rolle',
|
||||||
'role_system' => 'System-Berechtigungen',
|
'role_system' => 'System-Berechtigungen',
|
||||||
'role_manage_users' => 'Benutzer verwalten',
|
'role_manage_users' => 'Benutzer verwalten',
|
||||||
'role_manage_roles' => 'Rollen & Rollen-Berechtigungen verwalten',
|
'role_manage_roles' => 'Rollen und Rollen-Berechtigungen verwalten',
|
||||||
'role_manage_entity_permissions' => 'Alle Buch-, Kapitel und Seiten-Berechtigungen verwalten',
|
'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten',
|
||||||
'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten',
|
'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten',
|
||||||
'role_manage_settings' => 'Globaleinstellungen verwalrten',
|
'role_manage_settings' => 'Globaleinstellungen verwalten',
|
||||||
'role_asset' => 'Berechtigungen',
|
'role_asset' => 'Berechtigungen',
|
||||||
'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.',
|
'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.',
|
||||||
'role_all' => 'Alle',
|
'role_all' => 'Alle',
|
||||||
'role_own' => 'Eigene',
|
'role_own' => 'Eigene',
|
||||||
'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to',
|
'role_controlled_by_asset' => 'Berechtigungen werden vom Uploadziel bestimmt',
|
||||||
'role_save' => 'Rolle speichern',
|
'role_save' => 'Rolle speichern',
|
||||||
'role_update_success' => 'Rolle erfolgreich gespeichert',
|
'role_update_success' => 'Rolle erfolgreich gespeichert',
|
||||||
'role_users' => 'Dieser Rolle zugeordnete Benutzer',
|
'role_users' => 'Dieser Rolle zugeordnete Benutzer',
|
||||||
'role_users_none' => 'Bisher sind dieser Rolle keiner Benutzer zugeordnet,',
|
'role_users_none' => 'Bisher sind dieser Rolle keine Benutzer zugeordnet',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Users
|
* Users
|
||||||
@ -85,28 +85,28 @@ return [
|
|||||||
|
|
||||||
'users' => 'Benutzer',
|
'users' => 'Benutzer',
|
||||||
'user_profile' => 'Benutzerprofil',
|
'user_profile' => 'Benutzerprofil',
|
||||||
'users_add_new' => 'Benutzer hinzufügen',
|
'users_add_new' => 'Benutzer hinzufügen',
|
||||||
'users_search' => 'Benutzer suchen',
|
'users_search' => 'Benutzer suchen',
|
||||||
'users_role' => 'Benutzerrollen',
|
'users_role' => 'Benutzerrollen',
|
||||||
'users_external_auth_id' => 'Externe Authentifizierungs-ID',
|
'users_external_auth_id' => 'Externe Authentifizierungs-ID',
|
||||||
'users_password_warning' => 'Füllen Sie die folgenden Felder nur aus, wenn Sie Ihr Passwort ändern möchten:',
|
'users_password_warning' => 'Füllen Sie die folgenden Felder nur aus, wenn Sie Ihr Passwort ändern möchten:',
|
||||||
'users_system_public' => 'Dieser Benutzer repräsentiert alle Gast-Benutzer, die diese Seite betrachten. Er kann nicht zum Anmelden benutzt werden, sondern wird automatisch zugeordnet.',
|
'users_system_public' => 'Dieser Benutzer repräsentiert alle unangemeldeten Benutzer, die diese Seite betrachten. Er kann nicht zum Anmelden benutzt werden, sondern wird automatisch zugeordnet.',
|
||||||
|
'users_delete' => 'Benutzer löschen',
|
||||||
|
'users_delete_named' => 'Benutzer ":userName" löschen',
|
||||||
|
'users_delete_warning' => 'Der Benutzer ":userName" wird aus dem System gelöscht.',
|
||||||
|
'users_delete_confirm' => 'Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?',
|
||||||
|
'users_delete_success' => 'Benutzer erfolgreich gelöscht.',
|
||||||
'users_books_display_type' => 'Bevorzugtes Display-Layout für Bücher',
|
'users_books_display_type' => 'Bevorzugtes Display-Layout für Bücher',
|
||||||
'users_delete' => 'Benutzer löschen',
|
|
||||||
'users_delete_named' => 'Benutzer :userName löschen',
|
|
||||||
'users_delete_warning' => 'Sie möchten den Benutzer \':userName\' gänzlich aus dem System löschen.',
|
|
||||||
'users_delete_confirm' => 'Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?',
|
|
||||||
'users_delete_success' => 'Benutzer erfolgreich gelöscht.',
|
|
||||||
'users_edit' => 'Benutzer bearbeiten',
|
'users_edit' => 'Benutzer bearbeiten',
|
||||||
'users_edit_profile' => 'Profil bearbeiten',
|
'users_edit_profile' => 'Profil bearbeiten',
|
||||||
'users_edit_success' => 'Benutzer erfolgreich aktualisisert',
|
'users_edit_success' => 'Benutzer erfolgreich aktualisisert',
|
||||||
'users_avatar' => 'Benutzer-Bild',
|
'users_avatar' => 'Benutzer-Bild',
|
||||||
'users_avatar_desc' => 'Dieses Bild sollte einen Durchmesser von ca. 256px haben.',
|
'users_avatar_desc' => 'Das Bild sollte eine Auflösung von 256x256px haben.',
|
||||||
'users_preferred_language' => 'Bevorzugte Sprache',
|
'users_preferred_language' => 'Bevorzugte Sprache',
|
||||||
'users_social_accounts' => 'Social-Media Konten',
|
'users_social_accounts' => 'Social-Media Konten',
|
||||||
'users_social_accounts_info' => 'Hier können Sie andere Social-Media Konten für eine schnellere und einfachere Anmeldung verknüpfen. Wenn Sie ein Social-Media Konto hier lösen, bleibt der Zugriff erhalteb. Entfernen Sie in diesem Falle die Berechtigung in Ihren Profil-Einstellungen des verknüpften Social-Media Kontos.',
|
'users_social_accounts_info' => 'Hier können Sie andere Social-Media-Konten für eine schnellere und einfachere Anmeldung verknüpfen. Wenn Sie ein Social-Media Konto lösen, bleibt der Zugriff erhalten. Entfernen Sie in diesem Falle die Berechtigung in Ihren Profil-Einstellungen des verknüpften Social-Media-Kontos.',
|
||||||
'users_social_connect' => 'Social-Media Konto verknüpfen',
|
'users_social_connect' => 'Social-Media-Konto verknüpfen',
|
||||||
'users_social_disconnect' => 'Social-Media Kontoverknüpfung lösen',
|
'users_social_disconnect' => 'Social-Media-Konto lösen',
|
||||||
'users_social_connected' => ':socialAccount Konto wurde erfolgreich mit dem Profil verknüpft.',
|
'users_social_connected' => ':socialAccount-Konto wurde erfolgreich mit dem Profil verknüpft.',
|
||||||
'users_social_disconnected' => ':socialAccount Konto wurde erfolgreich vom Profil gelöst.',
|
'users_social_disconnected' => ':socialAccount-Konto wurde erfolgreich vom Profil gelöst.',
|
||||||
];
|
];
|
||||||
|
@ -19,54 +19,54 @@ return [
|
|||||||
'alpha' => ':attribute kann nur Buchstaben enthalten.',
|
'alpha' => ':attribute kann nur Buchstaben enthalten.',
|
||||||
'alpha_dash' => ':attribute kann nur Buchstaben, Zahlen und Bindestriche enthalten.',
|
'alpha_dash' => ':attribute kann nur Buchstaben, Zahlen und Bindestriche enthalten.',
|
||||||
'alpha_num' => ':attribute kann nur Buchstaben und Zahlen enthalten.',
|
'alpha_num' => ':attribute kann nur Buchstaben und Zahlen enthalten.',
|
||||||
'array' => ':attribute muss eine Array sein.',
|
'array' => ':attribute muss ein Array sein.',
|
||||||
'before' => ':attribute muss ein Datum vor :date sein.',
|
'before' => ':attribute muss ein Datum vor :date sein.',
|
||||||
'between' => [
|
'between' => [
|
||||||
'numeric' => ':attribute muss zwischen :min und :max liegen.',
|
'numeric' => ':attribute muss zwischen :min und :max liegen.',
|
||||||
'file' => ':attribute muss zwischen :min und :max Kilobytes groß sein.',
|
'file' => ':attribute muss zwischen :min und :max Kilobytes groß sein.',
|
||||||
'string' => ':attribute muss zwischen :min und :max Zeichen lang sein.',
|
'string' => ':attribute muss zwischen :min und :max Zeichen lang sein.',
|
||||||
'array' => ':attribute muss zwischen :min und :max Elemente enthalten.',
|
'array' => ':attribute muss zwischen :min und :max Elemente enthalten.',
|
||||||
],
|
],
|
||||||
'boolean' => ':attribute Feld muss wahr oder falsch sein.',
|
'boolean' => ':attribute Feld muss wahr oder falsch sein.',
|
||||||
'confirmed' => ':attribute Bestätigung stimmt nicht überein.',
|
'confirmed' => ':attribute stimmt nicht überein.',
|
||||||
'date' => ':attribute ist kein valides Datum.',
|
'date' => ':attribute ist kein valides Datum.',
|
||||||
'date_format' => ':attribute entspricht nicht dem Format :format.',
|
'date_format' => ':attribute entspricht nicht dem Format :format.',
|
||||||
'different' => ':attribute und :other müssen unterschiedlich sein.',
|
'different' => ':attribute und :other müssen unterschiedlich sein.',
|
||||||
'digits' => ':attribute muss :digits Stellen haben.',
|
'digits' => ':attribute muss :digits Stellen haben.',
|
||||||
'digits_between' => ':attribute muss zwischen :min und :max Stellen haben.',
|
'digits_between' => ':attribute muss zwischen :min und :max Stellen haben.',
|
||||||
'email' => ':attribute muss eine valide E-Mail Adresse sein.',
|
'email' => ':attribute muss eine valide E-Mail-Adresse sein.',
|
||||||
'filled' => ':attribute Feld ist erforderlich.',
|
'filled' => ':attribute ist erforderlich.',
|
||||||
'exists' => 'Markiertes :attribute ist ungültig.',
|
'exists' => ':attribute ist ungültig.',
|
||||||
'image' => ':attribute muss ein Bild sein.',
|
'image' => ':attribute muss ein Bild sein.',
|
||||||
'in' => 'Markiertes :attribute ist ungültig.',
|
'in' => ':attribute ist ungültig.',
|
||||||
'integer' => ':attribute muss eine Zahl sein.',
|
'integer' => ':attribute muss eine Zahl sein.',
|
||||||
'ip' => ':attribute muss eine valide IP-Adresse sein.',
|
'ip' => ':attribute muss eine valide IP-Adresse sein.',
|
||||||
'max' => [
|
'max' => [
|
||||||
'numeric' => ':attribute darf nicht größer als :max sein.',
|
'numeric' => ':attribute darf nicht größer als :max sein.',
|
||||||
'file' => ':attribute darf nicht größer als :max Kilobyte sein.',
|
'file' => ':attribute darf nicht größer als :max Kilobyte sein.',
|
||||||
'string' => ':attribute darf nicht länger als :max Zeichen sein.',
|
'string' => ':attribute darf nicht länger als :max Zeichen sein.',
|
||||||
'array' => ':attribute darf nicht mehr als :max Elemente enthalten.',
|
'array' => ':attribute darf nicht mehr als :max Elemente enthalten.',
|
||||||
],
|
],
|
||||||
'mimes' => ':attribute muss eine Datei vom Typ: :values sein.',
|
'mimes' => ':attribute muss eine Datei vom Typ: :values sein.',
|
||||||
'min' => [
|
'min' => [
|
||||||
'numeric' => ':attribute muss mindestens :min. sein',
|
'numeric' => ':attribute muss mindestens :min sein',
|
||||||
'file' => ':attribute muss mindestens :min Kilobyte groß sein.',
|
'file' => ':attribute muss mindestens :min Kilobyte groß sein.',
|
||||||
'string' => ':attribute muss mindestens :min Zeichen lang sein.',
|
'string' => ':attribute muss mindestens :min Zeichen lang sein.',
|
||||||
'array' => ':attribute muss mindesten :min Elemente enthalten.',
|
'array' => ':attribute muss mindesten :min Elemente enthalten.',
|
||||||
],
|
],
|
||||||
'not_in' => 'Markiertes :attribute ist ungültig.',
|
'not_in' => ':attribute ist ungültig.',
|
||||||
'numeric' => ':attribute muss eine Zahl sein.',
|
'numeric' => ':attribute muss eine Zahl sein.',
|
||||||
'regex' => ':attribute Format ist ungültig.',
|
'regex' => ':attribute ist in einem ungültigen Format.',
|
||||||
'required' => ':attribute Feld ist erforderlich.',
|
'required' => ':attribute ist erforderlich.',
|
||||||
'required_if' => ':attribute Feld ist erforderlich, wenn :other :value ist.',
|
'required_if' => ':attribute ist erforderlich, wenn :other :value ist.',
|
||||||
'required_with' => ':attribute Feld ist erforderlich, wenn :values vorhanden ist.',
|
'required_with' => ':attribute ist erforderlich, wenn :values vorhanden ist.',
|
||||||
'required_with_all' => ':attribute Feld ist erforderlich, wenn :values vorhanden sind.',
|
'required_with_all' => ':attribute ist erforderlich, wenn :values vorhanden sind.',
|
||||||
'required_without' => ':attribute Feld ist erforderlich, wenn :values nicht vorhanden ist.',
|
'required_without' => ':attribute ist erforderlich, wenn :values nicht vorhanden ist.',
|
||||||
'required_without_all' => ':attribute Feld ist erforderlich, wenn :values nicht vorhanden sind.',
|
'required_without_all' => ':attribute ist erforderlich, wenn :values nicht vorhanden sind.',
|
||||||
'same' => ':attribute und :other muss übereinstimmen.',
|
'same' => ':attribute und :other müssen übereinstimmen.',
|
||||||
'size' => [
|
'size' => [
|
||||||
'numeric' => ':attribute muss :size sein.',
|
'numeric' => ':attribute muss :size sein.',
|
||||||
'file' => ':attribute muss :size Kilobytes groß sein.',
|
'file' => ':attribute muss :size Kilobytes groß sein.',
|
||||||
'string' => ':attribute muss :size Zeichen lang sein.',
|
'string' => ':attribute muss :size Zeichen lang sein.',
|
||||||
'array' => ':attribute muss :size Elemente enthalten.',
|
'array' => ':attribute muss :size Elemente enthalten.',
|
||||||
],
|
],
|
||||||
|
@ -234,4 +234,27 @@ return [
|
|||||||
'profile_not_created_pages' => ':userName has not created any pages',
|
'profile_not_created_pages' => ':userName has not created any pages',
|
||||||
'profile_not_created_chapters' => ':userName has not created any chapters',
|
'profile_not_created_chapters' => ':userName has not created any chapters',
|
||||||
'profile_not_created_books' => ':userName has not created any books',
|
'profile_not_created_books' => ':userName has not created any books',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comments
|
||||||
|
*/
|
||||||
|
'comment' => 'Comment',
|
||||||
|
'comments' => 'Comments',
|
||||||
|
'comment_placeholder' => 'Enter your comments here, markdown supported...',
|
||||||
|
'no_comments' => 'No Comments',
|
||||||
|
'x_comments' => ':numComments Comments',
|
||||||
|
'one_comment' => '1 Comment',
|
||||||
|
'comments_loading' => 'Loading...',
|
||||||
|
'comment_save' => 'Save Comment',
|
||||||
|
'comment_reply' => 'Reply',
|
||||||
|
'comment_edit' => 'Edit',
|
||||||
|
'comment_delete' => 'Delete',
|
||||||
|
'comment_cancel' => 'Cancel',
|
||||||
|
'comment_created' => 'Comment added',
|
||||||
|
'comment_updated' => 'Comment updated',
|
||||||
|
'comment_deleted' => 'Comment deleted',
|
||||||
|
'comment_updated_text' => 'Updated :updateDiff by',
|
||||||
|
'comment_delete_confirm' => 'This will remove the contents of the comment. Are you sure you want to delete this comment?',
|
||||||
|
'comment_create' => 'Created'
|
||||||
|
|
||||||
];
|
];
|
@ -60,6 +60,13 @@ return [
|
|||||||
'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted',
|
'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted',
|
||||||
'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role',
|
'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role',
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
'comment_list' => 'An error occurred while fetching the comments.',
|
||||||
|
'cannot_add_comment_to_draft' => 'You cannot add comments to a draft.',
|
||||||
|
'comment_add' => 'An error occurred while adding the comment.',
|
||||||
|
'comment_delete' => 'An error occurred while deleting the comment.',
|
||||||
|
'empty_comment' => 'Cannot add an empty comment.',
|
||||||
|
|
||||||
// Error pages
|
// Error pages
|
||||||
'404_page_not_found' => 'Page Not Found',
|
'404_page_not_found' => 'Page Not Found',
|
||||||
'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.',
|
'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.',
|
||||||
|
@ -123,6 +123,7 @@ return [
|
|||||||
'pt_BR' => 'Português do Brasil',
|
'pt_BR' => 'Português do Brasil',
|
||||||
'sk' => 'Slovensky',
|
'sk' => 'Slovensky',
|
||||||
'ja' => '日本語',
|
'ja' => '日本語',
|
||||||
|
'pl' => 'Polski',
|
||||||
]
|
]
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
];
|
];
|
||||||
|
@ -214,4 +214,26 @@ return [
|
|||||||
'profile_not_created_pages' => ':userName no ha creado ninguna página',
|
'profile_not_created_pages' => ':userName no ha creado ninguna página',
|
||||||
'profile_not_created_chapters' => ':userName no ha creado ningún capítulo',
|
'profile_not_created_chapters' => ':userName no ha creado ningún capítulo',
|
||||||
'profile_not_created_books' => ':userName no ha creado ningún libro',
|
'profile_not_created_books' => ':userName no ha creado ningún libro',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comments
|
||||||
|
*/
|
||||||
|
'comment' => 'Comentario',
|
||||||
|
'comments' => 'Comentarios',
|
||||||
|
'comment_placeholder' => 'Introduzca sus comentarios aquí, markdown supported ...',
|
||||||
|
'no_comments' => 'No hay comentarios',
|
||||||
|
'x_comments' => ':numComments Comentarios',
|
||||||
|
'one_comment' => '1 Comentario',
|
||||||
|
'comments_loading' => 'Cargando ...',
|
||||||
|
'comment_save' => 'Guardar comentario',
|
||||||
|
'comment_reply' => 'Responder',
|
||||||
|
'comment_edit' => 'Editar',
|
||||||
|
'comment_delete' => 'Eliminar',
|
||||||
|
'comment_cancel' => 'Cancelar',
|
||||||
|
'comment_created' => 'Comentario añadido',
|
||||||
|
'comment_updated' => 'Comentario actualizado',
|
||||||
|
'comment_deleted' => 'Comentario eliminado',
|
||||||
|
'comment_updated_text' => 'Actualizado hace :updateDiff por',
|
||||||
|
'comment_delete_confirm' => 'Esto eliminará el contenido del comentario. ¿Estás seguro de que quieres eliminar este comentario?',
|
||||||
|
'comment_create' => 'Creado'
|
||||||
];
|
];
|
||||||
|
@ -67,4 +67,11 @@ return [
|
|||||||
'error_occurred' => 'Ha ocurrido un error',
|
'error_occurred' => 'Ha ocurrido un error',
|
||||||
'app_down' => 'La aplicación :appName se encuentra caída en este momento',
|
'app_down' => 'La aplicación :appName se encuentra caída en este momento',
|
||||||
'back_soon' => 'Volverá a estar operativa en corto tiempo.',
|
'back_soon' => 'Volverá a estar operativa en corto tiempo.',
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
'comment_list' => 'Se ha producido un error al buscar los comentarios.',
|
||||||
|
'cannot_add_comment_to_draft' => 'No puedes añadir comentarios a un borrador.',
|
||||||
|
'comment_add' => 'Se ha producido un error al añadir el comentario.',
|
||||||
|
'comment_delete' => 'Se ha producido un error al eliminar el comentario.',
|
||||||
|
'empty_comment' => 'No se puede agregar un comentario vacío.',
|
||||||
];
|
];
|
||||||
|
@ -10,7 +10,7 @@ return [
|
|||||||
| these language lines according to your application's requirements.
|
| these language lines according to your application's requirements.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
'failed' => 'Ces informations ne correspondent a aucun compte.',
|
'failed' => 'Ces informations ne correspondent à aucun compte.',
|
||||||
'throttle' => "Trop d'essais, veuillez réessayer dans :seconds secondes.",
|
'throttle' => "Trop d'essais, veuillez réessayer dans :seconds secondes.",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,9 +35,9 @@ return [
|
|||||||
'social_registration_text' => "S'inscrire et se connecter avec un réseau social",
|
'social_registration_text' => "S'inscrire et se connecter avec un réseau social",
|
||||||
|
|
||||||
'register_thanks' => 'Merci pour votre enregistrement',
|
'register_thanks' => 'Merci pour votre enregistrement',
|
||||||
'register_confirm' => 'Vérifiez vos e-mails et cliquer sur le lien de confirmation pour rejoindre :appName.',
|
'register_confirm' => 'Vérifiez vos e-mails et cliquez sur le lien de confirmation pour rejoindre :appName.',
|
||||||
'registrations_disabled' => "L'inscription est désactivée pour le moment",
|
'registrations_disabled' => "L'inscription est désactivée pour le moment",
|
||||||
'registration_email_domain_invalid' => 'Cette adresse e-mail ne peux pas adcéder à l\'application',
|
'registration_email_domain_invalid' => 'Cette adresse e-mail ne peut pas accéder à l\'application',
|
||||||
'register_success' => 'Merci pour votre inscription. Vous êtes maintenant inscrit(e) et connecté(e)',
|
'register_success' => 'Merci pour votre inscription. Vous êtes maintenant inscrit(e) et connecté(e)',
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ return [
|
|||||||
'back' => 'Retour',
|
'back' => 'Retour',
|
||||||
'save' => 'Enregistrer',
|
'save' => 'Enregistrer',
|
||||||
'continue' => 'Continuer',
|
'continue' => 'Continuer',
|
||||||
'select' => 'Selectionner',
|
'select' => 'Sélectionner',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form Labels
|
* Form Labels
|
||||||
@ -55,6 +55,6 @@ return [
|
|||||||
/**
|
/**
|
||||||
* Email Content
|
* Email Content
|
||||||
*/
|
*/
|
||||||
'email_action_help' => 'Si vous rencontrez des problèmes pour cliquer le bouton ":actionText", copiez et collez l\'adresse ci-dessous dans votre navigateur:',
|
'email_action_help' => 'Si vous rencontrez des problèmes pour cliquer sur le bouton ":actionText", copiez et collez l\'adresse ci-dessous dans votre navigateur :',
|
||||||
'email_rights' => 'Tous droits réservés',
|
'email_rights' => 'Tous droits réservés',
|
||||||
];
|
];
|
||||||
|
@ -12,7 +12,7 @@ return [
|
|||||||
'recently_update' => 'Mis à jour récemment',
|
'recently_update' => 'Mis à jour récemment',
|
||||||
'recently_viewed' => 'Vus récemment',
|
'recently_viewed' => 'Vus récemment',
|
||||||
'recent_activity' => 'Activité récente',
|
'recent_activity' => 'Activité récente',
|
||||||
'create_now' => 'En créer un récemment',
|
'create_now' => 'En créer un maintenant',
|
||||||
'revisions' => 'Révisions',
|
'revisions' => 'Révisions',
|
||||||
'meta_created' => 'Créé :timeLength',
|
'meta_created' => 'Créé :timeLength',
|
||||||
'meta_created_name' => 'Créé :timeLength par :user',
|
'meta_created_name' => 'Créé :timeLength par :user',
|
||||||
@ -59,7 +59,7 @@ return [
|
|||||||
'books_create' => 'Créer un nouveau livre',
|
'books_create' => 'Créer un nouveau livre',
|
||||||
'books_delete' => 'Supprimer un livre',
|
'books_delete' => 'Supprimer un livre',
|
||||||
'books_delete_named' => 'Supprimer le livre :bookName',
|
'books_delete_named' => 'Supprimer le livre :bookName',
|
||||||
'books_delete_explain' => 'Ceci va supprimer le livre nommé \':bookName\', Tous les chapitres et pages seront supprimés.',
|
'books_delete_explain' => 'Ceci va supprimer le livre nommé \':bookName\', tous les chapitres et pages seront supprimés.',
|
||||||
'books_delete_confirmation' => 'Êtes-vous sûr(e) de vouloir supprimer ce livre ?',
|
'books_delete_confirmation' => 'Êtes-vous sûr(e) de vouloir supprimer ce livre ?',
|
||||||
'books_edit' => 'Modifier le livre',
|
'books_edit' => 'Modifier le livre',
|
||||||
'books_edit_named' => 'Modifier le livre :bookName',
|
'books_edit_named' => 'Modifier le livre :bookName',
|
||||||
@ -90,18 +90,18 @@ return [
|
|||||||
'chapters_create' => 'Créer un nouveau chapitre',
|
'chapters_create' => 'Créer un nouveau chapitre',
|
||||||
'chapters_delete' => 'Supprimer le chapitre',
|
'chapters_delete' => 'Supprimer le chapitre',
|
||||||
'chapters_delete_named' => 'Supprimer le chapitre :chapterName',
|
'chapters_delete_named' => 'Supprimer le chapitre :chapterName',
|
||||||
'chapters_delete_explain' => 'Ceci va supprimer le chapitre \':chapterName\', Toutes les pages seront déplacée dans le livre parent.',
|
'chapters_delete_explain' => 'Ceci va supprimer le chapitre \':chapterName\', toutes les pages seront déplacées dans le livre parent.',
|
||||||
'chapters_delete_confirm' => 'Etes-vous sûr(e) de vouloir supprimer ce chapitre ?',
|
'chapters_delete_confirm' => 'Etes-vous sûr(e) de vouloir supprimer ce chapitre ?',
|
||||||
'chapters_edit' => 'Modifier le chapitre',
|
'chapters_edit' => 'Modifier le chapitre',
|
||||||
'chapters_edit_named' => 'Modifier le chapitre :chapterName',
|
'chapters_edit_named' => 'Modifier le chapitre :chapterName',
|
||||||
'chapters_save' => 'Enregistrer le chapitre',
|
'chapters_save' => 'Enregistrer le chapitre',
|
||||||
'chapters_move' => 'Déplace le chapitre',
|
'chapters_move' => 'Déplacer le chapitre',
|
||||||
'chapters_move_named' => 'Déplacer le chapitre :chapterName',
|
'chapters_move_named' => 'Déplacer le chapitre :chapterName',
|
||||||
'chapter_move_success' => 'Chapitre déplacé dans :bookName',
|
'chapter_move_success' => 'Chapitre déplacé dans :bookName',
|
||||||
'chapters_permissions' => 'Permissions du chapitre',
|
'chapters_permissions' => 'Permissions du chapitre',
|
||||||
'chapters_empty' => 'Il n\'y a pas de pages dans ce chapitre actuellement.',
|
'chapters_empty' => 'Il n\'y a pas de page dans ce chapitre actuellement.',
|
||||||
'chapters_permissions_active' => 'Permissions du chapitre activées',
|
'chapters_permissions_active' => 'Permissions du chapitre activées',
|
||||||
'chapters_permissions_success' => 'Permissions du chapitres mises à jour',
|
'chapters_permissions_success' => 'Permissions du chapitre mises à jour',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pages
|
* Pages
|
||||||
@ -131,7 +131,7 @@ return [
|
|||||||
'pages_edit_discard_draft' => 'Ecarter le brouillon',
|
'pages_edit_discard_draft' => 'Ecarter le brouillon',
|
||||||
'pages_edit_set_changelog' => 'Remplir le journal des changements',
|
'pages_edit_set_changelog' => 'Remplir le journal des changements',
|
||||||
'pages_edit_enter_changelog_desc' => 'Entrez une brève description des changements effectués',
|
'pages_edit_enter_changelog_desc' => 'Entrez une brève description des changements effectués',
|
||||||
'pages_edit_enter_changelog' => 'Entrez dans le journal des changements',
|
'pages_edit_enter_changelog' => 'Entrer dans le journal des changements',
|
||||||
'pages_save' => 'Enregistrez la page',
|
'pages_save' => 'Enregistrez la page',
|
||||||
'pages_title' => 'Titre de la page',
|
'pages_title' => 'Titre de la page',
|
||||||
'pages_name' => 'Nom de la page',
|
'pages_name' => 'Nom de la page',
|
||||||
@ -139,7 +139,7 @@ return [
|
|||||||
'pages_md_preview' => 'Prévisualisation',
|
'pages_md_preview' => 'Prévisualisation',
|
||||||
'pages_md_insert_image' => 'Insérer une image',
|
'pages_md_insert_image' => 'Insérer une image',
|
||||||
'pages_md_insert_link' => 'Insérer un lien',
|
'pages_md_insert_link' => 'Insérer un lien',
|
||||||
'pages_not_in_chapter' => 'La page n\'est pas dans un chanpitre',
|
'pages_not_in_chapter' => 'La page n\'est pas dans un chapitre',
|
||||||
'pages_move' => 'Déplacer la page',
|
'pages_move' => 'Déplacer la page',
|
||||||
'pages_move_success' => 'Page déplacée à ":parentName"',
|
'pages_move_success' => 'Page déplacée à ":parentName"',
|
||||||
'pages_permissions' => 'Permissions de la page',
|
'pages_permissions' => 'Permissions de la page',
|
||||||
@ -160,15 +160,15 @@ return [
|
|||||||
'pages_initial_revision' => 'Publication initiale',
|
'pages_initial_revision' => 'Publication initiale',
|
||||||
'pages_initial_name' => 'Nouvelle page',
|
'pages_initial_name' => 'Nouvelle page',
|
||||||
'pages_editing_draft_notification' => 'Vous éditez actuellement un brouillon qui a été sauvé :timeDiff.',
|
'pages_editing_draft_notification' => 'Vous éditez actuellement un brouillon qui a été sauvé :timeDiff.',
|
||||||
'pages_draft_edited_notification' => 'La page a été mise à jour depuis votre dernière visit. Vous devriez écarter ce brouillon.',
|
'pages_draft_edited_notification' => 'La page a été mise à jour depuis votre dernière visite. Vous devriez écarter ce brouillon.',
|
||||||
'pages_draft_edit_active' => [
|
'pages_draft_edit_active' => [
|
||||||
'start_a' => ':count utilisateurs ont commencé a éditer cette page',
|
'start_a' => ':count utilisateurs ont commencé à éditer cette page',
|
||||||
'start_b' => ':userName a commencé à éditer cette page',
|
'start_b' => ':userName a commencé à éditer cette page',
|
||||||
'time_a' => 'depuis la dernière sauvegarde',
|
'time_a' => 'depuis la dernière sauvegarde',
|
||||||
'time_b' => 'dans les :minCount dernières minutes',
|
'time_b' => 'dans les :minCount dernières minutes',
|
||||||
'message' => ':start :time. Attention a ne pas écraser les mises à jour de quelqu\'un d\'autre!',
|
'message' => ':start :time. Attention à ne pas écraser les mises à jour de quelqu\'un d\'autre !',
|
||||||
],
|
],
|
||||||
'pages_draft_discarded' => 'Brouuillon écarté, la page est dans sa version actuelle.',
|
'pages_draft_discarded' => 'Brouillon écarté, la page est dans sa version actuelle.',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editor sidebar
|
* Editor sidebar
|
||||||
@ -210,7 +210,29 @@ return [
|
|||||||
*/
|
*/
|
||||||
'profile_user_for_x' => 'Utilisateur depuis :time',
|
'profile_user_for_x' => 'Utilisateur depuis :time',
|
||||||
'profile_created_content' => 'Contenu créé',
|
'profile_created_content' => 'Contenu créé',
|
||||||
'profile_not_created_pages' => ':userName n\'a pas créé de pages',
|
'profile_not_created_pages' => ':userName n\'a pas créé de page',
|
||||||
'profile_not_created_chapters' => ':userName n\'a pas créé de chapitres',
|
'profile_not_created_chapters' => ':userName n\'a pas créé de chapitre',
|
||||||
'profile_not_created_books' => ':userName n\'a pas créé de livres',
|
'profile_not_created_books' => ':userName n\'a pas créé de livre',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comments
|
||||||
|
*/
|
||||||
|
'comment' => 'Commentaire',
|
||||||
|
'comments' => 'Commentaires',
|
||||||
|
'comment_placeholder' => 'Entrez vos commentaires ici, merci supporté ...',
|
||||||
|
'no_comments' => 'No Comments',
|
||||||
|
'x_comments' => ':numComments Commentaires',
|
||||||
|
'one_comment' => '1 Commentaire',
|
||||||
|
'comments_loading' => 'Loading ...',
|
||||||
|
'comment_save' => 'Enregistrer le commentaire',
|
||||||
|
'comment_reply' => 'Répondre',
|
||||||
|
'comment_edit' => 'Modifier',
|
||||||
|
'comment_delete' => 'Supprimer',
|
||||||
|
'comment_cancel' => 'Annuler',
|
||||||
|
'comment_created' => 'Commentaire ajouté',
|
||||||
|
'comment_updated' => 'Commentaire mis à jour',
|
||||||
|
'comment_deleted' => 'Commentaire supprimé',
|
||||||
|
'comment_updated_text' => 'Mis à jour il y a :updateDiff par',
|
||||||
|
'comment_delete_confirm' => 'Cela supprime le contenu du commentaire. Êtes-vous sûr de vouloir supprimer ce commentaire?',
|
||||||
|
'comment_create' => 'Créé'
|
||||||
];
|
];
|
||||||
|
@ -18,21 +18,21 @@ return [
|
|||||||
'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti',
|
'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti',
|
||||||
'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe',
|
'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe',
|
||||||
'ldap_extension_not_installed' => 'L\'extention LDAP PHP n\'est pas installée',
|
'ldap_extension_not_installed' => 'L\'extention LDAP PHP n\'est pas installée',
|
||||||
'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed',
|
'ldap_cannot_connect' => 'Impossible de se connecter au serveur LDAP, la connexion initiale a échoué',
|
||||||
'social_no_action_defined' => 'No action defined',
|
'social_no_action_defined' => 'Pas d\'action définie',
|
||||||
'social_account_in_use' => 'Cet compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.',
|
'social_account_in_use' => 'Ce compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.',
|
||||||
'social_account_email_in_use' => 'L\'email :email Est déjà utilisé. Si vous avez déjà un compte :socialAccount, vous pouvez le joindre à votre profil existant.',
|
'social_account_email_in_use' => 'L\'email :email est déjà utilisé. Si vous avez déjà un compte :socialAccount, vous pouvez le joindre à votre profil existant.',
|
||||||
'social_account_existing' => 'Ce compte :socialAccount est déjà rattaché à votre profil.',
|
'social_account_existing' => 'Ce compte :socialAccount est déjà rattaché à votre profil.',
|
||||||
'social_account_already_used_existing' => 'Ce compte :socialAccount est déjà utilisé par un autre utilisateur.',
|
'social_account_already_used_existing' => 'Ce compte :socialAccount est déjà utilisé par un autre utilisateur.',
|
||||||
'social_account_not_used' => 'Ce compte :socialAccount n\'est lié à aucun utilisateur. ',
|
'social_account_not_used' => 'Ce compte :socialAccount n\'est lié à aucun utilisateur. ',
|
||||||
'social_account_register_instructions' => 'Si vous n\'avez pas encore de compte, vous pouvez le lier avec l\'option :socialAccount.',
|
'social_account_register_instructions' => 'Si vous n\'avez pas encore de compte, vous pouvez le lier avec l\'option :socialAccount.',
|
||||||
'social_driver_not_found' => 'Social driver not found',
|
'social_driver_not_found' => 'Pilote de compte social absent',
|
||||||
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
|
'social_driver_not_configured' => 'Vos préférences pour le compte :socialAccount sont incorrectes.',
|
||||||
|
|
||||||
// System
|
// System
|
||||||
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
|
'path_not_writable' => 'Impossible d\'écrire dans :filePath. Assurez-vous d\'avoir les droits d\'écriture sur le serveur',
|
||||||
'cannot_get_image_from_url' => 'Impossible de récupérer l\'image depuis :url',
|
'cannot_get_image_from_url' => 'Impossible de récupérer l\'image depuis :url',
|
||||||
'cannot_create_thumbs' => 'Le serveur ne peux pas créer de miniatures, vérifier que l\extensions GD PHP est installée.',
|
'cannot_create_thumbs' => 'Le serveur ne peut pas créer de miniature, vérifier que l\'extension PHP GD est installée.',
|
||||||
'server_upload_limit' => 'La taille du fichier est trop grande.',
|
'server_upload_limit' => 'La taille du fichier est trop grande.',
|
||||||
'image_upload_error' => 'Une erreur est survenue pendant l\'envoi de l\'image',
|
'image_upload_error' => 'Une erreur est survenue pendant l\'envoi de l\'image',
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ return [
|
|||||||
|
|
||||||
// Roles
|
// Roles
|
||||||
'role_cannot_be_edited' => 'Ce rôle ne peut pas être modifié',
|
'role_cannot_be_edited' => 'Ce rôle ne peut pas être modifié',
|
||||||
'role_system_cannot_be_deleted' => 'Ceci est un rôle du système et on ne peut pas le supprimer',
|
'role_system_cannot_be_deleted' => 'Ceci est un rôle du système et ne peut pas être supprimé',
|
||||||
'role_registration_default_cannot_delete' => 'Ce rôle ne peut pas être supprimé tant qu\'il est le rôle par défaut',
|
'role_registration_default_cannot_delete' => 'Ce rôle ne peut pas être supprimé tant qu\'il est le rôle par défaut',
|
||||||
|
|
||||||
// Error pages
|
// Error pages
|
||||||
@ -67,4 +67,11 @@ return [
|
|||||||
'error_occurred' => 'Une erreur est survenue',
|
'error_occurred' => 'Une erreur est survenue',
|
||||||
'app_down' => ':appName n\'est pas en service pour le moment',
|
'app_down' => ':appName n\'est pas en service pour le moment',
|
||||||
'back_soon' => 'Nous serons bientôt de retour.',
|
'back_soon' => 'Nous serons bientôt de retour.',
|
||||||
|
|
||||||
|
// comments
|
||||||
|
'comment_list' => 'Une erreur s\'est produite lors de la récupération des commentaires.',
|
||||||
|
'cannot_add_comment_to_draft' => 'Vous ne pouvez pas ajouter de commentaires à un projet.',
|
||||||
|
'comment_add' => 'Une erreur s\'est produite lors de l\'ajout du commentaire.',
|
||||||
|
'comment_delete' => 'Une erreur s\'est produite lors de la suppression du commentaire.',
|
||||||
|
'empty_comment' => 'Impossible d\'ajouter un commentaire vide.',
|
||||||
];
|
];
|
||||||
|
@ -26,11 +26,11 @@ return [
|
|||||||
'app_editor' => 'Editeur des pages',
|
'app_editor' => 'Editeur des pages',
|
||||||
'app_editor_desc' => 'Sélectionnez l\'éditeur qui sera utilisé pour modifier les pages.',
|
'app_editor_desc' => 'Sélectionnez l\'éditeur qui sera utilisé pour modifier les pages.',
|
||||||
'app_custom_html' => 'HTML personnalisé dans l\'en-tête',
|
'app_custom_html' => 'HTML personnalisé dans l\'en-tête',
|
||||||
'app_custom_html_desc' => 'Le contenu inséré ici sera jouté en bas de la balise <head> de toutes les pages. Vous pouvez l\'utiliser pour ajouter du CSS personnalisé ou un tracker analytique.',
|
'app_custom_html_desc' => 'Le contenu inséré ici sera ajouté en bas de la balise <head> de toutes les pages. Vous pouvez l\'utiliser pour ajouter du CSS personnalisé ou un tracker analytique.',
|
||||||
'app_logo' => 'Logo de l\'Application',
|
'app_logo' => 'Logo de l\'Application',
|
||||||
'app_logo_desc' => 'Cette image doit faire 43px de hauteur. <br>Les images plus larges seront réduites.',
|
'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' => 'Couleur principale de l\'application',
|
||||||
'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.',
|
'app_primary_color_desc' => 'Cela devrait être une valeur hexadécimale. <br>Laisser vide pour rétablir la couleur par défaut.',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registration settings
|
* Registration settings
|
||||||
@ -61,13 +61,13 @@ return [
|
|||||||
'role_delete_success' => 'Le rôle a été supprimé avec succès',
|
'role_delete_success' => 'Le rôle a été supprimé avec succès',
|
||||||
'role_edit' => 'Modifier le rôle',
|
'role_edit' => 'Modifier le rôle',
|
||||||
'role_details' => 'Détails du rôle',
|
'role_details' => 'Détails du rôle',
|
||||||
'role_name' => 'Nom du Rôle',
|
'role_name' => 'Nom du rôle',
|
||||||
'role_desc' => 'Courte description du rôle',
|
'role_desc' => 'Courte description du rôle',
|
||||||
'role_system' => 'Permissions système',
|
'role_system' => 'Permissions système',
|
||||||
'role_manage_users' => 'Gérer les utilisateurs',
|
'role_manage_users' => 'Gérer les utilisateurs',
|
||||||
'role_manage_roles' => 'Gérer les rôles et permissions',
|
'role_manage_roles' => 'Gérer les rôles et permissions',
|
||||||
'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages',
|
'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages',
|
||||||
'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres chapitres et pages',
|
'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres, chapitres, et pages',
|
||||||
'role_manage_settings' => 'Gérer les préférences de l\'application',
|
'role_manage_settings' => 'Gérer les préférences de l\'application',
|
||||||
'role_asset' => 'Asset Permissions',
|
'role_asset' => 'Asset Permissions',
|
||||||
'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.',
|
'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.',
|
||||||
@ -107,7 +107,7 @@ return [
|
|||||||
'users_social_accounts_info' => 'Vous pouvez connecter des réseaux sociaux à votre compte pour vous connecter plus rapidement. Déconnecter un compte n\'enlèvera pas les accès autorisés précédemment sur votre compte de réseau social.',
|
'users_social_accounts_info' => 'Vous pouvez connecter des réseaux sociaux à votre compte pour vous connecter plus rapidement. Déconnecter un compte n\'enlèvera pas les accès autorisés précédemment sur votre compte de réseau social.',
|
||||||
'users_social_connect' => 'Connecter le compte',
|
'users_social_connect' => 'Connecter le compte',
|
||||||
'users_social_disconnect' => 'Déconnecter le compte',
|
'users_social_disconnect' => 'Déconnecter le compte',
|
||||||
'users_social_connected' => 'Votre compte :socialAccount a élté ajouté avec succès.',
|
'users_social_connected' => 'Votre compte :socialAccount a été ajouté avec succès.',
|
||||||
'users_social_disconnected' => 'Votre compte :socialAccount a été déconnecté avec succès',
|
'users_social_disconnected' => 'Votre compte :socialAccount a été déconnecté avec succès',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -214,4 +214,26 @@ return [
|
|||||||
'profile_not_created_pages' => ':userName heeft geen pagina\'s gemaakt',
|
'profile_not_created_pages' => ':userName heeft geen pagina\'s gemaakt',
|
||||||
'profile_not_created_chapters' => ':userName heeft geen hoofdstukken gemaakt',
|
'profile_not_created_chapters' => ':userName heeft geen hoofdstukken gemaakt',
|
||||||
'profile_not_created_books' => ':userName heeft geen boeken gemaakt',
|
'profile_not_created_books' => ':userName heeft geen boeken gemaakt',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comments
|
||||||
|
*/
|
||||||
|
'comment' => 'Commentaar',
|
||||||
|
'comments' => 'Commentaren',
|
||||||
|
'comment_placeholder' => 'Vul hier uw reacties in, markdown ondersteund ...',
|
||||||
|
'no_comments' => 'No Comments',
|
||||||
|
'x_comments' => ':numComments Opmerkingen',
|
||||||
|
'one_comment' => '1 commentaar',
|
||||||
|
'comments_loading' => 'Loading ...',
|
||||||
|
'comment_save' => 'Opslaan opslaan',
|
||||||
|
'comment_reply' => 'Antwoord',
|
||||||
|
'comment_edit' => 'Bewerken',
|
||||||
|
'comment_delete' => 'Verwijderen',
|
||||||
|
'comment_cancel' => 'Annuleren',
|
||||||
|
'comment_created' => 'Opmerking toegevoegd',
|
||||||
|
'comment_updated' => 'Opmerking bijgewerkt',
|
||||||
|
'comment_deleted' => 'Opmerking verwijderd',
|
||||||
|
'comment_updated_text' => 'Bijgewerkt :updateDiff geleden door',
|
||||||
|
'comment_delete_confirm' => 'Hiermee verwijdert u de inhoud van de reactie. Weet u zeker dat u deze reactie wilt verwijderen?',
|
||||||
|
'comment_create' => 'Gemaakt'
|
||||||
];
|
];
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user