5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-07-03 13:16:08 +00:00

feat(prosemirror): subir imágenes

This commit is contained in:
void 2019-11-20 12:01:09 -03:00
parent 0498a48b8c
commit 578ad08ac4
4 changed files with 124 additions and 2 deletions

View file

@ -275,4 +275,8 @@ svg {
white-space: pre-wrap;
}
}
.sutty-editor-loading-image {
opacity: .5;
}
}

View file

@ -38,7 +38,7 @@ import {toggleMark, setBlockType, wrapIn, baseKeymap} from "prosemirror-commands
import {toggleWrap, toggleBlockType, toggleList,
updateMark, removeMark} from "tiptap-commands"
import { DirectUpload } from "@rails/activestorage"
import {startImageUpload, placeholderPlugin} from "./imageUpload"
const toggleBold = toggleMark(schema.marks.strong)
const toggleItalic = toggleMark(schema.marks.em)
@ -102,6 +102,19 @@ class SuttyEditor {
setupBtn('ol', () => this.runCommand(toggleOl))
setupBtn('h1', () => this.runCommand(toggleH1))
setupBtn('h2', () => this.runCommand(toggleH2))
const imgInput = el.querySelector('.img-input')
imgInput.addEventListener('change', event => {
if (
this.view.state.selection.$from.parent.inlineContent
&& event.target.files.length
) {
const file = event.target.files[0]
event.target.value = ''
startImageUpload(this.view, file, schema)
}
this.view.focus()
})
}
buildState (markdown) {
@ -113,6 +126,7 @@ class SuttyEditor {
plugins: [
gapCursor(),
keymap(baseKeymap),
placeholderPlugin,
inputRules({
rules: [
//emDash, // -- => —

View file

@ -0,0 +1,104 @@
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)
}
})
})
}

View file

@ -6,7 +6,7 @@
%button.ul-btn= "ul"
%button.ol-btn= "ol"
%button.link-btn= "link"
%button.img-btn= "image"
%input.img-input{ type: 'file', accept: 'image/png, image/jpeg' }
%button.h1-btn= "h1"
%button.h2-btn= "h2"
.sutty-editor.sutty-editor-prosemirror.content{ 'data-sutty-identifier': identifier }