Repository: kensnyder/quill-image-drop-module Branch: master Commit: dabeb264ce20 Files: 8 Total size: 8.9 KB Directory structure: gitextract_v0wtbtvj/ ├── .gitignore ├── CHANGELOG.md ├── README.md ├── bin/ │ └── release.sh ├── index.js ├── package.json └── src/ ├── ImageDrop.js └── es5-wrapper.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *~ .DS_Store .idea node_modules ================================================ FILE: CHANGELOG.md ================================================ # Changelog ## v1.0.3 - March 29, 2017 - Drop images at mouse coordinates instead of last caret position ([Issue #2](https://github.com/kensnyder/quill-image-drop-module/issues/2)) ## v1.0.2 - March 25, 2017 - Add README link to plunker demo ## v1.0.1 - March 25, 2017 - Fix GitHub URL ## v1.0.0 - March 18, 2017 - Initial version ================================================ FILE: README.md ================================================ # Quill ImageDrop Module A module for Quill rich text editor to allow images to be pasted and drag/dropped into the editor. ## Demo [Plunker](https://plnkr.co/edit/ubVmPkBjqQESsefM3JrT?p=preview) ## Usage ### Webpack/ES6 ```javascript import Quill from 'quill'; import { ImageDrop } from 'quill-image-drop-module'; Quill.register('modules/imageDrop', ImageDrop); const quill = new Quill(editor, { // ... modules: { // ... imageDrop: true } }); ``` ### Script Tag Copy image-drop.min.js into your web root or include from node_modules ```html ``` ```javascript var quill = new Quill(editor, { // ... modules: { // ... imageDrop: true } }); ``` ================================================ FILE: bin/release.sh ================================================ #!/usr/bin/env bash dir="$(dirname "${BASH_SOURCE[0]}")/.." # Copy ES6 source file cp $dir/src/ImageDrop.js $dir/index.js # Copy the template cp $dir/src/es5-wrapper.js $dir/image-drop.min.js # Compile to ES5 js=$(node $dir/node_modules/babel-cli/bin/babel.js $dir/src/ImageDrop.js --presets=es2015 | $dir/node_modules/uglify-js/bin/uglifyjs -m) echo $js > tmp.js # Wrap sed -i '' -e '/MINIFIED_JS/r tmp.js' -e '/MINIFIED_JS/d' $dir/image-drop.min.js rm tmp.js ================================================ FILE: index.js ================================================ /** * Custom module for quilljs to allow user to drag images from their file system into the editor * and paste images from clipboard (Works on Chrome, Firefox, Edge, not on Safari) * @see https://quilljs.com/blog/building-a-custom-module/ */ export class ImageDrop { /** * Instantiate the module given a quill instance and any options * @param {Quill} quill * @param {Object} options */ constructor(quill, options = {}) { // save the quill reference this.quill = quill; // bind handlers to this instance this.handleDrop = this.handleDrop.bind(this); this.handlePaste = this.handlePaste.bind(this); // listen for drop and paste events this.quill.root.addEventListener('drop', this.handleDrop, false); this.quill.root.addEventListener('paste', this.handlePaste, false); } /** * Handler for drop event to read dropped files from evt.dataTransfer * @param {Event} evt */ handleDrop(evt) { evt.preventDefault(); if (evt.dataTransfer && evt.dataTransfer.files && evt.dataTransfer.files.length) { if (document.caretRangeFromPoint) { const selection = document.getSelection(); const range = document.caretRangeFromPoint(evt.clientX, evt.clientY); if (selection && range) { selection.setBaseAndExtent(range.startContainer, range.startOffset, range.startContainer, range.startOffset); } } this.readFiles(evt.dataTransfer.files, this.insert.bind(this)); } } /** * Handler for paste event to read pasted files from evt.clipboardData * @param {Event} evt */ handlePaste(evt) { if (evt.clipboardData && evt.clipboardData.items && evt.clipboardData.items.length) { this.readFiles(evt.clipboardData.items, dataUrl => { const selection = this.quill.getSelection(); if (selection) { // we must be in a browser that supports pasting (like Firefox) // so it has already been placed into the editor } else { // otherwise we wait until after the paste when this.quill.getSelection() // will return a valid index setTimeout(() => this.insert(dataUrl), 0); } }); } } /** * Insert the image into the document at the current cursor position * @param {String} dataUrl The base64-encoded image URI */ insert(dataUrl) { const index = (this.quill.getSelection() || {}).index || this.quill.getLength(); this.quill.insertEmbed(index, 'image', dataUrl, 'user'); } /** * Extract image URIs a list of files from evt.dataTransfer or evt.clipboardData * @param {File[]} files One or more File objects * @param {Function} callback A function to send each data URI to */ readFiles(files, callback) { // check each file for an image [].forEach.call(files, file => { if (!file.type.match(/^image\/(gif|jpe?g|a?png|svg|webp|bmp|vnd\.microsoft\.icon)/i)) { // file is not an image // Note that some file formats such as psd start with image/* but are not readable return; } // set up file reader const reader = new FileReader(); reader.onload = (evt) => { callback(evt.target.result); }; // read the clipboard item or file const blob = file.getAsFile ? file.getAsFile() : file; if (blob instanceof Blob) { reader.readAsDataURL(blob); } }); } } ================================================ FILE: package.json ================================================ { "name": "quill-image-drop-module", "version": "1.0.3", "description": "A module for Quill rich text editor to allow images to be pasted and drag/dropped into the editor.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "release": "sh ./bin/release.sh" }, "repository": { "type": "git", "url": "git+https://github.com/kensnyder/quill-image-drop-module.git" }, "keywords": [ "quill", "quilljs", "image", "drag", "and", "drop", "drop", "paste" ], "author": "@kensnyder", "license": "MIT", "bugs": { "url": "https://github.com/kensnyder/quill-image-drop-module/issues" }, "homepage": "https://github.com/kensnyder/quill-image-drop-module#readme", "devDependencies": { "babel-cli": "^6.24.0", "babel-preset-env": "^1.2.2", "babel-preset-es2015": "^6.24.0", "uglify-js": "^2.8.13" }, "dependencies": { "quill": "^1.2.2" } } ================================================ FILE: src/ImageDrop.js ================================================ /** * Custom module for quilljs to allow user to drag images from their file system into the editor * and paste images from clipboard (Works on Chrome, Firefox, Edge, not on Safari) * @see https://quilljs.com/blog/building-a-custom-module/ */ export class ImageDrop { /** * Instantiate the module given a quill instance and any options * @param {Quill} quill * @param {Object} options */ constructor(quill, options = {}) { // save the quill reference this.quill = quill; // bind handlers to this instance this.handleDrop = this.handleDrop.bind(this); this.handlePaste = this.handlePaste.bind(this); // listen for drop and paste events this.quill.root.addEventListener('drop', this.handleDrop, false); this.quill.root.addEventListener('paste', this.handlePaste, false); } /** * Handler for drop event to read dropped files from evt.dataTransfer * @param {Event} evt */ handleDrop(evt) { evt.preventDefault(); if (evt.dataTransfer && evt.dataTransfer.files && evt.dataTransfer.files.length) { if (document.caretRangeFromPoint) { const selection = document.getSelection(); const range = document.caretRangeFromPoint(evt.clientX, evt.clientY); if (selection && range) { selection.setBaseAndExtent(range.startContainer, range.startOffset, range.startContainer, range.startOffset); } } this.readFiles(evt.dataTransfer.files, this.insert.bind(this)); } } /** * Handler for paste event to read pasted files from evt.clipboardData * @param {Event} evt */ handlePaste(evt) { if (evt.clipboardData && evt.clipboardData.items && evt.clipboardData.items.length) { this.readFiles(evt.clipboardData.items, dataUrl => { const selection = this.quill.getSelection(); if (selection) { // we must be in a browser that supports pasting (like Firefox) // so it has already been placed into the editor } else { // otherwise we wait until after the paste when this.quill.getSelection() // will return a valid index setTimeout(() => this.insert(dataUrl), 0); } }); } } /** * Insert the image into the document at the current cursor position * @param {String} dataUrl The base64-encoded image URI */ insert(dataUrl) { const index = (this.quill.getSelection() || {}).index || this.quill.getLength(); this.quill.insertEmbed(index, 'image', dataUrl, 'user'); } /** * Extract image URIs a list of files from evt.dataTransfer or evt.clipboardData * @param {File[]} files One or more File objects * @param {Function} callback A function to send each data URI to */ readFiles(files, callback) { // check each file for an image [].forEach.call(files, file => { if (!file.type.match(/^image\/(gif|jpe?g|a?png|svg|webp|bmp|vnd\.microsoft\.icon)/i)) { // file is not an image // Note that some file formats such as psd start with image/* but are not readable return; } // set up file reader const reader = new FileReader(); reader.onload = (evt) => { callback(evt.target.result); }; // read the clipboard item or file const blob = file.getAsFile ? file.getAsFile() : file; if (blob instanceof Blob) { reader.readAsDataURL(blob); } }); } } ================================================ FILE: src/es5-wrapper.js ================================================ (function(){var exports={}; MINIFIED_JS window.Quill.register('modules/imageDrop',exports.ImageDrop);})();