diff --git a/ghost/admin/lib/koenig-editor/addon/components/koenig-card-image.js b/ghost/admin/lib/koenig-editor/addon/components/koenig-card-image.js index 726fe346d3..8833e259bb 100644 --- a/ghost/admin/lib/koenig-editor/addon/components/koenig-card-image.js +++ b/ghost/admin/lib/koenig-editor/addon/components/koenig-card-image.js @@ -5,17 +5,18 @@ import { IMAGE_EXTENSIONS, IMAGE_MIME_TYPES } from 'ghost-admin/components/gh-image-uploader'; -import {computed} from '@ember/object'; +import {computed, set} from '@ember/object'; import {htmlSafe} from '@ember/string'; +import {isEmpty} from '@ember/utils'; import {run} from '@ember/runloop'; import {inject as service} from '@ember/service'; -import {set} from '@ember/object'; export default Component.extend({ ui: service(), layout, // attrs + files: null, payload: null, isSelected: false, isEditing: false, @@ -92,6 +93,21 @@ export default Component.extend({ } }, + didReceiveAttrs() { + this._super(...arguments); + + // `payload.files` can be set if we have an externaly set image that + // should be uploaded. Typical example would be from a paste or drag/drop + if (!isEmpty(this.payload.files)) { + run.schedule('afterRender', this, function () { + this.set('files', this.payload.files); + + // we don't want to persist any file data in the document + delete this.payload.files; + }); + } + }, + willDestroyElement() { this._super(...arguments); this._detachHandlers(); diff --git a/ghost/admin/lib/koenig-editor/addon/components/koenig-editor.js b/ghost/admin/lib/koenig-editor/addon/components/koenig-editor.js index 469bf88e17..2e28326985 100644 --- a/ghost/admin/lib/koenig-editor/addon/components/koenig-editor.js +++ b/ghost/admin/lib/koenig-editor/addon/components/koenig-editor.js @@ -243,7 +243,11 @@ export default Component.extend({ let componentName = CARD_COMPONENT_MAP[cardName]; // the payload must be copied to avoid sharing the reference - payload = copy(payload, true); + // `payload.files` is special because it's set by paste/drag-n-drop + // events and can't be copied for security reasons + let {files} = payload; + let payloadCopy = copy(payload, true); + payloadCopy.files = files; // all of the properties that will be passed through to the // component cards via the template @@ -251,7 +255,7 @@ export default Component.extend({ cardName, componentName, koenigOptions, - payload, + payload: payloadCopy, env, options, editor, @@ -646,6 +650,35 @@ export default Component.extend({ return; } + // if we have image files pasted, create an image card for each and set + // the payload.files property which will cause the image to be auto-uploaded + // NOTE: browser support varies as of May 2018: + // - 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) => { + let {builder} = postEditor; + + if (editor.activeSection.isBlank) { + postEditor.removeSection(editor.activeSection); + } + + images.forEach((image) => { + let payload = { + files: [image] + }; + let imageCard = builder.createCardSection('image', payload); + postEditor.insertSection(imageCard); + }); + }); + return; + } + let range = editor.range; let {html, text} = getContentFromPasteEvent(event); diff --git a/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-card-image.hbs b/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-card-image.hbs index f633c16931..2b9d212d8f 100644 --- a/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-card-image.hbs +++ b/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-card-image.hbs @@ -12,6 +12,7 @@ hasEditMode=false }} {{#gh-uploader + files=files accept=imageMimeTypes extensions=imageExtensions onStart=(action "setPreviewSrc")