mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Updated attachments to work with new dropzone
- Fixes existing broken attachment edit tabs. - Redesigns area to move away from old tabbed interface. - Integrates new dropzone system, for both addition and edit.
This commit is contained in:
parent
722c38d576
commit
e36cdaad0d
@ -25,7 +25,6 @@ return [
|
||||
'images_deleted' => 'Images Deleted',
|
||||
'image_preview' => 'Image Preview',
|
||||
'image_upload_success' => 'Image uploaded successfully',
|
||||
'image_upload_failure' => 'Image failed to upload',
|
||||
'image_update_success' => 'Image details successfully updated',
|
||||
'image_delete_success' => 'Image successfully deleted',
|
||||
|
||||
|
@ -311,12 +311,12 @@ return [
|
||||
'attachments' => 'Attachments',
|
||||
'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.',
|
||||
'attachments_explain_instant_save' => 'Changes here are saved instantly.',
|
||||
'attachments_items' => 'Attached Items',
|
||||
'attachments_upload' => 'Upload File',
|
||||
'attachments_link' => 'Attach Link',
|
||||
'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
|
||||
'attachments_set_link' => 'Set Link',
|
||||
'attachments_delete' => 'Are you sure you want to delete this attachment?',
|
||||
'attachments_dropzone' => 'Drop files or click here to attach a file',
|
||||
'attachments_dropzone' => 'Drop files here to upload',
|
||||
'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_link_name' => 'Link Name',
|
||||
|
@ -53,6 +53,7 @@ return [
|
||||
|
||||
// Attachments
|
||||
'attachment_not_found' => 'Attachment not found',
|
||||
'attachment_upload_error' => 'An error occurred uploading the attachment file',
|
||||
|
||||
// Pages
|
||||
'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {showLoading} from '../services/dom';
|
||||
import {onSelect, showLoading} from '../services/dom';
|
||||
import {Component} from './component';
|
||||
|
||||
export class Attachments extends Component {
|
||||
@ -8,15 +8,16 @@ export class Attachments extends Component {
|
||||
this.pageId = this.$opts.pageId;
|
||||
this.editContainer = this.$refs.editContainer;
|
||||
this.listContainer = this.$refs.listContainer;
|
||||
this.mainTabs = this.$refs.mainTabs;
|
||||
this.list = this.$refs.list;
|
||||
this.linksContainer = this.$refs.linksContainer;
|
||||
this.listPanel = this.$refs.listPanel;
|
||||
this.attachLinkButton = this.$refs.attachLinkButton;
|
||||
|
||||
this.setupListeners();
|
||||
}
|
||||
|
||||
setupListeners() {
|
||||
const reloadListBound = this.reloadList.bind(this);
|
||||
this.container.addEventListener('dropzone-success', reloadListBound);
|
||||
this.container.addEventListener('dropzone-upload-success', reloadListBound);
|
||||
this.container.addEventListener('ajax-form-success', reloadListBound);
|
||||
|
||||
this.container.addEventListener('sortable-list-sort', event => {
|
||||
@ -39,16 +40,29 @@ export class Attachments extends Component {
|
||||
markdown: contentTypes['text/plain'],
|
||||
});
|
||||
});
|
||||
|
||||
this.attachLinkButton.addEventListener('click', () => {
|
||||
this.showSection('links');
|
||||
});
|
||||
}
|
||||
|
||||
showSection(section) {
|
||||
const sectionMap = {
|
||||
links: this.linksContainer,
|
||||
edit: this.editContainer,
|
||||
list: this.listContainer,
|
||||
};
|
||||
|
||||
for (const [name, elem] of Object.entries(sectionMap)) {
|
||||
elem.toggleAttribute('hidden', name !== section);
|
||||
}
|
||||
}
|
||||
|
||||
reloadList() {
|
||||
this.stopEdit();
|
||||
/** @var {Tabs} */
|
||||
const tabs = window.$components.firstOnElement(this.mainTabs, 'tabs');
|
||||
tabs.show('attachment-panel-items');
|
||||
window.$http.get(`/attachments/get/page/${this.pageId}`).then(resp => {
|
||||
this.list.innerHTML = resp.data;
|
||||
window.$components.init(this.list);
|
||||
this.listPanel.innerHTML = resp.data;
|
||||
window.$components.init(this.listPanel);
|
||||
});
|
||||
}
|
||||
|
||||
@ -59,8 +73,7 @@ export class Attachments extends Component {
|
||||
}
|
||||
|
||||
async startEdit(id) {
|
||||
this.editContainer.classList.remove('hidden');
|
||||
this.listContainer.classList.add('hidden');
|
||||
this.showSection('edit');
|
||||
|
||||
showLoading(this.editContainer);
|
||||
const resp = await window.$http.get(`/attachments/edit/${id}`);
|
||||
@ -69,8 +82,7 @@ export class Attachments extends Component {
|
||||
}
|
||||
|
||||
stopEdit() {
|
||||
this.editContainer.classList.add('hidden');
|
||||
this.listContainer.classList.remove('hidden');
|
||||
this.showSection('list');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,10 @@ export class EditorToolbox extends Component {
|
||||
|
||||
// Set the first tab as active on load
|
||||
this.setActiveTab(this.contentElements[0].dataset.tabContent);
|
||||
|
||||
setTimeout(() => {
|
||||
this.setActiveTab('files', true);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
setupListeners() {
|
||||
|
@ -228,6 +228,15 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
||||
animation: dzAnimIn 240ms ease-in-out;
|
||||
}
|
||||
|
||||
.dropzone-landing-area {
|
||||
background-color: var(--color-primary-light);
|
||||
padding: $-m $-l;
|
||||
width: 100%;
|
||||
border: 1px dashed var(--color-primary);
|
||||
color: var(--color-primary);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@keyframes dzAnimIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
@ -319,7 +328,7 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
||||
.dropzone-file-item-label,
|
||||
.dropzone-file-item-status {
|
||||
align-items: center;
|
||||
font-size: .9rem;
|
||||
font-size: .8rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.dropzone-file-item-status[data-status] {
|
||||
|
@ -253,6 +253,15 @@ body.flexbox {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fixed {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
&.top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -17,18 +17,35 @@
|
||||
</div>
|
||||
|
||||
<div component="tabs" class="tab-container">
|
||||
<div class="nav-tabs">
|
||||
<button refs="tabs@toggleFile" type="button" class="tab-item {{ $attachment->external ? '' : 'selected' }}">{{ trans('entities.attachments_upload') }}</button>
|
||||
<button refs="tabs@toggleLink" type="button" class="tab-item {{ $attachment->external ? 'selected' : '' }}">{{ trans('entities.attachments_set_link') }}</button>
|
||||
<div class="nav-tabs" role="tablist">
|
||||
<button id="attachment-edit-file-tab"
|
||||
type="button"
|
||||
aria-controls="attachment-edit-file-panel"
|
||||
aria-selected="{{ $attachment->external ? 'false' : 'true' }}"
|
||||
role="tab">{{ trans('entities.attachments_upload') }}</button>
|
||||
<button id="attachment-edit-link-tab"
|
||||
type="button"
|
||||
aria-controls="attachment-edit-link-panel"
|
||||
aria-selected="{{ $attachment->external ? 'true' : 'false' }}"
|
||||
role="tab">{{ trans('entities.attachments_set_link') }}</button>
|
||||
</div>
|
||||
<div refs="tabs@contentFile" class="mb-m {{ $attachment->external ? 'hidden' : '' }}">
|
||||
@include('form.dropzone', [
|
||||
<div id="attachment-edit-file-panel"
|
||||
@if($attachment->external) hidden @endif
|
||||
tabindex="0"
|
||||
role="tabpanel"
|
||||
aria-labelledby="attachment-edit-file-tab"
|
||||
class="mb-m">
|
||||
@include('form.simple-dropzone', [
|
||||
'placeholder' => trans('entities.attachments_edit_drop_upload'),
|
||||
'url' => url('/attachments/upload/' . $attachment->id),
|
||||
'successMessage' => trans('entities.attachments_file_updated'),
|
||||
])
|
||||
</div>
|
||||
<div refs="tabs@contentLink" class="{{ $attachment->external ? '' : 'hidden' }}">
|
||||
<div id="attachment-edit-link-panel"
|
||||
@if(!$attachment->external) hidden @endif
|
||||
tabindex="0"
|
||||
role="tabpanel"
|
||||
aria-labelledby="attachment-edit-link-tab">
|
||||
<div class="form-group">
|
||||
<label for="attachment_edit_url">{{ trans('entities.attachments_link_url') }}</label>
|
||||
<input type="text" id="attachment_edit_url"
|
||||
@ -43,6 +60,8 @@
|
||||
</div>
|
||||
|
||||
<button component="event-emit-select"
|
||||
option:event-emit-select:name="edit-back" type="button" class="button outline">{{ trans('common.back') }}</button>
|
||||
option:event-emit-select:name="edit-back"
|
||||
type="button"
|
||||
class="button outline">{{ trans('common.back') }}</button>
|
||||
<button refs="ajax-form@submit" type="button" class="button">{{ trans('common.save') }}</button>
|
||||
</div>
|
@ -22,6 +22,9 @@
|
||||
<div class="text-neg text-small">{{ $errors->first('attachment_link_url') }}</div>
|
||||
@endif
|
||||
</div>
|
||||
<button component="event-emit-select"
|
||||
option:event-emit-select:name="edit-back"
|
||||
type="button" class="button outline">{{ trans('common.cancel') }}</button>
|
||||
<button refs="ajax-form@submit"
|
||||
type="button"
|
||||
class="button">{{ trans('entities.attach') }}</button>
|
||||
|
@ -6,66 +6,44 @@
|
||||
class="toolbox-tab-content">
|
||||
|
||||
<h4>{{ trans('entities.attachments') }}</h4>
|
||||
<div class="px-l files">
|
||||
<div component="dropzone"
|
||||
option:dropzone:url="{{ url('/attachments/upload?uploaded_to=' . $page->id) }}"
|
||||
option:dropzone:success-message="{{ trans('entities.attachments_file_uploaded') }}"
|
||||
option:dropzone:error-message="{{ trans('errors.attachment_upload_error') }}"
|
||||
option:dropzone:upload-limit="{{ config('app.upload_limit') }}"
|
||||
option:dropzone:upload-limit-message="{{ trans('errors.server_upload_limit') }}"
|
||||
option:dropzone:zone-text="{{ trans('entities.attachments_dropzone') }}"
|
||||
option:dropzone:file-accept="*"
|
||||
class="px-l files">
|
||||
|
||||
<div refs="attachments@listContainer">
|
||||
<div refs="attachments@list-container dropzone@drop-target" class="relative">
|
||||
<p class="text-muted small">{{ trans('entities.attachments_explain') }} <span
|
||||
class="text-warn">{{ trans('entities.attachments_explain_instant_save') }}</span></p>
|
||||
|
||||
<div component="tabs" refs="attachments@mainTabs" class="tab-container">
|
||||
<div role="tablist">
|
||||
<button id="attachment-tab-items"
|
||||
role="tab"
|
||||
aria-selected="true"
|
||||
aria-controls="attachment-panel-items"
|
||||
type="button"
|
||||
class="tab-item">{{ trans('entities.attachments_items') }}</button>
|
||||
<button id="attachment-tab-upload"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="attachment-panel-upload"
|
||||
type="button"
|
||||
class="tab-item">{{ trans('entities.attachments_upload') }}</button>
|
||||
<button id="attachment-tab-links"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="attachment-panel-links"
|
||||
type="button"
|
||||
class="tab-item">{{ trans('entities.attachments_link') }}</button>
|
||||
<hr class="mb-s">
|
||||
|
||||
<div class="flex-container-row">
|
||||
<button refs="dropzone@select-button" type="button" class="button outline small">{{ trans('entities.attachments_upload') }}</button>
|
||||
<button refs="attachments@attach-link-button" type="button" class="button outline small">{{ trans('entities.attachments_link') }}</button>
|
||||
</div>
|
||||
<div id="attachment-panel-items"
|
||||
tabindex="0"
|
||||
role="tabpanel"
|
||||
aria-labelledby="attachment-tab-items"
|
||||
refs="attachments@list">
|
||||
<div>
|
||||
<p class="text-muted text-small">{{ trans('entities.attachments_upload_drop') }}</p>
|
||||
</div>
|
||||
<div refs="dropzone@status-area" class="fixed top-right px-m py-m"></div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div refs="attachments@list-panel">
|
||||
@include('attachments.manager-list', ['attachments' => $page->attachments->all()])
|
||||
</div>
|
||||
<div id="attachment-panel-upload"
|
||||
tabindex="0"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="attachment-tab-upload">
|
||||
@include('form.dropzone', [
|
||||
'placeholder' => trans('entities.attachments_dropzone'),
|
||||
'url' => url('/attachments/upload?uploaded_to=' . $page->id),
|
||||
'successMessage' => trans('entities.attachments_file_uploaded'),
|
||||
])
|
||||
|
||||
</div>
|
||||
<div id="attachment-panel-links"
|
||||
tabindex="0"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="attachment-tab-links"
|
||||
class="link-form-container">
|
||||
|
||||
<div refs="attachments@links-container" hidden class="link-form-container">
|
||||
@include('attachments.manager-link-form', ['pageId' => $page->id])
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div refs="attachments@editContainer" class="hidden attachment-edit-container">
|
||||
|
||||
</div>
|
||||
<div refs="attachments@edit-container" hidden class="attachment-edit-container"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
@ -1,8 +0,0 @@
|
||||
{{--
|
||||
@url - URL to upload to.
|
||||
@placeholder - Placeholder text
|
||||
@successMessage
|
||||
--}}
|
||||
<div refs="" class="dropzone-container text-center">
|
||||
<button type="button" class="dz-message">{{ $placeholder }}</button>
|
||||
</div>
|
21
resources/views/form/simple-dropzone.blade.php
Normal file
21
resources/views/form/simple-dropzone.blade.php
Normal file
@ -0,0 +1,21 @@
|
||||
{{--
|
||||
@url - URL to upload to.
|
||||
@placeholder - Placeholder text
|
||||
@successMessage
|
||||
--}}
|
||||
<div component="dropzone"
|
||||
option:dropzone:url="{{ $url }}"
|
||||
option:dropzone:success-message="{{ $successMessage }}"
|
||||
option:dropzone:error-message="{{ trans('errors.attachment_upload_error') }}"
|
||||
option:dropzone:upload-limit="{{ config('app.upload_limit') }}"
|
||||
option:dropzone:upload-limit-message="{{ trans('errors.server_upload_limit') }}"
|
||||
option:dropzone:zone-text="{{ trans('entities.attachments_dropzone') }}"
|
||||
option:dropzone:file-accept="*"
|
||||
class="relative">
|
||||
<div refs="dropzone@status-area" class="fixed top-right px-m py-m"></div>
|
||||
<button type="button"
|
||||
refs="dropzone@select-button dropzone@drop-target"
|
||||
class="dropzone-landing-area text-center">
|
||||
{{ $placeholder }}
|
||||
</button>
|
||||
</div>
|
@ -1,7 +1,7 @@
|
||||
<div components="image-manager dropzone"
|
||||
option:dropzone:url="{{ url('/images/gallery?' . http_build_query(['uploaded_to' => $uploaded_to ?? 0])) }}"
|
||||
option:dropzone:success-message="{{ trans('components.image_upload_success') }}"
|
||||
option:dropzone:error-message="{{ trans('components.image_upload_failure') }}"
|
||||
option:dropzone:error-message="{{ trans('errors.image_upload_error') }}"
|
||||
option:dropzone:upload-limit="{{ config('app.upload_limit') }}"
|
||||
option:dropzone:upload-limit-message="{{ trans('errors.server_upload_limit') }}"
|
||||
option:dropzone:zone-text="{{ trans('components.image_dropzone_drop') }}"
|
||||
|
Loading…
Reference in New Issue
Block a user