From f99c8ff99aee9beb8c692f36d4b84dc6e651e50a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 4 Jun 2017 15:37:10 +0100 Subject: [PATCH 01/74] Fixed role permission removal bug --- app/Services/PermissionService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/PermissionService.php b/app/Services/PermissionService.php index 6f9561a16..c6c981337 100644 --- a/app/Services/PermissionService.php +++ b/app/Services/PermissionService.php @@ -259,7 +259,7 @@ class PermissionService $roleIds = array_map(function($role) { return $role->id; }, $roles); - $this->jointPermission->newQuery()->whereIn('id', $roleIds)->delete(); + $this->jointPermission->newQuery()->whereIn('role_id', $roleIds)->delete(); } /** From 2060cdb931f14f03a9dfbeebd548f7933413af24 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 17 Jun 2017 12:41:18 +0100 Subject: [PATCH 02/74] Added code highlighting syntax modes --- resources/assets/js/code.js | 42 ++++++++++++++++++++++++++++++- resources/assets/js/directives.js | 2 +- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/resources/assets/js/code.js b/resources/assets/js/code.js index 872b13426..020c38365 100644 --- a/resources/assets/js/code.js +++ b/resources/assets/js/code.js @@ -17,18 +17,58 @@ require('codemirror/mode/yaml/yaml'); const CodeMirror = require('codemirror'); +const modeMap = { + css: 'css', + c: 'clike', + java: 'clike', + scala: 'clike', + kotlin: 'clike', + 'c++': 'clike', + 'c#': 'clike', + csharp: 'clike', + go: 'go', + html: 'htmlmixed', + javascript: 'javascript', + json: {name: 'javascript', json: true}, + js: 'javascript', + php: 'php', + md: 'markdown', + mdown: 'markdown', + markdown: 'markdown', + nginx: 'nginx', + powershell: 'powershell', + py: 'python', + python: 'python', + ruby: 'ruby', + rb: 'ruby', + shell: 'shell', + bash: 'shell', + toml: 'toml', + sql: 'sql', + xml: 'xml', + yaml: 'yaml', + yml: 'yaml', +}; + module.exports.highlight = function() { let codeBlocks = document.querySelectorAll('.page-content pre'); for (let i = 0; i < codeBlocks.length; i++) { + let innerCodeElem = codeBlocks[i].querySelector('code[class^=language-]'); + let mode = ''; + if (innerCodeElem !== null) { + let langName = innerCodeElem.className.replace('language-', ''); + if (typeof modeMap[langName] !== 'undefined') mode = modeMap[langName]; + } codeBlocks[i].innerHTML = codeBlocks[i].innerHTML.replace(//gi ,'\n'); let content = codeBlocks[i].textContent; + console.log('MODE', mode); CodeMirror(function(elt) { codeBlocks[i].parentNode.replaceChild(elt, codeBlocks[i]); }, { value: content, - mode: "", + mode: mode, lineNumbers: true, theme: 'base16-light', readOnly: true diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js index 221e18b0e..9a38add9a 100644 --- a/resources/assets/js/directives.js +++ b/resources/assets/js/directives.js @@ -399,7 +399,7 @@ module.exports = function (ngApp, events) { // Handle image upload and add image into markdown content function uploadImage(file) { - if (file.type.indexOf('image') !== 0) return; + if (file === null || !file.type.indexOf('image') !== 0) return; let formData = new FormData(); let ext = 'png'; let xhr = new XMLHttpRequest(); From c8be214ee0a3582614db2c1d9444316b40f04b0e Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 17 Jun 2017 15:07:55 +0100 Subject: [PATCH 03/74] Started tinymce code editor components --- resources/assets/js/code.js | 102 ++++++++++++++++++++----- resources/assets/js/pages/page-form.js | 78 ++++++++++++++++++- 2 files changed, 157 insertions(+), 23 deletions(-) diff --git a/resources/assets/js/code.js b/resources/assets/js/code.js index 020c38365..83cb664a1 100644 --- a/resources/assets/js/code.js +++ b/resources/assets/js/code.js @@ -52,31 +52,91 @@ const modeMap = { module.exports.highlight = function() { let codeBlocks = document.querySelectorAll('.page-content pre'); - for (let i = 0; i < codeBlocks.length; i++) { - let innerCodeElem = codeBlocks[i].querySelector('code[class^=language-]'); - let mode = ''; - if (innerCodeElem !== null) { - let langName = innerCodeElem.className.replace('language-', ''); - if (typeof modeMap[langName] !== 'undefined') mode = modeMap[langName]; - } - codeBlocks[i].innerHTML = codeBlocks[i].innerHTML.replace(//gi ,'\n'); - let content = codeBlocks[i].textContent; - console.log('MODE', mode); - - CodeMirror(function(elt) { - codeBlocks[i].parentNode.replaceChild(elt, codeBlocks[i]); - }, { - value: content, - mode: mode, - lineNumbers: true, - theme: 'base16-light', - readOnly: true - }); + highlightElem(codeBlocks[i]); } - }; +function highlightElem(elem) { + let innerCodeElem = elem.querySelector('code[class^=language-]'); + let mode = ''; + if (innerCodeElem !== null) { + let langName = innerCodeElem.className.replace('language-', ''); + if (typeof modeMap[langName] !== 'undefined') mode = modeMap[langName]; + } + elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); + let content = elem.textContent; + + CodeMirror(function(elt) { + elem.parentNode.replaceChild(elt, elem); + }, { + value: content, + mode: mode, + lineNumbers: true, + theme: 'base16-light', + readOnly: true + }); +} + +module.exports.highlightElem = highlightElem; + +module.exports.wysiwygView = function(elem) { + let doc = elem.ownerDocument; + elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); + let content = elem.textContent; + let newWrap = doc.createElement('div'); + let newTextArea = doc.createElement('textarea'); + + newWrap.className = 'CodeMirrorContainer'; + newTextArea.style.display = 'none'; + elem.parentNode.replaceChild(newWrap, elem); + + newWrap.appendChild(newTextArea); + newWrap.contentEditable = false; + newTextArea.textContent = content; + + let cm = CodeMirror(function(elt) { + newWrap.appendChild(elt); + }, { + value: content, + mode: '', + lineNumbers: true, + theme: 'base16-light', + readOnly: true + }); + setTimeout(() => { + cm.refresh(); + }, 300); + return newWrap; +}; + +// module.exports.wysiwygEditor = function(elem) { +// let doc = elem.ownerDocument; +// let newWrap = doc.createElement('div'); +// newWrap.className = 'CodeMirrorContainer'; +// let newTextArea = doc.createElement('textarea'); +// newTextArea.style.display = 'none'; +// elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); +// let content = elem.textContent; +// elem.parentNode.replaceChild(newWrap, elem); +// newWrap.appendChild(newTextArea); +// let cm = CodeMirror(function(elt) { +// newWrap.appendChild(elt); +// }, { +// value: content, +// mode: '', +// lineNumbers: true, +// theme: 'base16-light', +// readOnly: true +// }); +// cm.on('change', event => { +// newTextArea.innerText = cm.getValue(); +// }); +// setTimeout(() => { +// cm.refresh(); +// }, 300); +// }; + module.exports.markdownEditor = function(elem) { let content = elem.textContent; diff --git a/resources/assets/js/pages/page-form.js b/resources/assets/js/pages/page-form.js index 04951b174..871d2b528 100644 --- a/resources/assets/js/pages/page-form.js +++ b/resources/assets/js/pages/page-form.js @@ -1,5 +1,7 @@ "use strict"; +const Code = require('../code'); + /** * Handle pasting images from clipboard. * @param e - event @@ -60,13 +62,85 @@ function registerEditorShortcuts(editor) { editor.addShortcut('meta+shift+E', '', ['FormatBlock', false, 'code']); } + +function codePlugin() { + + function elemIsCodeBlock(elem) { + return elem.className === 'CodeMirrorContainer'; + } + + function showPopup(editor) { + let selectedNode = editor.selection.getNode(); + if (!elemIsCodeBlock(selectedNode)) { + return; + } + + let lang = selectedNode.hasAttribute('data-language') ? selectedNode.getAttribute('data-language') : ''; + let currentCode = selectedNode.querySelector('textarea').textContent; + console.log('SHOW POPUP'); + // TODO - Show custom editor + } + + window.tinymce.PluginManager.add('codeeditor', (editor, url) => { + + let $ = editor.$; + + editor.addButton('codeeditor', { + text: 'Code block', + icon: false, + onclick() { + showPopup(editor); + } + }); + + // Convert + editor.on('PreProcess', function (e) { + $('div.CodeMirrorContainer', e.node). + each((index, elem) => { + let $elem = $(elem); + let code = elem.querySelector('textarea').textContent; + + // $elem.attr('class', $.trim($elem.attr('class'))); + $elem.removeAttr('contentEditable'); + + $elem.empty().append('
').find('pre').first().append($('').each((index, elem) => {
+                    // Needs to be textContent since innerText produces BR:s
+                    elem.textContent = code;
+                }).attr('class', $elem.attr('class')));
+                console.log($elem[0].outerHTML);
+            });
+        });
+
+        editor.on('SetContent', function () {
+            let codeSamples = $('pre').filter((index, elem) => {
+                return elem.contentEditable !== "false";
+            });
+
+            if (codeSamples.length) {
+                editor.undoManager.transact(function () {
+                    codeSamples.each((index, elem) => {
+                        console.log(elem.textContent);
+                        let outerWrap = Code.wysiwygView(elem);
+                        outerWrap.addEventListener('dblclick', () => {
+                            showPopup(editor);
+                        })
+                    });
+                });
+            }
+        });
+
+    });
+}
+
 module.exports = function() {
+    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,
@@ -78,9 +152,9 @@ module.exports = function() {
         extended_valid_elements: 'pre[*]',
         automatic_uploads: false,
         valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]",
-        plugins: "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codesample",
+        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 codesample",
+        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 codeeditor",
         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"},

From 26e703a1cdb61be7da66e0967b17cec9b29f7c28 Mon Sep 17 00:00:00 2001
From: Shuma Yoshioka 
Date: Mon, 19 Jun 2017 00:02:09 +0900
Subject: [PATCH 04/74] translate activities.php

---
 resources/lang/ja/activities.php | 40 ++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 resources/lang/ja/activities.php

diff --git a/resources/lang/ja/activities.php b/resources/lang/ja/activities.php
new file mode 100644
index 000000000..b907e0c63
--- /dev/null
+++ b/resources/lang/ja/activities.php
@@ -0,0 +1,40 @@
+ 'がページを作成:',
+    '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'      => '並び順を変更しました',
+
+];

From 168c66815e10a16832d894762f0b4bb15dbf2a57 Mon Sep 17 00:00:00 2001
From: Shuma Yoshioka 
Date: Sat, 24 Jun 2017 20:44:45 +0900
Subject: [PATCH 05/74] add `ja` to settings

---
 resources/lang/en/settings.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php
index 31163e87e..4529b1978 100644
--- a/resources/lang/en/settings.php
+++ b/resources/lang/en/settings.php
@@ -121,6 +121,7 @@ return [
         'nl' => 'Nederlands',
         'pt_BR' => 'Português do Brasil',
         'sk' => 'Slovensky',
+        'ja' => '日本語',
     ]
     ///////////////////////////////////
 ];

From b8ebefd803696377fd585da89adf9d0c321f2596 Mon Sep 17 00:00:00 2001
From: Shuma Yoshioka 
Date: Sat, 24 Jun 2017 20:47:41 +0900
Subject: [PATCH 06/74] Translate components.php

---
 resources/lang/ja/components.php | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 resources/lang/ja/components.php

diff --git a/resources/lang/ja/components.php b/resources/lang/ja/components.php
new file mode 100644
index 000000000..89ed33ef3
--- /dev/null
+++ b/resources/lang/ja/components.php
@@ -0,0 +1,24 @@
+ '画像を選択',
+    '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' => '画像が削除されました'
+];

From 75eca03b0530a90775d9a646db639ff5ed4ca65b Mon Sep 17 00:00:00 2001
From: Shuma Yoshioka 
Date: Sat, 24 Jun 2017 20:49:06 +0900
Subject: [PATCH 07/74] Translate settings.php

---
 resources/lang/ja/settings.php | 112 +++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 resources/lang/ja/settings.php

diff --git a/resources/lang/ja/settings.php b/resources/lang/ja/settings.php
new file mode 100644
index 000000000..b4cf57aeb
--- /dev/null
+++ b/resources/lang/ja/settings.php
@@ -0,0 +1,112 @@
+ '設定',
+    'settings_save' => '設定を保存',
+    'settings_save_success' => '設定を保存しました',
+
+    /**
+     * App settings
+     */
+
+    'app_settings' => 'アプリケーション設定',
+    'app_name' => 'アプリケーション名',
+    'app_name_desc' => 'この名前はヘッダーやEメール内で表示されます。',
+    'app_name_header' => 'ヘッダーにアプリケーション名を表示する',
+    'app_public_viewing' => 'アプリケーションを公開する',
+    'app_secure_images' => '画像アップロード時のセキュリティを強化',
+    'app_secure_images_desc' => 'パフォーマンスの観点から、全ての画像が公開になっています。このオプションを有効にすると、画像URLの先頭にランダムで推測困難な文字列が追加され、アクセスを困難にします。',
+    'app_editor' => 'ページエディタ',
+    'app_editor_desc' => 'ここで選択されたエディタを全ユーザが使用します。',
+    'app_custom_html' => 'カスタムheadタグ',
+    'app_custom_html_desc' => 'スタイルシートやアナリティクスコード追加したい場合、ここを編集します。これはの最下部に挿入されます。',
+    'app_logo' => 'ロゴ',
+    'app_logo_desc' => '高さ43pxで表示されます。これを上回る場合、自動で縮小されます。',
+    'app_primary_color' => 'プライマリカラー',
+    'app_primary_color_desc' => '16進数カラーコードで入力します。空にした場合、デフォルトの色にリセットされます。',
+
+    /**
+     * Registration settings
+     */
+
+    'reg_settings' => '登録設定',
+    'reg_allow' => '新規登録を許可',
+    'reg_default_role' => '新規登録時のデフォルト役割',
+    'reg_confirm_email' => 'Eメール認証を必須にする',
+    'reg_confirm_email_desc' => 'ドメイン制限を有効にしている場合はEメール認証が必須となり、この項目は無視されます。',
+    'reg_confirm_restrict_domain' => 'ドメイン制限',
+    'reg_confirm_restrict_domain_desc' => '特定のドメインのみ登録できるようにする場合、以下にカンマ区切りで入力します。設定された場合、Eメール認証が必須になります。
登録後、ユーザは自由にEメールアドレスを変更できます。', + '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' => '256pxの正方形である必要があります。', + 'users_preferred_language' => '使用言語', + 'users_social_accounts' => 'ソーシャルアカウント', + 'users_social_accounts_info' => 'アカウントを接続すると、ログインが簡単になります。ここでアカウントの接続を解除すると、そのアカウントを経由したログインを禁止できます。接続解除後、各ソーシャルアカウントの設定にてこのアプリケーションへのアクセス許可を解除してください。', + 'users_social_connect' => 'アカウントを接続', + 'users_social_disconnect' => 'アカウントを接続解除', + 'users_social_connected' => '「:socialAccount」がプロフィールに接続されました。', + 'users_social_disconnected' => '「:socialAccount」がプロフィールから接続解除されました。' + +]; From 52010e5820e08e8b1ab2ce17bced210207220fca Mon Sep 17 00:00:00 2001 From: Shuma Yoshioka Date: Sat, 1 Jul 2017 16:29:28 +0900 Subject: [PATCH 08/74] Translate pagination.php --- resources/lang/ja/pagination.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 resources/lang/ja/pagination.php diff --git a/resources/lang/ja/pagination.php b/resources/lang/ja/pagination.php new file mode 100644 index 000000000..1ebcef722 --- /dev/null +++ b/resources/lang/ja/pagination.php @@ -0,0 +1,19 @@ + '« 前', + 'next' => '次 »', + +]; From b02052036619469ac3f7c92b39657bdc41bdac36 Mon Sep 17 00:00:00 2001 From: Shuma Yoshioka Date: Sat, 1 Jul 2017 16:29:35 +0900 Subject: [PATCH 09/74] Translate passwords.php --- resources/lang/ja/passwords.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 resources/lang/ja/passwords.php diff --git a/resources/lang/ja/passwords.php b/resources/lang/ja/passwords.php new file mode 100644 index 000000000..17c82e299 --- /dev/null +++ b/resources/lang/ja/passwords.php @@ -0,0 +1,22 @@ + 'パスワードは6文字以上である必要があります。', + 'user' => "このEメールアドレスに一致するユーザが見つかりませんでした。", + 'token' => 'このパスワードリセットトークンは無効です。', + 'sent' => 'パスワードリセットリンクを送信しました。', + 'reset' => 'パスワードはリセットされました。', + +]; From f10d3a85640575a56117ae8f4e9c4f9db74a61f2 Mon Sep 17 00:00:00 2001 From: Shuma Yoshioka Date: Sat, 1 Jul 2017 16:29:43 +0900 Subject: [PATCH 10/74] Translate validation.php --- resources/lang/ja/validation.php | 108 +++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 resources/lang/ja/validation.php diff --git a/resources/lang/ja/validation.php b/resources/lang/ja/validation.php new file mode 100644 index 000000000..e0fa3cb2c --- /dev/null +++ b/resources/lang/ja/validation.php @@ -0,0 +1,108 @@ + ':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は正しいEメールアドレスである必要があります。', + 'filled' => ':attributeは必須です。', + 'exists' => '選択された:attributeは不正です。', + 'image' => ':attributeは画像である必要があります。', + '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' => ':otherが:valueである場合、:attributeは必須です。', + 'required_with' => ':valuesが設定されている場合、:attributeは必須です。', + 'required_with_all' => ':valuesが設定されている場合、:attributeは必須です。', + 'required_without' => ':valuesが設定されていない場合、:attributeは必須です。', + 'required_without_all' => ':valuesが設定されていない場合、:attributeは必須です。', + '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' => [], + +]; From 60710e7fb4ec3973c7d4433088808603b553de0c Mon Sep 17 00:00:00 2001 From: Shuma Yoshioka Date: Sat, 1 Jul 2017 16:33:54 +0900 Subject: [PATCH 11/74] Translate auth.php --- resources/lang/ja/auth.php | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 resources/lang/ja/auth.php diff --git a/resources/lang/ja/auth.php b/resources/lang/ja/auth.php new file mode 100644 index 000000000..4d5aee8b3 --- /dev/null +++ b/resources/lang/ja/auth.php @@ -0,0 +1,76 @@ + 'この資格情報は登録されていません。', + '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' => 'このアカウントで使用するEメールアドレスを入力してください。', + 'create_account' => 'アカウント作成', + 'social_login' => 'SNSログイン', + 'social_registration' => 'SNS登録', + 'social_registration_text' => '他のサービスで登録 / ログインする', + + 'register_thanks' => '登録が完了しました!', + 'register_confirm' => 'メール内の確認ボタンを押して、:appNameへアクセスしてください。', + 'registrations_disabled' => '登録は現在停止中です。', + 'registration_email_domain_invalid' => 'このEmailドメインでの登録は許可されていません。', + 'register_success' => '登録が完了し、ログインできるようになりました!', + + + /** + * Password Reset + */ + 'reset_password' => 'パスワードリセット', + 'reset_password_send_instructions' => '以下にEメールアドレスを入力すると、パスワードリセットリンクが記載されたメールが送信されます。', + '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' => 'Eメールの確認が必要でしたが、システム上でEメールの送信ができませんでした。管理者に連絡し、Eメールが正しく設定されていることを確認してください。', + 'email_confirm_success' => 'Eメールアドレスが確認されました。', + 'email_confirm_resent' => '確認メールを再送信しました。受信トレイを確認してください。', + + 'email_not_confirmed' => 'Eメールアドレスが確認できていません', + 'email_not_confirmed_text' => 'Eメールアドレスの確認が完了していません。', + 'email_not_confirmed_click_link' => '登録時に受信したメールを確認し、確認リンクをクリックしてください。', + 'email_not_confirmed_resend' => 'Eメールが見つからない場合、以下のフォームから再送信してください。', + 'email_not_confirmed_resend_button' => '確認メールを再送信', +]; From 7bec70d429659e9c68c18df2c1d3cb10861bb72f Mon Sep 17 00:00:00 2001 From: Shuma Yoshioka Date: Sat, 1 Jul 2017 16:37:07 +0900 Subject: [PATCH 12/74] Translate common.php --- resources/lang/ja/common.php | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 resources/lang/ja/common.php diff --git a/resources/lang/ja/common.php b/resources/lang/ja/common.php new file mode 100644 index 000000000..383294880 --- /dev/null +++ b/resources/lang/ja/common.php @@ -0,0 +1,59 @@ + 'キャンセル', + 'confirm' => '確認', + 'back' => '戻る', + 'save' => '保存', + 'continue' => '続ける', + 'select' => '選択', + + /** + * Form Labels + */ + 'name' => '名称', + 'description' => '概要', + 'role' => '権限', + + /** + * Actions + */ + 'actions' => '実行', + 'view' => '表示', + 'create' => '作成', + 'update' => '更新', + 'edit' => '編集', + 'sort' => '並び順', + 'move' => '移動', + 'delete' => '削除', + 'search' => '検索', + 'search_clear' => '検索をクリア', + 'reset' => 'リセット', + 'remove' => '削除', + 'add' => '追加', + + + /** + * Misc + */ + 'deleted_user' => '削除済みユーザ', + 'no_activity' => '表示するアクティビティがありません', + 'no_items' => 'アイテムはありません', + 'back_to_top' => '上に戻る', + 'toggle_details' => '概要の表示切替', + + /** + * Header + */ + 'view_profile' => 'プロフィール表示', + 'edit_profile' => 'プロフィール編集', + + /** + * Email Content + */ + 'email_action_help' => '":actionText" をクリックできない場合、以下のURLをコピーしブラウザで開いてください:', + 'email_rights' => 'All rights reserved', +]; From 2d345fe45428c1d6ee9feb4d4272bfb61c52bae3 Mon Sep 17 00:00:00 2001 From: Shuma Yoshioka Date: Sat, 1 Jul 2017 16:38:20 +0900 Subject: [PATCH 13/74] Translate entities.php --- resources/lang/ja/entities.php | 236 +++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 resources/lang/ja/entities.php diff --git a/resources/lang/ja/entities.php b/resources/lang/ja/entities.php new file mode 100644 index 000000000..8d215516d --- /dev/null +++ b/resources/lang/ja/entities.php @@ -0,0 +1,236 @@ + '最近作成', + '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)', + 'x_pages' => ':countページ', + 'entity_select' => 'エンティティ選択', + 'images' => '画像', + 'my_recent_drafts' => '最近の下書き', + 'my_recently_viewed' => '閲覧履歴', + 'no_pages_viewed' => 'なにもページを閲覧していません', + 'no_pages_recently_created' => '最近作成されたページはありません', + 'no_pages_recently_updated' => '最近更新されたページはありません。', + 'export' => 'エクスポート', + 'export_html' => 'Webページ', + 'export_pdf' => 'PDF', + 'export_text' => 'テキストファイル', + + /** + * Permissions and restrictions + */ + 'permissions' => '権限', + 'permissions_intro' => 'この設定は各ユーザの役割よりも優先して適用されます。', + 'permissions_enable' => 'カスタム権限設定を有効にする', + 'permissions_save' => '権限を保存', + + /** + * Search + */ + 'search_results' => '検索結果', + 'search_total_results_found' => ':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' => 'Book', + 'books' => 'ブック', + 'books_empty' => 'まだブックは作成されていません', + 'books_popular' => '人気のブック', + 'books_recent' => '最近のブック', + 'books_popular_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' => 'チャプター', + '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' => 'ページ', + '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' => 'ページの権限を更新しました', + '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' => 'ファイルURL', + 'attachments_link_url_hint' => 'WebサイトまたはファイルへのURL', + 'attach' => '添付', + 'attachments_edit_file' => 'ファイルを編集', + 'attachments_edit_file_name' => 'ファイル名', + 'attachments_edit_drop_upload' => 'ファイルをドロップするか、クリックしてアップロード', + 'attachments_order_updated' => '添付ファイルの並び順が変更されました', + 'attachments_updated_success' => '添付ファイルが更新されました', + '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はブックを作成していません', +]; From b2b8706d052abad95b27eb289efb3e8d0e8e50e8 Mon Sep 17 00:00:00 2001 From: Shuma Yoshioka Date: Sat, 1 Jul 2017 16:38:43 +0900 Subject: [PATCH 14/74] Translate errors.php --- resources/lang/ja/errors.php | 70 ++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 resources/lang/ja/errors.php diff --git a/resources/lang/ja/errors.php b/resources/lang/ja/errors.php new file mode 100644 index 000000000..5905237fd --- /dev/null +++ b/resources/lang/ja/errors.php @@ -0,0 +1,70 @@ + 'リクエストされたページへの権限がありません。', + 'permissionJson' => '要求されたアクションを実行する権限がありません。', + + // Auth + 'error_user_exists_different_creds' => ':emailを持つユーザは既に存在しますが、資格情報が異なります。', + 'email_already_confirmed' => 'Eメールは既に確認済みです。ログインしてください。', + 'email_confirmation_invalid' => 'この確認トークンは無効か、または既に使用済みです。登録を再試行してください。', + 'email_confirmation_expired' => '確認トークンは有効期限切れです。確認メールを再送しました。', + 'ldap_fail_anonymous' => '匿名バインドを用いたLDAPアクセスに失敗しました', + 'ldap_fail_authed' => '識別名, パスワードを用いたLDAPアクセスに失敗しました', + 'ldap_extension_not_installed' => 'LDAP PHP extensionがインストールされていません', + '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が見つかりません。', + 'social_driver_not_configured' => 'あなたの:socialAccount設定は正しく構成されていません。', + + // System + 'path_not_writable' => 'ファイルパス :filePath へアップロードできませんでした。サーバ上での書き込みを許可してください。', + 'cannot_get_image_from_url' => ':url から画像を取得できませんでした。', + 'cannot_create_thumbs' => 'このサーバはサムネイルを作成できません。GD PHP extensionがインストールされていることを確認してください。', + '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' => 'この役割を登録時のデフォルトに設定することはできません', + + // Error pages + '404_page_not_found' => 'ページが見つかりません', + 'sorry_page_not_found' => 'ページを見つけることができませんでした。', + 'return_home' => 'ホームに戻る', + 'error_occurred' => 'エラーが発生しました', + 'app_down' => ':appNameは現在停止しています', + 'back_soon' => '回復までしばらくお待ちください。', +]; From 5f461c9796a6e6e642b96abcc13748fa81ee0d43 Mon Sep 17 00:00:00 2001 From: Shuma Yoshioka Date: Sat, 1 Jul 2017 16:29:12 +0900 Subject: [PATCH 15/74] Add `ja` locale to config --- config/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/app.php b/config/app.php index 54cdca21b..48348f837 100644 --- a/config/app.php +++ b/config/app.php @@ -58,7 +58,7 @@ return [ */ 'locale' => env('APP_LANG', 'en'), - 'locales' => ['en', 'de', 'es', 'fr', 'nl', 'pt_BR', 'sk'], + 'locales' => ['en', 'de', 'es', 'fr', 'nl', 'pt_BR', 'sk', 'ja'], /* |-------------------------------------------------------------------------- From 968e7b8b72dba148166253c00e6b0d09b714888f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 1 Jul 2017 13:23:46 +0100 Subject: [PATCH 16/74] Finished off main functionality of custom tinymce code editor --- resources/assets/js/code.js | 84 +++++++++++-------- resources/assets/js/pages/page-form.js | 69 ++++++++++----- resources/assets/js/vues/code-editor.js | 39 +++++++++ resources/assets/js/vues/vues.js | 5 +- resources/assets/sass/_codemirror.scss | 4 + resources/assets/sass/_components.scss | 4 + resources/assets/sass/_text.scss | 16 ++++ resources/lang/en/components.php | 10 ++- .../views/components/code-editor.blade.php | 29 +++++++ resources/views/pages/edit.blade.php | 1 + 10 files changed, 204 insertions(+), 57 deletions(-) create mode 100644 resources/assets/js/vues/code-editor.js create mode 100644 resources/views/components/code-editor.blade.php diff --git a/resources/assets/js/code.js b/resources/assets/js/code.js index 83cb664a1..ef6bca2e2 100644 --- a/resources/assets/js/code.js +++ b/resources/assets/js/code.js @@ -62,7 +62,7 @@ function highlightElem(elem) { let mode = ''; if (innerCodeElem !== null) { let langName = innerCodeElem.className.replace('language-', ''); - if (typeof modeMap[langName] !== 'undefined') mode = modeMap[langName]; + mode = getMode(langName); } elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); let content = elem.textContent; @@ -78,16 +78,35 @@ function highlightElem(elem) { }); } +/** + * Search for a codemirror code based off a user suggestion + * @param suggestion + * @returns {string} + */ +function getMode(suggestion) { + suggestion = suggestion.trim().replace(/^\./g, '').toLowerCase(); + return (typeof modeMap[suggestion] !== 'undefined') ? modeMap[suggestion] : ''; +} + module.exports.highlightElem = highlightElem; module.exports.wysiwygView = function(elem) { let doc = elem.ownerDocument; + let codeElem = elem.querySelector('code'); + + let lang = (elem.className || '').replace('language-', ''); + if (lang === '' && codeElem) { + console.log(codeElem.className); + lang = (codeElem.className || '').replace('language-', '') + } + elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); let content = elem.textContent; let newWrap = doc.createElement('div'); let newTextArea = doc.createElement('textarea'); newWrap.className = 'CodeMirrorContainer'; + newWrap.setAttribute('data-lang', lang); newTextArea.style.display = 'none'; elem.parentNode.replaceChild(newWrap, elem); @@ -99,7 +118,7 @@ module.exports.wysiwygView = function(elem) { newWrap.appendChild(elt); }, { value: content, - mode: '', + mode: getMode(lang), lineNumbers: true, theme: 'base16-light', readOnly: true @@ -107,50 +126,47 @@ module.exports.wysiwygView = function(elem) { setTimeout(() => { cm.refresh(); }, 300); - return newWrap; + return {wrap: newWrap, editor: cm}; }; -// module.exports.wysiwygEditor = function(elem) { -// let doc = elem.ownerDocument; -// let newWrap = doc.createElement('div'); -// newWrap.className = 'CodeMirrorContainer'; -// let newTextArea = doc.createElement('textarea'); -// newTextArea.style.display = 'none'; -// elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); -// let content = elem.textContent; -// elem.parentNode.replaceChild(newWrap, elem); -// newWrap.appendChild(newTextArea); -// let cm = CodeMirror(function(elt) { -// newWrap.appendChild(elt); -// }, { -// value: content, -// mode: '', -// lineNumbers: true, -// theme: 'base16-light', -// readOnly: true -// }); -// cm.on('change', event => { -// newTextArea.innerText = cm.getValue(); -// }); -// setTimeout(() => { -// cm.refresh(); -// }, 300); -// }; - -module.exports.markdownEditor = function(elem) { +module.exports.popupEditor = function(elem, modeSuggestion) { let content = elem.textContent; - let cm = CodeMirror(function(elt) { + return CodeMirror(function(elt) { elem.parentNode.insertBefore(elt, elem); elem.style.display = 'none'; }, { value: content, - mode: "markdown", + mode: getMode(modeSuggestion), + lineNumbers: true, + theme: 'base16-light', + lineWrapping: true + }); +}; + +module.exports.setMode = function(cmInstance, modeSuggestion) { + cmInstance.setOption('mode', getMode(modeSuggestion)); +}; +module.exports.setContent = function(cmInstance, codeContent) { + cmInstance.setValue(codeContent); + setTimeout(() => { + cmInstance.refresh(); + }, 10); +}; + +module.exports.markdownEditor = function(elem) { + let content = elem.textContent; + + return CodeMirror(function (elt) { + elem.parentNode.insertBefore(elt, elem); + elem.style.display = 'none'; + }, { + value: content, + mode: "markdown", lineNumbers: true, theme: 'base16-light', lineWrapping: true }); - return cm; }; diff --git a/resources/assets/js/pages/page-form.js b/resources/assets/js/pages/page-form.js index 871d2b528..a443213bf 100644 --- a/resources/assets/js/pages/page-form.js +++ b/resources/assets/js/pages/page-form.js @@ -58,11 +58,14 @@ function registerEditorShortcuts(editor) { // Other block shortcuts editor.addShortcut('meta+q', '', ['FormatBlock', false, 'blockquote']); editor.addShortcut('meta+d', '', ['FormatBlock', false, 'p']); - editor.addShortcut('meta+e', '', ['FormatBlock', false, 'pre']); + editor.addShortcut('meta+e', '', ['codeeditor', false, 'pre']); editor.addShortcut('meta+shift+E', '', ['FormatBlock', false, 'code']); } +/** + * Create and enable our custom code plugin + */ function codePlugin() { function elemIsCodeBlock(elem) { @@ -71,14 +74,35 @@ function codePlugin() { function showPopup(editor) { let selectedNode = editor.selection.getNode(); + if (!elemIsCodeBlock(selectedNode)) { + let providedCode = editor.selection.getNode().textContent; + window.vues['code-editor'].open(providedCode, '', (code, lang) => { + let wrap = document.createElement('div'); + wrap.innerHTML = `
`; + wrap.querySelector('code').innerText = code; + editor.formatter.toggle('pre'); + let node = editor.selection.getNode(); + editor.dom.setHTML(node, wrap.querySelector('pre').innerHTML); + editor.fire('SetContent'); + }); return; } - let lang = selectedNode.hasAttribute('data-language') ? selectedNode.getAttribute('data-language') : ''; + let lang = selectedNode.hasAttribute('data-lang') ? selectedNode.getAttribute('data-lang') : ''; let currentCode = selectedNode.querySelector('textarea').textContent; - console.log('SHOW POPUP'); - // TODO - Show custom editor + + window.vues['code-editor'].open(currentCode, lang, (code, lang) => { + let editorElem = selectedNode.querySelector('.CodeMirror'); + let cmInstance = editorElem.CodeMirror; + if (cmInstance) { + Code.setContent(cmInstance, code); + Code.setMode(cmInstance, lang); + } + let textArea = selectedNode.querySelector('textarea'); + if (textArea) textArea.textContent = code; + selectedNode.setAttribute('data-lang', lang); + }); } window.tinymce.PluginManager.add('codeeditor', (editor, url) => { @@ -88,9 +112,11 @@ function codePlugin() { editor.addButton('codeeditor', { text: 'Code block', icon: false, - onclick() { - showPopup(editor); - } + cmd: 'codeeditor' + }); + + editor.addCommand('codeeditor', () => { + showPopup(editor); }); // Convert @@ -98,32 +124,33 @@ function codePlugin() { $('div.CodeMirrorContainer', e.node). each((index, elem) => { let $elem = $(elem); - let code = elem.querySelector('textarea').textContent; + let textArea = elem.querySelector('textarea'); + let code = textArea.textContent; + let lang = elem.getAttribute('data-lang'); // $elem.attr('class', $.trim($elem.attr('class'))); $elem.removeAttr('contentEditable'); - - $elem.empty().append('
').find('pre').first().append($('').each((index, elem) => {
+                let $pre = $('
');
+                $pre.append($('').each((index, elem) => {
                     // Needs to be textContent since innerText produces BR:s
                     elem.textContent = code;
-                }).attr('class', $elem.attr('class')));
-                console.log($elem[0].outerHTML);
+                }).attr('class', `language-${lang}`));
+                $elem.replaceWith($pre);
             });
         });
 
         editor.on('SetContent', function () {
-            let codeSamples = $('pre').filter((index, elem) => {
+            let codeSamples = $('body > pre').filter((index, elem) => {
                 return elem.contentEditable !== "false";
             });
 
             if (codeSamples.length) {
                 editor.undoManager.transact(function () {
                     codeSamples.each((index, elem) => {
-                        console.log(elem.textContent);
-                        let outerWrap = Code.wysiwygView(elem);
-                        outerWrap.addEventListener('dblclick', () => {
-                            showPopup(editor);
-                        })
+                        let editDetails = Code.wysiwygView(elem);
+                        editDetails.wrap.addEventListener('dblclick', () => {
+                            showPopup(editor, editDetails.wrap, editDetails.editor);
+                        });
                     });
                 });
             }
@@ -154,7 +181,7 @@ module.exports = function() {
         valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]",
         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 codeeditor",
+        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"},
@@ -163,14 +190,14 @@ module.exports = function() {
             {title: "Header Tiny", format: "h5"},
             {title: "Paragraph", format: "p", exact: true, classes: ''},
             {title: "Blockquote", format: "blockquote"},
-            {title: "Code Block", icon: "code", format: "pre"},
+            {title: "Code Block", icon: "code", cmd: 'codeeditor'},
             {title: "Inline Code", icon: "code", inline: "code"},
             {title: "Callouts", items: [
                 {title: "Success", block: 'p', exact: true, attributes : {'class' : 'callout success'}},
                 {title: "Info", block: 'p', exact: true, attributes : {'class' : 'callout info'}},
                 {title: "Warning", block: 'p', exact: true, attributes : {'class' : 'callout warning'}},
                 {title: "Danger", block: 'p', exact: true, attributes : {'class' : 'callout danger'}}
-            ]}
+            ]},
         ],
         style_formats_merge: false,
         formats: {
diff --git a/resources/assets/js/vues/code-editor.js b/resources/assets/js/vues/code-editor.js
new file mode 100644
index 000000000..87bb28cce
--- /dev/null
+++ b/resources/assets/js/vues/code-editor.js
@@ -0,0 +1,39 @@
+const codeLib = require('../code');
+
+const methods = {
+    show() {
+        if (!this.editor) this.editor = codeLib.popupEditor(this.$refs.editor, this.language);
+        this.$refs.overlay.style.display = 'flex';
+    },
+    hide() {
+        this.$refs.overlay.style.display = 'none';
+    },
+    updateEditorMode(language) {
+        codeLib.setMode(this.editor, language);
+    },
+    open(code, language, callback) {
+        this.show();
+        this.updateEditorMode(language);
+        this.language = language;
+        codeLib.setContent(this.editor, code);
+        this.code = code;
+        this.callback = callback;
+    },
+    save() {
+        if (!this.callback) return;
+        this.callback(this.editor.getValue(), this.language);
+        this.hide();
+    }
+};
+
+const data = {
+    editor: null,
+    language: '',
+    code: '',
+    callback: null
+};
+
+module.exports = {
+    methods,
+    data
+};
\ No newline at end of file
diff --git a/resources/assets/js/vues/vues.js b/resources/assets/js/vues/vues.js
index 8cc1dd656..31d833bfb 100644
--- a/resources/assets/js/vues/vues.js
+++ b/resources/assets/js/vues/vues.js
@@ -7,12 +7,15 @@ function exists(id) {
 let vueMapping = {
     'search-system': require('./search'),
     'entity-dashboard': require('./entity-search'),
+    'code-editor': require('./code-editor')
 };
 
+window.vues = {};
+
 Object.keys(vueMapping).forEach(id => {
     if (exists(id)) {
         let config = vueMapping[id];
         config.el = '#' + id;
-        new Vue(config);
+        window.vues[id] = new Vue(config);
     }
 });
\ No newline at end of file
diff --git a/resources/assets/sass/_codemirror.scss b/resources/assets/sass/_codemirror.scss
index 9f9e38f55..bd85218a5 100644
--- a/resources/assets/sass/_codemirror.scss
+++ b/resources/assets/sass/_codemirror.scss
@@ -248,6 +248,10 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
   -webkit-tap-highlight-color: transparent;
   -webkit-font-variant-ligatures: contextual;
   font-variant-ligatures: contextual;
+  &:after {
+    content: none;
+    display: none;
+  }
 }
 .CodeMirror-wrap pre {
   word-wrap: break-word;
diff --git a/resources/assets/sass/_components.scss b/resources/assets/sass/_components.scss
index 5328057d9..f45db84b7 100644
--- a/resources/assets/sass/_components.scss
+++ b/resources/assets/sass/_components.scss
@@ -466,4 +466,8 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 
 .image-picker .none {
   display: none;
+}
+
+#code-editor .CodeMirror {
+  height: 400px;
 }
\ No newline at end of file
diff --git a/resources/assets/sass/_text.scss b/resources/assets/sass/_text.scss
index 4eaa492e7..ccef2a70f 100644
--- a/resources/assets/sass/_text.scss
+++ b/resources/assets/sass/_text.scss
@@ -135,6 +135,21 @@ pre {
   font-size: 12px;
   background-color: #f5f5f5;
   border: 1px solid #DDD;
+  padding-left: 31px;
+  position: relative;
+  padding-top: 3px;
+  padding-bottom: 3px;
+  &:after {
+    content: '';
+    display: block;
+    position: absolute;
+    top: 0;
+    width: 29px;
+    left: 0;
+    background-color: #f5f5f5;
+    height: 100%;
+    border-right: 1px solid #DDD;
+  }
 }
 
 
@@ -182,6 +197,7 @@ pre code {
   border: 0;
   font-size: 1em;
   display: block;
+  line-height: 1.6;
 }
 /*
  * Text colors
diff --git a/resources/lang/en/components.php b/resources/lang/en/components.php
index b9108702a..334502d05 100644
--- a/resources/lang/en/components.php
+++ b/resources/lang/en/components.php
@@ -20,5 +20,13 @@ return [
     'image_preview' => 'Image Preview',
     'image_upload_success' => 'Image uploaded successfully',
     'image_update_success' => 'Image details successfully updated',
-    'image_delete_success' => 'Image successfully deleted'
+    'image_delete_success' => 'Image successfully deleted',
+
+    /**
+     * Code editor
+     */
+    'code_editor' => 'Edit Code',
+    'code_language' => 'Code Language',
+    'code_content' => 'Code Content',
+    'code_save' => 'Save Code',
 ];
\ No newline at end of file
diff --git a/resources/views/components/code-editor.blade.php b/resources/views/components/code-editor.blade.php
new file mode 100644
index 000000000..23deaad99
--- /dev/null
+++ b/resources/views/components/code-editor.blade.php
@@ -0,0 +1,29 @@
+
+
+ +
+
\ No newline at end of file diff --git a/resources/views/pages/edit.blade.php b/resources/views/pages/edit.blade.php index 5ab25d1cc..6de47aaf1 100644 --- a/resources/views/pages/edit.blade.php +++ b/resources/views/pages/edit.blade.php @@ -21,6 +21,7 @@ @include('components.image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) + @include('components.code-editor') @include('components.entity-selector-popup') @stop \ No newline at end of file From a94844b6b756f6ef5e928b05f41a90a734541b89 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 1 Jul 2017 15:38:11 +0100 Subject: [PATCH 17/74] Fixed code block selection and drag/drop issues --- resources/assets/js/code.js | 1 - resources/assets/js/pages/page-form.js | 63 ++++++++++++++++---------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/resources/assets/js/code.js b/resources/assets/js/code.js index ef6bca2e2..24d520b76 100644 --- a/resources/assets/js/code.js +++ b/resources/assets/js/code.js @@ -96,7 +96,6 @@ module.exports.wysiwygView = function(elem) { let lang = (elem.className || '').replace('language-', ''); if (lang === '' && codeElem) { - console.log(codeElem.className); lang = (codeElem.className || '').replace('language-', '') } diff --git a/resources/assets/js/pages/page-form.js b/resources/assets/js/pages/page-form.js index a443213bf..9b3c90a28 100644 --- a/resources/assets/js/pages/page-form.js +++ b/resources/assets/js/pages/page-form.js @@ -74,6 +74,7 @@ function codePlugin() { function showPopup(editor) { let selectedNode = editor.selection.getNode(); + console.log('show ppoe'); if (!elemIsCodeBlock(selectedNode)) { let providedCode = editor.selection.getNode().textContent; @@ -81,6 +82,7 @@ function codePlugin() { let wrap = document.createElement('div'); wrap.innerHTML = `
`; wrap.querySelector('code').innerText = code; + editor.formatter.toggle('pre'); let node = editor.selection.getNode(); editor.dom.setHTML(node, wrap.querySelector('pre').innerHTML); @@ -105,6 +107,20 @@ function codePlugin() { }); } + function codeMirrorContainerToPre($codeMirrorContainer) { + let textArea = $codeMirrorContainer[0].querySelector('textarea'); + let code = textArea.textContent; + let lang = $codeMirrorContainer[0].getAttribute('data-lang'); + + $codeMirrorContainer.removeAttr('contentEditable'); + let $pre = $('
');
+        $pre.append($('').each((index, elem) => {
+            // Needs to be textContent since innerText produces BR:s
+            elem.textContent = code;
+        }).attr('class', `language-${lang}`));
+        $codeMirrorContainer.replaceWith($pre);
+    }
+
     window.tinymce.PluginManager.add('codeeditor', (editor, url) => {
 
         let $ = editor.$;
@@ -124,36 +140,36 @@ function codePlugin() {
             $('div.CodeMirrorContainer', e.node).
             each((index, elem) => {
                 let $elem = $(elem);
-                let textArea = elem.querySelector('textarea');
-                let code = textArea.textContent;
-                let lang = elem.getAttribute('data-lang');
-
-                // $elem.attr('class', $.trim($elem.attr('class')));
-                $elem.removeAttr('contentEditable');
-                let $pre = $('
');
-                $pre.append($('').each((index, elem) => {
-                    // Needs to be textContent since innerText produces BR:s
-                    elem.textContent = code;
-                }).attr('class', `language-${lang}`));
-                $elem.replaceWith($pre);
+                codeMirrorContainerToPre($elem);
             });
         });
 
+        editor.on('dblclick', event => {
+            let selectedNode = editor.selection.getNode();
+            if (!elemIsCodeBlock(selectedNode)) return;
+            showPopup(editor);
+        });
+
         editor.on('SetContent', function () {
+
+            // Recover broken codemirror instances
+            $('.CodeMirrorContainer').filter((index ,elem) => {
+                return typeof elem.querySelector('.CodeMirror').CodeMirror === 'undefined';
+            }).each((index, elem) => {
+                console.log('COVERT');
+                codeMirrorContainerToPre($(elem));
+            });
+
             let codeSamples = $('body > pre').filter((index, elem) => {
                 return elem.contentEditable !== "false";
             });
 
-            if (codeSamples.length) {
-                editor.undoManager.transact(function () {
-                    codeSamples.each((index, elem) => {
-                        let editDetails = Code.wysiwygView(elem);
-                        editDetails.wrap.addEventListener('dblclick', () => {
-                            showPopup(editor, editDetails.wrap, editDetails.editor);
-                        });
-                    });
+            if (!codeSamples.length) return;
+            editor.undoManager.transact(function () {
+                codeSamples.each((index, elem) => {
+                    Code.wysiwygView(elem);
                 });
-            }
+            });
         });
 
     });
@@ -178,7 +194,7 @@ module.exports = function() {
         paste_data_images: false,
         extended_valid_elements: 'pre[*]',
         automatic_uploads: false,
-        valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]",
+        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",
@@ -190,7 +206,7 @@ module.exports = function() {
             {title: "Header Tiny", format: "h5"},
             {title: "Paragraph", format: "p", exact: true, classes: ''},
             {title: "Blockquote", format: "blockquote"},
-            {title: "Code Block", icon: "code", cmd: 'codeeditor'},
+            {title: "Code Block", icon: "code", cmd: 'codeeditor', format: 'codeeditor'},
             {title: "Inline Code", icon: "code", inline: "code"},
             {title: "Callouts", items: [
                 {title: "Success", block: 'p', exact: true, attributes : {'class' : 'callout success'}},
@@ -201,6 +217,7 @@ module.exports = function() {
         ],
         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'},

From de6d8a811c1c5731e1edb67e2ed541fa1ada4bc7 Mon Sep 17 00:00:00 2001
From: Dan Brown 
Date: Sat, 1 Jul 2017 15:50:28 +0100
Subject: [PATCH 18/74] Added quick lang-selection options to code editor

---
 resources/assets/js/vues/code-editor.js       |  4 ++++
 resources/assets/sass/_components.scss        |  9 ++++++++
 .../views/components/code-editor.blade.php    | 22 +++++++++++++++++++
 3 files changed, 35 insertions(+)

diff --git a/resources/assets/js/vues/code-editor.js b/resources/assets/js/vues/code-editor.js
index 87bb28cce..35a98cc77 100644
--- a/resources/assets/js/vues/code-editor.js
+++ b/resources/assets/js/vues/code-editor.js
@@ -11,6 +11,10 @@ const methods = {
     updateEditorMode(language) {
         codeLib.setMode(this.editor, language);
     },
+    updateLanguage(lang) {
+        this.language = lang;
+        this.updateEditorMode(lang);
+    },
     open(code, language, callback) {
         this.show();
         this.updateEditorMode(language);
diff --git a/resources/assets/sass/_components.scss b/resources/assets/sass/_components.scss
index f45db84b7..12babae73 100644
--- a/resources/assets/sass/_components.scss
+++ b/resources/assets/sass/_components.scss
@@ -470,4 +470,13 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 
 #code-editor .CodeMirror {
   height: 400px;
+}
+
+#code-editor .lang-options {
+  max-width: 400px;
+  margin-bottom: $-s;
+  a {
+    margin-right: $-xs;
+    text-decoration: underline;
+  }
 }
\ No newline at end of file
diff --git a/resources/views/components/code-editor.blade.php b/resources/views/components/code-editor.blade.php
index 23deaad99..5a385ef49 100644
--- a/resources/views/components/code-editor.blade.php
+++ b/resources/views/components/code-editor.blade.php
@@ -10,6 +10,28 @@
             
+
+ + CSS + C + C++ + C# + Go + HTML + Java + JavaScript + JSON + PHP + MarkDown + Nginx + Python + Ruby + Shell/Bash + SQL + XML + YAML + +
From d5d83da7665a33f643cf17e09f984b10099ccd7f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 1 Jul 2017 16:10:52 +0100 Subject: [PATCH 19/74] Added diff and sh code types Verified changes to ensure fixes #296. --- resources/assets/js/code.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/assets/js/code.js b/resources/assets/js/code.js index 24d520b76..777baf81d 100644 --- a/resources/assets/js/code.js +++ b/resources/assets/js/code.js @@ -1,5 +1,6 @@ require('codemirror/mode/css/css'); require('codemirror/mode/clike/clike'); +require('codemirror/mode/diff/diff'); require('codemirror/mode/go/go'); require('codemirror/mode/htmlmixed/htmlmixed'); require('codemirror/mode/javascript/javascript'); @@ -26,6 +27,7 @@ const modeMap = { 'c++': 'clike', 'c#': 'clike', csharp: 'clike', + diff: 'diff', go: 'go', html: 'htmlmixed', javascript: 'javascript', @@ -42,6 +44,7 @@ const modeMap = { ruby: 'ruby', rb: 'ruby', shell: 'shell', + sh: 'shell', bash: 'shell', toml: 'toml', sql: 'sql', From cbff801aec1e69a49705cbf70f6c2c5b132e7efb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Jul 2017 15:40:42 +0100 Subject: [PATCH 20/74] Added test to cover f99c8ff. Closes #409 --- tests/Permissions/RolesTest.php | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/Permissions/RolesTest.php b/tests/Permissions/RolesTest.php index 83d1b98a8..d0e42c6ee 100644 --- a/tests/Permissions/RolesTest.php +++ b/tests/Permissions/RolesTest.php @@ -1,7 +1,10 @@ see('Cannot be deleted'); } - - public function test_image_delete_own_permission() { $this->giveUserPermissions($this->user, ['image-update-all']); @@ -620,4 +621,22 @@ class RolesTest extends BrowserKitTest ->dontSeeInDatabase('images', ['id' => $image->id]); } + public function test_role_permission_removal() + { + // To cover issue fixed in f99c8ff99aee9beb8c692f36d4b84dc6e651e50a. + $page = Page::first(); + $viewerRole = \BookStack\Role::getRole('viewer'); + $viewer = $this->getViewer(); + $this->actingAs($viewer)->visit($page->getUrl())->assertResponseOk(); + + $this->asAdmin()->put('/settings/roles/' . $viewerRole->id, [ + 'display_name' => $viewerRole->display_name, + 'description' => $viewerRole->description, + 'permission' => [] + ])->assertResponseStatus(302); + + $this->expectException(HttpException::class); + $this->actingAs($viewer)->visit($page->getUrl())->assertResponseStatus(404); + } + } From 4db2c274e21fb4a3900f057d3ff9d5d7f09b65be Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Jul 2017 15:59:40 +0100 Subject: [PATCH 21/74] Prevent empty-state actions visible without permission. Fixes #411 --- resources/views/books/show.blade.php | 6 ++++++ tests/BrowserKitTest.php | 11 +++++++++++ tests/Permissions/RolesTest.php | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php index adfec4525..ddbe7a0a4 100644 --- a/resources/views/books/show.blade.php +++ b/resources/views/books/show.blade.php @@ -72,9 +72,15 @@ @else

{{ trans('entities.books_empty_contents') }}

+ @if(userCan('page-create', $book)) {{ trans('entities.books_empty_create_page') }} + @endif + @if(userCan('page-create', $book) && userCan('chapter-create', $book))   -{{ trans('entities.books_empty_or') }}-    + @endif + @if(userCan('chapter-create', $book)) {{ trans('entities.books_empty_add_chapter') }} + @endif


@endif diff --git a/tests/BrowserKitTest.php b/tests/BrowserKitTest.php index c665bfc23..98259dea9 100644 --- a/tests/BrowserKitTest.php +++ b/tests/BrowserKitTest.php @@ -1,5 +1,6 @@ app[PermissionService::class]; + $restrictionService->buildJointPermissionsForEntity($entity); + } + /** * Quick way to create a new user * @param array $attributes diff --git a/tests/Permissions/RolesTest.php b/tests/Permissions/RolesTest.php index d0e42c6ee..eda5d092a 100644 --- a/tests/Permissions/RolesTest.php +++ b/tests/Permissions/RolesTest.php @@ -639,4 +639,22 @@ class RolesTest extends BrowserKitTest $this->actingAs($viewer)->visit($page->getUrl())->assertResponseStatus(404); } + public function test_empty_state_actions_not_visible_without_permission() + { + $admin = $this->getAdmin(); + // Book links + $book = factory(\BookStack\Book::class)->create(['created_by' => $admin->id, 'updated_by' => $admin->id]); + $this->updateEntityPermissions($book); + $this->actingAs($this->getViewer())->visit($book->getUrl()) + ->dontSee('Create a new page') + ->dontSee('Add a chapter'); + + // Chapter links + $chapter = factory(\BookStack\Chapter::class)->create(['created_by' => $admin->id, 'updated_by' => $admin->id, 'book_id' => $book->id]); + $this->updateEntityPermissions($chapter); + $this->actingAs($this->getViewer())->visit($chapter->getUrl()) + ->dontSee('Create a new page') + ->dontSee('Sort the current book'); + } + } From 005f0eb4fcfc7b3f9239bc094204d9ba65d0145b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Jul 2017 17:20:05 +0100 Subject: [PATCH 22/74] Updated default encoding and added conversion migration. Also updated how DB port is defined so that the DB_PORT env var can be used or it can be take from the host name. Fixes #405 --- app/Providers/AppServiceProvider.php | 3 ++ config/database.php | 15 ++++-- ...02_152834_update_db_encoding_to_ut8mb4.php | 46 +++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 database/migrations/2017_07_02_152834_update_db_encoding_to_ut8mb4.php diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 49cc15dd6..ef3ee6c48 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -23,6 +23,9 @@ class AppServiceProvider extends ServiceProvider \Blade::directive('icon', function($expression) { return ""; }); + + // Allow longer string lengths after upgrade to utf8mb4 + \Schema::defaultStringLength(191); } /** diff --git a/config/database.php b/config/database.php index 92c768245..64dc89864 100644 --- a/config/database.php +++ b/config/database.php @@ -16,6 +16,14 @@ if (env('REDIS_SERVERS', false)) { } } +$mysql_host = env('DB_HOST', 'localhost'); +$mysql_host_exploded = explode(':', $mysql_host); +$mysql_port = env('DB_PORT', 3306); +if (count($mysql_host_exploded) > 0) { + $mysql_host = $mysql_host_exploded[0]; + $mysql_port = intval($mysql_host_exploded[1]); +} + return [ /* @@ -70,12 +78,13 @@ return [ 'mysql' => [ 'driver' => 'mysql', - 'host' => env('DB_HOST', 'localhost'), + 'host' => $mysql_host, 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', + 'port' => $mysql_port, + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => false, ], diff --git a/database/migrations/2017_07_02_152834_update_db_encoding_to_ut8mb4.php b/database/migrations/2017_07_02_152834_update_db_encoding_to_ut8mb4.php new file mode 100644 index 000000000..8d06d92b1 --- /dev/null +++ b/database/migrations/2017_07_02_152834_update_db_encoding_to_ut8mb4.php @@ -0,0 +1,46 @@ +setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + $pdo->exec('ALTER DATABASE '.$database.' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'); + $key = 'Tables_in_' . $database; + foreach ($tables as $table) { + $tableName = $table->$key; + $pdo->exec('ALTER TABLE '.$tableName.' CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $database = DB::getDatabaseName(); + $tables = DB::select('SHOW TABLES'); + $pdo = DB::getPdo(); + $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + $pdo->exec('ALTER DATABASE '.$database.' CHARACTER SET utf8 COLLATE utf8_unicode_ci'); + $key = 'Tables_in_' . $database; + foreach ($tables as $table) { + $tableName = $table->$key; + $pdo->exec('ALTER TABLE '.$tableName.' CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci'); + } + } +} From f101e4f010e5744c6cb3651ed9f393448eb2d5ec Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Jul 2017 17:34:32 +0100 Subject: [PATCH 23/74] Fixed quoting db/table names in encoding migration. Also fixed incorrect if statement in db config. --- config/database.php | 2 +- .../2017_07_02_152834_update_db_encoding_to_ut8mb4.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/database.php b/config/database.php index 64dc89864..3883b5868 100644 --- a/config/database.php +++ b/config/database.php @@ -19,7 +19,7 @@ if (env('REDIS_SERVERS', false)) { $mysql_host = env('DB_HOST', 'localhost'); $mysql_host_exploded = explode(':', $mysql_host); $mysql_port = env('DB_PORT', 3306); -if (count($mysql_host_exploded) > 0) { +if (count($mysql_host_exploded) > 1) { $mysql_host = $mysql_host_exploded[0]; $mysql_port = intval($mysql_host_exploded[1]); } diff --git a/database/migrations/2017_07_02_152834_update_db_encoding_to_ut8mb4.php b/database/migrations/2017_07_02_152834_update_db_encoding_to_ut8mb4.php index 8d06d92b1..550c95826 100644 --- a/database/migrations/2017_07_02_152834_update_db_encoding_to_ut8mb4.php +++ b/database/migrations/2017_07_02_152834_update_db_encoding_to_ut8mb4.php @@ -17,11 +17,11 @@ class UpdateDbEncodingToUt8mb4 extends Migration $tables = DB::select('SHOW TABLES'); $pdo = DB::getPdo(); $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - $pdo->exec('ALTER DATABASE '.$database.' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'); + $pdo->exec('ALTER DATABASE `'.$database.'` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'); $key = 'Tables_in_' . $database; foreach ($tables as $table) { $tableName = $table->$key; - $pdo->exec('ALTER TABLE '.$tableName.' CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'); + $pdo->exec('ALTER TABLE `'.$tableName.'` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'); } } @@ -36,11 +36,11 @@ class UpdateDbEncodingToUt8mb4 extends Migration $tables = DB::select('SHOW TABLES'); $pdo = DB::getPdo(); $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - $pdo->exec('ALTER DATABASE '.$database.' CHARACTER SET utf8 COLLATE utf8_unicode_ci'); + $pdo->exec('ALTER DATABASE `'.$database.'` CHARACTER SET utf8 COLLATE utf8_unicode_ci'); $key = 'Tables_in_' . $database; foreach ($tables as $table) { $tableName = $table->$key; - $pdo->exec('ALTER TABLE '.$tableName.' CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci'); + $pdo->exec('ALTER TABLE `'.$tableName.'` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci'); } } } From 69c50b9b48eeb230a7f65ad64333cce3ca3c0dcf Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Jul 2017 19:35:13 +0100 Subject: [PATCH 24/74] Migrated markdown editor actions to new cm editor --- resources/assets/js/code.js | 6 +- resources/assets/js/controllers.js | 10 +- resources/assets/js/directives.js | 255 +++++++++++++---------------- resources/assets/js/global.js | 1 + 4 files changed, 119 insertions(+), 153 deletions(-) diff --git a/resources/assets/js/code.js b/resources/assets/js/code.js index 777baf81d..014c4eb77 100644 --- a/resources/assets/js/code.js +++ b/resources/assets/js/code.js @@ -169,6 +169,10 @@ module.exports.markdownEditor = function(elem) { theme: 'base16-light', lineWrapping: true }); - +}; + +module.exports.getMetaKey = function() { + let mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault; + return mac ? "Cmd" : "Ctrl"; }; diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js index 6a88aa811..ac1c3487c 100644 --- a/resources/assets/js/controllers.js +++ b/resources/assets/js/controllers.js @@ -370,14 +370,8 @@ module.exports = function (ngApp, events) { saveDraft(); }; - // Listen to shortcuts coming via events - $scope.$on('editor-keydown', (event, data) => { - // Save shortcut (ctrl+s) - if (data.keyCode == 83 && (navigator.platform.match("Mac") ? data.metaKey : data.ctrlKey)) { - data.preventDefault(); - saveDraft(); - } - }); + // Listen to save draft events from editor + $scope.$on('save-draft', saveDraft); /** * Discard the current draft and grab the current page diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js index 9a38add9a..51f1b7579 100644 --- a/resources/assets/js/directives.js +++ b/resources/assets/js/directives.js @@ -232,15 +232,33 @@ module.exports = function (ngApp, events) { }, link: function (scope, element, attrs) { - // Set initial model content - element = element.find('textarea').first(); - // 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()}; + 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(); @@ -257,6 +275,89 @@ module.exports = function (ngApp, events) { 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); + } + + // 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.showEntityLinkSelector(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); + }); + } + + // Show the image manager and handle image insertion + function showImageManager() { + let cursorPos = cm.getCursor('from'); + window.ImageManager.showExternal(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); @@ -267,6 +368,9 @@ module.exports = function (ngApp, events) { } 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); @@ -287,8 +391,7 @@ module.exports = function (ngApp, events) { restrict: 'A', link: function (scope, element, attrs) { - // Elements - const $input = element.find('[markdown-input] textarea').first(); + // 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"]'); @@ -299,11 +402,9 @@ module.exports = function (ngApp, events) { window.open(this.getAttribute('href')); }); - let currentCaretPos = 0; - - $input.blur(event => { - currentCaretPos = $input[0].selectionStart; - }); + // 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) => { @@ -315,140 +416,6 @@ module.exports = function (ngApp, events) { }, {queue: false, duration: 200, easing: 'linear'}); } }); - - // Editor key-presses - $input.keydown(event => { - // Insert image shortcut - if (event.which === 73 && event.ctrlKey && event.shiftKey) { - event.preventDefault(); - let caretPos = $input[0].selectionStart; - let currentContent = $input.val(); - const mdImageText = "![](http://)"; - $input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); - $input.focus(); - $input[0].selectionStart = caretPos + ("![](".length); - $input[0].selectionEnd = caretPos + ('![](http://'.length); - return; - } - - // Insert entity link shortcut - if (event.which === 75 && event.ctrlKey && event.shiftKey) { - showLinkSelector(); - return; - } - - // Pass key presses to controller via event - scope.$emit('editor-keydown', event); - }); - - // Insert image from image manager - $insertImage.click(event => { - window.ImageManager.showExternal(image => { - let caretPos = currentCaretPos; - let currentContent = $input.val(); - let mdImageText = "![" + image.name + "](" + image.thumbs.display + ")"; - $input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); - $input.change(); - }); - }); - - function showLinkSelector() { - window.showEntityLinkSelector((entity) => { - let selectionStart = currentCaretPos; - let selectionEnd = $input[0].selectionEnd; - let textSelected = (selectionEnd !== selectionStart); - let currentContent = $input.val(); - - if (textSelected) { - let selectedText = currentContent.substring(selectionStart, selectionEnd); - let linkText = `[${selectedText}](${entity.link})`; - $input.val(currentContent.substring(0, selectionStart) + linkText + currentContent.substring(selectionEnd)); - } else { - let linkText = ` [${entity.name}](${entity.link}) `; - $input.val(currentContent.substring(0, selectionStart) + linkText + currentContent.substring(selectionStart)) - } - $input.change(); - }); - } - $insertEntityLink.click(showLinkSelector); - - // Upload and insert image on paste - function editorPaste(e) { - e = e.originalEvent; - if (!e.clipboardData) return - let items = e.clipboardData.items; - if (!items) return; - for (let i = 0; i < items.length; i++) { - uploadImage(items[i].getAsFile()); - } - } - - $input.on('paste', editorPaste); - - // Handle image drop, Uploads images to BookStack. - function handleImageDrop(event) { - event.stopPropagation(); - event.preventDefault(); - let files = event.originalEvent.dataTransfer.files; - for (let i = 0; i < files.length; i++) { - uploadImage(files[i]); - } - } - - $input.on('drop', handleImageDrop); - - // Handle image upload and add image into markdown content - function uploadImage(file) { - if (file === null || !file.type.indexOf('image') !== 0) return; - let formData = new FormData(); - let ext = 'png'; - let xhr = new XMLHttpRequest(); - - if (file.name) { - let fileNameMatches = file.name.match(/\.(.+)$/); - if (fileNameMatches) { - ext = fileNameMatches[1]; - } - } - - // Insert image into markdown - let id = "image-" + Math.random().toString(16).slice(2); - let selectStart = $input[0].selectionStart; - let selectEnd = $input[0].selectionEnd; - let content = $input[0].value; - let selectText = content.substring(selectStart, selectEnd); - let placeholderImage = window.baseUrl(`/loading.gif#upload${id}`); - let innerContent = ((selectEnd > selectStart) ? `![${selectText}]` : '![]') + `(${placeholderImage})`; - $input[0].value = content.substring(0, selectStart) + innerContent + content.substring(selectEnd); - - $input.focus(); - $input[0].selectionStart = selectStart; - $input[0].selectionEnd = selectStart; - - 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 () { - let selectStart = $input[0].selectionStart; - if (xhr.status === 200 || xhr.status === 201) { - let result = JSON.parse(xhr.responseText); - $input[0].value = $input[0].value.replace(placeholderImage, result.thumbs.display); - $input.change(); - } else { - console.log(trans('errors.image_upload_error')); - console.log(xhr.responseText); - $input[0].value = $input[0].value.replace(innerContent, ''); - $input.change(); - } - $input.focus(); - $input[0].selectionStart = selectStart; - $input[0].selectionEnd = selectStart; - }; - xhr.send(formData); - } - } } }]); diff --git a/resources/assets/js/global.js b/resources/assets/js/global.js index dc6802e12..2ef062a5b 100644 --- a/resources/assets/js/global.js +++ b/resources/assets/js/global.js @@ -17,6 +17,7 @@ let axiosInstance = axios.create({ 'baseURL': window.baseUrl('') } }); +window.$http = axiosInstance; Vue.prototype.$http = axiosInstance; From b2dfc069c5f3acc4290bbf1731f04955fe7eb842 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Jul 2017 19:38:28 +0100 Subject: [PATCH 25/74] Updated readme attribution --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index e2f16e171..4f025e3c2 100644 --- a/readme.md +++ b/readme.md @@ -64,13 +64,15 @@ The BookStack source is provided under the MIT License. ## Attribution -These are the great projects used to help build BookStack: +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/) -* [highlight.js](https://highlightjs.org/) +* [CodeMirror](https://codemirror.net) +* [Vue.js](http://vuejs.org/) +* [Axios](https://github.com/mzabriskie/axios) * [jQuery Sortable](https://johnny.github.io/jquery-sortable/) * [Material Design Iconic Font](http://zavoloklom.github.io/material-design-iconic-font/icons.html) * [Dropzone.js](http://www.dropzonejs.com/) @@ -84,5 +86,3 @@ These are the great projects used to help build BookStack: * [Snappy (WKHTML2PDF)](https://github.com/barryvdh/laravel-snappy) * [Laravel IDE helper](https://github.com/barryvdh/laravel-ide-helper) * [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html) - -Additionally, Thank you [BrowserStack](https://www.browserstack.com/) for supporting us and making cross-browser testing easy. From 314d98abc301d0f8e9c9c0570d9a2ef1fdac3772 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Jul 2017 20:33:32 +0100 Subject: [PATCH 26/74] Removed logs, Updated version, Fixed inconsistent subheader --- resources/assets/js/pages/page-form.js | 2 -- resources/assets/sass/_header.scss | 8 +++++++- version | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/resources/assets/js/pages/page-form.js b/resources/assets/js/pages/page-form.js index 9b3c90a28..81d1cdea6 100644 --- a/resources/assets/js/pages/page-form.js +++ b/resources/assets/js/pages/page-form.js @@ -74,7 +74,6 @@ function codePlugin() { function showPopup(editor) { let selectedNode = editor.selection.getNode(); - console.log('show ppoe'); if (!elemIsCodeBlock(selectedNode)) { let providedCode = editor.selection.getNode().textContent; @@ -156,7 +155,6 @@ function codePlugin() { $('.CodeMirrorContainer').filter((index ,elem) => { return typeof elem.querySelector('.CodeMirror').CodeMirror === 'undefined'; }).each((index, elem) => { - console.log('COVERT'); codeMirrorContainerToPre($(elem)); }); diff --git a/resources/assets/sass/_header.scss b/resources/assets/sass/_header.scss index 12bd17076..16ed75545 100644 --- a/resources/assets/sass/_header.scss +++ b/resources/assets/sass/_header.scss @@ -155,7 +155,6 @@ form.search-box { text-decoration: none; } } - } .faded span.faded-text { @@ -175,6 +174,13 @@ form.search-box { &:last-child { padding-right: 0; } + &:first-child { + padding-left: 0; + } +} +.action-buttons .dropdown-container:last-child a { + padding-right: 0; + padding-left: $-s; } .action-buttons { text-align: right; diff --git a/version b/version index 973dcf5ac..1365ed940 100644 --- a/version +++ b/version @@ -1 +1 @@ -v0.16-dev +v0.17-dev From e7f8188ee539f76adcd511733a7b749801d676b2 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 10 Jul 2017 19:29:35 +0100 Subject: [PATCH 27/74] Prevented textarea styles interfering with codemirror Closes #424 --- resources/assets/sass/_forms.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/assets/sass/_forms.scss b/resources/assets/sass/_forms.scss index 1fc812896..392e9ec3e 100644 --- a/resources/assets/sass/_forms.scss +++ b/resources/assets/sass/_forms.scss @@ -32,7 +32,7 @@ #markdown-editor { position: relative; z-index: 5; - textarea { + #markdown-editor-input { font-family: 'Roboto Mono', monospace; font-style: normal; font-weight: 400; From 2ea7e1092336558809fc790c05adc6060e66973b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 10 Jul 2017 19:43:49 +0100 Subject: [PATCH 28/74] Set ldap to not follow referrals by default Added LDAP_FOLLOW_REFERRALS .env option to override. Fixes #317 --- app/Services/LdapService.php | 2 ++ config/services.php | 1 + 2 files changed, 3 insertions(+) diff --git a/app/Services/LdapService.php b/app/Services/LdapService.php index 71dc9c0e1..598efc19d 100644 --- a/app/Services/LdapService.php +++ b/app/Services/LdapService.php @@ -42,6 +42,8 @@ class LdapService $userFilter = $this->buildFilter($this->config['user_filter'], ['user' => $userName]); $baseDn = $this->config['base_dn']; $emailAttr = $this->config['email_attribute']; + $followReferrals = $this->config['follow_referrals'] ? 1 : 0; + $this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals); $users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', $emailAttr]); if ($users['count'] === 0) return null; diff --git a/config/services.php b/config/services.php index 99022e5f2..b4959c724 100644 --- a/config/services.php +++ b/config/services.php @@ -80,6 +80,7 @@ return [ 'user_filter' => env('LDAP_USER_FILTER', '(&(uid=${user}))'), 'version' => env('LDAP_VERSION', false), 'email_attribute' => env('LDAP_EMAIL_ATTRIBUTE', 'mail'), + 'follow_referrals' => env('LDAP_FOLLOW_REFERRALS', false), ] ]; From 9e0c9315737ff978c91114e5c74bba114f138cc9 Mon Sep 17 00:00:00 2001 From: JachuPL Date: Thu, 13 Jul 2017 16:00:42 +0200 Subject: [PATCH 29/74] Polish translation --- config/app.php | 2 +- resources/lang/en/settings.php | 1 + resources/lang/pl/activities.php | 40 ++++++ resources/lang/pl/auth.php | 76 ++++++++++ resources/lang/pl/common.php | 59 ++++++++ resources/lang/pl/components.php | 32 +++++ resources/lang/pl/entities.php | 237 +++++++++++++++++++++++++++++++ resources/lang/pl/errors.php | 70 +++++++++ resources/lang/pl/pagination.php | 19 +++ resources/lang/pl/passwords.php | 22 +++ resources/lang/pl/settings.php | 111 +++++++++++++++ resources/lang/pl/validation.php | 108 ++++++++++++++ 12 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 resources/lang/pl/activities.php create mode 100644 resources/lang/pl/auth.php create mode 100644 resources/lang/pl/common.php create mode 100644 resources/lang/pl/components.php create mode 100644 resources/lang/pl/entities.php create mode 100644 resources/lang/pl/errors.php create mode 100644 resources/lang/pl/pagination.php create mode 100644 resources/lang/pl/passwords.php create mode 100644 resources/lang/pl/settings.php create mode 100644 resources/lang/pl/validation.php diff --git a/config/app.php b/config/app.php index 48348f837..a390eaf83 100644 --- a/config/app.php +++ b/config/app.php @@ -58,7 +58,7 @@ return [ */ 'locale' => env('APP_LANG', 'en'), - 'locales' => ['en', 'de', 'es', 'fr', 'nl', 'pt_BR', 'sk', 'ja'], + 'locales' => ['en', 'de', 'es', 'fr', 'nl', 'pt_BR', 'sk', 'ja', 'pl'], /* |-------------------------------------------------------------------------- diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 4529b1978..3eec7737f 100644 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -122,6 +122,7 @@ return [ 'pt_BR' => 'Português do Brasil', 'sk' => 'Slovensky', 'ja' => '日本語', + 'pl' => 'Polski', ] /////////////////////////////////// ]; diff --git a/resources/lang/pl/activities.php b/resources/lang/pl/activities.php new file mode 100644 index 000000000..5ef5acab0 --- /dev/null +++ b/resources/lang/pl/activities.php @@ -0,0 +1,40 @@ + 'utworzono stronę', + 'page_create_notification' => 'Strona utworzona pomyślnie', + 'page_update' => 'zaktualizowano stronę', + 'page_update_notification' => 'Strona zaktualizowana pomyślnie', + 'page_delete' => 'usunięto stronę', + 'page_delete_notification' => 'Strona usunięta pomyślnie', + 'page_restore' => 'przywrócono stronę', + 'page_restore_notification' => 'Stronga przywrócona pomyślnie', + 'page_move' => 'przeniesiono stronę', + + // Chapters + 'chapter_create' => 'utworzono rozdział', + 'chapter_create_notification' => 'Rozdział utworzony pomyślnie', + 'chapter_update' => 'zaktualizowano rozdział', + 'chapter_update_notification' => 'Rozdział zaktualizowany pomyślnie', + 'chapter_delete' => 'usunięto rozdział', + 'chapter_delete_notification' => 'Rozdział usunięty pomyślnie', + 'chapter_move' => 'przeniesiono rozdział', + + // Books + 'book_create' => 'utworzono księgę', + 'book_create_notification' => 'Księga utworzona pomyślnie', + 'book_update' => 'zaktualizowano księgę', + 'book_update_notification' => 'Księga zaktualizowana pomyślnie', + 'book_delete' => 'usunięto księgę', + 'book_delete_notification' => 'Księga usunięta pomyślnie', + 'book_sort' => 'posortowano księgę', + 'book_sort_notification' => 'Księga posortowana pomyślnie', + +]; diff --git a/resources/lang/pl/auth.php b/resources/lang/pl/auth.php new file mode 100644 index 000000000..740e067ca --- /dev/null +++ b/resources/lang/pl/auth.php @@ -0,0 +1,76 @@ + 'These credentials do not match our records.', + 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', + + /** + * Login & Register + */ + 'sign_up' => 'Zarejestruj się', + 'log_in' => 'Zaloguj się', + 'log_in_with' => 'Zaloguj się za pomocą :socialDriver', + 'sign_up_with' => 'Zarejestruj się za pomocą :socialDriver', + 'logout' => 'Wyloguj', + + 'name' => 'Imię', + 'username' => 'Nazwa użytkownika', + 'email' => 'Email', + 'password' => 'Hasło', + 'password_confirm' => 'Potwierdzenie hasła', + 'password_hint' => 'Musi mieć więcej niż 5 znaków', + 'forgot_password' => 'Przypomnij hasło', + 'remember_me' => 'Zapamiętaj mnie', + 'ldap_email_hint' => 'Wprowadź adres email dla tego konta.', + 'create_account' => 'Utwórz konto', + 'social_login' => 'Logowanie za pomocą konta społecznościowego', + 'social_registration' => 'Rejestracja za pomocą konta społecznościowego', + 'social_registration_text' => 'Zarejestruj się za pomocą innej usługi.', + + 'register_thanks' => 'Dziękujemy za rejestrację!', + 'register_confirm' => 'Sprawdź podany adres e-mail i kliknij w link, by uzyskać dostęp do :appName.', + 'registrations_disabled' => 'Rejestracja jest obecnie zablokowana.', + 'registration_email_domain_invalid' => 'Adresy e-mail z tej domeny nie mają dostępu do tej aplikacji', + 'register_success' => 'Dziękujemy za rejestrację! Zalogowano Cię automatycznie.', + + + /** + * Password Reset + */ + 'reset_password' => 'Resetowanie hasła', + 'reset_password_send_instructions' => 'Wprowadź adres e-mail powiązany z Twoim kontem, by otrzymać link do resetowania hasła.', + 'reset_password_send_button' => 'Wyślij link do resetowania hasła', + 'reset_password_sent_success' => 'Wysłano link do resetowania hasła na adres :email.', + 'reset_password_success' => 'Hasło zostało zresetowane pomyślnie.', + + 'email_reset_subject' => 'Resetowanie hasła do :appName', + 'email_reset_text' => 'Otrzymujesz tę wiadomość ponieważ ktoś zażądał zresetowania hasła do Twojego konta.', + 'email_reset_not_requested' => 'Jeśli to nie Ty złożyłeś żądanie zresetowania hasła, zignoruj tę wiadomość.', + + + /** + * Email Confirmation + */ + 'email_confirm_subject' => 'Potwierdź swój adres email w :appName', + 'email_confirm_greeting' => 'Dziękujemy za dołączenie do :appName!', + 'email_confirm_text' => 'Prosimy byś potwierdził swoje hasło klikając przycisk poniżej:', + 'email_confirm_action' => 'Potwierdź email', + 'email_confirm_send_error' => 'Wymagane jest potwierdzenie hasła, lecz wiadomość nie mogła zostać wysłana. Skontaktuj się z administratorem w celu upewnienia się, że skrzynka została skonfigurowana prawidłowo.', + 'email_confirm_success' => 'Adres email został potwierdzony!', + 'email_confirm_resent' => 'Wiadomość potwierdzająca została wysłana, sprawdź swoją skrzynkę.', + + 'email_not_confirmed' => 'Adres email niepotwierdzony', + 'email_not_confirmed_text' => 'Twój adres email nie został jeszcze potwierdzony.', + 'email_not_confirmed_click_link' => 'Aby potwierdzić swoje konto kliknij w link wysłany w wiadomości po rejestracji.', + 'email_not_confirmed_resend' => 'Jeśli wiadomość do Ciebie nie dotarła możesz wysłać ją ponownie wypełniając formularz poniżej.', + 'email_not_confirmed_resend_button' => 'Wyślij ponownie wiadomość z potwierdzeniem', +]; \ No newline at end of file diff --git a/resources/lang/pl/common.php b/resources/lang/pl/common.php new file mode 100644 index 000000000..1c8963653 --- /dev/null +++ b/resources/lang/pl/common.php @@ -0,0 +1,59 @@ + 'Anuluj', + 'confirm' => 'Zatwierdź', + 'back' => 'Wstecz', + 'save' => 'Zapisz', + 'continue' => 'Kontynuuj', + 'select' => 'Wybierz', + + /** + * Form Labels + */ + 'name' => 'Nazwa', + 'description' => 'Opis', + 'role' => 'Rola', + + /** + * Actions + */ + 'actions' => 'Akcje', + 'view' => 'Widok', + 'create' => 'Utwórz', + 'update' => 'Zaktualizuj', + 'edit' => 'Edytuj', + 'sort' => 'Sortuj', + 'move' => 'Przenieś', + 'delete' => 'Usuń', + 'search' => 'Szukaj', + 'search_clear' => 'Wyczyść wyszukiwanie', + 'reset' => 'Resetuj', + 'remove' => 'Usuń', + 'add' => 'Dodaj', + + + /** + * Misc + */ + 'deleted_user' => 'Użytkownik usunięty', + 'no_activity' => 'Brak aktywności do pokazania', + 'no_items' => 'Brak elementów do wyświetlenia', + 'back_to_top' => 'Powrót na górę', + 'toggle_details' => 'Włącz/wyłącz szczegóły', + + /** + * Header + */ + 'view_profile' => 'Zobacz profil', + 'edit_profile' => 'Edytuj profil', + + /** + * Email Content + */ + 'email_action_help' => 'Jeśli masz problem z kliknięciem przycisku ":actionText", skopiuj i wklej poniższy adres URL w nowej karcie swojej przeglądarki:', + 'email_rights' => 'Wszelkie prawa zastrzeżone', +]; \ No newline at end of file diff --git a/resources/lang/pl/components.php b/resources/lang/pl/components.php new file mode 100644 index 000000000..c1dbcd44b --- /dev/null +++ b/resources/lang/pl/components.php @@ -0,0 +1,32 @@ + 'Wybór obrazka', + 'image_all' => 'Wszystkie', + 'image_all_title' => 'Zobacz wszystkie obrazki', + 'image_book_title' => 'Zobacz obrazki zapisane w tej księdze', + 'image_page_title' => 'Zobacz obrazki zapisane na tej stronie', + 'image_search_hint' => 'Szukaj po nazwie obrazka', + 'image_uploaded' => 'Udostępniono :uploadedDate', + 'image_load_more' => 'Wczytaj więcej', + 'image_image_name' => 'Nazwa obrazka', + 'image_delete_confirm' => 'Ten obrazek jest używany na stronach poniżej, kliknij ponownie Usuń by potwierdzić usunięcie obrazka.', + 'image_select_image' => 'Wybierz obrazek', + 'image_dropzone' => 'Upuść obrazki tutaj lub kliknij by wybrać obrazki do udostępnienia', + 'images_deleted' => 'Usunięte obrazki', + 'image_preview' => 'Podgląd obrazka', + 'image_upload_success' => 'Obrazek wysłany pomyślnie', + 'image_update_success' => 'Szczegóły obrazka zaktualizowane pomyślnie', + 'image_delete_success' => 'Obrazek usunięty pomyślnie', + + /** + * Code editor + */ + 'code_editor' => 'Edytuj kod', + 'code_language' => 'Język kodu', + 'code_content' => 'Zawartość kodu', + 'code_save' => 'Zapisz kod', +]; \ No newline at end of file diff --git a/resources/lang/pl/entities.php b/resources/lang/pl/entities.php new file mode 100644 index 000000000..30e853bce --- /dev/null +++ b/resources/lang/pl/entities.php @@ -0,0 +1,237 @@ + 'Ostatnio utworzone', + 'recently_created_pages' => 'Ostatnio utworzone strony', + 'recently_updated_pages' => 'Ostatnio zaktualizowane strony', + 'recently_created_chapters' => 'Ostatnio utworzone rozdziały', + 'recently_created_books' => 'Ostatnio utworzone księgi', + 'recently_update' => 'Ostatnio zaktualizowane', + 'recently_viewed' => 'Ostatnio wyświetlane', + 'recent_activity' => 'Ostatnia aktywność', + 'create_now' => 'Utwórz teraz', + 'revisions' => 'Rewizje', + 'meta_revision' => 'Rewizja #:revisionCount', + 'meta_created' => 'Utworzono :timeLength', + 'meta_created_name' => 'Utworzono :timeLength przez :user', + 'meta_updated' => 'Zaktualizowano :timeLength', + 'meta_updated_name' => 'Zaktualizowano :timeLength przez :user', + 'x_pages' => ':count stron', + 'entity_select' => 'Wybór encji', + 'images' => 'Obrazki', + 'my_recent_drafts' => 'Moje ostatnie szkice', + 'my_recently_viewed' => 'Moje ostatnio wyświetlane', + 'no_pages_viewed' => 'Nie wyświetlano żadnych stron', + 'no_pages_recently_created' => 'Nie utworzono ostatnio żadnych stron', + 'no_pages_recently_updated' => 'Nie zaktualizowano ostatnio żadnych stron', + 'export' => 'Eksportuj', + 'export_html' => 'Plik HTML', + 'export_pdf' => 'Plik PDF', + 'export_text' => 'Plik tekstowy', + + /** + * Permissions and restrictions + */ + 'permissions' => 'Uprawnienia', + 'permissions_intro' => 'Jeśli odblokowane, te uprawnienia będą miały priorytet względem pozostałych ustawionych uprawnień ról.', + 'permissions_enable' => 'Odblokuj własne uprawnienia', + 'permissions_save' => 'Zapisz uprawnienia', + + /** + * Search + */ + 'search_results' => 'Wyniki wyszukiwania', + 'search_total_results_found' => ':count znalezionych wyników|:count ogółem znalezionych wyników', + 'search_clear' => 'Wyczyść wyszukiwanie', + 'search_no_pages' => 'Brak stron spełniających zadane kryterium', + 'search_for_term' => 'Szukaj :term', + 'search_more' => 'Więcej wyników', + 'search_filters' => 'Filtry wyszukiwania', + 'search_content_type' => 'Rodziaj treści', + 'search_exact_matches' => 'Dokładne frazy', + 'search_tags' => 'Tagi wyszukiwania', + 'search_viewed_by_me' => 'Wyświetlone przeze mnie', + 'search_not_viewed_by_me' => 'Niewyświetlone przeze mnie', + 'search_permissions_set' => 'Zbiór uprawnień', + 'search_created_by_me' => 'Utworzone przeze mnie', + 'search_updated_by_me' => 'Zaktualizowane przeze mnie', + 'search_updated_before' => 'Zaktualizowane przed', + 'search_updated_after' => 'Zaktualizowane po', + 'search_created_before' => 'Utworzone przed', + 'search_created_after' => 'Utworzone po', + 'search_set_date' => 'Ustaw datę', + 'search_update' => 'Zaktualizuj wyszukiwanie', + + /** + * Books + */ + 'book' => 'Księga', + 'books' => 'Księgi', + 'books_empty' => 'Brak utworzonych ksiąg', + 'books_popular' => 'Popularne księgi', + 'books_recent' => 'Ostatnie księgi', + 'books_popular_empty' => 'Najbardziej popularne księgi zostaną wyświetlone w tym miejscu.', + 'books_create' => 'Utwórz księgę', + 'books_delete' => 'Usuń księgę', + 'books_delete_named' => 'Usuń księgę :bookName', + 'books_delete_explain' => 'To spowoduje usunięcie księgi \':bookName\', Wszystkie strony i rozdziały zostaną usunięte.', + 'books_delete_confirmation' => 'Czy na pewno chcesz usunąc tę księgę?', + 'books_edit' => 'Edytuj księgę', + 'books_edit_named' => 'Edytuj księgę :bookName', + 'books_form_book_name' => 'Nazwa księgi', + 'books_save' => 'Zapisz księgę', + 'books_permissions' => 'Uprawnienia księgi', + 'books_permissions_updated' => 'Zaktualizowano uprawnienia księgi', + 'books_empty_contents' => 'Brak stron lub rozdziałów w tej księdze.', + 'books_empty_create_page' => 'Utwórz nową stronę', + 'books_empty_or' => 'lub', + 'books_empty_sort_current_book' => 'posortuj bieżącą księgę', + 'books_empty_add_chapter' => 'Dodaj rozdział', + 'books_permissions_active' => 'Uprawnienia księgi aktywne', + 'books_search_this' => 'Wyszukaj w tej księdze', + 'books_navigation' => 'Nawigacja po księdze', + 'books_sort' => 'Sortuj zawartość Księgi', + 'books_sort_named' => 'Sortuj księgę :bookName', + 'books_sort_show_other' => 'Pokaż inne księgi', + 'books_sort_save' => 'Zapisz nowy porządek', + + /** + * Chapters + */ + 'chapter' => 'Rozdział', + 'chapters' => 'Rozdziały', + 'chapters_popular' => 'Popularne rozdziały', + 'chapters_new' => 'Nowy rozdział', + 'chapters_create' => 'Utwórz nowy rozdział', + 'chapters_delete' => 'Usuń rozdział', + 'chapters_delete_named' => 'Usuń rozdział :chapterName', + 'chapters_delete_explain' => 'To spowoduje usunięcie rozdziału \':chapterName\', Wszystkie strony zostaną usunięte + i dodane bezpośrednio do księgi macierzystej.', + 'chapters_delete_confirm' => 'Czy na pewno chcesz usunąć ten rozdział?', + 'chapters_edit' => 'Edytuj rozdział', + 'chapters_edit_named' => 'Edytuj rozdział :chapterName', + 'chapters_save' => 'Zapisz rozdział', + 'chapters_move' => 'Przenieś rozdział', + 'chapters_move_named' => 'Przenieś rozdział :chapterName', + 'chapter_move_success' => 'Rozdział przeniesiony do :bookName', + 'chapters_permissions' => 'Uprawienia rozdziału', + 'chapters_empty' => 'Brak stron w tym rozdziale.', + 'chapters_permissions_active' => 'Uprawnienia rozdziału aktywne', + 'chapters_permissions_success' => 'Zaktualizowano uprawnienia rozdziału', + 'chapters_search_this' => 'Przeszukaj ten rozdział', + + /** + * Pages + */ + 'page' => 'Strona', + 'pages' => 'Strony', + 'pages_popular' => 'Popularne strony', + 'pages_new' => 'Nowa strona', + 'pages_attachments' => 'Załączniki', + 'pages_navigation' => 'Nawigacja po stronie', + 'pages_delete' => 'Usuń stronę', + 'pages_delete_named' => 'Usuń stronę :pageName', + 'pages_delete_draft_named' => 'Usuń szkic strony :pageName', + 'pages_delete_draft' => 'Usuń szkic strony', + 'pages_delete_success' => 'Strona usunięta pomyślnie', + 'pages_delete_draft_success' => 'Szkic strony usunięty pomyślnie', + 'pages_delete_confirm' => 'Czy na pewno chcesz usunąć tę stron?', + 'pages_delete_draft_confirm' => 'Czy na pewno chcesz usunąć szkic strony?', + 'pages_editing_named' => 'Edytowanie strony :pageName', + 'pages_edit_toggle_header' => 'Włącz/wyłącz nagłówek', + 'pages_edit_save_draft' => 'Zapisz szkic', + 'pages_edit_draft' => 'Edytuj szkic strony', + 'pages_editing_draft' => 'Edytowanie szkicu strony', + 'pages_editing_page' => 'Edytowanie strony', + 'pages_edit_draft_save_at' => 'Szkic zapisany ', + 'pages_edit_delete_draft' => 'Usuń szkic', + 'pages_edit_discard_draft' => 'Porzuć szkic', + 'pages_edit_set_changelog' => 'Ustaw log zmian', + 'pages_edit_enter_changelog_desc' => 'Opisz zmiany, które zostały wprowadzone', + 'pages_edit_enter_changelog' => 'Wyświetl log zmian', + 'pages_save' => 'Zapisz stronę', + 'pages_title' => 'Tytuł strony', + 'pages_name' => 'Nazwa strony', + 'pages_md_editor' => 'Edytor', + 'pages_md_preview' => 'Podgląd', + 'pages_md_insert_image' => 'Wstaw obrazek', + 'pages_md_insert_link' => 'Wstaw łącze do encji', + 'pages_not_in_chapter' => 'Strona nie została umieszczona w rozdziale', + 'pages_move' => 'Przenieś stronę', + 'pages_move_success' => 'Strona przeniesiona do ":parentName"', + 'pages_permissions' => 'Uprawnienia strony', + 'pages_permissions_success' => 'Zaktualizowano uprawnienia strony', + 'pages_revisions' => 'Rewizje strony', + 'pages_revisions_named' => 'Rewizje strony :pageName', + 'pages_revision_named' => 'Rewizja stroony :pageName', + 'pages_revisions_created_by' => 'Utworzona przez', + 'pages_revisions_date' => 'Data rewizji', + 'pages_revisions_number' => '#', + 'pages_revisions_changelog' => 'Log zmian', + 'pages_revisions_changes' => 'Zmiany', + 'pages_revisions_current' => 'Obecna wersja', + 'pages_revisions_preview' => 'Podgląd', + 'pages_revisions_restore' => 'Przywróć', + 'pages_revisions_none' => 'Ta strona nie posiada żadnych rewizji', + 'pages_copy_link' => 'Kopiuj link', + 'pages_permissions_active' => 'Uprawnienia strony aktywne', + 'pages_initial_revision' => 'Wydanie pierwotne', + 'pages_initial_name' => 'Nowa strona', + 'pages_editing_draft_notification' => 'Edytujesz obecnie szkic, który był ostatnio zapisany :timeDiff.', + 'pages_draft_edited_notification' => 'Od tego czasu ta strona była zmieniana. Zalecane jest odrzucenie tego szkicu.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count użytkowników rozpoczęło edytowanie tej strony', + 'start_b' => ':userName edytuje stronę', + 'time_a' => ' od czasu ostatniej edycji', + 'time_b' => 'w ciągu ostatnich :minCount minut', + 'message' => ':start :time. Pamiętaj by nie nadpisywać czyichś zmian!', + ], + 'pages_draft_discarded' => 'Szkic odrzucony, edytor został uzupełniony najnowszą wersją strony', + + /** + * Editor sidebar + */ + 'page_tags' => 'Tagi strony', + 'tag' => 'Tag', + 'tags' => '', + 'tag_value' => 'Wartość tagu (opcjonalnie)', + 'tags_explain' => "Dodaj tagi by skategoryzować zawartość. \n W celu dokładniejszej organizacji zawartości możesz dodać wartości do tagów.", + 'tags_add' => 'Dodaj kolejny tag', + 'attachments' => 'Załączniki', + 'attachments_explain' => 'Udostępnij kilka plików lub załącz link. Będą one widoczne na marginesie strony.', + 'attachments_explain_instant_save' => 'Zmiany są zapisywane natychmiastowo.', + 'attachments_items' => 'Załączniki', + 'attachments_upload' => 'Dodaj plik', + 'attachments_link' => 'Dodaj link', + 'attachments_set_link' => 'Ustaw link', + 'attachments_delete_confirm' => 'Kliknij ponownie Usuń by potwierdzić usunięcie załącznika.', + 'attachments_dropzone' => 'Upuść pliki lub kliknij tutaj by udostępnić pliki', + 'attachments_no_files' => 'Nie udostępniono plików', + 'attachments_explain_link' => 'Możesz załączyć link jeśli nie chcesz udostępniać pliku. Może być to link do innej strony lub link do pliku w chmurze.', + 'attachments_link_name' => 'Nazwa linku', + 'attachment_link' => 'Link do załącznika', + 'attachments_link_url' => 'Link do pliku', + 'attachments_link_url_hint' => 'Strona lub plik', + 'attach' => 'Załącz', + 'attachments_edit_file' => 'Edytuj plik', + 'attachments_edit_file_name' => 'Nazwa pliku', + 'attachments_edit_drop_upload' => 'Upuść pliki lub kliknij tutaj by udostępnić pliki i nadpisać istniejące', + 'attachments_order_updated' => 'Kolejność załączników zaktualizowana', + 'attachments_updated_success' => 'Szczegóły załączników zaktualizowane', + 'attachments_deleted' => 'Załączniki usunięte', + 'attachments_file_uploaded' => 'Plik załączony pomyślnie', + 'attachments_file_updated' => 'Plik zaktualizowany pomyślnie', + 'attachments_link_attached' => 'Link pomyślnie dodany do strony', + + /** + * Profile View + */ + 'profile_user_for_x' => 'Użytkownik od :time', + 'profile_created_content' => 'Utworzona zawartość', + 'profile_not_created_pages' => ':userName nie utworzył żadnych stron', + 'profile_not_created_chapters' => ':userName nie utworzył żadnych rozdziałów', + 'profile_not_created_books' => ':userName nie utworzył żadnych ksiąg', +]; \ No newline at end of file diff --git a/resources/lang/pl/errors.php b/resources/lang/pl/errors.php new file mode 100644 index 000000000..633bf7a2d --- /dev/null +++ b/resources/lang/pl/errors.php @@ -0,0 +1,70 @@ + 'Nie masz uprawnień do wyświetlenia tej strony.', + 'permissionJson' => 'Nie masz uprawnień do wykonania tej akcji.', + + // Auth + 'error_user_exists_different_creds' => 'Użytkownik o adresie :email już istnieje.', + 'email_already_confirmed' => 'Email został potwierdzony, spróbuj się zalogować.', + 'email_confirmation_invalid' => 'Ten token jest nieprawidłowy lub został już wykorzystany. Spróbuj zarejestrować się ponownie.', + 'email_confirmation_expired' => 'Ten token potwierdzający wygasł. Wysłaliśmy Ci kolejny.', + 'ldap_fail_anonymous' => 'Dostęp LDAP przy użyciu anonimowego powiązania nie powiódł się', + 'ldap_fail_authed' => 'Dostęp LDAP przy użyciu tego dn i hasła nie powiódł się', + 'ldap_extension_not_installed' => 'Rozszerzenie LDAP PHP nie zostało zainstalowane', + 'ldap_cannot_connect' => 'Nie można połączyć z serwerem LDAP, połączenie nie zostało ustanowione', + 'social_no_action_defined' => 'Brak zdefiniowanej akcji', + 'social_account_in_use' => 'To konto :socialAccount jest już w użyciu, spróbuj zalogować się za pomocą opcji :socialAccount.', + 'social_account_email_in_use' => 'Email :email jest już w użyciu. Jeśli masz już konto, połącz konto :socialAccount z poziomu ustawień profilu.', + 'social_account_existing' => 'Konto :socialAccount jest już połączone z Twoim profilem', + 'social_account_already_used_existing' => 'Konto :socialAccount jest już używane przez innego użytkownika.', + 'social_account_not_used' => 'To konto :socialAccount nie jest połączone z żadnym użytkownikiem. Połącz je ze swoim kontem w ustawieniach profilu. ', + 'social_account_register_instructions' => 'Jeśli nie masz jeszcze konta, możesz zarejestrować je używając opcji :socialAccount.', + 'social_driver_not_found' => 'Funkcja społecznościowa nie została odnaleziona', + 'social_driver_not_configured' => 'Ustawienia konta :socialAccount nie są poprawne.', + + // System + 'path_not_writable' => 'Zapis do ścieżki :filePath jest niemożliwy. Upewnij się że aplikacja ma prawa do zapisu w niej.', + 'cannot_get_image_from_url' => 'Nie można pobrać obrazka z :url', + 'cannot_create_thumbs' => 'Serwer nie może utworzyć miniaturek. Upewnij się że rozszerzenie GD PHP zostało zainstalowane.', + 'server_upload_limit' => 'Serwer nie pozwala na przyjęcie pliku o tym rozmiarze. Spróbuj udostępnić coś o mniejszym rozmiarze.', + 'image_upload_error' => 'Wystąpił błąd podczas udostępniania obrazka', + + // Attachments + 'attachment_page_mismatch' => 'Niezgodność stron podczas aktualizacji załącznika', + + // Pages + 'page_draft_autosave_fail' => 'Zapis szkicu nie powiódł się. Upewnij się że posiadasz połączenie z internetem.', + + // Entities + 'entity_not_found' => 'Encja nie została odnaleziona', + 'book_not_found' => 'Księga nie została odnaleziona', + 'page_not_found' => 'Strona nie została odnaleziona', + 'chapter_not_found' => 'Rozdział nie został odnaleziony', + 'selected_book_not_found' => 'Wybrana księga nie została odnaleziona', + 'selected_book_chapter_not_found' => 'Wybrana księga lub rozdział nie zostały odnalezione', + 'guests_cannot_save_drafts' => 'Goście nie mogą zapisywać szkiców', + + // Users + 'users_cannot_delete_only_admin' => 'Nie możesz usunąć jedynego administratora', + 'users_cannot_delete_guest' => 'Nie możesz usunąć użytkownika-gościa', + + // Roles + 'role_cannot_be_edited' => 'Ta rola nie może być edytowana', + 'role_system_cannot_be_deleted' => 'Ta rola jest rolą systemową i nie może zostać usunięta', + 'role_registration_default_cannot_delete' => 'Ta rola nie może zostać usunięta jeśli jest ustawiona jako domyślna rola użytkownika', + + // Error pages + '404_page_not_found' => 'Strona nie została odnaleziona', + 'sorry_page_not_found' => 'Przepraszamy, ale strona której szukasz nie została odnaleziona.', + 'return_home' => 'Powrót do strony głównej', + 'error_occurred' => 'Wystąpił błąd', + 'app_down' => ':appName jest aktualnie wyłączona', + 'back_soon' => 'Niedługo zostanie uruchomiona ponownie.', +]; \ No newline at end of file diff --git a/resources/lang/pl/pagination.php b/resources/lang/pl/pagination.php new file mode 100644 index 000000000..564694190 --- /dev/null +++ b/resources/lang/pl/pagination.php @@ -0,0 +1,19 @@ + '« Poprzednia', + 'next' => 'Następna »', + +]; diff --git a/resources/lang/pl/passwords.php b/resources/lang/pl/passwords.php new file mode 100644 index 000000000..a9e669f4d --- /dev/null +++ b/resources/lang/pl/passwords.php @@ -0,0 +1,22 @@ + 'Hasło musi zawierać co najmniej 6 znaków i być zgodne z powtórzeniem.', + 'user' => "Nie znaleziono użytkownika o takim adresie email.", + 'token' => 'Ten token resetowania hasła jest nieprawidłowy.', + 'sent' => 'Wysłaliśmy Ci link do resetowania hasła!', + 'reset' => 'Twoje hasło zostało zresetowane!', + +]; diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php new file mode 100644 index 000000000..381e5517a --- /dev/null +++ b/resources/lang/pl/settings.php @@ -0,0 +1,111 @@ + 'Ustawienia', + 'settings_save' => 'Zapisz ustawienia', + 'settings_save_success' => 'Ustawienia zapisane', + + /** + * App settings + */ + + 'app_settings' => 'Ustawienia aplikacji', + 'app_name' => 'Nazwa aplikacji', + 'app_name_desc' => 'Ta nazwa jest wyświetlana w nagłówku i emailach.', + 'app_name_header' => 'Pokazać nazwę aplikacji w nagłówku?', + 'app_public_viewing' => 'Zezwolić na publiczne przeglądanie?', + 'app_secure_images' => 'Odblokować wyższe bezpieczeństwo obrazków?', + 'app_secure_images_desc' => 'Ze względów wydajnościowych wszystkie obrazki są publiczne. Ta opcja dodaje dodatkowy, trudny do zgadnienia losowy ciąg na początku nazwy obrazka. Upewnij się że indeksowanie ścieżek jest zablokowane, by uniknąć problemów z dostępem do obrazka.', + 'app_editor' => 'Edytor strony', + 'app_editor_desc' => 'Wybierz edytor używany przez użytkowników do edycji zawartości.', + 'app_custom_html' => 'Własna zawartość tagu ', + 'app_custom_html_desc' => 'Zawartość dodana tutaj zostanie dołączona do sekcji każdej strony. Przydatne przy nadpisywaniu styli lub dodawaniu analityki.', + 'app_logo' => 'Logo aplikacji', + 'app_logo_desc' => 'Ten obrazek powinien mieć nie więcej niż 43px w pionie.
Większe obrazki będą skalowane w dół.', + 'app_primary_color' => 'Podstawowy kolor aplikacji', + 'app_primary_color_desc' => 'To powinna być wartość HEX.
Zostaw to pole puste, by powrócić do podstawowego koloru.', + + /** + * Registration settings + */ + + 'reg_settings' => 'Ustawienia rejestracji', + 'reg_allow' => 'Zezwolić na rejestrację?', + 'reg_default_role' => 'Domyślna rola użytkownika po rejestracji', + 'reg_confirm_email' => 'Wymagać potwierdzenia adresu email?', + 'reg_confirm_email_desc' => 'Jeśli restrykcje domenowe zostały uzupełnione potwierdzenie adresu stanie się konieczne, a poniższa wartośc zostanie zignorowana.', + 'reg_confirm_restrict_domain' => 'Restrykcje domenowe dot. adresu email', + 'reg_confirm_restrict_domain_desc' => 'Wprowadź listę domen adresów email rozdzieloną przecinkami, którym chciałbyś zezwolić na rejestrację. Wymusi to konieczność potwierdzenia adresu email przez użytkownika przed uzyskaniem dostępu do aplikacji.
Pamiętaj, że użytkownicy będą mogli zmienić adres email po rejestracji.', + 'reg_confirm_restrict_domain_placeholder' => 'Brak restrykcji', + + /** + * Role settings + */ + + 'roles' => 'Role', + 'role_user_roles' => 'Role użytkownika', + 'role_create' => 'Utwórz nową rolę', + 'role_create_success' => 'Rola utworzona pomyślnie', + 'role_delete' => 'Usuń rolę', + 'role_delete_confirm' => 'To spowoduje usunięcie roli \':roleName\'.', + 'role_delete_users_assigned' => 'Tę rolę ma przypisanych :userCount użytkowników. Jeśli chcesz zmigrować użytkowników z tej roli, wybierz nową poniżej.', + 'role_delete_no_migration' => "Nie migruj użytkowników", + 'role_delete_sure' => 'Czy na pewno chcesz usunąć tę rolę?', + 'role_delete_success' => 'Rola usunięta pomyślnie', + 'role_edit' => 'Edytuj rolę', + 'role_details' => 'Szczegóły roli', + 'role_name' => 'Nazwa roli', + 'role_desc' => 'Krótki opis roli', + 'role_system' => 'Uprawnienia systemowe', + 'role_manage_users' => 'Zarządzanie użytkownikami', + 'role_manage_roles' => 'Zarządzanie rolami i uprawnieniami ról', + 'role_manage_entity_permissions' => 'Zarządzanie uprawnieniami ksiąg, rozdziałów i stron', + 'role_manage_own_entity_permissions' => 'Zarządzanie uprawnieniami własnych ksiąg, rozdziałów i stron', + 'role_manage_settings' => 'Zarządzanie ustawieniami aplikacji', + 'role_asset' => 'Zarządzanie zasobami', + 'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia ksiąg, rozdziałów i stron nadpisują te ustawienia.', + 'role_all' => 'Wszyscy', + 'role_own' => 'Własne', + 'role_controlled_by_asset' => 'Kontrolowane przez zasób, do którego zostały udostępnione', + 'role_save' => 'Zapisz rolę', + 'role_update_success' => 'Rola zapisana pomyślnie', + 'role_users' => 'Użytkownicy w tej roli', + 'role_users_none' => 'Brak użytkowników zapisanych do tej roli', + + /** + * Users + */ + + 'users' => 'Użytkownicy', + 'user_profile' => 'Profil użytkownika', + 'users_add_new' => 'Dodaj użytkownika', + 'users_search' => 'Wyszukaj użytkownika', + 'users_role' => 'Role użytkownika', + 'users_external_auth_id' => 'Zewnętrzne ID autentykacji', + 'users_password_warning' => 'Wypełnij poniżej tylko jeśli chcesz zmienić swoje hasło:', + 'users_system_public' => 'Ten użytkownik reprezentuje każdego gościa odwiedzającego tę aplikację. Nie można się na niego zalogować, lecz jest przyznawany automatycznie.', + 'users_delete' => 'Usuń użytkownika', + 'users_delete_named' => 'Usuń :userName', + 'users_delete_warning' => 'To usunie użytkownika \':userName\' z systemu.', + 'users_delete_confirm' => 'Czy na pewno chcesz usunąć tego użytkownika?', + 'users_delete_success' => 'Użytkownik usunięty pomyślnie', + 'users_edit' => 'Edytuj użytkownika', + 'users_edit_profile' => 'Edytuj profil', + 'users_edit_success' => 'Użytkownik zaktualizowany pomyśłnie', + 'users_avatar' => 'Avatar użytkownika', + 'users_avatar_desc' => 'Ten obrazek powinien mieć 25px x 256px.', + 'users_preferred_language' => 'Preferowany język', + 'users_social_accounts' => 'Konta społecznościowe', + 'users_social_accounts_info' => 'Tutaj możesz połączyć kilka kont społecznościowych w celu łatwiejszego i szybszego logowania.', + 'users_social_connect' => 'Podłącz konto', + 'users_social_disconnect' => 'Odłącz konto', + 'users_social_connected' => ':socialAccount zostało dodane do Twojego profilu.', + 'users_social_disconnected' => ':socialAccount zostało odłączone od Twojego profilu.', +]; diff --git a/resources/lang/pl/validation.php b/resources/lang/pl/validation.php new file mode 100644 index 000000000..6a7c13e80 --- /dev/null +++ b/resources/lang/pl/validation.php @@ -0,0 +1,108 @@ + ':attribute musi zostać zaakceptowany.', + 'active_url' => ':attribute nie jest prawidłowym adresem URL.', + 'after' => ':attribute musi być datą następującą po :date.', + 'alpha' => ':attribute może zawierać wyłącznie litery.', + 'alpha_dash' => ':attribute może zawierać wyłącznie litery, cyfry i myślniki.', + 'alpha_num' => ':attribute może zawierać wyłącznie litery i cyfry.', + 'array' => ':attribute musi być tablicą.', + 'before' => ':attribute musi być datą poprzedzającą :date.', + 'between' => [ + 'numeric' => ':attribute musi zawierać się w przedziale od :min do :max.', + 'file' => 'Waga :attribute musi zawierać się pomiędzy :min i :max kilobajtów.', + 'string' => 'Długość :attribute musi zawierać się pomiędzy :min i :max.', + 'array' => ':attribute musi mieć od :min do :max elementów.', + ], + 'boolean' => ':attribute musi być wartością prawda/fałsz.', + 'confirmed' => ':attribute i potwierdzenie muszą być zgodne.', + 'date' => ':attribute nie jest prawidłową datą.', + 'date_format' => ':attribute musi mieć format :format.', + 'different' => ':attribute i :other muszą się różnić.', + 'digits' => ':attribute musi mieć :digits cyfr.', + 'digits_between' => ':attribute musi mieć od :min do :max cyfr.', + 'email' => ':attribute musi być prawidłowym adresem e-mail.', + 'filled' => ':attribute jest wymagany.', + 'exists' => 'Wybrana wartość :attribute jest nieprawidłowa.', + 'image' => ':attribute musi być obrazkiem.', + 'in' => 'Wybrana wartość :attribute jest nieprawidłowa.', + 'integer' => ':attribute musi być liczbą całkowitą.', + 'ip' => ':attribute musi być prawidłowym adresem IP.', + 'max' => [ + 'numeric' => 'Wartość :attribute nie może być większa niż :max.', + 'file' => 'Wielkość :attribute nie może być większa niż :max kilobajtów.', + 'string' => 'Długość :attribute nie może być większa niż :max znaków.', + 'array' => 'Rozmiar :attribute nie może być większy niż :max elementów.', + ], + 'mimes' => ':attribute musi być plikiem typu: :values.', + 'min' => [ + 'numeric' => 'Wartość :attribute nie może być mniejsza od :min.', + 'file' => 'Wielkość :attribute nie może być mniejsza niż :min kilobajtów.', + 'string' => 'Długość :attribute nie może być mniejsza niż :min znaków.', + 'array' => 'Rozmiar :attribute musi posiadać co najmniej :min elementy.', + ], + 'not_in' => 'Wartość :attribute jest nieprawidłowa.', + 'numeric' => ':attribute musi być liczbą.', + 'regex' => 'Format :attribute jest nieprawidłowy.', + 'required' => 'Pole :attribute jest wymagane.', + 'required_if' => 'Pole :attribute jest wymagane jeśli :other ma wartość :value.', + 'required_with' => 'Pole :attribute jest wymagane jeśli :values zostało wprowadzone.', + 'required_with_all' => 'Pole :attribute jest wymagane jeśli :values są obecne.', + 'required_without' => 'Pole :attribute jest wymagane jeśli :values nie zostało wprowadzone.', + 'required_without_all' => 'Pole :attribute jest wymagane jeśli żadna z wartości :values nie została podana.', + 'same' => 'Pole :attribute i :other muszą być takie same.', + 'size' => [ + 'numeric' => ':attribute musi mieć długość :size.', + 'file' => ':attribute musi mieć :size kilobajtów.', + 'string' => ':attribute mmusi mieć długość :size znaków.', + 'array' => ':attribute musi posiadać :size elementów.', + ], + 'string' => ':attribute musi być ciągiem znaków.', + 'timezone' => ':attribute musi być prawidłową strefą czasową.', + 'unique' => ':attribute zostało już zajęte.', + 'url' => 'Format :attribute jest nieprawidłowy.', + + /* + |-------------------------------------------------------------------------- + | 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' => 'Potwierdzenie hasła jest wymagane.', + ], + ], + + /* + |-------------------------------------------------------------------------- + | 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' => [], + +]; From 67bc7007aa58cbb44801f3df1d1f98ae3f8e2c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Fri, 14 Jul 2017 16:05:46 +0100 Subject: [PATCH 30/74] Support new lines for book/chapter descriptions Avoid ignoring new lines when renderring the book/chapter descriptions on their respective detailed views. --- resources/views/books/show.blade.php | 6 +++--- resources/views/chapters/show.blade.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php index ddbe7a0a4..d5832b708 100644 --- a/resources/views/books/show.blade.php +++ b/resources/views/books/show.blade.php @@ -56,7 +56,7 @@

{{$book->name}}

-

{{$book->description}}

+

{!! nl2br($book->description) !!}


@@ -118,7 +118,7 @@
- +

{{ trans('entities.recent_activity') }}

@include('partials/activity-list', ['activity' => Activity::entityActivity($book, 20, 0)]) @@ -127,4 +127,4 @@
-@stop \ No newline at end of file +@stop diff --git a/resources/views/chapters/show.blade.php b/resources/views/chapters/show.blade.php index d4126cbcc..9b549cfbd 100644 --- a/resources/views/chapters/show.blade.php +++ b/resources/views/chapters/show.blade.php @@ -52,7 +52,7 @@

{{ $chapter->name }}

-

{{ $chapter->description }}

+

{!! nl2br($chapter->description) !!}

@if(count($pages) > 0)
From 711dcb4a4834a562bcdb36c7dac17964e93f38a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 13:29:29 +0100 Subject: [PATCH 31/74] Update travis.yml to try and solve the test issue around LDAP. --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 909e3e1f4..c5199b65f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,9 @@ cache: directories: - $HOME/.composer/cache +before_install: + - echo "extension=ldap.so" >> php --ini | grep "Loaded Configuration" | sed -e "s|.:\s||" + before_script: - mysql -u root -e 'create database `bookstack-test`;' - mysql -u root -e "CREATE USER 'bookstack-test'@'localhost' IDENTIFIED BY 'bookstack-test';" @@ -25,4 +28,4 @@ after_failure: - cat storage/logs/laravel.log script: - - phpunit \ No newline at end of file + - phpunit From 265ed34ffd49f199fe78e571a242eae39a4ea7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 13:34:19 +0100 Subject: [PATCH 32/74] Update travis.yml to try and solve the test issue around LDAP. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c5199b65f..97895fee8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ cache: - $HOME/.composer/cache before_install: - - echo "extension=ldap.so" >> php --ini | grep "Loaded Configuration" | sed -e "s|.:\s||" + - echo "extension = ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini before_script: - mysql -u root -e 'create database `bookstack-test`;' From ae2ec43a826c92d96ae33388eba3d1599dc598e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 13:35:38 +0100 Subject: [PATCH 33/74] Avoid having to wait until all tests are processed to exit upon error/failure. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 97895fee8..c79775caf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,4 +28,4 @@ after_failure: - cat storage/logs/laravel.log script: - - phpunit + - phpunit --stop-on-error --stop-on-failure From 0d98b4ce5e4176ef4f31a5374964c054c48048db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 13:37:15 +0100 Subject: [PATCH 34/74] Trying to make the tests green. --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c79775caf..edc5732f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,6 @@ cache: directories: - $HOME/.composer/cache -before_install: - - echo "extension = ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - before_script: - mysql -u root -e 'create database `bookstack-test`;' - mysql -u root -e "CREATE USER 'bookstack-test'@'localhost' IDENTIFIED BY 'bookstack-test';" From 5eeed03dcded3d024ac719599da250444bb87ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 13:53:02 +0100 Subject: [PATCH 35/74] Trying to make the tests green. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index edc5732f6..4bd36f568 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,11 @@ language: php php: - 7.0 +before_install: + - pecl install ldap + - echo "extension=ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + - php -i "(command-line 'phpinfo()')" | grep ldap + cache: directories: - $HOME/.composer/cache From afc56c12fe02e4a1947b22b1858f6b2662e9bd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 14:01:10 +0100 Subject: [PATCH 36/74] Trying to make the tests green. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4bd36f568..a4116a317 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ php: - 7.0 before_install: - - pecl install ldap + - sudo apt-get install php7.0-ldap - echo "extension=ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - php -i "(command-line 'phpinfo()')" | grep ldap From 3b771f2976e3272e77faaf1f5aed06d66aefd48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 14:03:31 +0100 Subject: [PATCH 37/74] Trying to make the tests green. --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a4116a317..f1495b46e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,12 @@ language: php php: - 7.0 +addons: + apt: + packages: + - php7.0-ldap + before_install: - - sudo apt-get install php7.0-ldap - echo "extension=ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - php -i "(command-line 'phpinfo()')" | grep ldap From 6ef522df7ec8b43f484461e7690b08196d3585c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 14:05:41 +0100 Subject: [PATCH 38/74] Trying to make the tests green. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f1495b46e..054bc8b7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ php: addons: apt: packages: - - php7.0-ldap + - php-ldap before_install: - echo "extension=ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From 684c20c4ea186876afb4aa84115773d032d7063b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 14:09:21 +0100 Subject: [PATCH 39/74] Trying to make the tests green. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 054bc8b7d..4613c64ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,8 @@ php: addons: apt: packages: - - php-ldap + - ldap-utils + - slapd before_install: - echo "extension=ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From 3407900abb7d1fe40551881ecf901d6e69c0d5a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 14:18:03 +0100 Subject: [PATCH 40/74] Trying to make the tests green. --- .travis.yml | 1 - tests/Auth/LdapTest.php | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4613c64ef..f03865201 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,6 @@ addons: before_install: - echo "extension=ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - php -i "(command-line 'phpinfo()')" | grep ldap cache: directories: diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index 681ead91c..f66d357e3 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -21,6 +21,7 @@ class LdapTest extends BrowserKitTest { $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); + $this->mockLdap->shouldReceive('setOption'); $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ @@ -129,4 +130,4 @@ class LdapTest extends BrowserKitTest ->dontSee('External Authentication'); } -} \ No newline at end of file +} From f38bc75ab4f1d6980ecff7e2a1eb70eda8b42565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 14:21:41 +0100 Subject: [PATCH 41/74] Trying to make the tests green. --- tests/Auth/LdapTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index f66d357e3..573de4c43 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -21,7 +21,7 @@ class LdapTest extends BrowserKitTest { $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); - $this->mockLdap->shouldReceive('setOption'); + $this->mockLdap->shouldReceive('setOption')->times(4); $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ @@ -50,6 +50,7 @@ class LdapTest extends BrowserKitTest $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); $ldapDn = 'cn=test-user,dc=test' . config('services.ldap.base_dn'); + $this->mockLdap->shouldReceive('setOption')->times(2); $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ From 245294fbc55d0a2ecc765620758763b2f8f72998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Blanco?= Date: Mon, 17 Jul 2017 14:42:08 +0100 Subject: [PATCH 42/74] Trying to make the tests green. --- tests/Auth/LdapTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index 573de4c43..f6e8336e6 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -74,6 +74,7 @@ class LdapTest extends BrowserKitTest { $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); + $this->mockLdap->shouldReceive('setOption')->times(2); $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ From bc067e9ad41804de26ec37fab90ec413b48b2270 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 22 Jul 2017 14:02:47 +0100 Subject: [PATCH 43/74] Updated dropdowns to hide after option click Fixes #429 --- resources/assets/js/controllers.js | 2 +- resources/assets/js/directives.js | 40 +++++++++++++++++------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js index ac1c3487c..9337ea889 100644 --- a/resources/assets/js/controllers.js +++ b/resources/assets/js/controllers.js @@ -379,7 +379,7 @@ module.exports = function (ngApp, events) { */ $scope.discardDraft = function () { let url = window.baseUrl('/ajax/page/' + pageId); - $http.get(url).then((responseData) => { + $http.get(url).then(responseData => { if (autoSave) $interval.cancel(autoSave); $scope.draftText = trans('entities.pages_editing_page'); $scope.isUpdateDraft = false; diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js index 51f1b7579..d783fd682 100644 --- a/resources/assets/js/directives.js +++ b/resources/assets/js/directives.js @@ -123,25 +123,31 @@ module.exports = function (ngApp, events) { restrict: 'A', link: function (scope, element, attrs) { const menu = element.find('ul'); - element.find('[dropdown-toggle]').on('click', function () { + + function hide() { + menu.hide(); + menu.removeClass('anim menuIn'); + } + + function show() { menu.show().addClass('anim menuIn'); + element.mouseleave(hide); + + // Focus on input if exist in dropdown and hide on enter press let inputs = menu.find('input'); - let hasInput = inputs.length > 0; - if (hasInput) { - inputs.first().focus(); - element.on('keypress', 'input', event => { - if (event.keyCode === 13) { - event.preventDefault(); - menu.hide(); - menu.removeClass('anim menuIn'); - return false; - } - }); - } - element.mouseleave(function () { - menu.hide(); - menu.removeClass('anim menuIn'); - }); + if (inputs.length > 0) inputs.first().focus(); + } + + // Hide menu on option click + element.on('click', '> ul a', hide); + // Show dropdown on toggle click. + element.find('[dropdown-toggle]').on('click', show); + // Hide menu on enter press in inputs + element.on('keypress', 'input', event => { + if (event.keyCode !== 13) return true; + event.preventDefault(); + hide(); + return false; }); } }; From b12e2ceada9b1b8a382b76c896fc392adcdf5b84 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 22 Jul 2017 14:21:56 +0100 Subject: [PATCH 44/74] Added included content into page's text view Allows rendered content to be shown in listings and used in searches. Also prevented angular tags in content being parsed in listings. Fixes #442 --- app/Repos/EntityRepo.php | 19 +++++++++++++++---- resources/views/books/show.blade.php | 4 ++-- resources/views/chapters/show.blade.php | 4 ++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/Repos/EntityRepo.php b/app/Repos/EntityRepo.php index 7bc5fc4fc..7865de772 100644 --- a/app/Repos/EntityRepo.php +++ b/app/Repos/EntityRepo.php @@ -571,7 +571,7 @@ class EntityRepo $draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id); $draftPage->html = $this->formatHtml($input['html']); - $draftPage->text = strip_tags($draftPage->html); + $draftPage->text = $this->pageToPlainText($draftPage->html); $draftPage->draft = false; $draftPage->revision_count = 1; @@ -713,6 +713,17 @@ class EntityRepo return $content; } + /** + * Get the plain text version of a page's content. + * @param Page $page + * @return string + */ + public function pageToPlainText(Page $page) + { + $html = $this->renderPage($page); + return strip_tags($html); + } + /** * Get a new draft page instance. * @param Book $book @@ -816,7 +827,7 @@ class EntityRepo $userId = user()->id; $page->fill($input); $page->html = $this->formatHtml($input['html']); - $page->text = strip_tags($page->html); + $page->text = $this->pageToPlainText($page); if (setting('app-editor') !== 'markdown') $page->markdown = ''; $page->updated_by = $userId; $page->revision_count++; @@ -933,7 +944,7 @@ class EntityRepo $revision = $page->revisions()->where('id', '=', $revisionId)->first(); $page->fill($revision->toArray()); $page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id); - $page->text = strip_tags($page->html); + $page->text = $this->pageToPlainText($page->html); $page->updated_by = user()->id; $page->save(); $this->searchService->indexEntity($page); @@ -953,7 +964,7 @@ class EntityRepo if ($page->draft) { $page->fill($data); if (isset($data['html'])) { - $page->text = strip_tags($data['html']); + $page->text = $this->pageToPlainText($data['html']); } $page->save(); return $page; diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php index ddbe7a0a4..353018dbc 100644 --- a/resources/views/books/show.blade.php +++ b/resources/views/books/show.blade.php @@ -50,7 +50,7 @@
-
+
@@ -112,7 +112,7 @@ @endif -
+

{{ $chapter->name }}

@@ -116,7 +116,7 @@ @endif