Compare commits

...

41 Commits

Author SHA1 Message Date
Dan Brown
e90da18ada Updated assets and version for v0.18.2 release 2017-10-01 18:12:59 +01:00
Dan Brown
a08d80e1cc Merge branch 'master' into release 2017-10-01 18:12:07 +01:00
Dan Brown
b711bc6816 Prevented 'Discard draft' option showing after saving a draft page 2017-10-01 18:11:24 +01:00
Dan Brown
247e6dba85 Fixed some design issues around cards
Reverted drop shadow change.
Fixed header line-height when linked.
Fixed overflowing paragraph text. Fixes #533.
2017-10-01 17:59:51 +01:00
Dan Brown
2b3d6e4e4a Updated search-regen command description 2017-10-01 17:51:59 +01:00
Dan Brown
6b1980c4f3 Merge branch 'master' of github.com:BookStackApp/BookStack 2017-10-01 13:19:41 +01:00
Dan Brown
9ba29770e1 Added azureAD social auth option
Closes #509
2017-10-01 13:19:17 +01:00
Dan Brown
3d375fae55 Merge pull request #529 from cipi1965/master
Updated italian translation
2017-10-01 11:44:45 +01:00
Dan Brown
c99a50de2c Merge pull request #528 from turbotankist/master
russian lang fixes
2017-10-01 11:43:31 +01:00
Dan Brown
1a32b25b5e Merge pull request #523 from sanderdw/master
Update dutch translations
2017-10-01 11:33:22 +01:00
Dan Brown
481aa5b5b0 Added 'last_commented' sort option to search
Closes #440
2017-10-01 11:24:33 +01:00
Dan Brown
c943eb4d0d Removed empty string null middleware as was causing issues 2017-09-30 14:44:52 +01:00
Dan Brown
aca6de49b0 Added missing middleware to trim input 2017-09-30 14:31:27 +01:00
Dan Brown
5fd04fa470 Updated search indexer to split words better
Will now split up words based on more chars than just spaces.
Not takes into account newlines, tabs, periods & commas.

Fixed #531
2017-09-30 14:14:23 +01:00
Dan Brown
87339e4cd0 Added missing codemirror theme class
Fixes #535
2017-09-30 13:48:38 +01:00
Dan Brown
a9eb058dad Updated issue template 2017-09-30 13:41:06 +01:00
Dan Brown
61fad6a665 Finished migration of last angular code 2017-09-30 13:27:08 +01:00
Matteo Piccina
fa4bee2d98 Updated italian translation 2017-09-27 10:44:08 +02:00
alexey
ce63260fa6 russian lang fixes 2017-09-27 11:17:56 +03:00
Dan Brown
a3557d5bb2 Tweaked shadows on cards 2017-09-24 18:47:34 +01:00
Dan Brown
9ca22976c3 Migrated editor toolbox, No more directives! 2017-09-24 18:30:21 +01:00
Dan Brown
9e2934fe17 Migrated editor inputs to non-angular JS 2017-09-23 12:24:06 +01:00
sanderdw
2259263214 Update entities.php 2017-09-23 00:52:08 +02:00
sanderdw
762cf5f183 Update components.php 2017-09-23 00:47:02 +02:00
sanderdw
07175f2b3e Update dutch translations 2017-09-23 00:28:25 +02:00
Dan Brown
6258175922 Updated assets and version for v0.18.1 release 2017-09-20 21:36:17 +01:00
Dan Brown
15736777a0 Merge branch 'master' into release 2017-09-20 21:35:33 +01:00
Dan Brown
0c4ddf16a5 Moved details card above book nav 2017-09-20 21:32:19 +01:00
Dan Brown
74a5e3113e Fixed page includes erroring on save
Closes #514
2017-09-20 21:03:40 +01:00
Dan Brown
df0a982433 Merge branch 'master' of github.com:BookStackApp/BookStack 2017-09-20 20:27:50 +01:00
Dan Brown
212f924ffa Refactored WYSIWYG editor image upload code
Added sketchy timeout to fix images being pasted at end of page.
Fixes #489
2017-09-20 20:27:00 +01:00
Dan Brown
09936566dd Upgrade tinymce version 2017-09-20 20:26:34 +01:00
Dan Brown
9469c04eab Merge pull request #517 from leomartinez/master
Added 'Spanish Argentina' translation
2017-09-20 20:17:39 +01:00
Leonardo Martinez
941bb73a68 Added missing colon 2017-09-19 14:25:44 -03:00
Leonardo Martinez
8e652f5d8f Added 'Spanish Argentina' translation. 2017-09-19 13:43:17 -03:00
Leonardo Martinez
eec1b21928 Added 'Spanish Argentina' translation. 2017-09-19 13:42:39 -03:00
Dan Brown
1baeb7bec9 Merge pull request #510 from sanderdw/patch-1
Update entities.php
2017-09-17 11:09:12 +01:00
Dan Brown
61475ca0a3 Merge pull request #506 from turbotankist/master
Russian lang added
2017-09-14 20:44:19 +01:00
sanderdw
244c5a3ebb Update entities.php 2017-09-14 21:43:47 +02:00
Dan Brown
39e7ac1c15 Updated social login to redirect to intended page.
Closes #508.
2017-09-14 20:20:47 +01:00
alexey
ab7f5def04 Russian lang added 2017-09-12 16:42:04 +03:00
87 changed files with 2658 additions and 922 deletions

View File

@@ -4,10 +4,18 @@ Desired Feature:
### For Bug Reports
* BookStack Version:
* BookStack Version *(Found in settings, Please don't put 'latest')*:
* PHP Version:
* MySQL Version:
##### Expected Behavior
##### Actual Behavior
##### Current Behavior
##### Steps to Reproduce

View File

@@ -19,7 +19,7 @@ class RegenerateSearch extends Command
*
* @var string
*/
protected $description = 'Command description';
protected $description = 'Re-index all content for searching';
protected $searchService;

View File

@@ -158,9 +158,9 @@ class PageController extends Controller
$this->checkOwnablePermission('page-view', $page);
$pageContent = $this->entityRepo->renderPage($page);
$page->html = $this->entityRepo->renderPage($page);
$sidebarTree = $this->entityRepo->getBookChildren($page->book);
$pageNav = $this->entityRepo->getPageNav($pageContent);
$pageNav = $this->entityRepo->getPageNav($page->html);
$page->load(['comments.createdBy']);
Views::add($page);
@@ -441,6 +441,7 @@ class PageController extends Controller
public function exportPdf($bookSlug, $pageSlug)
{
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
$page->html = $this->entityRepo->renderPage($page);
$pdfContent = $this->exportService->pageToPdf($page);
return response()->make($pdfContent, 200, [
'Content-Type' => 'application/octet-stream',
@@ -457,6 +458,7 @@ class PageController extends Controller
public function exportHtml($bookSlug, $pageSlug)
{
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
$page->html = $this->entityRepo->renderPage($page);
$containedHtml = $this->exportService->pageToContainedHtml($page);
return response()->make($containedHtml, 200, [
'Content-Type' => 'application/octet-stream',

View File

@@ -13,8 +13,8 @@ class Kernel extends HttpKernel
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\BookStack\Http\Middleware\TrimStrings::class,
];
/**
@@ -26,6 +26,8 @@ class Kernel extends HttpKernel
'web' => [
\BookStack\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\BookStack\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\BookStack\Http\Middleware\Localization::class
@@ -42,7 +44,7 @@ class Kernel extends HttpKernel
* @var array
*/
protected $routeMiddleware = [
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'auth' => \BookStack\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \BookStack\Http\Middleware\RedirectIfAuthenticated::class,

View File

@@ -0,0 +1,19 @@
<?php
namespace BookStack\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as BaseTrimmer;
class TrimStrings extends BaseTrimmer
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array
*/
protected $except = [
'password',
'password_confirmation',
'password-confirm',
];
}

View File

@@ -16,6 +16,7 @@ class EventServiceProvider extends ServiceProvider
protected $listen = [
SocialiteWasCalled::class => [
'SocialiteProviders\Slack\SlackExtendSocialite@handle',
'SocialiteProviders\Azure\AzureExtendSocialite@handle',
],
];

View File

@@ -716,7 +716,6 @@ class EntityRepo
$content = str_replace($matches[0][$index], trim($innerContent), $content);
}
$page->setAttribute('renderedHTML', $content);
return $content;
}

View File

@@ -382,11 +382,13 @@ class SearchService
protected function generateTermArrayFromText($text, $scoreAdjustment = 1)
{
$tokenMap = []; // {TextToken => OccurrenceCount}
$splitText = explode(' ', $text);
foreach ($splitText as $token) {
if ($token === '') continue;
$splitChars = " \n\t.,";
$token = strtok($text, $splitChars);
while ($token !== false) {
if (!isset($tokenMap[$token])) $tokenMap[$token] = 0;
$tokenMap[$token]++;
$token = strtok($splitChars);
}
$terms = [];
@@ -479,4 +481,23 @@ class SearchService
});
}
protected function filterSortBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
{
$functionName = camel_case('sort_by_' . $input);
if (method_exists($this, $functionName)) $this->$functionName($query, $model);
}
/**
* Sorting filter options
*/
protected function sortByLastCommented(\Illuminate\Database\Eloquent\Builder $query, Entity $model)
{
$commentsTable = $this->db->getTablePrefix() . 'comments';
$morphClass = str_replace('\\', '\\\\', $model->getMorphClass());
$commentQuery = $this->db->raw('(SELECT c1.entity_id, c1.entity_type, c1.created_at as last_commented FROM '.$commentsTable.' c1 LEFT JOIN '.$commentsTable.' c2 ON (c1.entity_id = c2.entity_id AND c1.entity_type = c2.entity_type AND c1.created_at < c2.created_at) WHERE c1.entity_type = \''. $morphClass .'\' AND c2.created_at IS NULL) as comments');
$query->join($commentQuery, $model->getTable() . '.id', '=', 'comments.entity_id')->orderBy('last_commented', 'desc');
}
}

View File

@@ -14,7 +14,7 @@ class SocialAuthService
protected $socialite;
protected $socialAccount;
protected $validSocialDrivers = ['google', 'github', 'facebook', 'slack', 'twitter'];
protected $validSocialDrivers = ['google', 'github', 'facebook', 'slack', 'twitter', 'azure'];
/**
* SocialAuthService constructor.
@@ -104,7 +104,8 @@ class SocialAuthService
// When a user is not logged in and a matching SocialAccount exists,
// Simply log the user into the application.
if (!$isLoggedIn && $socialAccount !== null) {
return $this->logUserIn($socialAccount->user);
auth()->login($socialAccount->user);
return redirect()->intended('/');
}
// When a user is logged in but the social account does not exist,
@@ -137,13 +138,6 @@ class SocialAuthService
throw new SocialSignInException($message . '.', '/login');
}
private function logUserIn($user)
{
auth()->login($user);
return redirect('/');
}
/**
* Ensure the social driver is correct and supported.
*

View File

@@ -18,7 +18,8 @@
"gathercontent/htmldiff": "^0.2.1",
"barryvdh/laravel-snappy": "^0.3.1",
"laravel/browser-kit-testing": "^1.0",
"socialiteproviders/slack": "^3.0"
"socialiteproviders/slack": "^3.0",
"socialiteproviders/microsoft-azure": "^3.0"
},
"require-dev": {
"fzaninotto/faker": "~1.4",

41
composer.lock generated
View File

@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "e6d32752d02dae662bedc69fa5856feb",
"content-hash": "5f0f4e912f1207e761caf9344f2308a0",
"hash": "aa5f3333b909857a179e6aa9c30ab9ab",
"content-hash": "dc4c98aa8942f27fde6a9faa440e1a74",
"packages": [
{
"name": "aws/aws-sdk-php",
@@ -2073,6 +2073,43 @@
"description": "Easily add new or override built-in providers in Laravel Socialite.",
"time": "2017-02-07 07:26:42"
},
{
"name": "socialiteproviders/microsoft-azure",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/SocialiteProviders/Microsoft-Azure.git",
"reference": "d7a703a782eb9f7eae0db803beaa3ddec19ef372"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SocialiteProviders/Microsoft-Azure/zipball/d7a703a782eb9f7eae0db803beaa3ddec19ef372",
"reference": "d7a703a782eb9f7eae0db803beaa3ddec19ef372",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0",
"socialiteproviders/manager": "~3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"SocialiteProviders\\Azure\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Hemmings",
"email": "chris@hemmin.gs"
}
],
"description": "Microsoft Azure OAuth2 Provider for Laravel Socialite",
"time": "2017-01-25 09:48:29"
},
{
"name": "socialiteproviders/slack",
"version": "v3.0.1",

View File

@@ -58,7 +58,7 @@ return [
*/
'locale' => env('APP_LANG', 'en'),
'locales' => ['en', 'de', 'es', 'fr', 'nl', 'pt_BR', 'sk', 'ja', 'pl', 'it'],
'locales' => ['en', 'de', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'ja', 'pl', 'it', 'ru'],
/*
|--------------------------------------------------------------------------

View File

@@ -72,6 +72,14 @@ return [
'name' => 'Twitter',
],
'azure' => [
'client_id' => env('AZURE_APP_ID', false),
'client_secret' => env('AZURE_APP_SECRET', false),
'tenant' => env('AZURE_TENANT', false),
'redirect' => env('APP_URL') . '/login/service/azure/callback',
'name' => 'Microsoft Azure',
],
'ldap' => [
'server' => env('LDAP_SERVER', false),
'dn' => env('LDAP_DN', false),

View File

@@ -25,11 +25,6 @@
"yargs": "^7.1.0"
},
"dependencies": {
"angular": "^1.5.5",
"angular-animate": "^1.5.5",
"angular-resource": "^1.5.5",
"angular-sanitize": "^1.5.5",
"angular-ui-sortable": "^0.17.0",
"axios": "^0.16.1",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.1",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("3",tinymce.util.Tools.resolve),g("1",["3"],function(a){return a("tinymce.PluginManager")}),g("2",["3"],function(a){return a("tinymce.util.Tools")}),g("0",["1","2"],function(a,b){return a.add("advlist",function(a){function c(b){return a.$.contains(a.getBody(),b)}function d(a){return a&&/^(OL|UL|DL)$/.test(a.nodeName)&&c(a)}function e(a,c){var d=[];return c&&b.each(c.split(/[ ,]/),function(a){d.push({text:a.replace(/\-/g," ").replace(/\b\w/g,function(a){return a.toUpperCase()}),data:"default"==a?"":a})}),d}function f(c,d){a.undoManager.transact(function(){var e,f=a.dom,g=a.selection;if(e=f.getParent(g.getNode(),"ol,ul"),!e||e.nodeName!=c||d===!1){var h={"list-style-type":d?d:""};a.execCommand("UL"==c?"InsertUnorderedList":"InsertOrderedList",!1,h)}e=f.getParent(g.getNode(),"ol,ul"),e&&b.each(f.select("ol,ul",e).concat([e]),function(a){a.nodeName!==c&&d!==!1&&(a=f.rename(a,c)),f.setStyle(a,"listStyleType",d?d:null),a.removeAttribute("data-mce-style")}),a.focus()})}function g(b){var c=a.dom.getStyle(a.dom.getParent(a.selection.getNode(),"ol,ul"),"listStyleType")||"";b.control.items().each(function(a){a.active(a.settings.data===c)})}var h,i,j=function(a,c){var d=a.settings.plugins?a.settings.plugins:"";return b.inArray(d.split(/[ ,]/),c)!==-1};h=e("OL",a.getParam("advlist_number_styles","default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman")),i=e("UL",a.getParam("advlist_bullet_styles","default,circle,disc,square"));var k=function(c){return function(){var e=this;a.on("NodeChange",function(a){var f=b.grep(a.parents,d);e.active(f.length>0&&f[0].nodeName===c)})}};j(a,"lists")&&(a.addCommand("ApplyUnorderedListStyle",function(a,b){f("UL",b["list-style-type"])}),a.addCommand("ApplyOrderedListStyle",function(a,b){f("OL",b["list-style-type"])}),a.addButton("numlist",{type:h.length>0?"splitbutton":"button",tooltip:"Numbered list",menu:h,onPostRender:k("OL"),onshow:g,onselect:function(a){f("OL",a.control.settings.data)},onclick:function(){f("OL",!1)}}),a.addButton("bullist",{type:i.length>0?"splitbutton":"button",tooltip:"Bullet list",onPostRender:k("UL"),menu:i,onshow:g,onselect:function(a){f("UL",a.control.settings.data)},onclick:function(){f("UL",!1)}}))}),function(){}}),d("0")()}();
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("3",tinymce.util.Tools.resolve),g("1",["3"],function(a){return a("tinymce.PluginManager")}),g("2",["3"],function(a){return a("tinymce.util.Tools")}),g("0",["1","2"],function(a,b){return a.add("advlist",function(a){function c(b){return a.$.contains(a.getBody(),b)}function d(a){return a&&/^(OL|UL|DL)$/.test(a.nodeName)&&c(a)}function e(a,c){var d=[];return c&&b.each(c.split(/[ ,]/),function(a){d.push({text:a.replace(/\-/g," ").replace(/\b\w/g,function(a){return a.toUpperCase()}),data:"default"==a?"":a})}),d}function f(b,c){var d="UL"==b?"InsertUnorderedList":"InsertOrderedList";a.execCommand(d,!1,c===!1?null:{"list-style-type":c})}function g(b){var c=a.dom.getStyle(a.dom.getParent(a.selection.getNode(),"ol,ul"),"listStyleType")||"";b.control.items().each(function(a){a.active(a.settings.data===c)})}var h,i,j=function(a,c){var d=a.settings.plugins?a.settings.plugins:"";return b.inArray(d.split(/[ ,]/),c)!==-1};h=e("OL",a.getParam("advlist_number_styles","default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman")),i=e("UL",a.getParam("advlist_bullet_styles","default,circle,disc,square"));var k=function(c){return function(){var e=this;a.on("NodeChange",function(a){var f=b.grep(a.parents,d);e.active(f.length>0&&f[0].nodeName===c)})}};j(a,"lists")&&(a.addCommand("ApplyUnorderedListStyle",function(a,b){f("UL",b["list-style-type"])}),a.addCommand("ApplyOrderedListStyle",function(a,b){f("OL",b["list-style-type"])}),a.addButton("numlist",{type:h.length>0?"splitbutton":"button",tooltip:"Numbered list",menu:h,onPostRender:k("OL"),onshow:g,onselect:function(a){f("OL",a.control.settings.data)},onclick:function(){a.execCommand("InsertOrderedList")}}),a.addButton("bullist",{type:i.length>0?"splitbutton":"button",tooltip:"Bullet list",onPostRender:k("UL"),menu:i,onshow:g,onselect:function(a){f("UL",a.control.settings.data)},onclick:function(){a.execCommand("InsertUnorderedList")}}))}),function(){}}),d("0")()}();

View File

@@ -1 +1 @@
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("3",tinymce.util.Tools.resolve),g("1",["3"],function(a){return a("tinymce.Env")}),g("2",["3"],function(a){return a("tinymce.PluginManager")}),g("0",["1","2"],function(a,b){return b.add("autolink",function(b){function c(a){f(a,-1,"(",!0)}function d(a){f(a,0,"",!0)}function e(a){f(a,-1,"",!1)}function f(a,b,c){function d(a,b){if(b<0&&(b=0),3==a.nodeType){var c=a.data.length;b>c&&(b=c)}return b}function e(a,b){1!=a.nodeType||a.hasChildNodes()?g.setStart(a,d(a,b)):g.setStartBefore(a)}function f(a,b){1!=a.nodeType||a.hasChildNodes()?g.setEnd(a,d(a,b)):g.setEndAfter(a)}var g,i,j,k,l,m,n,o,p,q;if("A"!=a.selection.getNode().tagName){if(g=a.selection.getRng(!0).cloneRange(),g.startOffset<5){if(o=g.endContainer.previousSibling,!o){if(!g.endContainer.firstChild||!g.endContainer.firstChild.nextSibling)return;o=g.endContainer.firstChild.nextSibling}if(p=o.length,e(o,p),f(o,p),g.endOffset<5)return;i=g.endOffset,k=o}else{if(k=g.endContainer,3!=k.nodeType&&k.firstChild){for(;3!=k.nodeType&&k.firstChild;)k=k.firstChild;3==k.nodeType&&(e(k,0),f(k,k.nodeValue.length))}i=1==g.endOffset?2:g.endOffset-1-b}j=i;do e(k,i>=2?i-2:0),f(k,i>=1?i-1:0),i-=1,q=g.toString();while(" "!=q&&""!==q&&160!=q.charCodeAt(0)&&i-2>=0&&q!=c);g.toString()==c||160==g.toString().charCodeAt(0)?(e(k,i),f(k,j),i+=1):0===g.startOffset?(e(k,0),f(k,j)):(e(k,i),f(k,j)),m=g.toString(),"."==m.charAt(m.length-1)&&f(k,j-1),m=g.toString(),n=m.match(h),n&&("www."==n[1]?n[1]="http://www.":/@$/.test(n[1])&&!/^mailto:/.test(n[1])&&(n[1]="mailto:"+n[1]),l=a.selection.getBookmark(),a.selection.setRng(g),a.execCommand("createlink",!1,n[1]+n[2]),a.settings.default_link_target&&a.dom.setAttrib(a.selection.getNode(),"target",a.settings.default_link_target),a.selection.moveToBookmark(l),a.nodeChanged())}}var g,h=/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i;return b.settings.autolink_pattern&&(h=b.settings.autolink_pattern),b.on("keydown",function(a){if(13==a.keyCode)return e(b)}),a.ie?void b.on("focus",function(){if(!g){g=!0;try{b.execCommand("AutoUrlDetect",!1,!0)}catch(a){}}}):(b.on("keypress",function(a){if(41==a.keyCode)return c(b)}),void b.on("keyup",function(a){if(32==a.keyCode)return d(b)}))}),function(){}}),d("0")()}();
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("3",tinymce.util.Tools.resolve),g("1",["3"],function(a){return a("tinymce.Env")}),g("2",["3"],function(a){return a("tinymce.PluginManager")}),g("0",["1","2"],function(a,b){var c=function(a,b){return a===b||" "===a||160===a.charCodeAt(0)};return b.add("autolink",function(b){function d(a){g(a,-1,"(",!0)}function e(a){g(a,0,"",!0)}function f(a){g(a,-1,"",!1)}function g(a,b,d){function e(a,b){if(b<0&&(b=0),3==a.nodeType){var c=a.data.length;b>c&&(b=c)}return b}function f(a,b){1!=a.nodeType||a.hasChildNodes()?h.setStart(a,e(a,b)):h.setStartBefore(a)}function g(a,b){1!=a.nodeType||a.hasChildNodes()?h.setEnd(a,e(a,b)):h.setEndAfter(a)}var h,j,k,l,m,n,o,p,q,r;if("A"!=a.selection.getNode().tagName){if(h=a.selection.getRng(!0).cloneRange(),h.startOffset<5){if(p=h.endContainer.previousSibling,!p){if(!h.endContainer.firstChild||!h.endContainer.firstChild.nextSibling)return;p=h.endContainer.firstChild.nextSibling}if(q=p.length,f(p,q),g(p,q),h.endOffset<5)return;j=h.endOffset,l=p}else{if(l=h.endContainer,3!=l.nodeType&&l.firstChild){for(;3!=l.nodeType&&l.firstChild;)l=l.firstChild;3==l.nodeType&&(f(l,0),g(l,l.nodeValue.length))}j=1==h.endOffset?2:h.endOffset-1-b}k=j;do f(l,j>=2?j-2:0),g(l,j>=1?j-1:0),j-=1,r=h.toString();while(" "!=r&&""!==r&&160!=r.charCodeAt(0)&&j-2>=0&&r!=d);c(h.toString(),d)?(f(l,j),g(l,k),j+=1):0===h.startOffset?(f(l,0),g(l,k)):(f(l,j),g(l,k)),n=h.toString(),"."==n.charAt(n.length-1)&&g(l,k-1),n=h.toString(),o=n.match(i),o&&("www."==o[1]?o[1]="http://www.":/@$/.test(o[1])&&!/^mailto:/.test(o[1])&&(o[1]="mailto:"+o[1]),m=a.selection.getBookmark(),a.selection.setRng(h),a.execCommand("createlink",!1,o[1]+o[2]),a.settings.default_link_target&&a.dom.setAttrib(a.selection.getNode(),"target",a.settings.default_link_target),a.selection.moveToBookmark(m),a.nodeChanged())}}var h,i=/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i;return b.settings.autolink_pattern&&(i=b.settings.autolink_pattern),b.on("keydown",function(a){if(13==a.keyCode)return f(b)}),a.ie?void b.on("focus",function(){if(!h){h=!0;try{b.execCommand("AutoUrlDetect",!1,!0)}catch(a){}}}):(b.on("keypress",function(a){if(41==a.keyCode)return d(b)}),void b.on("keyup",function(a){if(32==a.keyCode)return e(b)}))}),function(){}}),d("0")()}();

View File

@@ -1 +1 @@
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("6",tinymce.util.Tools.resolve),g("1",["6"],function(a){return a("tinymce.EditorManager")}),g("2",["6"],function(a){return a("tinymce.PluginManager")}),g("3",["6"],function(a){return a("tinymce.util.LocalStorage")}),g("4",["6"],function(a){return a("tinymce.util.Tools")}),h("5",window),g("0",["1","2","3","4","5"],function(a,b,c,d,e){return a._beforeUnloadHandler=function(){var b;return d.each(a.editors,function(a){a.plugins.autosave&&a.plugins.autosave.storeDraft(),!b&&a.isDirty()&&a.getParam("autosave_ask_before_unload",!0)&&(b=a.translate("You have unsaved changes are you sure you want to navigate away?"))}),b},b.add("autosave",function(b){function f(a,b){var c={s:1e3,m:6e4};return a=/^(\d+)([ms]?)$/.exec(""+(a||b)),(a[2]?c[a[2]]:1)*parseInt(a,10)}function g(){var a=parseInt(c.getItem(o+"time"),10)||0;return!((new Date).getTime()-a>q.autosave_retention)||(h(!1),!1)}function h(a){c.removeItem(o+"draft"),c.removeItem(o+"time"),a!==!1&&b.fire("RemoveDraft")}function i(){!n()&&b.isDirty()&&(c.setItem(o+"draft",b.getContent({format:"raw",no_events:!0})),c.setItem(o+"time",(new Date).getTime()),b.fire("StoreDraft"))}function j(){g()&&(b.setContent(c.getItem(o+"draft"),{format:"raw"}),b.fire("RestoreDraft"))}function k(){p||(setInterval(function(){b.removed||i()},q.autosave_interval),p=!0)}function l(){var a=this;a.disabled(!g()),b.on("StoreDraft RestoreDraft RemoveDraft",function(){a.disabled(!g())}),k()}function m(){b.undoManager.beforeChange(),j(),h(),b.undoManager.add()}function n(a){var c=b.settings.forced_root_block;return a=d.trim("undefined"==typeof a?b.getBody().innerHTML:a),""===a||new RegExp("^<"+c+"[^>]*>((\xa0|&nbsp;|[ \t]|<br[^>]*>)+?|)</"+c+">|<br>$","i").test(a)}var o,p,q=b.settings;o=q.autosave_prefix||"tinymce-autosave-{path}{query}-{id}-",o=o.replace(/\{path\}/g,document.location.pathname),o=o.replace(/\{query\}/g,document.location.search),o=o.replace(/\{id\}/g,b.id),q.autosave_interval=f(q.autosave_interval,"30s"),q.autosave_retention=f(q.autosave_retention,"20m"),b.addButton("restoredraft",{title:"Restore last draft",onclick:m,onPostRender:l}),b.addMenuItem("restoredraft",{text:"Restore last draft",onclick:m,onPostRender:l,context:"file"}),b.settings.autosave_restore_when_empty!==!1&&(b.on("init",function(){g()&&n()&&j()}),b.on("saveContent",function(){h()})),e.onbeforeunload=a._beforeUnloadHandler,this.hasDraft=g,this.storeDraft=i,this.restoreDraft=j,this.removeDraft=h,this.isEmpty=n}),function(){}}),d("0")()}();
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("6",tinymce.util.Tools.resolve),g("1",["6"],function(a){return a("tinymce.EditorManager")}),g("2",["6"],function(a){return a("tinymce.PluginManager")}),g("3",["6"],function(a){return a("tinymce.util.LocalStorage")}),g("4",["6"],function(a){return a("tinymce.util.Tools")}),h("5",window),g("0",["1","2","3","4","5"],function(a,b,c,d,e){return a._beforeUnloadHandler=function(){var b;return d.each(a.get(),function(a){a.plugins.autosave&&a.plugins.autosave.storeDraft(),!b&&a.isDirty()&&a.getParam("autosave_ask_before_unload",!0)&&(b=a.translate("You have unsaved changes are you sure you want to navigate away?"))}),b},b.add("autosave",function(b){function f(a,b){var c={s:1e3,m:6e4};return a=/^(\d+)([ms]?)$/.exec(""+(a||b)),(a[2]?c[a[2]]:1)*parseInt(a,10)}function g(){var a=parseInt(c.getItem(o+"time"),10)||0;return!((new Date).getTime()-a>q.autosave_retention)||(h(!1),!1)}function h(a){c.removeItem(o+"draft"),c.removeItem(o+"time"),a!==!1&&b.fire("RemoveDraft")}function i(){!n()&&b.isDirty()&&(c.setItem(o+"draft",b.getContent({format:"raw",no_events:!0})),c.setItem(o+"time",(new Date).getTime()),b.fire("StoreDraft"))}function j(){g()&&(b.setContent(c.getItem(o+"draft"),{format:"raw"}),b.fire("RestoreDraft"))}function k(){p||(setInterval(function(){b.removed||i()},q.autosave_interval),p=!0)}function l(){var a=this;a.disabled(!g()),b.on("StoreDraft RestoreDraft RemoveDraft",function(){a.disabled(!g())}),k()}function m(){b.undoManager.beforeChange(),j(),h(),b.undoManager.add()}function n(a){var c=b.settings.forced_root_block;return a=d.trim("undefined"==typeof a?b.getBody().innerHTML:a),""===a||new RegExp("^<"+c+"[^>]*>((\xa0|&nbsp;|[ \t]|<br[^>]*>)+?|)</"+c+">|<br>$","i").test(a)}var o,p,q=b.settings;o=q.autosave_prefix||"tinymce-autosave-{path}{query}-{id}-",o=o.replace(/\{path\}/g,document.location.pathname),o=o.replace(/\{query\}/g,document.location.search),o=o.replace(/\{id\}/g,b.id),q.autosave_interval=f(q.autosave_interval,"30s"),q.autosave_retention=f(q.autosave_retention,"20m"),b.addButton("restoredraft",{title:"Restore last draft",onclick:m,onPostRender:l}),b.addMenuItem("restoredraft",{text:"Restore last draft",onclick:m,onPostRender:l,context:"file"}),b.settings.autosave_restore_when_empty!==!1&&(b.on("init",function(){g()&&n()&&j()}),b.on("saveContent",function(){h()})),e.onbeforeunload=a._beforeUnloadHandler,this.hasDraft=g,this.storeDraft=i,this.restoreDraft=j,this.removeDraft=h,this.isEmpty=n}),function(){}}),d("0")()}();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("2",tinymce.util.Tools.resolve),g("1",["2"],function(a){return a("tinymce.PluginManager")}),g("0",["1"],function(a){return a.add("nonbreaking",function(a){var b=a.getParam("nonbreaking_force_tab");if(a.addCommand("mceNonBreaking",function(){a.insertContent(a.plugins.visualchars&&a.plugins.visualchars.state?'<span class="mce-nbsp">&nbsp;</span>':"&nbsp;"),a.dom.setAttrib(a.dom.select("span.mce-nbsp"),"data-mce-bogus","1")}),a.addButton("nonbreaking",{title:"Nonbreaking space",cmd:"mceNonBreaking"}),a.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),b){var c=+b>1?+b:3;a.on("keydown",function(b){if(9==b.keyCode){if(b.shiftKey)return;b.preventDefault();for(var d=0;d<c;d++)a.execCommand("mceNonBreaking")}})}}),function(){}}),d("0")()}();
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("2",tinymce.util.Tools.resolve),g("1",["2"],function(a){return a("tinymce.PluginManager")}),g("0",["1"],function(a){return a.add("nonbreaking",function(a){var b=a.getParam("nonbreaking_force_tab"),c=function(a,b){for(var c="",d=0;d<b;d++)c+=a;return c},d=function(b){var d=a.plugins.visualchars&&a.plugins.visualchars.state?'<span class="mce-nbsp">&nbsp;</span>':"&nbsp;";a.insertContent(c(d,b)),a.dom.setAttrib(a.dom.select("span.mce-nbsp"),"data-mce-bogus","1")};if(a.addCommand("mceNonBreaking",function(){d(1)}),a.addButton("nonbreaking",{title:"Nonbreaking space",cmd:"mceNonBreaking"}),a.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),b){var e=+b>1?+b:3;a.on("keydown",function(a){if(9==a.keyCode){if(a.shiftKey)return;a.preventDefault(),d(e)}})}}),function(){}}),d("0")()}();

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("4",tinymce.util.Tools.resolve),g("1",["4"],function(a){return a("tinymce.PluginManager")}),g("2",["4"],function(a){return a("tinymce.Env")}),g("3",["4"],function(a){return a("tinymce.util.Tools")}),g("0",["1","2","3"],function(a,b,c){return a.add("preview",function(a){var d=a.settings,e=!b.ie;a.addCommand("mcePreview",function(){a.windowManager.open({title:"Preview",width:parseInt(a.getParam("plugin_preview_width","650"),10),height:parseInt(a.getParam("plugin_preview_height","500"),10),html:'<iframe src="javascript:\'\'" frameborder="0"'+(e?' sandbox="allow-scripts"':"")+"></iframe>",buttons:{text:"Close",onclick:function(){this.parent().parent().close()}},onPostRender:function(){var b,f="";f+='<base href="'+a.documentBaseURI.getURI()+'">',c.each(a.contentCSS,function(b){f+='<link type="text/css" rel="stylesheet" href="'+a.documentBaseURI.toAbsolute(b)+'">'});var g=d.body_id||"tinymce";g.indexOf("=")!=-1&&(g=a.getParam("body_id","","hash"),g=g[a.id]||g);var h=d.body_class||"";h.indexOf("=")!=-1&&(h=a.getParam("body_class","","hash"),h=h[a.id]||"");var i='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A") {e.preventDefault();}}}, false);</script> ',j=a.settings.directionality?' dir="'+a.settings.directionality+'"':"";if(b="<!DOCTYPE html><html><head>"+f+'</head><body id="'+g+'" class="mce-content-body '+h+'"'+j+">"+a.getContent()+i+"</body></html>",e)this.getEl("body").firstChild.src="data:text/html;charset=utf-8,"+encodeURIComponent(b);else{var k=this.getEl("body").firstChild.contentWindow.document;k.open(),k.write(b),k.close()}}})}),a.addButton("preview",{title:"Preview",cmd:"mcePreview"}),a.addMenuItem("preview",{text:"Preview",cmd:"mcePreview",context:"view"})}),function(){}}),d("0")()}();
!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("4",tinymce.util.Tools.resolve),g("1",["4"],function(a){return a("tinymce.PluginManager")}),g("2",["4"],function(a){return a("tinymce.Env")}),g("3",["4"],function(a){return a("tinymce.util.Tools")}),g("0",["1","2","3"],function(a,b,c){return a.add("preview",function(a){var d=a.settings,e=!b.ie;a.addCommand("mcePreview",function(){a.windowManager.open({title:"Preview",width:parseInt(a.getParam("plugin_preview_width","650"),10),height:parseInt(a.getParam("plugin_preview_height","500"),10),html:'<iframe src="javascript:\'\'" frameborder="0"'+(e?' sandbox="allow-scripts"':"")+"></iframe>",buttons:{text:"Close",onclick:function(){this.parent().parent().close()}},onPostRender:function(){var b,f="",g=a.dom.encode;f+='<base href="'+g(a.documentBaseURI.getURI())+'">',c.each(a.contentCSS,function(b){f+='<link type="text/css" rel="stylesheet" href="'+g(a.documentBaseURI.toAbsolute(b))+'">'});var h=d.body_id||"tinymce";h.indexOf("=")!=-1&&(h=a.getParam("body_id","","hash"),h=h[a.id]||h);var i=d.body_class||"";i.indexOf("=")!=-1&&(i=a.getParam("body_class","","hash"),i=i[a.id]||"");var j='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A") {e.preventDefault();}}}, false);</script> ',k=a.settings.directionality?' dir="'+a.settings.directionality+'"':"";if(b="<!DOCTYPE html><html><head>"+f+'</head><body id="'+g(h)+'" class="mce-content-body '+g(i)+'"'+g(k)+">"+a.getContent()+j+"</body></html>",e)this.getEl("body").firstChild.src="data:text/html;charset=utf-8,"+encodeURIComponent(b);else{var l=this.getEl("body").firstChild.contentWindow.document;l.open(),l.write(b),l.close()}}})}),a.addButton("preview",{title:"Preview",cmd:"mcePreview"}),a.addMenuItem("preview",{text:"Preview",cmd:"mcePreview",context:"view"})}),function(){}}),d("0")()}();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}.mce-content-body p,.mce-content-body div,.mce-content-body h1,.mce-content-body h2,.mce-content-body h3,.mce-content-body h4,.mce-content-body h5,.mce-content-body h6{line-height:1.2em}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-content-body a[data-mce-selected],.mce-content-body code[data-mce-selected]{background:#bfe6ff}.mce-content-body hr{cursor:default}
.word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-content-body a[data-mce-selected],.mce-content-body code[data-mce-selected],.mce-content-body b[data-mce-selected],.mce-content-body i[data-mce-selected],.mce-content-body em[data-mce-selected],.mce-content-body strong[data-mce-selected],.mce-content-body sup[data-mce-selected],.mce-content-body sub[data-mce-selected]{background:#bfe6ff}.mce-content-body hr{cursor:default}.mce-content-body{line-height:1.3}

View File

@@ -1 +1 @@
body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}.mce-content-body p,.mce-content-body div,.mce-content-body h1,.mce-content-body h2,.mce-content-body h3,.mce-content-body h4,.mce-content-body h5,.mce-content-body h6{line-height:1.2em}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-content-body a[data-mce-selected],.mce-content-body code[data-mce-selected]{background:#bfe6ff}.mce-content-body hr{cursor:default}
body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;line-height:1.3;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px}.word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-content-body a[data-mce-selected],.mce-content-body code[data-mce-selected],.mce-content-body b[data-mce-selected],.mce-content-body i[data-mce-selected],.mce-content-body em[data-mce-selected],.mce-content-body strong[data-mce-selected],.mce-content-body sup[data-mce-selected],.mce-content-body sub[data-mce-selected]{background:#bfe6ff}.mce-content-body hr{cursor:default}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -76,7 +76,6 @@ The BookStack source is provided under the MIT License.
These are the great open-source projects used to help build BookStack:
* [Laravel](http://laravel.com/)
* [AngularJS](https://angularjs.org/)
* [jQuery](https://jquery.com/)
* [TinyMCE](https://www.tinymce.com/)
* [CodeMirror](https://codemirror.net)

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 129 129"><path fill="#f25022" d="M0 0h61.3v61.3H0z"/><path fill="#7fba00" d="M67.7 0H129v61.3H67.7z"/><path fill="#00a4ef" d="M0 67.7h61.3V129H0z"/><path fill="#ffb900" d="M67.7 67.7H129V129H67.7z"/></svg>

After

Width:  |  Height:  |  Size: 258 B

View File

@@ -0,0 +1,47 @@
class EditorToolbox {
constructor(elem) {
// Elements
this.elem = elem;
this.buttons = elem.querySelectorAll('[toolbox-tab-button]');
this.contentElements = elem.querySelectorAll('[toolbox-tab-content]');
this.toggleButton = elem.querySelector('[toolbox-toggle]');
// Toolbox toggle button click
this.toggleButton.addEventListener('click', this.toggle.bind(this));
// Tab button click
this.elem.addEventListener('click', event => {
let button = event.target.closest('[toolbox-tab-button]');
if (button === null) return;
let name = button.getAttribute('toolbox-tab-button');
this.setActiveTab(name, true);
});
// Set the first tab as active on load
this.setActiveTab(this.contentElements[0].getAttribute('toolbox-tab-content'));
}
toggle() {
this.elem.classList.toggle('open');
}
setActiveTab(tabName, openToolbox = false) {
// Set button visibility
for (let i = 0, len = this.buttons.length; i < len; i++) {
this.buttons[i].classList.remove('active');
let bName = this.buttons[i].getAttribute('toolbox-tab-button');
if (bName === tabName) this.buttons[i].classList.add('active');
}
// Set content visibility
for (let i = 0, len = this.contentElements.length; i < len; i++) {
this.contentElements[i].style.display = 'none';
let cName = this.contentElements[i].getAttribute('toolbox-tab-content');
if (cName === tabName) this.contentElements[i].style.display = 'block';
}
if (openToolbox) this.elem.classList.add('open');
}
}
module.exports = EditorToolbox;

View File

@@ -11,6 +11,9 @@ let componentMapping = {
'sidebar': require('./sidebar'),
'page-picker': require('./page-picker'),
'page-comments': require('./page-comments'),
'wysiwyg-editor': require('./wysiwyg-editor'),
'markdown-editor': require('./markdown-editor'),
'editor-toolbox': require('./editor-toolbox'),
};
window.components = {};

View File

@@ -0,0 +1,293 @@
const MarkdownIt = require("markdown-it");
const mdTasksLists = require('markdown-it-task-lists');
const code = require('../code');
class MarkdownEditor {
constructor(elem) {
this.elem = elem;
this.markdown = new MarkdownIt({html: true});
this.markdown.use(mdTasksLists, {label: true});
this.display = this.elem.querySelector('.markdown-display');
this.input = this.elem.querySelector('textarea');
this.htmlInput = this.elem.querySelector('input[name=html]');
this.cm = code.markdownEditor(this.input);
this.onMarkdownScroll = this.onMarkdownScroll.bind(this);
this.init();
}
init() {
// Prevent markdown display link click redirect
this.display.addEventListener('click', event => {
let link = event.target.closest('a');
if (link === null) return;
event.preventDefault();
window.open(link.getAttribute('href'));
});
// Button actions
this.elem.addEventListener('click', event => {
let button = event.target.closest('button[data-action]');
if (button === null) return;
let action = button.getAttribute('data-action');
if (action === 'insertImage') this.actionInsertImage();
if (action === 'insertLink') this.actionShowLinkSelector();
});
window.$events.listen('editor-markdown-update', value => {
this.cm.setValue(value);
this.updateAndRender();
});
this.codeMirrorSetup();
}
// Update the input content and render the display.
updateAndRender() {
let content = this.cm.getValue();
this.input.value = content;
let html = this.markdown.render(content);
window.$events.emit('editor-html-change', html);
window.$events.emit('editor-markdown-change', content);
this.display.innerHTML = html;
this.htmlInput.value = html;
}
onMarkdownScroll(lineCount) {
let elems = this.display.children;
if (elems.length <= lineCount) return;
let topElem = (lineCount === -1) ? elems[elems.length-1] : elems[lineCount];
// TODO - Replace jQuery
$(this.display).animate({
scrollTop: topElem.offsetTop
}, {queue: false, duration: 200, easing: 'linear'});
}
codeMirrorSetup() {
let cm = this.cm;
// Custom key commands
let metaKey = code.getMetaKey();
const extraKeys = {};
// Insert Image shortcut
extraKeys[`${metaKey}-Alt-I`] = function(cm) {
let selectedText = cm.getSelection();
let newText = `![${selectedText}](http://)`;
let cursorPos = cm.getCursor('from');
cm.replaceSelection(newText);
cm.setCursor(cursorPos.line, cursorPos.ch + newText.length -1);
};
// Save draft
extraKeys[`${metaKey}-S`] = cm => {window.$events.emit('editor-save-draft')};
// Show link selector
extraKeys[`Shift-${metaKey}-K`] = cm => {this.actionShowLinkSelector()};
// Insert Link
extraKeys[`${metaKey}-K`] = cm => {insertLink()};
// FormatShortcuts
extraKeys[`${metaKey}-1`] = cm => {replaceLineStart('##');};
extraKeys[`${metaKey}-2`] = cm => {replaceLineStart('###');};
extraKeys[`${metaKey}-3`] = cm => {replaceLineStart('####');};
extraKeys[`${metaKey}-4`] = cm => {replaceLineStart('#####');};
extraKeys[`${metaKey}-5`] = cm => {replaceLineStart('');};
extraKeys[`${metaKey}-d`] = cm => {replaceLineStart('');};
extraKeys[`${metaKey}-6`] = cm => {replaceLineStart('>');};
extraKeys[`${metaKey}-q`] = cm => {replaceLineStart('>');};
extraKeys[`${metaKey}-7`] = cm => {wrapSelection('\n```\n', '\n```');};
extraKeys[`${metaKey}-8`] = cm => {wrapSelection('`', '`');};
extraKeys[`Shift-${metaKey}-E`] = cm => {wrapSelection('`', '`');};
extraKeys[`${metaKey}-9`] = cm => {wrapSelection('<p class="callout info">', '</p>');};
cm.setOption('extraKeys', extraKeys);
// Update data on content change
cm.on('change', (instance, changeObj) => {
this.updateAndRender();
});
// Handle scroll to sync display view
cm.on('scroll', instance => {
// Thanks to http://liuhao.im/english/2015/11/10/the-sync-scroll-of-markdown-editor-in-javascript.html
let scroll = instance.getScrollInfo();
let atEnd = scroll.top + scroll.clientHeight === scroll.height;
if (atEnd) {
this.onMarkdownScroll(-1);
return;
}
let lineNum = instance.lineAtHeight(scroll.top, 'local');
let range = instance.getRange({line: 0, ch: null}, {line: lineNum, ch: null});
let parser = new DOMParser();
let doc = parser.parseFromString(this.markdown.render(range), 'text/html');
let totalLines = doc.documentElement.querySelectorAll('body > *');
this.onMarkdownScroll(totalLines.length);
});
// Handle image paste
cm.on('paste', (cm, event) => {
if (!event.clipboardData || !event.clipboardData.items) return;
for (let i = 0; i < event.clipboardData.items.length; i++) {
uploadImage(event.clipboardData.items[i].getAsFile());
}
});
// Handle images on drag-drop
cm.on('drop', (cm, event) => {
event.stopPropagation();
event.preventDefault();
let cursorPos = cm.coordsChar({left: event.pageX, top: event.pageY});
cm.setCursor(cursorPos);
if (!event.dataTransfer || !event.dataTransfer.files) return;
for (let i = 0; i < event.dataTransfer.files.length; i++) {
uploadImage(event.dataTransfer.files[i]);
}
});
// Helper to replace editor content
function replaceContent(search, replace) {
let text = cm.getValue();
let cursor = cm.listSelections();
cm.setValue(text.replace(search, replace));
cm.setSelections(cursor);
}
// Helper to replace the start of the line
function replaceLineStart(newStart) {
let cursor = cm.getCursor();
let lineContent = cm.getLine(cursor.line);
let lineLen = lineContent.length;
let lineStart = lineContent.split(' ')[0];
// Remove symbol if already set
if (lineStart === newStart) {
lineContent = lineContent.replace(`${newStart} `, '');
cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
cm.setCursor({line: cursor.line, ch: cursor.ch - (newStart.length + 1)});
return;
}
let alreadySymbol = /^[#>`]/.test(lineStart);
let posDif = 0;
if (alreadySymbol) {
posDif = newStart.length - lineStart.length;
lineContent = lineContent.replace(lineStart, newStart).trim();
} else if (newStart !== '') {
posDif = newStart.length + 1;
lineContent = newStart + ' ' + lineContent;
}
cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
cm.setCursor({line: cursor.line, ch: cursor.ch + posDif});
}
function wrapLine(start, end) {
let cursor = cm.getCursor();
let lineContent = cm.getLine(cursor.line);
let lineLen = lineContent.length;
let newLineContent = lineContent;
if (lineContent.indexOf(start) === 0 && lineContent.slice(-end.length) === end) {
newLineContent = lineContent.slice(start.length, lineContent.length - end.length);
} else {
newLineContent = `${start}${lineContent}${end}`;
}
cm.replaceRange(newLineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
cm.setCursor({line: cursor.line, ch: cursor.ch + start.length});
}
function wrapSelection(start, end) {
let selection = cm.getSelection();
if (selection === '') return wrapLine(start, end);
let newSelection = selection;
let frontDiff = 0;
let endDiff = 0;
if (selection.indexOf(start) === 0 && selection.slice(-end.length) === end) {
newSelection = selection.slice(start.length, selection.length - end.length);
endDiff = -(end.length + start.length);
} else {
newSelection = `${start}${selection}${end}`;
endDiff = start.length + end.length;
}
let selections = cm.listSelections()[0];
cm.replaceSelection(newSelection);
let headFirst = selections.head.ch <= selections.anchor.ch;
selections.head.ch += headFirst ? frontDiff : endDiff;
selections.anchor.ch += headFirst ? endDiff : frontDiff;
cm.setSelections([selections]);
}
// Handle image upload and add image into markdown content
function uploadImage(file) {
if (file === null || file.type.indexOf('image') !== 0) return;
let ext = 'png';
if (file.name) {
let fileNameMatches = file.name.match(/\.(.+)$/);
if (fileNameMatches.length > 1) ext = fileNameMatches[1];
}
// Insert image into markdown
let id = "image-" + Math.random().toString(16).slice(2);
let placeholderImage = window.baseUrl(`/loading.gif#upload${id}`);
let selectedText = cm.getSelection();
let placeHolderText = `![${selectedText}](${placeholderImage})`;
cm.replaceSelection(placeHolderText);
let remoteFilename = "image-" + Date.now() + "." + ext;
let formData = new FormData();
formData.append('file', file, remoteFilename);
window.$http.post('/images/gallery/upload', formData).then(resp => {
replaceContent(placeholderImage, resp.data.thumbs.display);
}).catch(err => {
events.emit('error', trans('errors.image_upload_error'));
replaceContent(placeHolderText, selectedText);
console.log(err);
});
}
function insertLink() {
let cursorPos = cm.getCursor('from');
let selectedText = cm.getSelection() || '';
let newText = `[${selectedText}]()`;
cm.focus();
cm.replaceSelection(newText);
let cursorPosDiff = (selectedText === '') ? -3 : -1;
cm.setCursor(cursorPos.line, cursorPos.ch + newText.length+cursorPosDiff);
}
this.updateAndRender();
}
actionInsertImage() {
let cursorPos = this.cm.getCursor('from');
window.ImageManager.show(image => {
let selectedText = this.cm.getSelection();
let newText = "![" + (selectedText || image.name) + "](" + image.thumbs.display + ")";
this.cm.focus();
this.cm.replaceSelection(newText);
this.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length);
});
}
// Show the popup link selector and insert a link when finished
actionShowLinkSelector() {
let cursorPos = this.cm.getCursor('from');
window.EntitySelectorPopup.show(entity => {
let selectedText = this.cm.getSelection() || entity.name;
let newText = `[${selectedText}](${entity.link})`;
this.cm.focus();
this.cm.replaceSelection(newText);
this.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length);
});
}
}
module.exports = MarkdownEditor ;

View File

@@ -0,0 +1,11 @@
class WysiwygEditor {
constructor(elem) {
this.elem = elem;
this.options = require("../pages/page-form");
tinymce.init(this.options);
}
}
module.exports = WysiwygEditor;

View File

@@ -1,147 +0,0 @@
"use strict";
const moment = require('moment');
require('moment/locale/en-gb');
const editorOptions = require("./pages/page-form");
moment.locale('en-gb');
module.exports = function (ngApp, events) {
ngApp.controller('PageEditController', ['$scope', '$http', '$attrs', '$interval', '$timeout', '$sce',
function ($scope, $http, $attrs, $interval, $timeout, $sce) {
$scope.editorOptions = editorOptions();
$scope.editContent = '';
$scope.draftText = '';
let pageId = Number($attrs.pageId);
let isEdit = pageId !== 0;
let autosaveFrequency = 30; // AutoSave interval in seconds.
let isMarkdown = $attrs.editorType === 'markdown';
$scope.draftsEnabled = $attrs.draftsEnabled === 'true';
$scope.isUpdateDraft = Number($attrs.pageUpdateDraft) === 1;
$scope.isNewPageDraft = Number($attrs.pageNewDraft) === 1;
// Set initial header draft text
if ($scope.isUpdateDraft || $scope.isNewPageDraft) {
$scope.draftText = trans('entities.pages_editing_draft');
} else {
$scope.draftText = trans('entities.pages_editing_page');
}
let autoSave = false;
let currentContent = {
title: false,
html: false
};
if (isEdit && $scope.draftsEnabled) {
setTimeout(() => {
startAutoSave();
}, 1000);
}
// Actions specifically for the markdown editor
if (isMarkdown) {
$scope.displayContent = '';
// Editor change event
$scope.editorChange = function (content) {
$scope.displayContent = $sce.trustAsHtml(content);
}
}
if (!isMarkdown) {
$scope.editorChange = function() {};
}
let lastSave = 0;
/**
* Start the AutoSave loop, Checks for content change
* before performing the costly AJAX request.
*/
function startAutoSave() {
currentContent.title = $('#name').val();
currentContent.html = $scope.editContent;
autoSave = $interval(() => {
// Return if manually saved recently to prevent bombarding the server
if (Date.now() - lastSave < (1000*autosaveFrequency)/2) return;
let newTitle = $('#name').val();
let newHtml = $scope.editContent;
if (newTitle !== currentContent.title || newHtml !== currentContent.html) {
currentContent.html = newHtml;
currentContent.title = newTitle;
saveDraft();
}
}, 1000 * autosaveFrequency);
}
let draftErroring = false;
/**
* Save a draft update into the system via an AJAX request.
*/
function saveDraft() {
if (!$scope.draftsEnabled) return;
let data = {
name: $('#name').val(),
html: isMarkdown ? $sce.getTrustedHtml($scope.displayContent) : $scope.editContent
};
if (isMarkdown) data.markdown = $scope.editContent;
let url = window.baseUrl('/ajax/page/' + pageId + '/save-draft');
$http.put(url, data).then(responseData => {
draftErroring = false;
let updateTime = moment.utc(moment.unix(responseData.data.timestamp)).toDate();
$scope.draftText = responseData.data.message + moment(updateTime).format('HH:mm');
if (!$scope.isNewPageDraft) $scope.isUpdateDraft = true;
showDraftSaveNotification();
lastSave = Date.now();
}, errorRes => {
if (draftErroring) return;
events.emit('error', trans('errors.page_draft_autosave_fail'));
draftErroring = true;
});
}
function showDraftSaveNotification() {
$scope.draftUpdated = true;
$timeout(() => {
$scope.draftUpdated = false;
}, 2000)
}
$scope.forceDraftSave = function() {
saveDraft();
};
// Listen to save draft events from editor
$scope.$on('save-draft', saveDraft);
/**
* Discard the current draft and grab the current page
* content from the system via an AJAX request.
*/
$scope.discardDraft = function () {
let url = window.baseUrl('/ajax/page/' + pageId);
$http.get(url).then(responseData => {
if (autoSave) $interval.cancel(autoSave);
$scope.draftText = trans('entities.pages_editing_page');
$scope.isUpdateDraft = false;
$scope.$broadcast('html-update', responseData.data.html);
$scope.$broadcast('markdown-update', responseData.data.markdown || responseData.data.html);
$('#name').val(responseData.data.name);
$timeout(() => {
startAutoSave();
}, 1000);
events.emit('success', trans('entities.pages_draft_discarded'));
});
};
}]);
};

View File

@@ -1,393 +0,0 @@
"use strict";
const MarkdownIt = require("markdown-it");
const mdTasksLists = require('markdown-it-task-lists');
const code = require('./code');
module.exports = function (ngApp, events) {
/**
* TinyMCE
* An angular wrapper around the tinyMCE editor.
*/
ngApp.directive('tinymce', ['$timeout', function ($timeout) {
return {
restrict: 'A',
scope: {
tinymce: '=',
mceModel: '=',
mceChange: '='
},
link: function (scope, element, attrs) {
function tinyMceSetup(editor) {
editor.on('ExecCommand change input NodeChange ObjectResized', (e) => {
let content = editor.getContent();
$timeout(() => {
scope.mceModel = content;
});
scope.mceChange(content);
});
editor.on('keydown', (event) => {
if (event.keyCode === 83 && (navigator.platform.match("Mac") ? event.metaKey : event.ctrlKey)) {
event.preventDefault();
scope.$emit('save-draft', event);
}
});
editor.on('init', (e) => {
scope.mceModel = editor.getContent();
});
scope.$on('html-update', (event, value) => {
editor.setContent(value);
editor.selection.select(editor.getBody(), true);
editor.selection.collapse(false);
scope.mceModel = editor.getContent();
});
}
scope.tinymce.extraSetups.push(tinyMceSetup);
tinymce.init(scope.tinymce);
}
}
}]);
const md = new MarkdownIt({html: true});
md.use(mdTasksLists, {label: true});
/**
* Markdown input
* Handles the logic for just the editor input field.
*/
ngApp.directive('markdownInput', ['$timeout', function ($timeout) {
return {
restrict: 'A',
scope: {
mdModel: '=',
mdChange: '='
},
link: function (scope, element, attrs) {
// Codemirror Setup
element = element.find('textarea').first();
let cm = code.markdownEditor(element[0]);
// Custom key commands
let metaKey = code.getMetaKey();
const extraKeys = {};
// Insert Image shortcut
extraKeys[`${metaKey}-Alt-I`] = function(cm) {
let selectedText = cm.getSelection();
let newText = `![${selectedText}](http://)`;
let cursorPos = cm.getCursor('from');
cm.replaceSelection(newText);
cm.setCursor(cursorPos.line, cursorPos.ch + newText.length -1);
};
// Save draft
extraKeys[`${metaKey}-S`] = function(cm) {scope.$emit('save-draft');};
// Show link selector
extraKeys[`Shift-${metaKey}-K`] = function(cm) {showLinkSelector()};
// Insert Link
extraKeys[`${metaKey}-K`] = function(cm) {insertLink()};
// FormatShortcuts
extraKeys[`${metaKey}-1`] = function(cm) {replaceLineStart('##');};
extraKeys[`${metaKey}-2`] = function(cm) {replaceLineStart('###');};
extraKeys[`${metaKey}-3`] = function(cm) {replaceLineStart('####');};
extraKeys[`${metaKey}-4`] = function(cm) {replaceLineStart('#####');};
extraKeys[`${metaKey}-5`] = function(cm) {replaceLineStart('');};
extraKeys[`${metaKey}-d`] = function(cm) {replaceLineStart('');};
extraKeys[`${metaKey}-6`] = function(cm) {replaceLineStart('>');};
extraKeys[`${metaKey}-q`] = function(cm) {replaceLineStart('>');};
extraKeys[`${metaKey}-7`] = function(cm) {wrapSelection('\n```\n', '\n```');};
extraKeys[`${metaKey}-8`] = function(cm) {wrapSelection('`', '`');};
extraKeys[`Shift-${metaKey}-E`] = function(cm) {wrapSelection('`', '`');};
extraKeys[`${metaKey}-9`] = function(cm) {wrapSelection('<p class="callout info">', '</p>');};
cm.setOption('extraKeys', extraKeys);
// Update data on content change
cm.on('change', (instance, changeObj) => {
update(instance);
});
// Handle scroll to sync display view
cm.on('scroll', instance => {
// Thanks to http://liuhao.im/english/2015/11/10/the-sync-scroll-of-markdown-editor-in-javascript.html
let scroll = instance.getScrollInfo();
let atEnd = scroll.top + scroll.clientHeight === scroll.height;
if (atEnd) {
scope.$emit('markdown-scroll', -1);
return;
}
let lineNum = instance.lineAtHeight(scroll.top, 'local');
let range = instance.getRange({line: 0, ch: null}, {line: lineNum, ch: null});
let parser = new DOMParser();
let doc = parser.parseFromString(md.render(range), 'text/html');
let totalLines = doc.documentElement.querySelectorAll('body > *');
scope.$emit('markdown-scroll', totalLines.length);
});
// Handle image paste
cm.on('paste', (cm, event) => {
if (!event.clipboardData || !event.clipboardData.items) return;
for (let i = 0; i < event.clipboardData.items.length; i++) {
uploadImage(event.clipboardData.items[i].getAsFile());
}
});
// Handle images on drag-drop
cm.on('drop', (cm, event) => {
event.stopPropagation();
event.preventDefault();
let cursorPos = cm.coordsChar({left: event.pageX, top: event.pageY});
cm.setCursor(cursorPos);
if (!event.dataTransfer || !event.dataTransfer.files) return;
for (let i = 0; i < event.dataTransfer.files.length; i++) {
uploadImage(event.dataTransfer.files[i]);
}
});
// Helper to replace editor content
function replaceContent(search, replace) {
let text = cm.getValue();
let cursor = cm.listSelections();
cm.setValue(text.replace(search, replace));
cm.setSelections(cursor);
}
// Helper to replace the start of the line
function replaceLineStart(newStart) {
let cursor = cm.getCursor();
let lineContent = cm.getLine(cursor.line);
let lineLen = lineContent.length;
let lineStart = lineContent.split(' ')[0];
// Remove symbol if already set
if (lineStart === newStart) {
lineContent = lineContent.replace(`${newStart} `, '');
cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
cm.setCursor({line: cursor.line, ch: cursor.ch - (newStart.length + 1)});
return;
}
let alreadySymbol = /^[#>`]/.test(lineStart);
let posDif = 0;
if (alreadySymbol) {
posDif = newStart.length - lineStart.length;
lineContent = lineContent.replace(lineStart, newStart).trim();
} else if (newStart !== '') {
posDif = newStart.length + 1;
lineContent = newStart + ' ' + lineContent;
}
cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
cm.setCursor({line: cursor.line, ch: cursor.ch + posDif});
}
function wrapLine(start, end) {
let cursor = cm.getCursor();
let lineContent = cm.getLine(cursor.line);
let lineLen = lineContent.length;
let newLineContent = lineContent;
if (lineContent.indexOf(start) === 0 && lineContent.slice(-end.length) === end) {
newLineContent = lineContent.slice(start.length, lineContent.length - end.length);
} else {
newLineContent = `${start}${lineContent}${end}`;
}
cm.replaceRange(newLineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
cm.setCursor({line: cursor.line, ch: cursor.ch + start.length});
}
function wrapSelection(start, end) {
let selection = cm.getSelection();
if (selection === '') return wrapLine(start, end);
let newSelection = selection;
let frontDiff = 0;
let endDiff = 0;
if (selection.indexOf(start) === 0 && selection.slice(-end.length) === end) {
newSelection = selection.slice(start.length, selection.length - end.length);
endDiff = -(end.length + start.length);
} else {
newSelection = `${start}${selection}${end}`;
endDiff = start.length + end.length;
}
let selections = cm.listSelections()[0];
cm.replaceSelection(newSelection);
let headFirst = selections.head.ch <= selections.anchor.ch;
selections.head.ch += headFirst ? frontDiff : endDiff;
selections.anchor.ch += headFirst ? endDiff : frontDiff;
cm.setSelections([selections]);
}
// Handle image upload and add image into markdown content
function uploadImage(file) {
if (file === null || file.type.indexOf('image') !== 0) return;
let ext = 'png';
if (file.name) {
let fileNameMatches = file.name.match(/\.(.+)$/);
if (fileNameMatches.length > 1) ext = fileNameMatches[1];
}
// Insert image into markdown
let id = "image-" + Math.random().toString(16).slice(2);
let placeholderImage = window.baseUrl(`/loading.gif#upload${id}`);
let selectedText = cm.getSelection();
let placeHolderText = `![${selectedText}](${placeholderImage})`;
cm.replaceSelection(placeHolderText);
let remoteFilename = "image-" + Date.now() + "." + ext;
let formData = new FormData();
formData.append('file', file, remoteFilename);
window.$http.post('/images/gallery/upload', formData).then(resp => {
replaceContent(placeholderImage, resp.data.thumbs.display);
}).catch(err => {
events.emit('error', trans('errors.image_upload_error'));
replaceContent(placeHolderText, selectedText);
console.log(err);
});
}
// Show the popup link selector and insert a link when finished
function showLinkSelector() {
let cursorPos = cm.getCursor('from');
window.EntitySelectorPopup.show(entity => {
let selectedText = cm.getSelection() || entity.name;
let newText = `[${selectedText}](${entity.link})`;
cm.focus();
cm.replaceSelection(newText);
cm.setCursor(cursorPos.line, cursorPos.ch + newText.length);
});
}
function insertLink() {
let cursorPos = cm.getCursor('from');
let selectedText = cm.getSelection() || '';
let newText = `[${selectedText}]()`;
cm.focus();
cm.replaceSelection(newText);
let cursorPosDiff = (selectedText === '') ? -3 : -1;
cm.setCursor(cursorPos.line, cursorPos.ch + newText.length+cursorPosDiff);
}
// Show the image manager and handle image insertion
function showImageManager() {
let cursorPos = cm.getCursor('from');
window.ImageManager.show(image => {
let selectedText = cm.getSelection();
let newText = "![" + (selectedText || image.name) + "](" + image.thumbs.display + ")";
cm.focus();
cm.replaceSelection(newText);
cm.setCursor(cursorPos.line, cursorPos.ch + newText.length);
});
}
// Update the data models and rendered output
function update(instance) {
let content = instance.getValue();
element.val(content);
$timeout(() => {
scope.mdModel = content;
scope.mdChange(md.render(content));
});
}
update(cm);
// Listen to commands from parent scope
scope.$on('md-insert-link', showLinkSelector);
scope.$on('md-insert-image', showImageManager);
scope.$on('markdown-update', (event, value) => {
cm.setValue(value);
element.val(value);
scope.mdModel = value;
scope.mdChange(md.render(value));
});
}
}
}]);
/**
* Markdown Editor
* Handles all functionality of the markdown editor.
*/
ngApp.directive('markdownEditor', ['$timeout', '$rootScope', function ($timeout, $rootScope) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
// Editor Elements
const $display = element.find('.markdown-display').first();
const $insertImage = element.find('button[data-action="insertImage"]');
const $insertEntityLink = element.find('button[data-action="insertEntityLink"]');
// Prevent markdown display link click redirect
$display.on('click', 'a', function(event) {
event.preventDefault();
window.open(this.getAttribute('href'));
});
// Editor UI Actions
$insertEntityLink.click(e => {scope.$broadcast('md-insert-link');});
$insertImage.click(e => {scope.$broadcast('md-insert-image');});
// Handle scroll sync event from editor scroll
$rootScope.$on('markdown-scroll', (event, lineCount) => {
let elems = $display[0].children[0].children;
if (elems.length > lineCount) {
let topElem = (lineCount === -1) ? elems[elems.length-1] : elems[lineCount];
$display.animate({
scrollTop: topElem.offsetTop
}, {queue: false, duration: 200, easing: 'linear'});
}
});
}
}
}]);
/**
* Page Editor Toolbox
* Controls all functionality for the sliding toolbox
* on the page edit view.
*/
ngApp.directive('toolbox', [function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
// Get common elements
const $buttons = elem.find('[toolbox-tab-button]');
const $content = elem.find('[toolbox-tab-content]');
const $toggle = elem.find('[toolbox-toggle]');
// Handle toolbox toggle click
$toggle.click((e) => {
elem.toggleClass('open');
});
// Set an active tab/content by name
function setActive(tabName, openToolbox) {
$buttons.removeClass('active');
$content.hide();
$buttons.filter(`[toolbox-tab-button="${tabName}"]`).addClass('active');
$content.filter(`[toolbox-tab-content="${tabName}"]`).show();
if (openToolbox) elem.addClass('open');
}
// Set the first tab content active on load
setActive($content.first().attr('toolbox-tab-content'), false);
// Handle tab button click
$buttons.click(function (e) {
let name = $(this).attr('toolbox-tab-button');
setActive(name, true);
});
}
}
}]);
};

View File

@@ -58,16 +58,6 @@ window.$http = axiosInstance;
Vue.prototype.$http = axiosInstance;
Vue.prototype.$events = window.$events;
// AngularJS - Create application and load components
const angular = require("angular");
require("angular-resource");
require("angular-animate");
require("angular-sanitize");
require("angular-ui-sortable");
let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']);
// Translation setup
// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system
const Translations = require("./translations");
@@ -79,11 +69,6 @@ window.trans_choice = translator.getPlural.bind(translator);
require("./vues/vues");
require("./components");
// Load in angular specific items
const Directives = require('./directives');
const Controllers = require('./controllers');
Directives(ngApp, window.$events);
Controllers(ngApp, window.$events);
//Global jQuery Config & Extensions

View File

@@ -1,54 +1,55 @@
"use strict";
const Code = require('../code');
/**
* Handle pasting images from clipboard.
* @param e - event
* @param editor - editor instance
* @param {ClipboardEvent} event
* @param editor
*/
function editorPaste(e, editor) {
if (!e.clipboardData) return;
let items = e.clipboardData.items;
if (!items) return;
function editorPaste(event, editor) {
if (!event.clipboardData || !event.clipboardData.items) return;
let items = event.clipboardData.items;
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") === -1) return;
let file = items[i].getAsFile();
let formData = new FormData();
let ext = 'png';
let xhr = new XMLHttpRequest();
if (file.name) {
let fileNameMatches = file.name.match(/\.(.+)$/);
if (fileNameMatches) {
ext = fileNameMatches[1];
}
}
if (items[i].type.indexOf("image") === -1) continue;
event.preventDefault();
let id = "image-" + Math.random().toString(16).slice(2);
let loadingImage = window.baseUrl('/loading.gif');
editor.execCommand('mceInsertContent', false, `<img src="${loadingImage}" id="${id}">`);
let remoteFilename = "image-" + Date.now() + "." + ext;
formData.append('file', file, remoteFilename);
formData.append('_token', document.querySelector('meta[name="token"]').getAttribute('content'));
xhr.open('POST', window.baseUrl('/images/gallery/upload'));
xhr.onload = function () {
if (xhr.status === 200 || xhr.status === 201) {
let result = JSON.parse(xhr.responseText);
editor.dom.setAttrib(id, 'src', result.thumbs.display);
} else {
console.log('An error occurred uploading the image', xhr.responseText);
let file = items[i].getAsFile();
setTimeout(() => {
editor.insertContent(`<p><img src="${loadingImage}" id="${id}"></p>`);
uploadImageFile(file).then(resp => {
editor.dom.setAttrib(id, 'src', resp.thumbs.display);
}).catch(err => {
editor.dom.remove(id);
}
};
xhr.send(formData);
window.$events.emit('error', trans('errors.image_upload_error'));
console.log(err);
});
}, 10);
}
}
/**
* Upload an image file to the server
* @param {File} file
*/
function uploadImageFile(file) {
if (file === null || file.type.indexOf('image') !== 0) return Promise.reject(`Not an image file`);
let ext = 'png';
if (file.name) {
let fileNameMatches = file.name.match(/\.(.+)$/);
if (fileNameMatches.length > 1) ext = fileNameMatches[1];
}
let remoteFilename = "image-" + Date.now() + "." + ext;
let formData = new FormData();
formData.append('file', file, remoteFilename);
return window.$http.post('/images/gallery/upload', formData).then(resp => (resp.data));
}
function registerEditorShortcuts(editor) {
// Headers
for (let i = 1; i < 5; i++) {
@@ -64,6 +65,12 @@ function registerEditorShortcuts(editor) {
editor.shortcuts.add('meta+e', '', ['codeeditor', false, 'pre']);
editor.shortcuts.add('meta+8', '', ['FormatBlock', false, 'code']);
editor.shortcuts.add('meta+shift+E', '', ['FormatBlock', false, 'code']);
// Save draft shortcut
editor.shortcuts.add('meta+S', '', () => {
window.$events.emit('editor-save-draft');
});
// Loop through callout styles
editor.shortcuts.add('meta+9', '', function() {
let selectedNode = editor.selection.getNode();
@@ -82,6 +89,7 @@ function registerEditorShortcuts(editor) {
}
editor.formatter.apply('p');
});
}
@@ -194,191 +202,192 @@ function codePlugin() {
});
}
codePlugin();
function hrPlugin() {
window.tinymce.PluginManager.add('customhr', function (editor) {
editor.addCommand('InsertHorizontalRule', function () {
let hrElem = document.createElement('hr');
let cNode = editor.selection.getNode();
let parentNode = cNode.parentNode;
parentNode.insertBefore(hrElem, cNode);
});
editor.addButton('hr', {
icon: 'hr',
tooltip: 'Horizontal line',
cmd: 'InsertHorizontalRule'
});
editor.addMenuItem('hr', {
icon: 'hr',
text: 'Horizontal line',
cmd: 'InsertHorizontalRule',
context: 'insert'
});
window.tinymce.PluginManager.add('customhr', function (editor) {
editor.addCommand('InsertHorizontalRule', function () {
let hrElem = document.createElement('hr');
let cNode = editor.selection.getNode();
let parentNode = cNode.parentNode;
parentNode.insertBefore(hrElem, cNode);
});
}
module.exports = function() {
hrPlugin();
codePlugin();
let settings = {
selector: '#html-editor',
content_css: [
window.baseUrl('/css/styles.css'),
window.baseUrl('/libs/material-design-iconic-font/css/material-design-iconic-font.min.css')
],
branding: false,
body_class: 'page-content',
browser_spellcheck: true,
relative_urls: false,
remove_script_host: false,
document_base_url: window.baseUrl('/'),
statusbar: false,
menubar: false,
paste_data_images: false,
extended_valid_elements: 'pre[*]',
automatic_uploads: false,
valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote],+div[pre]",
plugins: "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor",
imagetools_toolbar: 'imageoptions',
toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr | removeformat code fullscreen",
content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
style_formats: [
{title: "Header Large", format: "h2"},
{title: "Header Medium", format: "h3"},
{title: "Header Small", format: "h4"},
{title: "Header Tiny", format: "h5"},
{title: "Paragraph", format: "p", exact: true, classes: ''},
{title: "Blockquote", format: "blockquote"},
{title: "Code Block", icon: "code", cmd: 'codeeditor', format: 'codeeditor'},
{title: "Inline Code", icon: "code", inline: "code"},
{title: "Callouts", items: [
{title: "Info", format: 'calloutinfo'},
{title: "Success", format: 'calloutsuccess'},
{title: "Warning", format: 'calloutwarning'},
{title: "Danger", format: 'calloutdanger'}
]},
],
style_formats_merge: false,
formats: {
codeeditor: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div'},
alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
calloutsuccess: {block: 'p', exact: true, attributes: {class: 'callout success'}},
calloutinfo: {block: 'p', exact: true, attributes: {class: 'callout info'}},
calloutwarning: {block: 'p', exact: true, attributes: {class: 'callout warning'}},
calloutdanger: {block: 'p', exact: true, attributes: {class: 'callout danger'}}
},
file_browser_callback: function (field_name, url, type, win) {
editor.addButton('hr', {
icon: 'hr',
tooltip: 'Horizontal line',
cmd: 'InsertHorizontalRule'
});
if (type === 'file') {
window.EntitySelectorPopup.show(function(entity) {
let originalField = win.document.getElementById(field_name);
originalField.value = entity.link;
$(originalField).closest('.mce-form').find('input').eq(2).val(entity.name);
editor.addMenuItem('hr', {
icon: 'hr',
text: 'Horizontal line',
cmd: 'InsertHorizontalRule',
context: 'insert'
});
});
module.exports = {
selector: '#html-editor',
content_css: [
window.baseUrl('/css/styles.css'),
window.baseUrl('/libs/material-design-iconic-font/css/material-design-iconic-font.min.css')
],
branding: false,
body_class: 'page-content',
browser_spellcheck: true,
relative_urls: false,
remove_script_host: false,
document_base_url: window.baseUrl('/'),
statusbar: false,
menubar: false,
paste_data_images: false,
extended_valid_elements: 'pre[*]',
automatic_uploads: false,
valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote],+div[pre]",
plugins: "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor",
imagetools_toolbar: 'imageoptions',
toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr | removeformat code fullscreen",
content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
style_formats: [
{title: "Header Large", format: "h2"},
{title: "Header Medium", format: "h3"},
{title: "Header Small", format: "h4"},
{title: "Header Tiny", format: "h5"},
{title: "Paragraph", format: "p", exact: true, classes: ''},
{title: "Blockquote", format: "blockquote"},
{title: "Code Block", icon: "code", cmd: 'codeeditor', format: 'codeeditor'},
{title: "Inline Code", icon: "code", inline: "code"},
{title: "Callouts", items: [
{title: "Info", format: 'calloutinfo'},
{title: "Success", format: 'calloutsuccess'},
{title: "Warning", format: 'calloutwarning'},
{title: "Danger", format: 'calloutdanger'}
]},
],
style_formats_merge: false,
formats: {
codeeditor: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div'},
alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
calloutsuccess: {block: 'p', exact: true, attributes: {class: 'callout success'}},
calloutinfo: {block: 'p', exact: true, attributes: {class: 'callout info'}},
calloutwarning: {block: 'p', exact: true, attributes: {class: 'callout warning'}},
calloutdanger: {block: 'p', exact: true, attributes: {class: 'callout danger'}}
},
file_browser_callback: function (field_name, url, type, win) {
if (type === 'file') {
window.EntitySelectorPopup.show(function(entity) {
let originalField = win.document.getElementById(field_name);
originalField.value = entity.link;
$(originalField).closest('.mce-form').find('input').eq(2).val(entity.name);
});
}
if (type === 'image') {
// Show image manager
window.ImageManager.show(function (image) {
// Set popover link input to image url then fire change event
// to ensure the new value sticks
win.document.getElementById(field_name).value = image.url;
if ("createEvent" in document) {
let evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
win.document.getElementById(field_name).dispatchEvent(evt);
} else {
win.document.getElementById(field_name).fireEvent("onchange");
}
// Replace the actively selected content with the linked image
let html = `<a href="${image.url}" target="_blank">`;
html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
html += '</a>';
win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html);
});
}
},
paste_preprocess: function (plugin, args) {
let content = args.content;
if (content.indexOf('<img src="file://') !== -1) {
args.content = '';
}
},
setup: function (editor) {
editor.on('init ExecCommand change input NodeChange ObjectResized', editorChange);
function editorChange() {
let content = editor.getContent();
window.$events.emit('editor-html-change', content);
}
window.$events.listen('editor-html-update', html => {
editor.setContent(html);
editor.selection.select(editor.getBody(), true);
editor.selection.collapse(false);
editorChange(html);
});
registerEditorShortcuts(editor);
let wrap;
function hasTextContent(node) {
return node && !!( node.textContent || node.innerText );
}
editor.on('dragstart', function () {
let node = editor.selection.getNode();
if (node.nodeName !== 'IMG') return;
wrap = editor.dom.getParent(node, '.mceTemp');
if (!wrap && node.parentNode.nodeName === 'A' && !hasTextContent(node.parentNode)) {
wrap = node.parentNode;
}
});
editor.on('drop', function (event) {
let dom = editor.dom,
rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint(event.clientX, event.clientY, editor.getDoc());
// Don't allow anything to be dropped in a captioned image.
if (dom.getParent(rng.startContainer, '.mceTemp')) {
event.preventDefault();
} else if (wrap) {
event.preventDefault();
editor.undoManager.transact(function () {
editor.selection.setRng(rng);
editor.selection.setNode(wrap);
dom.remove(wrap);
});
}
if (type === 'image') {
// Show image manager
wrap = null;
});
// Custom Image picker button
editor.addButton('image-insert', {
title: 'My title',
icon: 'image',
tooltip: 'Insert an image',
onclick: function () {
window.ImageManager.show(function (image) {
// Set popover link input to image url then fire change event
// to ensure the new value sticks
win.document.getElementById(field_name).value = image.url;
if ("createEvent" in document) {
let evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
win.document.getElementById(field_name).dispatchEvent(evt);
} else {
win.document.getElementById(field_name).fireEvent("onchange");
}
// Replace the actively selected content with the linked image
let html = `<a href="${image.url}" target="_blank">`;
html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
html += '</a>';
win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html);
editor.execCommand('mceInsertContent', false, html);
});
}
});
},
paste_preprocess: function (plugin, args) {
let content = args.content;
if (content.indexOf('<img src="file://') !== -1) {
args.content = '';
}
},
extraSetups: [],
setup: function (editor) {
// Run additional setup actions
// Used by the angular side of things
for (let i = 0; i < settings.extraSetups.length; i++) {
settings.extraSetups[i](editor);
}
registerEditorShortcuts(editor);
let wrap;
function hasTextContent(node) {
return node && !!( node.textContent || node.innerText );
}
editor.on('dragstart', function () {
let node = editor.selection.getNode();
if (node.nodeName !== 'IMG') return;
wrap = editor.dom.getParent(node, '.mceTemp');
if (!wrap && node.parentNode.nodeName === 'A' && !hasTextContent(node.parentNode)) {
wrap = node.parentNode;
}
});
editor.on('drop', function (event) {
let dom = editor.dom,
rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint(event.clientX, event.clientY, editor.getDoc());
// Don't allow anything to be dropped in a captioned image.
if (dom.getParent(rng.startContainer, '.mceTemp')) {
event.preventDefault();
} else if (wrap) {
event.preventDefault();
editor.undoManager.transact(function () {
editor.selection.setRng(rng);
editor.selection.setNode(wrap);
dom.remove(wrap);
});
}
wrap = null;
});
// Custom Image picker button
editor.addButton('image-insert', {
title: 'My title',
icon: 'image',
tooltip: 'Insert an image',
onclick: function () {
window.ImageManager.show(function (image) {
let html = `<a href="${image.url}" target="_blank">`;
html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
html += '</a>';
editor.execCommand('mceInsertContent', false, html);
});
}
});
// Paste image-uploads
editor.on('paste', function(event) {
editorPaste(event, editor);
});
}
};
return settings;
// Paste image-uploads
editor.on('paste', event => { editorPaste(event, editor) });
}
};

View File

@@ -0,0 +1,149 @@
const moment = require('moment');
require('moment/locale/en-gb');
moment.locale('en-gb');
let autoSaveFrequency = 30;
let autoSave = false;
let draftErroring = false;
let currentContent = {
title: false,
html: false
};
let lastSave = 0;
function mounted() {
let elem = this.$el;
this.draftsEnabled = elem.getAttribute('drafts-enabled') === 'true';
this.editorType = elem.getAttribute('editor-type');
this.pageId= Number(elem.getAttribute('page-id'));
this.isNewDraft = Number(elem.getAttribute('page-new-draft')) === 1;
this.isUpdateDraft = Number(elem.getAttribute('page-update-draft')) === 1;
if (this.pageId !== 0 && this.draftsEnabled) {
window.setTimeout(() => {
this.startAutoSave();
}, 1000);
}
if (this.isUpdateDraft || this.isNewDraft) {
this.draftText = trans('entities.pages_editing_draft');
} else {
this.draftText = trans('entities.pages_editing_page');
}
// Listen to save draft events from editor
window.$events.listen('editor-save-draft', this.saveDraft);
// Listen to content changes from the editor
window.$events.listen('editor-html-change', html => {
this.editorHTML = html;
});
window.$events.listen('editor-markdown-change', markdown => {
this.editorMarkdown = markdown;
});
}
let data = {
draftsEnabled: false,
editorType: 'wysiwyg',
pagedId: 0,
isNewDraft: false,
isUpdateDraft: false,
draftText: '',
draftUpdated : false,
changeSummary: '',
editorHTML: '',
editorMarkdown: '',
};
let methods = {
startAutoSave() {
currentContent.title = document.getElementById('name').value.trim();
currentContent.html = this.editorHTML;
autoSave = window.setInterval(() => {
// Return if manually saved recently to prevent bombarding the server
if (Date.now() - lastSave < (1000 * autoSaveFrequency)/2) return;
let newTitle = document.getElementById('name').value.trim();
let newHtml = this.editorHTML;
if (newTitle !== currentContent.title || newHtml !== currentContent.html) {
currentContent.html = newHtml;
currentContent.title = newTitle;
this.saveDraft();
}
}, 1000 * autoSaveFrequency);
},
saveDraft() {
if (!this.draftsEnabled) return;
let data = {
name: document.getElementById('name').value.trim(),
html: this.editorHTML
};
if (this.editorType === 'markdown') data.markdown = this.editorMarkdown;
let url = window.baseUrl(`/ajax/page/${this.pageId}/save-draft`);
window.$http.put(url, data).then(response => {
draftErroring = false;
let updateTime = moment.utc(moment.unix(response.data.timestamp)).toDate();
if (!this.isNewDraft) this.isUpdateDraft = true;
this.draftNotifyChange(response.data.message + moment(updateTime).format('HH:mm'));
lastSave = Date.now();
}, errorRes => {
if (draftErroring) return;
window.$events('error', trans('errors.page_draft_autosave_fail'));
draftErroring = true;
});
},
draftNotifyChange(text) {
this.draftText = text;
this.draftUpdated = true;
window.setTimeout(() => {
this.draftUpdated = false;
}, 2000);
},
discardDraft() {
let url = window.baseUrl(`/ajax/page/${this.pageId}`);
window.$http.get(url).then(response => {
if (autoSave) window.clearInterval(autoSave);
this.draftText = trans('entities.pages_editing_page');
this.isUpdateDraft = false;
window.$events.emit('editor-html-update', response.data.html);
window.$events.emit('editor-markdown-update', response.data.markdown || response.data.html);
document.getElementById('name').value = response.data.name;
window.setTimeout(() => {
this.startAutoSave();
}, 1000);
window.$events.emit('success', trans('entities.pages_draft_discarded'));
});
},
};
let computed = {
changeSummaryShort() {
let len = this.changeSummary.length;
if (len === 0) return trans('entities.pages_edit_set_changelog');
if (len <= 16) return this.changeSummary;
return this.changeSummary.slice(0, 16) + '...';
}
};
module.exports = {
mounted, data, methods, computed,
};

View File

@@ -11,6 +11,7 @@ let vueMapping = {
'image-manager': require('./image-manager'),
'tag-manager': require('./tag-manager'),
'attachment-manager': require('./attachment-manager'),
'page-editor': require('./page-editor'),
};
window.vues = {};

View File

@@ -195,10 +195,13 @@
font-weight: 400;
text-transform: uppercase;
}
h3 a {
line-height: 1;
}
.body, p.empty-text {
padding: $-m;
}
a {
a, p {
word-wrap: break-word;
word-break: break-word;
}

View File

@@ -370,6 +370,7 @@ span.CodeMirror-selectedtext { background: none; }
.cm-s-base16-light span.cm-keyword { color: #ac4142; }
.cm-s-base16-light span.cm-string { color: #e09c3c; }
.cm-s-base16-light span.cm-builtin { color: #4c7f9e; }
.cm-s-base16-light span.cm-variable { color: #90a959; }
.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }
.cm-s-base16-light span.cm-def { color: #d28445; }

View File

@@ -120,13 +120,15 @@ return [
'en' => 'English',
'de' => 'Deutsch',
'es' => 'Español',
'es_AR' => 'Español Argentina',
'fr' => 'Français',
'nl' => 'Nederlands',
'pt_BR' => 'Português do Brasil',
'sk' => 'Slovensky',
'ja' => '日本語',
'pl' => 'Polski',
'it' => 'Italian'
'it' => 'Italian',
'ru' => 'Русский'
]
///////////////////////////////////
];

View File

@@ -0,0 +1,42 @@
<?php
return [
/**
* Activity text strings.
* Is used for all the text within activity logs & notifications.
*/
// Pages
'page_create' => 'página creada',
'page_create_notification' => 'Página creada exitosamente',
'page_update' => 'página actualizada',
'page_update_notification' => 'Página actualizada exitosamente',
'page_delete' => 'página borrada',
'page_delete_notification' => 'Página borrada exitosamente',
'page_restore' => 'página restaurada',
'page_restore_notification' => 'Página restaurada exitosamente',
'page_move' => 'página movida',
// Chapters
'chapter_create' => 'capítulo creado',
'chapter_create_notification' => 'Capítulo creado exitosamente',
'chapter_update' => 'capítulo actualizado',
'chapter_update_notification' => 'Capítulo actualizado exitosamente',
'chapter_delete' => 'capítulo borrado',
'chapter_delete_notification' => 'Capítulo borrado exitosamente',
'chapter_move' => 'capítulo movido',
// Books
'book_create' => 'libro creado',
'book_create_notification' => 'Libro creado exitosamente',
'book_update' => 'libro actualizado',
'book_update_notification' => 'Libro actualizado exitosamente',
'book_delete' => 'libro borrado',
'book_delete_notification' => 'Libro borrado exitosamente',
'book_sort' => 'libro ordenado',
'book_sort_notification' => 'Libro reordenado exitosamente',
// Other
'commented_on' => 'comentado',
];

View File

@@ -0,0 +1,76 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'Las credenciales no concuerdan con nuestros registros.',
'throttle' => 'Demasiados intentos fallidos de conexión. Por favor intente nuevamente en :seconds segundos.',
/**
* Login & Register
*/
'sign_up' => 'Registrarse',
'log_in' => 'Acceder',
'log_in_with' => 'Acceder con :socialDriver',
'sign_up_with' => 'Registrarse con :socialDriver',
'logout' => 'Logout',
'name' => 'Nombre',
'username' => 'Nombre de usuario',
'email' => 'Correo electrónico',
'password' => 'Contraseña',
'password_confirm' => 'Confirmar contraseña',
'password_hint' => 'Debe contener al menos 5 caracteres',
'forgot_password' => '¿Olvidó la contraseña?',
'remember_me' => 'Recordarme',
'ldap_email_hint' => 'Por favor introduzca un correo electrónico para utilizar con esta cuenta.',
'create_account' => 'Crear una cuenta',
'social_login' => 'Acceso con cuenta Social',
'social_registration' => 'Registro con cuenta Social',
'social_registration_text' => 'Registrar y entrar utilizando otro servicio.',
'register_thanks' => '¡Gracias por registrarse!',
'register_confirm' => 'Por favor verifique su correo electrónico y presione en el botón de confirmación enviado para acceder a :appName.',
'registrations_disabled' => 'Los registros están deshabilitados actualmente',
'registration_email_domain_invalid' => 'Este dominio de correo electrónico no tiene acceso a esta aplicación',
'register_success' => '¡Gracias por registrarse! Ahora se encuentra registrado y ha accedido a la aplicación.',
/**
* Password Reset
*/
'reset_password' => 'Restablecer la contraseña',
'reset_password_send_instructions' => 'Introduzca su correo electrónico a continuación y se le enviará un correo electrónico con un enlace para la restauración',
'reset_password_send_button' => 'Enviar enlace de restauración',
'reset_password_sent_success' => 'Se envió un enlace para restablecer la contraseña a :email.',
'reset_password_success' => 'Su contraseña se restableció con éxito.',
'email_reset_subject' => 'Restauración de la contraseña de para la aplicación :appName',
'email_reset_text' => 'Ud. esta recibiendo este correo electrónico debido a que recibimos una solicitud de restauración de la contraseña de su cuenta.',
'email_reset_not_requested' => 'Si ud. no solicitó un cambio de contraseña, no se requiere ninguna acción.',
/**
* Email Confirmation
*/
'email_confirm_subject' => 'Confirme su correo electrónico en :appName',
'email_confirm_greeting' => '¡Gracias por unirse a :appName!',
'email_confirm_text' => 'Por favor confirme su dirección de correo electrónico presionando en el siguiente botón:',
'email_confirm_action' => 'Confirmar correo electrónico',
'email_confirm_send_error' => 'Se pidió confirmación de correo electrónico pero el sistema no pudo enviar el correo electrónico. Contacte al administrador para asegurarse que el correo electrónico está configurado correctamente.',
'email_confirm_success' => '¡Su correo electrónico hasido confirmado!',
'email_confirm_resent' => 'Correo electrónico de confirmación reenviado, Por favor verifique su bandeja de entrada.',
'email_not_confirmed' => 'Dirección de correo electrónico no confirmada',
'email_not_confirmed_text' => 'Su cuenta de correo electrónico todavía no ha sido confirmada.',
'email_not_confirmed_click_link' => 'Por favor verifique el correo electrónico con el enlace de confirmación que fue enviado luego de registrarse.',
'email_not_confirmed_resend' => 'Si no puede encontrar el correo electrónico, puede solicitar el renvío del correo electrónico de confirmación rellenando el formulario a continuación.',
'email_not_confirmed_resend_button' => 'Reenviar correo electrónico de confirmación',
];

View File

@@ -0,0 +1,61 @@
<?php
return [
/**
* Buttons
*/
'cancel' => 'Cancelar',
'confirm' => 'Confirmar',
'back' => 'Atrás',
'save' => 'Guardar',
'continue' => 'Continuar',
'select' => 'Seleccionar',
'more' => 'Más',
/**
* Form Labels
*/
'name' => 'Nombre',
'description' => 'Descripción',
'role' => 'Rol',
/**
* Actions
*/
'actions' => 'Acciones',
'view' => 'Ver',
'create' => 'Crear',
'update' => 'Actualizar',
'edit' => 'Editar',
'sort' => 'Ordenar',
'move' => 'Mover',
'reply' => 'Responder',
'delete' => 'Borrar',
'search' => 'Buscar',
'search_clear' => 'Limpiar búsqueda',
'reset' => 'Restablecer',
'remove' => 'Remover',
'add' => 'Agregar',
/**
* Misc
*/
'deleted_user' => 'Usuario borrado',
'no_activity' => 'Ninguna actividad para mostrar',
'no_items' => 'No hay items disponibles',
'back_to_top' => 'Volver arriba',
'toggle_details' => 'Alternar detalles',
'details' => 'Detalles',
/**
* Header
*/
'view_profile' => 'Ver Perfil',
'edit_profile' => 'Editar Perfil',
/**
* Email Content
*/
'email_action_help' => 'Si está teniendo problemas haga click en el botón ":actionText", copie y pegue la siguiente URL en su navegador web:',
'email_rights' => 'Todos los derechos reservados',
];

View File

@@ -0,0 +1,32 @@
<?php
return [
/**
* Image Manager
*/
'image_select' => 'Seleccionar Imagen',
'image_all' => 'Todo',
'image_all_title' => 'Ver todas las imágenes',
'image_book_title' => 'Ver las imágenes subidas a este libro',
'image_page_title' => 'Ver las imágenes subidas a esta página',
'image_search_hint' => 'Buscar por nombre de imagen',
'image_uploaded' => 'Subido el :uploadedDate',
'image_load_more' => 'Cargar más',
'image_image_name' => 'Nombre de imagen',
'image_delete_confirm' => 'Esta imagen esta siendo utilizada en las páginas a continuación, haga click de nuevo para confirmar que quiere borrar esta imagen.',
'image_select_image' => 'Seleccionar Imagen',
'image_dropzone' => 'Arrastre las imágenes o hacer click aquí para Subir',
'images_deleted' => 'Imágenes borradas',
'image_preview' => 'Preview de la imagen',
'image_upload_success' => 'Imagen subida éxitosamente',
'image_update_success' => 'Detalles de la imagen actualizados exitosamente',
'image_delete_success' => 'Imagen borrada exitosamente',
/**
* Code editor
*/
'code_editor' => 'Editar Código',
'code_language' => 'Lenguaje del Código',
'code_content' => 'Contenido del Código',
'code_save' => 'Guardar Código',
];

View File

@@ -0,0 +1,260 @@
<?php
return [
/**
* Shared
*/
'recently_created' => 'Recientemente creado',
'recently_created_pages' => 'Páginas recientemente creadas',
'recently_updated_pages' => 'Páginas recientemente actualizadas',
'recently_created_chapters' => 'Capítulos recientemente creados',
'recently_created_books' => 'Libros recientemente creados',
'recently_update' => 'Recientemente actualizado',
'recently_viewed' => 'Recientemente visto',
'recent_activity' => 'Actividad reciente',
'create_now' => 'Crear uno ahora',
'revisions' => 'Revisiones',
'meta_created' => 'Creado el :timeLength',
'meta_created_name' => 'Creado el :timeLength por :user',
'meta_updated' => 'Actualizado el :timeLength',
'meta_updated_name' => 'Actualizado el :timeLength por :user',
'x_pages' => ':count Páginas',
'entity_select' => 'Seleccione entidad',
'images' => 'Imágenes',
'my_recent_drafts' => 'Mis borradores recientes',
'my_recently_viewed' => 'Mis visualizaciones recientes',
'no_pages_viewed' => 'Ud. no ha visto ninguna página',
'no_pages_recently_created' => 'Ninguna página ha sido creada recientemente',
'no_pages_recently_updated' => 'Ninguna página ha sido actualizada recientemente',
'export' => 'Export',
'export_html' => 'Contained Web File',
'export_pdf' => 'PDF File',
'export_text' => 'Plain Text File',
/**
* Permissions and restrictions
*/
'permissions' => 'Permisos',
'permissions_intro' => 'una vez habilitado, Estos permisos tendrán prioridad por encima de cualquier permiso establecido.',
'permissions_enable' => 'Habilitar permisos custom',
'permissions_save' => 'Guardar permisos',
/**
* Search
*/
'search_results' => 'Buscar resultados',
'search_total_results_found' => ':count resultados encontrados|:count total de resultados encontrados',
'search_clear' => 'Limpiar resultados',
'search_no_pages' => 'Ninguna página encontrada para la búsqueda',
'search_for_term' => 'Busqueda por :term',
'search_more' => 'Más resultados',
'search_filters' => 'Filtros de búsqueda',
'search_content_type' => 'Tipo de contenido',
'search_exact_matches' => 'Coincidencias exactas',
'search_tags' => 'Búsquedas de etiquetas',
'search_viewed_by_me' => 'Vistos por mí',
'search_not_viewed_by_me' => 'No vistos por mí',
'search_permissions_set' => 'Permisos establecidos',
'search_created_by_me' => 'Creado por mí',
'search_updated_by_me' => 'Actualizado por mí',
'search_updated_before' => 'Actualizado antes de',
'search_updated_after' => 'Actualizado después de',
'search_created_before' => 'Creado antes de',
'search_created_after' => 'Creado después de',
'search_set_date' => 'Esablecer fecha',
'search_update' => 'Actualizar búsqueda',
/**
* Books
*/
'book' => 'Libro',
'books' => 'Libros',
'x_books' => ':count Libro|:count Libros',
'books_empty' => 'No hay libros creados',
'books_popular' => 'Libros populares',
'books_recent' => 'Libros recientes',
'books_new' => 'Libros nuevos',
'books_popular_empty' => 'Los libros más populares aparecerán aquí.',
'books_new_empty' => 'Los libros creados más recientemente aparecerán aquí.',
'books_create' => 'Crear nuevo libro',
'books_delete' => 'Borrar libro',
'books_delete_named' => 'Borrar libro :bookName',
'books_delete_explain' => 'Esto borrará el libro con el nombre \':bookName\', Todas las páginas y capítulos serán removidos.',
'books_delete_confirmation' => '¿Está seguro de que desea borrar este libro?',
'books_edit' => 'Editar Libro',
'books_edit_named' => 'Editar Libro :bookName',
'books_form_book_name' => 'Nombre de libro',
'books_save' => 'Guardar libro',
'books_permissions' => 'permisos de libro',
'books_permissions_updated' => 'Permisos de libro actualizados',
'books_empty_contents' => 'Ninguna página o capítulo ha sido creada para este libro.',
'books_empty_create_page' => 'Crear una nueva página',
'books_empty_or' => 'ó',
'books_empty_sort_current_book' => 'Organizar el libro actual',
'books_empty_add_chapter' => 'Agregar un capítulo',
'books_permissions_active' => 'Permisos de libro activados',
'books_search_this' => 'Buscar en este libro',
'books_navigation' => 'Navegación de libro',
'books_sort' => 'Organizar contenido de libro',
'books_sort_named' => 'Organizar libro :bookName',
'books_sort_show_other' => 'Mostrar otros libros',
'books_sort_save' => 'Guardar nuevo orden',
/**
* Chapters
*/
'chapter' => 'Capítulo',
'chapters' => 'Capítulos',
'x_chapters' => ':count Capítulo|:count Capítulos',
'chapters_popular' => 'Capítulos populares',
'chapters_new' => 'Nuevo capítulo',
'chapters_create' => 'Crear nuevo capítulo',
'chapters_delete' => 'Borrar capítulo',
'chapters_delete_named' => 'Borrar capítulo :chapterName',
'chapters_delete_explain' => 'Esto borrará el capítulo con el nombre \':chapterName\', todas las páginas serán removidas y agregadas directamente al libro padre.',
'chapters_delete_confirm' => '¿Está seguro de borrar este capítulo?',
'chapters_edit' => 'Editar capítulo',
'chapters_edit_named' => 'Editar capítulo :chapterName',
'chapters_save' => 'Guardar capítulo',
'chapters_move' => 'Mover capítulo',
'chapters_move_named' => 'Mover Capítulo :chapterName',
'chapter_move_success' => 'Capítulo movido a :bookName',
'chapters_permissions' => 'Permisos de capítulo',
'chapters_empty' => 'No existen páginas en este capítulo.',
'chapters_permissions_active' => 'Permisos de capítulo activado',
'chapters_permissions_success' => 'Permisos de capítulo actualizados',
'chapters_search_this' => 'Buscar en este capítulo',
/**
* Pages
*/
'page' => 'Página',
'pages' => 'Páginas',
'x_pages' => ':count Página|:count Páginas',
'pages_popular' => 'Páginas populares',
'pages_new' => 'Nueva página',
'pages_attachments' => 'Adjuntos',
'pages_navigation' => 'Navegación de página',
'pages_delete' => 'Borrar página',
'pages_delete_named' => 'Borrar página :pageName',
'pages_delete_draft_named' => 'Borrar borrador de página :pageName',
'pages_delete_draft' => 'Borrar borrador de página',
'pages_delete_success' => 'Página borrada',
'pages_delete_draft_success' => 'Borrador de página borrado',
'pages_delete_confirm' => '¿Está seguro de borrar esta página?',
'pages_delete_draft_confirm' => 'Está seguro de que desea borrar este borrador de página?',
'pages_editing_named' => 'Editando página :pageName',
'pages_edit_toggle_header' => 'Alternar cabecera',
'pages_edit_save_draft' => 'Guardar borrador',
'pages_edit_draft' => 'Editar borrador de página',
'pages_editing_draft' => 'Editando borrador',
'pages_editing_page' => 'Editando página',
'pages_edit_draft_save_at' => 'Borrador guardado el ',
'pages_edit_delete_draft' => 'Borrar borrador',
'pages_edit_discard_draft' => 'Descartar borrador',
'pages_edit_set_changelog' => 'Establecer cambios de registro',
'pages_edit_enter_changelog_desc' => 'Introduzca una breve descripción de los cambios que ha realizado',
'pages_edit_enter_changelog' => 'Entrar en cambio de registro',
'pages_save' => 'Guardar página',
'pages_title' => 'Título de página',
'pages_name' => 'Nombre de página',
'pages_md_editor' => 'Editor',
'pages_md_preview' => 'Previsualizar',
'pages_md_insert_image' => 'Insertar Imagen',
'pages_md_insert_link' => 'Insertar link de entidad',
'pages_not_in_chapter' => 'La página no esá en el capítulo',
'pages_move' => 'Mover página',
'pages_move_success' => 'Página movida a ":parentName"',
'pages_permissions' => 'Permisos de página',
'pages_permissions_success' => 'Permisos de página actualizados',
'pages_revision' => 'Revisión',
'pages_revisions' => 'Revisiones de página',
'pages_revisions_named' => 'Revisiones de página para :pageName',
'pages_revision_named' => 'Revisión de ágina para :pageName',
'pages_revisions_created_by' => 'Creado por',
'pages_revisions_date' => 'Fecha de revisión',
'pages_revisions_number' => '#',
'pages_revisions_changelog' => 'Registro de cambios',
'pages_revisions_changes' => 'Cambios',
'pages_revisions_current' => 'Versión actual',
'pages_revisions_preview' => 'Previsualizar',
'pages_revisions_restore' => 'Restaurar',
'pages_revisions_none' => 'Esta página no tiene revisiones',
'pages_copy_link' => 'Copiar enlace',
'pages_permissions_active' => 'Permisos de página activos',
'pages_initial_revision' => 'Publicación inicial',
'pages_initial_name' => 'Página nueva',
'pages_editing_draft_notification' => 'Usted está actualmente editando un borrador que fue guardado por última vez el :timeDiff.',
'pages_draft_edited_notification' => 'Esta página ha sido actualizada desde aquel momento. Se recomienda que cancele este borrador.',
'pages_draft_edit_active' => [
'start_a' => ':count usuarios han comenzado a editar esta página',
'start_b' => ':userName ha comenzado a editar esta página',
'time_a' => 'desde que las página fue actualizada',
'time_b' => 'en los últimos :minCount minutos',
'message' => ':start :time. Ten cuidado de no sobreescribir los cambios del otro usuario',
],
'pages_draft_discarded' => 'Borrador descartado, el editor ha sido actualizado con el contenido de la página actual',
/**
* Editor sidebar
*/
'page_tags' => 'Etiquetas de página',
'tag' => 'Etiqueta',
'tags' => 'Etiquetas',
'tag_value' => 'Valor de la etiqueta (Opcional)',
'tags_explain' => "Agregar algunas etiquetas para mejorar la categorización de su contenido. \n Se puede asignar un valor a una etiqueta para una organizacón con mayor detalle.",
'tags_add' => 'Agregar otra etiqueta',
'attachments' => 'Adjuntos',
'attachments_explain' => 'Subir archivos o agregar enlaces para mostrar en la página. Estos son visibles en la barra lateral de la página.',
'attachments_explain_instant_save' => 'Los cambios se guardan de manera instantánea.',
'attachments_items' => 'Elementos adjuntados',
'attachments_upload' => 'Archivo adjuntado',
'attachments_link' => 'Adjuntar enlace',
'attachments_set_link' => 'Establecer enlace',
'attachments_delete_confirm' => 'Presione en borrar nuevamente para confirmar que quiere borrar este elemento adjunto.',
'attachments_dropzone' => 'Arrastre archivos aquí o presione aquí para adjuntar un archivo',
'attachments_no_files' => 'No se adjuntó ningún archivo',
'attachments_explain_link' => 'Usted puede agregar un enlace o si lo prefiere puede agregar un archivo. Esto puede ser un enlace a otra página o un enlace a un archivo en la nube.',
'attachments_link_name' => 'Nombre del enlace',
'attachment_link' => 'Enlace adjunto',
'attachments_link_url' => 'Enlace a archivo',
'attachments_link_url_hint' => 'URL del sitio o archivo',
'attach' => 'Adjuntar',
'attachments_edit_file' => 'Editar archivo',
'attachments_edit_file_name' => 'Nombre del archivo',
'attachments_edit_drop_upload' => 'Arrastre los archivos o presione aquí para subir o sobreescribir',
'attachments_order_updated' => 'Orden de adjuntos actualizado',
'attachments_updated_success' => 'Detalles de adjuntos actualizados',
'attachments_deleted' => 'Adjunto borrado',
'attachments_file_uploaded' => 'Archivo subido exitosamente',
'attachments_file_updated' => 'Archivo actualizado exitosamente',
'attachments_link_attached' => 'Enlace agregado exitosamente a la página',
/**
* Profile View
*/
'profile_user_for_x' => 'Usuario para :time',
'profile_created_content' => 'Contenido creado',
'profile_not_created_pages' => ':userName no ha creado ninguna página',
'profile_not_created_chapters' => ':userName no ha creado ningún capítulo',
'profile_not_created_books' => ':userName no ha creado ningún libro',
/**
* Comments
*/
'comment' => 'Comentario',
'comments' => 'Comentarios',
'comment_placeholder' => 'DEjar un comentario aquí',
'comment_count' => '{0} Sin Comentarios|{1} 1 Comentario|[2,*] :count Comentarios',
'comment_save' => 'Guardar comentario',
'comment_saving' => 'Guardando comentario...',
'comment_deleting' => 'Borrando comentario...',
'comment_new' => 'Nuevo comentario',
'comment_created' => 'comentado :createDiff',
'comment_updated' => 'Actualizado :updateDiff por :username',
'comment_deleted_success' => 'Comentario borrado',
'comment_created_success' => 'Comentario agregado',
'comment_updated_success' => 'Comentario actualizado',
'comment_delete_confirm' => '¿Está seguro que quiere borrar este comentario?',
'comment_in_reply_to' => 'En respuesta a :commentId',
];

View File

@@ -0,0 +1,77 @@
<?php
return [
/**
* Error text strings.
*/
// Permissions
'permission' => 'Ud. no tiene permisos para visualizar la página solicitada.',
'permissionJson' => 'Ud. no tiene permisos para ejecutar la acción solicitada.',
// Auth
'error_user_exists_different_creds' => 'Un usuario con el email :email ya existe pero con credenciales diferentes.',
'email_already_confirmed' => 'El email ya ha sido confirmado, Intente loguearse en la aplicación.',
'email_confirmation_invalid' => 'Este token de confirmación no e válido o ya ha sido usado,Intente registrar uno nuevamente.',
'email_confirmation_expired' => 'El token de confirmación ha expirado, Un nuevo email de confirmacón ha sido enviado.',
'ldap_fail_anonymous' => 'El acceso con LDAP ha fallado usando binding anónimo',
'ldap_fail_authed' => 'El acceso LDAP usando el dn & password detallados',
'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada',
'ldap_cannot_connect' => 'No se puede conectar con el servidor ldap, la conexión inicial ha fallado',
'social_no_action_defined' => 'Acción no definida',
'social_account_in_use' => 'la cuenta :socialAccount ya se encuentra en uso, intente loguearse a través de la opcón :socialAccount .',
'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.',
'social_account_existing' => 'La cuenta :socialAccount ya se encuentra asignada a su perfil.',
'social_account_already_used_existing' => 'La cuenta :socialAccount ya se encuentra usada por otro usuario.',
'social_account_not_used' => 'La cuenta :socialAccount no está asociada a ningún usuario. Por favor adjuntela a su configuración de perfil. ',
'social_account_register_instructions' => 'Si no dispone de una cuenta, puede registrar una cuenta usando la opción de :socialAccount .',
'social_driver_not_found' => 'Driver social no encontrado',
'social_driver_not_configured' => 'Su configuración :socialAccount no es correcta.',
// System
'path_not_writable' => 'La ruta :filePath no pudo ser cargada. Asegurese de que es escribible por el servidor.',
'cannot_get_image_from_url' => 'No se puede obtener la imagen desde :url',
'cannot_create_thumbs' => 'El servidor no puede crear la imagen miniatura. Por favor chequee que tiene la extensión GD instalada.',
'server_upload_limit' => 'El servidor no permite la subida de ficheros de este tamañ. Por favor intente con un fichero de menor tamañ.',
'image_upload_error' => 'Ha ocurrido un error al subir la imagen',
// Attachments
'attachment_page_mismatch' => 'Página no coincidente durante la subida del adjunto ',
// Pages
'page_draft_autosave_fail' => 'Fallo al guardar borrador. Asegurese de que tiene conexión a Internet antes de guardar este borrador',
// Entities
'entity_not_found' => 'Entidad no encontrada',
'book_not_found' => 'Libro no encontrado',
'page_not_found' => 'Página no encontrada',
'chapter_not_found' => 'Capítulo no encontrado',
'selected_book_not_found' => 'El libro seleccionado no fue encontrado',
'selected_book_chapter_not_found' => 'El libro o capítulo seleccionado no fue encontrado',
'guests_cannot_save_drafts' => 'Los invitados no pueden guardar los borradores',
// Users
'users_cannot_delete_only_admin' => 'No se puede borrar el único administrador',
'users_cannot_delete_guest' => 'No se puede borrar el usuario invitado',
// Roles
'role_cannot_be_edited' => 'Este rol no puede ser editado',
'role_system_cannot_be_deleted' => 'Este rol es un rol de sistema y no puede ser borrado',
'role_registration_default_cannot_delete' => 'Este rol no puede ser borrado mientras sea el rol por defecto de registro',
// Comments
'comment_list' => 'Se produjo un error al obtener los comentarios.',
'cannot_add_comment_to_draft' => 'No puede gregar comentarios a un borrador.',
'comment_add' => 'Se produjo un error al agregar o actualizar el comentario.',
'comment_delete' => 'Se produjo un error al borrar el comentario.',
'empty_comment' => 'No se puede agregar un comentario vacío.',
// Error pages
'404_page_not_found' => 'Página no encontrada',
'sorry_page_not_found' => 'Lo sentimos, la página que intenta acceder no pudo ser encontrada.',
'return_home' => 'Volver al home',
'error_occurred' => 'Ha ocurrido un error',
'app_down' => 'La aplicación :appName se encuentra caída en este momento',
'back_soon' => 'Volverá a estar operativa en corto tiempo.',
];

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Anterior',
'next' => 'Siguiente &raquo;',
];

View File

@@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reminder Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'password' => 'La contraseña debe ser como mínimo de seis caracteres y coincidir con la confirmación.',
'user' => "No podemos encontrar un usuario con esta dirección de correo electrónico.",
'token' => 'Este token de restablecimiento de contraseña no es válido.',
'sent' => '¡Hemos enviado a su cuenta de correo electrónico un enlace para restaurar su contraseña!',
'reset' => '¡Su contraseña fue restaurada!',
];

View File

@@ -0,0 +1,115 @@
<?php
return [
/**
* Settings text strings
* Contains all text strings used in the general settings sections of BookStack
* including users and roles.
*/
'settings' => 'Ajustes',
'settings_save' => 'Guardar ajustes',
'settings_save_success' => 'Ajustes guardados',
/**
* App settings
*/
'app_settings' => 'Ajustes de Aplicación',
'app_name' => 'Nombre de aplicación',
'app_name_desc' => 'Este nombre se muestra en la cabecera y en cualquier correo electrónico de la aplicación',
'app_name_header' => '¿Mostrar el nombre de la aplicación en la cabecera?',
'app_public_viewing' => '¿Permitir vista pública?',
'app_secure_images' => '¿Habilitar mayor seguridad para subir imágenes?',
'app_secure_images_desc' => 'Por razones de rendimiento, todas las imágenes son públicas. Esta opción agrega una cadena larga difícil de adivinar, asegúrese que los índices de directorios no están habilitados para prevenir el acceso fácil a las imágenes.',
'app_editor' => 'Editor de página',
'app_editor_desc' => 'Seleccione cuál editor será usado por todos los usuarios para editar páginas.',
'app_custom_html' => 'Contenido de cabecera HTML personalizable',
'app_custom_html_desc' => 'Cualquier contenido agregado aquí será agregado al final de la sección <head> de cada página. Esto es útil para sobreescribir estilos o agregar código para analíticas.',
'app_logo' => 'Logo de la aplicación',
'app_logo_desc' => 'Esta imagen debería ser de 43px en altura. <br>Las imágenes grandes seán escaladas.',
'app_primary_color' => 'Color primario de la aplicación',
'app_primary_color_desc' => 'Esto debería ser un valor hexadecimal. <br>Deje el valor vacío para reiniciar al valor por defecto.',
'app_homepage' => 'Página de inicio de la Aplicación',
'app_homepage_desc' => 'Seleccione una página de inicio para mostrar en lugar de la vista por defecto. Se ignoran los permisos de página para las páginas seleccionadas.',
'app_homepage_default' => 'Página de inicio por defecto seleccionadad',
/**
* Registration settings
*/
'reg_settings' => 'Ajustes de registro',
'reg_allow' => '¿Permitir registro?',
'reg_default_role' => 'Rol de usuario por defecto despúes del registro',
'reg_confirm_email' => '¿Requerir correo electrónico de confirmación?',
'reg_confirm_email_desc' => 'Si se utiliza la restricción por dominio, entonces se requerirá la confirmación por correo electrónico y se ignorará el valor a continuación.',
'reg_confirm_restrict_domain' => 'Restringir registro al dominio',
'reg_confirm_restrict_domain_desc' => 'Introduzca una lista separada por comas de los correos electrónicos del dominio a los que les gustaría restringir el registro por dominio. A los usuarios les será enviado un correo elctrónico para confirmar la dirección antes de que se le permita interactuar con la aplicación. <br> Note que a los usuarios se les permitirá cambiar sus direcciones de correo electrónico luego de un registro éxioso.',
'reg_confirm_restrict_domain_placeholder' => 'Ninguna restricción establecida',
/**
* Role settings
*/
'roles' => 'Roles',
'role_user_roles' => 'Roles de usuario',
'role_create' => 'Crear nuevo rol',
'role_create_success' => 'Rol creado satisfactoriamente',
'role_delete' => 'Borrar rol',
'role_delete_confirm' => 'Se borrará el rol con nombre \':roleName\'.',
'role_delete_users_assigned' => 'Este rol tiene :userCount usuarios asignados. Si ud. quisiera migrar los usuarios de este rol, seleccione un nuevo rol a continuación.',
'role_delete_no_migration' => "No migrar usuarios",
'role_delete_sure' => '¿Está seguro que desea borrar este rol?',
'role_delete_success' => 'Rol borrado satisfactoriamente',
'role_edit' => 'Editar rol',
'role_details' => 'Detalles de rol',
'role_name' => 'Nombre de rol',
'role_desc' => 'Descripción corta de rol',
'role_system' => 'Permisos de sistema',
'role_manage_users' => 'Gestionar usuarios',
'role_manage_roles' => 'Gestionar roles y permisos de roles',
'role_manage_entity_permissions' => 'Gestionar todos los permisos de libros, capítulos y páginas',
'role_manage_own_entity_permissions' => 'Gestionar permisos en libros propios, capítulos y páginas',
'role_manage_settings' => 'Gestionar ajustes de activos',
'role_asset' => 'Permisos de activos',
'role_asset_desc' => 'Estos permisos controlan el acceso por defecto a los activos del sistema. Permisos a Libros, Capítulos y Páginas sobreescribiran estos permisos.',
'role_all' => 'Todo',
'role_own' => 'Propio',
'role_controlled_by_asset' => 'Controlado por el activo al que ha sido subido',
'role_save' => 'Guardar rol',
'role_update_success' => 'Rol actualizado exitosamente',
'role_users' => 'Usuarios en este rol',
'role_users_none' => 'No hay usuarios asignados a este rol',
/**
* Users
*/
'users' => 'Usuarios',
'user_profile' => 'Perfil de usuario',
'users_add_new' => 'Agregar nuevo usuario',
'users_search' => 'Buscar usuarios',
'users_role' => 'Roles de usuario',
'users_external_auth_id' => 'ID externo de autenticación',
'users_password_warning' => 'Solo rellene a continuación si desea cambiar su password:',
'users_system_public' => 'Este usuario representa cualquier usuario invitado que visita la aplicación. No puede utilizarse para hacer login sino que es asignado automáticamente.',
'users_delete' => 'Borrar usuario',
'users_delete_named' => 'Borrar usuario :userName',
'users_delete_warning' => 'Se borrará completamente el usuario con el nombre \':userName\' del sistema.',
'users_delete_confirm' => '¿Está seguro que desea borrar este usuario?',
'users_delete_success' => 'Usuarios removidos exitosamente',
'users_edit' => 'Editar Usuario',
'users_edit_profile' => 'Editar perfil',
'users_edit_success' => 'Usuario actualizado',
'users_avatar' => 'Avatar del usuario',
'users_avatar_desc' => 'Esta imagen debe ser de aproximadamente 256px por lado.',
'users_preferred_language' => 'Lenguaje preferido',
'users_social_accounts' => 'Cuentas sociales',
'users_social_accounts_info' => 'Aquí puede conectar sus otras cuentas para un acceso rápido y más fácil. Desconectando una cuenta aquí no revoca accesos ya autorizados. Revoque el acceso desde los ajustes de perfil en la cuenta social conectada.',
'users_social_connect' => 'Conectar cuenta',
'users_social_disconnect' => 'Desconectar cuenta',
'users_social_connected' => 'La cuenta :socialAccount ha sido exitosamente añadida a su perfil.',
'users_social_disconnected' => 'La cuenta :socialAccount ha sido desconectada exitosamente de su perfil.',
];

View File

@@ -0,0 +1,108 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'El :attribute debe ser aceptado.',
'active_url' => 'El :attribute no es una URl válida.',
'after' => 'El :attribute debe ser una fecha posterior :date.',
'alpha' => 'El :attribute solo puede contener letras.',
'alpha_dash' => 'El :attribute solo puede contener letras, números y guiones.',
'alpha_num' => 'El :attribute solo puede contener letras y número.',
'array' => 'El :attribute debe de ser un array.',
'before' => 'El :attribute debe ser una fecha anterior a :date.',
'between' => [
'numeric' => 'El :attribute debe estar entre :min y :max.',
'file' => 'El :attribute debe estar entre :min y :max kilobytes.',
'string' => 'El :attribute debe estar entre :min y :max carácteres.',
'array' => 'El :attribute debe estar entre :min y :max items.',
],
'boolean' => 'El campo :attribute debe ser true o false.',
'confirmed' => 'La confirmación de :attribute no concuerda.',
'date' => 'El :attribute no es una fecha válida.',
'date_format' => 'El :attribute no coincide con el formato :format.',
'different' => ':attribute y :other deben ser diferentes.',
'digits' => ':attribute debe ser de :digits dígitos.',
'digits_between' => ':attribute debe ser un valor entre :min y :max dígios.',
'email' => ':attribute debe ser una dirección álida.',
'filled' => 'El campo :attribute es requerido.',
'exists' => 'El :attribute seleccionado es inválido.',
'image' => 'El :attribute debe ser una imagen.',
'in' => 'El selected :attribute es inválio.',
'integer' => 'El :attribute debe ser un entero.',
'ip' => 'El :attribute debe ser una dirección IP álida.',
'max' => [
'numeric' => ':attribute no puede ser mayor que :max.',
'file' => ':attribute no puede ser mayor que :max kilobytes.',
'string' => ':attribute no puede ser mayor que :max carácteres.',
'array' => ':attribute no puede contener más de :max items.',
],
'mimes' => ':attribute debe ser un fichero de tipo: :values.',
'min' => [
'numeric' => ':attribute debe ser al menos de :min.',
'file' => ':attribute debe ser al menos :min kilobytes.',
'string' => ':attribute debe ser al menos :min caracteres.',
'array' => ':attribute debe tener como mínimo :min items.',
],
'not_in' => ':attribute seleccionado es inválio.',
'numeric' => ':attribute debe ser numérico.',
'regex' => ':attribute con formato inválido',
'required' => ':attribute es requerido.',
'required_if' => ':attribute es requerido cuando :other vale :value.',
'required_with' => 'El campo :attribute es requerido cuando se encuentre entre los valores :values.',
'required_with_all' => 'El campo :attribute es requerido cuando los valores sean :values.',
'required_without' => ':attribute es requerido cuando no se encuentre entre los valores :values.',
'required_without_all' => ':attribute es requerido cuando ninguno de los valores :values están presentes.',
'same' => ':attribute y :other deben coincidir.',
'size' => [
'numeric' => ':attribute debe ser :size.',
'file' => ':attribute debe ser :size kilobytes.',
'string' => ':attribute debe ser :size caracteres.',
'array' => ':attribute debe contener :size items.',
],
'string' => 'El atributo :attribute debe ser una cadena.',
'timezone' => 'El atributo :attribute debe ser una zona válida.',
'unique' => 'El atributo :attribute ya ha sido tomado.',
'url' => 'El atributo :attribute tiene un formato inválid.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'password-confirm' => [
'required_with' => 'Confirmación de Password requerida',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
'attributes' => [],
];

View File

@@ -37,4 +37,6 @@ return [
'book_sort' => 'ha ordinato il libro',
'book_sort_notification' => 'Libro Riordinato Correttamente',
// Other
'commented_on' => 'ha commentato in',
];

View File

@@ -29,6 +29,7 @@ return [
'edit' => 'Modifica',
'sort' => 'Ordina',
'move' => 'Muovi',
'reply' => 'Rispondi',
'delete' => 'Elimina',
'search' => 'Cerca',
'search_clear' => 'Pulisci Ricerca',

View File

@@ -19,7 +19,6 @@ return [
'meta_created_name' => 'Creato :timeLength da :user',
'meta_updated' => 'Aggiornato :timeLength',
'meta_updated_name' => 'Aggiornato :timeLength da :user',
'x_pages' => ':count Pagine',
'entity_select' => 'Selezione Entità',
'images' => 'Immagini',
'my_recent_drafts' => 'Bozze Recenti',
@@ -70,6 +69,7 @@ return [
*/
'book' => 'Libro',
'books' => 'Libri',
'x_books' => ':count Libro|:count Libri',
'books_empty' => 'Nessun libro è stato creato',
'books_popular' => 'Libri Popolari',
'books_recent' => 'Libri Recenti',
@@ -105,6 +105,7 @@ return [
*/
'chapter' => 'Capitolo',
'chapters' => 'Capitoli',
'x_chapters' => ':count Capitolo|:count Capitoli',
'chapters_popular' => 'Capitoli Popolari',
'chapters_new' => 'Nuovo Capitolo',
'chapters_create' => 'Crea un nuovo capitolo',
@@ -129,20 +130,21 @@ return [
*/
'page' => 'Pagina',
'pages' => 'Pagine',
'x_pages' => ':count Pagina|:count Pagine',
'pages_popular' => 'Pagine Popolari',
'pages_new' => 'Nuova Pagina',
'pages_attachments' => 'Allegati',
'pages_navigation' => 'Page Navigation',
'pages_navigation' => 'Navigazione Pagine',
'pages_delete' => 'Elimina Pagina',
'pages_delete_named' => 'Elimina la pagina :pageName',
'pages_delete_draft_named' => 'Delete Draft Page :pageName',
'pages_delete_draft_named' => 'Elimina bozza della pagina :pageName',
'pages_delete_draft' => 'Elimina Bozza Pagina',
'pages_delete_success' => 'Pagina eliminata',
'pages_delete_draft_success' => 'Bozza di una pagina eliminata',
'pages_delete_confirm' => 'Sei sicuro di voler eliminare questa pagina?',
'pages_delete_draft_confirm' => 'Sei sicuro di voler eliminare la bozza di questa pagina?',
'pages_editing_named' => 'Modifica :pageName',
'pages_edit_toggle_header' => 'Toggle header',
'pages_edit_toggle_header' => 'Mostra/Nascondi header',
'pages_edit_save_draft' => 'Salva Bozza',
'pages_edit_draft' => 'Modifica Bozza della pagina',
'pages_editing_draft' => 'Modifica Bozza',
@@ -164,7 +166,7 @@ return [
'pages_move' => 'Muovi Pagina',
'pages_move_success' => 'Pagina mossa in ":parentName"',
'pages_permissions' => 'Permessi Pagina',
'pages_permissions_success' => 'Page permissions updated',
'pages_permissions_success' => 'Permessi pagina aggiornati',
'pages_revision' => 'Versione',
'pages_revisions' => 'Versioni Pagina',
'pages_revisions_named' => 'Versioni della pagina :pageName',
@@ -242,10 +244,17 @@ return [
*/
'comment' => 'Commento',
'comments' => 'Commenti',
'comment_count' => '1 Commento|:count Commenti',
'comment_placeholder' => 'Scrivi un commento',
'comment_count' => '{0} Nessun Commento|{1} 1 Commento|[2,*] :count Commenti',
'comment_save' => 'Salva Commento',
'comment_saving' => 'Salvataggio commento...',
'comment_deleting' => 'Eliminazione commento...',
'comment_new' => 'Nuovo Commento',
'comment_created' => 'ha commentato :createDiff',
'comment_updated' => 'Aggiornato :updateDiff da :username',
'comment_deleted_success' => 'Commento eliminato',
'comment_created_success' => 'Commento aggiunto',
'comment_updated_success' => 'Commento aggiornato',
'comment_delete_confirm' => 'Questo rimuoverà il contenuto del commento?',
'comment_delete_confirm' => 'Sei sicuro di voler elminare questo commento?',
'comment_in_reply_to' => 'In risposta a :commentId',
];

View File

@@ -37,4 +37,6 @@ return [
'book_sort' => 'sorteerde boek',
'book_sort_notification' => 'Boek Succesvol Gesorteerd',
// Other
'commented_on' => 'reactie op',
];

View File

@@ -10,6 +10,7 @@ return [
'save' => 'Opslaan',
'continue' => 'Doorgaan',
'select' => 'Kies',
'more' => 'Meer',
/**
* Form Labels
@@ -33,7 +34,7 @@ return [
'search_clear' => 'Zoekopdracht wissen',
'reset' => 'Reset',
'remove' => 'Verwijderen',
'add' => 'Toevoegen',
/**
* Misc

View File

@@ -20,5 +20,12 @@ return [
'image_preview' => 'Afbeelding Voorbeeld',
'image_upload_success' => 'Afbeelding succesvol geüpload',
'image_update_success' => 'Afbeeldingsdetails succesvol verwijderd',
'image_delete_success' => 'Afbeelding succesvol verwijderd'
];
'image_delete_success' => 'Afbeelding succesvol verwijderd',
/**
* Code editor
*/
'code_editor' => 'Code invoegen',
'code_language' => 'Code taal',
'code_content' => 'Code',
'code_save' => 'Sla code op',
];

View File

@@ -14,6 +14,7 @@ return [
'recent_activity' => 'Recente Activiteit',
'create_now' => 'Maak er zelf één',
'revisions' => 'Revisies',
'meta_revision' => 'Revisie #:revisionCount',
'meta_created' => 'Aangemaakt :timeLength',
'meta_created_name' => 'Aangemaakt: :timeLength door :user',
'meta_updated' => ':timeLength Aangepast',
@@ -43,18 +44,37 @@ return [
* Search
*/
'search_results' => 'Zoekresultaten',
'search_total_results_found' => ':count resultaten gevonden|:count resultaten gevonden',
'search_clear' => 'Zoekopdracht wissen',
'search_no_pages' => 'Er zijn geen pagina\'s gevonden',
'search_for_term' => 'Zoeken op :term',
'search_more' => 'Meer resultaten',
'search_filters' => 'Zoek filters',
'search_content_type' => 'Content Type',
'search_exact_matches' => 'Exacte Matches',
'search_tags' => 'Zoek tags',
'search_viewed_by_me' => 'Bekeken door mij',
'search_not_viewed_by_me' => 'Niet bekeken door mij',
'search_permissions_set' => 'Permissies gezet',
'search_created_by_me' => 'Door mij gemaakt',
'search_updated_by_me' => 'Door mij geupdate',
'search_updated_before' => 'Geupdate voor',
'search_updated_after' => 'Geupdate na',
'search_created_before' => 'Gecreeerd voor',
'search_created_after' => 'Gecreeerd na',
'search_set_date' => 'Zet datum',
'search_update' => 'Update zoekresultaten',
/**
* Books
*/
'book' => 'Boek',
'books' => 'Boeken',
'x_books' => ':count Boek|:count Boeken',
'books_empty' => 'Er zijn geen boeken aangemaakt',
'books_popular' => 'Populaire Boeken',
'books_recent' => 'Recente Boeken',
'books_new' => 'Nieuwe Boeken',
'books_popular_empty' => 'De meest populaire boeken worden hier weergegeven.',
'books_create' => 'Nieuw Boek Aanmaken',
'books_delete' => 'Boek Verwijderen',
@@ -85,6 +105,7 @@ return [
*/
'chapter' => 'Hoofdstuk',
'chapters' => 'Hoofdstukken',
'x_chapters' => ':count Hoofdstuk|:count Hoofdstukken',
'chapters_popular' => 'Populaire Hoofdstukken',
'chapters_new' => 'Nieuw Hoofdstuk',
'chapters_create' => 'Hoofdstuk Toevoegen',
@@ -103,12 +124,14 @@ return [
'chapters_empty' => 'Er zijn geen pagina\'s in dit hoofdstuk aangemaakt.',
'chapters_permissions_active' => 'Hoofdstuk Permissies Actief',
'chapters_permissions_success' => 'Hoofdstuk Permissies Bijgewerkt',
'chapters_search_this' => 'Doorzoek dit hoofdstuk',
/**
* Pages
*/
'page' => 'Pagina',
'pages' => 'Pagina\'s',
'x_pages' => ':count Pagina|:count Pagina\'s',
'pages_popular' => 'Populaire Pagina\'s',
'pages_new' => 'Nieuwe Pagina',
'pages_attachments' => 'Bijlages',
@@ -122,7 +145,7 @@ return [
'pages_delete_confirm' => 'Weet je zeker dat je deze pagina wilt verwijderen?',
'pages_delete_draft_confirm' => 'Weet je zeker dat je dit concept wilt verwijderen?',
'pages_editing_named' => 'Pagina :pageName Bewerken',
'pages_edit_toggle_header' => 'Toggle header',
'pages_edit_toggle_header' => 'Wissel header',
'pages_edit_save_draft' => 'Concept opslaan',
'pages_edit_draft' => 'Paginaconcept Bewerken',
'pages_editing_draft' => 'Concept Bewerken',
@@ -132,12 +155,12 @@ return [
'pages_edit_discard_draft' => 'Concept Verwijderen',
'pages_edit_set_changelog' => 'Changelog',
'pages_edit_enter_changelog_desc' => 'Geef een korte omschrijving van de wijzingen die je gemaakt hebt.',
'pages_edit_enter_changelog' => 'Enter Changelog',
'pages_edit_enter_changelog' => 'Zie logboek',
'pages_save' => 'Pagina Opslaan',
'pages_title' => 'Pagina Titel',
'pages_name' => 'Pagina Naam',
'pages_md_editor' => 'Bewerker',
'pages_md_preview' => 'Preview',
'pages_md_preview' => 'Voorbeeld',
'pages_md_insert_image' => 'Afbeelding Invoegen',
'pages_md_insert_link' => 'Entity Link Invoegen',
'pages_not_in_chapter' => 'Deze pagina staat niet in een hoofdstuk',
@@ -145,11 +168,13 @@ return [
'pages_move_success' => 'Pagina verplaatst naar ":parentName"',
'pages_permissions' => 'Pagina Permissies',
'pages_permissions_success' => 'Pagina Permissies bijgwerkt',
'pages_revision' => 'Revisie',
'pages_revisions' => 'Pagina Revisies',
'pages_revisions_named' => 'Pagina Revisies voor :pageName',
'pages_revision_named' => 'Pagina Revisie voor :pageName',
'pages_revisions_created_by' => 'Aangemaakt door',
'pages_revisions_date' => 'Revisiedatum',
'pages_revisions_number' => '#',
'pages_revisions_changelog' => 'Changelog',
'pages_revisions_changes' => 'Wijzigingen',
'pages_revisions_current' => 'Huidige Versie',
@@ -218,8 +243,19 @@ return [
/**
* Comments
*/
'comment' => 'Commentaar',
'comments' => 'Commentaren',
'comment_placeholder' => 'Vul hier uw reacties in',
'comment_save' => 'Opslaan opslaan',
];
'comment' => 'Reactie',
'comments' => 'Reacties',
'comment_placeholder' => 'Laat hier een reactie achter',
'comment_count' => '{0} Geen reacties|{1} 1 Reactie|[2,*] :count Reacties',
'comment_save' => 'Sla reactie op',
'comment_saving' => 'Opslaan van reactie...',
'comment_deleting' => 'Verwijderen van reactie...',
'comment_new' => 'Nieuwe reactie',
'comment_created' => 'reactie gegeven :createDiff',
'comment_updated' => 'Update :updateDiff door :username',
'comment_deleted_success' => 'Reactie verwijderd',
'comment_created_success' => 'Reactie toegevoegd',
'comment_updated_success' => 'Reactie bijgewerkt',
'comment_delete_confirm' => 'Zeker reactie verwijderen?',
'comment_in_reply_to' => 'Antwoord op :commentId',
];

View File

@@ -60,6 +60,12 @@ return [
'role_system_cannot_be_deleted' => 'Dit is een systeemrol en kan niet verwijderd worden',
'role_registration_default_cannot_delete' => 'Deze rol kan niet verwijerd worden zolang dit de standaardrol na registratie is.',
// Comments
'comment_list' => 'Er is een fout opgetreden tijdens het ophalen van de reacties.',
'cannot_add_comment_to_draft' => 'U kunt geen reacties toevoegen aan een concept.',
'comment_add' => 'Er is een fout opgetreden tijdens het toevoegen van de reactie.',
'comment_delete' => 'Er is een fout opgetreden tijdens het verwijderen van de reactie.',
'empty_comment' => 'Kan geen lege reactie toevoegen.',
// Error pages
'404_page_not_found' => 'Pagina Niet Gevonden',
'sorry_page_not_found' => 'Sorry, de pagina die je zocht is niet beschikbaar.',
@@ -67,11 +73,4 @@ return [
'error_occurred' => 'Er Ging Iets Fout',
'app_down' => ':appName is nu niet beschikbaar',
'back_soon' => 'Komt snel weer online.',
// Comments
'comment_list' => 'Er is een fout opgetreden tijdens het ophalen van de reacties.',
'cannot_add_comment_to_draft' => 'U kunt geen reacties toevoegen aan een ontwerp.',
'comment_add' => 'Er is een fout opgetreden tijdens het toevoegen van de reactie.',
'comment_delete' => 'Er is een fout opgetreden tijdens het verwijderen van de reactie.',
'empty_comment' => 'Kan geen lege reactie toevoegen.',
];

View File

@@ -0,0 +1,42 @@
<?php
return [
/**
* Activity text strings.
* Is used for all the text within activity logs & notifications.
*/
// Pages
'page_create' => 'создал страницу',
'page_create_notification' => 'Страница успешно создана',
'page_update' => 'обновил страницу',
'page_update_notification' => 'Станица успешно обновлена',
'page_delete' => 'удалил страницу',
'page_delete_notification' => 'Старница успешно удалена',
'page_restore' => 'восстановил страницу',
'page_restore_notification' => 'Страница успешно восстановлена',
'page_move' => 'переместил страницу',
// Chapters
'chapter_create' => 'создал главу',
'chapter_create_notification' => 'глава успешно создана',
'chapter_update' => 'обновил главу',
'chapter_update_notification' => 'Глава успешно обновленна',
'chapter_delete' => 'удалил главу',
'chapter_delete_notification' => 'Глава успешно удалено',
'chapter_move' => 'переместил главу',
// Books
'book_create' => 'создал книгу',
'book_create_notification' => 'Книга успешно создана',
'book_update' => 'обновил книгу',
'book_update_notification' => 'Книга успешно обновлена',
'book_delete' => 'удалил книгу',
'book_delete_notification' => 'Книга успешно удалена',
'book_sort' => 'отсортировал книгу',
'book_sort_notification' => 'Книга успешно отсортирована',
// Other
'commented_on' => 'прокомментировал',
];

View File

@@ -0,0 +1,76 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'Учётная запись не найдена.',
'throttle' => 'Слишком много попыток входа. Пожалуйста, попробуйте позже через :seconds секунд.',
/**
* Login & Register
*/
'sign_up' => 'Регистрация',
'log_in' => 'Вход',
'log_in_with' => 'Вход с :socialDriver',
'sign_up_with' => 'Регистрация с :socialDriver',
'logout' => 'Выход',
'name' => 'Имя',
'username' => 'Логин',
'email' => 'Е-мэйл',
'password' => 'Пароль',
'password_confirm' => 'Подтверждение пароля',
'password_hint' => 'Должен быть больше 5 символов',
'forgot_password' => 'Забыли пароль?',
'remember_me' => 'Запомнить меня',
'ldap_email_hint' => 'Введите email адрес для данной учётной записи.',
'create_account' => 'Создать аккаунт',
'social_login' => 'Вход через Соцсеть',
'social_registration' => 'Регистрация через Соцсеть',
'social_registration_text' => 'Регистрация и вход через другой сервис.',
'register_thanks' => 'Благодарим за регистрацию!',
'register_confirm' => 'Проверьте свою электронную почту и нажмите кнопку подтверждения для доступа к :appName.',
'registrations_disabled' => 'Регистрация отключена',
'registration_email_domain_invalid' => 'Данный домен электрронной почты не доступен для регистрации',
'register_success' => 'Спасибо за регистрацию! Регистрация и вход в систему выполнены.',
/**
* Password Reset
*/
'reset_password' => 'Сброс пароля',
'reset_password_send_instructions' => 'Введите свой адрес электронной почты ниже, и вам будет отправлено электронное письмо с ссылкой для сброса пароля.',
'reset_password_send_button' => 'Отправить ссылку для сброса',
'reset_password_sent_success' => 'Ссылка для сброса была отправлена на :email.',
'reset_password_success' => 'Ваш пароль был успешно сброшен.',
'email_reset_subject' => 'Сбросить ваш :appName пароль',
'email_reset_text' => 'Вы получили это электронное письмо, потому что мы получили запрос на сброс пароля для вашей учетной записи.',
'email_reset_not_requested' => 'Если вы не запрашивали сброса пароля, то никаких дополнительных действий не требуется.',
/**
* Email Confirmation
*/
'email_confirm_subject' => 'Подтвердите ваш почтовый адрес на :appName',
'email_confirm_greeting' => 'Благодарим за участие :appName!',
'email_confirm_text' => 'Пожалуйста, подтвердите ваш почтовый адрес кликнув на кнопку ниже:',
'email_confirm_action' => 'Подтвердить е-мэйл',
'email_confirm_send_error' => 'Требуется подтверждение электронной почты, но система не может отправить электронное письмо. Свяжитесь с администратором, чтобы убедиться, что адрес электронной почты настроен правильно.',
'email_confirm_success' => 'Ваш е-мэйл был подтверждён!',
'email_confirm_resent' => 'Письмо с подтверждение выслано снова. Пожалуйста, проверьте ваш почтовый ящик.',
'email_not_confirmed' => 'Е-мэйл не подтверждён',
'email_not_confirmed_text' => 'Ваш email адрес всё ещё не подтверждён.',
'email_not_confirmed_click_link' => 'Пожалуйста, нажмите на ссылку в письме, которое было отправлено при регистрации.',
'email_not_confirmed_resend' => 'Если вы не можете найти электронное письмо, вы можете снова отправить письмо с подтверждением по форме ниже.',
'email_not_confirmed_resend_button' => 'Переотправить письмо с подтверждёнием',
];

View File

@@ -0,0 +1,61 @@
<?php
return [
/**
* Buttons
*/
'cancel' => 'Отмена',
'confirm' => 'Применить',
'back' => 'Назад',
'save' => 'Сохранить',
'continue' => 'Продолжить',
'select' => 'Выбрать',
'more' => 'Ещё',
/**
* Form Labels
*/
'name' => 'Имя',
'description' => 'Описание',
'role' => 'Роль',
/**
* Actions
*/
'actions' => 'Действия',
'view' => 'Просмотр',
'create' => 'Создание',
'update' => 'Обновление',
'edit' => 'Редактировать',
'sort' => 'Сортировать',
'move' => 'Переместить',
'reply' => 'Ответить',
'delete' => 'Удалить',
'search' => 'Поиск',
'search_clear' => 'Очистить поиск',
'reset' => 'Сбросить',
'remove' => 'Удалить',
'add' => 'Добавить',
/**
* Misc
*/
'deleted_user' => 'Удалённый пользователь',
'no_activity' => 'Нет действий для просмотра',
'no_items' => 'Нет доступных элементов',
'back_to_top' => 'Вернуться наверх',
'toggle_details' => 'Подробности',
'details' => 'Детали',
/**
* Header
*/
'view_profile' => 'Просмотреть профиль',
'edit_profile' => 'Редактировать профиль',
/**
* Email Content
*/
'email_action_help' => 'Если у вас возникли проблемы с нажатием кнопки ":actionText", то скопируйте и вставьте указанный URL-адрес в свой веб-браузер:',
'email_rights' => 'Все прова зарезервированы',
];

View File

@@ -0,0 +1,25 @@
<?php
return [
/**
* Image Manager
*/
'image_select' => 'Выбрать изображение',
'image_all' => 'Все',
'image_all_title' => 'Простмотр всех изображений',
'image_book_title' => 'Просмотр всех изображений загруженных в эту книгу',
'image_page_title' => 'Просмотр всех изображений загруженных на эту страницу',
'image_search_hint' => 'Поиск по имени изображения',
'image_uploaded' => 'Загруженно :uploadedDate',
'image_load_more' => 'Загрузить ещё',
'image_image_name' => 'Имя изображения',
'image_delete_confirm' => 'Это изображение используется на странице ниже. Снова кликните удалить для подтверждения того что вы хотите удалить.',
'image_select_image' => 'Выбрать изображение',
'image_dropzone' => 'Перетащите изображение или кликните для загрузки',
'images_deleted' => 'Изображения удалены',
'image_preview' => 'Предосмотр изображения',
'image_upload_success' => 'Изображение загружено успешно',
'image_update_success' => 'Детали изображения успешно обновлены',
'image_delete_success' => 'Изображение успешно удалено',
];

View File

@@ -0,0 +1,260 @@
<?php
return [
/**
* Shared
*/
'recently_created' => 'Недавно созданные',
'recently_created_pages' => 'Недавно созданные страницы',
'recently_updated_pages' => 'Недавно обновлённые страницы',
'recently_created_chapters' => 'Недавно созданные главы',
'recently_created_books' => 'Недавно созданные книги',
'recently_update' => 'Недавно обновленные',
'recently_viewed' => 'Недавно просмотренные',
'recent_activity' => 'Недавние действия',
'create_now' => 'Создать сейчас',
'revisions' => 'Версия',
'meta_revision' => 'Версия #:revisionCount',
'meta_created' => 'Создано :timeLength',
'meta_created_name' => 'Создано :timeLength пользователем :user',
'meta_updated' => 'Обновлено :timeLength',
'meta_updated_name' => 'Обновлено :timeLength пользователем :user',
'entity_select' => 'Выбор объекта',
'images' => 'Изображения',
'my_recent_drafts' => 'Мои последние черновики',
'my_recently_viewed' => 'Мои недавние просмотры',
'no_pages_viewed' => 'Вы не просматривали ни одной страницы',
'no_pages_recently_created' => 'Недавно не были созданы страницы',
'no_pages_recently_updated' => 'Недавно не обновлялись страницы',
'export' => 'Экспорт',
'export_html' => 'Веб файл',
'export_pdf' => 'PDF файл',
'export_text' => 'Текстовый файл',
/**
* Permissions and restrictions
*/
'permissions' => 'Разрешения',
'permissions_intro' => 'После включения эти разрешения будут иметь приоритет над любыми установленными полномочиями.',
'permissions_enable' => 'Включение пользовательских разрешений',
'permissions_save' => 'Сохранить разрешения',
/**
* Search
*/
'search_results' => 'Результаты поиска',
'search_total_results_found' => ':count результатов найдено|:count всего результатов найдено',
'search_clear' => 'Очистить поиск',
'search_no_pages' => 'Нет страниц, соответствующих этому поиску.',
'search_for_term' => 'Искать :term',
'search_more' => 'Ещё результаты',
'search_filters' => 'Фильтры поиска',
'search_content_type' => 'Тип содержимого',
'search_exact_matches' => 'Точные соответствия',
'search_tags' => 'Поиск по тэгам',
'search_viewed_by_me' => 'Просмотрено мной',
'search_not_viewed_by_me' => 'Не просматривалось мной',
'search_permissions_set' => 'Набор разрешений',
'search_created_by_me' => 'Создано мной',
'search_updated_by_me' => 'Обновлено мной',
'search_updated_before' => 'Обновлено до',
'search_updated_after' => 'Обновлено после',
'search_created_before' => 'Создано до',
'search_created_after' => 'Создано после',
'search_set_date' => 'Установить дату',
'search_update' => 'Обновить поиск',
/**
* Books
*/
'book' => 'Книга',
'books' => 'Книги',
'x_books' => ':count книг|:count Книг',
'books_empty' => 'Нет созданных книг',
'books_popular' => 'Популярные книги',
'books_recent' => 'Недавние книги',
'books_new' => 'Новые книги',
'books_popular_empty' => 'Здесь появятся самые популярные книги.',
'books_new_empty' => 'Здесь появятся самые последние созданные книги.',
'books_create' => 'Создать новую книгу',
'books_delete' => 'Удалить книгу',
'books_delete_named' => 'Удалить книгу :bookName',
'books_delete_explain' => 'Это удалит книги с именем \':bookName\'. Все разделы и страницы будут удалены.',
'books_delete_confirmation' => 'Вы действительно хотите удалить эту книгу?',
'books_edit' => 'Редактировать книгу',
'books_edit_named' => 'Редактировать книгу :bookName',
'books_form_book_name' => 'Имя книги',
'books_save' => 'Сохранить книгу',
'books_permissions' => 'Разрешения на книгу',
'books_permissions_updated' => 'Разрешения на книгу обновлены',
'books_empty_contents' => 'Для этой книги нет страниц или разделов.',
'books_empty_create_page' => 'Создать новую страницу',
'books_empty_or' => 'или',
'books_empty_sort_current_book' => 'Сортировка текущей книги',
'books_empty_add_chapter' => 'Добавить главу',
'books_permissions_active' => 'действующие разрешения на книгу',
'books_search_this' => 'Поиск в этой книге',
'books_navigation' => 'Навигация по книге',
'books_sort' => 'Сортировка содержимого книги',
'books_sort_named' => 'Сортировка книги :bookName',
'books_sort_show_other' => 'Показать другие книги',
'books_sort_save' => 'Сохранить новый порядок',
/**
* Chapters
*/
'chapter' => 'Глава',
'chapters' => 'Главы',
'x_chapters' => ':count глава|:count Главы',
'chapters_popular' => 'Популярные главы',
'chapters_new' => 'Новая глава',
'chapters_create' => 'Создать новую главу',
'chapters_delete' => 'Удалить главу',
'chapters_delete_named' => 'Удалить главу :chapterName',
'chapters_delete_explain' => 'Это удалит главу с именем \':chapterName\'. Все страницы главы будут удалены и перемещены напрямую в книгу.',
'chapters_delete_confirm' => 'Вы действительно хотите удалить эту главу?',
'chapters_edit' => 'Редактировать главу',
'chapters_edit_named' => 'редактировать главу :chapterName',
'chapters_save' => 'Сохранить главу',
'chapters_move' => 'Переместить главу',
'chapters_move_named' => 'Переместить главу :chapterName',
'chapter_move_success' => 'Глава перемещена в :bookName',
'chapters_permissions' => 'Разрешения главы',
'chapters_empty' => 'В этой главе нет страниц.',
'chapters_permissions_active' => 'Действующие разрешения главы',
'chapters_permissions_success' => 'Разрешения главы обновлены',
'chapters_search_this' => 'Искать в этой главе',
/**
* Pages
*/
'page' => 'Страница',
'pages' => 'Страницы',
'x_pages' => ':count страниц|:count страниц',
'pages_popular' => 'Популярные страницы',
'pages_new' => 'Новая страница',
'pages_attachments' => 'Вложения',
'pages_navigation' => 'Навигация на странице',
'pages_delete' => 'Удалить устраницу',
'pages_delete_named' => 'Удалить страницу :pageName',
'pages_delete_draft_named' => 'Удалить черновик :pageName',
'pages_delete_draft' => 'Удалить черновик',
'pages_delete_success' => 'Страница удалена',
'pages_delete_draft_success' => 'Черновик удалён',
'pages_delete_confirm' => 'Вы действительно хотите удалить эту страницу?',
'pages_delete_draft_confirm' => 'Вы действительно хотите удалить этот черновик?',
'pages_editing_named' => 'Редактирование страницы :pageName',
'pages_edit_toggle_header' => 'Переключение заголовка',
'pages_edit_save_draft' => 'Сохранить черновик',
'pages_edit_draft' => 'Редактировать черновик',
'pages_editing_draft' => 'Редактирование черновика',
'pages_editing_page' => 'Редактирование страницы',
'pages_edit_draft_save_at' => 'Черновик сохранить в ',
'pages_edit_delete_draft' => 'Удалить черновик',
'pages_edit_discard_draft' => 'отменить черновик',
'pages_edit_set_changelog' => 'Задать список изменений',
'pages_edit_enter_changelog_desc' => 'Введите краткое описание изменений, которые вы сделали',
'pages_edit_enter_changelog' => 'Введите список изменений',
'pages_save' => 'Сохранить страницу',
'pages_title' => 'Заголовок страницы',
'pages_name' => 'Имя страницы',
'pages_md_editor' => 'Редактор',
'pages_md_preview' => 'Просмотр',
'pages_md_insert_image' => 'Вставить изображение',
'pages_md_insert_link' => 'Вставить ссылку на объект',
'pages_not_in_chapter' => 'Страница не находится в главе',
'pages_move' => 'Переместить страницу',
'pages_move_success' => 'Страница перемещена в ":parentName"',
'pages_permissions' => 'Разрешения страницы',
'pages_permissions_success' => 'PРазрешения страницы обновлены',
'pages_revision' => 'Версия',
'pages_revisions' => 'Версия страницы',
'pages_revisions_named' => 'Версии страницы для :pageName',
'pages_revision_named' => 'Версия страницы для :pageName',
'pages_revisions_created_by' => 'Создана',
'pages_revisions_date' => 'Дата версии',
'pages_revisions_number' => '#',
'pages_revisions_changelog' => 'Список изменений',
'pages_revisions_changes' => 'Изменения',
'pages_revisions_current' => 'Текущая версия',
'pages_revisions_preview' => 'Просмотр',
'pages_revisions_restore' => 'Восстановить',
'pages_revisions_none' => 'У этой страницы нет других версий',
'pages_copy_link' => 'Копировать ссылку',
'pages_permissions_active' => 'Действующие разрешения на страницу',
'pages_initial_revision' => 'Первоначальное издание',
'pages_initial_name' => 'Новая страница',
'pages_editing_draft_notification' => 'Вы в настоящее время редактируете черновик, который был сохранен :timeDiff.',
'pages_draft_edited_notification' => 'Эта страница была обновлена до этого момента. Рекомендуется отменить этот черновик',
'pages_draft_edit_active' => [
'start_a' => ':count пользователей начали редактирование этой страницы',
'start_b' => ':userName начал редактирование этой страницы',
'time_a' => 'поскольку последние страницы были обновлены',
'time_b' => 'за последние :minCount минут',
'message' => ':start :time. Будьте осторожны, чтобы не перезаписывать друг друга!',
],
'pages_draft_discarded' => 'Черновик сброшен, редактор обновлен текущим содержимым страницы',
/**
* Editor sidebar
*/
'page_tags' => 'Теги страницы',
'tag' => 'Тэг',
'tags' => '',
'tag_value' => 'Значение тэга (опционально)',
'tags_explain' => "Добавьте теги, чтобы лучше классифицировать ваш контент. \n Вы можете присвоить значение тегу для более глубокой организации.",
'tags_add' => 'Добавить тэг',
'attachments' => 'Вложение',
'attachments_explain' => 'Загрузите несколько файлов или добавьте ссылку для отображения на своей странице. Они видны на боковой панели страницы.',
'attachments_explain_instant_save' => 'Изменения здесь сохраняются мгновенно.',
'attachments_items' => 'Прикрепленные элементы',
'attachments_upload' => 'Загрузить файл',
'attachments_link' => 'Присоединить ссылку',
'attachments_set_link' => 'Установить ссылку',
'attachments_delete_confirm' => 'Нажмите «Удалить» еще раз, чтобы подтвердить, что вы хотите удалить этот файл.',
'attachments_dropzone' => 'Перетащите файл сюда или нажмите здесь, чтобы загрузить файл',
'attachments_no_files' => 'Файлы не загружены',
'attachments_explain_link' => 'Вы можете присоединить ссылку, если вы предпочитаете не загружать файл. Это может быть ссылка на другую страницу или ссылку на файл в облаке',
'attachments_link_name' => 'Имя ссылки',
'attachment_link' => 'Ссылка на вложение',
'attachments_link_url' => 'Ссылка на файл',
'attachments_link_url_hint' => 'URL-адрес сайта или файла',
'attach' => 'Прикрепить',
'attachments_edit_file' => 'Редактировать файл',
'attachments_edit_file_name' => 'Имя файла',
'attachments_edit_drop_upload' => 'перетащите файлы или нажмите здесь, чтобы загрузить и перезаписать',
'attachments_order_updated' => 'Прикрепленный файл обновлен',
'attachments_updated_success' => 'Attachment details updated',
'attachments_deleted' => 'Приложение удалено',
'attachments_file_uploaded' => 'Файл успешно загружен',
'attachments_file_updated' => 'Файл успешно обновлен',
'attachments_link_attached' => 'Ссылка успешно присоединена к странице',
/**
* Profile View
*/
'profile_user_for_x' => 'пользователь уже :time',
'profile_created_content' => 'Созданный контент',
'profile_not_created_pages' => ':userName не создавал страниц',
'profile_not_created_chapters' => ':userName не создавал глав',
'profile_not_created_books' => ':userName не создавал ни одной книги',
/**
* Comments
*/
'comment' => 'Комментарий',
'comments' => 'Комментарии',
'comment_placeholder' => 'Оставить комментарий здесь',
'comment_count' => '{0} Нет комментариев|{1} 1 комментарий|[2,*] :count комментария',
'comment_save' => 'Сохранить комментарий',
'comment_saving' => 'Сохраниение комментария...',
'comment_deleting' => 'Удаление комментария...',
'comment_new' => 'Новый комментарий',
'comment_created' => 'прокомментировал :createDiff',
'comment_updated' => 'Обновлён :updateDiff пользователем :username',
'comment_deleted_success' => 'Комментарий удалён',
'comment_created_success' => 'Комментарий добавлён',
'comment_updated_success' => 'Комментарий обновлён',
'comment_delete_confirm' => 'Вы уверенны, что хотите удалить этот комментарий?',
'comment_in_reply_to' => 'В ответ на :commentId',
];

View File

@@ -0,0 +1,77 @@
<?php
return [
/**
* Error text strings.
*/
// Permissions
'permission' => 'У вас нет доступа к запрашиваемой странице.',
'permissionJson' => 'У вас нет разрешения для запрашиваемого действия.',
// Auth
'error_user_exists_different_creds' => 'Пользователь с электронной почтой: :email уже существует, но с другими учетными данными.',
'email_already_confirmed' => 'Электронная почта уже подтверждена, попробуйте войти в систему.',
'email_confirmation_invalid' => 'Этот токен подтверждения недействителен или уже используется. Повторите попытку регистрации.',
'email_confirmation_expired' => 'Идентификатор подтверждения истек. Отправлено новое письмо с подтверждением.',
'ldap_fail_anonymous' => 'Недопустимый доступ LDAP с использованием анонимной привязки',
'ldap_fail_authed' => 'Не удалось получить доступ к LDAP, используя данные dn & password',
'ldap_extension_not_installed' => 'LDAP расширения для PHP не установлено',
'ldap_cannot_connect' => 'Не удается подключиться к серверу ldap, Не удалось выполнить начальное соединение',
'social_no_action_defined' => 'Действие не определено',
'social_account_in_use' => 'Этот :socialAccount аккаунт уже исопльзуется, Попробуйте войти с параматрами :socialAccount.',
'social_account_email_in_use' => 'Электронный ящик :email уже используется. Если у вас уже есть учетная запись, вы можете подключить свою учетную запись :socialAccount из настроек своего профиля.',
'social_account_existing' => 'Этот :socialAccount уже привязан к вашему профилю.',
'social_account_already_used_existing' => 'Этот :socialAccount уже используется другим пользователем.',
'social_account_not_used' => 'Эта :socialAccount учетная запись не связана ни с какими пользователями. Прикрепите его в настройках вашего профиля.',
'social_account_register_instructions' => 'Если у вас еще нет учетной записи, вы можете зарегистрироваться, используя параметр :socialAccount.',
'social_driver_not_found' => 'Драйдер для Соцсети не найден',
'social_driver_not_configured' => 'Настройки вашего :socialAccount сконфигурированы неправильно.',
// System
'path_not_writable' => 'Невозможно загрузить файл по пути :filePath . Убедитесь что сервер доступен для записи.',
'cannot_get_image_from_url' => 'Не удается получить изображение из :url',
'cannot_create_thumbs' => 'Сервер не может создавать эскизы. Убедитесь, что у вас установлено расширение GD PHP.',
'server_upload_limit' => 'Сервер не разрешает загрузку такого размера. Попробуйте уменьшить размер файла.',
'image_upload_error' => 'Произошла ошибка при загрузке изображения.',
// Attachments
'attachment_page_mismatch' => 'Несоответствие страницы во время обновления вложения',
// Pages
'page_draft_autosave_fail' => 'Не удалось сохранить черновик. Перед сохранением этой страницы убедитесь, что у вас есть подключение к Интернету.',
// Entities
'entity_not_found' => 'Объект не найден',
'book_not_found' => 'Книга не найдена',
'page_not_found' => 'Страница не найдена',
'chapter_not_found' => 'Глава не найдена',
'selected_book_not_found' => 'Выбранная книга не найдена',
'selected_book_chapter_not_found' => 'Выбранная книга или глава не найдена',
'guests_cannot_save_drafts' => 'Гости не могут сохранить черновики',
// Users
'users_cannot_delete_only_admin' => 'Вы не можете удалить единственного администратора',
'users_cannot_delete_guest' => 'Вы не можете удалить гостевого пользователя',
// Roles
'role_cannot_be_edited' => 'Невозможно отредактировать данную роль',
'role_system_cannot_be_deleted' => 'Эта роль является системной и не может быть удалена',
'role_registration_default_cannot_delete' => 'Эта роль не может быть удалена, так как она устанолена в качестве роли регистрации по-умолчанию',
// Comments
'comment_list' => 'При получении комментариев произошла ошибка.',
'cannot_add_comment_to_draft' => 'Вы не можете добавлять комментарии к черновику.',
'comment_add' => 'При добавлении / обновлении комментария произошла ошибка.',
'comment_delete' => 'При удалении комментария произошла ошибка.',
'empty_comment' => 'Нельзя добавить пустой комментарий.',
// Error pages
'404_page_not_found' => 'Старница не найдена',
'sorry_page_not_found' => 'Извините, страница, которую вы искали, не найдена.',
'return_home' => 'вернуться на главную страницу',
'error_occurred' => 'Произошла ошибка',
'app_down' => ':appName в данный момент не достпуно',
'back_soon' => 'Скоро восстановится.',
];

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Предыдущая',
'next' => 'Следующая &raquo;',
];

View File

@@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reminder Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'password' => 'Пароль должен содержать не менее шести символов для применения.',
'user' => "Невозможно найти пользователя с указанным e-mail адресом.",
'token' => 'Этот токен для сброса пароля недействителен.',
'sent' => 'Ссылка для сброса пароля была отправлена на электронную почту!',
'reset' => 'Ваш пароль был сброшен!',
];

116
resources/lang/ru/settings.php Executable file
View File

@@ -0,0 +1,116 @@
<?php
return [
/**
* Settings text strings
* Contains all text strings used in the general settings sections of BookStack
* including users and roles.
*/
'settings' => 'Настройки',
'settings_save' => 'Сохранить настройки',
'settings_save_success' => 'Настройки сохранены',
/**
* App settings
*/
'app_settings' => 'Настройки приложения',
'app_name' => 'Имя приложения',
'app_name_desc' => 'Это имя отображается в заголовке и в любых письмах.',
'app_name_header' => 'Показать имя приложения в заголовке?',
'app_public_viewing' => 'Разрешить публичный просмотр?',
'app_secure_images' => 'Включить загрузку изображений с более высокой безопасностью?',
'app_secure_images_desc' => 'По соображениям производительности все изображения являются общедоступными. Этот параметр добавляет случайную, труднодоступную строку перед образами изображений. Убедитесь, что индексация каталогов не включена, чтобы предотвратить к ним легкий доступ.',
'app_editor' => 'Редактор страницы',
'app_editor_desc' => 'Выберите, какой редактор будет использоваться всеми пользователями для редактирования страниц.',
'app_custom_html' => 'Пользовательский контент заголовка HTML',
'app_custom_html_desc' => 'Любой контент, добавленный здесь, будет вставлен в нижнюю часть раздела <head> каждой страницы. Это удобно для переопределения стилей или добавления кода аналитики.',
'app_logo' => 'Лого приложения',
'app_logo_desc' => 'Это изображение должно быть 43px в высоту. <br>Большее изображение будет уменьшено.',
'app_primary_color' => 'Главный цвет приложения',
'app_primary_color_desc' => 'Это должно быть указано в hex. <br>Оставьте пустым чтобы использовать цвет по-умолчанию.',
'app_homepage' => 'Домашняя страница приложения',
'app_homepage_desc' => 'Выберите страницу, которая будет отображаться на главной странице вместо стандартной. Права на страницы игнорируются для выбранных страниц.',
'app_homepage_default' => 'Выбрана домашняя страница по-умолчанию',
/**
* Registration
*/
'reg_settings' => 'Настройки регистрации',
'reg_allow' => 'Открыть регистрацию?',
'reg_default_role' => 'Роль пользователя по-умолчанию после регистрации',
'reg_confirm_email' => 'Требуется подтверждение по электронной почте?',
'reg_confirm_email_desc' => 'Если используется ограничение домена, тогда потребуется подтверждение по электронной почте и этот пункт будет проигнорирован.',
'reg_confirm_restrict_domain' => 'Ограничить регистрацию по домену',
'reg_confirm_restrict_domain_desc' => 'EВведите список доменов электронной почты, разделенных запятыми, на которые вы хотели бы ограничить регистрацию. Пользователям будет отправлено электронное письмо, чтобы подтвердить их адрес, прежде чем им разрешат взаимодействовать с приложением. <br> Обратите внимание, что пользователи смогут изменять свои адреса электронной почты после успешной регистрации.',
'reg_confirm_restrict_domain_placeholder' => 'Нет ограничений',
/**
* Role settings
*/
'roles' => 'Роли',
'role_user_roles' => 'Роли пользователя',
'role_create' => 'Создать новую роль',
'role_create_success' => 'Роль упешно создана',
'role_delete' => 'Удалить роль',
'role_delete_confirm' => 'Это удалит роль с именем \':roleName\'.',
'role_delete_users_assigned' => 'Эта роль имеет :userCount пользователей привязанных к ней. Если вы хотите перенести пользователей из этой роли, выберите новую роль ниже.',
'role_delete_no_migration' => "Не мигрировать пользователей",
'role_delete_sure' => 'Вы уверены что хотите удалить данную роль?',
'role_delete_success' => 'Роль успешно удалена',
'role_edit' => 'Редактировать роль',
'role_details' => 'Детали роли',
'role_name' => 'Имя роли',
'role_desc' => 'Короткое описание роли',
'role_system' => 'Системные разрешения',
'role_manage_users' => 'Управление пользователями',
'role_manage_roles' => 'Управление ролями и правами на роли',
'role_manage_entity_permissions' => 'Управление правами на все книги, главы и страницы',
'role_manage_own_entity_permissions' => 'Управление разрешениями для собственных книг, разделов и страниц',
'role_manage_settings' => 'Управление настройками приложения',
'role_asset' => 'Разрешение для активации',
'role_asset_desc' => 'Эти разрешения контролируют доступ по-умолчанию к параметрам внутри системы. Разрешения на книги, главы и страницы перезапишут эти разрешения.',
'role_all' => 'Все',
'role_own' => 'Владелец',
'role_controlled_by_asset' => 'Регилируемые активацией они загружаются в',
'role_save' => 'Сохранить роль',
'role_update_success' => 'Роль успешно обновлена',
'role_users' => 'Пользователи с данной ролью',
'role_users_none' => 'Нет пользователей с данной ролью',
/**
* Users
*/
'users' => 'Пользователи',
'user_profile' => 'Профиль пользователя',
'users_add_new' => 'Добавить нового пользователя',
'users_search' => 'Поиск пользователей',
'users_role' => 'Роли пользователя',
'users_external_auth_id' => 'Внешний ID аутентификации',
'users_password_warning' => 'Введите ниже свой пароль новый пароль для его изменения:',
'users_system_public' => 'Этот пользователь представляет любых гостевых пользователей, которые посещают ваше приложение. Он не может использоваться для входа в систему и назначается автоматически.',
'users_delete' => 'Удалить пользователя',
'users_delete_named' => 'Удалить пользователя :userName',
'users_delete_warning' => 'Это полностью удалит этого пользователя с именем \':userName\' из системы.',
'users_delete_confirm' => 'Вы уверены что хотите удалить этого пользователя?',
'users_delete_success' => 'Пользователи успешно удалены',
'users_edit' => 'Редактировать польщователя',
'users_edit_profile' => 'Редактировать профиль',
'users_edit_success' => 'Пользователь успешно обновлён',
'users_avatar' => 'Аватар пользователя',
'users_avatar_desc' => 'Это изображение должно быть размером около 256 пикселей.',
'users_preferred_language' => 'Предпочитаемый язык',
'users_social_accounts' => 'Аккаунты Соцсетей',
'users_social_accounts_info' => 'Здесь вы можете подключить другие учетные записи для более быстрого и легкого входа в систему. Отключение учетной записи здесь не разрешено. Отменить доступ к настройкам вашего профиля в подключенном социальном аккаунте.',
'users_social_connect' => 'Подключить аккаунт',
'users_social_disconnect' => 'Отключить аккаунт',
'users_social_connected' => ':socialAccount аккаунт упешно подключён к вашему профилю.',
'users_social_disconnected' => ':socialAccount аккаунт успешно отключён от вашего профиля.',
];

View File

@@ -0,0 +1,108 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => ':attribute должен быть принят.',
'active_url' => ':attribute не является валидным URL.',
'after' => ':attribute дата должна быть позже :date.',
'alpha' => ':attribute может содержать только буквы.',
'alpha_dash' => ':attribute может содержать только буквы, цифры и тире.',
'alpha_num' => ':attribute должен содержать только буквы и цифры.',
'array' => ':attribute должен быть массивом.',
'before' => ':attribute дата должна быть до :date.',
'between' => [
'numeric' => ':attribute должен быть между :min и :max.',
'file' => ':attribute должен быть между :min и :max килобайт.',
'string' => 'длина :attribute должена быть между :min и :max символами.',
'array' => ':attribute должен содержать не менее :min и не более:max элементов.',
],
'boolean' => ':attribute поле может быть только true или false.',
'confirmed' => ':attribute подтверждение не совпадает.',
'date' => ':attribute не корректные данные.',
'date_format' => ':attribute не соответствует формату :format.',
'different' => ':attribute и :other должны быть различны.',
'digits' => ':attribute должен быть из :digits цифр.',
'digits_between' => ':attribute должен иметь от :min до :max цифр.',
'email' => ':attribute must be a valid email address.',
'filled' => ':attribute поле необходимо.',
'exists' => 'выделенный :attribute невалиден.',
'image' => ':attribute must be an image.',
'in' => 'выделенный :attribute невалиден.',
'integer' => ':attribute должно быть целое число.',
'ip' => ':attribute должен быть валидный IP адрес.',
'max' => [
'numeric' => ':attribute не может быть больше чем :max.',
'file' => ':attribute не может быть больше чем :max килобайт.',
'string' => ':attribute не может быть больше чем :max символов.',
'array' => ':attribute не может содержать больше чем :max элементов.',
],
'mimes' => ':attribute должен быть файлом с типом: :values.',
'min' => [
'numeric' => ':attribute должен быть хотя бы :min.',
'file' => ':attribute должен быть минимум :min килобайт.',
'string' => ':attribute должен быть минимум :min символов.',
'array' => ':attribute должен содержать хотя бы :min элементов.',
],
'not_in' => 'Выбранный :attribute некорректен.',
'numeric' => ':attribute должен быть числом.',
'regex' => ':attribute неправильный формат.',
'required' => ':attribute обязательное поле.',
'required_if' => ':attribute обязательное поле когда :other со значением :value.',
'required_with' => ':attribute обязательное поле когда :values установлено.',
'required_with_all' => ':attribute обязательное поле когда :values установлены.',
'required_without' => ':attribute обязательное поле когда :values не установлены.',
'required_without_all' => ':attribute обязательное поле когда ни одно из :values не установлены.',
'same' => ':attribute и :other должны совпадать.',
'size' => [
'numeric' => ':attribute должен быть :size.',
'file' => ':attribute должен быть :size килобайт.',
'string' => ':attribute должен быть :size символов.',
'array' => ':attribute должен содержать :size элементов.',
],
'string' => ':attribute должен быть строкой.',
'timezone' => ':attribute должен быть валидной временной зоной.',
'unique' => ':attribute уже есть.',
'url' => ':attribute имеет неправильный формат.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'password-confirm' => [
'required_with' => 'Требуется подтверждение пароля',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
'attributes' => [],
];

View File

@@ -1,7 +1,7 @@
@extends('base')
@section('head')
<script src="{{ baseUrl('/libs/tinymce/tinymce.min.js?ver=4.6.3') }}"></script>
<script src="{{ baseUrl('/libs/tinymce/tinymce.min.js?ver=4.6.6') }}"></script>
@stop
@section('body-class', 'flexbox')

View File

@@ -1,5 +1,5 @@
<div toolbox class="floating-toolbox">
<div editor-toolbox class="floating-toolbox">
<div class="tabs primary-background-light">
<span toolbox-toggle><i class="zmdi zmdi-caret-left-circle"></i></span>

View File

@@ -1,5 +1,5 @@
<div class="page-editor flex-fill flex" ng-controller="PageEditController" drafts-enabled="{{ $draftsEnabled ? 'true' : 'false' }}" editor-type="{{ setting('app-editor') }}" page-id="{{ $model->id or 0 }}" page-new-draft="{{ $model->draft or 0 }}" page-update-draft="{{ $model->isDraft or 0 }}">
<div class="page-editor flex-fill flex" id="page-editor" drafts-enabled="{{ $draftsEnabled ? 'true' : 'false' }}" editor-type="{{ setting('app-editor') }}" page-id="{{ $model->id or 0 }}" page-new-draft="{{ $model->draft or 0 }}" page-update-draft="{{ $model->isDraft or 0 }}">
{{ csrf_field() }}
@@ -15,30 +15,30 @@
</div>
<div class="col-sm-4 faded text-center">
<div ng-show="draftsEnabled" dropdown class="dropdown-container draft-display">
<a dropdown-toggle class="text-primary text-button"><span class="faded-text" ng-bind="draftText"></span>&nbsp; <i class="zmdi zmdi-more-vert"></i></a>
<i class="zmdi zmdi-check-circle text-pos draft-notification" ng-class="{visible: draftUpdated}"></i>
<div v-show="draftsEnabled" dropdown class="dropdown-container draft-display">
<a dropdown-toggle class="text-primary text-button"><span class="faded-text" v-text="draftText"></span>&nbsp; <i class="zmdi zmdi-more-vert"></i></a>
<i class="zmdi zmdi-check-circle text-pos draft-notification" :class="{visible: draftUpdated}"></i>
<ul>
<li>
<a ng-click="forceDraftSave()" class="text-pos"><i class="zmdi zmdi-save"></i>{{ trans('entities.pages_edit_save_draft') }}</a>
<a @click="saveDraft()" class="text-pos"><i class="zmdi zmdi-save"></i>{{ trans('entities.pages_edit_save_draft') }}</a>
</li>
<li ng-if="isNewPageDraft">
<li v-if="isNewDraft">
<a href="{{ $model->getUrl('/delete') }}" class="text-neg"><i class="zmdi zmdi-delete"></i>{{ trans('entities.pages_edit_delete_draft') }}</a>
</li>
<li>
<a type="button" ng-if="isUpdateDraft" ng-click="discardDraft()" class="text-neg"><i class="zmdi zmdi-close-circle"></i>{{ trans('entities.pages_edit_discard_draft') }}</a>
<li v-if="isUpdateDraft">
<a type="button" @click="discardDraft" class="text-neg"><i class="zmdi zmdi-close-circle"></i>{{ trans('entities.pages_edit_discard_draft') }}</a>
</li>
</ul>
</div>
</div>
<div class="col-sm-4 faded">
<div class="action-buttons" ng-cloak>
<div class="action-buttons" v-cloak>
<div dropdown class="dropdown-container">
<a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-edit"></i> <span ng-bind="(changeSummary | limitTo:16) + (changeSummary.length>16?'...':'') || '{{ trans('entities.pages_edit_set_changelog') }}'"></span></a>
<a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-edit"></i> <span v-text="changeSummaryShort"></span></a>
<ul class="wide">
<li class="padded">
<p class="text-muted">{{ trans('entities.pages_edit_enter_changelog_desc') }}</p>
<input name="summary" id="summary-input" type="text" placeholder="{{ trans('entities.pages_edit_enter_changelog') }}" ng-model="changeSummary" />
<input name="summary" id="summary-input" type="text" placeholder="{{ trans('entities.pages_edit_enter_changelog') }}" v-model="changeSummary" />
</li>
</ul>
</div>
@@ -62,9 +62,9 @@
{{--WYSIWYG Editor--}}
@if(setting('app-editor') === 'wysiwyg')
<div tinymce="editorOptions" mce-change="editorChange" mce-model="editContent" class="flex-fill flex">
<div wysiwyg-editor class="flex-fill flex">
<textarea id="html-editor" name="html" rows="5" ng-non-bindable
@if($errors->has('html')) class="neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif</textarea>
@if($errors->has('html')) class="neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif</textarea>
</div>
@if($errors->has('html'))
@@ -74,7 +74,7 @@
{{--Markdown Editor--}}
@if(setting('app-editor') === 'markdown')
<div id="markdown-editor" markdown-editor class="flex-fill flex code-fill">
<div ng-non-bindable id="markdown-editor" markdown-editor class="flex-fill flex code-fill">
<div class="markdown-editor-wrap">
<div class="editor-toolbar">
@@ -82,12 +82,12 @@
<div class="float right buttons">
<button class="text-button" type="button" data-action="insertImage"><i class="zmdi zmdi-image"></i>{{ trans('entities.pages_md_insert_image') }}</button>
&nbsp;|&nbsp;
<button class="text-button" type="button" data-action="insertEntityLink"><i class="zmdi zmdi-link"></i>{{ trans('entities.pages_md_insert_link') }}</button>
<button class="text-button" type="button" data-action="insertLink"><i class="zmdi zmdi-link"></i>{{ trans('entities.pages_md_insert_link') }}</button>
</div>
</div>
<div markdown-input md-change="editorChange" md-model="editContent" class="flex flex-fill">
<textarea ng-non-bindable id="markdown-editor-input" name="markdown" rows="5"
<div markdown-input class="flex flex-fill">
<textarea id="markdown-editor-input" name="markdown" rows="5"
@if($errors->has('markdown')) class="neg" @endif>@if(isset($model) || old('markdown')){{htmlspecialchars( old('markdown') ? old('markdown') : ($model->markdown === '' ? $model->html : $model->markdown))}}@endif</textarea>
</div>
@@ -98,13 +98,14 @@
<div class="">{{ trans('entities.pages_md_preview') }}</div>
</div>
<div class="markdown-display">
<div class="page-content" ng-bind-html="displayContent"></div>
<div class="page-content"></div>
</div>
</div>
<input type="hidden" name="html"/>
</div>
<input type="hidden" name="html" ng-value="displayContent">
@if($errors->has('markdown'))
<div class="text-neg text-small">{{ $errors->first('markdown') }}</div>

View File

@@ -123,14 +123,15 @@
</div>
@endif
@include('partials/book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
<div class="card">
<h3><i class="zmdi zmdi-info-outline"></i> {{ trans('common.details') }}</h3>
<div class="body">
@include('partials.entity-meta', ['entity' => $page])
</div>
</div>
@include('partials/book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
@stop
@section('body')

View File

@@ -35,6 +35,21 @@ class PageContentTest extends TestCase
$pageContent->assertSee('Well This is a second block of content');
}
public function test_saving_page_with_includes()
{
$page = Page::first();
$secondPage = Page::all()->get(2);
$this->asEditor();
$page->html = "<p>{{@$secondPage->id}}</p>";
$resp = $this->put($page->getUrl(), ['name' => $page->name, 'html' => $page->html, 'summary' => '']);
$resp->assertStatus(302);
$page = Page::find($page->id);
$this->assertContains("{{@$secondPage->id}}", $page->html);
}
public function test_page_revision_views_viewable()
{
$this->asEditor();

View File

@@ -1 +1 @@
v0.18
v0.18.2