mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-08-25 11:45:58 +00:00
converted image picker to blade-based component
Also updated some other JS translations
This commit is contained in:
parent
242dc21876
commit
05316c90ba
@ -117,7 +117,7 @@ class AttachmentController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$attachment = $this->attachmentService->updateFile($attachment, $request->all());
|
$attachment = $this->attachmentService->updateFile($attachment, $request->all());
|
||||||
return $attachment;
|
return $this->jsonSuccess($attachment, trans('entities.attachments_updated_success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,6 +117,17 @@ abstract class Controller extends BaseController
|
|||||||
return true;
|
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.
|
* Send back a json error message.
|
||||||
* @param string $messageText
|
* @param string $messageText
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
return [
|
return [
|
||||||
|
|
||||||
'app-name' => 'BookStack',
|
'app-name' => 'BookStack',
|
||||||
|
'app-logo' => '',
|
||||||
'app-name-header' => true,
|
'app-name-header' => true,
|
||||||
'app-editor' => 'wysiwyg',
|
'app-editor' => 'wysiwyg',
|
||||||
'app-color' => '#0288D1',
|
'app-color' => '#0288D1',
|
||||||
|
@ -576,7 +576,7 @@ export default function (ngApp, events) {
|
|||||||
* Get files for the current page from the server.
|
* Get files for the current page from the server.
|
||||||
*/
|
*/
|
||||||
function getFiles() {
|
function getFiles() {
|
||||||
let url = window.baseUrl(`/attachments/get/page/${pageId}`)
|
let url = window.baseUrl(`/attachments/get/page/${pageId}`);
|
||||||
$http.get(url).then(resp => {
|
$http.get(url).then(resp => {
|
||||||
$scope.files = resp.data;
|
$scope.files = resp.data;
|
||||||
currentOrder = resp.data.map(file => {return file.id}).join(':');
|
currentOrder = resp.data.map(file => {return file.id}).join(':');
|
||||||
@ -672,7 +672,7 @@ export default function (ngApp, events) {
|
|||||||
$scope.editFile.link = '';
|
$scope.editFile.link = '';
|
||||||
}
|
}
|
||||||
$scope.editFile = false;
|
$scope.editFile = false;
|
||||||
events.emit('success', 'Attachment details updated');
|
events.emit('success', resp.headers('message-success'));
|
||||||
}, checkError('edit'));
|
}, checkError('edit'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ export default function (ngApp, events) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sub form component to allow inner-form sections to act like thier own forms.
|
* Sub form component to allow inner-form sections to act like their own forms.
|
||||||
*/
|
*/
|
||||||
ngApp.directive('subForm', function() {
|
ngApp.directive('subForm', function() {
|
||||||
return {
|
return {
|
||||||
@ -50,96 +50,13 @@ export default function (ngApp, events) {
|
|||||||
element.find('button[type="submit"]').click(submitEvent);
|
element.find('button[type="submit"]').click(submitEvent);
|
||||||
|
|
||||||
function submitEvent(e) {
|
function submitEvent(e) {
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
if (attrs.subForm) scope.$eval(attrs.subForm);
|
if (attrs.subForm) scope.$eval(attrs.subForm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Image Picker
|
|
||||||
* Is a simple front-end interface that connects to an ImageManager if present.
|
|
||||||
*/
|
|
||||||
ngApp.directive('imagePicker', ['$http', 'imageManagerService', function ($http, imageManagerService) {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
template: `
|
|
||||||
<div class="image-picker">
|
|
||||||
<div>
|
|
||||||
<img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
|
|
||||||
<img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
|
|
||||||
</div>
|
|
||||||
<button class="button" type="button" ng-click="showImageManager()">Select Image</button>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<button class="text-button" ng-click="reset()" type="button">Reset</button>
|
|
||||||
<span ng-show="showRemove" class="sep">|</span>
|
|
||||||
<button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
|
|
||||||
|
|
||||||
<input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
scope: {
|
|
||||||
name: '@',
|
|
||||||
resizeHeight: '@',
|
|
||||||
resizeWidth: '@',
|
|
||||||
resizeCrop: '@',
|
|
||||||
showRemove: '=',
|
|
||||||
currentImage: '@',
|
|
||||||
currentId: '@',
|
|
||||||
defaultImage: '@',
|
|
||||||
imageClass: '@'
|
|
||||||
},
|
|
||||||
link: function (scope, element, attrs) {
|
|
||||||
let usingIds = typeof scope.currentId !== 'undefined' || scope.currentId === 'false';
|
|
||||||
scope.image = scope.currentImage;
|
|
||||||
scope.value = scope.currentImage || '';
|
|
||||||
if (usingIds) scope.value = scope.currentId;
|
|
||||||
|
|
||||||
function setImage(imageModel, imageUrl) {
|
|
||||||
scope.image = imageUrl;
|
|
||||||
scope.value = usingIds ? imageModel.id : imageUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.reset = function () {
|
|
||||||
setImage({id: 0}, scope.defaultImage);
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.remove = function () {
|
|
||||||
scope.image = 'none';
|
|
||||||
scope.value = 'none';
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.showImageManager = function () {
|
|
||||||
imageManagerService.show((image) => {
|
|
||||||
scope.updateImageFromModel(image);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.updateImageFromModel = function (model) {
|
|
||||||
let isResized = scope.resizeWidth && scope.resizeHeight;
|
|
||||||
|
|
||||||
if (!isResized) {
|
|
||||||
scope.$apply(() => {
|
|
||||||
setImage(model, model.url);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cropped = scope.resizeCrop ? 'true' : 'false';
|
|
||||||
let requestString = '/images/thumb/' + model.id + '/' + scope.resizeWidth + '/' + scope.resizeHeight + '/' + cropped;
|
|
||||||
requestString = window.baseUrl(requestString);
|
|
||||||
$http.get(requestString).then((response) => {
|
|
||||||
setImage(model, response.data.url);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DropZone
|
* DropZone
|
||||||
* Used for uploading images
|
* Used for uploading images
|
||||||
@ -149,16 +66,17 @@ export default function (ngApp, events) {
|
|||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
template: `
|
template: `
|
||||||
<div class="dropzone-container">
|
<div class="dropzone-container">
|
||||||
<div class="dz-message">Drop files or click here to upload</div>
|
<div class="dz-message">{{message}}</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
scope: {
|
scope: {
|
||||||
uploadUrl: '@',
|
uploadUrl: '@',
|
||||||
eventSuccess: '=',
|
eventSuccess: '=',
|
||||||
eventError: '=',
|
eventError: '=',
|
||||||
uploadedTo: '@'
|
uploadedTo: '@',
|
||||||
},
|
},
|
||||||
link: function (scope, element, attrs) {
|
link: function (scope, element, attrs) {
|
||||||
|
scope.message = attrs.message;
|
||||||
if (attrs.placeholder) element[0].querySelector('.dz-message').textContent = attrs.placeholder;
|
if (attrs.placeholder) element[0].querySelector('.dz-message').textContent = attrs.placeholder;
|
||||||
let dropZone = new DropZone(element[0].querySelector('.dropzone-container'), {
|
let dropZone = new DropZone(element[0].querySelector('.dropzone-container'), {
|
||||||
url: scope.uploadUrl,
|
url: scope.uploadUrl,
|
||||||
|
@ -161,6 +161,51 @@ $(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// Detect IE for css
|
||||||
if(navigator.userAgent.indexOf('MSIE')!==-1
|
if(navigator.userAgent.indexOf('MSIE')!==-1
|
||||||
|| navigator.appVersion.indexOf('Trident/') > 0
|
|| navigator.appVersion.indexOf('Trident/') > 0
|
||||||
|
@ -465,4 +465,8 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
|||||||
border-bottom-width: 3px;
|
border-bottom-width: 3px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-picker .none {
|
||||||
|
display: none;
|
||||||
}
|
}
|
@ -31,6 +31,8 @@ return [
|
|||||||
'delete' => 'Delete',
|
'delete' => 'Delete',
|
||||||
'search' => 'Search',
|
'search' => 'Search',
|
||||||
'search_clear' => 'Clear Search',
|
'search_clear' => 'Clear Search',
|
||||||
|
'reset' => 'Reset',
|
||||||
|
'remove' => 'Remove',
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,5 +15,7 @@ return [
|
|||||||
'imagem_image_name' => 'Image Name',
|
'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_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_select_image' => 'Select Image',
|
||||||
|
'imagem_dropzone' => 'Drop images or click here to upload',
|
||||||
'images_deleted' => 'Images Deleted',
|
'images_deleted' => 'Images Deleted',
|
||||||
|
'image_preview' => 'Image Preview',
|
||||||
];
|
];
|
@ -193,6 +193,7 @@ return [
|
|||||||
'attachments_link' => 'Attach Link',
|
'attachments_link' => 'Attach Link',
|
||||||
'attachments_set_link' => 'Set Link',
|
'attachments_set_link' => 'Set Link',
|
||||||
'attachments_delete_confirm' => 'Click delete again to confirm you want to delete this attachment.',
|
'attachments_delete_confirm' => 'Click delete again to confirm you want to delete this attachment.',
|
||||||
|
'attachments_dropzone' => 'Drop files or click here to attach a file',
|
||||||
'attachments_no_files' => 'No files have been uploaded',
|
'attachments_no_files' => 'No files have been uploaded',
|
||||||
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
|
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
|
||||||
'attachments_link_name' => 'Link Name',
|
'attachments_link_name' => 'Link Name',
|
||||||
@ -204,6 +205,7 @@ return [
|
|||||||
'attachments_edit_file_name' => 'File Name',
|
'attachments_edit_file_name' => 'File Name',
|
||||||
'attachments_edit_drop_upload' => 'Drop files or click here to upload and overwrite',
|
'attachments_edit_drop_upload' => 'Drop files or click here to upload and overwrite',
|
||||||
'attachments_order_updated' => 'Attachment order updated',
|
'attachments_order_updated' => 'Attachment order updated',
|
||||||
|
'attachments_updated_success' => 'Attachment details updated',
|
||||||
'attachments_deleted' => 'Attachment deleted',
|
'attachments_deleted' => 'Attachment deleted',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
17
resources/views/components/image-picker.blade.php
Normal file
17
resources/views/components/image-picker.blade.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<div class="image-picker" data-default-image="{{ $defaultImage }}" data-resize-height="{{ $resizeHeight }}" data-resize-width="{{ $resizeWidth }}" data-current-id="{{ $currentId or '' }}" data-resize-crop="{{ $resizeCrop or '' }}">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<img @if($currentImage && $currentImage !== 'none') src="{{$currentImage}}" @else src="{{$defaultImage}}" @endif class="{{$imageClass}} @if($currentImage=== 'none') none @endif" alt="{{ trans('components.image_preview') }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="button" type="button" data-action="show-image-manager">{{ trans('components.imagem_select_image') }}</button>
|
||||||
|
<br>
|
||||||
|
<button class="text-button" data-action="reset-image" type="button">{{ trans('common.reset') }}</button>
|
||||||
|
|
||||||
|
@if ($showRemove)
|
||||||
|
<span class="sep">|</span>
|
||||||
|
<button class="text-button neg" data-action="remove-image" type="button">{{ trans('common.remove') }}</button>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<input type="hidden" name="{{$name}}" id="{{$name}}" value="{{$currentId or $currentImage or ''}}">
|
||||||
|
</div>
|
@ -75,7 +75,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div tab-content="file">
|
<div tab-content="file">
|
||||||
<drop-zone upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone>
|
<drop-zone message="{{ trans('entities.attachments_dropzone') }}" upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone>
|
||||||
</div>
|
</div>
|
||||||
<div tab-content="link" sub-form="attachLinkSubmit(file)">
|
<div tab-content="link" sub-form="attachLinkSubmit(file)">
|
||||||
<p class="muted small">{{ trans('entities.attachments_explain_link') }}</p>
|
<p class="muted small">{{ trans('entities.attachments_explain_link') }}</p>
|
||||||
@ -123,8 +123,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="button" ng-click="cancelEdit()">{{ trans('entities.back') }}</button>
|
<button type="button" class="button" ng-click="cancelEdit()">{{ trans('common.back') }}</button>
|
||||||
<button type="submit" class="button pos">{{ trans('entities.save') }}</button>
|
<button type="submit" class="button pos">{{ trans('common.save') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<drop-zone upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone>
|
<drop-zone message="{{ trans('components.imagem_dropzone') }}" upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<h1>{{ trans('settings.settings') }}</h1>
|
<h1>{{ trans('settings.settings') }}</h1>
|
||||||
|
|
||||||
<form action="{{ baseUrl("/settings") }}" method="POST" ng-cloak>
|
<form action="{{ baseUrl("/settings") }}" method="POST">
|
||||||
{!! csrf_field() !!}
|
{!! csrf_field() !!}
|
||||||
|
|
||||||
<h3>{{ trans('settings.app_settings') }}</h3>
|
<h3>{{ trans('settings.app_settings') }}</h3>
|
||||||
@ -48,7 +48,17 @@
|
|||||||
<div class="form-group" id="logo-control">
|
<div class="form-group" id="logo-control">
|
||||||
<label for="setting-app-logo">{{ trans('settings.app_logo') }}</label>
|
<label for="setting-app-logo">{{ trans('settings.app_logo') }}</label>
|
||||||
<p class="small">{!! trans('settings.app_logo_desc') !!}</p>
|
<p class="small">{!! trans('settings.app_logo_desc') !!}</p>
|
||||||
<image-picker resize-height="43" show-remove="true" resize-width="200" current-image="{{ setting('app-logo', '') }}" default-image="{{ baseUrl('/logo.png') }}" name="setting-app-logo" image-class="logo-image"></image-picker>
|
|
||||||
|
@include('components.image-picker', [
|
||||||
|
'resizeHeight' => '43',
|
||||||
|
'resizeWidth' => '200',
|
||||||
|
'showRemove' => true,
|
||||||
|
'defaultImage' => baseUrl('/logo.png'),
|
||||||
|
'currentImage' => setting('app-logo'),
|
||||||
|
'name' => 'setting-app-logo',
|
||||||
|
'imageClass' => 'logo-image'
|
||||||
|
])
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" id="color-control">
|
<div class="form-group" id="color-control">
|
||||||
<label for="setting-app-color">{{ trans('settings.app_primary_color') }}</label>
|
<label for="setting-app-color">{{ trans('settings.app_primary_color') }}</label>
|
||||||
|
@ -31,7 +31,18 @@
|
|||||||
<div class="form-group" id="logo-control">
|
<div class="form-group" id="logo-control">
|
||||||
<label for="user-avatar">{{ trans('settings.users_avatar') }}</label>
|
<label for="user-avatar">{{ trans('settings.users_avatar') }}</label>
|
||||||
<p class="small">{{ trans('settings.users_avatar_desc') }}</p>
|
<p class="small">{{ trans('settings.users_avatar_desc') }}</p>
|
||||||
<image-picker resize-height="512" resize-width="512" current-image="{{ $user->getAvatar(80) }}" current-id="{{ $user->image_id }}" default-image="{{ baseUrl("/user_avatar.png") }}" name="image_id" show-remove="false" image-class="['avatar' ,'large']"></image-picker>
|
|
||||||
|
@include('components.image-picker', [
|
||||||
|
'resizeHeight' => '512',
|
||||||
|
'resizeWidth' => '512',
|
||||||
|
'showRemove' => false,
|
||||||
|
'defaultImage' => baseUrl('/user_avatar.png'),
|
||||||
|
'currentImage' => $user->getAvatar(80),
|
||||||
|
'currentId' => $user->image_id,
|
||||||
|
'name' => 'image_id',
|
||||||
|
'imageClass' => 'avatar large'
|
||||||
|
])
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user