Paste middlewares example
by Comandeer
HTML
<div id="editor" contenteditable></div>
<ul id="images"></ul>
CSS
#editor {
border: 5px dashed red;
padding: 10px;
min-height: 2em;
}
#editor:empty::after {
content: 'Paste inside me!';
}
#editor:focus-within::after {
content: '';
}
JavaScript
class PasteHandler {
constructor() {
this.handlers = [];
}
addHandler( fn ) {
this.handlers.push( fn );
}
handle( evt ) {
const handlers = this.handlers.slice( 0 );
evt.preventDefault();
next();
function next() {
const handler = handlers.shift();
if ( handler ) {
handler( evt.clipboardData, next );
}
}
}
}
const pasteHandler = new PasteHandler();
pasteHandler.addHandler( ( clipboardData, next ) => {
console.log( [ ...clipboardData.items ].map( ( { type } ) => type ) );
next();
} );
pasteHandler.addHandler( ( clipboardData, next ) => {
const images = document.querySelector( '#images' );
images.innerHTML = [ ...clipboardData.files ].reduce( ( html, file ) => {
if ( !file.type.startsWith( 'image') ) {
return html;
}
const url = URL.createObjectURL( file );
html += `<li><img src="${ url }" alt="${ file.name }"></li>`;
return html;
}, '' );
next();
} );
pasteHandler.addHandler( ( clipboardData ) => {
const html = clipboardData.getData( 'text/html' );
const selection = window.getSelection();
if ( !selection.rangeCount ) {
return false;
}
selection.deleteFromDocument();
const range = selection.getRangeAt( 0 );
const fragment = range.createContextualFragment( html );
range.insertNode( fragment );
} );
document.querySelector( '#editor' ).addEventListener( 'paste', pasteHandler.handle.bind( pasteHandler ) );