From a3f6569701c8553b3c77509c99a0fc056ab990a8 Mon Sep 17 00:00:00 2001 From: Alexandros Georgantas <alexgeorg86@gmail.com> Date: Mon, 20 Feb 2017 15:36:22 +0200 Subject: [PATCH] Image functionality in progress --- .gitignore | 16 ++++ app/components/SimpleEditor/Editor.js | 20 ++--- app/components/SimpleEditor/SimpleEditor.jsx | 4 +- app/components/SimpleEditor/config.js | 4 +- .../SimpleEditor/elements/images/Image.js | 10 --- .../elements/images/ImageFileProxy.js | 48 +++++++++++ .../elements/images/ImageHTMLConverter.js | 13 ++- .../SimpleEditor/elements/images/ImageNode.js | 23 +++++ .../elements/images/ImagePackage.js | 6 +- .../elements/images/InsertImageCommand.js | 86 +++++-------------- 10 files changed, 138 insertions(+), 92 deletions(-) create mode 100644 .gitignore delete mode 100644 app/components/SimpleEditor/elements/images/Image.js create mode 100644 app/components/SimpleEditor/elements/images/ImageFileProxy.js create mode 100644 app/components/SimpleEditor/elements/images/ImageNode.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e4e6936 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.env.* +.DS_Store +_build/* +api/db/* +api/db/* +coverage +logs/* +node_modules +npm-debug.log +public/assets/* +public/uploads/* +pubsweet.log +uploads/* +.flowconfig +.tern-project +.vscode/ diff --git a/app/components/SimpleEditor/Editor.js b/app/components/SimpleEditor/Editor.js index df2376b..a325e1d 100644 --- a/app/components/SimpleEditor/Editor.js +++ b/app/components/SimpleEditor/Editor.js @@ -44,19 +44,19 @@ class Editor extends ProseEditor { didMount () { // this.documentSession.on('didUpdate', this.documentSessionUpdated, this) - // this.documentSession.on('fileUploadTrigger', this.handleUpload, this) + // this.editorSession.on('fileUploadTrigger', this.handleUpload, this) this.extendState({ editorReady: true }) } - handleUpload (file, callback) { - const { fileUpload } = this.props - - // TODO -- then / catch - fileUpload(file).then((res, err) => { - if (err != null) callback(null, err) - return callback(res.file, null) - }) - } + // handleUpload (file, callback) { + // const { fileUpload } = this.props + // + // // TODO -- then / catch + // // fileUpload(file).then((res, err) => { + // // if (err != null) callback(null, err) + // // return callback(res.file, null) + // // }) + // } render ($$) { const { trackChangesView } = this.state diff --git a/app/components/SimpleEditor/SimpleEditor.jsx b/app/components/SimpleEditor/SimpleEditor.jsx index f505084..8cca512 100644 --- a/app/components/SimpleEditor/SimpleEditor.jsx +++ b/app/components/SimpleEditor/SimpleEditor.jsx @@ -55,7 +55,8 @@ export default class SimpleEditor extends React.Component { }) editorSession.setSaveHandler({ - saveDocument: this.save + saveDocument: this.save, + uploadFile: this.props.fileUpload }) return { @@ -163,7 +164,6 @@ export default class SimpleEditor extends React.Component { containerId, disabled, editorSession, - fileUpload, fragment, history, onSave, diff --git a/app/components/SimpleEditor/config.js b/app/components/SimpleEditor/config.js index dfc01f6..e613737 100644 --- a/app/components/SimpleEditor/config.js +++ b/app/components/SimpleEditor/config.js @@ -23,7 +23,7 @@ import CommentPackage from './elements/comment/CommentPackage' // import ExtractPackage from './elements/extract/ExtractPackage' import NotePackage from './elements/note/NotePackage' // import SourceNotePackage from './elements/source_note/SourceNotePackage' -// import ImagePackage from './elements/images/ImagePackage' +import ImagePackage from './elements/images/ImagePackage' // // import TrackChangePackage from './elements/track_change/TrackChangePackage' @@ -64,7 +64,7 @@ let config = { config.import(NotePackage) // config.import(SourceNotePackage) config.import(CommentPackage) - // config.import(ImagePackage) + config.import(ImagePackage) // // config.import(TrackChangePackage) diff --git a/app/components/SimpleEditor/elements/images/Image.js b/app/components/SimpleEditor/elements/images/Image.js deleted file mode 100644 index d48d44c..0000000 --- a/app/components/SimpleEditor/elements/images/Image.js +++ /dev/null @@ -1,10 +0,0 @@ -import { DocumentNode } from 'substance' - -class Image extends DocumentNode {} - -Image.define({ - type: 'image', - src: { type: 'string', default: 'http://' } -}) - -export default Image diff --git a/app/components/SimpleEditor/elements/images/ImageFileProxy.js b/app/components/SimpleEditor/elements/images/ImageFileProxy.js new file mode 100644 index 0000000..72a3736 --- /dev/null +++ b/app/components/SimpleEditor/elements/images/ImageFileProxy.js @@ -0,0 +1,48 @@ +import { FileProxy } from 'substance' + +class ImageFileProxy extends FileProxy { + + constructor (fileNode, context) { + super(fileNode, context) + console.log('imageFileProxy', this) + console.log('imageFileProxy Node', fileNode) + console.log('imageFileProxy Context', context) + // used locally e.g. after drop or file dialog + this.file = fileNode.data + if (this.file) { + this._fileUrl = URL.createObjectURL(this.file) + } + this.url = fileNode.url + } + + getUrl () { + // if we have fetched the url already, just serve it here + if (this.url) { + return this.url + } + // if we have a local file, use it's data URL + if (this._fileUrl) { + return this._fileUrl + } + // no URL available + return '' + } + + sync () { + console.log('sync', this) + if (!this.url) { + console.info('Simulating file upload. Creating blob url instead.', this._fileUrl) + console.log('file in sync', this.file) + // this.context.editorSession.saveHandler.uploadFile() + this.url = this._fileUrl + } + return Promise.resolve() + } +} + +ImageFileProxy.match = function(fileNode, context) { // eslint-disable-line + console.log('imageFileProxy match', fileNode) + return fileNode.fileType === 'image' +} + +export default ImageFileProxy diff --git a/app/components/SimpleEditor/elements/images/ImageHTMLConverter.js b/app/components/SimpleEditor/elements/images/ImageHTMLConverter.js index 485bb4d..46e452d 100644 --- a/app/components/SimpleEditor/elements/images/ImageHTMLConverter.js +++ b/app/components/SimpleEditor/elements/images/ImageHTMLConverter.js @@ -6,11 +6,18 @@ export default { type: 'image', tagName: 'img', - import: function (el, node) { - node.src = el.attr('src') + import: function (el, node, converter) { + let imageFile = converter.createNode({ + id: 'file-' + node.id, + type: 'file', + fileType: 'image', + url: el.attr('src') + }) + node.imageFile = imageFile.id }, export: function (node, el) { - el.attr('src', node.src) + let imageFile = node.document.get(node.imageFile) + el.attr('src', imageFile.getUrl()) } } diff --git a/app/components/SimpleEditor/elements/images/ImageNode.js b/app/components/SimpleEditor/elements/images/ImageNode.js new file mode 100644 index 0000000..1805265 --- /dev/null +++ b/app/components/SimpleEditor/elements/images/ImageNode.js @@ -0,0 +1,23 @@ +import { DocumentNode } from 'substance' + +class ImageNode extends DocumentNode { + getImageFile () { + if (this.imageFile) { + return this.document.get(this.imageFile) + } + } + + getUrl () { + let imageFile = this.getImageFile() + if (imageFile) { + return imageFile.getUrl() + } + } +} + +ImageNode.schema = { + type: 'image', + imageFile: { type: 'file' } +} + +export default ImageNode diff --git a/app/components/SimpleEditor/elements/images/ImagePackage.js b/app/components/SimpleEditor/elements/images/ImagePackage.js index 085c604..56388f2 100644 --- a/app/components/SimpleEditor/elements/images/ImagePackage.js +++ b/app/components/SimpleEditor/elements/images/ImagePackage.js @@ -1,8 +1,9 @@ -import ImageNode from './Image' +import ImageNode from './ImageNode' import ImageComponent from './ImageComponent' import ImageHTMLConverter from './ImageHTMLConverter' import InsertImageCommand from './InsertImageCommand' import InsertImageTool from './InsertImageTool' +import ImageFileProxy from './ImageFileProxy' export default { name: 'image', @@ -11,10 +12,11 @@ export default { config.addComponent('image', ImageComponent) config.addConverter('html', ImageHTMLConverter) config.addCommand('insert-image', InsertImageCommand) - config.addTool('insert-image', InsertImageTool, { target: 'insert' }) + config.addTool('insert-image', InsertImageTool, { toolGroup: 'annotations' }) config.addIcon('insert-image', { 'fontawesome': 'fa-image' }) config.addLabel('image', { en: 'Image' }) config.addLabel('insert-image', { en: 'Insert image' }) + config.addFileProxy(ImageFileProxy) }, ImageNode: ImageNode, ImageComponent: ImageComponent, diff --git a/app/components/SimpleEditor/elements/images/InsertImageCommand.js b/app/components/SimpleEditor/elements/images/InsertImageCommand.js index b5af426..33d4bf9 100644 --- a/app/components/SimpleEditor/elements/images/InsertImageCommand.js +++ b/app/components/SimpleEditor/elements/images/InsertImageCommand.js @@ -1,4 +1,4 @@ -import { Command, pasteContent } from 'substance' +import { Command } from 'substance' class ImageCommand extends Command { constructor () { @@ -19,74 +19,34 @@ class ImageCommand extends Command { return newState } - /** - Inserts (stub) images and triggers a fileupload. - After upload has completed, the image URLs get updated. - */ - execute (params, context) { - let state = this.getCommandState(params) - // Return if command is disabled - if (state.disabled) return - - let documentSession = params.documentSession - let sel = params.selection - let surface = params.surface - let files = params.files - - // can drop images only into container editors - if (!surface.isContainerEditor()) return - - // creating a small doc where we add the images - // and then we use the paste transformation to get this snippet - // into the real doc - let doc = surface.getDocument() - let snippet = doc.createSnippet() - - // as file upload takes longer we will insert stub images - let items = files.map(function (file) { - let node = snippet.create({ type: 'image' }) - snippet.show(node) - return { - file: file, - nodeId: node.id - } - }) - - surface.transaction(function (tx) { - tx.before.selection = sel - return pasteContent(tx, { - selection: sel, - containerId: surface.getContainerId(), - doc: snippet + execute (params) { + let editorSession = params.editorSession + console.log('onExecution', params) + editorSession.transaction((tx) => { + params.files.forEach((file) => { + this._insertImage(tx, file) }) }) - // start uploading - items.forEach(function (item) { - let nodeId = item.nodeId - let file = item.file - let node = doc.get(nodeId) - node.emit('upload:started') - context.documentSession.emit('fileUploadTrigger', file, (filePath, error) => { - let node = doc.get(nodeId) - if (error != null) { - node.emit('upload:failed') - return - } - if (node) { - documentSession.transaction(function (tx) { - tx.set([nodeId, 'src'], filePath) - }) - node.emit('upload:finished') - } - }) + editorSession.fileManager.sync() + } + + _insertImage (tx, file) { + console.log('file', file) + console.log('insert', this) + let imageFile = tx.create({ + type: 'file', + fileType: 'image', + mimeType: file.type }) - return { - status: 'file-upload-process-started' - } + console.log(' After imageFile', imageFile) + // Inserts image at current cursor pos + tx.insertBlockNode({ + type: 'image', + imageFile: imageFile.id + }) } - } export default ImageCommand -- GitLab