├── .babelrc ├── .gitignore ├── TODO.md ├── webpack.config.js ├── bower.json ├── package.json ├── LICENSE ├── src ├── utils.js └── quill-module.js ├── README.md ├── examples └── basic-usage.js └── quill-module.js /.babelrc: -------------------------------------------------------------------------------- 1 | { "presets": ["es2015"] } 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | * Add JSFiddle example usage 4 | * Expand on examples 5 | * Add demo page to `immense.js.org/quill-drag-and-drop-module` & `quill-drag-and-drop-module.js.org` 6 | * Fix weirdness of passing `{tag, attr}` as second param of `onDrop` 7 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: './src/quill-module.js', 3 | output: { 4 | filename: 'quill-module.js', 5 | library: 'DragAndDropModule', 6 | libraryTarget: 'umd' 7 | }, 8 | module: { 9 | loaders: [ 10 | { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"} 11 | ] 12 | }, 13 | externals: { 14 | quill: { 15 | root: "Quill", 16 | commonjs: "quill", 17 | commonjs2: "quill", 18 | amd: "quill" 19 | } 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quill-drag-and-drop-module", 3 | "description": "Quill module to add drag-and-drop support to the Quill container", 4 | "main": "quill-module.js", 5 | "authors": [ 6 | "Christian Bankester " 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "quill", 11 | "drag-and-drop" 12 | ], 13 | "homepage": "https://github.com/immense/quill-drag-and-drop-module", 14 | "moduleType": [], 15 | "ignore": [ 16 | "**/.*", 17 | "node_modules", 18 | "bower_components", 19 | "test", 20 | "tests" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quill-drag-and-drop-module", 3 | "version": "0.3.0", 4 | "description": "Quill module to add drag-and-drop support to the Quill container", 5 | "main": "quill-module.js", 6 | "scripts": { 7 | "compile": "webpack" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/immense/quill-drag-and-drop-module.git" 12 | }, 13 | "keywords": [ 14 | "quill", 15 | "drag-and-drop" 16 | ], 17 | "author": "Christian Bankester ", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/immense/quill-drag-and-drop-module/issues" 21 | }, 22 | "homepage": "https://github.com/immense/quill-drag-and-drop-module#readme", 23 | "devDependencies": { 24 | "babel-core": "^6.4.0", 25 | "babel-loader": "^6.2.1", 26 | "babel-preset-es2015": "^6.3.13", 27 | "webpack": "^1.12.11" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Immense Networks 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | export function convertDraggable(draggable) { 2 | if (draggable.content_type_pattern && draggable.tag && draggable.attr) { 3 | const ret = Object.assign({}, draggable); 4 | ret.content_type_regex = new RegExp(draggable.content_type_pattern); 5 | delete ret.content_type_pattern; 6 | return ret; 7 | } else { 8 | const e = new Error("draggables should have content_type_pattern, tag and attr keys"); 9 | e.invalid_draggable = draggable; 10 | throw e; 11 | } 12 | }; 13 | 14 | export function filesMatching(file_list, draggables) { 15 | const ret = []; 16 | for (let i = 0; i < file_list.length; i++) { 17 | const file = file_list.item(i); 18 | const draggable = draggables.find(d => d.content_type_regex.test(file.type)); 19 | draggable && ret.push({file, tag: draggable.tag, attr: draggable.attr}); 20 | } 21 | return ret; 22 | }; 23 | 24 | export function getFileDataUrl(file) { 25 | const reader = new FileReader(); 26 | return new Promise(resolve => { 27 | reader.addEventListener("load", function () { 28 | resolve(reader.result); 29 | }, false); 30 | reader.readAsDataURL(file); 31 | }); 32 | }; 33 | 34 | export function nullReturner() { 35 | return null; 36 | }; 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quill Drag-and-Drop Module 2 | 3 | [Quill](http://quilljs.com/) module to add drag-and-drop support to the Quill container 4 | 5 | ## Installation 6 | 7 | The quill drag-and-drop module is available as a [Bower](http://bower.io/) package and as an [npm](https://www.npmjs.com/) package. 8 | 9 | To install with Bower: 10 | 11 | `bower install quill-drag-and-drop-module` 12 | 13 | Or, to install with npm: 14 | 15 | `npm install --save quill-drag-and-drop-module` 16 | 17 | ## Usage 18 | 19 | It is expected that either: 20 | * `Quill` is globally accessible, or 21 | * `"quill"` is requirable via [CommonJS](http://wiki.commonjs.org/wiki/CommonJS) or [AMD](https://github.com/amdjs/amdjs-api/wiki/AMD) 22 | 23 | Instantiate a new Quill like so: 24 | 25 | ```javascript 26 | const Quill = require('quill'); 27 | const DragAndDropModule = require('quill-drag-and-drop-module'); 28 | ... 29 | const quill = new Quill('#basic-wrapper .editor-container', { 30 | modules: { 31 | toolbar: { 32 | container: '#basic-toolbar' 33 | }, 34 | dragAndDrop: { 35 | draggables: [ 36 | { 37 | content_type_pattern: DragAndDropModule.image_content_type_pattern, 38 | tag: 'img', 39 | attr: 'src' 40 | }, 41 | ], 42 | onDrop(file) { 43 | return DragAndDropModule.utils.getFileDataUrl(file) 44 | .then(base64 => {...}) 45 | .then(response_from_server => response_from_server.url_of_resource); 46 | } 47 | } 48 | } 49 | }); 50 | ``` 51 | 52 | See the [demo](http://immense.js.org/quill-drag-and-drop-module) for a working example. 53 | 54 | ## Building 55 | 56 | To compile the ES2015 source to ES5 [UMD](https://github.com/umdjs/umd), do the following in a Node.js enabled environment: 57 | 58 | ```bash 59 | cd /path/to/git/repo 60 | npm install 61 | npm run compile 62 | ``` 63 | 64 | ## License 65 | 66 | The quill drag-and-drop module is released under the MIT License. Please see the [LICENSE](LICENSE) file for details. 67 | -------------------------------------------------------------------------------- /examples/basic-usage.js: -------------------------------------------------------------------------------- 1 | const Quill = require('quill'); 2 | const DragAndDropModule = require('quill-drag-and-drop-module'); 3 | 4 | const image_content_type_pattern = DragAndDropModule.image_content_type_pattern; 5 | const getFileDataUrl = DragAndDropModule.utils.getFileDataUrl; 6 | 7 | function doSomethingWithBase64Image(base64_content) { 8 | 9 | // we'll just return an href as an example 10 | return "http://quilljs.com/images/quill-photo.jpg"; 11 | } 12 | 13 | const basic_editor = new Quill('#basic-editor', { 14 | modules: { 15 | toolbar: { 16 | container: '#basic-toolbar' 17 | }, 18 | dragAndDrop: { 19 | 20 | // draggables is an array containing the types of files that are allowed 21 | // to be dragged onto the editor, and the type of html element & name of 22 | // html attribute that will be added to the editor from this file 23 | draggables: [ 24 | { 25 | 26 | // string regex pattern used to match a dropped file's `type` 27 | content_type_pattern: image_content_type_pattern, 28 | 29 | // the type of html element that will be added when a file matching 30 | // this draggable is dropped on the editor 31 | tag: 'img', 32 | 33 | // the attribute of the created html element that will be set based on 34 | // the file's data & result of onDrop (see below) 35 | attr: 'src' 36 | } 37 | ], 38 | 39 | // onDrop will be called any time a file with a type matching a 40 | // content_type_pattern defined in draggables is dropped on the editor 41 | // params: 42 | // file - the File object that was dropped 43 | onDrop(file) { 44 | return getFileDataUrl(file).then(base64_content => { 45 | 46 | // do something with the base64 content 47 | // e.g. save file to server, resize image, add a watermark, etc. 48 | return doSomethingWithBase64Image(base64_content); 49 | }) 50 | .then(response_from_do_something => { 51 | 52 | // whatever you return (or promise) from `onDrop` will be used as the 53 | // value of the `attr` attribute for the new html element, 54 | // with a couple of exceptions: 55 | // returning `false` from `onDrop` => 56 | // this file will be ignored; no new element will be added to the 57 | // editor 58 | // returning `null` from `onDrop` => 59 | // the file's data url (i.e. base64 representation) will be used 60 | // it's the same as if you'd done: 61 | // `onDrop: DragAndDropModule.utils.getFileDataUrl` 62 | // This is the default behavior (i.e., it's what will happen if 63 | // you don't define `onDrop`) 64 | return response_from_do_something; 65 | }) 66 | .catch(err => { 67 | 68 | // return false to tell Quill to ignore this dropped file 69 | return false; 70 | }); 71 | } 72 | } 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /src/quill-module.js: -------------------------------------------------------------------------------- 1 | import Quill from 'quill'; 2 | import {convertDraggable, filesMatching, getFileDataUrl, nullReturner} from './utils'; 3 | 4 | const image_content_type_pattern = '^image\/'; 5 | const DEFAULT_OPTIONS = { 6 | container: null, 7 | onDrop: null, 8 | draggable_content_type_patterns: [ 9 | image_content_type_pattern 10 | ] 11 | }; 12 | 13 | const private_data = new WeakMap(); 14 | 15 | export default class DragAndDropModule { 16 | 17 | constructor(quill, options) { 18 | const _private = new Map(); 19 | 20 | private_data.set(this, _private); 21 | 22 | _private 23 | .set('quill', quill) 24 | .set('options', Object.assign({}, DEFAULT_OPTIONS, options)) 25 | .set('container', options.container || quill.container.querySelector('.ql-editor')) 26 | .set('draggables', this.options.draggables.map(convertDraggable)) 27 | .set('listeners', new Set()); 28 | 29 | // Drop listener 30 | this.addListener(this.container, 'drop', event => { 31 | const onDrop = this.options.onDrop; 32 | const node = event.target['ql-data'] ? event.target : this.container; 33 | const files = event.dataTransfer.files; 34 | const file_infos = filesMatching(files, this.draggables); 35 | 36 | if (file_infos.length === 0) return; 37 | 38 | event.stopPropagation(); 39 | event.preventDefault(); 40 | 41 | // call onDrop for each dropped file 42 | Promise.all(file_infos.map(file_info => { 43 | return Promise 44 | .resolve((onDrop || nullReturner)(file_info.file, {tag: file_info.tag, attr: file_info.attr})) 45 | .then(ret => ({on_drop_ret_val: ret, file_info})); 46 | })) 47 | 48 | // map return vals of onDrop/nullReturner to file datas 49 | .then(datas => Promise.all(datas.map(({on_drop_ret_val, file_info}) => { 50 | if (on_drop_ret_val === false) { 51 | // if onDrop() returned false (or a false-bearing promise), it 52 | // means that we shouldn't do anything with this file 53 | return; 54 | } 55 | const {tag, attr} = file_info; 56 | // if ret is null, either onDrop() returned null (or a null- 57 | // bearing promise), or onDrop isn't defined, so just use the 58 | // file's base64 as the value for tag[draggable.attr] 59 | // 60 | // if ret is non-false and non-null, it means onDrop returned 61 | // something (or promised something) that isn't null or false. 62 | // Assume it's what we should use for tag[draggable.attr] 63 | let data; 64 | if (on_drop_ret_val === null) 65 | data = getFileDataUrl(file_info.file); 66 | else 67 | data = on_drop_ret_val; 68 | 69 | return Promise 70 | .resolve(data) 71 | .then(ret => ({data: ret, tag, attr})); 72 | }))) 73 | .then(datas => datas.forEach(file_info => { 74 | // loop through each file_info and attach them to the editor 75 | 76 | // file_info is undefined if onDrop returned false 77 | if (file_info) { 78 | const {data, tag, attr} = file_info; 79 | // create an element from the given `tag` (e.g. 'img') 80 | const new_element = document.createElement(tag); 81 | 82 | // set `attr` to `data` (e.g. img.src = "data:image/png;base64..") 83 | new_element.setAttribute(attr, data); 84 | 85 | // attach the tag to the quill container 86 | // TODO: maybe a better way to determine *exactly* where to append 87 | // the node? Currently, we're guessing based on event.target, but 88 | // that only gets us the node itself, not the position within the 89 | // node (i.e., if the node is a text node, maybe it's possible to 90 | // split the text node on the point where the user to dropped) 91 | node.appendChild(new_element); 92 | } 93 | })); 94 | }); 95 | } 96 | 97 | destroy() { 98 | // remove listeners 99 | const listeners = private_data.get(this).get('listeners'); 100 | listeners.forEach(({node, event_name, listener}) => { 101 | node.removeEventListener(event_name, listener); 102 | }); 103 | } 104 | 105 | addListener(node, event_name, listener_fn) { 106 | const listener = listener_fn.bind(this); 107 | node.addEventListener(event_name, listener, false); 108 | private_data.get(this).get('listeners').add({node, event_name, listener}); 109 | } 110 | 111 | get quill() { 112 | return private_data.get(this).get('quill'); 113 | } 114 | 115 | get draggables() { 116 | return private_data.get(this).get('draggables'); 117 | } 118 | 119 | get container() { 120 | return private_data.get(this).get('container'); 121 | } 122 | 123 | get options() { 124 | return private_data.get(this).get('options'); 125 | } 126 | 127 | static get image_content_type_pattern() { 128 | return image_content_type_pattern; 129 | } 130 | 131 | static get utils() { 132 | return { 133 | getFileDataUrl 134 | }; 135 | } 136 | } 137 | 138 | Quill.register('modules/dragAndDrop', DragAndDropModule); 139 | -------------------------------------------------------------------------------- /quill-module.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(require("quill")); 4 | else if(typeof define === 'function' && define.amd) 5 | define(["quill"], factory); 6 | else if(typeof exports === 'object') 7 | exports["DragAndDropModule"] = factory(require("quill")); 8 | else 9 | root["DragAndDropModule"] = factory(root["Quill"]); 10 | })(this, function(__WEBPACK_EXTERNAL_MODULE_1__) { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) 20 | /******/ return installedModules[moduleId].exports; 21 | 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ exports: {}, 25 | /******/ id: moduleId, 26 | /******/ loaded: false 27 | /******/ }; 28 | 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | 32 | /******/ // Flag the module as loaded 33 | /******/ module.loaded = true; 34 | 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | 39 | 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | 46 | /******/ // __webpack_public_path__ 47 | /******/ __webpack_require__.p = ""; 48 | 49 | /******/ // Load entry module and return exports 50 | /******/ return __webpack_require__(0); 51 | /******/ }) 52 | /************************************************************************/ 53 | /******/ ([ 54 | /* 0 */ 55 | /***/ (function(module, exports, __webpack_require__) { 56 | 57 | 'use strict'; 58 | 59 | Object.defineProperty(exports, "__esModule", { 60 | value: true 61 | }); 62 | 63 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 64 | 65 | var _quill = __webpack_require__(1); 66 | 67 | var _quill2 = _interopRequireDefault(_quill); 68 | 69 | var _utils = __webpack_require__(2); 70 | 71 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 72 | 73 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 74 | 75 | var image_content_type_pattern = '^image\/'; 76 | var DEFAULT_OPTIONS = { 77 | container: null, 78 | onDrop: null, 79 | draggable_content_type_patterns: [image_content_type_pattern] 80 | }; 81 | 82 | var private_data = new WeakMap(); 83 | 84 | var DragAndDropModule = function () { 85 | function DragAndDropModule(quill, options) { 86 | var _this = this; 87 | 88 | _classCallCheck(this, DragAndDropModule); 89 | 90 | var _private = new Map(); 91 | 92 | private_data.set(this, _private); 93 | 94 | _private.set('quill', quill).set('options', Object.assign({}, DEFAULT_OPTIONS, options)).set('container', options.container || quill.container.querySelector('.ql-editor')).set('draggables', this.options.draggables.map(_utils.convertDraggable)).set('listeners', new Set()); 95 | 96 | // Drop listener 97 | this.addListener(this.container, 'drop', function (event) { 98 | var onDrop = _this.options.onDrop; 99 | var node = event.target['ql-data'] ? event.target : _this.container; 100 | var files = event.dataTransfer.files; 101 | var file_infos = (0, _utils.filesMatching)(files, _this.draggables); 102 | 103 | if (file_infos.length === 0) return; 104 | 105 | event.stopPropagation(); 106 | event.preventDefault(); 107 | 108 | // call onDrop for each dropped file 109 | Promise.all(file_infos.map(function (file_info) { 110 | return Promise.resolve((onDrop || _utils.nullReturner)(file_info.file, { tag: file_info.tag, attr: file_info.attr })).then(function (ret) { 111 | return { on_drop_ret_val: ret, file_info: file_info }; 112 | }); 113 | }) 114 | 115 | // map return vals of onDrop/nullReturner to file datas 116 | ).then(function (datas) { 117 | return Promise.all(datas.map(function (_ref) { 118 | var on_drop_ret_val = _ref.on_drop_ret_val, 119 | file_info = _ref.file_info; 120 | 121 | if (on_drop_ret_val === false) { 122 | // if onDrop() returned false (or a false-bearing promise), it 123 | // means that we shouldn't do anything with this file 124 | return; 125 | } 126 | var tag = file_info.tag, 127 | attr = file_info.attr; 128 | // if ret is null, either onDrop() returned null (or a null- 129 | // bearing promise), or onDrop isn't defined, so just use the 130 | // file's base64 as the value for tag[draggable.attr] 131 | // 132 | // if ret is non-false and non-null, it means onDrop returned 133 | // something (or promised something) that isn't null or false. 134 | // Assume it's what we should use for tag[draggable.attr] 135 | 136 | var data = void 0; 137 | if (on_drop_ret_val === null) data = (0, _utils.getFileDataUrl)(file_info.file);else data = on_drop_ret_val; 138 | 139 | return Promise.resolve(data).then(function (ret) { 140 | return { data: ret, tag: tag, attr: attr }; 141 | }); 142 | })); 143 | }).then(function (datas) { 144 | return datas.forEach(function (file_info) { 145 | // loop through each file_info and attach them to the editor 146 | 147 | // file_info is undefined if onDrop returned false 148 | if (file_info) { 149 | var data = file_info.data, 150 | tag = file_info.tag, 151 | attr = file_info.attr; 152 | // create an element from the given `tag` (e.g. 'img') 153 | 154 | var new_element = document.createElement(tag); 155 | 156 | // set `attr` to `data` (e.g. img.src = "data:image/png;base64..") 157 | new_element.setAttribute(attr, data); 158 | 159 | // attach the tag to the quill container 160 | // TODO: maybe a better way to determine *exactly* where to append 161 | // the node? Currently, we're guessing based on event.target, but 162 | // that only gets us the node itself, not the position within the 163 | // node (i.e., if the node is a text node, maybe it's possible to 164 | // split the text node on the point where the user to dropped) 165 | node.appendChild(new_element); 166 | } 167 | }); 168 | }); 169 | }); 170 | } 171 | 172 | _createClass(DragAndDropModule, [{ 173 | key: 'destroy', 174 | value: function destroy() { 175 | // remove listeners 176 | var listeners = private_data.get(this).get('listeners'); 177 | listeners.forEach(function (_ref2) { 178 | var node = _ref2.node, 179 | event_name = _ref2.event_name, 180 | listener = _ref2.listener; 181 | 182 | node.removeEventListener(event_name, listener); 183 | }); 184 | } 185 | }, { 186 | key: 'addListener', 187 | value: function addListener(node, event_name, listener_fn) { 188 | var listener = listener_fn.bind(this); 189 | node.addEventListener(event_name, listener, false); 190 | private_data.get(this).get('listeners').add({ node: node, event_name: event_name, listener: listener }); 191 | } 192 | }, { 193 | key: 'quill', 194 | get: function get() { 195 | return private_data.get(this).get('quill'); 196 | } 197 | }, { 198 | key: 'draggables', 199 | get: function get() { 200 | return private_data.get(this).get('draggables'); 201 | } 202 | }, { 203 | key: 'container', 204 | get: function get() { 205 | return private_data.get(this).get('container'); 206 | } 207 | }, { 208 | key: 'options', 209 | get: function get() { 210 | return private_data.get(this).get('options'); 211 | } 212 | }], [{ 213 | key: 'image_content_type_pattern', 214 | get: function get() { 215 | return image_content_type_pattern; 216 | } 217 | }, { 218 | key: 'utils', 219 | get: function get() { 220 | return { 221 | getFileDataUrl: _utils.getFileDataUrl 222 | }; 223 | } 224 | }]); 225 | 226 | return DragAndDropModule; 227 | }(); 228 | 229 | exports.default = DragAndDropModule; 230 | 231 | 232 | _quill2.default.register('modules/dragAndDrop', DragAndDropModule); 233 | 234 | /***/ }), 235 | /* 1 */ 236 | /***/ (function(module, exports) { 237 | 238 | module.exports = __WEBPACK_EXTERNAL_MODULE_1__; 239 | 240 | /***/ }), 241 | /* 2 */ 242 | /***/ (function(module, exports) { 243 | 244 | "use strict"; 245 | 246 | Object.defineProperty(exports, "__esModule", { 247 | value: true 248 | }); 249 | exports.convertDraggable = convertDraggable; 250 | exports.filesMatching = filesMatching; 251 | exports.getFileDataUrl = getFileDataUrl; 252 | exports.nullReturner = nullReturner; 253 | function convertDraggable(draggable) { 254 | if (draggable.content_type_pattern && draggable.tag && draggable.attr) { 255 | var ret = Object.assign({}, draggable); 256 | ret.content_type_regex = new RegExp(draggable.content_type_pattern); 257 | delete ret.content_type_pattern; 258 | return ret; 259 | } else { 260 | var e = new Error("draggables should have content_type_pattern, tag and attr keys"); 261 | e.invalid_draggable = draggable; 262 | throw e; 263 | } 264 | }; 265 | 266 | function filesMatching(file_list, draggables) { 267 | var ret = []; 268 | 269 | var _loop = function _loop(i) { 270 | var file = file_list.item(i); 271 | var draggable = draggables.find(function (d) { 272 | return d.content_type_regex.test(file.type); 273 | }); 274 | draggable && ret.push({ file: file, tag: draggable.tag, attr: draggable.attr }); 275 | }; 276 | 277 | for (var i = 0; i < file_list.length; i++) { 278 | _loop(i); 279 | } 280 | return ret; 281 | }; 282 | 283 | function getFileDataUrl(file) { 284 | var reader = new FileReader(); 285 | return new Promise(function (resolve) { 286 | reader.addEventListener("load", function () { 287 | resolve(reader.result); 288 | }, false); 289 | reader.readAsDataURL(file); 290 | }); 291 | }; 292 | 293 | function nullReturner() { 294 | return null; 295 | }; 296 | 297 | /***/ }) 298 | /******/ ]) 299 | }); 300 | ; --------------------------------------------------------------------------------