mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Added first pass at feature image drag+drop uploading
refs https://github.com/TryGhost/Team/issues/884 - add `[data-user-is-dragging]` to `body` element when any drag is occurring so that we can make drop zones active - added dropzone and drop handling to feature image component
This commit is contained in:
parent
0f9177919c
commit
876c2b6cdd
7 changed files with 138 additions and 3 deletions
|
@ -8,6 +8,21 @@
|
|||
@onComplete={{this.setUploadedImage}}
|
||||
as |uploader|
|
||||
>
|
||||
{{#if (feature "featureImgDragDrop")}}
|
||||
{{#unless @image}}
|
||||
<div
|
||||
class="gh-editor-feature-image-dropzone"
|
||||
{{on "dragover" this.dragOver}}
|
||||
{{on "dragleave" this.dragLeave}}
|
||||
{{on "drop" (fn this.drop uploader.setFiles)}}
|
||||
></div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.canDrop}}
|
||||
<div class="gh-editor-feature-image-drop-indicator bg-blue br-pill pe-none"></div>
|
||||
{{/if}}
|
||||
|
||||
{{#if uploader.isUploading}}
|
||||
{{!-- upload in progress --}}
|
||||
{{uploader.progressBar}}
|
||||
|
@ -63,8 +78,12 @@
|
|||
{{else}}
|
||||
{{!-- no-image state --}}
|
||||
<div class="flex flex-row items-center {{if this.hideButton "invisible"}}">
|
||||
<button type="button" class="gh-editor-feature-image-add-button" {{on "click" uploader.triggerFileDialog}}>{{svg-jar "plus"}}<span>Add feature image</span></button>
|
||||
<button type="button" class="gh-editor-feature-image-unsplash" {{on "click" this.toggleUnsplashSelector}}>{{svg-jar "unsplash"}}</button>
|
||||
{{#if this.canDrop}}
|
||||
<div class="gh-editor-feature-image-add-button"><span>Drop to upload feature image</span></div>
|
||||
{{else}}
|
||||
<button type="button" class="gh-editor-feature-image-add-button" {{on "click" uploader.triggerFileDialog}}>{{svg-jar "plus"}}<span>Add feature image</span></button>
|
||||
<button type="button" class="gh-editor-feature-image-unsplash" {{on "click" this.toggleUnsplashSelector}}>{{svg-jar "unsplash"}}</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -7,9 +7,10 @@ export default class GhEditorFeatureImageComponent extends Component {
|
|||
@tracked isHovered = false;
|
||||
@tracked captionInputFocused = false;
|
||||
@tracked showUnsplashSelector = false;
|
||||
@tracked canDrop = false;
|
||||
|
||||
get hideButton() {
|
||||
return !this.isHovered && !this.args.forceButtonDisplay;
|
||||
return !this.canDrop && !this.isHovered && !this.args.forceButtonDisplay;
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -39,4 +40,47 @@ export default class GhEditorFeatureImageComponent extends Component {
|
|||
onAltInput(event) {
|
||||
this.args.updateAlt(event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
dragOver(event) {
|
||||
if (!event.dataTransfer.files) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this is needed to work around inconsistencies with dropping files
|
||||
// from Chrome's downloads bar
|
||||
if (navigator.userAgent.indexOf('Chrome') > -1) {
|
||||
let eA = event.dataTransfer.effectAllowed;
|
||||
event.dataTransfer.dropEffect = (eA === 'move' || eA === 'linkMove') ? 'move' : 'copy';
|
||||
}
|
||||
|
||||
// event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
this.canDrop = true;
|
||||
}
|
||||
|
||||
@action
|
||||
dragLeave(event) {
|
||||
if (!event.dataTransfer.files) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
this.canDrop = false;
|
||||
}
|
||||
|
||||
@action
|
||||
drop(setFiles, event) {
|
||||
if (!event.dataTransfer.files) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
this.canDrop = false;
|
||||
|
||||
setFiles(event.dataTransfer.files);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ export default Route.extend(ShortcutsRoute, {
|
|||
this.router.on('routeDidChange', () => {
|
||||
this.notifications.displayDelayed();
|
||||
});
|
||||
|
||||
// TODO: featureImgDragDrop - move event initialization here when removing feature flag
|
||||
},
|
||||
|
||||
beforeModel() {
|
||||
|
@ -143,6 +145,12 @@ export default Route.extend(ShortcutsRoute, {
|
|||
}
|
||||
},
|
||||
|
||||
willDestroy() {
|
||||
// TODO: featureImgDragDrop - remove .session. when removing feature flag
|
||||
document.body.removeEventListener('dragenter', this.session.bodyDragEnterHandler);
|
||||
document.body.removeEventListener('dragleave', this.session.bodyDragLeaveHandler);
|
||||
},
|
||||
|
||||
async prepareApp() {
|
||||
await this.config.fetchUnauthenticated();
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ export default Service.extend({
|
|||
multipleProducts: feature('multipleProducts', {developer: true}),
|
||||
emailCardSegments: feature('emailCardSegments', {developer: true}),
|
||||
savedIndicator: feature('savedIndicator', {developer: true}),
|
||||
featureImgDragDrop: feature('featureImgDragDrop', {developer: true}),
|
||||
|
||||
_user: null,
|
||||
|
||||
|
|
|
@ -51,6 +51,35 @@ export default class SessionService extends ESASessionService {
|
|||
});
|
||||
}
|
||||
|
||||
// TODO: featureImgDragDrop - move this to application route init when removing flag
|
||||
if (this.feature.featureImgDragDrop) {
|
||||
// when any drag event is occurring we add `data-user-is-dragging` to the
|
||||
// body element so that we can have dropzones start listening to pointer
|
||||
// events allowing us to have interactive elements "underneath" drop zones
|
||||
if (this.feature.featureImgDragDrop) {
|
||||
this.bodyDragEnterHandler = (event) => {
|
||||
if (!event.dataTransfer) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
document.body.dataset.userIsDragging = true;
|
||||
window.clearTimeout(this.dragTimer);
|
||||
};
|
||||
this.bodyDragLeaveHandler = (event) => {
|
||||
event.preventDefault();
|
||||
window.clearTimeout(this.dragTimer);
|
||||
this.dragTimer = window.setTimeout(() => {
|
||||
delete document.body.dataset.userIsDragging;
|
||||
}, 100);
|
||||
};
|
||||
document.body.addEventListener('dragenter', this.bodyDragEnterHandler);
|
||||
document.body.addEventListener('dragleave', this.bodyDragLeaveHandler);
|
||||
}
|
||||
}
|
||||
|
||||
this.loadServerNotifications();
|
||||
this.whatsNew.fetchLatest.perform();
|
||||
}
|
||||
|
|
|
@ -425,6 +425,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
.gh-editor-feature-image-dropzone {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 175px;
|
||||
top: -50px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
body[data-user-is-dragging] .gh-editor-feature-image-dropzone {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.gh-editor-feature-image-drop-indicator {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 40px;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
.gh-editor-feature-image {
|
||||
margin-left: -1.2rem;
|
||||
padding-left: 1.2rem;
|
||||
|
|
|
@ -293,6 +293,19 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gh-expandable-block">
|
||||
<div class="gh-expandable-header">
|
||||
<div>
|
||||
<h4 class="gh-expandable-title">Feature image drag & drop</h4>
|
||||
<p class="gh-expandable-description">
|
||||
Allow dropping image files on feature image to upload
|
||||
</p>
|
||||
</div>
|
||||
<div class="for-switch">
|
||||
<GhFeatureFlag @flag="featureImgDragDrop" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
Loading…
Add table
Reference in a new issue