mirror of
https://0xacab.org/sutty/sutty
synced 2024-07-06 00:45:45 +00:00
105 lines
2.9 KiB
JavaScript
105 lines
2.9 KiB
JavaScript
|
import { DirectUpload } from "@rails/activestorage"
|
||
|
|
||
|
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(
|
||
|
action.add.blobUrl ? 'img' : 'placeholder'
|
||
|
)
|
||
|
|
||
|
// mostrar imágen en cache mientras tanto
|
||
|
if (action.add.blobUrl) {
|
||
|
widget.src = action.add.blobUrl
|
||
|
widget.classList.add('sutty-editor-loading-image')
|
||
|
}
|
||
|
|
||
|
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) }
|
||
|
}
|
||
|
})
|
||
|
export {placeholderPlugin}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
// XXX: buscar una manera mejor de pasar el schema
|
||
|
export function startImageUpload (view, file, schema) {
|
||
|
const altText = window.prompt('descripción de imágen', '')
|
||
|
|
||
|
let id = {}
|
||
|
|
||
|
const blobUrl = URL.createObjectURL(file)
|
||
|
|
||
|
// 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, blobUrl},
|
||
|
})
|
||
|
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,
|
||
|
alt: altText.length ? altText : undefined,
|
||
|
}))
|
||
|
.setMeta(placeholderPlugin, {remove: {id}})
|
||
|
)
|
||
|
}, () => {
|
||
|
// On failure, just clean up the placeholder
|
||
|
view.dispatch(tr.setMeta(placeholderPlugin, {remove: {id}}))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
export function uploadFile (file) {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
const upload = new DirectUpload(
|
||
|
file,
|
||
|
location.origin + '/rails/active_storage/direct_uploads',
|
||
|
)
|
||
|
|
||
|
upload.create((error, blob) => {
|
||
|
if (error) {
|
||
|
reject(error)
|
||
|
} else {
|
||
|
const url = `${location.origin}/rails/active_storage/blobs/${blob.signed_id}/${blob.filename}`
|
||
|
resolve(url)
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
}
|