113 lines
3.9 KiB
JavaScript
113 lines
3.9 KiB
JavaScript
/* eslint-env browser */
|
|
import * as Y from '../../src/index.js'
|
|
import ProsemirrorBinding from '../../bindings/ProsemirrorBinding/ProsemirrorBinding.js'
|
|
import WebsocketProvider from '../../provider/websocket/WebSocketProvider.js'
|
|
|
|
import {EditorState} from 'prosemirror-state'
|
|
import {EditorView} from 'prosemirror-view'
|
|
import {Schema, DOMParser, Mark, Fragment, Node, Slice} from 'prosemirror-model'
|
|
import {schema} from 'prosemirror-schema-basic'
|
|
import {exampleSetup} from 'prosemirror-example-setup'
|
|
import {Plugin} from 'prosemirror-state'
|
|
import {Decoration, DecorationSet} from 'prosemirror-view'
|
|
|
|
let placeholderPlugin = new Plugin({
|
|
state: {
|
|
init() { return DecorationSet.empty },
|
|
apply(tr, set) {
|
|
// Adjust decoration positions to changes made by the transaction
|
|
set = set.map(tr.mapping, tr.doc)
|
|
// See if the transaction adds or removes any placeholders
|
|
let action = tr.getMeta(this)
|
|
if (action && action.add) {
|
|
let widget = document.createElement("placeholder")
|
|
let deco = Decoration.widget(action.add.pos, widget, {id: action.add.id})
|
|
set = set.add(tr.doc, [deco])
|
|
} else if (action && action.remove) {
|
|
set = set.remove(set.find(null, null,
|
|
spec => spec.id == action.remove.id))
|
|
}
|
|
return set
|
|
}
|
|
},
|
|
props: {
|
|
decorations(state) { return this.getState(state) }
|
|
}
|
|
})
|
|
|
|
function findPlaceholder(state, id) {
|
|
let decos = placeholderPlugin.getState(state)
|
|
let found = decos.find(null, null, spec => spec.id == id)
|
|
return found.length ? found[0].from : null
|
|
}
|
|
|
|
document.querySelector("#image-upload").addEventListener("change", e => {
|
|
if (view.state.selection.$from.parent.inlineContent && e.target.files.length)
|
|
startImageUpload(view, e.target.files[0])
|
|
view.focus()
|
|
})
|
|
|
|
function startImageUpload(view, file) {
|
|
// A fresh object to act as the ID for this upload
|
|
let id = {}
|
|
|
|
// Replace the selection with a placeholder
|
|
let tr = view.state.tr
|
|
if (!tr.selection.empty) tr.deleteSelection()
|
|
tr.setMeta(placeholderPlugin, {add: {id, pos: tr.selection.from}})
|
|
view.dispatch(tr)
|
|
|
|
uploadFile(file).then(url => {
|
|
let pos = findPlaceholder(view.state, id)
|
|
// If the content around the placeholder has been deleted, drop
|
|
// the image
|
|
if (pos == null) return
|
|
// Otherwise, insert it at the placeholder's position, and remove
|
|
// the placeholder
|
|
view.dispatch(view.state.tr
|
|
.replaceWith(pos, pos, schema.nodes.image.create({src: url}))
|
|
.setMeta(placeholderPlugin, {remove: {id}}))
|
|
}, () => {
|
|
// On failure, just clean up the placeholder
|
|
view.dispatch(tr.setMeta(placeholderPlugin, {remove: {id}}))
|
|
})
|
|
}
|
|
|
|
// This is just a dummy that loads the file and creates a data URL.
|
|
// You could swap it out with a function that does an actual upload
|
|
// and returns a regular URL for the uploaded file.
|
|
function uploadFile (file) {
|
|
let reader = new FileReader()
|
|
return new Promise((accept, fail) => {
|
|
reader.onload = () => accept(reader.result)
|
|
reader.onerror = () => fail(reader.error)
|
|
// Some extra delay to make the asynchronicity visible
|
|
setTimeout(() => reader.readAsDataURL(file), 1500)
|
|
})
|
|
}
|
|
|
|
const view = new EditorView(document.querySelector('#editor'), {
|
|
state: EditorState.create({
|
|
doc: DOMParser.fromSchema(schema).parse(document.querySelector('#content')),
|
|
plugins: exampleSetup({schema}).concat(placeholderPlugin)
|
|
})
|
|
})
|
|
|
|
const provider = new WebsocketProvider('ws://localhost:1234/')
|
|
const ydocument = provider.get('prosemirror')
|
|
/**
|
|
* @type {any}
|
|
*/
|
|
const type = ydocument.define('prosemirror', Y.XmlFragment)
|
|
const prosemirrorBinding = new ProsemirrorBinding(type, view)
|
|
|
|
window.view = view
|
|
window.EditorState = EditorState
|
|
window.EditorView = EditorView
|
|
window.Mark = Mark
|
|
window.Fragment = Fragment
|
|
window.Node = Node
|
|
window.Schema = Schema
|
|
window.Slice = Slice
|
|
window.prosemirrorBinding = prosemirrorBinding
|