Merge branch 'master' into release
This commit is contained in:
commit
33a04697ef
|
@ -216,12 +216,12 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||||
*/
|
*/
|
||||||
public function getShortName($chars = 8)
|
public function getShortName($chars = 8)
|
||||||
{
|
{
|
||||||
if (strlen($this->name) <= $chars) {
|
if (mb_strlen($this->name) <= $chars) {
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
$splitName = explode(' ', $this->name);
|
$splitName = explode(' ', $this->name);
|
||||||
if (strlen($splitName[0]) <= $chars) {
|
if (mb_strlen($splitName[0]) <= $chars) {
|
||||||
return $splitName[0];
|
return $splitName[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class CreateAdmin extends Command
|
||||||
if (empty($email)) {
|
if (empty($email)) {
|
||||||
$email = $this->ask('Please specify an email address for the new admin user');
|
$email = $this->ask('Please specify an email address for the new admin user');
|
||||||
}
|
}
|
||||||
if (strlen($email) < 5 || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
if (mb_strlen($email) < 5 || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
return $this->error('Invalid email address provided');
|
return $this->error('Invalid email address provided');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class CreateAdmin extends Command
|
||||||
if (empty($name)) {
|
if (empty($name)) {
|
||||||
$name = $this->ask('Please specify an name for the new admin user');
|
$name = $this->ask('Please specify an name for the new admin user');
|
||||||
}
|
}
|
||||||
if (strlen($name) < 2) {
|
if (mb_strlen($name) < 2) {
|
||||||
return $this->error('Invalid name provided');
|
return $this->error('Invalid name provided');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class CreateAdmin extends Command
|
||||||
if (empty($password)) {
|
if (empty($password)) {
|
||||||
$password = $this->secret('Please specify a password for the new admin user');
|
$password = $this->secret('Please specify a password for the new admin user');
|
||||||
}
|
}
|
||||||
if (strlen($password) < 5) {
|
if (mb_strlen($password) < 5) {
|
||||||
return $this->error('Invalid password provided, Must be at least 5 characters');
|
return $this->error('Invalid password provided, Must be at least 5 characters');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ class Book extends Entity
|
||||||
public function getExcerpt(int $length = 100)
|
public function getExcerpt(int $length = 100)
|
||||||
{
|
{
|
||||||
$description = $this->description;
|
$description = $this->description;
|
||||||
return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
|
return mb_strlen($description) > $length ? mb_substr($description, 0, $length-3) . '...' : $description;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -83,7 +83,7 @@ class Bookshelf extends Entity
|
||||||
public function getExcerpt(int $length = 100)
|
public function getExcerpt(int $length = 100)
|
||||||
{
|
{
|
||||||
$description = $this->description;
|
$description = $this->description;
|
||||||
return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
|
return mb_strlen($description) > $length ? mb_substr($description, 0, $length-3) . '...' : $description;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -56,7 +56,7 @@ class Chapter extends Entity
|
||||||
public function getExcerpt(int $length = 100)
|
public function getExcerpt(int $length = 100)
|
||||||
{
|
{
|
||||||
$description = $this->text ?? $this->description;
|
$description = $this->text ?? $this->description;
|
||||||
return strlen($description) > $length ? substr($description, 0, $length-3) . '...' : $description;
|
return mb_strlen($description) > $length ? mb_substr($description, 0, $length-3) . '...' : $description;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -852,11 +852,14 @@ class EntityRepo
|
||||||
*/
|
*/
|
||||||
public function destroyPage(Page $page)
|
public function destroyPage(Page $page)
|
||||||
{
|
{
|
||||||
// Check if set as custom homepage
|
// Check if set as custom homepage & remove setting if not used or throw error if active
|
||||||
$customHome = setting('app-homepage', '0:');
|
$customHome = setting('app-homepage', '0:');
|
||||||
if (intval($page->id) === intval(explode(':', $customHome)[0])) {
|
if (intval($page->id) === intval(explode(':', $customHome)[0])) {
|
||||||
|
if (setting('app-homepage-type') === 'page') {
|
||||||
throw new NotifyException(trans('errors.page_custom_home_deletion'), $page->getUrl());
|
throw new NotifyException(trans('errors.page_custom_home_deletion'), $page->getUrl());
|
||||||
}
|
}
|
||||||
|
setting()->remove('app-homepage');
|
||||||
|
}
|
||||||
|
|
||||||
$this->destroyEntityCommonRelations($page);
|
$this->destroyEntityCommonRelations($page);
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ class PageRepo extends EntityRepo
|
||||||
// Create an unique id for the element
|
// Create an unique id for the element
|
||||||
// Uses the content as a basis to ensure output is the same every time
|
// Uses the content as a basis to ensure output is the same every time
|
||||||
// the same content is passed through.
|
// the same content is passed through.
|
||||||
$contentId = 'bkmrk-' . substr(strtolower(preg_replace('/\s+/', '-', trim($element->nodeValue))), 0, 20);
|
$contentId = 'bkmrk-' . mb_substr(strtolower(preg_replace('/\s+/', '-', trim($element->nodeValue))), 0, 20);
|
||||||
$newId = urlencode($contentId);
|
$newId = urlencode($contentId);
|
||||||
$loopIndex = 0;
|
$loopIndex = 0;
|
||||||
|
|
||||||
|
@ -422,25 +422,29 @@ class PageRepo extends EntityRepo
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$tree = collect([]);
|
$tree = collect($headers)->map(function($header) {
|
||||||
foreach ($headers as $header) {
|
$text = trim(str_replace("\xc2\xa0", '', $header->nodeValue));
|
||||||
$text = $header->nodeValue;
|
if (mb_strlen($text) > 30) {
|
||||||
$tree->push([
|
$text = mb_substr($text, 0, 27) . '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
'nodeName' => strtolower($header->nodeName),
|
'nodeName' => strtolower($header->nodeName),
|
||||||
'level' => intval(str_replace('h', '', $header->nodeName)),
|
'level' => intval(str_replace('h', '', $header->nodeName)),
|
||||||
'link' => '#' . $header->getAttribute('id'),
|
'link' => '#' . $header->getAttribute('id'),
|
||||||
'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text
|
'text' => $text,
|
||||||
]);
|
];
|
||||||
}
|
})->filter(function($header) {
|
||||||
|
return mb_strlen($header['text']) > 0;
|
||||||
|
});
|
||||||
|
|
||||||
// Normalise headers if only smaller headers have been used
|
// Normalise headers if only smaller headers have been used
|
||||||
if (count($tree) > 0) {
|
|
||||||
$minLevel = $tree->pluck('level')->min();
|
$minLevel = $tree->pluck('level')->min();
|
||||||
$tree = $tree->map(function ($header) use ($minLevel) {
|
$tree = $tree->map(function ($header) use ($minLevel) {
|
||||||
$header['level'] -= ($minLevel - 2);
|
$header['level'] -= ($minLevel - 2);
|
||||||
return $header;
|
return $header;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return $tree->toArray();
|
return $tree->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ class RegisterController extends Controller
|
||||||
|
|
||||||
if ($registrationRestrict) {
|
if ($registrationRestrict) {
|
||||||
$restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
|
$restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
|
||||||
$userEmailDomain = $domain = substr(strrchr($userData['email'], "@"), 1);
|
$userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1);
|
||||||
if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
|
if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
|
||||||
throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
|
throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,7 +230,7 @@ class ImageRepo
|
||||||
{
|
{
|
||||||
$image->thumbs = [
|
$image->thumbs = [
|
||||||
'gallery' => $this->getThumbnail($image, 150, 150, false),
|
'gallery' => $this->getThumbnail($image, 150, 150, false),
|
||||||
'display' => $this->getThumbnail($image, 840, null, true)
|
'display' => $this->getThumbnail($image, 1680, null, true)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,18 +123,19 @@ function baseUrl($path, $forceAppDomain = false)
|
||||||
// Remove non-specified domain if forced and we have a domain
|
// Remove non-specified domain if forced and we have a domain
|
||||||
if ($isFullUrl && $forceAppDomain) {
|
if ($isFullUrl && $forceAppDomain) {
|
||||||
if (!empty($base) && strpos($path, $base) === 0) {
|
if (!empty($base) && strpos($path, $base) === 0) {
|
||||||
$path = trim(substr($path, strlen($base) - 1));
|
$path = mb_substr($path, mb_strlen($base));
|
||||||
}
|
} else {
|
||||||
$explodedPath = explode('/', $path);
|
$explodedPath = explode('/', $path);
|
||||||
$path = implode('/', array_splice($explodedPath, 3));
|
$path = implode('/', array_splice($explodedPath, 3));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return normal url path if not specified in config
|
// Return normal url path if not specified in config
|
||||||
if (config('app.url') === '') {
|
if (config('app.url') === '') {
|
||||||
return url($path);
|
return url($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $base . '/' . $path;
|
return $base . '/' . ltrim($path, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -180,9 +180,20 @@ class MarkdownEditor {
|
||||||
|
|
||||||
// Handle image paste
|
// Handle image paste
|
||||||
cm.on('paste', (cm, event) => {
|
cm.on('paste', (cm, event) => {
|
||||||
if (!event.clipboardData || !event.clipboardData.items) return;
|
const clipboardItems = event.clipboardData.items;
|
||||||
for (let i = 0; i < event.clipboardData.items.length; i++) {
|
if (!event.clipboardData || !clipboardItems) return;
|
||||||
uploadImage(event.clipboardData.items[i].getAsFile());
|
|
||||||
|
// Don't handle if clipboard includes text content
|
||||||
|
for (let clipboardItem of clipboardItems) {
|
||||||
|
if (clipboardItem.type.includes('text/')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let clipboardItem of clipboardItems) {
|
||||||
|
if (clipboardItem.type.includes("image")) {
|
||||||
|
uploadImage(clipboardItem.getAsFile());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ class PageDisplay {
|
||||||
|
|
||||||
// Sidebar page nav click event
|
// Sidebar page nav click event
|
||||||
$('.sidebar-page-nav').on('click', 'a', event => {
|
$('.sidebar-page-nav').on('click', 'a', event => {
|
||||||
|
window.components['tri-layout'][0].showContent();
|
||||||
this.goToText(event.target.getAttribute('href').substr(1));
|
this.goToText(event.target.getAttribute('href').substr(1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,28 +66,44 @@ class TriLayout {
|
||||||
*/
|
*/
|
||||||
mobileTabClick(event) {
|
mobileTabClick(event) {
|
||||||
const tab = event.target.getAttribute('tri-layout-mobile-tab');
|
const tab = event.target.getAttribute('tri-layout-mobile-tab');
|
||||||
|
this.showTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the content tab.
|
||||||
|
* Used by the page-display component.
|
||||||
|
*/
|
||||||
|
showContent() {
|
||||||
|
this.showTab('content');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the given tab
|
||||||
|
* @param tabName
|
||||||
|
*/
|
||||||
|
showTab(tabName) {
|
||||||
this.scrollCache[this.lastTabShown] = document.documentElement.scrollTop;
|
this.scrollCache[this.lastTabShown] = document.documentElement.scrollTop;
|
||||||
|
|
||||||
// Set tab status
|
// Set tab status
|
||||||
const activeTabs = document.querySelectorAll('.tri-layout-mobile-tab.active');
|
const tabs = document.querySelectorAll('.tri-layout-mobile-tab');
|
||||||
for (let tab of activeTabs) {
|
for (let tab of tabs) {
|
||||||
tab.classList.remove('active');
|
const isActive = (tab.getAttribute('tri-layout-mobile-tab') === tabName);
|
||||||
|
tab.classList.toggle('active', isActive);
|
||||||
}
|
}
|
||||||
event.target.classList.add('active');
|
|
||||||
|
|
||||||
// Toggle section
|
// Toggle section
|
||||||
const showInfo = (tab === 'info');
|
const showInfo = (tabName === 'info');
|
||||||
this.elem.classList.toggle('show-info', showInfo);
|
this.elem.classList.toggle('show-info', showInfo);
|
||||||
|
|
||||||
// Set the scroll position from cache
|
// Set the scroll position from cache
|
||||||
const pageHeader = document.querySelector('header');
|
const pageHeader = document.querySelector('header');
|
||||||
const defaultScrollTop = pageHeader.getBoundingClientRect().bottom;
|
const defaultScrollTop = pageHeader.getBoundingClientRect().bottom;
|
||||||
document.documentElement.scrollTop = this.scrollCache[tab] || defaultScrollTop;
|
document.documentElement.scrollTop = this.scrollCache[tabName] || defaultScrollTop;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.documentElement.scrollTop = this.scrollCache[tab] || defaultScrollTop;
|
document.documentElement.scrollTop = this.scrollCache[tabName] || defaultScrollTop;
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
this.lastTabShown = tab;
|
this.lastTabShown = tabName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,20 @@ import DrawIO from "../services/drawio";
|
||||||
* @param editor
|
* @param editor
|
||||||
*/
|
*/
|
||||||
function editorPaste(event, editor, wysiwygComponent) {
|
function editorPaste(event, editor, wysiwygComponent) {
|
||||||
if (!event.clipboardData || !event.clipboardData.items) return;
|
const clipboardItems = event.clipboardData.items;
|
||||||
|
if (!event.clipboardData || !clipboardItems) return;
|
||||||
|
|
||||||
for (let clipboardItem of event.clipboardData.items) {
|
// Don't handle if clipboard includes text content
|
||||||
if (clipboardItem.type.indexOf("image") === -1) continue;
|
for (let clipboardItem of clipboardItems) {
|
||||||
event.preventDefault();
|
if (clipboardItem.type.includes('text/')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let clipboardItem of clipboardItems) {
|
||||||
|
if (!clipboardItem.type.includes("image")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const id = "image-" + Math.random().toString(16).slice(2);
|
const id = "image-" + Math.random().toString(16).slice(2);
|
||||||
const loadingImage = window.baseUrl('/loading.gif');
|
const loadingImage = window.baseUrl('/loading.gif');
|
||||||
|
|
|
@ -181,7 +181,7 @@
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-bottom: $-xl;
|
margin-bottom: $-xl;
|
||||||
overflow: auto;
|
overflow: initial;
|
||||||
min-height: 60vh;
|
min-height: 60vh;
|
||||||
&.auto-height {
|
&.auto-height {
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
@ -202,7 +202,7 @@
|
||||||
}
|
}
|
||||||
@include smaller-than($s) {
|
@include smaller-than($s) {
|
||||||
.content-wrap.card {
|
.content-wrap.card {
|
||||||
padding: $-m $-s;
|
padding: $-m $-m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@include smaller-than($m) {
|
@include smaller-than($m) {
|
||||||
.grid.third {
|
.grid.third:not(.no-break) {
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
}
|
}
|
||||||
.grid.half:not(.no-break), .grid.left-focus:not(.no-break), .grid.right-focus:not(.no-break) {
|
.grid.half:not(.no-break), .grid.left-focus:not(.no-break), .grid.right-focus:not(.no-break) {
|
||||||
|
@ -81,7 +81,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@include smaller-than($s) {
|
@include smaller-than($s) {
|
||||||
.grid.third {
|
.grid.third:not(.no-break) {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,10 +257,6 @@ body.flexbox {
|
||||||
padding-left: $-m;
|
padding-left: $-m;
|
||||||
padding-right: $-m;
|
padding-right: $-m;
|
||||||
}
|
}
|
||||||
.tri-layout-right-contents > div, .tri-layout-left-contents > div {
|
|
||||||
opacity: 0.6;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
.tri-layout-left > *, .tri-layout-right > * {
|
.tri-layout-left > *, .tri-layout-right > * {
|
||||||
display: none;
|
display: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
@ -298,6 +294,13 @@ body.flexbox {
|
||||||
.tri-layout-mobile-tabs {
|
.tri-layout-mobile-tabs {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.tri-layout-left-contents > div, .tri-layout-right-contents > div {
|
||||||
|
opacity: 0.6;
|
||||||
|
transition: opacity ease-in-out 120ms;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include smaller-than($m) {
|
@include smaller-than($m) {
|
||||||
|
@ -306,11 +309,3 @@ body.flexbox {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tri-layout-left-contents > div, .tri-layout-right-contents > div {
|
|
||||||
opacity: 0.6;
|
|
||||||
transition: opacity ease-in-out 120ms;
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -164,15 +164,21 @@
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entity-list-item {
|
.entity-list-item {
|
||||||
padding-top: $-xxs;
|
padding-top: $-xxs;
|
||||||
padding-bottom: $-xxs;
|
padding-bottom: $-xxs;
|
||||||
|
background-clip: content-box;
|
||||||
|
border-radius: 0 3px 3px 0;
|
||||||
.content {
|
.content {
|
||||||
padding-top: $-xs;
|
padding-top: $-xs;
|
||||||
padding-bottom: $-xs;
|
padding-bottom: $-xs;
|
||||||
max-width: calc(100% - 20px);
|
max-width: calc(100% - 20px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.entity-list-item.selected {
|
||||||
|
background-color: rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
.entity-list-item.no-hover {
|
.entity-list-item.no-hover {
|
||||||
margin-top: -$-xs;
|
margin-top: -$-xs;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
|
|
|
@ -20,11 +20,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include smaller-than($m) {
|
@include smaller-than($s) {
|
||||||
.page-edit-toolbar {
|
.page-edit-toolbar {
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
overflow-y: visible;
|
overflow-y: visible;
|
||||||
z-index: 12;
|
|
||||||
}
|
}
|
||||||
.page-edit-toolbar .grid.third {
|
.page-edit-toolbar .grid.third {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -35,8 +34,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include smaller-than($m) {
|
.page-save-mobile-button {
|
||||||
.page-edit-toolbar #save-button {
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 30;
|
z-index: 30;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
@ -47,12 +45,10 @@
|
||||||
bottom: $-s;
|
bottom: $-s;
|
||||||
box-shadow: $bs-hover;
|
box-shadow: $bs-hover;
|
||||||
background-color: currentColor;
|
background-color: currentColor;
|
||||||
|
text-align: center;
|
||||||
svg {
|
svg {
|
||||||
fill: #FFF;
|
fill: #FFF;
|
||||||
}
|
margin-right: 0;
|
||||||
span {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,15 +291,27 @@ li.checkbox-item, li.task-list-item {
|
||||||
.text-center {
|
.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-left {
|
.text-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-right {
|
.text-right {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@each $sizeLetter, $size in $screen-sizes {
|
||||||
|
@include larger-than($size) {
|
||||||
|
.text-#{$sizeLetter}-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.text-#{$sizeLetter}-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.text-#{$sizeLetter}-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.text-bigger {
|
.text-bigger {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,14 @@ return [
|
||||||
'book_sort' => 'sorteerde boek',
|
'book_sort' => 'sorteerde boek',
|
||||||
'book_sort_notification' => 'Boek Succesvol Gesorteerd',
|
'book_sort_notification' => 'Boek Succesvol Gesorteerd',
|
||||||
|
|
||||||
|
// Bookshelves
|
||||||
|
'bookshelf_create' => 'maakte Boekenplank',
|
||||||
|
'bookshelf_create_notification' => 'Boekenplank Succesvol Aangemaakt',
|
||||||
|
'bookshelf_update' => 'veranderde boekenplank',
|
||||||
|
'bookshelf_update_notification' => 'Boekenplank Succesvol Bijgewerkt',
|
||||||
|
'bookshelf_delete' => 'verwijderde boekenplank',
|
||||||
|
'bookshelf_delete_notification' => 'Boekenplank Succesvol Verwijderd',
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
'commented_on' => 'reactie op',
|
'commented_on' => 'reactie op',
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
<?php
|
<?php
|
||||||
return [
|
return [
|
||||||
|
|
||||||
/**
|
|
||||||
* Buttons
|
// Buttons
|
||||||
*/
|
|
||||||
'cancel' => 'Annuleren',
|
'cancel' => 'Annuleren',
|
||||||
'confirm' => 'Bevestigen',
|
'confirm' => 'Bevestigen',
|
||||||
'back' => 'Terug',
|
'back' => 'Terug',
|
||||||
'save' => 'Opslaan',
|
'save' => 'Opslaan',
|
||||||
'continue' => 'Doorgaan',
|
'continue' => 'Doorgaan',
|
||||||
'select' => 'Kies',
|
'select' => 'Kies',
|
||||||
|
'toggle_all' => 'Toggle Alles',
|
||||||
'more' => 'Meer',
|
'more' => 'Meer',
|
||||||
|
|
||||||
/**
|
// Form Labels
|
||||||
* Form Labels
|
|
||||||
*/
|
|
||||||
'name' => 'Naam',
|
'name' => 'Naam',
|
||||||
'description' => 'Beschrijving',
|
'description' => 'Beschrijving',
|
||||||
'role' => 'Rol',
|
'role' => 'Rol',
|
||||||
'cover_image' => 'Omslagfoto',
|
'cover_image' => 'Omslagfoto',
|
||||||
'cover_image_description' => 'Deze afbeelding moet ongeveer 300x170px zijn.',
|
'cover_image_description' => 'Deze afbeelding moet ongeveer 300x170px zijn.',
|
||||||
/**
|
|
||||||
* Actions
|
// Actions
|
||||||
*/
|
|
||||||
'actions' => 'Acties',
|
'actions' => 'Acties',
|
||||||
'view' => 'Bekijk',
|
'view' => 'Bekijk',
|
||||||
|
'view_all' => 'Bekijk Alle',
|
||||||
'create' => 'Aanmaken',
|
'create' => 'Aanmaken',
|
||||||
'update' => 'Update',
|
'update' => 'Update',
|
||||||
'edit' => 'Bewerk',
|
'edit' => 'Bewerk',
|
||||||
'sort' => 'Sorteer',
|
'sort' => 'Sorteer',
|
||||||
'move' => 'Verplaats',
|
'move' => 'Verplaats',
|
||||||
|
'copy' => 'Kopiëren',
|
||||||
|
'reply' => 'Beantwoorden',
|
||||||
'delete' => 'Verwijder',
|
'delete' => 'Verwijder',
|
||||||
'search' => 'Zoek',
|
'search' => 'Zoek',
|
||||||
'search_clear' => 'Zoekopdracht wissen',
|
'search_clear' => 'Zoekopdracht wissen',
|
||||||
|
@ -37,15 +37,22 @@ return [
|
||||||
'remove' => 'Verwijderen',
|
'remove' => 'Verwijderen',
|
||||||
'add' => 'Toevoegen',
|
'add' => 'Toevoegen',
|
||||||
|
|
||||||
/**
|
// Sort Options
|
||||||
* Misc
|
'sort_name' => 'Naam',
|
||||||
*/
|
'sort_created_at' => 'Aanmaakdatum',
|
||||||
|
'sort_updated_at' => 'Gewijzigd op',
|
||||||
|
|
||||||
|
// Misc
|
||||||
'deleted_user' => 'Verwijderde gebruiker',
|
'deleted_user' => 'Verwijderde gebruiker',
|
||||||
'no_activity' => 'Geen activiteiten',
|
'no_activity' => 'Geen activiteiten',
|
||||||
'no_items' => 'Geen items beschikbaar',
|
'no_items' => 'Geen items beschikbaar',
|
||||||
'back_to_top' => 'Terug naar boven',
|
'back_to_top' => 'Terug naar boven',
|
||||||
'toggle_details' => 'Details Weergeven',
|
'toggle_details' => 'Details Weergeven',
|
||||||
'toggle_thumbnails' => 'Thumbnails Weergeven',
|
'toggle_thumbnails' => 'Thumbnails Weergeven',
|
||||||
|
'details' => 'Details',
|
||||||
|
'grid_view' => 'Grid weergave',
|
||||||
|
'list_view' => 'Lijst weergave',
|
||||||
|
'default' => 'Standaard',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Header
|
* Header
|
||||||
|
@ -53,6 +60,10 @@ return [
|
||||||
'view_profile' => 'Profiel Weergeven',
|
'view_profile' => 'Profiel Weergeven',
|
||||||
'edit_profile' => 'Profiel Bewerken',
|
'edit_profile' => 'Profiel Bewerken',
|
||||||
|
|
||||||
|
// Layout tabs
|
||||||
|
'tab_info' => 'Info',
|
||||||
|
'tab_content' => 'Inhoud',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Email Content
|
* Email Content
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -65,9 +65,38 @@ return [
|
||||||
'search_set_date' => 'Zet datum',
|
'search_set_date' => 'Zet datum',
|
||||||
'search_update' => 'Update zoekresultaten',
|
'search_update' => 'Update zoekresultaten',
|
||||||
|
|
||||||
/**
|
// Shelves
|
||||||
* Books
|
'shelf' => 'Boekenplank',
|
||||||
*/
|
'shelves' => 'Boekenplanken',
|
||||||
|
'x_shelves' => ':count Boekenplank|:count Boekenplanken',
|
||||||
|
'shelves_long' => 'Boekenplanken',
|
||||||
|
'shelves_empty' => 'Er zijn geen boekenplanken aangemaakt',
|
||||||
|
'shelves_create' => 'Nieuwe Boekenplank Aanmaken',
|
||||||
|
'shelves_popular' => 'Populaire Boekenplanken',
|
||||||
|
'shelves_new' => 'Nieuwe Boekenplanken',
|
||||||
|
'shelves_popular_empty' => 'De meest populaire boekenplanken worden hier weergegeven.',
|
||||||
|
'shelves_new_empty' => 'De meest recent aangemaakt boekenplanken worden hier weergeven.',
|
||||||
|
'shelves_save' => 'Boekenplanken Opslaan',
|
||||||
|
'shelves_books' => 'Boeken op deze plank',
|
||||||
|
'shelves_add_books' => 'Toevoegen boeken aan deze plank',
|
||||||
|
'shelves_drag_books' => 'Sleep boeken hier naartoe om deze toe te voegen aan deze plank',
|
||||||
|
'shelves_empty_contents' => 'Er zijn geen boeken aan deze plank toegekend',
|
||||||
|
'shelves_edit_and_assign' => 'Bewerk boekenplank om boeken toe te kennen.',
|
||||||
|
'shelves_edit_named' => 'Bewerk Boekenplank :name',
|
||||||
|
'shelves_edit' => 'Bewerk Boekenplank',
|
||||||
|
'shelves_delete' => 'Verwijder Boekenplank',
|
||||||
|
'shelves_delete_named' => 'Verwijder Boekenplank :name',
|
||||||
|
'shelves_delete_explain' => "Deze actie verwijdert de boekenplank met naam ':name'. De boeken op deze plank worden niet verwijderd.",
|
||||||
|
'shelves_delete_confirmation' => 'Weet je zeker dat je deze boekenplank wilt verwijderen?',
|
||||||
|
'shelves_permissions' => 'Boekenplank Permissies',
|
||||||
|
'shelves_permissions_updated' => 'Boekenplank Permissies Opgeslagen',
|
||||||
|
'shelves_permissions_active' => 'Boekenplank Permissies Actief',
|
||||||
|
'shelves_copy_permissions_to_books' => 'Kopieer Permissies naar Boeken',
|
||||||
|
'shelves_copy_permissions' => 'Kopieer Permissies',
|
||||||
|
'shelves_copy_permissions_explain' => 'Met deze actie worden de permissies van deze boekenplank gekopieerd naar alle boeken op de plank. Voordat deze actie wordt uitgevoerd, zorg dat de wijzigingen in de permissies van deze boekenplank zijn opgeslagen.',
|
||||||
|
'shelves_copy_permission_success' => 'Boekenplank permissies gekopieerd naar :count boeken',
|
||||||
|
|
||||||
|
// Books
|
||||||
'book' => 'Boek',
|
'book' => 'Boek',
|
||||||
'books' => 'Boeken',
|
'books' => 'Boeken',
|
||||||
'x_books' => ':count Boek|:count Boeken',
|
'x_books' => ':count Boek|:count Boeken',
|
||||||
|
|
|
@ -26,6 +26,7 @@ return [
|
||||||
*/
|
*/
|
||||||
'actions' => 'Действия',
|
'actions' => 'Действия',
|
||||||
'view' => 'Просмотр',
|
'view' => 'Просмотр',
|
||||||
|
'view_all' => 'Показать все',
|
||||||
'create' => 'Создание',
|
'create' => 'Создание',
|
||||||
'update' => 'Обновление',
|
'update' => 'Обновление',
|
||||||
'edit' => 'Редактировать',
|
'edit' => 'Редактировать',
|
||||||
|
@ -40,18 +41,24 @@ return [
|
||||||
'remove' => 'Удалить',
|
'remove' => 'Удалить',
|
||||||
'add' => 'Добавить',
|
'add' => 'Добавить',
|
||||||
|
|
||||||
|
// Sort Options
|
||||||
|
'sort_name' => 'По имени',
|
||||||
|
'sort_created_at' => 'По дате создания',
|
||||||
|
'sort_updated_at' => 'По дате обновления',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Misc
|
* Misc
|
||||||
*/
|
*/
|
||||||
'deleted_user' => 'Удаленный пользователь',
|
'deleted_user' => 'Удаленный пользователь',
|
||||||
'no_activity' => 'Нет действий для просмотра',
|
'no_activity' => 'Нет действий для просмотра',
|
||||||
'no_items' => 'Нет доступных элементов',
|
'no_items' => 'Нет доступных элементов',
|
||||||
'back_to_top' => 'Вернуться наверх',
|
'back_to_top' => 'Наверх',
|
||||||
'toggle_details' => 'Подробности',
|
'toggle_details' => 'Подробности',
|
||||||
'toggle_thumbnails' => 'Миниатюры',
|
'toggle_thumbnails' => 'Миниатюры',
|
||||||
'details' => 'Детали',
|
'details' => 'Детали',
|
||||||
'grid_view' => 'Вид сеткой',
|
'grid_view' => 'Вид сеткой',
|
||||||
'list_view' => 'Вид списком',
|
'list_view' => 'Вид списком',
|
||||||
|
'default' => 'По умолчанию',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Header
|
* Header
|
||||||
|
@ -59,6 +66,10 @@ return [
|
||||||
'view_profile' => 'Просмотреть профиль',
|
'view_profile' => 'Просмотреть профиль',
|
||||||
'edit_profile' => 'Редактировать профиль',
|
'edit_profile' => 'Редактировать профиль',
|
||||||
|
|
||||||
|
// Layout tabs
|
||||||
|
'tab_info' => 'Информация',
|
||||||
|
'tab_content' => 'Содержание',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Email Content
|
* Email Content
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -105,11 +105,13 @@ return [
|
||||||
*/
|
*/
|
||||||
'shelf' => 'Полка',
|
'shelf' => 'Полка',
|
||||||
'shelves' => 'Полки',
|
'shelves' => 'Полки',
|
||||||
|
'x_shelves' => ':count полок|:count полок',
|
||||||
'shelves_long' => 'Книжные полки',
|
'shelves_long' => 'Книжные полки',
|
||||||
'shelves_empty' => 'Полки не созданы',
|
'shelves_empty' => 'Полки не созданы',
|
||||||
'shelves_create' => 'Создать новую полку',
|
'shelves_create' => 'Создать новую полку',
|
||||||
'shelves_popular' => 'Популярные полки',
|
'shelves_popular' => 'Популярные полки',
|
||||||
'shelves_new' => 'Новые полки',
|
'shelves_new' => 'Новые полки',
|
||||||
|
'shelves_new_action' => 'Новая полка',
|
||||||
'shelves_popular_empty' => 'Популярные полки появятся здесь.',
|
'shelves_popular_empty' => 'Популярные полки появятся здесь.',
|
||||||
'shelves_new_empty' => 'Последние созданные полки появятся здесь.',
|
'shelves_new_empty' => 'Последние созданные полки появятся здесь.',
|
||||||
'shelves_save' => 'Сохранить полку',
|
'shelves_save' => 'Сохранить полку',
|
||||||
|
|
|
@ -1,77 +1,73 @@
|
||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
return [
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings text strings
|
* Settings text strings
|
||||||
* Contains all text strings used in the general settings sections of BookStack
|
* Contains all text strings used in the general settings sections of BookStack
|
||||||
* including users and roles.
|
* including users and roles.
|
||||||
*/
|
*/
|
||||||
|
return [
|
||||||
|
|
||||||
|
// Common Messages
|
||||||
'settings' => 'Настройки',
|
'settings' => 'Настройки',
|
||||||
'settings_save' => 'Сохранить настройки',
|
'settings_save' => 'Сохранить настройки',
|
||||||
'settings_save_success' => 'Настройки сохранены',
|
'settings_save_success' => 'Настройки сохранены',
|
||||||
|
|
||||||
/**
|
// App Settings
|
||||||
* App settings
|
'app_customization' => 'Настройки',
|
||||||
*/
|
'app_features_security' => 'Функции & Безопасность',
|
||||||
|
|
||||||
'app_settings' => 'Настройки приложения',
|
|
||||||
'app_name' => 'Имя приложения',
|
'app_name' => 'Имя приложения',
|
||||||
'app_name_desc' => 'Это имя отображается в заголовке и в любых письмах.',
|
'app_name_desc' => 'Имя отображается в заголовке email отправленных системой.',
|
||||||
'app_name_header' => 'Показать имя приложения в заголовке?',
|
'app_name_header' => 'Отображать имя приложения в заголовке',
|
||||||
|
'app_public_access' => 'Публичный доступ',
|
||||||
|
'app_public_access_desc' => 'Включение этой опции позволит неавторизованным посетителям получить доступ к содержимому вашего BookStack.',
|
||||||
|
'app_public_access_desc_guest' => 'Публичный доступ контролируется через настройки пользователя "Guest"',
|
||||||
|
'app_public_access_toggle' => 'Разрешить публичный доступ',
|
||||||
'app_public_viewing' => 'Разрешить публичный просмотр?',
|
'app_public_viewing' => 'Разрешить публичный просмотр?',
|
||||||
'app_secure_images' => 'Включить загрузку изображений с повышенной безопасностью?',
|
'app_secure_images' => 'Загрузка изображений с высоким уровнем безопасности.',
|
||||||
'app_secure_images_desc' => 'Из соображений производительности все изображения являются общедоступными. Этот параметр добавляет случайную сложную строку перед образами изображений. Убедитесь, что индексация каталогов не включена, чтобы предотвратить к ним легкий доступ.',
|
'app_secure_images_toggle' => 'Включить загрузку изображений с высоким уровнем безопасности',
|
||||||
|
'app_secure_images_desc' => 'Для высокой производительности все изображения являются общедоступными. Этот параметр добавляет случайную строку перед URL изображения. Убедитесь, что индексация каталогов отключена, для предотвращения легкого доступа.',
|
||||||
'app_editor' => 'Редактор страницы',
|
'app_editor' => 'Редактор страницы',
|
||||||
'app_editor_desc' => 'Выберите, какой редактор будет использоваться всеми пользователями для редактирования страниц.',
|
'app_editor_desc' => 'Выберите, какой редактор будет использоваться всеми пользователями для редактирования страниц.',
|
||||||
'app_custom_html' => 'Пользовательский контент заголовка HTML',
|
'app_custom_html' => 'Пользовательский контент заголовка HTML',
|
||||||
'app_custom_html_desc' => 'Любой контент, добавленный здесь, будет вставлен в нижнюю часть раздела <head> каждой страницы. Это удобно для переопределения стилей или добавления кода аналитики.',
|
'app_custom_html_desc' => 'Любой контент, добавленный здесь, будет вставлен в нижнюю часть раздела <head> каждой страницы. Это удобно для переопределения стилей или добавления кода аналитики.',
|
||||||
'app_logo' => 'Лого приложения',
|
'app_logo' => 'Лого приложения',
|
||||||
'app_logo_desc' => 'Это изображение должно быть 43px в высоту. <br>Большое изображение будет уменьшено.',
|
'app_logo_desc' => 'Это изображение должно быть 43px в высоту. <br>Большое изображение будет уменьшено.',
|
||||||
'app_primary_color' => 'Главный цвет приложения',
|
'app_primary_color' => 'Основной цвет приложения',
|
||||||
'app_primary_color_desc' => 'Значение должно быть указано в hex-формате. <br>Оставьте пустым чтобы использовать цвет по умолчанию.',
|
'app_primary_color_desc' => 'Значение должно быть указано в hex-формате. <br>Оставьте пустым чтобы использовать цвет по умолчанию.',
|
||||||
'app_homepage' => 'Домашняя страница приложения',
|
'app_homepage' => 'Стартовая страница приложения',
|
||||||
'app_homepage_desc' => 'Выберите страницу, которая будет отображаться на главной странице вместо стандартной. Права на страницы игнорируются для выбранных страниц.',
|
'app_homepage_desc' => 'Выберите страницу, которая будет отображаться на главной странице вместо стандартной. Права на страницы игнорируются для выбранных страниц.',
|
||||||
'app_homepage_default' => 'Выбрана домашняя страница по умолчанию',
|
'app_homepage_select' => 'Выберите страницу',
|
||||||
'app_homepage_books' => 'Или выберите страницу со списком книг в качестве главной страницы. Это будет иметь приоритет над любой другой страницей.',
|
'app_disable_comments' => 'Отключение комментов',
|
||||||
'app_disable_comments' => 'Отключить комментарии',
|
'app_disable_comments_toggle' => 'Отключить комментарии',
|
||||||
'app_disable_comments_desc' => 'Отключить комментарии на всех страницах приложения. Существующие комментарии не отображаются.',
|
'app_disable_comments_desc' => 'Отключение комментов на всех страницах. Существующие комментарии отображаться не будут.',
|
||||||
|
|
||||||
/**
|
|
||||||
* Registration settings
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Registration Settings
|
||||||
'reg_settings' => 'Настройки регистрации',
|
'reg_settings' => 'Настройки регистрации',
|
||||||
'reg_allow' => 'Открыть регистрацию?',
|
'reg_enable' => 'Разрешить регистрацияю',
|
||||||
|
'reg_enable_toggle' => 'Разрешить регистрацию',
|
||||||
|
'reg_enable_desc' => 'Если регистрация разрешена, пользователь сможет зарегистрироваться в системе самомтоятельно. При регистрации назначается роль пользователя по умолчанию',
|
||||||
'reg_default_role' => 'Роль пользователя по умолчанию после регистрации',
|
'reg_default_role' => 'Роль пользователя по умолчанию после регистрации',
|
||||||
'reg_confirm_email' => 'Требуется подтверждение по электронной почте?',
|
'reg_email_confirmation' => 'Подтверждение электонной почты',
|
||||||
|
'reg_email_confirmation_toggle' => 'Требовать подтверждение по электронной почте',
|
||||||
'reg_confirm_email_desc' => 'Если используется ограничение по домену, подтверждение будет обязательно, а этот пункт проигнорирован.',
|
'reg_confirm_email_desc' => 'Если используется ограничение по домену, подтверждение будет обязательно, а этот пункт проигнорирован.',
|
||||||
'reg_confirm_restrict_domain' => 'Ограничить регистрацию по домену',
|
'reg_confirm_restrict_domain' => 'Ограничить регистрацию по домену',
|
||||||
'reg_confirm_restrict_domain_desc' => 'Введите список доменов почты через запятую, для которых возможна регистрация. Пользователям будет отправлено письмо для подтверждения адреса перед входом в приложение. <br> Обратите внимание, что пользователи смогут изменить свои адреса уже после регистрации.',
|
'reg_confirm_restrict_domain_desc' => 'Введите список доменов почты через запятую, для которых разрешена регистрация. Пользователям будет отправлено письмо для подтверждения адреса перед входом в приложение. <br> Обратите внимание, что пользователи смогут изменить свои адреса уже после регистрации.',
|
||||||
'reg_confirm_restrict_domain_placeholder' => 'Нет ограничений',
|
'reg_confirm_restrict_domain_placeholder' => 'Без ограничений',
|
||||||
|
|
||||||
/**
|
|
||||||
* Maintenance settings
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Maintenance settings
|
||||||
'maint' => 'Обслуживание',
|
'maint' => 'Обслуживание',
|
||||||
'maint_image_cleanup' => 'Очистка изображений',
|
'maint_image_cleanup' => 'Очистка изображений',
|
||||||
'maint_image_cleanup_desc' => 'Сканирует содержимое страниц и предыдущих версий и определяет изображения, которые не используются. Убедитесь, что у вас есть резервная копия базы данных и папки изображений перед запуском этой функции.',
|
'maint_image_cleanup_desc' => 'Сканирует содержимое страниц и предыдущих версий и определяет изображения, которые не используются. Убедитесь, что у вас есть резервная копия базы данных и папки изображений перед запуском этой функции.',
|
||||||
'maint_image_cleanup_ignore_revisions' => 'Пропускать изображения в версиях',
|
'maint_image_cleanup_ignore_revisions' => 'Пропускать изображения в версиях',
|
||||||
'maint_image_cleanup_run' => 'Запустить очистку',
|
'maint_image_cleanup_run' => 'Выполнить очистку',
|
||||||
'maint_image_cleanup_warning' => 'Найдено :count возможно бесполезных изображений. Вы уверены, что хотите удалить эти изображения?',
|
'maint_image_cleanup_warning' => 'Найдено :count возможно бесполезных изображений. Вы уверены, что хотите удалить эти изображения?',
|
||||||
'maint_image_cleanup_success' => ':count возможно бесполезных изображений было найдено и удалено!',
|
'maint_image_cleanup_success' => ':count возможно бесполезных изображений было найдено и удалено!',
|
||||||
'maint_image_cleanup_nothing_found' => 'Не найдено ни одного бесполезного изображения!',
|
'maint_image_cleanup_nothing_found' => 'Не найдено ни одного бесполезного изображения!',
|
||||||
|
|
||||||
/**
|
// Role Settings
|
||||||
* Role settings
|
|
||||||
*/
|
|
||||||
|
|
||||||
'roles' => 'Роли',
|
'roles' => 'Роли',
|
||||||
'role_user_roles' => 'Роли пользователя',
|
'role_user_roles' => 'Роли пользователя',
|
||||||
'role_create' => 'Создать новую роль',
|
'role_create' => 'Добавить роль',
|
||||||
'role_create_success' => 'Роль упешно создана',
|
'role_create_success' => 'Роль упешно добавлена',
|
||||||
'role_delete' => 'Удалить роль',
|
'role_delete' => 'Удалить роль',
|
||||||
'role_delete_confirm' => 'Это удалит роль с именем \':roleName\'.',
|
'role_delete_confirm' => 'Это удалит роль с именем \':roleName\'.',
|
||||||
'role_delete_users_assigned' => 'Эта роль назначена :userCount пользователям. Если вы хотите перенести их из этой роли, выберите новую роль ниже.',
|
'role_delete_users_assigned' => 'Эта роль назначена :userCount пользователям. Если вы хотите перенести их из этой роли, выберите новую роль ниже.',
|
||||||
|
@ -81,7 +77,7 @@ return [
|
||||||
'role_edit' => 'Редактировать роль',
|
'role_edit' => 'Редактировать роль',
|
||||||
'role_details' => 'Детали роли',
|
'role_details' => 'Детали роли',
|
||||||
'role_name' => 'Имя роли',
|
'role_name' => 'Имя роли',
|
||||||
'role_desc' => 'Короткое описание роли',
|
'role_desc' => 'Краткое описание роли',
|
||||||
'role_external_auth_id' => 'Внешние ID авторизации',
|
'role_external_auth_id' => 'Внешние ID авторизации',
|
||||||
'role_system' => 'Системные разрешения',
|
'role_system' => 'Системные разрешения',
|
||||||
'role_manage_users' => 'Управление пользователями',
|
'role_manage_users' => 'Управление пользователями',
|
||||||
|
@ -91,37 +87,43 @@ return [
|
||||||
'role_manage_settings' => 'Управление настройками приложения',
|
'role_manage_settings' => 'Управление настройками приложения',
|
||||||
'role_asset' => 'Разрешение для активации',
|
'role_asset' => 'Разрешение для активации',
|
||||||
'role_asset_desc' => 'Эти разрешения контролируют доступ по умолчанию к параметрам внутри системы. Разрешения на книги, главы и страницы перезапишут эти разрешения.',
|
'role_asset_desc' => 'Эти разрешения контролируют доступ по умолчанию к параметрам внутри системы. Разрешения на книги, главы и страницы перезапишут эти разрешения.',
|
||||||
|
'role_asset_admins' => 'Администраторы автоматически получают доступ ко всему контенту, но эти опции могут отображать или скрывать параметры пользовательского интерфейса.',
|
||||||
'role_all' => 'Все',
|
'role_all' => 'Все',
|
||||||
'role_own' => 'Владелец',
|
'role_own' => 'Владелец',
|
||||||
'role_controlled_by_asset' => 'Регулируемые активацией они загружаются в',
|
'role_controlled_by_asset' => 'Контролируется активом, в который они загружены',
|
||||||
'role_save' => 'Сохранить роль',
|
'role_save' => 'Сохранить роль',
|
||||||
'role_update_success' => 'Роль успешно обновлена',
|
'role_update_success' => 'Роль успешно обновлена',
|
||||||
'role_users' => 'Пользователи с данной ролью',
|
'role_users' => 'Пользователи с данной ролью',
|
||||||
'role_users_none' => 'Нет пользователей с данной ролью',
|
'role_users_none' => 'Нет пользователей с данной ролью',
|
||||||
|
|
||||||
/**
|
// Users
|
||||||
* Users
|
|
||||||
*/
|
|
||||||
|
|
||||||
'users' => 'Пользователи',
|
'users' => 'Пользователи',
|
||||||
'user_profile' => 'Профиль пользователя',
|
'user_profile' => 'Профиль пользователя',
|
||||||
'users_add_new' => 'Добавить нового пользователя',
|
'users_add_new' => 'Добавить пользователя',
|
||||||
'users_search' => 'Поиск пользователей',
|
'users_search' => 'Поиск пользователей',
|
||||||
|
'users_details' => 'Данные пользователя',
|
||||||
|
'users_details_desc' => 'Задайте имя для этого пользователя, чтобы другие могли его узнать',
|
||||||
|
'users_details_desc_no_email' => 'Задайте имя для этого пользователя, чтобы другие могли его узнать',
|
||||||
'users_role' => 'Роли пользователя',
|
'users_role' => 'Роли пользователя',
|
||||||
|
'users_role_desc' => 'Назначьте роли пользователю. Если назначено несколько ролей, разрешения будут суммироваться и пользователь получит все права назначенных ролей.',
|
||||||
|
'users_password' => 'Пароль пользователя',
|
||||||
|
'users_password_desc' => 'Установите пароль для входа в приложение. Должно быть не менее 5 символов.',
|
||||||
'users_external_auth_id' => 'Внешний ID аутентификации',
|
'users_external_auth_id' => 'Внешний ID аутентификации',
|
||||||
'users_password_warning' => 'Введите ниже свой пароль новый пароль для его изменения:',
|
'users_external_auth_id_desc' => 'Этот ID используется для связи с вашей LDAP системой.',
|
||||||
|
'users_password_warning' => 'Заполните ниже только если вы хотите сменить свой пароль.',
|
||||||
'users_system_public' => 'Этот пользователь представляет любых гостевых пользователей, которые посещают ваше приложение. Он не может использоваться для входа в систему и назначается автоматически.',
|
'users_system_public' => 'Этот пользователь представляет любых гостевых пользователей, которые посещают ваше приложение. Он не может использоваться для входа в систему и назначается автоматически.',
|
||||||
'users_delete' => 'Удалить пользователя',
|
'users_delete' => 'Удалить пользователя',
|
||||||
'users_delete_named' => 'Удалить пользователя :userName',
|
'users_delete_named' => 'Удалить пользователя :userName',
|
||||||
'users_delete_warning' => 'Это полностью удалит этого пользователя с именем \':userName\' из системы.',
|
'users_delete_warning' => 'Это полностью удалит пользователя с именем \':userName\' из системы.',
|
||||||
'users_delete_confirm' => 'Вы уверены что хотите удалить этого пользователя?',
|
'users_delete_confirm' => 'Вы уверены что хотите удалить этого пользователя?',
|
||||||
'users_delete_success' => 'Пользователи успешно удалены',
|
'users_delete_success' => 'Пользователи успешно удалены',
|
||||||
'users_edit' => 'Редактировать польщователя',
|
'users_edit' => 'Редактировать пользователя',
|
||||||
'users_edit_profile' => 'Редактировать профиль',
|
'users_edit_profile' => 'Редактировать профиль',
|
||||||
'users_edit_success' => 'Пользователь успешно обновлен',
|
'users_edit_success' => 'Пользователь успешно обновлен',
|
||||||
'users_avatar' => 'Аватар пользователя',
|
'users_avatar' => 'Аватар пользователя',
|
||||||
'users_avatar_desc' => 'Это изображение должно быть размером около 256px.',
|
'users_avatar_desc' => 'Выберите изображение. Изображение должно быть квадратным, размером около 256px.',
|
||||||
'users_preferred_language' => 'Предпочитаемый язык',
|
'users_preferred_language' => 'Предпочитаемый язык',
|
||||||
|
'users_preferred_language_desc' => 'Этот параметр изменит язык интерфейса приложения. Это не влияет на созданный пользователем контент.',
|
||||||
'users_social_accounts' => 'Аккаунты Соцсетей',
|
'users_social_accounts' => 'Аккаунты Соцсетей',
|
||||||
'users_social_accounts_info' => 'Здесь вы можете подключить другие учетные записи для более быстрого и легкого входа в систему. Отключение учетной записи здесь не разрешено. Отменить доступ к настройкам вашего профиля в подключенном социальном аккаунте.',
|
'users_social_accounts_info' => 'Здесь вы можете подключить другие учетные записи для более быстрого и легкого входа в систему. Отключение учетной записи здесь не разрешено. Отменить доступ к настройкам вашего профиля в подключенном социальном аккаунте.',
|
||||||
'users_social_connect' => 'Подключить аккаунт',
|
'users_social_connect' => 'Подключить аккаунт',
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
<h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
|
<h1 id="{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</h1>
|
||||||
|
|
||||||
@if($bookChild->isA('chapter'))
|
@if($bookChild->isA('chapter'))
|
||||||
<p>{{ $bookChild->description }}</p>
|
<p>{{ $bookChild->text }}</p>
|
||||||
|
|
||||||
@if(count($bookChild->pages) > 0)
|
@if(count($bookChild->pages) > 0)
|
||||||
@foreach($bookChild->pages as $page)
|
@foreach($bookChild->pages as $page)
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
@extends('tri-layout')
|
@extends('tri-layout')
|
||||||
|
|
||||||
@section('container-classes', 'mt-xl')
|
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
@include('books.list', ['books' => $books, 'view' => $view])
|
@include('books.list', ['books' => $books, 'view' => $view])
|
||||||
@stop
|
@stop
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
<div class="content-wrap mt-m card">
|
<div class="content-wrap mt-m card">
|
||||||
<div class="grid half v-center">
|
<div class="grid half v-center no-row-gap">
|
||||||
<h1 class="list-heading">{{ trans('entities.books') }}</h1>
|
<h1 class="list-heading">{{ trans('entities.books') }}</h1>
|
||||||
<div class="text-right">
|
<div class="text-m-right my-m">
|
||||||
|
|
||||||
@include('partials.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort, 'type' => 'books'])
|
@include('partials.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort, 'type' => 'books'])
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<div page-comments page-id="{{ $page->id }}" class="comments-list">
|
<div page-comments page-id="{{ $page->id }}" class="comments-list">
|
||||||
<div comment-count-bar class="grid half left-focus v-center">
|
<div comment-count-bar class="grid half left-focus v-center no-row-gap">
|
||||||
<h5 comments-title>{{ trans_choice('entities.comment_count', count($page->comments), ['count' => count($page->comments)]) }}</h5>
|
<h5 comments-title>{{ trans_choice('entities.comment_count', count($page->comments), ['count' => count($page->comments)]) }}</h5>
|
||||||
@if (count($page->comments) === 0)
|
@if (count($page->comments) === 0)
|
||||||
<div class="text-right" comment-add-button-container>
|
<div class="text-m-right" comment-add-button-container>
|
||||||
<button type="button" action="addComment"
|
<button type="button" action="addComment"
|
||||||
class="button outline">{{ trans('entities.comment_add') }}</button>
|
class="button outline">{{ trans('entities.comment_add') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
@extends('simple-layout')
|
@extends('tri-layout')
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
<div class="container mt-m">
|
@include('books.list', ['books' => $books, 'view' => $view])
|
||||||
<div class="grid right-focus gap-xl">
|
@stop
|
||||||
<div>
|
|
||||||
|
|
||||||
|
@section('left')
|
||||||
|
@include('common.home-sidebar')
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('right')
|
||||||
<div class="actions mb-xl">
|
<div class="actions mb-xl">
|
||||||
<h5>{{ trans('common.actions') }}</h5>
|
<h5>{{ trans('common.actions') }}</h5>
|
||||||
<div class="icon-list text-primary">
|
<div class="icon-list text-primary">
|
||||||
|
@ -12,12 +16,4 @@
|
||||||
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('common.home-sidebar')
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
@include('books.list', ['books' => $books, 'view' => $view])
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
|
@ -1,26 +1,24 @@
|
||||||
@extends('simple-layout')
|
@extends('tri-layout')
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
<div class="container mt-l">
|
<div class="mt-m">
|
||||||
<div class="grid right-focus gap-xl">
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<div class="actions mb-xl">
|
|
||||||
<h5>{{ trans('common.actions') }}</h5>
|
|
||||||
<div class="icon-list text-primary">
|
|
||||||
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@include('common.home-sidebar')
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="content-wrap card">
|
<div class="content-wrap card">
|
||||||
<div class="page-content" page-display="{{ $customHomepage->id }}">
|
<div class="page-content" page-display="{{ $customHomepage->id }}">
|
||||||
@include('pages.page-display', ['page' => $customHomepage])
|
@include('pages.page-display', ['page' => $customHomepage])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('left')
|
||||||
|
@include('common.home-sidebar')
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('right')
|
||||||
|
<div class="actions mb-xl">
|
||||||
|
<h5>{{ trans('common.actions') }}</h5>
|
||||||
|
<div class="icon-list text-primary">
|
||||||
|
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
|
@ -1,10 +1,14 @@
|
||||||
@extends('simple-layout')
|
@extends('tri-layout')
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
<div class="container mt-m">
|
@include('shelves.list', ['shelves' => $shelves, 'view' => $view])
|
||||||
<div class="grid right-focus gap-xl">
|
@stop
|
||||||
<div>
|
|
||||||
|
|
||||||
|
@section('left')
|
||||||
|
@include('common.home-sidebar')
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('right')
|
||||||
<div class="actions mb-xl">
|
<div class="actions mb-xl">
|
||||||
<h5>{{ trans('common.actions') }}</h5>
|
<h5>{{ trans('common.actions') }}</h5>
|
||||||
<div class="icon-list text-primary">
|
<div class="icon-list text-primary">
|
||||||
|
@ -12,12 +16,4 @@
|
||||||
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('common.home-sidebar')
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
@include('shelves.list', ['shelves' => $shelves, 'view' => $view])
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
{{--Header Bar--}}
|
{{--Header Bar--}}
|
||||||
<div class="primary-background-light toolbar page-edit-toolbar">
|
<div class="primary-background-light toolbar page-edit-toolbar">
|
||||||
<div class="grid third v-center">
|
<div class="grid third no-break v-center">
|
||||||
|
|
||||||
<div class="action-buttons text-left px-m py-xs">
|
<div class="action-buttons text-left px-m py-xs">
|
||||||
<a href="{{ back()->getTargetUrl() }}" class="text-button text-primary">@icon('back')<span class="hide-under-l">{{ trans('common.back') }}</span></a>
|
<a href="{{ back()->getTargetUrl() }}" class="text-button text-primary">@icon('back')<span class="hide-under-l">{{ trans('common.back') }}</span></a>
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
<span>{{-- Prevents button jumping on menu show --}}</span>
|
<span>{{-- Prevents button jumping on menu show --}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" id="save-button" class="float-left text-primary text-button text-pos-hover">@icon('save')<span>{{ trans('entities.pages_save') }}</span></button>
|
<button type="submit" id="save-button" class="float-left text-primary text-button text-pos-hover hide-under-m">@icon('save')<span>{{ trans('entities.pages_save') }}</span></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -120,4 +120,6 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" id="save-button-mobile" title="{{ trans('entities.pages_save') }}" class="text-primary text-button hide-over-m page-save-mobile-button">@icon('save')</button>
|
||||||
</div>
|
</div>
|
|
@ -190,6 +190,11 @@
|
||||||
<div>
|
<div>
|
||||||
<div v-pre class="card content-wrap">
|
<div v-pre class="card content-wrap">
|
||||||
<h1 class="list-heading">{{ trans('entities.search_results') }}</h1>
|
<h1 class="list-heading">{{ trans('entities.search_results') }}</h1>
|
||||||
|
<form action="{{ baseUrl('/search') }}" method="GET" class="search-box flexible hide-over-l">
|
||||||
|
<input value="{{$searchTerm}}" type="text" name="term" placeholder="{{ trans('common.search') }}">
|
||||||
|
<button type="submit">@icon('search')</button>
|
||||||
|
<button v-if="searching" v-cloak class="search-box-cancel text-neg" v-on:click="clearSearch" type="button">@icon('close')</button>
|
||||||
|
</form>
|
||||||
<h6 class="text-muted">{{ trans_choice('entities.search_total_results_found', $totalResults, ['count' => $totalResults]) }}</h6>
|
<h6 class="text-muted">{{ trans_choice('entities.search_total_results_found', $totalResults, ['count' => $totalResults]) }}</h6>
|
||||||
<div class="book-contents">
|
<div class="book-contents">
|
||||||
@include('partials.entity-list', ['entities' => $entities, 'showPath' => true])
|
@include('partials.entity-list', ['entities' => $entities, 'showPath' => true])
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?php namespace Tests;
|
<?php namespace Tests;
|
||||||
|
|
||||||
|
use BookStack\Entities\Page;
|
||||||
use BookStack\Notifications\ConfirmEmail;
|
use BookStack\Notifications\ConfirmEmail;
|
||||||
use BookStack\Auth\User;
|
use BookStack\Auth\User;
|
||||||
use BookStack\Settings\SettingService;
|
use BookStack\Settings\SettingService;
|
||||||
|
@ -334,6 +335,17 @@ class AuthTest extends BrowserKitTest
|
||||||
->seeLink('Sign up');
|
->seeLink('Sign up');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_login_redirects_to_initially_requested_url_correctly()
|
||||||
|
{
|
||||||
|
config()->set('app.url', 'http://localhost');
|
||||||
|
$page = Page::query()->first();
|
||||||
|
|
||||||
|
$this->visit($page->getUrl())
|
||||||
|
->seePageUrlIs(baseUrl('/login'));
|
||||||
|
$this->login('admin@admin.com', 'password')
|
||||||
|
->seePageUrlIs($page->getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a login
|
* Perform a login
|
||||||
* @param string $email
|
* @param string $email
|
||||||
|
|
|
@ -76,6 +76,20 @@ class ExportTest extends TestCase
|
||||||
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $book->slug . '.html"');
|
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $book->slug . '.html"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_book_html_export_shows_chapter_descriptions()
|
||||||
|
{
|
||||||
|
$chapterDesc = 'My custom test chapter description ' . str_random(12);
|
||||||
|
$chapter = Chapter::query()->first();
|
||||||
|
$chapter->description = $chapterDesc;
|
||||||
|
$chapter->save();
|
||||||
|
|
||||||
|
$book = $chapter->book;
|
||||||
|
$this->asEditor();
|
||||||
|
|
||||||
|
$resp = $this->get($book->getUrl('/export/html'));
|
||||||
|
$resp->assertSee($chapterDesc);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_chapter_text_export()
|
public function test_chapter_text_export()
|
||||||
{
|
{
|
||||||
$chapter = Chapter::first();
|
$chapter = Chapter::first();
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
<?php namespace Tests;
|
|
||||||
|
|
||||||
class HelpersTest extends TestCase
|
|
||||||
{
|
|
||||||
|
|
||||||
public function test_base_url_takes_config_into_account()
|
|
||||||
{
|
|
||||||
config()->set('app.url', 'http://example.com/bookstack');
|
|
||||||
$result = baseUrl('/');
|
|
||||||
$this->assertEquals('http://example.com/bookstack/', $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function test_base_url_takes_extra_path_into_account_on_forced_domain()
|
|
||||||
{
|
|
||||||
config()->set('app.url', 'http://example.com/bookstack');
|
|
||||||
$result = baseUrl('http://example.com/bookstack/', true);
|
|
||||||
$this->assertEquals('http://example.com/bookstack/', $result);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -38,10 +38,14 @@ class HomepageTest extends TestCase
|
||||||
$name = 'My custom homepage';
|
$name = 'My custom homepage';
|
||||||
$content = str_repeat('This is the body content of my custom homepage.', 20);
|
$content = str_repeat('This is the body content of my custom homepage.', 20);
|
||||||
$customPage = $this->newPage(['name' => $name, 'html' => $content]);
|
$customPage = $this->newPage(['name' => $name, 'html' => $content]);
|
||||||
$this->setSettings(['app-homepage' => $customPage->id]);
|
$this->setSettings([
|
||||||
|
'app-homepage' => $customPage->id,
|
||||||
|
'app-homepage-type' => 'page'
|
||||||
|
]);
|
||||||
|
|
||||||
$homeVisit = $this->get('/');
|
$homeVisit = $this->get('/');
|
||||||
$homeVisit->assertSee($name);
|
$homeVisit->assertSee($name);
|
||||||
|
$homeVisit->assertElementNotExists('#home-default');
|
||||||
|
|
||||||
$pageDeleteReq = $this->delete($customPage->getUrl());
|
$pageDeleteReq = $this->delete($customPage->getUrl());
|
||||||
$pageDeleteReq->assertStatus(302);
|
$pageDeleteReq->assertStatus(302);
|
||||||
|
@ -54,6 +58,23 @@ class HomepageTest extends TestCase
|
||||||
$homeVisit->assertStatus(200);
|
$homeVisit->assertStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_custom_homepage_can_be_deleted_once_custom_homepage_no_longer_used()
|
||||||
|
{
|
||||||
|
$this->asEditor();
|
||||||
|
$name = 'My custom homepage';
|
||||||
|
$content = str_repeat('This is the body content of my custom homepage.', 20);
|
||||||
|
$customPage = $this->newPage(['name' => $name, 'html' => $content]);
|
||||||
|
$this->setSettings([
|
||||||
|
'app-homepage' => $customPage->id,
|
||||||
|
'app-homepage-type' => 'default'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pageDeleteReq = $this->delete($customPage->getUrl());
|
||||||
|
$pageDeleteReq->assertStatus(302);
|
||||||
|
$pageDeleteReq->assertSessionHas('success');
|
||||||
|
$pageDeleteReq->assertSessionMissing('error');
|
||||||
|
}
|
||||||
|
|
||||||
public function test_set_book_homepage()
|
public function test_set_book_homepage()
|
||||||
{
|
{
|
||||||
$editor = $this->getEditor();
|
$editor = $this->getEditor();
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php namespace Tests;
|
||||||
|
|
||||||
|
class HelpersTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function test_base_url_takes_config_into_account()
|
||||||
|
{
|
||||||
|
config()->set('app.url', 'http://example.com/bookstack');
|
||||||
|
$result = baseUrl('/');
|
||||||
|
$this->assertEquals('http://example.com/bookstack/', $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_base_url_takes_extra_path_into_account_on_forced_domain()
|
||||||
|
{
|
||||||
|
config()->set('app.url', 'http://example.com/bookstack');
|
||||||
|
$result = baseUrl('http://example.com/bookstack/', true);
|
||||||
|
$this->assertEquals('http://example.com/bookstack/', $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_base_url_force_domain_works_as_expected_with_full_url_given()
|
||||||
|
{
|
||||||
|
config()->set('app.url', 'http://example.com');
|
||||||
|
$result = baseUrl('http://examps.com/books/test/page/cat', true);
|
||||||
|
$this->assertEquals('http://example.com/books/test/page/cat', $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_base_url_force_domain_works_when_app_domain_is_same_as_given_url()
|
||||||
|
{
|
||||||
|
config()->set('app.url', 'http://example.com');
|
||||||
|
$result = baseUrl('http://example.com/books/test/page/cat', true);
|
||||||
|
$this->assertEquals('http://example.com/books/test/page/cat', $result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
namespace Tests;
|
||||||
|
|
||||||
|
use BookStack\Entities\Repos\PageRepo;
|
||||||
|
|
||||||
|
class PageRepoTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var PageRepo $pageRepo
|
||||||
|
*/
|
||||||
|
protected $pageRepo;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->pageRepo = app()->make(PageRepo::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_get_page_nav_does_not_show_empty_titles()
|
||||||
|
{
|
||||||
|
$content = '<h1 id="testa">Hello</h1><h2 id="testb"> </h2><h3 id="testc"></h3>';
|
||||||
|
$navMap = $this->pageRepo->getPageNav($content);
|
||||||
|
|
||||||
|
$this->assertCount(1, $navMap);
|
||||||
|
$this->assertArraySubset([
|
||||||
|
'nodeName' => 'h1',
|
||||||
|
'link' => '#testa',
|
||||||
|
'text' => 'Hello'
|
||||||
|
], $navMap[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue