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