From a908fa84e2028b6270852fc35bd14544cecd9eb4 Mon Sep 17 00:00:00 2001
From: Alexandros Georgantas <alexgeorg86@gmail.com>
Date: Tue, 20 Dec 2016 15:17:23 +0200
Subject: [PATCH] Image implementation and ignore DS_Store

---
 .gitignore                                    |   1 +
 api/db/dev/.gitkeep                           |   0
 api/db/production/.gitkeep                    |   0
 app/components/SimpleEditor/Editor.js         |   2 +-
 app/components/SimpleEditor/config.js         |   2 +
 .../SimpleEditor/elements/elements.scss       |   2 +
 .../SimpleEditor/elements/images/Image.js     |  11 ++
 .../elements/images/ImageComponent.js         |  51 +++++++++
 .../elements/images/ImageHTMLConverter.js     |  18 ++++
 .../elements/images/ImagePackage.js           |  24 +++++
 .../elements/images/InsertImageCommand.js     | 101 ++++++++++++++++++
 .../elements/images/InsertImageTool.js        |  29 +++++
 .../SimpleEditor/elements/images/image.scss   |  16 +++
 .../elements/images/insert-image-tool.scss    |   5 +
 config/dev.js                                 |   2 +-
 .../uploads/e417958680511ad409805ea6f23c35c7  | Bin 0 -> 684 bytes
 16 files changed, 262 insertions(+), 2 deletions(-)
 delete mode 100644 api/db/dev/.gitkeep
 delete mode 100644 api/db/production/.gitkeep
 create mode 100644 app/components/SimpleEditor/elements/images/Image.js
 create mode 100644 app/components/SimpleEditor/elements/images/ImageComponent.js
 create mode 100644 app/components/SimpleEditor/elements/images/ImageHTMLConverter.js
 create mode 100644 app/components/SimpleEditor/elements/images/ImagePackage.js
 create mode 100644 app/components/SimpleEditor/elements/images/InsertImageCommand.js
 create mode 100644 app/components/SimpleEditor/elements/images/InsertImageTool.js
 create mode 100644 app/components/SimpleEditor/elements/images/image.scss
 create mode 100644 app/components/SimpleEditor/elements/images/insert-image-tool.scss
 create mode 100644 public/uploads/e417958680511ad409805ea6f23c35c7

diff --git a/.gitignore b/.gitignore
index e44031e..e67bc2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ logs/*
 node_modules
 public/assets/*
 pubsweet.log
+.DS_Store
diff --git a/api/db/dev/.gitkeep b/api/db/dev/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/api/db/production/.gitkeep b/api/db/production/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/components/SimpleEditor/Editor.js b/app/components/SimpleEditor/Editor.js
index 0b1a223..7bd5c3c 100644
--- a/app/components/SimpleEditor/Editor.js
+++ b/app/components/SimpleEditor/Editor.js
@@ -96,7 +96,7 @@ class Editor extends ProseEditor {
   _renderEditor ($$) {
     const configurator = this.props.configurator
     const editing = this.props.disabled ? 'selection' : 'full'
-
+    console.log('ed', editing)
     return $$(ContainerEditor, {
       editing: editing,
       documentSession: this.documentSession,
diff --git a/app/components/SimpleEditor/config.js b/app/components/SimpleEditor/config.js
index a637603..79df1f7 100644
--- a/app/components/SimpleEditor/config.js
+++ b/app/components/SimpleEditor/config.js
@@ -20,6 +20,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'
 
 // var DialoguePackage = require('./elements/dialogue/DialoguePackage')
 // var NumberedListPackage = require('./elements/numbered_list/NumberedListPackage')
@@ -56,6 +57,7 @@ let config = {
     config.import(NotePackage)
     config.import(SourceNotePackage)
     config.import(CommentPackage)
+    config.import(ImagePackage)
 
     // config.import(DialoguePackage)
     // config.import(NoStyleListPackage)
diff --git a/app/components/SimpleEditor/elements/elements.scss b/app/components/SimpleEditor/elements/elements.scss
index 786bf0a..735e3a2 100644
--- a/app/components/SimpleEditor/elements/elements.scss
+++ b/app/components/SimpleEditor/elements/elements.scss
@@ -7,3 +7,5 @@
 // @import './no_style_list/noStyleList';
 // @import './numbered_list/numberedList';
 @import './source_note/sourceNote';
+@import './images/image';
+@import './images/insert-image-tool';
diff --git a/app/components/SimpleEditor/elements/images/Image.js b/app/components/SimpleEditor/elements/images/Image.js
new file mode 100644
index 0000000..67e4d8a
--- /dev/null
+++ b/app/components/SimpleEditor/elements/images/Image.js
@@ -0,0 +1,11 @@
+import { DocumentNode } from 'substance'
+
+class Image extends DocumentNode {}
+
+Image.define({
+  type: 'image',
+  src: { type: 'string', default: 'http://' },
+  previewSrc: { type: 'string', optional: true }
+})
+
+export default Image
diff --git a/app/components/SimpleEditor/elements/images/ImageComponent.js b/app/components/SimpleEditor/elements/images/ImageComponent.js
new file mode 100644
index 0000000..30c6a73
--- /dev/null
+++ b/app/components/SimpleEditor/elements/images/ImageComponent.js
@@ -0,0 +1,51 @@
+import { BlockNodeComponent } from 'substance'
+
+class ImageComponent extends BlockNodeComponent {
+
+  didMount () {
+    super.didMount.call(this)
+    const { node } = this.props
+    node.on('src:changed', this.rerender, this)
+    // TODO: we should try to factor this out for reuse
+    node.on('upload:started', this.onUploadStarted, this)
+    node.on('upload:finished', this.onUploadFinished, this)
+  }
+
+  dispose () {
+    super.dispose.call(this)
+    const { node } = this.props
+    node.off(this)
+  }
+
+  render ($$) {
+    let el = super.render.call(this, $$)
+    el.addClass('sc-image')
+
+    el.append(
+      $$('img').attr({
+        src: this.props.node.src
+      }).ref('image')
+    )
+
+    if (this.state.uploading) {
+      let progressBar = $$('div')
+        .addClass('se-progress-bar')
+        .ref('progressBar')
+        .append('Uploading ...')
+      el.append(progressBar)
+    }
+
+    return el
+  }
+
+  onUploadStarted () {
+    this.setState({ uploading: true })
+  }
+
+  onUploadFinished () {
+    this.setState({})
+  }
+
+}
+
+export default ImageComponent
diff --git a/app/components/SimpleEditor/elements/images/ImageHTMLConverter.js b/app/components/SimpleEditor/elements/images/ImageHTMLConverter.js
new file mode 100644
index 0000000..088352c
--- /dev/null
+++ b/app/components/SimpleEditor/elements/images/ImageHTMLConverter.js
@@ -0,0 +1,18 @@
+/*
+ * HTML converter for Paragraphs.
+ */
+export default {
+
+  type: 'image',
+  tagName: 'img',
+
+  import: function (el, node) {
+    node.src = el.attr('src')
+    node.previewSrc = el.attr('data-preview-src')
+  },
+
+  export: function (node, el) {
+    el.attr('src', node.src)
+    if (node.previewSrc) el.attr('data-preview-src', node.previewSrc)
+  }
+}
diff --git a/app/components/SimpleEditor/elements/images/ImagePackage.js b/app/components/SimpleEditor/elements/images/ImagePackage.js
new file mode 100644
index 0000000..ec44a1d
--- /dev/null
+++ b/app/components/SimpleEditor/elements/images/ImagePackage.js
@@ -0,0 +1,24 @@
+import ImageNode from './Image'
+import ImageComponent from './ImageComponent'
+import ImageHTMLConverter from './ImageHTMLConverter'
+import InsertImageCommand from './InsertImageCommand'
+import InsertImageTool from './InsertImageTool'
+
+export default {
+  name: 'image',
+  configure: function (config) {
+    config.addNode(ImageNode)
+    config.addComponent('image', ImageComponent)
+    config.addConverter('html', ImageHTMLConverter)
+    config.addCommand('insert-image', InsertImageCommand)
+    config.addTool('insert-image', InsertImageTool)
+    config.addIcon('insert-image', { 'fontawesome': 'fa-image' })
+    config.addLabel('image', { en: 'Image' })
+    config.addLabel('insert-image', { en: 'Insert image' })
+  },
+  ImageNode: ImageNode,
+  ImageComponent: ImageComponent,
+  ImageHTMLConverter: ImageHTMLConverter,
+  InsertImageCommand: InsertImageCommand,
+  InsertImageTool: InsertImageTool
+}
diff --git a/app/components/SimpleEditor/elements/images/InsertImageCommand.js b/app/components/SimpleEditor/elements/images/InsertImageCommand.js
new file mode 100644
index 0000000..c2a2f5d
--- /dev/null
+++ b/app/components/SimpleEditor/elements/images/InsertImageCommand.js
@@ -0,0 +1,101 @@
+import { Command, pasteContent } from 'substance'
+
+class ImageCommand extends Command {
+  constructor () {
+    super({ name: 'insert-image' })
+  }
+
+  getCommandState (params) {
+    let sel = params.selection
+    let surface = params.surface
+    let newState = {
+      disabled: true,
+      active: false
+    }
+    if (sel && !sel.isNull() && !sel.isCustomSelection() &&
+        surface && surface.isContainerEditor()) {
+      newState.disabled = false
+    }
+    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 fileClient = context.fileClient
+    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
+      })
+    })
+
+    // start uploading
+    items.forEach(function (item) {
+      let nodeId = item.nodeId
+      // let file = item.file
+      console.log('item', item)
+      let node = doc.get(nodeId)
+      node.emit('upload:started')
+      // let node = doc.get(nodeId)
+      if (node) {
+        node.emit('upload:finished')
+        // documentSession.transaction(function (tx) {
+        //   tx.set([nodeId, 'src'],)
+        // })
+      }
+      // let channel = fileClient.uploadFile(file, function (err, url) {
+        // if (err) {
+        //   url = 'error'
+        // }
+        // get the node again to make sure it still exists
+        // let node = doc.get(nodeId)
+        // if (node) {
+        //   node.emit('upload:finished')
+        //   documentSession.transaction(function (tx) {
+        //     tx.set([nodeId, 'src'], url)
+        //   })
+        // }
+      // })
+    })
+
+    return {
+      status: 'file-upload-process-started'
+    }
+  }
+
+}
+
+export default ImageCommand
diff --git a/app/components/SimpleEditor/elements/images/InsertImageTool.js b/app/components/SimpleEditor/elements/images/InsertImageTool.js
new file mode 100644
index 0000000..adfb46c
--- /dev/null
+++ b/app/components/SimpleEditor/elements/images/InsertImageTool.js
@@ -0,0 +1,29 @@
+import { Tool } from 'substance'
+
+class InsertImageTool extends Tool {
+
+  getClassNames () {
+    return 'sc-insert-image-tool'
+  }
+
+  renderButton ($$) {
+    let button = super.renderButton($$)
+    let input = $$('input').attr('type', 'file').ref('input')
+      .on('change', this.onFileSelect)
+    return [button, input]
+  }
+
+  onClick () {
+    this.refs.input.click()
+  }
+
+  onFileSelect (e) {
+    let files = e.currentTarget.files
+    this.executeCommand({
+      files: Array.prototype.slice.call(files)
+    })
+  }
+
+}
+
+export default InsertImageTool
diff --git a/app/components/SimpleEditor/elements/images/image.scss b/app/components/SimpleEditor/elements/images/image.scss
new file mode 100644
index 0000000..166907f
--- /dev/null
+++ b/app/components/SimpleEditor/elements/images/image.scss
@@ -0,0 +1,16 @@
+.sc-image {
+  display: block;
+  margin: 0 auto;
+  max-width: 100%;
+  position: relative;
+
+  img {
+    max-width: 1600px;
+  }
+
+  .se-progress-bar {
+    height: 300px;
+    width: 400px;
+  }
+
+}
diff --git a/app/components/SimpleEditor/elements/images/insert-image-tool.scss b/app/components/SimpleEditor/elements/images/insert-image-tool.scss
new file mode 100644
index 0000000..d870d20
--- /dev/null
+++ b/app/components/SimpleEditor/elements/images/insert-image-tool.scss
@@ -0,0 +1,5 @@
+.sc-insert-image-tool > input {
+  left: -1000px;
+  position: fixed;
+  top: -1000px;
+}
diff --git a/config/dev.js b/config/dev.js
index 8f9fe04..6b5f464 100644
--- a/config/dev.js
+++ b/config/dev.js
@@ -12,7 +12,7 @@ module.exports = {
   },
   'pubsweet-backend': {
     dbPath: path.join(__dirname, '..', 'api', 'db'),
-    secret: 'c0d9a89b-fcce-49b3-83bc-0ccf3326d0ef',
+    secret: 'c2f6dba5-b5fa-418a-8dfe-430917a306ee',
     API_ENDPOINT: '/api'
   },
   'pubsweet-component-ink-backend': universal.inkBackend,
diff --git a/public/uploads/e417958680511ad409805ea6f23c35c7 b/public/uploads/e417958680511ad409805ea6f23c35c7
new file mode 100644
index 0000000000000000000000000000000000000000..3074ec8386b48ffeebc1fb63061235129dc2e141
GIT binary patch
literal 684
zcmV;d0#p5oP)<h;3K|Lk000e1NJLTq002k;002k`1ONa4|Kxkj0007WNkl<ZcmeI!
z1FZITAIIVA(b4<Pwzqh}yqL3X+YV;iwr$(Cw_w)M%tybSsA-xWboXigcanatnBThE
zzNV(89*26{KSSPfux^Q4%*P_<LyJmSPkv4|sY|jB6(tUmthYspHzn&IQR1&=P}W<b
z#2b=zuqbhWWOe&c6uhrX!WJz|dfy@v*X<y0`fJD=4$!5kscIee@v7g3yksw35;w0m
zM9vphm9R-(5(U3mQL=UvCHgEQQO}4{pIbnZeih}sV>Stj5j>;2y#|HH&C*_j!uytM
zuR-Athv`T@sNi#Z`G4|31;4w)9#%A$Nht=MYUT*z5)5KZ-?rBvW_6aS>K~-j`Ys&9
zAXwbx{;qS-98NMQ#25#`ybkkjJ%hF}AVkGMz>;=zmDlu|YFwJ^3Lz>Cs<p}P740<W
zGSN<hwh{7XdLZSXISh!LkF3NfgN`Y3gmrWpmrfKpPx`+sQOOUs(sG>!@@FSM2Y-u-
z4$xxji_A<b$;TU_qUn~`QWuKMgNhv>D!X1wy(%(WE7s{fQPFo=s$XQ5P>hAVD=L|(
zrKX9@6lHbV-|POYFsY@cicE+9-nb3w6PYF3VbIGWvrRh;I$vZSHd>F0%sKT8T36((
zY@}8fIcwH4s6&6*r=z4<eJV1&rqnZtV?@qV<&(_nIgxV|bq$)$4~5^4RTW#^ry{4<
zEcFdyGg0t}?JT8Jhox=jF;TDybq?YJQNelCJ!q2K#2DRTV*P`d<U%n9=jZ3tIS4lM
zgBZaNHj%IPLCoeT{h~y#qs>a~gG!oWZRdJXuYXL{>m}z}QwO9O)YQ~et$zU+brk~r
Sek1_^0000<MNUMnLSTZXVMXZx

literal 0
HcmV?d00001

-- 
GitLab