Skip to content
Snippets Groups Projects
Commit a908fa84 authored by Alexandros Georgantas's avatar Alexandros Georgantas
Browse files

Image implementation and ignore DS_Store

parent 71e408bf
No related branches found
No related tags found
No related merge requests found
Showing
with 262 additions and 2 deletions
...@@ -5,3 +5,4 @@ logs/* ...@@ -5,3 +5,4 @@ logs/*
node_modules node_modules
public/assets/* public/assets/*
pubsweet.log pubsweet.log
.DS_Store
...@@ -96,7 +96,7 @@ class Editor extends ProseEditor { ...@@ -96,7 +96,7 @@ class Editor extends ProseEditor {
_renderEditor ($$) { _renderEditor ($$) {
const configurator = this.props.configurator const configurator = this.props.configurator
const editing = this.props.disabled ? 'selection' : 'full' const editing = this.props.disabled ? 'selection' : 'full'
console.log('ed', editing)
return $$(ContainerEditor, { return $$(ContainerEditor, {
editing: editing, editing: editing,
documentSession: this.documentSession, documentSession: this.documentSession,
......
...@@ -20,6 +20,7 @@ import CommentPackage from './elements/comment/CommentPackage' ...@@ -20,6 +20,7 @@ import CommentPackage from './elements/comment/CommentPackage'
import ExtractPackage from './elements/extract/ExtractPackage' import ExtractPackage from './elements/extract/ExtractPackage'
import NotePackage from './elements/note/NotePackage' import NotePackage from './elements/note/NotePackage'
import SourceNotePackage from './elements/source_note/SourceNotePackage' import SourceNotePackage from './elements/source_note/SourceNotePackage'
import ImagePackage from './elements/images/ImagePackage'
// var DialoguePackage = require('./elements/dialogue/DialoguePackage') // var DialoguePackage = require('./elements/dialogue/DialoguePackage')
// var NumberedListPackage = require('./elements/numbered_list/NumberedListPackage') // var NumberedListPackage = require('./elements/numbered_list/NumberedListPackage')
...@@ -56,6 +57,7 @@ let config = { ...@@ -56,6 +57,7 @@ let config = {
config.import(NotePackage) config.import(NotePackage)
config.import(SourceNotePackage) config.import(SourceNotePackage)
config.import(CommentPackage) config.import(CommentPackage)
config.import(ImagePackage)
// config.import(DialoguePackage) // config.import(DialoguePackage)
// config.import(NoStyleListPackage) // config.import(NoStyleListPackage)
......
...@@ -7,3 +7,5 @@ ...@@ -7,3 +7,5 @@
// @import './no_style_list/noStyleList'; // @import './no_style_list/noStyleList';
// @import './numbered_list/numberedList'; // @import './numbered_list/numberedList';
@import './source_note/sourceNote'; @import './source_note/sourceNote';
@import './images/image';
@import './images/insert-image-tool';
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
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
/*
* 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)
}
}
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
}
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
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
.sc-image {
display: block;
margin: 0 auto;
max-width: 100%;
position: relative;
img {
max-width: 1600px;
}
.se-progress-bar {
height: 300px;
width: 400px;
}
}
.sc-insert-image-tool > input {
left: -1000px;
position: fixed;
top: -1000px;
}
...@@ -12,7 +12,7 @@ module.exports = { ...@@ -12,7 +12,7 @@ module.exports = {
}, },
'pubsweet-backend': { 'pubsweet-backend': {
dbPath: path.join(__dirname, '..', 'api', 'db'), dbPath: path.join(__dirname, '..', 'api', 'db'),
secret: 'c0d9a89b-fcce-49b3-83bc-0ccf3326d0ef', secret: 'c2f6dba5-b5fa-418a-8dfe-430917a306ee',
API_ENDPOINT: '/api' API_ENDPOINT: '/api'
}, },
'pubsweet-component-ink-backend': universal.inkBackend, 'pubsweet-component-ink-backend': universal.inkBackend,
......
File added
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment