Showing
78 changed files
with
1622 additions
and
539 deletions
| ... | @@ -56,4 +56,13 @@ class Book extends Entity | ... | @@ -56,4 +56,13 @@ class Book extends Entity |
| 56 | return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description; | 56 | return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | + /** | ||
| 60 | + * Return a generalised, common raw query that can be 'unioned' across entities. | ||
| 61 | + * @return string | ||
| 62 | + */ | ||
| 63 | + public function entityRawQuery() | ||
| 64 | + { | ||
| 65 | + return "'BookStack\\\\Book' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text,'' as html, '0' as book_id, '0' as priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at"; | ||
| 66 | + } | ||
| 67 | + | ||
| 59 | } | 68 | } | ... | ... |
| ... | @@ -51,4 +51,13 @@ class Chapter extends Entity | ... | @@ -51,4 +51,13 @@ class Chapter extends Entity |
| 51 | return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description; | 51 | return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | + /** | ||
| 55 | + * Return a generalised, common raw query that can be 'unioned' across entities. | ||
| 56 | + * @return string | ||
| 57 | + */ | ||
| 58 | + public function entityRawQuery() | ||
| 59 | + { | ||
| 60 | + return "'BookStack\\\\Chapter' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, '' as html, book_id, priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at"; | ||
| 61 | + } | ||
| 62 | + | ||
| 54 | } | 63 | } | ... | ... |
| ... | @@ -12,7 +12,7 @@ class RegeneratePermissions extends Command | ... | @@ -12,7 +12,7 @@ class RegeneratePermissions extends Command |
| 12 | * | 12 | * |
| 13 | * @var string | 13 | * @var string |
| 14 | */ | 14 | */ |
| 15 | - protected $signature = 'bookstack:regenerate-permissions'; | 15 | + protected $signature = 'bookstack:regenerate-permissions {--database= : The database connection to use.}'; |
| 16 | 16 | ||
| 17 | /** | 17 | /** |
| 18 | * The console command description. | 18 | * The console command description. |
| ... | @@ -46,7 +46,14 @@ class RegeneratePermissions extends Command | ... | @@ -46,7 +46,14 @@ class RegeneratePermissions extends Command |
| 46 | */ | 46 | */ |
| 47 | public function handle() | 47 | public function handle() |
| 48 | { | 48 | { |
| 49 | + $connection = \DB::getDefaultConnection(); | ||
| 50 | + if ($this->option('database') !== null) { | ||
| 51 | + \DB::setDefaultConnection($this->option('database')); | ||
| 52 | + } | ||
| 53 | + | ||
| 49 | $this->permissionService->buildJointPermissions(); | 54 | $this->permissionService->buildJointPermissions(); |
| 55 | + | ||
| 56 | + \DB::setDefaultConnection($connection); | ||
| 50 | $this->comment('Permissions regenerated'); | 57 | $this->comment('Permissions regenerated'); |
| 51 | } | 58 | } |
| 52 | } | 59 | } | ... | ... |
app/Console/Commands/RegenerateSearch.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace BookStack\Console\Commands; | ||
| 4 | + | ||
| 5 | +use BookStack\Services\SearchService; | ||
| 6 | +use Illuminate\Console\Command; | ||
| 7 | + | ||
| 8 | +class RegenerateSearch extends Command | ||
| 9 | +{ | ||
| 10 | + /** | ||
| 11 | + * The name and signature of the console command. | ||
| 12 | + * | ||
| 13 | + * @var string | ||
| 14 | + */ | ||
| 15 | + protected $signature = 'bookstack:regenerate-search {--database= : The database connection to use.}'; | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * The console command description. | ||
| 19 | + * | ||
| 20 | + * @var string | ||
| 21 | + */ | ||
| 22 | + protected $description = 'Command description'; | ||
| 23 | + | ||
| 24 | + protected $searchService; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * Create a new command instance. | ||
| 28 | + * | ||
| 29 | + * @param SearchService $searchService | ||
| 30 | + */ | ||
| 31 | + public function __construct(SearchService $searchService) | ||
| 32 | + { | ||
| 33 | + parent::__construct(); | ||
| 34 | + $this->searchService = $searchService; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * Execute the console command. | ||
| 39 | + * | ||
| 40 | + * @return mixed | ||
| 41 | + */ | ||
| 42 | + public function handle() | ||
| 43 | + { | ||
| 44 | + $connection = \DB::getDefaultConnection(); | ||
| 45 | + if ($this->option('database') !== null) { | ||
| 46 | + \DB::setDefaultConnection($this->option('database')); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + $this->searchService->indexAllEntities(); | ||
| 50 | + \DB::setDefaultConnection($connection); | ||
| 51 | + $this->comment('Search index regenerated'); | ||
| 52 | + } | ||
| 53 | +} |
| 1 | -<?php | 1 | +<?php namespace BookStack\Console; |
| 2 | - | ||
| 3 | -namespace BookStack\Console; | ||
| 4 | 2 | ||
| 5 | use Illuminate\Console\Scheduling\Schedule; | 3 | use Illuminate\Console\Scheduling\Schedule; |
| 6 | use Illuminate\Foundation\Console\Kernel as ConsoleKernel; | 4 | use Illuminate\Foundation\Console\Kernel as ConsoleKernel; |
| ... | @@ -13,10 +11,11 @@ class Kernel extends ConsoleKernel | ... | @@ -13,10 +11,11 @@ class Kernel extends ConsoleKernel |
| 13 | * @var array | 11 | * @var array |
| 14 | */ | 12 | */ |
| 15 | protected $commands = [ | 13 | protected $commands = [ |
| 16 | - \BookStack\Console\Commands\ClearViews::class, | 14 | + Commands\ClearViews::class, |
| 17 | - \BookStack\Console\Commands\ClearActivity::class, | 15 | + Commands\ClearActivity::class, |
| 18 | - \BookStack\Console\Commands\ClearRevisions::class, | 16 | + Commands\ClearRevisions::class, |
| 19 | - \BookStack\Console\Commands\RegeneratePermissions::class, | 17 | + Commands\RegeneratePermissions::class, |
| 18 | + Commands\RegenerateSearch::class | ||
| 20 | ]; | 19 | ]; |
| 21 | 20 | ||
| 22 | /** | 21 | /** | ... | ... |
| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | class Entity extends Ownable | 4 | class Entity extends Ownable |
| 5 | { | 5 | { |
| 6 | 6 | ||
| 7 | - protected $fieldsToSearch = ['name', 'description']; | 7 | + public $textField = 'description'; |
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | * Compares this entity to another given entity. | 10 | * Compares this entity to another given entity. |
| ... | @@ -66,6 +66,15 @@ class Entity extends Ownable | ... | @@ -66,6 +66,15 @@ class Entity extends Ownable |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | /** | 68 | /** |
| 69 | + * Get the related search terms. | ||
| 70 | + * @return \Illuminate\Database\Eloquent\Relations\MorphMany | ||
| 71 | + */ | ||
| 72 | + public function searchTerms() | ||
| 73 | + { | ||
| 74 | + return $this->morphMany(SearchTerm::class, 'entity'); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + /** | ||
| 69 | * Get this entities restrictions. | 78 | * Get this entities restrictions. |
| 70 | */ | 79 | */ |
| 71 | public function permissions() | 80 | public function permissions() |
| ... | @@ -153,67 +162,19 @@ class Entity extends Ownable | ... | @@ -153,67 +162,19 @@ class Entity extends Ownable |
| 153 | } | 162 | } |
| 154 | 163 | ||
| 155 | /** | 164 | /** |
| 156 | - * Perform a full-text search on this entity. | 165 | + * Get the body text of this entity. |
| 157 | - * @param string[] $fieldsToSearch | ||
| 158 | - * @param string[] $terms | ||
| 159 | - * @param string[] array $wheres | ||
| 160 | * @return mixed | 166 | * @return mixed |
| 161 | */ | 167 | */ |
| 162 | - public function fullTextSearchQuery($terms, $wheres = []) | 168 | + public function getText() |
| 163 | { | 169 | { |
| 164 | - $exactTerms = []; | 170 | + return $this->{$this->textField}; |
| 165 | - $fuzzyTerms = []; | ||
| 166 | - $search = static::newQuery(); | ||
| 167 | - | ||
| 168 | - foreach ($terms as $key => $term) { | ||
| 169 | - $term = htmlentities($term, ENT_QUOTES); | ||
| 170 | - $term = preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $term); | ||
| 171 | - if (preg_match('/".*?"/', $term) || is_numeric($term)) { | ||
| 172 | - $term = str_replace('"', '', $term); | ||
| 173 | - $exactTerms[] = '%' . $term . '%'; | ||
| 174 | - } else { | ||
| 175 | - $term = '' . $term . '*'; | ||
| 176 | - if ($term !== '*') $fuzzyTerms[] = $term; | ||
| 177 | - } | ||
| 178 | - } | ||
| 179 | - | ||
| 180 | - $isFuzzy = count($exactTerms) === 0 && count($fuzzyTerms) > 0; | ||
| 181 | - | ||
| 182 | - | ||
| 183 | - // Perform fulltext search if relevant terms exist. | ||
| 184 | - if ($isFuzzy) { | ||
| 185 | - $termString = implode(' ', $fuzzyTerms); | ||
| 186 | - $fields = implode(',', $this->fieldsToSearch); | ||
| 187 | - $search = $search->selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]); | ||
| 188 | - $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]); | ||
| 189 | } | 171 | } |
| 190 | 172 | ||
| 191 | - // Ensure at least one exact term matches if in search | 173 | + /** |
| 192 | - if (count($exactTerms) > 0) { | 174 | + * Return a generalised, common raw query that can be 'unioned' across entities. |
| 193 | - $search = $search->where(function ($query) use ($exactTerms) { | 175 | + * @return string |
| 194 | - foreach ($exactTerms as $exactTerm) { | 176 | + */ |
| 195 | - foreach ($this->fieldsToSearch as $field) { | 177 | + public function entityRawQuery(){return '';} |
| 196 | - $query->orWhere($field, 'like', $exactTerm); | ||
| 197 | - } | ||
| 198 | - } | ||
| 199 | - }); | ||
| 200 | - } | ||
| 201 | - | ||
| 202 | - $orderBy = $isFuzzy ? 'title_relevance' : 'updated_at'; | ||
| 203 | - | ||
| 204 | - // Add additional where terms | ||
| 205 | - foreach ($wheres as $whereTerm) { | ||
| 206 | - $search->where($whereTerm[0], $whereTerm[1], $whereTerm[2]); | ||
| 207 | - } | ||
| 208 | - | ||
| 209 | - // Load in relations | ||
| 210 | - if ($this->isA('page')) { | ||
| 211 | - $search = $search->with('book', 'chapter', 'createdBy', 'updatedBy'); | ||
| 212 | - } else if ($this->isA('chapter')) { | ||
| 213 | - $search = $search->with('book'); | ||
| 214 | - } | ||
| 215 | 178 | ||
| 216 | - return $search->orderBy($orderBy, 'desc'); | ||
| 217 | - } | ||
| 218 | 179 | ||
| 219 | } | 180 | } | ... | ... |
| 1 | <?php namespace BookStack\Http\Controllers; | 1 | <?php namespace BookStack\Http\Controllers; |
| 2 | 2 | ||
| 3 | use BookStack\Repos\EntityRepo; | 3 | use BookStack\Repos\EntityRepo; |
| 4 | +use BookStack\Services\SearchService; | ||
| 4 | use BookStack\Services\ViewService; | 5 | use BookStack\Services\ViewService; |
| 5 | use Illuminate\Http\Request; | 6 | use Illuminate\Http\Request; |
| 6 | 7 | ||
| ... | @@ -8,16 +9,19 @@ class SearchController extends Controller | ... | @@ -8,16 +9,19 @@ class SearchController extends Controller |
| 8 | { | 9 | { |
| 9 | protected $entityRepo; | 10 | protected $entityRepo; |
| 10 | protected $viewService; | 11 | protected $viewService; |
| 12 | + protected $searchService; | ||
| 11 | 13 | ||
| 12 | /** | 14 | /** |
| 13 | * SearchController constructor. | 15 | * SearchController constructor. |
| 14 | * @param EntityRepo $entityRepo | 16 | * @param EntityRepo $entityRepo |
| 15 | * @param ViewService $viewService | 17 | * @param ViewService $viewService |
| 18 | + * @param SearchService $searchService | ||
| 16 | */ | 19 | */ |
| 17 | - public function __construct(EntityRepo $entityRepo, ViewService $viewService) | 20 | + public function __construct(EntityRepo $entityRepo, ViewService $viewService, SearchService $searchService) |
| 18 | { | 21 | { |
| 19 | $this->entityRepo = $entityRepo; | 22 | $this->entityRepo = $entityRepo; |
| 20 | $this->viewService = $viewService; | 23 | $this->viewService = $viewService; |
| 24 | + $this->searchService = $searchService; | ||
| 21 | parent::__construct(); | 25 | parent::__construct(); |
| 22 | } | 26 | } |
| 23 | 27 | ||
| ... | @@ -27,105 +31,55 @@ class SearchController extends Controller | ... | @@ -27,105 +31,55 @@ class SearchController extends Controller |
| 27 | * @return \Illuminate\View\View | 31 | * @return \Illuminate\View\View |
| 28 | * @internal param string $searchTerm | 32 | * @internal param string $searchTerm |
| 29 | */ | 33 | */ |
| 30 | - public function searchAll(Request $request) | 34 | + public function search(Request $request) |
| 31 | { | 35 | { |
| 32 | - if (!$request->has('term')) { | ||
| 33 | - return redirect()->back(); | ||
| 34 | - } | ||
| 35 | $searchTerm = $request->get('term'); | 36 | $searchTerm = $request->get('term'); |
| 36 | - $paginationAppends = $request->only('term'); | ||
| 37 | - $pages = $this->entityRepo->getBySearch('page', $searchTerm, [], 20, $paginationAppends); | ||
| 38 | - $books = $this->entityRepo->getBySearch('book', $searchTerm, [], 10, $paginationAppends); | ||
| 39 | - $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, [], 10, $paginationAppends); | ||
| 40 | $this->setPageTitle(trans('entities.search_for_term', ['term' => $searchTerm])); | 37 | $this->setPageTitle(trans('entities.search_for_term', ['term' => $searchTerm])); |
| 41 | - return view('search/all', [ | ||
| 42 | - 'pages' => $pages, | ||
| 43 | - 'books' => $books, | ||
| 44 | - 'chapters' => $chapters, | ||
| 45 | - 'searchTerm' => $searchTerm | ||
| 46 | - ]); | ||
| 47 | - } | ||
| 48 | - | ||
| 49 | - /** | ||
| 50 | - * Search only the pages in the system. | ||
| 51 | - * @param Request $request | ||
| 52 | - * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View | ||
| 53 | - */ | ||
| 54 | - public function searchPages(Request $request) | ||
| 55 | - { | ||
| 56 | - if (!$request->has('term')) return redirect()->back(); | ||
| 57 | 38 | ||
| 58 | - $searchTerm = $request->get('term'); | 39 | + $page = $request->has('page') && is_int(intval($request->get('page'))) ? intval($request->get('page')) : 1; |
| 59 | - $paginationAppends = $request->only('term'); | 40 | + $nextPageLink = baseUrl('/search?term=' . urlencode($searchTerm) . '&page=' . ($page+1)); |
| 60 | - $pages = $this->entityRepo->getBySearch('page', $searchTerm, [], 20, $paginationAppends); | ||
| 61 | - $this->setPageTitle(trans('entities.search_page_for_term', ['term' => $searchTerm])); | ||
| 62 | - return view('search/entity-search-list', [ | ||
| 63 | - 'entities' => $pages, | ||
| 64 | - 'title' => trans('entities.search_results_page'), | ||
| 65 | - 'searchTerm' => $searchTerm | ||
| 66 | - ]); | ||
| 67 | - } | ||
| 68 | 41 | ||
| 69 | - /** | 42 | + $results = $this->searchService->searchEntities($searchTerm, 'all', $page, 20); |
| 70 | - * Search only the chapters in the system. | 43 | + $hasNextPage = $this->searchService->searchEntities($searchTerm, 'all', $page+1, 20)['count'] > 0; |
| 71 | - * @param Request $request | ||
| 72 | - * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View | ||
| 73 | - */ | ||
| 74 | - public function searchChapters(Request $request) | ||
| 75 | - { | ||
| 76 | - if (!$request->has('term')) return redirect()->back(); | ||
| 77 | 44 | ||
| 78 | - $searchTerm = $request->get('term'); | 45 | + return view('search/all', [ |
| 79 | - $paginationAppends = $request->only('term'); | 46 | + 'entities' => $results['results'], |
| 80 | - $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, [], 20, $paginationAppends); | 47 | + 'totalResults' => $results['total'], |
| 81 | - $this->setPageTitle(trans('entities.search_chapter_for_term', ['term' => $searchTerm])); | 48 | + 'searchTerm' => $searchTerm, |
| 82 | - return view('search/entity-search-list', [ | 49 | + 'hasNextPage' => $hasNextPage, |
| 83 | - 'entities' => $chapters, | 50 | + 'nextPageLink' => $nextPageLink |
| 84 | - 'title' => trans('entities.search_results_chapter'), | ||
| 85 | - 'searchTerm' => $searchTerm | ||
| 86 | ]); | 51 | ]); |
| 87 | } | 52 | } |
| 88 | 53 | ||
| 54 | + | ||
| 89 | /** | 55 | /** |
| 90 | - * Search only the books in the system. | 56 | + * Searches all entities within a book. |
| 91 | * @param Request $request | 57 | * @param Request $request |
| 92 | - * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View | 58 | + * @param integer $bookId |
| 59 | + * @return \Illuminate\View\View | ||
| 60 | + * @internal param string $searchTerm | ||
| 93 | */ | 61 | */ |
| 94 | - public function searchBooks(Request $request) | 62 | + public function searchBook(Request $request, $bookId) |
| 95 | { | 63 | { |
| 96 | - if (!$request->has('term')) return redirect()->back(); | 64 | + $term = $request->get('term', ''); |
| 97 | - | 65 | + $results = $this->searchService->searchBook($bookId, $term); |
| 98 | - $searchTerm = $request->get('term'); | 66 | + return view('partials/entity-list', ['entities' => $results]); |
| 99 | - $paginationAppends = $request->only('term'); | ||
| 100 | - $books = $this->entityRepo->getBySearch('book', $searchTerm, [], 20, $paginationAppends); | ||
| 101 | - $this->setPageTitle(trans('entities.search_book_for_term', ['term' => $searchTerm])); | ||
| 102 | - return view('search/entity-search-list', [ | ||
| 103 | - 'entities' => $books, | ||
| 104 | - 'title' => trans('entities.search_results_book'), | ||
| 105 | - 'searchTerm' => $searchTerm | ||
| 106 | - ]); | ||
| 107 | } | 67 | } |
| 108 | 68 | ||
| 109 | /** | 69 | /** |
| 110 | - * Searches all entities within a book. | 70 | + * Searches all entities within a chapter. |
| 111 | * @param Request $request | 71 | * @param Request $request |
| 112 | - * @param integer $bookId | 72 | + * @param integer $chapterId |
| 113 | * @return \Illuminate\View\View | 73 | * @return \Illuminate\View\View |
| 114 | * @internal param string $searchTerm | 74 | * @internal param string $searchTerm |
| 115 | */ | 75 | */ |
| 116 | - public function searchBook(Request $request, $bookId) | 76 | + public function searchChapter(Request $request, $chapterId) |
| 117 | { | 77 | { |
| 118 | - if (!$request->has('term')) { | 78 | + $term = $request->get('term', ''); |
| 119 | - return redirect()->back(); | 79 | + $results = $this->searchService->searchChapter($chapterId, $term); |
| 120 | - } | 80 | + return view('partials/entity-list', ['entities' => $results]); |
| 121 | - $searchTerm = $request->get('term'); | ||
| 122 | - $searchWhereTerms = [['book_id', '=', $bookId]]; | ||
| 123 | - $pages = $this->entityRepo->getBySearch('page', $searchTerm, $searchWhereTerms); | ||
| 124 | - $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, $searchWhereTerms); | ||
| 125 | - return view('search/book', ['pages' => $pages, 'chapters' => $chapters, 'searchTerm' => $searchTerm]); | ||
| 126 | } | 81 | } |
| 127 | 82 | ||
| 128 | - | ||
| 129 | /** | 83 | /** |
| 130 | * Search for a list of entities and return a partial HTML response of matching entities. | 84 | * Search for a list of entities and return a partial HTML response of matching entities. |
| 131 | * Returns the most popular entities if no search is provided. | 85 | * Returns the most popular entities if no search is provided. |
| ... | @@ -134,18 +88,13 @@ class SearchController extends Controller | ... | @@ -134,18 +88,13 @@ class SearchController extends Controller |
| 134 | */ | 88 | */ |
| 135 | public function searchEntitiesAjax(Request $request) | 89 | public function searchEntitiesAjax(Request $request) |
| 136 | { | 90 | { |
| 137 | - $entities = collect(); | ||
| 138 | $entityTypes = $request->has('types') ? collect(explode(',', $request->get('types'))) : collect(['page', 'chapter', 'book']); | 91 | $entityTypes = $request->has('types') ? collect(explode(',', $request->get('types'))) : collect(['page', 'chapter', 'book']); |
| 139 | $searchTerm = ($request->has('term') && trim($request->get('term')) !== '') ? $request->get('term') : false; | 92 | $searchTerm = ($request->has('term') && trim($request->get('term')) !== '') ? $request->get('term') : false; |
| 140 | 93 | ||
| 141 | // Search for entities otherwise show most popular | 94 | // Search for entities otherwise show most popular |
| 142 | if ($searchTerm !== false) { | 95 | if ($searchTerm !== false) { |
| 143 | - foreach (['page', 'chapter', 'book'] as $entityType) { | 96 | + $searchTerm .= ' {type:'. implode('|', $entityTypes->toArray()) .'}'; |
| 144 | - if ($entityTypes->contains($entityType)) { | 97 | + $entities = $this->searchService->searchEntities($searchTerm)['results']; |
| 145 | - $entities = $entities->merge($this->entityRepo->getBySearch($entityType, $searchTerm)->items()); | ||
| 146 | - } | ||
| 147 | - } | ||
| 148 | - $entities = $entities->sortByDesc('title_relevance'); | ||
| 149 | } else { | 98 | } else { |
| 150 | $entityNames = $entityTypes->map(function ($type) { | 99 | $entityNames = $entityTypes->map(function ($type) { |
| 151 | return 'BookStack\\' . ucfirst($type); | 100 | return 'BookStack\\' . ucfirst($type); | ... | ... |
| ... | @@ -2,12 +2,16 @@ | ... | @@ -2,12 +2,16 @@ |
| 2 | 2 | ||
| 3 | namespace BookStack\Notifications; | 3 | namespace BookStack\Notifications; |
| 4 | 4 | ||
| 5 | +use Illuminate\Bus\Queueable; | ||
| 5 | use Illuminate\Notifications\Notification; | 6 | use Illuminate\Notifications\Notification; |
| 7 | +use Illuminate\Contracts\Queue\ShouldQueue; | ||
| 6 | use Illuminate\Notifications\Messages\MailMessage; | 8 | use Illuminate\Notifications\Messages\MailMessage; |
| 7 | 9 | ||
| 8 | -class ConfirmEmail extends Notification | 10 | +class ConfirmEmail extends Notification implements ShouldQueue |
| 9 | { | 11 | { |
| 10 | 12 | ||
| 13 | + use Queueable; | ||
| 14 | + | ||
| 11 | public $token; | 15 | public $token; |
| 12 | 16 | ||
| 13 | /** | 17 | /** | ... | ... |
| ... | @@ -8,8 +8,7 @@ class Page extends Entity | ... | @@ -8,8 +8,7 @@ class Page extends Entity |
| 8 | protected $simpleAttributes = ['name', 'id', 'slug']; | 8 | protected $simpleAttributes = ['name', 'id', 'slug']; |
| 9 | 9 | ||
| 10 | protected $with = ['book']; | 10 | protected $with = ['book']; |
| 11 | - | 11 | + public $textField = 'text'; |
| 12 | - protected $fieldsToSearch = ['name', 'text']; | ||
| 13 | 12 | ||
| 14 | /** | 13 | /** |
| 15 | * Converts this page into a simplified array. | 14 | * Converts this page into a simplified array. |
| ... | @@ -96,4 +95,14 @@ class Page extends Entity | ... | @@ -96,4 +95,14 @@ class Page extends Entity |
| 96 | return mb_convert_encoding($text, 'UTF-8'); | 95 | return mb_convert_encoding($text, 'UTF-8'); |
| 97 | } | 96 | } |
| 98 | 97 | ||
| 98 | + /** | ||
| 99 | + * Return a generalised, common raw query that can be 'unioned' across entities. | ||
| 100 | + * @param bool $withContent | ||
| 101 | + * @return string | ||
| 102 | + */ | ||
| 103 | + public function entityRawQuery($withContent = false) | ||
| 104 | + { $htmlQuery = $withContent ? 'html' : "'' as html"; | ||
| 105 | + return "'BookStack\\\\Page' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, {$htmlQuery}, book_id, priority, chapter_id, draft, created_by, updated_by, updated_at, created_at"; | ||
| 106 | + } | ||
| 107 | + | ||
| 99 | } | 108 | } | ... | ... |
This diff is collapsed.
Click to expand it.
app/SearchTerm.php
0 → 100644
| 1 | +<?php namespace BookStack; | ||
| 2 | + | ||
| 3 | +class SearchTerm extends Model | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | + protected $fillable = ['term', 'entity_id', 'entity_type', 'score']; | ||
| 7 | + public $timestamps = false; | ||
| 8 | + | ||
| 9 | + /** | ||
| 10 | + * Get the entity that this term belongs to | ||
| 11 | + * @return \Illuminate\Database\Eloquent\Relations\MorphTo | ||
| 12 | + */ | ||
| 13 | + public function entity() | ||
| 14 | + { | ||
| 15 | + return $this->morphTo('entity'); | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | +} |
| ... | @@ -479,8 +479,7 @@ class PermissionService | ... | @@ -479,8 +479,7 @@ class PermissionService |
| 479 | * @return \Illuminate\Database\Query\Builder | 479 | * @return \Illuminate\Database\Query\Builder |
| 480 | */ | 480 | */ |
| 481 | public function bookChildrenQuery($book_id, $filterDrafts = false, $fetchPageContent = false) { | 481 | public function bookChildrenQuery($book_id, $filterDrafts = false, $fetchPageContent = false) { |
| 482 | - $pageContentSelect = $fetchPageContent ? 'html' : "''"; | 482 | + $pageSelect = $this->db->table('pages')->selectRaw($this->page->entityRawQuery($fetchPageContent))->where('book_id', '=', $book_id)->where(function($query) use ($filterDrafts) { |
| 483 | - $pageSelect = $this->db->table('pages')->selectRaw("'BookStack\\\\Page' as entity_type, id, slug, name, text, {$pageContentSelect} as description, book_id, priority, chapter_id, draft")->where('book_id', '=', $book_id)->where(function($query) use ($filterDrafts) { | ||
| 484 | $query->where('draft', '=', 0); | 483 | $query->where('draft', '=', 0); |
| 485 | if (!$filterDrafts) { | 484 | if (!$filterDrafts) { |
| 486 | $query->orWhere(function($query) { | 485 | $query->orWhere(function($query) { |
| ... | @@ -488,7 +487,7 @@ class PermissionService | ... | @@ -488,7 +487,7 @@ class PermissionService |
| 488 | }); | 487 | }); |
| 489 | } | 488 | } |
| 490 | }); | 489 | }); |
| 491 | - $chapterSelect = $this->db->table('chapters')->selectRaw("'BookStack\\\\Chapter' as entity_type, id, slug, name, '' as text, description, book_id, priority, 0 as chapter_id, 0 as draft")->where('book_id', '=', $book_id); | 490 | + $chapterSelect = $this->db->table('chapters')->selectRaw($this->chapter->entityRawQuery())->where('book_id', '=', $book_id); |
| 492 | $query = $this->db->query()->select('*')->from($this->db->raw("({$pageSelect->toSql()} UNION {$chapterSelect->toSql()}) AS U")) | 491 | $query = $this->db->query()->select('*')->from($this->db->raw("({$pageSelect->toSql()} UNION {$chapterSelect->toSql()}) AS U")) |
| 493 | ->mergeBindings($pageSelect)->mergeBindings($chapterSelect); | 492 | ->mergeBindings($pageSelect)->mergeBindings($chapterSelect); |
| 494 | 493 | ||
| ... | @@ -514,7 +513,7 @@ class PermissionService | ... | @@ -514,7 +513,7 @@ class PermissionService |
| 514 | * @param string $entityType | 513 | * @param string $entityType |
| 515 | * @param Builder|Entity $query | 514 | * @param Builder|Entity $query |
| 516 | * @param string $action | 515 | * @param string $action |
| 517 | - * @return mixed | 516 | + * @return Builder |
| 518 | */ | 517 | */ |
| 519 | public function enforceEntityRestrictions($entityType, $query, $action = 'view') | 518 | public function enforceEntityRestrictions($entityType, $query, $action = 'view') |
| 520 | { | 519 | { |
| ... | @@ -540,7 +539,7 @@ class PermissionService | ... | @@ -540,7 +539,7 @@ class PermissionService |
| 540 | } | 539 | } |
| 541 | 540 | ||
| 542 | /** | 541 | /** |
| 543 | - * Filter items that have entities set a a polymorphic relation. | 542 | + * Filter items that have entities set as a polymorphic relation. |
| 544 | * @param $query | 543 | * @param $query |
| 545 | * @param string $tableName | 544 | * @param string $tableName |
| 546 | * @param string $entityIdColumn | 545 | * @param string $entityIdColumn | ... | ... |
app/Services/SearchService.php
0 → 100644
This diff is collapsed.
Click to expand it.
| ... | @@ -64,6 +64,10 @@ | ... | @@ -64,6 +64,10 @@ |
| 64 | "post-update-cmd": [ | 64 | "post-update-cmd": [ |
| 65 | "Illuminate\\Foundation\\ComposerScripts::postUpdate", | 65 | "Illuminate\\Foundation\\ComposerScripts::postUpdate", |
| 66 | "php artisan optimize" | 66 | "php artisan optimize" |
| 67 | + ], | ||
| 68 | + "refresh-test-database": [ | ||
| 69 | + "php artisan migrate:refresh --database=mysql_testing", | ||
| 70 | + "php artisan db:seed --class=DummyContentSeeder --database=mysql_testing" | ||
| 67 | ] | 71 | ] |
| 68 | }, | 72 | }, |
| 69 | "config": { | 73 | "config": { | ... | ... |
| ... | @@ -100,7 +100,7 @@ return [ | ... | @@ -100,7 +100,7 @@ return [ |
| 100 | | | 100 | | |
| 101 | */ | 101 | */ |
| 102 | 102 | ||
| 103 | - 'log' => 'single', | 103 | + 'log' => env('APP_LOGGING', 'single'), |
| 104 | 104 | ||
| 105 | /* | 105 | /* |
| 106 | |-------------------------------------------------------------------------- | 106 | |-------------------------------------------------------------------------- | ... | ... |
| ... | @@ -43,7 +43,8 @@ $factory->define(BookStack\Page::class, function ($faker) { | ... | @@ -43,7 +43,8 @@ $factory->define(BookStack\Page::class, function ($faker) { |
| 43 | 'name' => $faker->sentence, | 43 | 'name' => $faker->sentence, |
| 44 | 'slug' => str_random(10), | 44 | 'slug' => str_random(10), |
| 45 | 'html' => $html, | 45 | 'html' => $html, |
| 46 | - 'text' => strip_tags($html) | 46 | + 'text' => strip_tags($html), |
| 47 | + 'revision_count' => 1 | ||
| 47 | ]; | 48 | ]; |
| 48 | }); | 49 | }); |
| 49 | 50 | ... | ... |
| ... | @@ -12,9 +12,10 @@ class AddSearchIndexes extends Migration | ... | @@ -12,9 +12,10 @@ class AddSearchIndexes extends Migration |
| 12 | */ | 12 | */ |
| 13 | public function up() | 13 | public function up() |
| 14 | { | 14 | { |
| 15 | - DB::statement('ALTER TABLE pages ADD FULLTEXT search(name, text)'); | 15 | + $prefix = DB::getTablePrefix(); |
| 16 | - DB::statement('ALTER TABLE books ADD FULLTEXT search(name, description)'); | 16 | + DB::statement("ALTER TABLE {$prefix}pages ADD FULLTEXT search(name, text)"); |
| 17 | - DB::statement('ALTER TABLE chapters ADD FULLTEXT search(name, description)'); | 17 | + DB::statement("ALTER TABLE {$prefix}books ADD FULLTEXT search(name, description)"); |
| 18 | + DB::statement("ALTER TABLE {$prefix}chapters ADD FULLTEXT search(name, description)"); | ||
| 18 | } | 19 | } |
| 19 | 20 | ||
| 20 | /** | 21 | /** | ... | ... |
| ... | @@ -12,9 +12,10 @@ class FulltextWeighting extends Migration | ... | @@ -12,9 +12,10 @@ class FulltextWeighting extends Migration |
| 12 | */ | 12 | */ |
| 13 | public function up() | 13 | public function up() |
| 14 | { | 14 | { |
| 15 | - DB::statement('ALTER TABLE pages ADD FULLTEXT name_search(name)'); | 15 | + $prefix = DB::getTablePrefix(); |
| 16 | - DB::statement('ALTER TABLE books ADD FULLTEXT name_search(name)'); | 16 | + DB::statement("ALTER TABLE {$prefix}pages ADD FULLTEXT name_search(name)"); |
| 17 | - DB::statement('ALTER TABLE chapters ADD FULLTEXT name_search(name)'); | 17 | + DB::statement("ALTER TABLE {$prefix}books ADD FULLTEXT name_search(name)"); |
| 18 | + DB::statement("ALTER TABLE {$prefix}chapters ADD FULLTEXT name_search(name)"); | ||
| 18 | } | 19 | } |
| 19 | 20 | ||
| 20 | /** | 21 | /** | ... | ... |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +use Illuminate\Support\Facades\Schema; | ||
| 4 | +use Illuminate\Database\Schema\Blueprint; | ||
| 5 | +use Illuminate\Database\Migrations\Migration; | ||
| 6 | + | ||
| 7 | +class CreateSearchIndexTable extends Migration | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * Run the migrations. | ||
| 11 | + * | ||
| 12 | + * @return void | ||
| 13 | + */ | ||
| 14 | + public function up() | ||
| 15 | + { | ||
| 16 | + Schema::create('search_terms', function (Blueprint $table) { | ||
| 17 | + $table->increments('id'); | ||
| 18 | + $table->string('term', 200); | ||
| 19 | + $table->string('entity_type', 100); | ||
| 20 | + $table->integer('entity_id'); | ||
| 21 | + $table->integer('score'); | ||
| 22 | + | ||
| 23 | + $table->index('term'); | ||
| 24 | + $table->index('entity_type'); | ||
| 25 | + $table->index(['entity_type', 'entity_id']); | ||
| 26 | + $table->index('score'); | ||
| 27 | + }); | ||
| 28 | + | ||
| 29 | + // Drop search indexes | ||
| 30 | + Schema::table('pages', function(Blueprint $table) { | ||
| 31 | + $table->dropIndex('search'); | ||
| 32 | + $table->dropIndex('name_search'); | ||
| 33 | + }); | ||
| 34 | + Schema::table('books', function(Blueprint $table) { | ||
| 35 | + $table->dropIndex('search'); | ||
| 36 | + $table->dropIndex('name_search'); | ||
| 37 | + }); | ||
| 38 | + Schema::table('chapters', function(Blueprint $table) { | ||
| 39 | + $table->dropIndex('search'); | ||
| 40 | + $table->dropIndex('name_search'); | ||
| 41 | + }); | ||
| 42 | + | ||
| 43 | + app(\BookStack\Services\SearchService::class)->indexAllEntities(); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * Reverse the migrations. | ||
| 48 | + * | ||
| 49 | + * @return void | ||
| 50 | + */ | ||
| 51 | + public function down() | ||
| 52 | + { | ||
| 53 | + $prefix = DB::getTablePrefix(); | ||
| 54 | + DB::statement("ALTER TABLE {$prefix}pages ADD FULLTEXT search(name, text)"); | ||
| 55 | + DB::statement("ALTER TABLE {$prefix}books ADD FULLTEXT search(name, description)"); | ||
| 56 | + DB::statement("ALTER TABLE {$prefix}chapters ADD FULLTEXT search(name, description)"); | ||
| 57 | + DB::statement("ALTER TABLE {$prefix}pages ADD FULLTEXT name_search(name)"); | ||
| 58 | + DB::statement("ALTER TABLE {$prefix}books ADD FULLTEXT name_search(name)"); | ||
| 59 | + DB::statement("ALTER TABLE {$prefix}chapters ADD FULLTEXT name_search(name)"); | ||
| 60 | + | ||
| 61 | + Schema::dropIfExists('search_terms'); | ||
| 62 | + } | ||
| 63 | +} |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +use Illuminate\Support\Facades\Schema; | ||
| 4 | +use Illuminate\Database\Schema\Blueprint; | ||
| 5 | +use Illuminate\Database\Migrations\Migration; | ||
| 6 | + | ||
| 7 | +class AddRevisionCounts extends Migration | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * Run the migrations. | ||
| 11 | + * | ||
| 12 | + * @return void | ||
| 13 | + */ | ||
| 14 | + public function up() | ||
| 15 | + { | ||
| 16 | + Schema::table('pages', function (Blueprint $table) { | ||
| 17 | + $table->integer('revision_count'); | ||
| 18 | + }); | ||
| 19 | + Schema::table('page_revisions', function (Blueprint $table) { | ||
| 20 | + $table->integer('revision_number'); | ||
| 21 | + $table->index('revision_number'); | ||
| 22 | + }); | ||
| 23 | + | ||
| 24 | + // Update revision count | ||
| 25 | + $pTable = DB::getTablePrefix() . 'pages'; | ||
| 26 | + $rTable = DB::getTablePrefix() . 'page_revisions'; | ||
| 27 | + DB::statement("UPDATE ${pTable} SET ${pTable}.revision_count=(SELECT count(*) FROM ${rTable} WHERE ${rTable}.page_id=${pTable}.id)"); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * Reverse the migrations. | ||
| 32 | + * | ||
| 33 | + * @return void | ||
| 34 | + */ | ||
| 35 | + public function down() | ||
| 36 | + { | ||
| 37 | + Schema::table('pages', function (Blueprint $table) { | ||
| 38 | + $table->dropColumn('revision_count'); | ||
| 39 | + }); | ||
| 40 | + Schema::table('page_revisions', function (Blueprint $table) { | ||
| 41 | + $table->dropColumn('revision_number'); | ||
| 42 | + }); | ||
| 43 | + } | ||
| 44 | +} |
| ... | @@ -16,7 +16,7 @@ class DummyContentSeeder extends Seeder | ... | @@ -16,7 +16,7 @@ class DummyContentSeeder extends Seeder |
| 16 | $user->attachRole($role); | 16 | $user->attachRole($role); |
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | - $books = factory(\BookStack\Book::class, 20)->create(['created_by' => $user->id, 'updated_by' => $user->id]) | 19 | + factory(\BookStack\Book::class, 20)->create(['created_by' => $user->id, 'updated_by' => $user->id]) |
| 20 | ->each(function($book) use ($user) { | 20 | ->each(function($book) use ($user) { |
| 21 | $chapters = factory(\BookStack\Chapter::class, 5)->create(['created_by' => $user->id, 'updated_by' => $user->id]) | 21 | $chapters = factory(\BookStack\Chapter::class, 5)->create(['created_by' => $user->id, 'updated_by' => $user->id]) |
| 22 | ->each(function($chapter) use ($user, $book){ | 22 | ->each(function($chapter) use ($user, $book){ |
| ... | @@ -28,7 +28,7 @@ class DummyContentSeeder extends Seeder | ... | @@ -28,7 +28,7 @@ class DummyContentSeeder extends Seeder |
| 28 | $book->pages()->saveMany($pages); | 28 | $book->pages()->saveMany($pages); |
| 29 | }); | 29 | }); |
| 30 | 30 | ||
| 31 | - $restrictionService = app(\BookStack\Services\PermissionService::class); | 31 | + app(\BookStack\Services\PermissionService::class)->buildJointPermissions(); |
| 32 | - $restrictionService->buildJointPermissions(); | 32 | + app(\BookStack\Services\SearchService::class)->indexAllEntities(); |
| 33 | } | 33 | } |
| 34 | } | 34 | } | ... | ... |
| 1 | -var elixir = require('laravel-elixir'); | 1 | +const argv = require('yargs').argv; |
| 2 | +const gulp = require('gulp'), | ||
| 3 | + plumber = require('gulp-plumber'); | ||
| 4 | +const autoprefixer = require('gulp-autoprefixer'); | ||
| 5 | +const uglify = require('gulp-uglify'); | ||
| 6 | +const minifycss = require('gulp-clean-css'); | ||
| 7 | +const sass = require('gulp-sass'); | ||
| 8 | +const browserify = require("browserify"); | ||
| 9 | +const source = require('vinyl-source-stream'); | ||
| 10 | +const buffer = require('vinyl-buffer'); | ||
| 11 | +const babelify = require("babelify"); | ||
| 12 | +const watchify = require("watchify"); | ||
| 13 | +const envify = require("envify"); | ||
| 14 | +const gutil = require("gulp-util"); | ||
| 2 | 15 | ||
| 3 | -elixir(mix => { | 16 | +if (argv.production) process.env.NODE_ENV = 'production'; |
| 4 | - mix.sass('styles.scss'); | 17 | + |
| 5 | - mix.sass('print-styles.scss'); | 18 | +gulp.task('styles', () => { |
| 6 | - mix.sass('export-styles.scss'); | 19 | + let chain = gulp.src(['resources/assets/sass/**/*.scss']) |
| 7 | - mix.browserify('global.js', './public/js/common.js'); | 20 | + .pipe(plumber({ |
| 21 | + errorHandler: function (error) { | ||
| 22 | + console.log(error.message); | ||
| 23 | + this.emit('end'); | ||
| 24 | + }})) | ||
| 25 | + .pipe(sass()) | ||
| 26 | + .pipe(autoprefixer('last 2 versions')); | ||
| 27 | + if (argv.production) chain = chain.pipe(minifycss()); | ||
| 28 | + return chain.pipe(gulp.dest('public/css/')); | ||
| 8 | }); | 29 | }); |
| 30 | + | ||
| 31 | + | ||
| 32 | +function scriptTask(watch=false) { | ||
| 33 | + | ||
| 34 | + let props = { | ||
| 35 | + basedir: 'resources/assets/js', | ||
| 36 | + debug: true, | ||
| 37 | + entries: ['global.js'] | ||
| 38 | + }; | ||
| 39 | + | ||
| 40 | + let bundler = watch ? watchify(browserify(props), { poll: true }) : browserify(props); | ||
| 41 | + bundler.transform(envify, {global: true}).transform(babelify, {presets: ['es2015']}); | ||
| 42 | + function rebundle() { | ||
| 43 | + let stream = bundler.bundle(); | ||
| 44 | + stream = stream.pipe(source('common.js')); | ||
| 45 | + if (argv.production) stream = stream.pipe(buffer()).pipe(uglify()); | ||
| 46 | + return stream.pipe(gulp.dest('public/js/')); | ||
| 47 | + } | ||
| 48 | + bundler.on('update', function() { | ||
| 49 | + rebundle(); | ||
| 50 | + gutil.log('Rebundle...'); | ||
| 51 | + }); | ||
| 52 | + bundler.on('log', gutil.log); | ||
| 53 | + return rebundle(); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +gulp.task('scripts', () => {scriptTask(false)}); | ||
| 57 | +gulp.task('scripts-watch', () => {scriptTask(true)}); | ||
| 58 | + | ||
| 59 | +gulp.task('default', ['styles', 'scripts-watch'], () => { | ||
| 60 | + gulp.watch("resources/assets/sass/**/*.scss", ['styles']); | ||
| 61 | +}); | ||
| 62 | + | ||
| 63 | +gulp.task('build', ['styles', 'scripts']); | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| 1 | { | 1 | { |
| 2 | "private": true, | 2 | "private": true, |
| 3 | "scripts": { | 3 | "scripts": { |
| 4 | - "build": "gulp --production", | 4 | + "build": "gulp build", |
| 5 | - "dev": "gulp watch", | 5 | + "production": "gulp build --production", |
| 6 | - "watch": "gulp watch" | 6 | + "dev": "gulp", |
| 7 | + "watch": "gulp" | ||
| 7 | }, | 8 | }, |
| 8 | "devDependencies": { | 9 | "devDependencies": { |
| 10 | + "babelify": "^7.3.0", | ||
| 11 | + "browserify": "^14.3.0", | ||
| 12 | + "envify": "^4.0.0", | ||
| 13 | + "gulp": "3.9.1", | ||
| 14 | + "gulp-autoprefixer": "3.1.1", | ||
| 15 | + "gulp-clean-css": "^3.0.4", | ||
| 16 | + "gulp-minify-css": "1.2.4", | ||
| 17 | + "gulp-plumber": "1.1.0", | ||
| 18 | + "gulp-sass": "3.1.0", | ||
| 19 | + "gulp-uglify": "2.1.2", | ||
| 20 | + "vinyl-buffer": "^1.0.0", | ||
| 21 | + "vinyl-source-stream": "^1.1.0", | ||
| 22 | + "watchify": "^3.9.0", | ||
| 23 | + "yargs": "^7.1.0" | ||
| 24 | + }, | ||
| 25 | + "dependencies": { | ||
| 9 | "angular": "^1.5.5", | 26 | "angular": "^1.5.5", |
| 10 | "angular-animate": "^1.5.5", | 27 | "angular-animate": "^1.5.5", |
| 11 | "angular-resource": "^1.5.5", | 28 | "angular-resource": "^1.5.5", |
| 12 | "angular-sanitize": "^1.5.5", | 29 | "angular-sanitize": "^1.5.5", |
| 13 | - "angular-ui-sortable": "^0.15.0", | 30 | + "angular-ui-sortable": "^0.17.0", |
| 31 | + "axios": "^0.16.1", | ||
| 32 | + "babel-preset-es2015": "^6.24.1", | ||
| 33 | + "clipboard": "^1.5.16", | ||
| 14 | "dropzone": "^4.0.1", | 34 | "dropzone": "^4.0.1", |
| 15 | - "gulp": "^3.9.0", | 35 | + "gulp-util": "^3.0.8", |
| 16 | - "laravel-elixir": "^6.0.0-11", | 36 | + "markdown-it": "^8.3.1", |
| 17 | - "laravel-elixir-browserify-official": "^0.1.3", | 37 | + "markdown-it-task-lists": "^2.0.0", |
| 18 | - "marked": "^0.3.5", | 38 | + "moment": "^2.12.0", |
| 19 | - "moment": "^2.12.0" | 39 | + "vue": "^2.2.6" |
| 20 | }, | 40 | }, |
| 21 | - "dependencies": { | 41 | + "browser": { |
| 22 | - "clipboard": "^1.5.16" | 42 | + "vue": "vue/dist/vue.common.js" |
| 23 | } | 43 | } |
| 24 | } | 44 | } | ... | ... |
| ... | @@ -74,7 +74,7 @@ These are the great projects used to help build BookStack: | ... | @@ -74,7 +74,7 @@ These are the great projects used to help build BookStack: |
| 74 | * [Dropzone.js](http://www.dropzonejs.com/) | 74 | * [Dropzone.js](http://www.dropzonejs.com/) |
| 75 | * [ZeroClipboard](http://zeroclipboard.org/) | 75 | * [ZeroClipboard](http://zeroclipboard.org/) |
| 76 | * [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html) | 76 | * [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html) |
| 77 | -* [Marked](https://github.com/chjj/marked) | 77 | +* [markdown-it](https://github.com/markdown-it/markdown-it) and [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists) |
| 78 | * [Moment.js](http://momentjs.com/) | 78 | * [Moment.js](http://momentjs.com/) |
| 79 | * [BarryVD](https://github.com/barryvdh) | 79 | * [BarryVD](https://github.com/barryvdh) |
| 80 | * [Debugbar](https://github.com/barryvdh/laravel-debugbar) | 80 | * [Debugbar](https://github.com/barryvdh/laravel-debugbar) | ... | ... |
| 1 | "use strict"; | 1 | "use strict"; |
| 2 | 2 | ||
| 3 | -import moment from 'moment'; | 3 | +const moment = require('moment'); |
| 4 | -import 'moment/locale/en-gb'; | 4 | +require('moment/locale/en-gb'); |
| 5 | -import editorOptions from "./pages/page-form"; | 5 | +const editorOptions = require("./pages/page-form"); |
| 6 | 6 | ||
| 7 | moment.locale('en-gb'); | 7 | moment.locale('en-gb'); |
| 8 | 8 | ||
| 9 | -export default function (ngApp, events) { | 9 | +module.exports = function (ngApp, events) { |
| 10 | 10 | ||
| 11 | ngApp.controller('ImageManagerController', ['$scope', '$attrs', '$http', '$timeout', 'imageManagerService', | 11 | ngApp.controller('ImageManagerController', ['$scope', '$attrs', '$http', '$timeout', 'imageManagerService', |
| 12 | function ($scope, $attrs, $http, $timeout, imageManagerService) { | 12 | function ($scope, $attrs, $http, $timeout, imageManagerService) { |
| ... | @@ -259,39 +259,6 @@ export default function (ngApp, events) { | ... | @@ -259,39 +259,6 @@ export default function (ngApp, events) { |
| 259 | 259 | ||
| 260 | }]); | 260 | }]); |
| 261 | 261 | ||
| 262 | - | ||
| 263 | - ngApp.controller('BookShowController', ['$scope', '$http', '$attrs', '$sce', function ($scope, $http, $attrs, $sce) { | ||
| 264 | - $scope.searching = false; | ||
| 265 | - $scope.searchTerm = ''; | ||
| 266 | - $scope.searchResults = ''; | ||
| 267 | - | ||
| 268 | - $scope.searchBook = function (e) { | ||
| 269 | - e.preventDefault(); | ||
| 270 | - let term = $scope.searchTerm; | ||
| 271 | - if (term.length == 0) return; | ||
| 272 | - $scope.searching = true; | ||
| 273 | - $scope.searchResults = ''; | ||
| 274 | - let searchUrl = window.baseUrl('/search/book/' + $attrs.bookId); | ||
| 275 | - searchUrl += '?term=' + encodeURIComponent(term); | ||
| 276 | - $http.get(searchUrl).then((response) => { | ||
| 277 | - $scope.searchResults = $sce.trustAsHtml(response.data); | ||
| 278 | - }); | ||
| 279 | - }; | ||
| 280 | - | ||
| 281 | - $scope.checkSearchForm = function () { | ||
| 282 | - if ($scope.searchTerm.length < 1) { | ||
| 283 | - $scope.searching = false; | ||
| 284 | - } | ||
| 285 | - }; | ||
| 286 | - | ||
| 287 | - $scope.clearSearch = function () { | ||
| 288 | - $scope.searching = false; | ||
| 289 | - $scope.searchTerm = ''; | ||
| 290 | - }; | ||
| 291 | - | ||
| 292 | - }]); | ||
| 293 | - | ||
| 294 | - | ||
| 295 | ngApp.controller('PageEditController', ['$scope', '$http', '$attrs', '$interval', '$timeout', '$sce', | 262 | ngApp.controller('PageEditController', ['$scope', '$http', '$attrs', '$interval', '$timeout', '$sce', |
| 296 | function ($scope, $http, $attrs, $interval, $timeout, $sce) { | 263 | function ($scope, $http, $attrs, $interval, $timeout, $sce) { |
| 297 | 264 | ... | ... |
| 1 | "use strict"; | 1 | "use strict"; |
| 2 | -import DropZone from "dropzone"; | 2 | +const DropZone = require("dropzone"); |
| 3 | -import markdown from "marked"; | 3 | +const MarkdownIt = require("markdown-it"); |
| 4 | +const mdTasksLists = require('markdown-it-task-lists'); | ||
| 4 | 5 | ||
| 5 | -export default function (ngApp, events) { | 6 | +module.exports = function (ngApp, events) { |
| 6 | 7 | ||
| 7 | /** | 8 | /** |
| 8 | * Common tab controls using simple jQuery functions. | 9 | * Common tab controls using simple jQuery functions. |
| ... | @@ -214,18 +215,8 @@ export default function (ngApp, events) { | ... | @@ -214,18 +215,8 @@ export default function (ngApp, events) { |
| 214 | } | 215 | } |
| 215 | }]); | 216 | }]); |
| 216 | 217 | ||
| 217 | - let renderer = new markdown.Renderer(); | 218 | + const md = new MarkdownIt(); |
| 218 | - // Custom markdown checkbox list item | 219 | + md.use(mdTasksLists, {label: true}); |
| 219 | - // Attribution: https://github.com/chjj/marked/issues/107#issuecomment-44542001 | ||
| 220 | - renderer.listitem = function(text) { | ||
| 221 | - if (/^\s*\[[x ]\]\s*/.test(text)) { | ||
| 222 | - text = text | ||
| 223 | - .replace(/^\s*\[ \]\s*/, '<input type="checkbox"/>') | ||
| 224 | - .replace(/^\s*\[x\]\s*/, '<input type="checkbox" checked/>'); | ||
| 225 | - return `<li class="checkbox-item">${text}</li>`; | ||
| 226 | - } | ||
| 227 | - return `<li>${text}</li>`; | ||
| 228 | - }; | ||
| 229 | 220 | ||
| 230 | /** | 221 | /** |
| 231 | * Markdown input | 222 | * Markdown input |
| ... | @@ -244,20 +235,20 @@ export default function (ngApp, events) { | ... | @@ -244,20 +235,20 @@ export default function (ngApp, events) { |
| 244 | element = element.find('textarea').first(); | 235 | element = element.find('textarea').first(); |
| 245 | let content = element.val(); | 236 | let content = element.val(); |
| 246 | scope.mdModel = content; | 237 | scope.mdModel = content; |
| 247 | - scope.mdChange(markdown(content, {renderer: renderer})); | 238 | + scope.mdChange(md.render(content)); |
| 248 | 239 | ||
| 249 | element.on('change input', (event) => { | 240 | element.on('change input', (event) => { |
| 250 | content = element.val(); | 241 | content = element.val(); |
| 251 | $timeout(() => { | 242 | $timeout(() => { |
| 252 | scope.mdModel = content; | 243 | scope.mdModel = content; |
| 253 | - scope.mdChange(markdown(content, {renderer: renderer})); | 244 | + scope.mdChange(md.render(content)); |
| 254 | }); | 245 | }); |
| 255 | }); | 246 | }); |
| 256 | 247 | ||
| 257 | scope.$on('markdown-update', (event, value) => { | 248 | scope.$on('markdown-update', (event, value) => { |
| 258 | element.val(value); | 249 | element.val(value); |
| 259 | scope.mdModel = value; | 250 | scope.mdModel = value; |
| 260 | - scope.mdChange(markdown(value)); | 251 | + scope.mdChange(md.render(value)); |
| 261 | }); | 252 | }); |
| 262 | 253 | ||
| 263 | } | 254 | } | ... | ... |
| 1 | "use strict"; | 1 | "use strict"; |
| 2 | 2 | ||
| 3 | -// AngularJS - Create application and load components | ||
| 4 | -import angular from "angular"; | ||
| 5 | -import "angular-resource"; | ||
| 6 | -import "angular-animate"; | ||
| 7 | -import "angular-sanitize"; | ||
| 8 | -import "angular-ui-sortable"; | ||
| 9 | - | ||
| 10 | // Url retrieval function | 3 | // Url retrieval function |
| 11 | window.baseUrl = function(path) { | 4 | window.baseUrl = function(path) { |
| 12 | let basePath = document.querySelector('meta[name="base-url"]').getAttribute('content'); | 5 | let basePath = document.querySelector('meta[name="base-url"]').getAttribute('content'); |
| ... | @@ -15,11 +8,33 @@ window.baseUrl = function(path) { | ... | @@ -15,11 +8,33 @@ window.baseUrl = function(path) { |
| 15 | return basePath + '/' + path; | 8 | return basePath + '/' + path; |
| 16 | }; | 9 | }; |
| 17 | 10 | ||
| 11 | +const Vue = require("vue"); | ||
| 12 | +const axios = require("axios"); | ||
| 13 | + | ||
| 14 | +let axiosInstance = axios.create({ | ||
| 15 | + headers: { | ||
| 16 | + 'X-CSRF-TOKEN': document.querySelector('meta[name=token]').getAttribute('content'), | ||
| 17 | + 'baseURL': window.baseUrl('') | ||
| 18 | + } | ||
| 19 | +}); | ||
| 20 | + | ||
| 21 | +Vue.prototype.$http = axiosInstance; | ||
| 22 | + | ||
| 23 | +require("./vues/vues"); | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +// AngularJS - Create application and load components | ||
| 27 | +const angular = require("angular"); | ||
| 28 | +require("angular-resource"); | ||
| 29 | +require("angular-animate"); | ||
| 30 | +require("angular-sanitize"); | ||
| 31 | +require("angular-ui-sortable"); | ||
| 32 | + | ||
| 18 | let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); | 33 | let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); |
| 19 | 34 | ||
| 20 | // Translation setup | 35 | // Translation setup |
| 21 | // Creates a global function with name 'trans' to be used in the same way as Laravel's translation system | 36 | // Creates a global function with name 'trans' to be used in the same way as Laravel's translation system |
| 22 | -import Translations from "./translations" | 37 | +const Translations = require("./translations"); |
| 23 | let translator = new Translations(window.translations); | 38 | let translator = new Translations(window.translations); |
| 24 | window.trans = translator.get.bind(translator); | 39 | window.trans = translator.get.bind(translator); |
| 25 | 40 | ||
| ... | @@ -47,11 +62,12 @@ class EventManager { | ... | @@ -47,11 +62,12 @@ class EventManager { |
| 47 | } | 62 | } |
| 48 | 63 | ||
| 49 | window.Events = new EventManager(); | 64 | window.Events = new EventManager(); |
| 65 | +Vue.prototype.$events = window.Events; | ||
| 50 | 66 | ||
| 51 | // Load in angular specific items | 67 | // Load in angular specific items |
| 52 | -import Services from './services'; | 68 | +const Services = require('./services'); |
| 53 | -import Directives from './directives'; | 69 | +const Directives = require('./directives'); |
| 54 | -import Controllers from './controllers'; | 70 | +const Controllers = require('./controllers'); |
| 55 | Services(ngApp, window.Events); | 71 | Services(ngApp, window.Events); |
| 56 | Directives(ngApp, window.Events); | 72 | Directives(ngApp, window.Events); |
| 57 | Controllers(ngApp, window.Events); | 73 | Controllers(ngApp, window.Events); |
| ... | @@ -154,4 +170,4 @@ if(navigator.userAgent.indexOf('MSIE')!==-1 | ... | @@ -154,4 +170,4 @@ if(navigator.userAgent.indexOf('MSIE')!==-1 |
| 154 | } | 170 | } |
| 155 | 171 | ||
| 156 | // Page specific items | 172 | // Page specific items |
| 157 | -import "./pages/page-show"; | 173 | +require("./pages/page-show"); | ... | ... |
| ... | @@ -60,7 +60,7 @@ function registerEditorShortcuts(editor) { | ... | @@ -60,7 +60,7 @@ function registerEditorShortcuts(editor) { |
| 60 | editor.addShortcut('meta+shift+E', '', ['FormatBlock', false, 'code']); | 60 | editor.addShortcut('meta+shift+E', '', ['FormatBlock', false, 'code']); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | -export default function() { | 63 | +module.exports = function() { |
| 64 | let settings = { | 64 | let settings = { |
| 65 | selector: '#html-editor', | 65 | selector: '#html-editor', |
| 66 | content_css: [ | 66 | content_css: [ |
| ... | @@ -68,6 +68,7 @@ export default function() { | ... | @@ -68,6 +68,7 @@ export default function() { |
| 68 | window.baseUrl('/libs/material-design-iconic-font/css/material-design-iconic-font.min.css') | 68 | window.baseUrl('/libs/material-design-iconic-font/css/material-design-iconic-font.min.css') |
| 69 | ], | 69 | ], |
| 70 | body_class: 'page-content', | 70 | body_class: 'page-content', |
| 71 | + browser_spellcheck: true, | ||
| 71 | relative_urls: false, | 72 | relative_urls: false, |
| 72 | remove_script_host: false, | 73 | remove_script_host: false, |
| 73 | document_base_url: window.baseUrl('/'), | 74 | document_base_url: window.baseUrl('/'), |
| ... | @@ -213,4 +214,4 @@ export default function() { | ... | @@ -213,4 +214,4 @@ export default function() { |
| 213 | } | 214 | } |
| 214 | }; | 215 | }; |
| 215 | return settings; | 216 | return settings; |
| 216 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 217 | +}; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| 1 | "use strict"; | 1 | "use strict"; |
| 2 | // Configure ZeroClipboard | 2 | // Configure ZeroClipboard |
| 3 | -import Clipboard from "clipboard"; | 3 | +const Clipboard = require("clipboard"); |
| 4 | 4 | ||
| 5 | -export default window.setupPageShow = function (pageId) { | 5 | +let setupPageShow = window.setupPageShow = function (pageId) { |
| 6 | 6 | ||
| 7 | // Set up pointer | 7 | // Set up pointer |
| 8 | let $pointer = $('#pointer').detach(); | 8 | let $pointer = $('#pointer').detach(); |
| ... | @@ -81,6 +81,12 @@ export default window.setupPageShow = function (pageId) { | ... | @@ -81,6 +81,12 @@ export default window.setupPageShow = function (pageId) { |
| 81 | let $idElem = $(idElem); | 81 | let $idElem = $(idElem); |
| 82 | let color = $('#custom-styles').attr('data-color-light'); | 82 | let color = $('#custom-styles').attr('data-color-light'); |
| 83 | $idElem.css('background-color', color).attr('data-highlighted', 'true').smoothScrollTo(); | 83 | $idElem.css('background-color', color).attr('data-highlighted', 'true').smoothScrollTo(); |
| 84 | + setTimeout(() => { | ||
| 85 | + $idElem.addClass('anim').addClass('selectFade').css('background-color', ''); | ||
| 86 | + setTimeout(() => { | ||
| 87 | + $idElem.removeClass('selectFade'); | ||
| 88 | + }, 3000); | ||
| 89 | + }, 100); | ||
| 84 | } else { | 90 | } else { |
| 85 | $('.page-content').find(':contains("' + text + '")').smoothScrollTo(); | 91 | $('.page-content').find(':contains("' + text + '")').smoothScrollTo(); |
| 86 | } | 92 | } |
| ... | @@ -151,3 +157,5 @@ export default window.setupPageShow = function (pageId) { | ... | @@ -151,3 +157,5 @@ export default window.setupPageShow = function (pageId) { |
| 151 | }); | 157 | }); |
| 152 | 158 | ||
| 153 | }; | 159 | }; |
| 160 | + | ||
| 161 | +module.exports = setupPageShow; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
resources/assets/js/vues/entity-search.js
0 → 100644
| 1 | +let data = { | ||
| 2 | + id: null, | ||
| 3 | + type: '', | ||
| 4 | + searching: false, | ||
| 5 | + searchTerm: '', | ||
| 6 | + searchResults: '', | ||
| 7 | +}; | ||
| 8 | + | ||
| 9 | +let computed = { | ||
| 10 | + | ||
| 11 | +}; | ||
| 12 | + | ||
| 13 | +let methods = { | ||
| 14 | + | ||
| 15 | + searchBook() { | ||
| 16 | + if (this.searchTerm.trim().length === 0) return; | ||
| 17 | + this.searching = true; | ||
| 18 | + this.searchResults = ''; | ||
| 19 | + let url = window.baseUrl(`/search/${this.type}/${this.id}`); | ||
| 20 | + url += `?term=${encodeURIComponent(this.searchTerm)}`; | ||
| 21 | + this.$http.get(url).then(resp => { | ||
| 22 | + this.searchResults = resp.data; | ||
| 23 | + }); | ||
| 24 | + }, | ||
| 25 | + | ||
| 26 | + checkSearchForm() { | ||
| 27 | + this.searching = this.searchTerm > 0; | ||
| 28 | + }, | ||
| 29 | + | ||
| 30 | + clearSearch() { | ||
| 31 | + this.searching = false; | ||
| 32 | + this.searchTerm = ''; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +function mounted() { | ||
| 38 | + this.id = Number(this.$el.getAttribute('entity-id')); | ||
| 39 | + this.type = this.$el.getAttribute('entity-type'); | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +module.exports = { | ||
| 43 | + data, computed, methods, mounted | ||
| 44 | +}; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/assets/js/vues/search.js
0 → 100644
| 1 | +const moment = require('moment'); | ||
| 2 | + | ||
| 3 | +let data = { | ||
| 4 | + terms: '', | ||
| 5 | + termString : '', | ||
| 6 | + search: { | ||
| 7 | + type: { | ||
| 8 | + page: true, | ||
| 9 | + chapter: true, | ||
| 10 | + book: true | ||
| 11 | + }, | ||
| 12 | + exactTerms: [], | ||
| 13 | + tagTerms: [], | ||
| 14 | + option: {}, | ||
| 15 | + dates: { | ||
| 16 | + updated_after: false, | ||
| 17 | + updated_before: false, | ||
| 18 | + created_after: false, | ||
| 19 | + created_before: false, | ||
| 20 | + } | ||
| 21 | + } | ||
| 22 | +}; | ||
| 23 | + | ||
| 24 | +let computed = { | ||
| 25 | + | ||
| 26 | +}; | ||
| 27 | + | ||
| 28 | +let methods = { | ||
| 29 | + | ||
| 30 | + appendTerm(term) { | ||
| 31 | + this.termString += ' ' + term; | ||
| 32 | + this.termString = this.termString.replace(/\s{2,}/g, ' '); | ||
| 33 | + this.termString = this.termString.replace(/^\s+/, ''); | ||
| 34 | + this.termString = this.termString.replace(/\s+$/, ''); | ||
| 35 | + }, | ||
| 36 | + | ||
| 37 | + exactParse(searchString) { | ||
| 38 | + this.search.exactTerms = []; | ||
| 39 | + let exactFilter = /"(.+?)"/g; | ||
| 40 | + let matches; | ||
| 41 | + while ((matches = exactFilter.exec(searchString)) !== null) { | ||
| 42 | + this.search.exactTerms.push(matches[1]); | ||
| 43 | + } | ||
| 44 | + }, | ||
| 45 | + | ||
| 46 | + exactChange() { | ||
| 47 | + let exactFilter = /"(.+?)"/g; | ||
| 48 | + this.termString = this.termString.replace(exactFilter, ''); | ||
| 49 | + let matchesTerm = this.search.exactTerms.filter(term => { | ||
| 50 | + return term.trim() !== ''; | ||
| 51 | + }).map(term => { | ||
| 52 | + return `"${term}"` | ||
| 53 | + }).join(' '); | ||
| 54 | + this.appendTerm(matchesTerm); | ||
| 55 | + }, | ||
| 56 | + | ||
| 57 | + addExact() { | ||
| 58 | + this.search.exactTerms.push(''); | ||
| 59 | + setTimeout(() => { | ||
| 60 | + let exactInputs = document.querySelectorAll('.exact-input'); | ||
| 61 | + exactInputs[exactInputs.length - 1].focus(); | ||
| 62 | + }, 100); | ||
| 63 | + }, | ||
| 64 | + | ||
| 65 | + removeExact(index) { | ||
| 66 | + this.search.exactTerms.splice(index, 1); | ||
| 67 | + this.exactChange(); | ||
| 68 | + }, | ||
| 69 | + | ||
| 70 | + tagParse(searchString) { | ||
| 71 | + this.search.tagTerms = []; | ||
| 72 | + let tagFilter = /\[(.+?)\]/g; | ||
| 73 | + let matches; | ||
| 74 | + while ((matches = tagFilter.exec(searchString)) !== null) { | ||
| 75 | + this.search.tagTerms.push(matches[1]); | ||
| 76 | + } | ||
| 77 | + }, | ||
| 78 | + | ||
| 79 | + tagChange() { | ||
| 80 | + let tagFilter = /\[(.+?)\]/g; | ||
| 81 | + this.termString = this.termString.replace(tagFilter, ''); | ||
| 82 | + let matchesTerm = this.search.tagTerms.filter(term => { | ||
| 83 | + return term.trim() !== ''; | ||
| 84 | + }).map(term => { | ||
| 85 | + return `[${term}]` | ||
| 86 | + }).join(' '); | ||
| 87 | + this.appendTerm(matchesTerm); | ||
| 88 | + }, | ||
| 89 | + | ||
| 90 | + addTag() { | ||
| 91 | + this.search.tagTerms.push(''); | ||
| 92 | + setTimeout(() => { | ||
| 93 | + let tagInputs = document.querySelectorAll('.tag-input'); | ||
| 94 | + tagInputs[tagInputs.length - 1].focus(); | ||
| 95 | + }, 100); | ||
| 96 | + }, | ||
| 97 | + | ||
| 98 | + removeTag(index) { | ||
| 99 | + this.search.tagTerms.splice(index, 1); | ||
| 100 | + this.tagChange(); | ||
| 101 | + }, | ||
| 102 | + | ||
| 103 | + typeParse(searchString) { | ||
| 104 | + let typeFilter = /{\s?type:\s?(.*?)\s?}/; | ||
| 105 | + let match = searchString.match(typeFilter); | ||
| 106 | + let type = this.search.type; | ||
| 107 | + if (!match) { | ||
| 108 | + type.page = type.book = type.chapter = true; | ||
| 109 | + return; | ||
| 110 | + } | ||
| 111 | + let splitTypes = match[1].replace(/ /g, '').split('|'); | ||
| 112 | + type.page = (splitTypes.indexOf('page') !== -1); | ||
| 113 | + type.chapter = (splitTypes.indexOf('chapter') !== -1); | ||
| 114 | + type.book = (splitTypes.indexOf('book') !== -1); | ||
| 115 | + }, | ||
| 116 | + | ||
| 117 | + typeChange() { | ||
| 118 | + let typeFilter = /{\s?type:\s?(.*?)\s?}/; | ||
| 119 | + let type = this.search.type; | ||
| 120 | + if (type.page === type.chapter && type.page === type.book) { | ||
| 121 | + this.termString = this.termString.replace(typeFilter, ''); | ||
| 122 | + return; | ||
| 123 | + } | ||
| 124 | + let selectedTypes = Object.keys(type).filter(type => {return this.search.type[type];}).join('|'); | ||
| 125 | + let typeTerm = '{type:'+selectedTypes+'}'; | ||
| 126 | + if (this.termString.match(typeFilter)) { | ||
| 127 | + this.termString = this.termString.replace(typeFilter, typeTerm); | ||
| 128 | + return; | ||
| 129 | + } | ||
| 130 | + this.appendTerm(typeTerm); | ||
| 131 | + }, | ||
| 132 | + | ||
| 133 | + optionParse(searchString) { | ||
| 134 | + let optionFilter = /{([a-z_\-:]+?)}/gi; | ||
| 135 | + let matches; | ||
| 136 | + while ((matches = optionFilter.exec(searchString)) !== null) { | ||
| 137 | + this.search.option[matches[1].toLowerCase()] = true; | ||
| 138 | + } | ||
| 139 | + }, | ||
| 140 | + | ||
| 141 | + optionChange(optionName) { | ||
| 142 | + let isChecked = this.search.option[optionName]; | ||
| 143 | + if (isChecked) { | ||
| 144 | + this.appendTerm(`{${optionName}}`); | ||
| 145 | + } else { | ||
| 146 | + this.termString = this.termString.replace(`{${optionName}}`, ''); | ||
| 147 | + } | ||
| 148 | + }, | ||
| 149 | + | ||
| 150 | + updateSearch(e) { | ||
| 151 | + e.preventDefault(); | ||
| 152 | + window.location = '/search?term=' + encodeURIComponent(this.termString); | ||
| 153 | + }, | ||
| 154 | + | ||
| 155 | + enableDate(optionName) { | ||
| 156 | + this.search.dates[optionName.toLowerCase()] = moment().format('YYYY-MM-DD'); | ||
| 157 | + this.dateChange(optionName); | ||
| 158 | + }, | ||
| 159 | + | ||
| 160 | + dateParse(searchString) { | ||
| 161 | + let dateFilter = /{([a-z_\-]+?):([a-z_\-0-9]+?)}/gi; | ||
| 162 | + let dateTags = Object.keys(this.search.dates); | ||
| 163 | + let matches; | ||
| 164 | + while ((matches = dateFilter.exec(searchString)) !== null) { | ||
| 165 | + if (dateTags.indexOf(matches[1]) === -1) continue; | ||
| 166 | + this.search.dates[matches[1].toLowerCase()] = matches[2]; | ||
| 167 | + } | ||
| 168 | + }, | ||
| 169 | + | ||
| 170 | + dateChange(optionName) { | ||
| 171 | + let dateFilter = new RegExp('{\\s?'+optionName+'\\s?:([a-z_\\-0-9]+?)}', 'gi'); | ||
| 172 | + this.termString = this.termString.replace(dateFilter, ''); | ||
| 173 | + if (!this.search.dates[optionName]) return; | ||
| 174 | + this.appendTerm(`{${optionName}:${this.search.dates[optionName]}}`); | ||
| 175 | + }, | ||
| 176 | + | ||
| 177 | + dateRemove(optionName) { | ||
| 178 | + this.search.dates[optionName] = false; | ||
| 179 | + this.dateChange(optionName); | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | +}; | ||
| 183 | + | ||
| 184 | +function created() { | ||
| 185 | + this.termString = document.querySelector('[name=searchTerm]').value; | ||
| 186 | + this.typeParse(this.termString); | ||
| 187 | + this.exactParse(this.termString); | ||
| 188 | + this.tagParse(this.termString); | ||
| 189 | + this.optionParse(this.termString); | ||
| 190 | + this.dateParse(this.termString); | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +module.exports = { | ||
| 194 | + data, computed, methods, created | ||
| 195 | +}; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/assets/js/vues/vues.js
0 → 100644
| 1 | +const Vue = require("vue"); | ||
| 2 | + | ||
| 3 | +function exists(id) { | ||
| 4 | + return document.getElementById(id) !== null; | ||
| 5 | +} | ||
| 6 | + | ||
| 7 | +let vueMapping = { | ||
| 8 | + 'search-system': require('./search'), | ||
| 9 | + 'entity-dashboard': require('./entity-search'), | ||
| 10 | +}; | ||
| 11 | + | ||
| 12 | +Object.keys(vueMapping).forEach(id => { | ||
| 13 | + if (exists(id)) { | ||
| 14 | + let config = vueMapping[id]; | ||
| 15 | + config.el = '#' + id; | ||
| 16 | + new Vue(config); | ||
| 17 | + } | ||
| 18 | +}); | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
| 2 | .anim.fadeIn { | 2 | .anim.fadeIn { |
| 3 | opacity: 0; | 3 | opacity: 0; |
| 4 | animation-name: fadeIn; | 4 | animation-name: fadeIn; |
| 5 | - animation-duration: 160ms; | 5 | + animation-duration: 180ms; |
| 6 | animation-timing-function: ease-in-out; | 6 | animation-timing-function: ease-in-out; |
| 7 | animation-fill-mode: forwards; | 7 | animation-fill-mode: forwards; |
| 8 | } | 8 | } |
| ... | @@ -127,3 +127,7 @@ | ... | @@ -127,3 +127,7 @@ |
| 127 | animation-delay: 0s; | 127 | animation-delay: 0s; |
| 128 | animation-timing-function: cubic-bezier(.62, .28, .23, .99); | 128 | animation-timing-function: cubic-bezier(.62, .28, .23, .99); |
| 129 | } | 129 | } |
| 130 | + | ||
| 131 | +.anim.selectFade { | ||
| 132 | + transition: background-color ease-in-out 3000ms; | ||
| 133 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -98,19 +98,36 @@ label { | ... | @@ -98,19 +98,36 @@ label { |
| 98 | 98 | ||
| 99 | label.radio, label.checkbox { | 99 | label.radio, label.checkbox { |
| 100 | font-weight: 400; | 100 | font-weight: 400; |
| 101 | + user-select: none; | ||
| 101 | input[type="radio"], input[type="checkbox"] { | 102 | input[type="radio"], input[type="checkbox"] { |
| 102 | margin-right: $-xs; | 103 | margin-right: $-xs; |
| 103 | } | 104 | } |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 107 | +label.inline.checkbox { | ||
| 108 | + margin-right: $-m; | ||
| 109 | +} | ||
| 110 | + | ||
| 106 | label + p.small { | 111 | label + p.small { |
| 107 | margin-bottom: 0.8em; | 112 | margin-bottom: 0.8em; |
| 108 | } | 113 | } |
| 109 | 114 | ||
| 110 | -input[type="text"], input[type="number"], input[type="email"], input[type="search"], input[type="url"], input[type="password"], select, textarea { | 115 | +table.form-table { |
| 116 | + max-width: 100%; | ||
| 117 | + td { | ||
| 118 | + overflow: hidden; | ||
| 119 | + padding: $-xxs/2 0; | ||
| 120 | + } | ||
| 121 | +} | ||
| 122 | + | ||
| 123 | +input[type="text"], input[type="number"], input[type="email"], input[type="date"], input[type="search"], input[type="url"], input[type="password"], select, textarea { | ||
| 111 | @extend .input-base; | 124 | @extend .input-base; |
| 112 | } | 125 | } |
| 113 | 126 | ||
| 127 | +input[type=date] { | ||
| 128 | + width: 190px; | ||
| 129 | +} | ||
| 130 | + | ||
| 114 | .toggle-switch { | 131 | .toggle-switch { |
| 115 | display: inline-block; | 132 | display: inline-block; |
| 116 | background-color: #BBB; | 133 | background-color: #BBB; | ... | ... |
| ... | @@ -109,6 +109,7 @@ | ... | @@ -109,6 +109,7 @@ |
| 109 | transition-property: right, border; | 109 | transition-property: right, border; |
| 110 | border-left: 0px solid #FFF; | 110 | border-left: 0px solid #FFF; |
| 111 | background-color: #FFF; | 111 | background-color: #FFF; |
| 112 | + max-width: 320px; | ||
| 112 | &.fixed { | 113 | &.fixed { |
| 113 | background-color: #FFF; | 114 | background-color: #FFF; |
| 114 | z-index: 5; | 115 | z-index: 5; | ... | ... |
| ... | @@ -269,19 +269,31 @@ span.highlight { | ... | @@ -269,19 +269,31 @@ span.highlight { |
| 269 | /* | 269 | /* |
| 270 | * Lists | 270 | * Lists |
| 271 | */ | 271 | */ |
| 272 | +ul, ol { | ||
| 273 | + overflow: hidden; | ||
| 274 | + p { | ||
| 275 | + margin: 0; | ||
| 276 | + } | ||
| 277 | +} | ||
| 272 | ul { | 278 | ul { |
| 273 | padding-left: $-m * 1.3; | 279 | padding-left: $-m * 1.3; |
| 274 | list-style: disc; | 280 | list-style: disc; |
| 275 | - overflow: hidden; | 281 | + ul { |
| 282 | + list-style: circle; | ||
| 283 | + margin-top: 0; | ||
| 284 | + margin-bottom: 0; | ||
| 285 | + } | ||
| 286 | + label { | ||
| 287 | + margin: 0; | ||
| 288 | + } | ||
| 276 | } | 289 | } |
| 277 | 290 | ||
| 278 | ol { | 291 | ol { |
| 279 | list-style: decimal; | 292 | list-style: decimal; |
| 280 | padding-left: $-m * 2; | 293 | padding-left: $-m * 2; |
| 281 | - overflow: hidden; | ||
| 282 | } | 294 | } |
| 283 | 295 | ||
| 284 | -li.checkbox-item { | 296 | +li.checkbox-item, li.task-list-item { |
| 285 | list-style: none; | 297 | list-style: none; |
| 286 | margin-left: - ($-m * 1.3); | 298 | margin-left: - ($-m * 1.3); |
| 287 | input[type="checkbox"] { | 299 | input[type="checkbox"] { | ... | ... |
| ... | @@ -7,8 +7,8 @@ | ... | @@ -7,8 +7,8 @@ |
| 7 | @import "grid"; | 7 | @import "grid"; |
| 8 | @import "blocks"; | 8 | @import "blocks"; |
| 9 | @import "buttons"; | 9 | @import "buttons"; |
| 10 | -@import "forms"; | ||
| 11 | @import "tables"; | 10 | @import "tables"; |
| 11 | +@import "forms"; | ||
| 12 | @import "animations"; | 12 | @import "animations"; |
| 13 | @import "tinymce"; | 13 | @import "tinymce"; |
| 14 | @import "highlightjs"; | 14 | @import "highlightjs"; |
| ... | @@ -17,7 +17,11 @@ | ... | @@ -17,7 +17,11 @@ |
| 17 | @import "lists"; | 17 | @import "lists"; |
| 18 | @import "pages"; | 18 | @import "pages"; |
| 19 | 19 | ||
| 20 | -[v-cloak], [v-show] {display: none;} | 20 | +[v-cloak], [v-show] { |
| 21 | + display: none; opacity: 0; | ||
| 22 | + animation-name: none !important; | ||
| 23 | +} | ||
| 24 | + | ||
| 21 | 25 | ||
| 22 | [ng\:cloak], [ng-cloak], .ng-cloak { | 26 | [ng\:cloak], [ng-cloak], .ng-cloak { |
| 23 | display: none !important; | 27 | display: none !important; |
| ... | @@ -272,8 +276,3 @@ $btt-size: 40px; | ... | @@ -272,8 +276,3 @@ $btt-size: 40px; |
| 272 | 276 | ||
| 273 | 277 | ||
| 274 | 278 | ||
| 275 | - | ||
| 276 | - | ||
| 277 | - | ||
| 278 | - | ||
| 279 | - | ... | ... |
| ... | @@ -43,18 +43,9 @@ return [ | ... | @@ -43,18 +43,9 @@ return [ |
| 43 | * Search | 43 | * Search |
| 44 | */ | 44 | */ |
| 45 | 'search_results' => 'Suchergebnisse', | 45 | 'search_results' => 'Suchergebnisse', |
| 46 | - 'search_results_page' => 'Seiten-Suchergebnisse', | ||
| 47 | - 'search_results_chapter' => 'Kapitel-Suchergebnisse', | ||
| 48 | - 'search_results_book' => 'Buch-Suchergebnisse', | ||
| 49 | 'search_clear' => 'Suche zurücksetzen', | 46 | 'search_clear' => 'Suche zurücksetzen', |
| 50 | - 'search_view_pages' => 'Zeige alle passenden Seiten', | ||
| 51 | - 'search_view_chapters' => 'Zeige alle passenden Kapitel', | ||
| 52 | - 'search_view_books' => 'Zeige alle passenden Bücher', | ||
| 53 | 'search_no_pages' => 'Es wurden keine passenden Suchergebnisse gefunden', | 47 | 'search_no_pages' => 'Es wurden keine passenden Suchergebnisse gefunden', |
| 54 | 'search_for_term' => 'Suche nach :term', | 48 | 'search_for_term' => 'Suche nach :term', |
| 55 | - 'search_page_for_term' => 'Suche nach :term in Seiten', | ||
| 56 | - 'search_chapter_for_term' => 'Suche nach :term in Kapiteln', | ||
| 57 | - 'search_book_for_term' => 'Suche nach :term in Büchern', | ||
| 58 | 49 | ||
| 59 | /** | 50 | /** |
| 60 | * Books | 51 | * Books | ... | ... |
| ... | @@ -14,6 +14,7 @@ return [ | ... | @@ -14,6 +14,7 @@ return [ |
| 14 | 'recent_activity' => 'Recent Activity', | 14 | 'recent_activity' => 'Recent Activity', |
| 15 | 'create_now' => 'Create one now', | 15 | 'create_now' => 'Create one now', |
| 16 | 'revisions' => 'Revisions', | 16 | 'revisions' => 'Revisions', |
| 17 | + 'meta_revision' => 'Revision #:revisionCount', | ||
| 17 | 'meta_created' => 'Created :timeLength', | 18 | 'meta_created' => 'Created :timeLength', |
| 18 | 'meta_created_name' => 'Created :timeLength by :user', | 19 | 'meta_created_name' => 'Created :timeLength by :user', |
| 19 | 'meta_updated' => 'Updated :timeLength', | 20 | 'meta_updated' => 'Updated :timeLength', |
| ... | @@ -43,18 +44,26 @@ return [ | ... | @@ -43,18 +44,26 @@ return [ |
| 43 | * Search | 44 | * Search |
| 44 | */ | 45 | */ |
| 45 | 'search_results' => 'Search Results', | 46 | 'search_results' => 'Search Results', |
| 46 | - 'search_results_page' => 'Page Search Results', | 47 | + 'search_total_results_found' => ':count result found|:count total results found', |
| 47 | - 'search_results_chapter' => 'Chapter Search Results', | ||
| 48 | - 'search_results_book' => 'Book Search Results', | ||
| 49 | 'search_clear' => 'Clear Search', | 48 | 'search_clear' => 'Clear Search', |
| 50 | - 'search_view_pages' => 'View all matches pages', | ||
| 51 | - 'search_view_chapters' => 'View all matches chapters', | ||
| 52 | - 'search_view_books' => 'View all matches books', | ||
| 53 | 'search_no_pages' => 'No pages matched this search', | 49 | 'search_no_pages' => 'No pages matched this search', |
| 54 | 'search_for_term' => 'Search for :term', | 50 | 'search_for_term' => 'Search for :term', |
| 55 | - 'search_page_for_term' => 'Page search for :term', | 51 | + 'search_more' => 'More Results', |
| 56 | - 'search_chapter_for_term' => 'Chapter search for :term', | 52 | + 'search_filters' => 'Search Filters', |
| 57 | - 'search_book_for_term' => 'Books search for :term', | 53 | + 'search_content_type' => 'Content Type', |
| 54 | + 'search_exact_matches' => 'Exact Matches', | ||
| 55 | + 'search_tags' => 'Tag Searches', | ||
| 56 | + 'search_viewed_by_me' => 'Viewed by me', | ||
| 57 | + 'search_not_viewed_by_me' => 'Not viewed by me', | ||
| 58 | + 'search_permissions_set' => 'Permissions set', | ||
| 59 | + 'search_created_by_me' => 'Created by me', | ||
| 60 | + 'search_updated_by_me' => 'Updated by me', | ||
| 61 | + 'search_updated_before' => 'Updated before', | ||
| 62 | + 'search_updated_after' => 'Updated after', | ||
| 63 | + 'search_created_before' => 'Created before', | ||
| 64 | + 'search_created_after' => 'Created after', | ||
| 65 | + 'search_set_date' => 'Set Date', | ||
| 66 | + 'search_update' => 'Update Search', | ||
| 58 | 67 | ||
| 59 | /** | 68 | /** |
| 60 | * Books | 69 | * Books |
| ... | @@ -112,6 +121,7 @@ return [ | ... | @@ -112,6 +121,7 @@ return [ |
| 112 | 'chapters_empty' => 'No pages are currently in this chapter.', | 121 | 'chapters_empty' => 'No pages are currently in this chapter.', |
| 113 | 'chapters_permissions_active' => 'Chapter Permissions Active', | 122 | 'chapters_permissions_active' => 'Chapter Permissions Active', |
| 114 | 'chapters_permissions_success' => 'Chapter Permissions Updated', | 123 | 'chapters_permissions_success' => 'Chapter Permissions Updated', |
| 124 | + 'chapters_search_this' => 'Search this chapter', | ||
| 115 | 125 | ||
| 116 | /** | 126 | /** |
| 117 | * Pages | 127 | * Pages |
| ... | @@ -159,6 +169,7 @@ return [ | ... | @@ -159,6 +169,7 @@ return [ |
| 159 | 'pages_revision_named' => 'Page Revision for :pageName', | 169 | 'pages_revision_named' => 'Page Revision for :pageName', |
| 160 | 'pages_revisions_created_by' => 'Created By', | 170 | 'pages_revisions_created_by' => 'Created By', |
| 161 | 'pages_revisions_date' => 'Revision Date', | 171 | 'pages_revisions_date' => 'Revision Date', |
| 172 | + 'pages_revisions_number' => '#', | ||
| 162 | 'pages_revisions_changelog' => 'Changelog', | 173 | 'pages_revisions_changelog' => 'Changelog', |
| 163 | 'pages_revisions_changes' => 'Changes', | 174 | 'pages_revisions_changes' => 'Changes', |
| 164 | 'pages_revisions_current' => 'Current Version', | 175 | 'pages_revisions_current' => 'Current Version', | ... | ... |
| ... | @@ -120,6 +120,7 @@ return [ | ... | @@ -120,6 +120,7 @@ return [ |
| 120 | 'fr' => 'Français', | 120 | 'fr' => 'Français', |
| 121 | 'nl' => 'Nederlands', | 121 | 'nl' => 'Nederlands', |
| 122 | 'pt_BR' => 'Português do Brasil', | 122 | 'pt_BR' => 'Português do Brasil', |
| 123 | + 'sk' => 'Slovensky', | ||
| 123 | ] | 124 | ] |
| 124 | /////////////////////////////////// | 125 | /////////////////////////////////// |
| 125 | ]; | 126 | ]; | ... | ... |
| ... | @@ -11,7 +11,7 @@ return [ | ... | @@ -11,7 +11,7 @@ return [ |
| 11 | | | 11 | | |
| 12 | */ | 12 | */ |
| 13 | 'failed' => 'Las credenciales no concuerdan con nuestros registros.', | 13 | 'failed' => 'Las credenciales no concuerdan con nuestros registros.', |
| 14 | - 'throttle' => 'Demasiados intentos fallidos de conexiÃn. Por favor intente nuevamente en :seconds segundos.', | 14 | + 'throttle' => 'Demasiados intentos fallidos de conexión. Por favor intente nuevamente en :seconds segundos.', |
| 15 | 15 | ||
| 16 | /** | 16 | /** |
| 17 | * Login & Register | 17 | * Login & Register | ... | ... |
| ... | @@ -18,7 +18,7 @@ return [ | ... | @@ -18,7 +18,7 @@ return [ |
| 18 | 'image_dropzone' => 'Arrastre las imágenes o hacer click aquí para Subir', | 18 | 'image_dropzone' => 'Arrastre las imágenes o hacer click aquí para Subir', |
| 19 | 'images_deleted' => 'Imágenes borradas', | 19 | 'images_deleted' => 'Imágenes borradas', |
| 20 | 'image_preview' => 'Preview de la imagen', | 20 | 'image_preview' => 'Preview de la imagen', |
| 21 | - 'image_upload_success' => 'Imagen subida exitosamente', | 21 | + 'image_upload_success' => 'Imagen subida éxitosamente', |
| 22 | 'image_update_success' => 'Detalles de la imagen actualizados exitosamente', | 22 | 'image_update_success' => 'Detalles de la imagen actualizados exitosamente', |
| 23 | 'image_delete_success' => 'Imagen borrada exitosamente' | 23 | 'image_delete_success' => 'Imagen borrada exitosamente' |
| 24 | ]; | 24 | ]; | ... | ... |
| ... | @@ -4,7 +4,7 @@ return [ | ... | @@ -4,7 +4,7 @@ return [ |
| 4 | /** | 4 | /** |
| 5 | * Shared | 5 | * Shared |
| 6 | */ | 6 | */ |
| 7 | - 'recently_created' => 'Recientemente creadod', | 7 | + 'recently_created' => 'Recientemente creado', |
| 8 | 'recently_created_pages' => 'Páginas recientemente creadas', | 8 | 'recently_created_pages' => 'Páginas recientemente creadas', |
| 9 | 'recently_updated_pages' => 'Páginas recientemente actualizadas', | 9 | 'recently_updated_pages' => 'Páginas recientemente actualizadas', |
| 10 | 'recently_created_chapters' => 'CapÃtulos recientemente creados', | 10 | 'recently_created_chapters' => 'CapÃtulos recientemente creados', |
| ... | @@ -43,18 +43,9 @@ return [ | ... | @@ -43,18 +43,9 @@ return [ |
| 43 | * Search | 43 | * Search |
| 44 | */ | 44 | */ |
| 45 | 'search_results' => 'Buscar resultados', | 45 | 'search_results' => 'Buscar resultados', |
| 46 | - 'search_results_page' => 'resultados de búsqueda en página', | ||
| 47 | - 'search_results_chapter' => 'Resultados de búsqueda en capítulo ', | ||
| 48 | - 'search_results_book' => 'Resultados de búsqueda en libro', | ||
| 49 | 'search_clear' => 'Limpiar resultados', | 46 | 'search_clear' => 'Limpiar resultados', |
| 50 | - 'search_view_pages' => 'Ver todas las páginas que concuerdan', | ||
| 51 | - 'search_view_chapters' => 'Ver todos los capítulos que concuerdan', | ||
| 52 | - 'search_view_books' => 'Ver todos los libros que concuerdan', | ||
| 53 | 'search_no_pages' => 'Ninguna página encontrada para la búsqueda', | 47 | 'search_no_pages' => 'Ninguna página encontrada para la búsqueda', |
| 54 | 'search_for_term' => 'Busqueda por :term', | 48 | 'search_for_term' => 'Busqueda por :term', |
| 55 | - 'search_page_for_term' => 'Búsqueda de página por :term', | ||
| 56 | - 'search_chapter_for_term' => 'Búsqueda por capítulo de :term', | ||
| 57 | - 'search_book_for_term' => 'Búsqueda en libro de :term', | ||
| 58 | 49 | ||
| 59 | /** | 50 | /** |
| 60 | * Books | 51 | * Books |
| ... | @@ -148,79 +139,79 @@ return [ | ... | @@ -148,79 +139,79 @@ return [ |
| 148 | 'pages_md_editor' => 'Editor', | 139 | 'pages_md_editor' => 'Editor', |
| 149 | 'pages_md_preview' => 'Preview', | 140 | 'pages_md_preview' => 'Preview', |
| 150 | 'pages_md_insert_image' => 'Insertar Imagen', | 141 | 'pages_md_insert_image' => 'Insertar Imagen', |
| 151 | - 'pages_md_insert_link' => 'Insert Entity Link', | 142 | + 'pages_md_insert_link' => 'Insertar link de entidad', |
| 152 | - 'pages_not_in_chapter' => 'Page is not in a chapter', | 143 | + 'pages_not_in_chapter' => 'La página no esá en el caÃtulo', |
| 153 | - 'pages_move' => 'Move Page', | 144 | + 'pages_move' => 'Mover página', |
| 154 | - 'pages_move_success' => 'Page moved to ":parentName"', | 145 | + 'pages_move_success' => 'Página movida a ":parentName"', |
| 155 | - 'pages_permissions' => 'Page Permissions', | 146 | + 'pages_permissions' => 'Permisos de página', |
| 156 | - 'pages_permissions_success' => 'Page permissions updated', | 147 | + 'pages_permissions_success' => 'Permisos de página actualizados', |
| 157 | - 'pages_revisions' => 'Page Revisions', | 148 | + 'pages_revisions' => 'Revisiones de página', |
| 158 | - 'pages_revisions_named' => 'Page Revisions for :pageName', | 149 | + 'pages_revisions_named' => 'Revisiones de página para :pageName', |
| 159 | - 'pages_revision_named' => 'Page Revision for :pageName', | 150 | + 'pages_revision_named' => 'Revisión de ágina para :pageName', |
| 160 | - 'pages_revisions_created_by' => 'Created By', | 151 | + 'pages_revisions_created_by' => 'Creado por', |
| 161 | - 'pages_revisions_date' => 'Revision Date', | 152 | + 'pages_revisions_date' => 'Fecha de revisión', |
| 162 | 'pages_revisions_changelog' => 'Changelog', | 153 | 'pages_revisions_changelog' => 'Changelog', |
| 163 | - 'pages_revisions_changes' => 'Changes', | 154 | + 'pages_revisions_changes' => 'Cambios', |
| 164 | - 'pages_revisions_current' => 'Current Version', | 155 | + 'pages_revisions_current' => 'Versión actual', |
| 165 | 'pages_revisions_preview' => 'Preview', | 156 | 'pages_revisions_preview' => 'Preview', |
| 166 | - 'pages_revisions_restore' => 'Restore', | 157 | + 'pages_revisions_restore' => 'Restaurar', |
| 167 | - 'pages_revisions_none' => 'This page has no revisions', | 158 | + 'pages_revisions_none' => 'Esta página no tiene revisiones', |
| 168 | - 'pages_copy_link' => 'Copy Link', | 159 | + 'pages_copy_link' => 'Copiar Link', |
| 169 | - 'pages_permissions_active' => 'Page Permissions Active', | 160 | + 'pages_permissions_active' => 'Permisos de página activos', |
| 170 | - 'pages_initial_revision' => 'Initial publish', | 161 | + 'pages_initial_revision' => 'Publicación inicial', |
| 171 | - 'pages_initial_name' => 'New Page', | 162 | + 'pages_initial_name' => 'Página nueva', |
| 172 | - 'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.', | 163 | + 'pages_editing_draft_notification' => 'Ud. está actualmente editando un borrador que fue guardado porúltima vez el :timeDiff.', |
| 173 | - 'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.', | 164 | + 'pages_draft_edited_notification' => 'Esta página ha sido actualizada desde aquel momento. Se recomienda que cancele este borrador.', |
| 174 | 'pages_draft_edit_active' => [ | 165 | 'pages_draft_edit_active' => [ |
| 175 | - 'start_a' => ':count users have started editing this page', | 166 | + 'start_a' => ':count usuarios han comenzado a editar esta página', |
| 176 | - 'start_b' => ':userName has started editing this page', | 167 | + 'start_b' => ':userName ha comenzado a editar esta página', |
| 177 | - 'time_a' => 'since the pages was last updated', | 168 | + 'time_a' => 'desde que las página fue actualizada', |
| 178 | - 'time_b' => 'in the last :minCount minutes', | 169 | + 'time_b' => 'en los Ãltimos :minCount minutos', |
| 179 | - 'message' => ':start :time. Take care not to overwrite each other\'s updates!', | 170 | + 'message' => ':start :time. Ten cuidado de no sobreescribir los cambios del otro usuario', |
| 180 | ], | 171 | ], |
| 181 | - 'pages_draft_discarded' => 'Draft discarded, The editor has been updated with the current page content', | 172 | + 'pages_draft_discarded' => 'Borrador descartado, el editor ha sido actualizado con el contenido de la página actual', |
| 182 | 173 | ||
| 183 | /** | 174 | /** |
| 184 | * Editor sidebar | 175 | * Editor sidebar |
| 185 | */ | 176 | */ |
| 186 | - 'page_tags' => 'Page Tags', | 177 | + 'page_tags' => 'Etiquetas de página', |
| 187 | - 'tag' => 'Tag', | 178 | + 'tag' => 'Etiqueta', |
| 188 | - 'tags' => '', | 179 | + 'tags' => 'Etiquetas', |
| 189 | - 'tag_value' => 'Tag Value (Optional)', | 180 | + 'tag_value' => 'Valor de la etiqueta (Opcional)', |
| 190 | - 'tags_explain' => "Add some tags to better categorise your content. \n You can assign a value to a tag for more in-depth organisation.", | 181 | + 'tags_explain' => "Agregar algunas etiquetas para mejorar la categorización de su contenido. \n Ud. puede asignar un valor a una etiqueta para una organizacón a mayor detalle.", |
| 191 | - 'tags_add' => 'Add another tag', | 182 | + 'tags_add' => 'Agregar otra etiqueta', |
| 192 | - 'attachments' => 'Attachments', | 183 | + 'attachments' => 'Adjuntos', |
| 193 | - 'attachments_explain' => 'Upload some files or attach some link to display on your page. These are visible in the page sidebar.', | 184 | + 'attachments_explain' => 'Subir ficheros o agregar links para mostrar en la página. Estos son visibles en la barra lateral de la página.', |
| 194 | - 'attachments_explain_instant_save' => 'Changes here are saved instantly.', | 185 | + 'attachments_explain_instant_save' => 'Los cambios son guardados de manera instantánea .', |
| 195 | - 'attachments_items' => 'Attached Items', | 186 | + 'attachments_items' => 'Items adjuntados', |
| 196 | - 'attachments_upload' => 'Upload File', | 187 | + 'attachments_upload' => 'Fichero adjuntado', |
| 197 | - 'attachments_link' => 'Attach Link', | 188 | + 'attachments_link' => 'Adjuntar Link', |
| 198 | - 'attachments_set_link' => 'Set Link', | 189 | + 'attachments_set_link' => 'Setear Link', |
| 199 | - 'attachments_delete_confirm' => 'Click delete again to confirm you want to delete this attachment.', | 190 | + 'attachments_delete_confirm' => 'Haga click en borrar nuevamente para confirmar que quiere borrar este adjunto.', |
| 200 | - 'attachments_dropzone' => 'Drop files or click here to attach a file', | 191 | + 'attachments_dropzone' => 'Arrastre ficheros aquÃo haga click aquÃpara adjuntar un fichero', |
| 201 | - 'attachments_no_files' => 'No files have been uploaded', | 192 | + 'attachments_no_files' => 'NingÃn fichero ha sido adjuntado', |
| 202 | - 'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.', | 193 | + 'attachments_explain_link' => 'Ud. puede agregar un link o si lo prefiere puede agregar un fichero. Esto puede ser un link a otra página o un link a un fichero en la nube.', |
| 203 | - 'attachments_link_name' => 'Link Name', | 194 | + 'attachments_link_name' => 'Nombre de Link', |
| 204 | - 'attachment_link' => 'Attachment link', | 195 | + 'attachment_link' => 'Link adjunto', |
| 205 | - 'attachments_link_url' => 'Link to file', | 196 | + 'attachments_link_url' => 'Link a fichero', |
| 206 | - 'attachments_link_url_hint' => 'Url of site or file', | 197 | + 'attachments_link_url_hint' => 'Url del sitio o fichero', |
| 207 | - 'attach' => 'Attach', | 198 | + 'attach' => 'Adjuntar', |
| 208 | - 'attachments_edit_file' => 'Edit File', | 199 | + 'attachments_edit_file' => 'Editar fichero', |
| 209 | - 'attachments_edit_file_name' => 'File Name', | 200 | + 'attachments_edit_file_name' => 'Nombre del fichero', |
| 210 | - 'attachments_edit_drop_upload' => 'Drop files or click here to upload and overwrite', | 201 | + 'attachments_edit_drop_upload' => 'Arrastre a los ficheros o haga click aquÃpara subir o sobreescribir', |
| 211 | - 'attachments_order_updated' => 'Attachment order updated', | 202 | + 'attachments_order_updated' => 'Orden de adjuntos actualizado', |
| 212 | - 'attachments_updated_success' => 'Attachment details updated', | 203 | + 'attachments_updated_success' => 'Detalles de adjuntos actualizados', |
| 213 | - 'attachments_deleted' => 'Attachment deleted', | 204 | + 'attachments_deleted' => 'Adjunto borrado', |
| 214 | - 'attachments_file_uploaded' => 'File successfully uploaded', | 205 | + 'attachments_file_uploaded' => 'Fichero subido éxitosamente', |
| 215 | - 'attachments_file_updated' => 'File successfully updated', | 206 | + 'attachments_file_updated' => 'Fichero actualizado éxitosamente', |
| 216 | - 'attachments_link_attached' => 'Link successfully attached to page', | 207 | + 'attachments_link_attached' => 'Link agregado éxitosamente a la ágina', |
| 217 | 208 | ||
| 218 | /** | 209 | /** |
| 219 | * Profile View | 210 | * Profile View |
| 220 | */ | 211 | */ |
| 221 | - 'profile_user_for_x' => 'User for :time', | 212 | + 'profile_user_for_x' => 'Usuario para :time', |
| 222 | - 'profile_created_content' => 'Created Content', | 213 | + 'profile_created_content' => 'Contenido creado', |
| 223 | - 'profile_not_created_pages' => ':userName has not created any pages', | 214 | + 'profile_not_created_pages' => ':userName no ha creado ninguna página', |
| 224 | - 'profile_not_created_chapters' => ':userName has not created any chapters', | 215 | + 'profile_not_created_chapters' => ':userName no ha creado ningún capÃtulo', |
| 225 | - 'profile_not_created_books' => ':userName has not created any books', | 216 | + 'profile_not_created_books' => ':userName no ha creado ningún libro', |
| 226 | ]; | 217 | ]; | ... | ... |
| ... | @@ -7,64 +7,64 @@ return [ | ... | @@ -7,64 +7,64 @@ return [ |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | // Permissions | 9 | // Permissions |
| 10 | - 'permission' => 'You do not have permission to access the requested page.', | 10 | + 'permission' => 'Ud. no tiene permisos para visualizar la página solicitada.', |
| 11 | - 'permissionJson' => 'You do not have permission to perform the requested action.', | 11 | + 'permissionJson' => 'Ud. no tiene permisos para ejecutar la acción solicitada.', |
| 12 | 12 | ||
| 13 | // Auth | 13 | // Auth |
| 14 | - 'error_user_exists_different_creds' => 'A user with the email :email already exists but with different credentials.', | 14 | + 'error_user_exists_different_creds' => 'Un usuario con el email :email ya existe pero con credenciales diferentes.', |
| 15 | - 'email_already_confirmed' => 'Email has already been confirmed, Try logging in.', | 15 | + 'email_already_confirmed' => 'El email ya ha sido confirmado, Intente loguearse en la aplicación.', |
| 16 | - 'email_confirmation_invalid' => 'This confirmation token is not valid or has already been used, Please try registering again.', | 16 | + 'email_confirmation_invalid' => 'Este token de confirmación no e válido o ya ha sido usado,Intente registrar uno nuevamente.', |
| 17 | - 'email_confirmation_expired' => 'The confirmation token has expired, A new confirmation email has been sent.', | 17 | + 'email_confirmation_expired' => 'El token de confirmación ha expirado, Un nuevo email de confirmacón ha sido enviado.', |
| 18 | - 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', | 18 | + 'ldap_fail_anonymous' => 'El acceso con LDAP ha fallado usando binding anónimo', |
| 19 | - 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', | 19 | + 'ldap_fail_authed' => 'El acceso LDAP usando el dn & password detallados', |
| 20 | - 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', | 20 | + 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', |
| 21 | - 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', | 21 | + 'ldap_cannot_connect' => 'No se puede conectar con el servidor ldap, la conexión inicial ha fallado', |
| 22 | - 'social_no_action_defined' => 'No action defined', | 22 | + 'social_no_action_defined' => 'Acción no definida', |
| 23 | - 'social_account_in_use' => 'This :socialAccount account is already in use, Try logging in via the :socialAccount option.', | 23 | + 'social_account_in_use' => 'la cuenta :socialAccount ya se encuentra en uso, intente loguearse a través de la opcón :socialAccount .', |
| 24 | - 'social_account_email_in_use' => 'The email :email is already in use. If you already have an account you can connect your :socialAccount account from your profile settings.', | 24 | + 'social_account_email_in_use' => 'El email :email ya se encuentra en uso. Si ud. ya dispone de una cuenta puede loguearse a través de su cuenta :socialAccount desde la configuración de perfil.', |
| 25 | - 'social_account_existing' => 'This :socialAccount is already attached to your profile.', | 25 | + 'social_account_existing' => 'La cuenta :socialAccount ya se encuentra asignada a su perfil.', |
| 26 | - 'social_account_already_used_existing' => 'This :socialAccount account is already used by another user.', | 26 | + 'social_account_already_used_existing' => 'La cuenta :socialAccount ya se encuentra usada por otro usuario.', |
| 27 | - 'social_account_not_used' => 'This :socialAccount account is not linked to any users. Please attach it in your profile settings. ', | 27 | + 'social_account_not_used' => 'La cuenta :socialAccount no está asociada a ningún usuario. Por favor adjuntela a su configuración de perfil. ', |
| 28 | - 'social_account_register_instructions' => 'If you do not yet have an account, You can register an account using the :socialAccount option.', | 28 | + 'social_account_register_instructions' => 'Si no dispone de una cuenta, puede registrar una cuenta usando la opción de :socialAccount .', |
| 29 | - 'social_driver_not_found' => 'Social driver not found', | 29 | + 'social_driver_not_found' => 'Driver social no encontrado', |
| 30 | - 'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.', | 30 | + 'social_driver_not_configured' => 'Su configuración :socialAccount no es correcta.', |
| 31 | 31 | ||
| 32 | // System | 32 | // System |
| 33 | - 'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.', | 33 | + 'path_not_writable' => 'La ruta :filePath no pudo ser cargada. Asegurese de que es escribible por el servidor.', |
| 34 | - 'cannot_get_image_from_url' => 'Cannot get image from :url', | 34 | + 'cannot_get_image_from_url' => 'No se puede obtener la imagen desde :url', |
| 35 | - 'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.', | 35 | + 'cannot_create_thumbs' => 'El servidor no puede crear la imagen miniatura. Por favor chequee que tiene la extensión GD instalada.', |
| 36 | - 'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.', | 36 | + 'server_upload_limit' => 'El servidor no permite la subida de ficheros de este tamañ. Por favor intente con un fichero de menor tamañ.', |
| 37 | - 'image_upload_error' => 'An error occurred uploading the image', | 37 | + 'image_upload_error' => 'Ha ocurrido un error al subir la imagen', |
| 38 | 38 | ||
| 39 | // Attachments | 39 | // Attachments |
| 40 | - 'attachment_page_mismatch' => 'Page mismatch during attachment update', | 40 | + 'attachment_page_mismatch' => 'Página no coincidente durante la subida del adjunto ', |
| 41 | 41 | ||
| 42 | // Pages | 42 | // Pages |
| 43 | - 'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page', | 43 | + 'page_draft_autosave_fail' => 'Fallo al guardar borrador. Asegurese de que tiene conexión a Internet antes de guardar este borrador', |
| 44 | 44 | ||
| 45 | // Entities | 45 | // Entities |
| 46 | - 'entity_not_found' => 'Entity not found', | 46 | + 'entity_not_found' => 'Entidad no encontrada', |
| 47 | - 'book_not_found' => 'Book not found', | 47 | + 'book_not_found' => 'Libro no encontrado', |
| 48 | - 'page_not_found' => 'Page not found', | 48 | + 'page_not_found' => 'Página no encontrada', |
| 49 | - 'chapter_not_found' => 'Chapter not found', | 49 | + 'chapter_not_found' => 'Capítulo no encontrado', |
| 50 | - 'selected_book_not_found' => 'The selected book was not found', | 50 | + 'selected_book_not_found' => 'El libro seleccionado no fue encontrado', |
| 51 | - 'selected_book_chapter_not_found' => 'The selected Book or Chapter was not found', | 51 | + 'selected_book_chapter_not_found' => 'El libro o capítulo seleccionado no fue encontrado', |
| 52 | - 'guests_cannot_save_drafts' => 'Guests cannot save drafts', | 52 | + 'guests_cannot_save_drafts' => 'Los invitados no pueden guardar los borradores', |
| 53 | 53 | ||
| 54 | // Users | 54 | // Users |
| 55 | - 'users_cannot_delete_only_admin' => 'You cannot delete the only admin', | 55 | + 'users_cannot_delete_only_admin' => 'No se puede borrar el único administrador', |
| 56 | - 'users_cannot_delete_guest' => 'You cannot delete the guest user', | 56 | + 'users_cannot_delete_guest' => 'No se puede borrar el usuario invitado', |
| 57 | 57 | ||
| 58 | // Roles | 58 | // Roles |
| 59 | - 'role_cannot_be_edited' => 'This role cannot be edited', | 59 | + 'role_cannot_be_edited' => 'Este rol no puede ser editado', |
| 60 | - 'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted', | 60 | + 'role_system_cannot_be_deleted' => 'Este rol es un rol de sistema y no puede ser borrado', |
| 61 | - 'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role', | 61 | + 'role_registration_default_cannot_delete' => 'Este rol no puede ser borrado mientras sea el rol por defecto de registro', |
| 62 | 62 | ||
| 63 | // Error pages | 63 | // Error pages |
| 64 | - '404_page_not_found' => 'Page Not Found', | 64 | + '404_page_not_found' => 'Página no encontrada', |
| 65 | - 'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.', | 65 | + 'sorry_page_not_found' => 'Lo sentimos, la página que intenta acceder no pudo ser encontrada.', |
| 66 | - 'return_home' => 'Return to home', | 66 | + 'return_home' => 'Volver al home', |
| 67 | - 'error_occurred' => 'An Error Occurred', | 67 | + 'error_occurred' => 'Ha ocurrido un error', |
| 68 | - 'app_down' => ':appName is down right now', | 68 | + 'app_down' => 'La aplicación :appName se encuentra caída en este momento', |
| 69 | - 'back_soon' => 'It will be back up soon.', | 69 | + 'back_soon' => 'Volverá a estar operativa en corto tiempo.', |
| 70 | ]; | 70 | ]; | ... | ... |
This diff is collapsed.
Click to expand it.
| ... | @@ -13,67 +13,67 @@ return [ | ... | @@ -13,67 +13,67 @@ return [ |
| 13 | | | 13 | | |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | - 'accepted' => 'The :attribute must be accepted.', | 16 | + 'accepted' => 'El :attribute debe ser aceptado.', |
| 17 | - 'active_url' => 'The :attribute is not a valid URL.', | 17 | + 'active_url' => 'El :attribute no es una URl válida.', |
| 18 | - 'after' => 'The :attribute must be a date after :date.', | 18 | + 'after' => 'El :attribute debe ser una fecha posterior :date.', |
| 19 | - 'alpha' => 'The :attribute may only contain letters.', | 19 | + 'alpha' => 'El :attribute solo puede contener letras.', |
| 20 | - 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', | 20 | + 'alpha_dash' => 'El :attribute solo puede contener letras, números y guiones.', |
| 21 | - 'alpha_num' => 'The :attribute may only contain letters and numbers.', | 21 | + 'alpha_num' => 'El :attribute solo puede contener letras y número.', |
| 22 | - 'array' => 'The :attribute must be an array.', | 22 | + 'array' => 'El :attribute debe de ser un array.', |
| 23 | - 'before' => 'The :attribute must be a date before :date.', | 23 | + 'before' => 'El :attribute debe ser una fecha anterior a :date.', |
| 24 | 'between' => [ | 24 | 'between' => [ |
| 25 | - 'numeric' => 'The :attribute must be between :min and :max.', | 25 | + 'numeric' => 'El :attribute debe estar entre :min y :max.', |
| 26 | - 'file' => 'The :attribute must be between :min and :max kilobytes.', | 26 | + 'file' => 'El :attribute debe estar entre :min y :max kilobytes.', |
| 27 | - 'string' => 'The :attribute must be between :min and :max characters.', | 27 | + 'string' => 'El :attribute debe estar entre :min y :max carácteres.', |
| 28 | - 'array' => 'The :attribute must have between :min and :max items.', | 28 | + 'array' => 'El :attribute debe estar entre :min y :max items.', |
| 29 | ], | 29 | ], |
| 30 | - 'boolean' => 'The :attribute field must be true or false.', | 30 | + 'boolean' => 'El campo :attribute debe ser true o false.', |
| 31 | - 'confirmed' => 'The :attribute confirmation does not match.', | 31 | + 'confirmed' => 'La confirmación de :attribute no concuerda.', |
| 32 | - 'date' => 'The :attribute is not a valid date.', | 32 | + 'date' => 'El :attribute no es una fecha válida.', |
| 33 | - 'date_format' => 'The :attribute does not match the format :format.', | 33 | + 'date_format' => 'El :attribute no coincide con el formato :format.', |
| 34 | - 'different' => 'The :attribute and :other must be different.', | 34 | + 'different' => ':attribute y :other deben ser diferentes.', |
| 35 | - 'digits' => 'The :attribute must be :digits digits.', | 35 | + 'digits' => ':attribute debe ser de :digits dígitos.', |
| 36 | - 'digits_between' => 'The :attribute must be between :min and :max digits.', | 36 | + 'digits_between' => ':attribute debe ser un valor entre :min y :max dígios.', |
| 37 | - 'email' => 'The :attribute must be a valid email address.', | 37 | + 'email' => ':attribute debe ser una dirección álida.', |
| 38 | - 'filled' => 'The :attribute field is required.', | 38 | + 'filled' => 'El campo :attribute es requerido.', |
| 39 | - 'exists' => 'The selected :attribute is invalid.', | 39 | + 'exists' => 'El :attribute seleccionado es inválido.', |
| 40 | - 'image' => 'The :attribute must be an image.', | 40 | + 'image' => 'El :attribute debe ser una imagen.', |
| 41 | - 'in' => 'The selected :attribute is invalid.', | 41 | + 'in' => 'El selected :attribute es inválio.', |
| 42 | - 'integer' => 'The :attribute must be an integer.', | 42 | + 'integer' => 'El :attribute debe ser un entero.', |
| 43 | - 'ip' => 'The :attribute must be a valid IP address.', | 43 | + 'ip' => 'El :attribute debe ser una dirección IP álida.', |
| 44 | 'max' => [ | 44 | 'max' => [ |
| 45 | - 'numeric' => 'The :attribute may not be greater than :max.', | 45 | + 'numeric' => ':attribute no puede ser mayor que :max.', |
| 46 | - 'file' => 'The :attribute may not be greater than :max kilobytes.', | 46 | + 'file' => ':attribute no puede ser mayor que :max kilobytes.', |
| 47 | - 'string' => 'The :attribute may not be greater than :max characters.', | 47 | + 'string' => ':attribute no puede ser mayor que :max carácteres.', |
| 48 | - 'array' => 'The :attribute may not have more than :max items.', | 48 | + 'array' => ':attribute no puede contener más de :max items.', |
| 49 | ], | 49 | ], |
| 50 | - 'mimes' => 'The :attribute must be a file of type: :values.', | 50 | + 'mimes' => ':attribute debe ser un fichero de tipo: :values.', |
| 51 | 'min' => [ | 51 | 'min' => [ |
| 52 | - 'numeric' => 'The :attribute must be at least :min.', | 52 | + 'numeric' => ':attribute debe ser al menos de :min.', |
| 53 | - 'file' => 'The :attribute must be at least :min kilobytes.', | 53 | + 'file' => ':attribute debe ser al menos :min kilobytes.', |
| 54 | - 'string' => 'The :attribute must be at least :min characters.', | 54 | + 'string' => ':attribute debe ser al menos :min caracteres.', |
| 55 | - 'array' => 'The :attribute must have at least :min items.', | 55 | + 'array' => ':attribute debe tener como mínimo :min items.', |
| 56 | ], | 56 | ], |
| 57 | - 'not_in' => 'The selected :attribute is invalid.', | 57 | + 'not_in' => ':attribute seleccionado es inválio.', |
| 58 | - 'numeric' => 'The :attribute must be a number.', | 58 | + 'numeric' => ':attribute debe ser numérico.', |
| 59 | - 'regex' => 'The :attribute format is invalid.', | 59 | + 'regex' => ':attribute con formato inválido', |
| 60 | - 'required' => 'The :attribute field is required.', | 60 | + 'required' => ':attribute es requerido.', |
| 61 | - 'required_if' => 'The :attribute field is required when :other is :value.', | 61 | + 'required_if' => ':attribute es requerido cuando :other vale :value.', |
| 62 | - 'required_with' => 'The :attribute field is required when :values is present.', | 62 | + 'required_with' => 'El campo :attribute es requerido cuando se encuentre entre los valores :values.', |
| 63 | - 'required_with_all' => 'The :attribute field is required when :values is present.', | 63 | + 'required_with_all' => 'El campo :attribute es requerido cuando los valores sean :values.', |
| 64 | - 'required_without' => 'The :attribute field is required when :values is not present.', | 64 | + 'required_without' => ':attribute es requerido cuando no se encuentre entre los valores :values.', |
| 65 | - 'required_without_all' => 'The :attribute field is required when none of :values are present.', | 65 | + 'required_without_all' => ':attribute es requerido cuando ninguno de los valores :values están presentes.', |
| 66 | - 'same' => 'The :attribute and :other must match.', | 66 | + 'same' => ':attribute y :other deben coincidir.', |
| 67 | 'size' => [ | 67 | 'size' => [ |
| 68 | - 'numeric' => 'The :attribute must be :size.', | 68 | + 'numeric' => ':attribute debe ser :size.', |
| 69 | - 'file' => 'The :attribute must be :size kilobytes.', | 69 | + 'file' => ':attribute debe ser :size kilobytes.', |
| 70 | - 'string' => 'The :attribute must be :size characters.', | 70 | + 'string' => ':attribute debe ser :size caracteres.', |
| 71 | - 'array' => 'The :attribute must contain :size items.', | 71 | + 'array' => ':attribute debe contener :size items.', |
| 72 | ], | 72 | ], |
| 73 | - 'string' => 'The :attribute must be a string.', | 73 | + 'string' => 'El atributo :attribute debe ser una cadena.', |
| 74 | - 'timezone' => 'The :attribute must be a valid zone.', | 74 | + 'timezone' => 'El atributo :attribute debe ser una zona válida.', |
| 75 | - 'unique' => 'The :attribute has already been taken.', | 75 | + 'unique' => 'El atributo :attribute ya ha sido tomado.', |
| 76 | - 'url' => 'The :attribute format is invalid.', | 76 | + 'url' => 'El atributo :attribute tiene un formato inválid.', |
| 77 | 77 | ||
| 78 | /* | 78 | /* |
| 79 | |-------------------------------------------------------------------------- | 79 | |-------------------------------------------------------------------------- |
| ... | @@ -88,7 +88,7 @@ return [ | ... | @@ -88,7 +88,7 @@ return [ |
| 88 | 88 | ||
| 89 | 'custom' => [ | 89 | 'custom' => [ |
| 90 | 'password-confirm' => [ | 90 | 'password-confirm' => [ |
| 91 | - 'required_with' => 'Password confirmation required', | 91 | + 'required_with' => 'Confirmación de Password requerida', |
| 92 | ], | 92 | ], |
| 93 | ], | 93 | ], |
| 94 | 94 | ... | ... |
| ... | @@ -43,18 +43,9 @@ return [ | ... | @@ -43,18 +43,9 @@ return [ |
| 43 | * Search | 43 | * Search |
| 44 | */ | 44 | */ |
| 45 | 'search_results' => 'Résultats de recherche', | 45 | 'search_results' => 'Résultats de recherche', |
| 46 | - 'search_results_page' => 'Résultats de recherche des pages', | ||
| 47 | - 'search_results_chapter' => 'Résultats de recherche des chapitres', | ||
| 48 | - 'search_results_book' => 'Résultats de recherche des livres', | ||
| 49 | 'search_clear' => 'Réinitialiser la recherche', | 46 | 'search_clear' => 'Réinitialiser la recherche', |
| 50 | - 'search_view_pages' => 'Voir toutes les pages correspondantes', | ||
| 51 | - 'search_view_chapters' => 'Voir tous les chapitres correspondants', | ||
| 52 | - 'search_view_books' => 'Voir tous les livres correspondants', | ||
| 53 | 'search_no_pages' => 'Aucune page correspondant à cette recherche', | 47 | 'search_no_pages' => 'Aucune page correspondant à cette recherche', |
| 54 | 'search_for_term' => 'recherche pour :term', | 48 | 'search_for_term' => 'recherche pour :term', |
| 55 | - 'search_page_for_term' => 'Recherche de page pour :term', | ||
| 56 | - 'search_chapter_for_term' => 'Recherche de chapitre pour :term', | ||
| 57 | - 'search_book_for_term' => 'Recherche de livres pour :term', | ||
| 58 | 49 | ||
| 59 | /** | 50 | /** |
| 60 | * Books | 51 | * Books | ... | ... |
| ... | @@ -43,18 +43,9 @@ return [ | ... | @@ -43,18 +43,9 @@ return [ |
| 43 | * Search | 43 | * Search |
| 44 | */ | 44 | */ |
| 45 | 'search_results' => 'Zoekresultaten', | 45 | 'search_results' => 'Zoekresultaten', |
| 46 | - 'search_results_page' => 'Pagina Zoekresultaten', | ||
| 47 | - 'search_results_chapter' => 'Hoofdstuk Zoekresultaten', | ||
| 48 | - 'search_results_book' => 'Boek Zoekresultaten', | ||
| 49 | 'search_clear' => 'Zoekopdracht wissen', | 46 | 'search_clear' => 'Zoekopdracht wissen', |
| 50 | - 'search_view_pages' => 'Bekijk alle gevonden pagina\'s', | ||
| 51 | - 'search_view_chapters' => 'Bekijk alle gevonden hoofdstukken', | ||
| 52 | - 'search_view_books' => 'Bekijk alle gevonden boeken', | ||
| 53 | 'search_no_pages' => 'Er zijn geen pagina\'s gevonden', | 47 | 'search_no_pages' => 'Er zijn geen pagina\'s gevonden', |
| 54 | 'search_for_term' => 'Zoeken op :term', | 48 | 'search_for_term' => 'Zoeken op :term', |
| 55 | - 'search_page_for_term' => 'Pagina doorzoeken op :term', | ||
| 56 | - 'search_chapter_for_term' => 'Hoofdstuk doorzoeken op :term', | ||
| 57 | - 'search_book_for_term' => 'Boeken doorzoeken op :term', | ||
| 58 | 49 | ||
| 59 | /** | 50 | /** |
| 60 | * Books | 51 | * Books | ... | ... |
| ... | @@ -43,18 +43,9 @@ return [ | ... | @@ -43,18 +43,9 @@ return [ |
| 43 | * Search | 43 | * Search |
| 44 | */ | 44 | */ |
| 45 | 'search_results' => 'Resultado(s) da Pesquisa', | 45 | 'search_results' => 'Resultado(s) da Pesquisa', |
| 46 | - 'search_results_page' => 'Resultado(s) de Pesquisa de Página', | ||
| 47 | - 'search_results_chapter' => 'Resultado(s) de Pesquisa de Capítulo', | ||
| 48 | - 'search_results_book' => 'Resultado(s) de Pesquisa de Livro', | ||
| 49 | 'search_clear' => 'Limpar Pesquisa', | 46 | 'search_clear' => 'Limpar Pesquisa', |
| 50 | - 'search_view_pages' => 'Visualizar todas as páginas correspondentes', | ||
| 51 | - 'search_view_chapters' => 'Visualizar todos os capítulos correspondentes', | ||
| 52 | - 'search_view_books' => 'Visualizar todos os livros correspondentes', | ||
| 53 | 'search_no_pages' => 'Nenhuma página corresponde à pesquisa', | 47 | 'search_no_pages' => 'Nenhuma página corresponde à pesquisa', |
| 54 | 'search_for_term' => 'Pesquisar por :term', | 48 | 'search_for_term' => 'Pesquisar por :term', |
| 55 | - 'search_page_for_term' => 'Pesquisar Página por :term', | ||
| 56 | - 'search_chapter_for_term' => 'Pesquisar Capítulo por :term', | ||
| 57 | - 'search_book_for_term' => 'Pesquisar Livros por :term', | ||
| 58 | 49 | ||
| 59 | /** | 50 | /** |
| 60 | * Books | 51 | * Books | ... | ... |
resources/lang/sk/activities.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * Activity text strings. | ||
| 7 | + * Is used for all the text within activity logs & notifications. | ||
| 8 | + */ | ||
| 9 | + | ||
| 10 | + // Pages | ||
| 11 | + 'page_create' => 'vytvoril stránku', | ||
| 12 | + 'page_create_notification' => 'Stránka úspešne vytvorená', | ||
| 13 | + 'page_update' => 'aktualizoval stránku', | ||
| 14 | + 'page_update_notification' => 'Stránka úspešne aktualizovaná', | ||
| 15 | + 'page_delete' => 'odstránil stránku', | ||
| 16 | + 'page_delete_notification' => 'Stránka úspešne odstránená', | ||
| 17 | + 'page_restore' => 'obnovil stránku', | ||
| 18 | + 'page_restore_notification' => 'Stránka úspešne obnovená', | ||
| 19 | + 'page_move' => 'presunul stránku', | ||
| 20 | + | ||
| 21 | + // Chapters | ||
| 22 | + 'chapter_create' => 'vytvoril kapitolu', | ||
| 23 | + 'chapter_create_notification' => 'Kapitola úspešne vytvorená', | ||
| 24 | + 'chapter_update' => 'aktualizoval kapitolu', | ||
| 25 | + 'chapter_update_notification' => 'Kapitola úspešne aktualizovaná', | ||
| 26 | + 'chapter_delete' => 'odstránil kapitolu', | ||
| 27 | + 'chapter_delete_notification' => 'Kapitola úspešne odstránená', | ||
| 28 | + 'chapter_move' => 'presunul kapitolu', | ||
| 29 | + | ||
| 30 | + // Books | ||
| 31 | + 'book_create' => 'vytvoril knihu', | ||
| 32 | + 'book_create_notification' => 'Kniha úspešne vytvorená', | ||
| 33 | + 'book_update' => 'aktualizoval knihu', | ||
| 34 | + 'book_update_notification' => 'Kniha úspešne aktualizovaná', | ||
| 35 | + 'book_delete' => 'odstránil knihu', | ||
| 36 | + 'book_delete_notification' => 'Kniha úspešne odstránená', | ||
| 37 | + 'book_sort' => 'zoradil knihu', | ||
| 38 | + 'book_sort_notification' => 'Kniha úspešne znovu zoradená', | ||
| 39 | + | ||
| 40 | +]; |
resources/lang/sk/auth.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + /* | ||
| 4 | + |-------------------------------------------------------------------------- | ||
| 5 | + | Authentication Language Lines | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | | ||
| 8 | + | The following language lines are used during authentication for various | ||
| 9 | + | messages that we need to display to the user. You are free to modify | ||
| 10 | + | these language lines according to your application's requirements. | ||
| 11 | + | | ||
| 12 | + */ | ||
| 13 | + 'failed' => 'Tieto údaje nesedia s našimi záznamami.', | ||
| 14 | + 'throttle' => 'Priveľa pokusov o prihlásenie. Skúste znova o :seconds sekúnd.', | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * Login & Register | ||
| 18 | + */ | ||
| 19 | + 'sign_up' => 'Registrácia', | ||
| 20 | + 'log_in' => 'Prihlásenie', | ||
| 21 | + 'log_in_with' => 'Prihlásiť sa cez :socialDriver', | ||
| 22 | + 'sign_up_with' => 'Registrovať sa cez :socialDriver', | ||
| 23 | + 'logout' => 'Odhlásenie', | ||
| 24 | + | ||
| 25 | + 'name' => 'Meno', | ||
| 26 | + 'username' => 'Používateľské meno', | ||
| 27 | + 'email' => 'Email', | ||
| 28 | + 'password' => 'Heslo', | ||
| 29 | + 'password_confirm' => 'Potvrdiť heslo', | ||
| 30 | + 'password_hint' => 'Musí mať viac ako 5 znakov', | ||
| 31 | + 'forgot_password' => 'Zabudli ste heslo?', | ||
| 32 | + 'remember_me' => 'Zapamätať si ma', | ||
| 33 | + 'ldap_email_hint' => 'Zadajte prosím email, ktorý sa má použiť pre tento účet.', | ||
| 34 | + 'create_account' => 'Vytvoriť účet', | ||
| 35 | + 'social_login' => 'Sociálne prihlásenie', | ||
| 36 | + 'social_registration' => 'Sociálna registrácia', | ||
| 37 | + 'social_registration_text' => 'Registrovať sa a prihlásiť sa použitím inej služby.', | ||
| 38 | + | ||
| 39 | + 'register_thanks' => 'Ďakujeme zaregistráciu!', | ||
| 40 | + 'register_confirm' => 'Skontrolujte prosím svoj email a kliknite na potvrdzujúce tlačidlo pre prístup k :appName.', | ||
| 41 | + 'registrations_disabled' => 'Registrácie sú momentálne zablokované', | ||
| 42 | + 'registration_email_domain_invalid' => 'Táto emailová doména nemá prístup k tejto aplikácii', | ||
| 43 | + 'register_success' => 'Ďakujeme za registráciu! Teraz ste registrovaný a prihlásený.', | ||
| 44 | + | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * Password Reset | ||
| 48 | + */ | ||
| 49 | + 'reset_password' => 'Reset hesla', | ||
| 50 | + 'reset_password_send_instructions' => 'Zadajte svoj email nižšie a bude Vám odoslaný email s odkazom pre reset hesla.', | ||
| 51 | + 'reset_password_send_button' => 'Poslať odkaz na reset hesla', | ||
| 52 | + 'reset_password_sent_success' => 'Odkaz na reset hesla bol poslaný na :email.', | ||
| 53 | + 'reset_password_success' => 'Vaše heslo bolo úspešne resetované.', | ||
| 54 | + | ||
| 55 | + 'email_reset_subject' => 'Reset Vášho :appName hesla', | ||
| 56 | + 'email_reset_text' => 'Tento email Ste dostali pretože sme dostali požiadavku na reset hesla pre Váš účet.', | ||
| 57 | + 'email_reset_not_requested' => 'Ak ste nepožiadali o reset hesla, nemusíte nič robiť.', | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * Email Confirmation | ||
| 62 | + */ | ||
| 63 | + 'email_confirm_subject' => 'Potvrdiť email na :appName', | ||
| 64 | + 'email_confirm_greeting' => 'Ďakujeme za pridanie sa k :appName!', | ||
| 65 | + 'email_confirm_text' => 'Prosím potvrďte Vašu emailovú adresu kliknutím na tlačidlo nižšie:', | ||
| 66 | + 'email_confirm_action' => 'Potvrdiť email', | ||
| 67 | + 'email_confirm_send_error' => 'Je požadované overenie emailu, ale systém nemohol odoslať email. Kontaktujte administrátora by ste sa uistili, že email je nastavený správne.', | ||
| 68 | + 'email_confirm_success' => 'Váš email bol overený!', | ||
| 69 | + 'email_confirm_resent' => 'Potvrdzujúci email bol poslaný znovu, skontrolujte prosím svoju emailovú schránku.', | ||
| 70 | + | ||
| 71 | + 'email_not_confirmed' => 'Emailová adresa nebola overená', | ||
| 72 | + 'email_not_confirmed_text' => 'Vaša emailová adresa nebola zatiaľ overená.', | ||
| 73 | + 'email_not_confirmed_click_link' => 'Prosím, kliknite na odkaz v emaili, ktorý bol poslaný krátko po Vašej registrácii.', | ||
| 74 | + 'email_not_confirmed_resend' => 'Ak nemôžete násť email, môžete znova odoslať overovací email odoslaním doleuvedeného formulára.', | ||
| 75 | + 'email_not_confirmed_resend_button' => 'Znova odoslať overovací email', | ||
| 76 | +]; |
resources/lang/sk/common.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + | ||
| 4 | + /** | ||
| 5 | + * Buttons | ||
| 6 | + */ | ||
| 7 | + 'cancel' => 'Zrušiť', | ||
| 8 | + 'confirm' => 'Potvrdiť', | ||
| 9 | + 'back' => 'Späť', | ||
| 10 | + 'save' => 'Uložiť', | ||
| 11 | + 'continue' => 'Pokračovať', | ||
| 12 | + 'select' => 'Vybrať', | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * Form Labels | ||
| 16 | + */ | ||
| 17 | + 'name' => 'Meno', | ||
| 18 | + 'description' => 'Popis', | ||
| 19 | + 'role' => 'Rola', | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * Actions | ||
| 23 | + */ | ||
| 24 | + 'actions' => 'Akcie', | ||
| 25 | + 'view' => 'Zobraziť', | ||
| 26 | + 'create' => 'Vytvoriť', | ||
| 27 | + 'update' => 'Aktualizovať', | ||
| 28 | + 'edit' => 'Editovať', | ||
| 29 | + 'sort' => 'Zoradiť', | ||
| 30 | + 'move' => 'Presunúť', | ||
| 31 | + 'delete' => 'Zmazať', | ||
| 32 | + 'search' => 'Hľadť', | ||
| 33 | + 'search_clear' => 'Vyčistiť hľadanie', | ||
| 34 | + 'reset' => 'Reset', | ||
| 35 | + 'remove' => 'Odstrániť', | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * Misc | ||
| 40 | + */ | ||
| 41 | + 'deleted_user' => 'Odstránený používateľ', | ||
| 42 | + 'no_activity' => 'Žiadna aktivita na zobrazenie', | ||
| 43 | + 'no_items' => 'Žiadne položky nie sú dostupné', | ||
| 44 | + 'back_to_top' => 'Späť nahor', | ||
| 45 | + 'toggle_details' => 'Prepnúť detaily', | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * Header | ||
| 49 | + */ | ||
| 50 | + 'view_profile' => 'Zobraziť profil', | ||
| 51 | + 'edit_profile' => 'Upraviť profil', | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * Email Content | ||
| 55 | + */ | ||
| 56 | + 'email_action_help' => 'Ak máte problém klinkúť na tlačidlo ":actionText", skopírujte a vložte URL uvedenú nižšie do Vášho prehliadača:', | ||
| 57 | + 'email_rights' => 'Všetky práva vyhradené', | ||
| 58 | +]; |
resources/lang/sk/components.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + | ||
| 4 | + /** | ||
| 5 | + * Image Manager | ||
| 6 | + */ | ||
| 7 | + 'image_select' => 'Vybrať obrázok', | ||
| 8 | + 'image_all' => 'Všetko', | ||
| 9 | + 'image_all_title' => 'Zobraziť všetky obrázky', | ||
| 10 | + 'image_book_title' => 'Zobraziť obrázky nahrané do tejto knihy', | ||
| 11 | + 'image_page_title' => 'Zobraziť obrázky nahrané do tejto stránky', | ||
| 12 | + 'image_search_hint' => 'Hľadať obrázok podľa názvu', | ||
| 13 | + 'image_uploaded' => 'Nahrané :uploadedDate', | ||
| 14 | + 'image_load_more' => 'Načítať viac', | ||
| 15 | + 'image_image_name' => 'Názov obrázka', | ||
| 16 | + 'image_delete_confirm' => 'Tento obrázok je použitý na stránkach uvedených nižšie, kliknite znova na zmazať pre potvrdenie zmazania tohto obrázka.', | ||
| 17 | + 'image_select_image' => 'Vybrať obrázok', | ||
| 18 | + 'image_dropzone' => 'Presuňte obrázky sem alebo kliknite sem pre nahranie', | ||
| 19 | + 'images_deleted' => 'Obrázky zmazané', | ||
| 20 | + 'image_preview' => 'Náhľad obrázka', | ||
| 21 | + 'image_upload_success' => 'Obrázok úspešne nahraný', | ||
| 22 | + 'image_update_success' => 'Detaily obrázka úspešne aktualizované', | ||
| 23 | + 'image_delete_success' => 'Obrázok úspešne zmazaný' | ||
| 24 | +]; |
resources/lang/sk/entities.php
0 → 100644
This diff is collapsed.
Click to expand it.
resources/lang/sk/errors.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * Error text strings. | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | + // Permissions | ||
| 10 | + 'permission' => 'Nemáte oprávnenie pre prístup k požadovanej stránke.', | ||
| 11 | + 'permissionJson' => 'Nemáte oprávnenie pre vykonanie požadovaného úkonu.', | ||
| 12 | + | ||
| 13 | + // Auth | ||
| 14 | + 'error_user_exists_different_creds' => 'Používateľ s emailom :email už existuje, ale s inými údajmi.', | ||
| 15 | + 'email_already_confirmed' => 'Email bol už overený, skúste sa prihlásiť.', | ||
| 16 | + 'email_confirmation_invalid' => 'Tento potvrdzujúci token nie je platný alebo už bol použitý, skúste sa prosím registrovať znova.', | ||
| 17 | + 'email_confirmation_expired' => 'Potvrdzujúci token expiroval, bol odoslaný nový potvrdzujúci email.', | ||
| 18 | + 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', | ||
| 19 | + 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', | ||
| 20 | + 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', | ||
| 21 | + 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', | ||
| 22 | + 'social_no_action_defined' => 'Nebola definovaná žiadna akcia', | ||
| 23 | + 'social_account_in_use' => 'Tento :socialAccount účet sa už používa, skúste sa prihlásiť pomocou možnosti :socialAccount.', | ||
| 24 | + 'social_account_email_in_use' => 'Email :email sa už používa. Ak už máte účet, môžete pripojiť svoj :socialAccount účet v nastaveniach profilu.', | ||
| 25 | + 'social_account_existing' => 'Tento :socialAccount účet je už spojený s Vaším profilom.', | ||
| 26 | + 'social_account_already_used_existing' => 'Tento :socialAccount účet už používa iný používateľ.', | ||
| 27 | + 'social_account_not_used' => 'Tento :socialAccount účet nie je spojený so žiadnym používateľom. Pripojte ho prosím v nastaveniach Vášho profilu. ', | ||
| 28 | + 'social_account_register_instructions' => 'Ak zatiaľ nemáte účet, môžete sa registrovať pomocou možnosti :socialAccount.', | ||
| 29 | + 'social_driver_not_found' => 'Ovládač socialnych sietí nebol nájdený', | ||
| 30 | + 'social_driver_not_configured' => 'Nastavenia Vášho :socialAccount účtu nie sú správne.', | ||
| 31 | + | ||
| 32 | + // System | ||
| 33 | + 'path_not_writable' => 'Do cesty :filePath sa nedá nahrávať. Uistite sa, že je zapisovateľná serverom.', | ||
| 34 | + 'cannot_get_image_from_url' => 'Nedá sa získať obrázok z :url', | ||
| 35 | + 'cannot_create_thumbs' => 'Server nedokáže vytvoriť náhľady. Skontrolujte prosím, či máte nainštalované GD rozšírenie PHP.', | ||
| 36 | + 'server_upload_limit' => 'Server nedovoľuje nahrávanie súborov s takouto veľkosťou. Skúste prosím menší súbor.', | ||
| 37 | + 'image_upload_error' => 'Pri nahrávaní obrázka nastala chyba', | ||
| 38 | + | ||
| 39 | + // Attachments | ||
| 40 | + 'attachment_page_mismatch' => 'Page mismatch during attachment update', | ||
| 41 | + | ||
| 42 | + // Pages | ||
| 43 | + 'page_draft_autosave_fail' => 'Koncept nemohol byť uložený. Uistite sa, že máte pripojenie k internetu pre uložením tejto stránky', | ||
| 44 | + | ||
| 45 | + // Entities | ||
| 46 | + 'entity_not_found' => 'Entita nenájdená', | ||
| 47 | + 'book_not_found' => 'Kniha nenájdená', | ||
| 48 | + 'page_not_found' => 'Stránka nenájdená', | ||
| 49 | + 'chapter_not_found' => 'Kapitola nenájdená', | ||
| 50 | + 'selected_book_not_found' => 'Vybraná kniha nebola nájdená', | ||
| 51 | + 'selected_book_chapter_not_found' => 'Vybraná kniha alebo kapitola nebola nájdená', | ||
| 52 | + 'guests_cannot_save_drafts' => 'Hosť nemôže ukladať koncepty', | ||
| 53 | + | ||
| 54 | + // Users | ||
| 55 | + 'users_cannot_delete_only_admin' => 'Nemôžete zmazať posledného správcu', | ||
| 56 | + 'users_cannot_delete_guest' => 'Nemôžete zmazať hosťa', | ||
| 57 | + | ||
| 58 | + // Roles | ||
| 59 | + 'role_cannot_be_edited' => 'Táto rola nemôže byť upravovaná', | ||
| 60 | + 'role_system_cannot_be_deleted' => 'Táto rola je systémová rola a nemôže byť zmazaná', | ||
| 61 | + 'role_registration_default_cannot_delete' => 'Táto rola nemôže byť zmazaná, pretože je nastavená ako prednastavená rola pri registrácii', | ||
| 62 | + | ||
| 63 | + // Error pages | ||
| 64 | + '404_page_not_found' => 'Stránka nenájdená', | ||
| 65 | + 'sorry_page_not_found' => 'Prepáčte, stránka ktorú hľadáte nebola nájdená.', | ||
| 66 | + 'return_home' => 'Vrátiť sa domov', | ||
| 67 | + 'error_occurred' => 'Nastala chyba', | ||
| 68 | + 'app_down' => ':appName je momentálne nedostupná', | ||
| 69 | + 'back_soon' => 'Čoskoro bude opäť dostupná.', | ||
| 70 | +]; |
resources/lang/sk/pagination.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /* | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | Pagination Language Lines | ||
| 8 | + |-------------------------------------------------------------------------- | ||
| 9 | + | | ||
| 10 | + | The following language lines are used by the paginator library to build | ||
| 11 | + | the simple pagination links. You are free to change them to anything | ||
| 12 | + | you want to customize your views to better match your application. | ||
| 13 | + | | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + 'previous' => '« Predchádzajúca', | ||
| 17 | + 'next' => 'Ďalšia »', | ||
| 18 | + | ||
| 19 | +]; |
resources/lang/sk/passwords.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /* | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | Password Reminder Language Lines | ||
| 8 | + |-------------------------------------------------------------------------- | ||
| 9 | + | | ||
| 10 | + | The following language lines are the default lines which match reasons | ||
| 11 | + | that are given by the password broker for a password update attempt | ||
| 12 | + | has failed, such as for an invalid token or invalid new password. | ||
| 13 | + | | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + 'password' => 'Heslo musí obsahovať aspoň šesť znakov a musí byť rovnaké ako potvrdzujúce.', | ||
| 17 | + 'user' => "Nenašli sme používateľa s takou emailovou adresou.", | ||
| 18 | + 'token' => 'Tento token pre reset hesla je neplatný.', | ||
| 19 | + 'sent' => 'Poslali sme Vám email s odkazom na reset hesla!', | ||
| 20 | + 'reset' => 'Vaše heslo bolo resetované!', | ||
| 21 | + | ||
| 22 | +]; |
resources/lang/sk/settings.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * Settings text strings | ||
| 7 | + * Contains all text strings used in the general settings sections of BookStack | ||
| 8 | + * including users and roles. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + 'settings' => 'Nastavenia', | ||
| 12 | + 'settings_save' => 'Uložiť nastavenia', | ||
| 13 | + 'settings_save_success' => 'Nastavenia uložené', | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * App settings | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + 'app_settings' => 'Nastavenia aplikácie', | ||
| 20 | + 'app_name' => 'Názov aplikácia', | ||
| 21 | + 'app_name_desc' => 'Tento názov sa zobrazuje v hlavičke a v emailoch.', | ||
| 22 | + 'app_name_header' => 'Zobraziť názov aplikácie v hlavičke?', | ||
| 23 | + 'app_public_viewing' => 'Povoliť verejné zobrazenie?', | ||
| 24 | + 'app_secure_images' => 'Povoliť nahrávanie súborov so zvýšeným zabezpečením?', | ||
| 25 | + 'app_secure_images_desc' => 'Kvôli výkonu sú všetky obrázky verejné. Táto možnosť pridá pred URL obrázka náhodný, ťažko uhádnuteľný reťazec. Aby ste zabránili jednoduchému prístupu, uistite sa, že indexy priečinkov nie sú povolené.', | ||
| 26 | + 'app_editor' => 'Editor stránky', | ||
| 27 | + 'app_editor_desc' => 'Vyberte editor, ktorý bude používaný všetkými používateľmi na editáciu stránok.', | ||
| 28 | + 'app_custom_html' => 'Vlastný HTML obsah hlavičky', | ||
| 29 | + 'app_custom_html_desc' => 'Všetok text pridaný sem bude vložený naspodok <head> sekcie na každej stránke. Môže sa to zísť pri zmene štýlu alebo pre pridanie analytického kódu.', | ||
| 30 | + 'app_logo' => 'Logo aplikácie', | ||
| 31 | + 'app_logo_desc' => 'Tento obrázok by mal mať 43px na výšku. <br>Veľké obrázky budú preškálované na menší rozmer.', | ||
| 32 | + 'app_primary_color' => 'Primárna farba pre aplikáciu', | ||
| 33 | + 'app_primary_color_desc' => 'Toto by mala byť hodnota v hex tvare. <br>Nechajte prázdne ak chcete použiť prednastavenú farbu.', | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * Registration settings | ||
| 37 | + */ | ||
| 38 | + | ||
| 39 | + 'reg_settings' => 'Nastavenia registrácie', | ||
| 40 | + 'reg_allow' => 'Povoliť registráciu?', | ||
| 41 | + 'reg_default_role' => 'Prednastavená používateľská rola po registrácii', | ||
| 42 | + 'reg_confirm_email' => 'Vyžadovať overenie emailu?', | ||
| 43 | + 'reg_confirm_email_desc' => 'Ak je použité obmedzenie domény, potom bude vyžadované overenie emailu a hodnota nižšie bude ignorovaná.', | ||
| 44 | + 'reg_confirm_restrict_domain' => 'Obmedziť registráciu na doménu', | ||
| 45 | + 'reg_confirm_restrict_domain_desc' => 'Zadajte zoznam domén, pre ktoré chcete povoliť registráciu oddelených čiarkou. Používatelia dostanú email kvôli overeniu adresy predtým ako im bude dovolené používať aplikáciu. <br> Používatelia si budú môcť po úspešnej registrácii zmeniť svoju emailovú adresu.', | ||
| 46 | + 'reg_confirm_restrict_domain_placeholder' => 'Nie sú nastavené žiadne obmedzenia', | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * Role settings | ||
| 50 | + */ | ||
| 51 | + | ||
| 52 | + 'roles' => 'Roly', | ||
| 53 | + 'role_user_roles' => 'Používateľské roly', | ||
| 54 | + 'role_create' => 'Vytvoriť novú rolu', | ||
| 55 | + 'role_create_success' => 'Rola úspešne vytvorená', | ||
| 56 | + 'role_delete' => 'Zmazať rolu', | ||
| 57 | + 'role_delete_confirm' => 'Toto zmaže rolu menom \':roleName\'.', | ||
| 58 | + 'role_delete_users_assigned' => 'Túto rolu má priradenú :userCount používateľov. Ak chcete premigrovať používateľov z tejto roly, vyberte novú rolu nižšie.', | ||
| 59 | + 'role_delete_no_migration' => "Nemigrovať používateľov", | ||
| 60 | + 'role_delete_sure' => 'Ste si istý, že chcete zmazať túto rolu?', | ||
| 61 | + 'role_delete_success' => 'Rola úspešne zmazaná', | ||
| 62 | + 'role_edit' => 'Upraviť rolu', | ||
| 63 | + 'role_details' => 'Detaily roly', | ||
| 64 | + 'role_name' => 'Názov roly', | ||
| 65 | + 'role_desc' => 'Krátky popis roly', | ||
| 66 | + 'role_system' => 'Systémové oprávnenia', | ||
| 67 | + 'role_manage_users' => 'Spravovať používateľov', | ||
| 68 | + 'role_manage_roles' => 'Spravovať role a oprávnenia rolí', | ||
| 69 | + 'role_manage_entity_permissions' => 'Spravovať všetky oprávnenia kníh, kapitol a stránok', | ||
| 70 | + 'role_manage_own_entity_permissions' => 'Spravovať oprávnenia vlastných kníh, kapitol a stránok', | ||
| 71 | + 'role_manage_settings' => 'Spravovať nastavenia aplikácie', | ||
| 72 | + 'role_asset' => 'Oprávnenia majetku', | ||
| 73 | + 'role_asset_desc' => 'Tieto oprávnenia regulujú prednastavený prístup k zdroju v systéme. Oprávnenia pre knihy, kapitoly a stránky majú vyššiu prioritu.', | ||
| 74 | + 'role_all' => 'Všetko', | ||
| 75 | + 'role_own' => 'Vlastné', | ||
| 76 | + 'role_controlled_by_asset' => 'Regulované zdrojom, do ktorého sú nahrané', | ||
| 77 | + 'role_save' => 'Uložiť rolu', | ||
| 78 | + 'role_update_success' => 'Roly úspešne aktualizované', | ||
| 79 | + 'role_users' => 'Používatelia s touto rolou', | ||
| 80 | + 'role_users_none' => 'Žiadni používatelia nemajú priradenú túto rolu', | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * Users | ||
| 84 | + */ | ||
| 85 | + | ||
| 86 | + 'users' => 'Používatelia', | ||
| 87 | + 'user_profile' => 'Profil používateľa', | ||
| 88 | + 'users_add_new' => 'Pridať nového používateľa', | ||
| 89 | + 'users_search' => 'Hľadať medzi používateľmi', | ||
| 90 | + 'users_role' => 'Používateľské roly', | ||
| 91 | + 'users_external_auth_id' => 'Externé autentifikačné ID', | ||
| 92 | + 'users_password_warning' => 'Pole nižšie vyplňte iba ak chcete zmeniť heslo:', | ||
| 93 | + 'users_system_public' => 'Tento účet reprezentuje každého hosťovského používateľa, ktorý navštívi Vašu inštanciu. Nedá sa pomocou neho prihlásiť a je priradený automaticky.', | ||
| 94 | + 'users_delete' => 'Zmazať používateľa', | ||
| 95 | + 'users_delete_named' => 'Zmazať používateľa :userName', | ||
| 96 | + 'users_delete_warning' => ' Toto úplne odstráni používateľa menom \':userName\' zo systému.', | ||
| 97 | + 'users_delete_confirm' => 'Ste si istý, že chcete zmazať tohoto používateľa?', | ||
| 98 | + 'users_delete_success' => 'Používateľ úspešne zmazaný', | ||
| 99 | + 'users_edit' => 'Upraviť používateľa', | ||
| 100 | + 'users_edit_profile' => 'Upraviť profil', | ||
| 101 | + 'users_edit_success' => 'Používateľ úspešne upravený', | ||
| 102 | + 'users_avatar' => 'Avatar používateľa', | ||
| 103 | + 'users_avatar_desc' => 'Tento obrázok by mal byť štvorec s rozmerom približne 256px.', | ||
| 104 | + 'users_preferred_language' => 'Preferovaný jazyk', | ||
| 105 | + 'users_social_accounts' => 'Sociálne účty', | ||
| 106 | + 'users_social_accounts_info' => 'Tu si môžete pripojiť iné účty pre rýchlejšie a jednoduchšie prihlásenie. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.', | ||
| 107 | + 'users_social_connect' => 'Pripojiť účet', | ||
| 108 | + 'users_social_disconnect' => 'Odpojiť účet', | ||
| 109 | + 'users_social_connected' => ':socialAccount účet bol úspešne pripojený k Vášmu profilu.', | ||
| 110 | + 'users_social_disconnected' => ':socialAccount účet bol úspešne odpojený od Vášho profilu.', | ||
| 111 | +]; |
resources/lang/sk/validation.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /* | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | Validation Language Lines | ||
| 8 | + |-------------------------------------------------------------------------- | ||
| 9 | + | | ||
| 10 | + | The following language lines contain the default error messages used by | ||
| 11 | + | the validator class. Some of these rules have multiple versions such | ||
| 12 | + | as the size rules. Feel free to tweak each of these messages here. | ||
| 13 | + | | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + 'accepted' => ':attribute musí byť akceptovaný.', | ||
| 17 | + 'active_url' => ':attribute nie je platná URL.', | ||
| 18 | + 'after' => ':attribute musí byť dátum po :date.', | ||
| 19 | + 'alpha' => ':attribute môže obsahovať iba písmená.', | ||
| 20 | + 'alpha_dash' => ':attribute môže obsahovať iba písmená, čísla a pomlčky.', | ||
| 21 | + 'alpha_num' => ':attribute môže obsahovať iba písmená a čísla.', | ||
| 22 | + 'array' => ':attribute musí byť pole.', | ||
| 23 | + 'before' => ':attribute musí byť dátum pred :date.', | ||
| 24 | + 'between' => [ | ||
| 25 | + 'numeric' => ':attribute musí byť medzi :min a :max.', | ||
| 26 | + 'file' => ':attribute musí byť medzi :min a :max kilobajtmi.', | ||
| 27 | + 'string' => ':attribute musí byť medzi :min a :max znakmi.', | ||
| 28 | + 'array' => ':attribute musí byť medzi :min a :max položkami.', | ||
| 29 | + ], | ||
| 30 | + 'boolean' => ':attribute pole musí byť true alebo false.', | ||
| 31 | + 'confirmed' => ':attribute potvrdenie nesedí.', | ||
| 32 | + 'date' => ':attribute nie je platný dátum.', | ||
| 33 | + 'date_format' => ':attribute nesedí s formátom :format.', | ||
| 34 | + 'different' => ':attribute a :other musia byť rozdielne.', | ||
| 35 | + 'digits' => ':attribute musí mať :digits číslic.', | ||
| 36 | + 'digits_between' => ':attribute musí mať medzi :min a :max číslicami.', | ||
| 37 | + 'email' => ':attribute musí byť platná emailová adresa.', | ||
| 38 | + 'filled' => 'Políčko :attribute je povinné.', | ||
| 39 | + 'exists' => 'Vybraný :attribute nie je platný.', | ||
| 40 | + 'image' => ':attribute musí byť obrázok.', | ||
| 41 | + 'in' => 'Vybraný :attribute je neplatný.', | ||
| 42 | + 'integer' => ':attribute musí byť celé číslo.', | ||
| 43 | + 'ip' => ':attribute musí byť platná IP adresa.', | ||
| 44 | + 'max' => [ | ||
| 45 | + 'numeric' => ':attribute nesmie byť väčší ako :max.', | ||
| 46 | + 'file' => ':attribute nesmie byť väčší ako :max kilobajtov.', | ||
| 47 | + 'string' => ':attribute nesmie byť dlhší ako :max znakov.', | ||
| 48 | + 'array' => ':attribute nesmie mať viac ako :max položiek.', | ||
| 49 | + ], | ||
| 50 | + 'mimes' => ':attribute musí byť súbor typu: :values.', | ||
| 51 | + 'min' => [ | ||
| 52 | + 'numeric' => ':attribute musí byť aspoň :min.', | ||
| 53 | + 'file' => ':attribute musí mať aspoň :min kilobajtov.', | ||
| 54 | + 'string' => ':attribute musí mať aspoň :min znakov.', | ||
| 55 | + 'array' => ':attribute musí mať aspoň :min položiek.', | ||
| 56 | + ], | ||
| 57 | + 'not_in' => 'Vybraný :attribute je neplatný.', | ||
| 58 | + 'numeric' => ':attribute musí byť číslo.', | ||
| 59 | + 'regex' => ':attribute formát je neplatný.', | ||
| 60 | + 'required' => 'Políčko :attribute je povinné.', | ||
| 61 | + 'required_if' => 'Políčko :attribute je povinné ak :other je :value.', | ||
| 62 | + 'required_with' => 'Políčko :attribute je povinné ak :values existuje.', | ||
| 63 | + 'required_with_all' => 'Políčko :attribute je povinné ak :values existuje.', | ||
| 64 | + 'required_without' => 'Políčko :attribute je povinné aj :values neexistuje.', | ||
| 65 | + 'required_without_all' => 'Políčko :attribute je povinné ak ani jedno z :values neexistuje.', | ||
| 66 | + 'same' => ':attribute a :other musia byť rovnaké.', | ||
| 67 | + 'size' => [ | ||
| 68 | + 'numeric' => ':attribute musí byť :size.', | ||
| 69 | + 'file' => ':attribute musí mať :size kilobajtov.', | ||
| 70 | + 'string' => ':attribute musí mať :size znakov.', | ||
| 71 | + 'array' => ':attribute musí obsahovať :size položiek.', | ||
| 72 | + ], | ||
| 73 | + 'string' => ':attribute musí byť reťazec.', | ||
| 74 | + 'timezone' => ':attribute musí byť plantá časová zóna.', | ||
| 75 | + 'unique' => ':attribute je už použité.', | ||
| 76 | + 'url' => ':attribute formát je neplatný.', | ||
| 77 | + | ||
| 78 | + /* | ||
| 79 | + |-------------------------------------------------------------------------- | ||
| 80 | + | Custom Validation Language Lines | ||
| 81 | + |-------------------------------------------------------------------------- | ||
| 82 | + | | ||
| 83 | + | Here you may specify custom validation messages for attributes using the | ||
| 84 | + | convention "attribute.rule" to name the lines. This makes it quick to | ||
| 85 | + | specify a specific custom language line for a given attribute rule. | ||
| 86 | + | | ||
| 87 | + */ | ||
| 88 | + | ||
| 89 | + 'custom' => [ | ||
| 90 | + 'password-confirm' => [ | ||
| 91 | + 'required_with' => 'Vyžaduje sa potvrdenie hesla', | ||
| 92 | + ], | ||
| 93 | + ], | ||
| 94 | + | ||
| 95 | + /* | ||
| 96 | + |-------------------------------------------------------------------------- | ||
| 97 | + | Custom Validation Attributes | ||
| 98 | + |-------------------------------------------------------------------------- | ||
| 99 | + | | ||
| 100 | + | The following language lines are used to swap attribute place-holders | ||
| 101 | + | with something more reader friendly such as E-Mail Address instead | ||
| 102 | + | of "email". This simply helps us make messages a little cleaner. | ||
| 103 | + | | ||
| 104 | + */ | ||
| 105 | + | ||
| 106 | + 'attributes' => [], | ||
| 107 | + | ||
| 108 | +]; |
| ... | @@ -47,7 +47,7 @@ | ... | @@ -47,7 +47,7 @@ |
| 47 | </a> | 47 | </a> |
| 48 | </div> | 48 | </div> |
| 49 | <div class="col-lg-4 col-sm-3 text-center"> | 49 | <div class="col-lg-4 col-sm-3 text-center"> |
| 50 | - <form action="{{ baseUrl('/search/all') }}" method="GET" class="search-box"> | 50 | + <form action="{{ baseUrl('/search') }}" method="GET" class="search-box"> |
| 51 | <input id="header-search-box-input" type="text" name="term" tabindex="2" value="{{ isset($searchTerm) ? $searchTerm : '' }}"> | 51 | <input id="header-search-box-input" type="text" name="term" tabindex="2" value="{{ isset($searchTerm) ? $searchTerm : '' }}"> |
| 52 | <button id="header-search-box-button" type="submit" class="text-button"><i class="zmdi zmdi-search"></i></button> | 52 | <button id="header-search-box-button" type="submit" class="text-button"><i class="zmdi zmdi-search"></i></button> |
| 53 | </form> | 53 | </form> | ... | ... |
| ... | @@ -50,15 +50,15 @@ | ... | @@ -50,15 +50,15 @@ |
| 50 | </div> | 50 | </div> |
| 51 | 51 | ||
| 52 | 52 | ||
| 53 | - <div class="container" id="book-dashboard" ng-controller="BookShowController" book-id="{{ $book->id }}"> | 53 | + <div class="container" id="entity-dashboard" entity-id="{{ $book->id }}" entity-type="book"> |
| 54 | <div class="row"> | 54 | <div class="row"> |
| 55 | <div class="col-md-7"> | 55 | <div class="col-md-7"> |
| 56 | 56 | ||
| 57 | <h1>{{$book->name}}</h1> | 57 | <h1>{{$book->name}}</h1> |
| 58 | - <div class="book-content" ng-show="!searching"> | 58 | + <div class="book-content" v-if="!searching"> |
| 59 | - <p class="text-muted" ng-non-bindable>{{$book->description}}</p> | 59 | + <p class="text-muted" v-pre>{{$book->description}}</p> |
| 60 | 60 | ||
| 61 | - <div class="page-list" ng-non-bindable> | 61 | + <div class="page-list" v-pre> |
| 62 | <hr> | 62 | <hr> |
| 63 | @if(count($bookChildren) > 0) | 63 | @if(count($bookChildren) > 0) |
| 64 | @foreach($bookChildren as $childElement) | 64 | @foreach($bookChildren as $childElement) |
| ... | @@ -81,12 +81,12 @@ | ... | @@ -81,12 +81,12 @@ |
| 81 | @include('partials.entity-meta', ['entity' => $book]) | 81 | @include('partials.entity-meta', ['entity' => $book]) |
| 82 | </div> | 82 | </div> |
| 83 | </div> | 83 | </div> |
| 84 | - <div class="search-results" ng-cloak ng-show="searching"> | 84 | + <div class="search-results" v-cloak v-if="searching"> |
| 85 | - <h3 class="text-muted">{{ trans('entities.search_results') }} <a ng-if="searching" ng-click="clearSearch()" class="text-small"><i class="zmdi zmdi-close"></i>{{ trans('entities.search_clear') }}</a></h3> | 85 | + <h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" v-on:click="clearSearch()" class="text-small"><i class="zmdi zmdi-close"></i>{{ trans('entities.search_clear') }}</a></h3> |
| 86 | - <div ng-if="!searchResults"> | 86 | + <div v-if="!searchResults"> |
| 87 | @include('partials/loading-icon') | 87 | @include('partials/loading-icon') |
| 88 | </div> | 88 | </div> |
| 89 | - <div ng-bind-html="searchResults"></div> | 89 | + <div v-html="searchResults"></div> |
| 90 | </div> | 90 | </div> |
| 91 | 91 | ||
| 92 | 92 | ||
| ... | @@ -94,6 +94,7 @@ | ... | @@ -94,6 +94,7 @@ |
| 94 | 94 | ||
| 95 | <div class="col-md-4 col-md-offset-1"> | 95 | <div class="col-md-4 col-md-offset-1"> |
| 96 | <div class="margin-top large"></div> | 96 | <div class="margin-top large"></div> |
| 97 | + | ||
| 97 | @if($book->restricted) | 98 | @if($book->restricted) |
| 98 | <p class="text-muted"> | 99 | <p class="text-muted"> |
| 99 | @if(userCan('restrictions-manage', $book)) | 100 | @if(userCan('restrictions-manage', $book)) |
| ... | @@ -103,14 +104,16 @@ | ... | @@ -103,14 +104,16 @@ |
| 103 | @endif | 104 | @endif |
| 104 | </p> | 105 | </p> |
| 105 | @endif | 106 | @endif |
| 107 | + | ||
| 106 | <div class="search-box"> | 108 | <div class="search-box"> |
| 107 | - <form ng-submit="searchBook($event)"> | 109 | + <form v-on:submit="searchBook"> |
| 108 | - <input ng-model="searchTerm" ng-change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.books_search_this') }}"> | 110 | + <input v-model="searchTerm" v-on:change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.books_search_this') }}"> |
| 109 | <button type="submit"><i class="zmdi zmdi-search"></i></button> | 111 | <button type="submit"><i class="zmdi zmdi-search"></i></button> |
| 110 | - <button ng-if="searching" ng-click="clearSearch()" type="button"><i class="zmdi zmdi-close"></i></button> | 112 | + <button v-if="searching" v-cloak class="text-neg" v-on:click="clearSearch()" type="button"><i class="zmdi zmdi-close"></i></button> |
| 111 | </form> | 113 | </form> |
| 112 | </div> | 114 | </div> |
| 113 | - <div class="activity anim fadeIn"> | 115 | + |
| 116 | + <div class="activity"> | ||
| 114 | <h3>{{ trans('entities.recent_activity') }}</h3> | 117 | <h3>{{ trans('entities.recent_activity') }}</h3> |
| 115 | @include('partials/activity-list', ['activity' => Activity::entityActivity($book, 20, 0)]) | 118 | @include('partials/activity-list', ['activity' => Activity::entityActivity($book, 20, 0)]) |
| 116 | </div> | 119 | </div> | ... | ... |
| 1 | <div class="breadcrumbs"> | 1 | <div class="breadcrumbs"> |
| 2 | + @if (userCan('view', $chapter->book)) | ||
| 2 | <a href="{{ $chapter->book->getUrl() }}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $chapter->book->getShortName() }}</a> | 3 | <a href="{{ $chapter->book->getUrl() }}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $chapter->book->getShortName() }}</a> |
| 3 | <span class="sep">»</span> | 4 | <span class="sep">»</span> |
| 5 | + @endif | ||
| 4 | <a href="{{ $chapter->getUrl() }}" class="text-chapter text-button"><i class="zmdi zmdi-collection-bookmark"></i>{{$chapter->getShortName()}}</a> | 6 | <a href="{{ $chapter->getUrl() }}" class="text-chapter text-button"><i class="zmdi zmdi-collection-bookmark"></i>{{$chapter->getShortName()}}</a> |
| 5 | </div> | 7 | </div> |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -47,10 +47,11 @@ | ... | @@ -47,10 +47,11 @@ |
| 47 | </div> | 47 | </div> |
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | - <div class="container" ng-non-bindable> | 50 | + <div class="container" id="entity-dashboard" entity-id="{{ $chapter->id }}" entity-type="chapter"> |
| 51 | <div class="row"> | 51 | <div class="row"> |
| 52 | - <div class="col-md-8"> | 52 | + <div class="col-md-7"> |
| 53 | <h1>{{ $chapter->name }}</h1> | 53 | <h1>{{ $chapter->name }}</h1> |
| 54 | + <div class="chapter-content" v-if="!searching"> | ||
| 54 | <p class="text-muted">{{ $chapter->description }}</p> | 55 | <p class="text-muted">{{ $chapter->description }}</p> |
| 55 | 56 | ||
| 56 | @if(count($pages) > 0) | 57 | @if(count($pages) > 0) |
| ... | @@ -80,7 +81,16 @@ | ... | @@ -80,7 +81,16 @@ |
| 80 | 81 | ||
| 81 | @include('partials.entity-meta', ['entity' => $chapter]) | 82 | @include('partials.entity-meta', ['entity' => $chapter]) |
| 82 | </div> | 83 | </div> |
| 83 | - <div class="col-md-3 col-md-offset-1"> | 84 | + |
| 85 | + <div class="search-results" v-cloak v-if="searching"> | ||
| 86 | + <h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" v-on:click="clearSearch()" class="text-small"><i class="zmdi zmdi-close"></i>{{ trans('entities.search_clear') }}</a></h3> | ||
| 87 | + <div v-if="!searchResults"> | ||
| 88 | + @include('partials/loading-icon') | ||
| 89 | + </div> | ||
| 90 | + <div v-html="searchResults"></div> | ||
| 91 | + </div> | ||
| 92 | + </div> | ||
| 93 | + <div class="col-md-4 col-md-offset-1"> | ||
| 84 | <div class="margin-top large"></div> | 94 | <div class="margin-top large"></div> |
| 85 | @if($book->restricted || $chapter->restricted) | 95 | @if($book->restricted || $chapter->restricted) |
| 86 | <div class="text-muted"> | 96 | <div class="text-muted"> |
| ... | @@ -105,7 +115,16 @@ | ... | @@ -105,7 +115,16 @@ |
| 105 | </div> | 115 | </div> |
| 106 | @endif | 116 | @endif |
| 107 | 117 | ||
| 118 | + <div class="search-box"> | ||
| 119 | + <form v-on:submit="searchBook"> | ||
| 120 | + <input v-model="searchTerm" v-on:change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.chapters_search_this') }}"> | ||
| 121 | + <button type="submit"><i class="zmdi zmdi-search"></i></button> | ||
| 122 | + <button v-if="searching" v-cloak class="text-neg" v-on:click="clearSearch()" type="button"><i class="zmdi zmdi-close"></i></button> | ||
| 123 | + </form> | ||
| 124 | + </div> | ||
| 125 | + | ||
| 108 | @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree]) | 126 | @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree]) |
| 127 | + | ||
| 109 | </div> | 128 | </div> |
| 110 | </div> | 129 | </div> |
| 111 | </div> | 130 | </div> | ... | ... |
| 1 | <div class="breadcrumbs"> | 1 | <div class="breadcrumbs"> |
| 2 | + @if (userCan('view', $page->book)) | ||
| 2 | <a href="{{ $page->book->getUrl() }}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $page->book->getShortName() }}</a> | 3 | <a href="{{ $page->book->getUrl() }}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $page->book->getShortName() }}</a> |
| 3 | - @if($page->hasChapter()) | ||
| 4 | <span class="sep">»</span> | 4 | <span class="sep">»</span> |
| 5 | + @endif | ||
| 6 | + @if($page->hasChapter() && userCan('view', $page->chapter)) | ||
| 5 | <a href="{{ $page->chapter->getUrl() }}" class="text-chapter text-button"> | 7 | <a href="{{ $page->chapter->getUrl() }}" class="text-chapter text-button"> |
| 6 | <i class="zmdi zmdi-collection-bookmark"></i> | 8 | <i class="zmdi zmdi-collection-bookmark"></i> |
| 7 | {{ $page->chapter->getShortName() }} | 9 | {{ $page->chapter->getShortName() }} |
| 8 | </a> | 10 | </a> |
| 9 | - @endif | ||
| 10 | <span class="sep">»</span> | 11 | <span class="sep">»</span> |
| 12 | + @endif | ||
| 11 | <a href="{{ $page->getUrl() }}" class="text-page text-button"><i class="zmdi zmdi-file"></i>{{ $page->getShortName() }}</a> | 13 | <a href="{{ $page->getUrl() }}" class="text-page text-button"><i class="zmdi zmdi-file"></i>{{ $page->getShortName() }}</a> |
| 12 | </div> | 14 | </div> |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -19,6 +19,7 @@ | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | ||
| 20 | <table class="table"> | 20 | <table class="table"> |
| 21 | <tr> | 21 | <tr> |
| 22 | + <th width="3%">{{ trans('entities.pages_revisions_number') }}</th> | ||
| 22 | <th width="23%">{{ trans('entities.pages_name') }}</th> | 23 | <th width="23%">{{ trans('entities.pages_name') }}</th> |
| 23 | <th colspan="2" width="8%">{{ trans('entities.pages_revisions_created_by') }}</th> | 24 | <th colspan="2" width="8%">{{ trans('entities.pages_revisions_created_by') }}</th> |
| 24 | <th width="15%">{{ trans('entities.pages_revisions_date') }}</th> | 25 | <th width="15%">{{ trans('entities.pages_revisions_date') }}</th> |
| ... | @@ -27,6 +28,7 @@ | ... | @@ -27,6 +28,7 @@ |
| 27 | </tr> | 28 | </tr> |
| 28 | @foreach($page->revisions as $index => $revision) | 29 | @foreach($page->revisions as $index => $revision) |
| 29 | <tr> | 30 | <tr> |
| 31 | + <td>{{ $revision->revision_number == 0 ? '' : $revision->revision_number }}</td> | ||
| 30 | <td>{{ $revision->name }}</td> | 32 | <td>{{ $revision->name }}</td> |
| 31 | <td style="line-height: 0;"> | 33 | <td style="line-height: 0;"> |
| 32 | @if($revision->createdBy) | 34 | @if($revision->createdBy) | ... | ... |
| ... | @@ -3,13 +3,13 @@ | ... | @@ -3,13 +3,13 @@ |
| 3 | 3 | ||
| 4 | @if(isset($page) && $page->tags->count() > 0) | 4 | @if(isset($page) && $page->tags->count() > 0) |
| 5 | <div class="tag-display"> | 5 | <div class="tag-display"> |
| 6 | - <h6 class="text-muted">Page Tags</h6> | 6 | + <h6 class="text-muted">{{ trans('entities.page_tags') }}</h6> |
| 7 | <table> | 7 | <table> |
| 8 | <tbody> | 8 | <tbody> |
| 9 | @foreach($page->tags as $tag) | 9 | @foreach($page->tags as $tag) |
| 10 | <tr class="tag"> | 10 | <tr class="tag"> |
| 11 | - <td @if(!$tag->value) colspan="2" @endif><a href="{{ baseUrl('/search/all?term=%5B' . urlencode($tag->name) .'%5D') }}">{{ $tag->name }}</a></td> | 11 | + <td @if(!$tag->value) colspan="2" @endif><a href="{{ baseUrl('/search?term=%5B' . urlencode($tag->name) .'%5D') }}">{{ $tag->name }}</a></td> |
| 12 | - @if($tag->value) <td class="tag-value"><a href="{{ baseUrl('/search/all?term=%5B' . urlencode($tag->name) .'%3D' . urlencode($tag->value) . '%5D') }}">{{$tag->value}}</a></td> @endif | 12 | + @if($tag->value) <td class="tag-value"><a href="{{ baseUrl('/search?term=%5B' . urlencode($tag->name) .'%3D' . urlencode($tag->value) . '%5D') }}">{{$tag->value}}</a></td> @endif |
| 13 | </tr> | 13 | </tr> |
| 14 | @endforeach | 14 | @endforeach |
| 15 | </tbody> | 15 | </tbody> |
| ... | @@ -39,8 +39,10 @@ | ... | @@ -39,8 +39,10 @@ |
| 39 | 39 | ||
| 40 | <h6 class="text-muted">{{ trans('entities.books_navigation') }}</h6> | 40 | <h6 class="text-muted">{{ trans('entities.books_navigation') }}</h6> |
| 41 | <ul class="sidebar-page-list menu"> | 41 | <ul class="sidebar-page-list menu"> |
| 42 | - <li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></li> | ||
| 43 | 42 | ||
| 43 | + @if (userCan('view', $book)) | ||
| 44 | + <li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></li> | ||
| 45 | + @endif | ||
| 44 | 46 | ||
| 45 | @foreach($sidebarTree as $bookChild) | 47 | @foreach($sidebarTree as $bookChild) |
| 46 | <li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}"> | 48 | <li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}"> | ... | ... |
| 1 | <p class="text-muted small"> | 1 | <p class="text-muted small"> |
| 2 | + @if ($entity->isA('page')) {{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }} <br> @endif | ||
| 2 | @if ($entity->createdBy) | 3 | @if ($entity->createdBy) |
| 3 | - {!! trans('entities.meta_created_name', ['timeLength' => $entity->created_at->diffForHumans(), 'user' => "<a href='{$entity->createdBy->getProfileUrl()}'>".htmlentities($entity->createdBy->name). "</a>"]) !!} | 4 | + {!! trans('entities.meta_created_name', [ |
| 5 | + 'timeLength' => '<span title="'.$entity->created_at->toDayDateTimeString().'">'.$entity->created_at->diffForHumans() . '</span>', | ||
| 6 | + 'user' => "<a href='{$entity->createdBy->getProfileUrl()}'>".htmlentities($entity->createdBy->name). "</a>" | ||
| 7 | + ]) !!} | ||
| 4 | @else | 8 | @else |
| 5 | - {{ trans('entities.meta_created', ['timeLength' => $entity->created_at->diffForHumans()]) }} | 9 | + <span title="{{$entity->created_at->toDayDateTimeString()}}">{{ trans('entities.meta_created', ['timeLength' => $entity->created_at->diffForHumans()]) }}</span> |
| 6 | @endif | 10 | @endif |
| 7 | <br> | 11 | <br> |
| 8 | @if ($entity->updatedBy) | 12 | @if ($entity->updatedBy) |
| 9 | - {!! trans('entities.meta_updated_name', ['timeLength' => $entity->updated_at->diffForHumans(), 'user' => "<a href='{$entity->updatedBy->getProfileUrl()}'>".htmlentities($entity->updatedBy->name). "</a>"]) !!} | 13 | + {!! trans('entities.meta_updated_name', [ |
| 14 | + 'timeLength' => '<span title="' . $entity->updated_at->toDayDateTimeString() .'">' . $entity->updated_at->diffForHumans() .'</span>', | ||
| 15 | + 'user' => "<a href='{$entity->updatedBy->getProfileUrl()}'>".htmlentities($entity->updatedBy->name). "</a>" | ||
| 16 | + ]) !!} | ||
| 10 | @else | 17 | @else |
| 11 | - {{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }} | 18 | + <span title="{{ $entity->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }}</span> |
| 12 | @endif | 19 | @endif |
| 13 | </p> | 20 | </p> |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
This diff is collapsed.
Click to expand it.
| ... | @@ -123,11 +123,9 @@ Route::group(['middleware' => 'auth'], function () { | ... | @@ -123,11 +123,9 @@ Route::group(['middleware' => 'auth'], function () { |
| 123 | Route::get('/link/{id}', 'PageController@redirectFromLink'); | 123 | Route::get('/link/{id}', 'PageController@redirectFromLink'); |
| 124 | 124 | ||
| 125 | // Search | 125 | // Search |
| 126 | - Route::get('/search/all', 'SearchController@searchAll'); | 126 | + Route::get('/search', 'SearchController@search'); |
| 127 | - Route::get('/search/pages', 'SearchController@searchPages'); | ||
| 128 | - Route::get('/search/books', 'SearchController@searchBooks'); | ||
| 129 | - Route::get('/search/chapters', 'SearchController@searchChapters'); | ||
| 130 | Route::get('/search/book/{bookId}', 'SearchController@searchBook'); | 127 | Route::get('/search/book/{bookId}', 'SearchController@searchBook'); |
| 128 | + Route::get('/search/chapter/{bookId}', 'SearchController@searchChapter'); | ||
| 131 | 129 | ||
| 132 | // Other Pages | 130 | // Other Pages |
| 133 | Route::get('/', 'HomeController@index'); | 131 | Route::get('/', 'HomeController@index'); | ... | ... |
| ... | @@ -22,6 +22,12 @@ abstract class BrowserKitTest extends TestCase | ... | @@ -22,6 +22,12 @@ abstract class BrowserKitTest extends TestCase |
| 22 | private $admin; | 22 | private $admin; |
| 23 | private $editor; | 23 | private $editor; |
| 24 | 24 | ||
| 25 | + public function tearDown() | ||
| 26 | + { | ||
| 27 | + \DB::disconnect(); | ||
| 28 | + parent::tearDown(); | ||
| 29 | + } | ||
| 30 | + | ||
| 25 | /** | 31 | /** |
| 26 | * Creates the application. | 32 | * Creates the application. |
| 27 | * | 33 | * | ... | ... |
This diff is collapsed.
Click to expand it.
| 1 | <?php namespace Tests; | 1 | <?php namespace Tests; |
| 2 | 2 | ||
| 3 | +use BookStack\Book; | ||
| 4 | +use BookStack\Chapter; | ||
| 5 | +use BookStack\Page; | ||
| 6 | +use BookStack\Repos\EntityRepo; | ||
| 7 | +use BookStack\Repos\UserRepo; | ||
| 8 | + | ||
| 3 | class EntityTest extends BrowserKitTest | 9 | class EntityTest extends BrowserKitTest |
| 4 | { | 10 | { |
| 5 | 11 | ||
| ... | @@ -18,7 +24,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -18,7 +24,7 @@ class EntityTest extends BrowserKitTest |
| 18 | $this->bookDelete($book); | 24 | $this->bookDelete($book); |
| 19 | } | 25 | } |
| 20 | 26 | ||
| 21 | - public function bookDelete(\BookStack\Book $book) | 27 | + public function bookDelete(Book $book) |
| 22 | { | 28 | { |
| 23 | $this->asAdmin() | 29 | $this->asAdmin() |
| 24 | ->visit($book->getUrl()) | 30 | ->visit($book->getUrl()) |
| ... | @@ -32,7 +38,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -32,7 +38,7 @@ class EntityTest extends BrowserKitTest |
| 32 | ->notSeeInDatabase('books', ['id' => $book->id]); | 38 | ->notSeeInDatabase('books', ['id' => $book->id]); |
| 33 | } | 39 | } |
| 34 | 40 | ||
| 35 | - public function bookUpdate(\BookStack\Book $book) | 41 | + public function bookUpdate(Book $book) |
| 36 | { | 42 | { |
| 37 | $newName = $book->name . ' Updated'; | 43 | $newName = $book->name . ' Updated'; |
| 38 | $this->asAdmin() | 44 | $this->asAdmin() |
| ... | @@ -46,12 +52,12 @@ class EntityTest extends BrowserKitTest | ... | @@ -46,12 +52,12 @@ class EntityTest extends BrowserKitTest |
| 46 | ->seePageIs($book->getUrl() . '-updated') | 52 | ->seePageIs($book->getUrl() . '-updated') |
| 47 | ->see($newName); | 53 | ->see($newName); |
| 48 | 54 | ||
| 49 | - return \BookStack\Book::find($book->id); | 55 | + return Book::find($book->id); |
| 50 | } | 56 | } |
| 51 | 57 | ||
| 52 | public function test_book_sort_page_shows() | 58 | public function test_book_sort_page_shows() |
| 53 | { | 59 | { |
| 54 | - $books = \BookStack\Book::all(); | 60 | + $books = Book::all(); |
| 55 | $bookToSort = $books[0]; | 61 | $bookToSort = $books[0]; |
| 56 | $this->asAdmin() | 62 | $this->asAdmin() |
| 57 | ->visit($bookToSort->getUrl()) | 63 | ->visit($bookToSort->getUrl()) |
| ... | @@ -65,7 +71,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -65,7 +71,7 @@ class EntityTest extends BrowserKitTest |
| 65 | 71 | ||
| 66 | public function test_book_sort_item_returns_book_content() | 72 | public function test_book_sort_item_returns_book_content() |
| 67 | { | 73 | { |
| 68 | - $books = \BookStack\Book::all(); | 74 | + $books = Book::all(); |
| 69 | $bookToSort = $books[0]; | 75 | $bookToSort = $books[0]; |
| 70 | $firstPage = $bookToSort->pages[0]; | 76 | $firstPage = $bookToSort->pages[0]; |
| 71 | $firstChapter = $bookToSort->chapters[0]; | 77 | $firstChapter = $bookToSort->chapters[0]; |
| ... | @@ -79,7 +85,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -79,7 +85,7 @@ class EntityTest extends BrowserKitTest |
| 79 | 85 | ||
| 80 | public function pageCreation($chapter) | 86 | public function pageCreation($chapter) |
| 81 | { | 87 | { |
| 82 | - $page = factory(\BookStack\Page::class)->make([ | 88 | + $page = factory(Page::class)->make([ |
| 83 | 'name' => 'My First Page' | 89 | 'name' => 'My First Page' |
| 84 | ]); | 90 | ]); |
| 85 | 91 | ||
| ... | @@ -88,7 +94,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -88,7 +94,7 @@ class EntityTest extends BrowserKitTest |
| 88 | ->visit($chapter->getUrl()) | 94 | ->visit($chapter->getUrl()) |
| 89 | ->click('New Page'); | 95 | ->click('New Page'); |
| 90 | 96 | ||
| 91 | - $draftPage = \BookStack\Page::where('draft', '=', true)->orderBy('created_at', 'desc')->first(); | 97 | + $draftPage = Page::where('draft', '=', true)->orderBy('created_at', 'desc')->first(); |
| 92 | 98 | ||
| 93 | $this->seePageIs($draftPage->getUrl()) | 99 | $this->seePageIs($draftPage->getUrl()) |
| 94 | // Fill out form | 100 | // Fill out form |
| ... | @@ -99,13 +105,13 @@ class EntityTest extends BrowserKitTest | ... | @@ -99,13 +105,13 @@ class EntityTest extends BrowserKitTest |
| 99 | ->seePageIs($chapter->book->getUrl() . '/page/my-first-page') | 105 | ->seePageIs($chapter->book->getUrl() . '/page/my-first-page') |
| 100 | ->see($page->name); | 106 | ->see($page->name); |
| 101 | 107 | ||
| 102 | - $page = \BookStack\Page::where('slug', '=', 'my-first-page')->where('chapter_id', '=', $chapter->id)->first(); | 108 | + $page = Page::where('slug', '=', 'my-first-page')->where('chapter_id', '=', $chapter->id)->first(); |
| 103 | return $page; | 109 | return $page; |
| 104 | } | 110 | } |
| 105 | 111 | ||
| 106 | - public function chapterCreation(\BookStack\Book $book) | 112 | + public function chapterCreation(Book $book) |
| 107 | { | 113 | { |
| 108 | - $chapter = factory(\BookStack\Chapter::class)->make([ | 114 | + $chapter = factory(Chapter::class)->make([ |
| 109 | 'name' => 'My First Chapter' | 115 | 'name' => 'My First Chapter' |
| 110 | ]); | 116 | ]); |
| 111 | 117 | ||
| ... | @@ -122,13 +128,13 @@ class EntityTest extends BrowserKitTest | ... | @@ -122,13 +128,13 @@ class EntityTest extends BrowserKitTest |
| 122 | ->seePageIs($book->getUrl() . '/chapter/my-first-chapter') | 128 | ->seePageIs($book->getUrl() . '/chapter/my-first-chapter') |
| 123 | ->see($chapter->name)->see($chapter->description); | 129 | ->see($chapter->name)->see($chapter->description); |
| 124 | 130 | ||
| 125 | - $chapter = \BookStack\Chapter::where('slug', '=', 'my-first-chapter')->where('book_id', '=', $book->id)->first(); | 131 | + $chapter = Chapter::where('slug', '=', 'my-first-chapter')->where('book_id', '=', $book->id)->first(); |
| 126 | return $chapter; | 132 | return $chapter; |
| 127 | } | 133 | } |
| 128 | 134 | ||
| 129 | public function bookCreation() | 135 | public function bookCreation() |
| 130 | { | 136 | { |
| 131 | - $book = factory(\BookStack\Book::class)->make([ | 137 | + $book = factory(Book::class)->make([ |
| 132 | 'name' => 'My First Book' | 138 | 'name' => 'My First Book' |
| 133 | ]); | 139 | ]); |
| 134 | $this->asAdmin() | 140 | $this->asAdmin() |
| ... | @@ -154,7 +160,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -154,7 +160,7 @@ class EntityTest extends BrowserKitTest |
| 154 | $expectedPattern = '/\/books\/my-first-book-[0-9a-zA-Z]{3}/'; | 160 | $expectedPattern = '/\/books\/my-first-book-[0-9a-zA-Z]{3}/'; |
| 155 | $this->assertRegExp($expectedPattern, $this->currentUri, "Did not land on expected page [$expectedPattern].\n"); | 161 | $this->assertRegExp($expectedPattern, $this->currentUri, "Did not land on expected page [$expectedPattern].\n"); |
| 156 | 162 | ||
| 157 | - $book = \BookStack\Book::where('slug', '=', 'my-first-book')->first(); | 163 | + $book = Book::where('slug', '=', 'my-first-book')->first(); |
| 158 | return $book; | 164 | return $book; |
| 159 | } | 165 | } |
| 160 | 166 | ||
| ... | @@ -165,8 +171,8 @@ class EntityTest extends BrowserKitTest | ... | @@ -165,8 +171,8 @@ class EntityTest extends BrowserKitTest |
| 165 | $updater = $this->getEditor(); | 171 | $updater = $this->getEditor(); |
| 166 | $entities = $this->createEntityChainBelongingToUser($creator, $updater); | 172 | $entities = $this->createEntityChainBelongingToUser($creator, $updater); |
| 167 | $this->actingAs($creator); | 173 | $this->actingAs($creator); |
| 168 | - app('BookStack\Repos\UserRepo')->destroy($creator); | 174 | + app(UserRepo::class)->destroy($creator); |
| 169 | - app('BookStack\Repos\EntityRepo')->savePageRevision($entities['page']); | 175 | + app(EntityRepo::class)->savePageRevision($entities['page']); |
| 170 | 176 | ||
| 171 | $this->checkEntitiesViewable($entities); | 177 | $this->checkEntitiesViewable($entities); |
| 172 | } | 178 | } |
| ... | @@ -178,8 +184,8 @@ class EntityTest extends BrowserKitTest | ... | @@ -178,8 +184,8 @@ class EntityTest extends BrowserKitTest |
| 178 | $updater = $this->getEditor(); | 184 | $updater = $this->getEditor(); |
| 179 | $entities = $this->createEntityChainBelongingToUser($creator, $updater); | 185 | $entities = $this->createEntityChainBelongingToUser($creator, $updater); |
| 180 | $this->actingAs($updater); | 186 | $this->actingAs($updater); |
| 181 | - app('BookStack\Repos\UserRepo')->destroy($updater); | 187 | + app(UserRepo::class)->destroy($updater); |
| 182 | - app('BookStack\Repos\EntityRepo')->savePageRevision($entities['page']); | 188 | + app(EntityRepo::class)->savePageRevision($entities['page']); |
| 183 | 189 | ||
| 184 | $this->checkEntitiesViewable($entities); | 190 | $this->checkEntitiesViewable($entities); |
| 185 | } | 191 | } |
| ... | @@ -216,7 +222,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -216,7 +222,7 @@ class EntityTest extends BrowserKitTest |
| 216 | 222 | ||
| 217 | public function test_old_page_slugs_redirect_to_new_pages() | 223 | public function test_old_page_slugs_redirect_to_new_pages() |
| 218 | { | 224 | { |
| 219 | - $page = \BookStack\Page::first(); | 225 | + $page = Page::first(); |
| 220 | $pageUrl = $page->getUrl(); | 226 | $pageUrl = $page->getUrl(); |
| 221 | $newPageUrl = '/books/' . $page->book->slug . '/page/super-test-page'; | 227 | $newPageUrl = '/books/' . $page->book->slug . '/page/super-test-page'; |
| 222 | // Need to save twice since revisions are not generated in seeder. | 228 | // Need to save twice since revisions are not generated in seeder. |
| ... | @@ -225,7 +231,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -225,7 +231,7 @@ class EntityTest extends BrowserKitTest |
| 225 | ->type('super test', '#name') | 231 | ->type('super test', '#name') |
| 226 | ->press('Save Page'); | 232 | ->press('Save Page'); |
| 227 | 233 | ||
| 228 | - $page = \BookStack\Page::first(); | 234 | + $page = Page::first(); |
| 229 | $pageUrl = $page->getUrl(); | 235 | $pageUrl = $page->getUrl(); |
| 230 | 236 | ||
| 231 | // Second Save | 237 | // Second Save |
| ... | @@ -242,7 +248,7 @@ class EntityTest extends BrowserKitTest | ... | @@ -242,7 +248,7 @@ class EntityTest extends BrowserKitTest |
| 242 | 248 | ||
| 243 | public function test_recently_updated_pages_on_home() | 249 | public function test_recently_updated_pages_on_home() |
| 244 | { | 250 | { |
| 245 | - $page = \BookStack\Page::orderBy('updated_at', 'asc')->first(); | 251 | + $page = Page::orderBy('updated_at', 'asc')->first(); |
| 246 | $this->asAdmin()->visit('/') | 252 | $this->asAdmin()->visit('/') |
| 247 | ->dontSeeInElement('#recently-updated-pages', $page->name); | 253 | ->dontSeeInElement('#recently-updated-pages', $page->name); |
| 248 | $this->visit($page->getUrl() . '/edit') | 254 | $this->visit($page->getUrl() . '/edit') | ... | ... |
tests/Entity/PageRevisionTest.php
0 → 100644
| 1 | +<?php namespace Entity; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +use BookStack\Page; | ||
| 5 | +use Tests\TestCase; | ||
| 6 | + | ||
| 7 | +class PageRevisionTest extends TestCase | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | + public function test_page_revision_count_increments_on_update() | ||
| 11 | + { | ||
| 12 | + $page = Page::first(); | ||
| 13 | + $startCount = $page->revision_count; | ||
| 14 | + | ||
| 15 | + $resp = $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']); | ||
| 16 | + $resp->assertStatus(302); | ||
| 17 | + | ||
| 18 | + $this->assertTrue(Page::find($page->id)->revision_count === $startCount+1); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public function test_revision_count_shown_in_page_meta() | ||
| 22 | + { | ||
| 23 | + $page = Page::first(); | ||
| 24 | + $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']); | ||
| 25 | + $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']); | ||
| 26 | + $page = Page::find($page->id); | ||
| 27 | + | ||
| 28 | + $pageView = $this->get($page->getUrl()); | ||
| 29 | + $pageView->assertSee('Revision #' . $page->revision_count); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -522,4 +522,21 @@ class RestrictionsTest extends BrowserKitTest | ... | @@ -522,4 +522,21 @@ class RestrictionsTest extends BrowserKitTest |
| 522 | ->see('Delete Chapter'); | 522 | ->see('Delete Chapter'); |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | + public function test_page_visible_if_has_permissions_when_book_not_visible() | ||
| 526 | + { | ||
| 527 | + $book = \BookStack\Book::first(); | ||
| 528 | + $bookChapter = $book->chapters->first(); | ||
| 529 | + $bookPage = $bookChapter->pages->first(); | ||
| 530 | + | ||
| 531 | + $this->setEntityRestrictions($book, []); | ||
| 532 | + $this->setEntityRestrictions($bookPage, ['view']); | ||
| 533 | + | ||
| 534 | + $this->actingAs($this->viewer); | ||
| 535 | + $this->get($bookPage->getUrl()); | ||
| 536 | + $this->assertResponseOk(); | ||
| 537 | + $this->see($bookPage->name); | ||
| 538 | + $this->dontSee(substr($book->name, 0, 15)); | ||
| 539 | + $this->dontSee(substr($bookChapter->name, 0, 15)); | ||
| 540 | + } | ||
| 541 | + | ||
| 525 | } | 542 | } | ... | ... |
| ... | @@ -76,4 +76,16 @@ abstract class TestCase extends BaseTestCase | ... | @@ -76,4 +76,16 @@ abstract class TestCase extends BaseTestCase |
| 76 | public function newChapter($input = ['name' => 'test chapter', 'description' => 'My new test chapter'], Book $book) { | 76 | public function newChapter($input = ['name' => 'test chapter', 'description' => 'My new test chapter'], Book $book) { |
| 77 | return $this->app[EntityRepo::class]->createFromInput('chapter', $input, $book); | 77 | return $this->app[EntityRepo::class]->createFromInput('chapter', $input, $book); |
| 78 | } | 78 | } |
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * Create and return a new test page | ||
| 82 | + * @param array $input | ||
| 83 | + * @return Chapter | ||
| 84 | + */ | ||
| 85 | + public function newPage($input = ['name' => 'test page', 'html' => 'My new test page']) { | ||
| 86 | + $book = Book::first(); | ||
| 87 | + $entityRepo = $this->app[EntityRepo::class]; | ||
| 88 | + $draftPage = $entityRepo->getDraftPage($book); | ||
| 89 | + return $entityRepo->publishPageDraft($draftPage, $input); | ||
| 90 | + } | ||
| 79 | } | 91 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or sign in to post a comment