mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Added drag/drop and paste support for video files
refs https://github.com/TryGhost/Team/issues/1229 - generalized `insertImageCards()` to `insertCardsFromFiles()` and added support for video cards - added `canInsertCardsFromFiles()` function so the editor can check before starting an editor run loop and generating an undo point
This commit is contained in:
parent
7e4a277163
commit
09cae883a8
2 changed files with 50 additions and 36 deletions
|
@ -21,6 +21,7 @@ import {TrackedObject} from 'tracked-built-ins';
|
||||||
import {action} from '@ember/object';
|
import {action} from '@ember/object';
|
||||||
import {assign} from '@ember/polyfills';
|
import {assign} from '@ember/polyfills';
|
||||||
import {camelize, capitalize} from '@ember/string';
|
import {camelize, capitalize} from '@ember/string';
|
||||||
|
import {canInsertCardsFromFiles, insertCardsFromFiles} from '../utils/insert-cards-from-files';
|
||||||
import {captureMessage} from '@sentry/browser';
|
import {captureMessage} from '@sentry/browser';
|
||||||
import {createParserPlugins} from '@tryghost/kg-parser-plugins';
|
import {createParserPlugins} from '@tryghost/kg-parser-plugins';
|
||||||
import {getContentFromPasteEvent} from 'mobiledoc-kit/utils/parse-utils';
|
import {getContentFromPasteEvent} from 'mobiledoc-kit/utils/parse-utils';
|
||||||
|
@ -29,7 +30,6 @@ import {getOwner} from '@ember/application';
|
||||||
import {getParent} from '../lib/dnd/utils';
|
import {getParent} from '../lib/dnd/utils';
|
||||||
import {utils as ghostHelperUtils} from '@tryghost/helpers';
|
import {utils as ghostHelperUtils} from '@tryghost/helpers';
|
||||||
import {guidFor} from '@ember/object/internals';
|
import {guidFor} from '@ember/object/internals';
|
||||||
import {insertImageCards} from '../utils/insert-cards-from-files';
|
|
||||||
import {run} from '@ember/runloop';
|
import {run} from '@ember/runloop';
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
import {svgJar} from 'ghost-admin/helpers/svg-jar';
|
import {svgJar} from 'ghost-admin/helpers/svg-jar';
|
||||||
|
@ -956,19 +956,11 @@ export default Component.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have image files pasted, create an image card for each and set
|
// if we have files pasted, create a card for each and set the
|
||||||
// the payload.files property which will cause the image to be auto-uploaded
|
// payload.files property which will cause the file to be auto-uploaded
|
||||||
// NOTE: browser support varies as of May 2018:
|
if (canInsertCardsFromFiles(event.clipboardData.files)) {
|
||||||
// - Safari: will paste all images
|
|
||||||
// - Chrome: will only paste the first image
|
|
||||||
// - Firefox: will not paste any images
|
|
||||||
let images = Array.from(event.clipboardData.files).filter(file => file.type.indexOf('image') > -1);
|
|
||||||
if (images.length > 0) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopImmediatePropagation();
|
|
||||||
|
|
||||||
editor.run((postEditor) => {
|
editor.run((postEditor) => {
|
||||||
insertImageCards(images, postEditor);
|
insertCardsFromFiles(event.clipboardData.files, postEditor);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1139,14 +1131,11 @@ export default Component.extend({
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (event.dataTransfer.files) {
|
if (canInsertCardsFromFiles(event.dataTransfer.files)) {
|
||||||
let images = Array.from(event.dataTransfer.files).filter(file => file.type.indexOf('image') > -1);
|
this.editor.run((postEditor) => {
|
||||||
if (images.length > 0) {
|
insertCardsFromFiles(event.dataTransfer.files, postEditor);
|
||||||
this.editor.run((postEditor) => {
|
});
|
||||||
insertImageCards(images, postEditor);
|
this._scrollCursorIntoView({jumpToCard: true});
|
||||||
});
|
|
||||||
this._scrollCursorIntoView({jumpToCard: true});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
// helper function to insert image cards at or after the current active section
|
export function canInsertCardsFromFiles(files) {
|
||||||
|
return filterAllowedFiles(files).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to insert cards at or after the current active section
|
||||||
// used when pasting or dropping image files
|
// used when pasting or dropping image files
|
||||||
export function insertImageCards(files, postEditor) {
|
export function insertCardsFromFiles(_files, postEditor) {
|
||||||
let {builder, editor} = postEditor;
|
const files = filterAllowedFiles(_files);
|
||||||
let collection = editor.post.sections;
|
|
||||||
|
if (!files.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {builder, editor} = postEditor;
|
||||||
|
const collection = editor.post.sections;
|
||||||
let section = editor.activeSection;
|
let section = editor.activeSection;
|
||||||
|
|
||||||
// when dropping an image on the editor before it's had focus there will be
|
// when dropping an file on the editor before it's had focus there will be
|
||||||
// no active section so we insert the image at the end of the document
|
// no active section so we insert the card at the end of the document
|
||||||
if (!section) {
|
if (!section) {
|
||||||
section = editor.post.sections.tail;
|
section = editor.post.sections.tail;
|
||||||
|
|
||||||
|
@ -14,7 +24,7 @@ export function insertImageCards(files, postEditor) {
|
||||||
// we use `insertSectionBefore` and don't want the image to be added
|
// we use `insertSectionBefore` and don't want the image to be added
|
||||||
// before the last card
|
// before the last card
|
||||||
if (!section.isMarkerable) {
|
if (!section.isMarkerable) {
|
||||||
let blank = builder.createMarkupSection();
|
const blank = builder.createMarkupSection();
|
||||||
postEditor.insertSectionAtEnd(blank);
|
postEditor.insertSectionAtEnd(blank);
|
||||||
postEditor.setRange(blank.toRange());
|
postEditor.setRange(blank.toRange());
|
||||||
section = postEditor._range.head.section;
|
section = postEditor._range.head.section;
|
||||||
|
@ -29,8 +39,8 @@ export function insertImageCards(files, postEditor) {
|
||||||
// list items cannot contain card sections so insert a blank paragraph after
|
// list items cannot contain card sections so insert a blank paragraph after
|
||||||
// the whole list ready to be replaced by the image cards
|
// the whole list ready to be replaced by the image cards
|
||||||
if (section.isListItem) {
|
if (section.isListItem) {
|
||||||
let list = section.parent;
|
const list = section.parent;
|
||||||
let blank = builder.createMarkupSection();
|
const blank = builder.createMarkupSection();
|
||||||
if (list.next) {
|
if (list.next) {
|
||||||
postEditor.insertSectionBefore(collection, blank, list.next);
|
postEditor.insertSectionBefore(collection, blank, list.next);
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,15 +50,16 @@ export function insertImageCards(files, postEditor) {
|
||||||
section = postEditor._range.head.section;
|
section = postEditor._range.head.section;
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert an image card for each image, keep track of the last card to be
|
// insert a card for each file, keep track of the last card to be
|
||||||
// inserted so that the cursor can be placed on it at the end
|
// inserted so that the cursor can be placed on it at the end
|
||||||
let lastImageSection;
|
let lastCardSection;
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
let payload = {
|
const cardName = getCardNameFromFile(file);
|
||||||
|
const payload = {
|
||||||
files: [file]
|
files: [file]
|
||||||
};
|
};
|
||||||
lastImageSection = builder.createCardSection('image', payload);
|
lastCardSection = builder.createCardSection(cardName, payload);
|
||||||
postEditor.insertSectionBefore(collection, lastImageSection, section);
|
postEditor.insertSectionBefore(collection, lastCardSection, section);
|
||||||
});
|
});
|
||||||
|
|
||||||
// remove the current section if it's blank - avoids unexpected blank
|
// remove the current section if it's blank - avoids unexpected blank
|
||||||
|
@ -58,5 +69,19 @@ export function insertImageCards(files, postEditor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// place cursor on the last inserted image
|
// place cursor on the last inserted image
|
||||||
postEditor.setRange(lastImageSection.tailPosition());
|
postEditor.setRange(lastCardSection.tailPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterAllowedFiles(files) {
|
||||||
|
return Array.from(files).filter(file => file.type.match(/^(image|video)/));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCardNameFromFile(file) {
|
||||||
|
if (file.type.startsWith('image')) {
|
||||||
|
return 'image';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.type.startsWith('video')) {
|
||||||
|
return 'video';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue