diff --git a/app/Http/Controllers/AttachmentController.php b/app/Http/Controllers/AttachmentController.php index a81cb8a68..b5e7db41e 100644 --- a/app/Http/Controllers/AttachmentController.php +++ b/app/Http/Controllers/AttachmentController.php @@ -117,7 +117,7 @@ class AttachmentController extends Controller } $attachment = $this->attachmentService->updateFile($attachment, $request->all()); - return $this->jsonSuccess($attachment, trans('entities.attachments_updated_success')); + return response()->json($attachment); } /** diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index c5255c0ba..2b6c88fe0 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -117,17 +117,6 @@ abstract class Controller extends BaseController return true; } - /** - * Send a json respons with a message attached as a header. - * @param $data - * @param string $successMessage - * @return $this - */ - protected function jsonSuccess($data, $successMessage = "") - { - return response()->json($data)->header('message-success', $successMessage); - } - /** * Send back a json error message. * @param string $messageText diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 2fc64b236..e325b9322 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -43,4 +43,39 @@ class HomeController extends Controller ]); } + /** + * Get a js representation of the current translations + * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response + */ + public function getTranslations() { + $locale = trans()->getLocale(); + $cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale; + if (cache()->has($cacheKey) && config('app.env') !== 'development') { + $resp = cache($cacheKey); + } else { + $translations = [ + // Get only translations which might be used in JS + 'common' => trans('common'), + 'components' => trans('components'), + 'entities' => trans('entities'), + 'errors' => trans('errors') + ]; + if ($locale !== 'en') { + $enTrans = [ + 'common' => trans('common', [], null, 'en'), + 'components' => trans('components', [], null, 'en'), + 'entities' => trans('entities', [], null, 'en'), + 'errors' => trans('errors', [], null, 'en') + ]; + $translations = array_replace_recursive($enTrans, $translations); + } + $resp = 'window.translations = ' . json_encode($translations); + cache()->put($cacheKey, $resp, 120); + } + + return response($resp, 200, [ + 'Content-Type' => 'application/javascript' + ]); + } + } diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js index af740f508..0d57b09ad 100644 --- a/resources/assets/js/controllers.js +++ b/resources/assets/js/controllers.js @@ -64,7 +64,7 @@ export default function (ngApp, events) { $scope.$apply(() => { $scope.images.unshift(data); }); - events.emit('success', 'Image uploaded'); + events.emit('success', trans('components.image_upload_success')); }; /** @@ -151,10 +151,9 @@ export default function (ngApp, events) { if ($scope.searching) components['term'] = $scope.searchTerm; - let urlQueryString = Object.keys(components).map((key) => { + url += Object.keys(components).map((key) => { return key + '=' + encodeURIComponent(components[key]); }).join('&'); - url += urlQueryString; $http.get(url).then((response) => { $scope.images = $scope.images.concat(response.data.images); @@ -209,7 +208,7 @@ export default function (ngApp, events) { event.preventDefault(); let url = window.baseUrl('/images/update/' + $scope.selectedImage.id); $http.put(url, this.selectedImage).then(response => { - events.emit('success', 'Image details updated'); + events.emit('success', trans('components.image_update_success')); }, (response) => { if (response.status === 422) { let errors = response.data; @@ -238,7 +237,7 @@ export default function (ngApp, events) { $http.delete(url).then((response) => { $scope.images.splice($scope.images.indexOf($scope.selectedImage), 1); $scope.selectedImage = false; - events.emit('success', 'Image successfully deleted'); + events.emit('success', trans('components.image_delete_success')); }, (response) => { // Pages failure if (response.status === 400) { @@ -309,9 +308,9 @@ export default function (ngApp, events) { // Set initial header draft text if ($scope.isUpdateDraft || $scope.isNewPageDraft) { - $scope.draftText = 'Editing Draft' + $scope.draftText = trans('entities.pages_editing_draft'); } else { - $scope.draftText = 'Editing Page' + $scope.draftText = trans('entities.pages_editing_page'); } let autoSave = false; @@ -388,7 +387,7 @@ export default function (ngApp, events) { lastSave = Date.now(); }, errorRes => { if (draftErroring) return; - events.emit('error', 'Failed to save draft. Ensure you have internet connection before saving this page.') + events.emit('error', trans('errors.page_draft_autosave_fail')); draftErroring = true; }); } @@ -421,7 +420,7 @@ export default function (ngApp, events) { let url = window.baseUrl('/ajax/page/' + pageId); $http.get(url).then((responseData) => { if (autoSave) $interval.cancel(autoSave); - $scope.draftText = 'Editing Page'; + $scope.draftText = trans('entities.pages_editing_page'); $scope.isUpdateDraft = false; $scope.$broadcast('html-update', responseData.data.html); $scope.$broadcast('markdown-update', responseData.data.markdown || responseData.data.html); @@ -429,7 +428,7 @@ export default function (ngApp, events) { $timeout(() => { startAutoSave(); }, 1000); - events.emit('success', 'Draft discarded, The editor has been updated with the current page content'); + events.emit('success', trans('entities.pages_draft_discarded')); }); }; @@ -594,7 +593,7 @@ export default function (ngApp, events) { $scope.$apply(() => { $scope.files.push(data); }); - events.emit('success', 'File uploaded'); + events.emit('success', trans('entities.attachments_file_uploaded')); }; /** @@ -612,7 +611,7 @@ export default function (ngApp, events) { data.link = ''; } }); - events.emit('success', 'File updated'); + events.emit('success', trans('entities.attachments_file_updated')); }; /** @@ -638,7 +637,7 @@ export default function (ngApp, events) { file.uploaded_to = pageId; $http.post(window.baseUrl('/attachments/link'), file).then(resp => { $scope.files.push(resp.data); - events.emit('success', 'Link attached'); + events.emit('success', trans('entities.attachments_link_attached')); $scope.file = getCleanFile(); }, checkError('link')); }; @@ -672,7 +671,7 @@ export default function (ngApp, events) { $scope.editFile.link = ''; } $scope.editFile = false; - events.emit('success', resp.headers('message-success')); + events.emit('success', trans('entities.attachments_updated_success')); }, checkError('edit')); }; diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js index 68c3150e0..ef8bcd85c 100644 --- a/resources/assets/js/directives.js +++ b/resources/assets/js/directives.js @@ -102,7 +102,7 @@ export default function (ngApp, events) { $(file.previewElement).find('[data-dz-errormessage]').text(message); } - if (xhr.status === 413) setMessage('The server does not allow uploads of this size. Please try a smaller file.'); + if (xhr.status === 413) setMessage(trans('errors.server_upload_limit')); if (errorMessage.file) setMessage(errorMessage.file[0]); }); @@ -261,15 +261,21 @@ export default function (ngApp, events) { link: function (scope, element, attrs) { // Elements - const input = element.find('[markdown-input] textarea').first(); - const display = element.find('.markdown-display').first(); - const insertImage = element.find('button[data-action="insertImage"]'); - const insertEntityLink = element.find('button[data-action="insertEntityLink"]') + const $input = element.find('[markdown-input] textarea').first(); + const $display = element.find('.markdown-display').first(); + const $insertImage = element.find('button[data-action="insertImage"]'); + const $insertEntityLink = element.find('button[data-action="insertEntityLink"]'); + + // Prevent markdown display link click redirect + $display.on('click', 'a', function(event) { + event.preventDefault(); + window.open(this.getAttribute('href')); + }); let currentCaretPos = 0; - input.blur(event => { - currentCaretPos = input[0].selectionStart; + $input.blur(event => { + currentCaretPos = $input[0].selectionStart; }); // Scroll sync @@ -279,10 +285,10 @@ export default function (ngApp, events) { displayHeight; function setScrollHeights() { - inputScrollHeight = input[0].scrollHeight; - inputHeight = input.height(); - displayScrollHeight = display[0].scrollHeight; - displayHeight = display.height(); + inputScrollHeight = $input[0].scrollHeight; + inputHeight = $input.height(); + displayScrollHeight = $display[0].scrollHeight; + displayHeight = $display.height(); } setTimeout(() => { @@ -291,29 +297,29 @@ export default function (ngApp, events) { window.addEventListener('resize', setScrollHeights); let scrollDebounceTime = 800; let lastScroll = 0; - input.on('scroll', event => { + $input.on('scroll', event => { let now = Date.now(); if (now - lastScroll > scrollDebounceTime) { setScrollHeights() } - let scrollPercent = (input.scrollTop() / (inputScrollHeight - inputHeight)); + let scrollPercent = ($input.scrollTop() / (inputScrollHeight - inputHeight)); let displayScrollY = (displayScrollHeight - displayHeight) * scrollPercent; - display.scrollTop(displayScrollY); + $display.scrollTop(displayScrollY); lastScroll = now; }); // Editor key-presses - input.keydown(event => { + $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(); + 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); + $input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); + $input.focus(); + $input[0].selectionStart = caretPos + ("![](".length); + $input[0].selectionEnd = caretPos + ('![](http://'.length); return; } @@ -328,35 +334,35 @@ export default function (ngApp, events) { }); // Insert image from image manager - insertImage.click(event => { + $insertImage.click(event => { window.ImageManager.showExternal(image => { let caretPos = currentCaretPos; - let currentContent = input.val(); + let currentContent = $input.val(); let mdImageText = "![" + image.name + "](" + image.thumbs.display + ")"; - input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); - input.change(); + $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 selectionEnd = $input[0].selectionEnd; let textSelected = (selectionEnd !== selectionStart); - let currentContent = input.val(); + 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)); + $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.val(currentContent.substring(0, selectionStart) + linkText + currentContent.substring(selectionStart)) } - input.change(); + $input.change(); }); } - insertEntityLink.click(showLinkSelector); + $insertEntityLink.click(showLinkSelector); // Upload and insert image on paste function editorPaste(e) { @@ -369,7 +375,7 @@ export default function (ngApp, events) { } } - input.on('paste', editorPaste); + $input.on('paste', editorPaste); // Handle image drop, Uploads images to BookStack. function handleImageDrop(event) { @@ -381,7 +387,7 @@ export default function (ngApp, events) { } } - input.on('drop', handleImageDrop); + $input.on('drop', handleImageDrop); // Handle image upload and add image into markdown content function uploadImage(file) { @@ -399,17 +405,17 @@ export default function (ngApp, events) { // 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 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[0].value = content.substring(0, selectStart) + innerContent + content.substring(selectEnd); - input.focus(); - input[0].selectionStart = selectStart; - input[0].selectionEnd = selectStart; + $input.focus(); + $input[0].selectionStart = selectStart; + $input[0].selectionEnd = selectStart; let remoteFilename = "image-" + Date.now() + "." + ext; formData.append('file', file, remoteFilename); @@ -417,20 +423,20 @@ export default function (ngApp, events) { xhr.open('POST', window.baseUrl('/images/gallery/upload')); xhr.onload = function () { - let selectStart = input[0].selectionStart; + 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(); + $input[0].value = $input[0].value.replace(placeholderImage, result.thumbs.display); + $input.change(); } else { - console.log('An error occurred uploading the image'); + console.log(trans('errors.image_upload_error')); console.log(xhr.responseText); - input[0].value = input[0].value.replace(innerContent, ''); - input.change(); + $input[0].value = $input[0].value.replace(innerContent, ''); + $input.change(); } - input.focus(); - input[0].selectionStart = selectStart; - input[0].selectionEnd = selectStart; + $input.focus(); + $input[0].selectionStart = selectStart; + $input[0].selectionEnd = selectStart; }; xhr.send(formData); } @@ -568,8 +574,7 @@ export default function (ngApp, events) { } // Enter or tab key else if ((event.keyCode === 13 || event.keyCode === 9) && !event.shiftKey) { - let text = suggestionElems[active].textContent; - currentInput[0].value = text; + currentInput[0].value = suggestionElems[active].textContent; currentInput.focus(); $suggestionBox.hide(); isShowing = false; @@ -665,7 +670,7 @@ export default function (ngApp, events) { ngApp.directive('entityLinkSelector', [function($http) { return { - restict: 'A', + restrict: 'A', link: function(scope, element, attrs) { const selectButton = element.find('.entity-link-selector-confirm'); diff --git a/resources/assets/js/global.js b/resources/assets/js/global.js index 7a7cc592e..94462ed64 100644 --- a/resources/assets/js/global.js +++ b/resources/assets/js/global.js @@ -17,6 +17,12 @@ window.baseUrl = function(path) { let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); +// Translation setup +// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system +import Translations from "./translations" +let translator = new Translations(window.translations); +window.trans = translator.get.bind(translator); + // Global Event System class EventManager { constructor() { @@ -70,150 +76,83 @@ jQuery.expr[":"].contains = $.expr.createPseudo(function (arg) { }); // Global jQuery Elements -$(function () { - - let notifications = $('.notification'); - let successNotification = notifications.filter('.pos'); - let errorNotification = notifications.filter('.neg'); - let warningNotification = notifications.filter('.warning'); - // Notification Events - window.Events.listen('success', function (text) { - successNotification.hide(); - successNotification.find('span').text(text); - setTimeout(() => { - successNotification.show(); - }, 1); - }); - window.Events.listen('warning', function (text) { - warningNotification.find('span').text(text); - warningNotification.show(); - }); - window.Events.listen('error', function (text) { - errorNotification.find('span').text(text); - errorNotification.show(); - }); - - // Notification hiding - notifications.click(function () { - $(this).fadeOut(100); - }); - - // Chapter page list toggles - $('.chapter-toggle').click(function (e) { - e.preventDefault(); - $(this).toggleClass('open'); - $(this).closest('.chapter').find('.inset-list').slideToggle(180); - }); - - // Back to top button - $('#back-to-top').click(function() { - $('#header').smoothScrollTo(); - }); - let scrollTopShowing = false; - let scrollTop = document.getElementById('back-to-top'); - let scrollTopBreakpoint = 1200; - window.addEventListener('scroll', function() { - let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0; - if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) { - scrollTop.style.display = 'block'; - scrollTopShowing = true; - setTimeout(() => { - scrollTop.style.opacity = 0.4; - }, 1); - } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) { - scrollTop.style.opacity = 0; - scrollTopShowing = false; - setTimeout(() => { - scrollTop.style.display = 'none'; - }, 500); - } - }); - - // Common jQuery actions - $('[data-action="expand-entity-list-details"]').click(function() { - $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240); - }); - - // Popup close - $('.popup-close').click(function() { - $(this).closest('.overlay').fadeOut(240); - }); - $('.overlay').click(function(event) { - if (!$(event.target).hasClass('overlay')) return; - $(this).fadeOut(240); - }); - - // Prevent markdown display link click redirect - $('.markdown-display').on('click', 'a', function(event) { - event.preventDefault(); - window.open($(this).attr('href')); - }); - - // Toggle Switches - let $switches = $('[toggle-switch]'); - if ($switches.length > 0) { - $switches.click(event => { - let $switch = $(event.target); - let input = $switch.find('input').first()[0]; - let checked = input.value !== 'true'; - input.value = checked ? 'true' : 'false'; - $switch.toggleClass('active', checked); - }); - } - - // Image pickers - $('.image-picker').on('click', 'button', event => { - let button = event.target; - let picker = $(button).closest('.image-picker')[0]; - let action = button.getAttribute('data-action'); - let resize = picker.getAttribute('data-resize-height') && picker.getAttribute('data-resize-width'); - let usingIds = picker.getAttribute('data-current-id') !== ''; - let resizeCrop = picker.getAttribute('data-resize-crop') !== ''; - let imageElem = picker.querySelector('img'); - let input = picker.querySelector('input'); - - function setImage(image) { - - if (image === 'none') { - imageElem.src = picker.getAttribute('data-default-image'); - imageElem.classList.add('none'); - input.value = 'none'; - return; - } - - imageElem.src = image.url; - input.value = usingIds ? image.id : image.url; - imageElem.classList.remove('none'); - } - - if (action === 'show-image-manager') { - window.ImageManager.showExternal((image) => { - if (!resize) { - setImage(image); - return; - } - let requestString = '/images/thumb/' + image.id + '/' + picker.getAttribute('data-resize-width') + '/' + picker.getAttribute('data-resize-height') + '/' + (resizeCrop ? 'true' : 'false'); - $.get(window.baseUrl(requestString), resp => { - image.url = resp.url; - setImage(image); - }); - }); - } else if (action === 'reset-image') { - setImage({id: 0, url: picker.getAttribute('data-default-image')}); - } else if (action === 'remove-image') { - setImage('none'); - } - - }); - - // Detect IE for css - if(navigator.userAgent.indexOf('MSIE')!==-1 - || navigator.appVersion.indexOf('Trident/') > 0 - || navigator.userAgent.indexOf('Safari') !== -1){ - $('body').addClass('flexbox-support'); - } - +let notifications = $('.notification'); +let successNotification = notifications.filter('.pos'); +let errorNotification = notifications.filter('.neg'); +let warningNotification = notifications.filter('.warning'); +// Notification Events +window.Events.listen('success', function (text) { + successNotification.hide(); + successNotification.find('span').text(text); + setTimeout(() => { + successNotification.show(); + }, 1); }); +window.Events.listen('warning', function (text) { + warningNotification.find('span').text(text); + warningNotification.show(); +}); +window.Events.listen('error', function (text) { + errorNotification.find('span').text(text); + errorNotification.show(); +}); + +// Notification hiding +notifications.click(function () { + $(this).fadeOut(100); +}); + +// Chapter page list toggles +$('.chapter-toggle').click(function (e) { + e.preventDefault(); + $(this).toggleClass('open'); + $(this).closest('.chapter').find('.inset-list').slideToggle(180); +}); + +// Back to top button +$('#back-to-top').click(function() { + $('#header').smoothScrollTo(); +}); +let scrollTopShowing = false; +let scrollTop = document.getElementById('back-to-top'); +let scrollTopBreakpoint = 1200; +window.addEventListener('scroll', function() { + let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0; + if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) { + scrollTop.style.display = 'block'; + scrollTopShowing = true; + setTimeout(() => { + scrollTop.style.opacity = 0.4; + }, 1); + } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) { + scrollTop.style.opacity = 0; + scrollTopShowing = false; + setTimeout(() => { + scrollTop.style.display = 'none'; + }, 500); + } +}); + +// Common jQuery actions +$('[data-action="expand-entity-list-details"]').click(function() { + $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240); +}); + +// Popup close +$('.popup-close').click(function() { + $(this).closest('.overlay').fadeOut(240); +}); +$('.overlay').click(function(event) { + if (!$(event.target).hasClass('overlay')) return; + $(this).fadeOut(240); +}); + +// Detect IE for css +if(navigator.userAgent.indexOf('MSIE')!==-1 + || navigator.appVersion.indexOf('Trident/') > 0 + || navigator.userAgent.indexOf('Safari') !== -1){ + $('body').addClass('flexbox-support'); +} // Page specific items import "./pages/page-show"; diff --git a/resources/assets/js/translations.js b/resources/assets/js/translations.js new file mode 100644 index 000000000..306c696b6 --- /dev/null +++ b/resources/assets/js/translations.js @@ -0,0 +1,47 @@ +/** + * Translation Manager + * Handles the JavaScript side of translating strings + * in a way which fits with Laravel. + */ +class Translator { + + /** + * Create an instance, Passing in the required translations + * @param translations + */ + constructor(translations) { + this.store = translations; + } + + /** + * Get a translation, Same format as laravel's 'trans' helper + * @param key + * @param replacements + * @returns {*} + */ + get(key, replacements) { + let splitKey = key.split('.'); + let value = splitKey.reduce((a, b) => { + return a != undefined ? a[b] : a; + }, this.store); + + if (value === undefined) { + console.log(`Translation with key "${key}" does not exist`); + value = key; + } + + if (replacements === undefined) return value; + + let replaceMatches = value.match(/:([\S]+)/g); + if (replaceMatches === null) return value; + replaceMatches.forEach(match => { + let key = match.substring(1); + if (typeof replacements[key] === 'undefined') return; + value = value.replace(match, replacements[key]); + }); + return value; + } + +} + +export default Translator diff --git a/resources/assets/sass/_tables.scss b/resources/assets/sass/_tables.scss index 37c61159d..21553b839 100644 --- a/resources/assets/sass/_tables.scss +++ b/resources/assets/sass/_tables.scss @@ -35,6 +35,12 @@ table.table { tr:hover { background-color: #EEE; } + .text-right { + text-align: right; + } + .text-center { + text-align: center; + } } table.no-style { diff --git a/resources/lang/de/settings.php b/resources/lang/de/settings.php index 183480faa..0017acd1d 100644 --- a/resources/lang/de/settings.php +++ b/resources/lang/de/settings.php @@ -16,7 +16,7 @@ return [ 'app_name_desc' => 'Dieser Name wird im Header und E-Mails angezeigt.', 'app_name_header' => 'Anwendungsname im Header anzeigen?', 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', - 'app_secure_images' => 'Erh&oml;hte Sicherheit für Bilduploads aktivieren?', + 'app_secure_images' => 'Erhöhte Sicherheit für Bilduploads aktivieren?', 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten vor die Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnindexes deaktiviert sind, um einen einfachen Zugrif zu verhindern.', 'app_editor' => 'Seiteneditor', 'app_editor_desc' => 'Wählen sie den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.', diff --git a/resources/lang/en/components.php b/resources/lang/en/components.php index cc023799a..b9108702a 100644 --- a/resources/lang/en/components.php +++ b/resources/lang/en/components.php @@ -4,18 +4,21 @@ return [ /** * Image Manager */ - 'imagem_select' => 'Image Select', - 'imagem_all' => 'All', - 'imagem_all_title' => 'View all images', - 'imagem_book_title' => 'View images uploaded to this book', - 'imagem_page_title' => 'View images uploaded to this page', - 'imagem_search_hint' => 'Search by image name', - 'imagem_uploaded' => 'Uploaded :uploadedDate', - 'imagem_load_more' => 'Load More', - 'imagem_image_name' => 'Image Name', - 'imagem_delete_confirm' => 'This image is used in the pages below, Click delete again to confirm you want to delete this image.', - 'imagem_select_image' => 'Select Image', - 'imagem_dropzone' => 'Drop images or click here to upload', + 'image_select' => 'Image Select', + 'image_all' => 'All', + 'image_all_title' => 'View all images', + 'image_book_title' => 'View images uploaded to this book', + 'image_page_title' => 'View images uploaded to this page', + 'image_search_hint' => 'Search by image name', + 'image_uploaded' => 'Uploaded :uploadedDate', + 'image_load_more' => 'Load More', + 'image_image_name' => 'Image Name', + 'image_delete_confirm' => 'This image is used in the pages below, Click delete again to confirm you want to delete this image.', + 'image_select_image' => 'Select Image', + 'image_dropzone' => 'Drop images or click here to upload', 'images_deleted' => 'Images Deleted', 'image_preview' => 'Image Preview', + 'image_upload_success' => 'Image uploaded successfully', + 'image_update_success' => 'Image details successfully updated', + 'image_delete_success' => 'Image successfully deleted' ]; \ No newline at end of file diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 87ffb4985..033d9614e 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -129,6 +129,8 @@ return [ 'pages_edit_toggle_header' => 'Toggle header', 'pages_edit_save_draft' => 'Save Draft', 'pages_edit_draft' => 'Edit Page Draft', + 'pages_editing_draft' => 'Editing Draft', + 'pages_editing_page' => 'Editing Page', 'pages_edit_draft_save_at' => 'Draft saved at ', 'pages_edit_delete_draft' => 'Delete Draft', 'pages_edit_discard_draft' => 'Discard Draft', @@ -175,6 +177,7 @@ return [ 'time_b' => 'in the last :minCount minutes', 'message' => ':start :time. Take care not to overwrite each other\'s updates!', ], + 'pages_draft_discarded' => 'Draft discarded, The editor has been updated with the current page content', /** * Editor sidebar @@ -207,6 +210,9 @@ return [ 'attachments_order_updated' => 'Attachment order updated', 'attachments_updated_success' => 'Attachment details updated', 'attachments_deleted' => 'Attachment deleted', + 'attachments_file_uploaded' => 'File successfully uploaded', + 'attachments_file_updated' => 'File successfully updated', + 'attachments_link_attached' => 'Link successfully attached to page', /** * Profile View diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index d36f39932..c4578a37a 100644 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -33,10 +33,15 @@ return [ 'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.', 'cannot_get_image_from_url' => 'Cannot get image from :url', 'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.', + 'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.', + 'image_upload_error' => 'An error occurred uploading the image', // Attachments 'attachment_page_mismatch' => 'Page mismatch during attachment update', + // Pages + 'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page', + // Entities 'entity_not_found' => 'Entity not found', 'book_not_found' => 'Book not found', diff --git a/resources/views/base.blade.php b/resources/views/base.blade.php index b1c74fbd0..43f22d89a 100644 --- a/resources/views/base.blade.php +++ b/resources/views/base.blade.php @@ -17,6 +17,7 @@ + @yield('head') diff --git a/resources/views/chapters/move.blade.php b/resources/views/chapters/move.blade.php index a28d61d41..9e6ddb521 100644 --- a/resources/views/chapters/move.blade.php +++ b/resources/views/chapters/move.blade.php @@ -19,7 +19,7 @@ {!! csrf_field() !!} - @include('partials/entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book']) + @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book']) {{ trans('common.cancel') }} diff --git a/resources/views/partials/entity-selector-popup.blade.php b/resources/views/components/entity-selector-popup.blade.php similarity index 88% rename from resources/views/partials/entity-selector-popup.blade.php rename to resources/views/components/entity-selector-popup.blade.php index a758cc021..1c4d1fadb 100644 --- a/resources/views/partials/entity-selector-popup.blade.php +++ b/resources/views/components/entity-selector-popup.blade.php @@ -5,7 +5,7 @@ - @include('partials/entity-selector', ['name' => 'entity-selector']) + @include('components.entity-selector', ['name' => 'entity-selector']) diff --git a/resources/views/partials/entity-selector.blade.php b/resources/views/components/entity-selector.blade.php similarity index 93% rename from resources/views/partials/entity-selector.blade.php rename to resources/views/components/entity-selector.blade.php index 8f3d82f67..8fb2187e6 100644 --- a/resources/views/partials/entity-selector.blade.php +++ b/resources/views/components/entity-selector.blade.php @@ -2,7 +2,7 @@
-
@include('partials/loading-icon')
+
@include('partials.loading-icon')
\ No newline at end of file diff --git a/resources/views/partials/image-manager.blade.php b/resources/views/components/image-manager.blade.php similarity index 80% rename from resources/views/partials/image-manager.blade.php rename to resources/views/components/image-manager.blade.php index 0d3626f5e..39f3bcd3c 100644 --- a/resources/views/partials/image-manager.blade.php +++ b/resources/views/components/image-manager.blade.php @@ -3,7 +3,7 @@ @@ -51,14 +51,14 @@
- +

- {{ trans('components.imagem_delete_confirm') }} + {{ trans('components.image_delete_confirm') }}

- + diff --git a/resources/views/components/image-picker.blade.php b/resources/views/components/image-picker.blade.php index c2c56ee9f..47fb2b8b7 100644 --- a/resources/views/components/image-picker.blade.php +++ b/resources/views/components/image-picker.blade.php @@ -1,10 +1,10 @@ -
+
{{ trans('components.image_preview') }}
- +
@@ -13,5 +13,54 @@ @endif - -
\ No newline at end of file + +
+ + \ No newline at end of file diff --git a/resources/views/components/toggle-switch.blade.php b/resources/views/components/toggle-switch.blade.php index b20b74d5e..ad54d5ab1 100644 --- a/resources/views/components/toggle-switch.blade.php +++ b/resources/views/components/toggle-switch.blade.php @@ -1,4 +1,15 @@ -
+
-
\ No newline at end of file +
+ \ No newline at end of file diff --git a/resources/views/pages/edit.blade.php b/resources/views/pages/edit.blade.php index e50cc7c5b..e1c0a169d 100644 --- a/resources/views/pages/edit.blade.php +++ b/resources/views/pages/edit.blade.php @@ -20,7 +20,7 @@ - @include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) - @include('partials/entity-selector-popup') + @include('components.image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) + @include('components.entity-selector-popup') @stop \ No newline at end of file diff --git a/resources/views/pages/move.blade.php b/resources/views/pages/move.blade.php index 2bf226047..a9b6d69d7 100644 --- a/resources/views/pages/move.blade.php +++ b/resources/views/pages/move.blade.php @@ -19,7 +19,7 @@ {!! csrf_field() !!} - @include('partials/entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter']) + @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter']) {{ trans('common.cancel') }} diff --git a/resources/views/partials/custom-styles.blade.php b/resources/views/partials/custom-styles.blade.php index 885cc2729..62bcc881f 100644 --- a/resources/views/partials/custom-styles.blade.php +++ b/resources/views/partials/custom-styles.blade.php @@ -1,4 +1,4 @@ -