Created
May 3, 2019 09:45
-
-
Save yalamber/d436025368069d692bf84449385cdaa7 to your computer and use it in GitHub Desktop.
Slate Firebase storage image upload
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { getEventRange, getEventTransfer } from 'slate-react'; | |
import { Circle } from 'rc-progress'; | |
import imageExtensions from 'image-extensions'; | |
import isUrl from 'is-url'; | |
import styled from '@emotion/styled'; | |
const Image = styled('img')` | |
display: block; | |
max-width: 100%; | |
max-height: 20em; | |
box-shadow: ${props => (props.selected ? '0 0 0 2px blue;' : (props.status === 'error'? '0 0 0 2px red;': 'none'))}; | |
`; | |
const LoadingIndicator = ({children, progress}) => { | |
return ( | |
<div style={{position: 'relative', display: 'inline-block'}}> | |
<Circle percent={progress} style={{maxWidth: '20%', position: 'absolute', zIndex:2, margin: 'auto auto', }} strokeWidth="10" strokeColor="#60A677" /> | |
<div style={{opacity: 0.5}}> | |
{children} | |
</div> | |
</div> | |
) | |
} | |
export default function FirebaseImgUpload(options) { | |
const app = options.firebaseApp; | |
const storageRef = app.storage().ref(); | |
const pluginHelpers = { | |
isImage(url) { | |
return imageExtensions.includes(pluginHelpers.getExtension(url)); | |
}, | |
getExtension(url) { | |
return new URL(url).pathname.split('.').pop(); | |
}, | |
insertImage(file) { | |
return (editor, src, target) => { | |
if (target) { | |
editor.select(target); | |
} | |
editor.insertBlock({ | |
type: 'image', | |
data: { src, status: 'loading' }, | |
}); | |
editor.wrapBlock({ | |
type: 'loadingIndicator', | |
data: {progress: 0} | |
}); | |
//upload image | |
let ref = storageRef.child(`images/${file.name}`); | |
let uploadTask = ref.putString(src, 'data_url'); | |
uploadTask.on('state_changed', function (snapshot) { | |
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; | |
//update progress bar | |
editor.unwrapBlock('loadingIndicator').wrapBlock({ | |
type: 'loadingIndicator', | |
data: {progress} | |
}); | |
}, function (error) { | |
// Handle unsuccessful uploads | |
editor.setBlocks({ data: { src, status: 'error' }}); | |
}, function () { | |
// Handle successful uploads on complete | |
// For instance, get the download URL: https://firebasestorage.googleapis.com/... | |
uploadTask.snapshot.ref.getDownloadURL().then(function (downloadURL) { | |
//update Image | |
console.log('Updated with uploaded image'); | |
editor.unwrapBlock("loadingIndicator"); | |
editor.setBlocks({ data: { src: downloadURL, status: 'loaded' }}); | |
}); | |
}); | |
} | |
}, | |
onDropOrPaste(event, editor, next) { | |
const target = getEventRange(event, editor) | |
if (!target && event.type === 'drop') return next() | |
const transfer = getEventTransfer(event) | |
const { type, text, files } = transfer | |
if (type === 'files') { | |
for (const file of files) { | |
const reader = new FileReader() | |
const [mime] = file.type.split('/') | |
if (mime !== 'image') continue | |
reader.addEventListener('load', () => { | |
editor.command(pluginHelpers.insertImage(file), reader.result, target) | |
}) | |
reader.readAsDataURL(file) | |
} | |
return | |
} | |
if (type === 'text') { | |
if (!isUrl(text)) return next(); | |
if (!pluginHelpers.isImage(text)) return next(); | |
editor.command(pluginHelpers.insertImage, text, target); | |
return; | |
} | |
next(); | |
}, | |
renderNode(props, editor, next) { | |
const { attributes, node, isFocused } = props | |
switch (node.type) { | |
case 'image': { | |
const src = node.data.get('src'); | |
const status = node.data.get('status'); | |
return <Image src={src} selected={isFocused} {...attributes} status={status} />; | |
} | |
case 'loadingIndicator': { | |
const progress = node.data.get('progress'); | |
return <LoadingIndicator {...props} progress={progress} /> | |
} | |
default: { | |
return next(); | |
} | |
} | |
} | |
} | |
// Return our "plugin" object, containing the `onKeyDown` handler. | |
return { | |
onDrop: pluginHelpers.onDropOrPaste, | |
onPaste: pluginHelpers.onDropOrPaste, | |
renderNode: pluginHelpers.renderNode | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment