├── .gitignore ├── demo ├── test.jpg ├── index.html └── script.js ├── .editorconfig ├── CHANGELOG.md ├── .eslintrc ├── webpack.config.js ├── LICENSE ├── src ├── DefaultOptions.js ├── modules │ ├── BaseModule.js │ ├── DisplaySize.js │ ├── Resize.js │ └── Toolbar.js └── ImageResize.js ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | .idea 4 | node_modules 5 | /npm-debug.log 6 | -------------------------------------------------------------------------------- /demo/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Etoile984816138/quill-image-resize-module/HEAD/demo/test.jpg -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | indent_style = tab 12 | indent_size = 4 13 | 14 | [*.json,*.eslintrc] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v3.0.0 - April 9, 2017 4 | 5 | - Position drag handles relative to editor, not document 6 | - Simplify toolbar and use floats 7 | - Improved styling 8 | 9 | ## v2.0.0 - April 3, 2017 10 | 11 | - Added toolbar for alignment 12 | - Modularized 13 | - Fix resize bug 14 | 15 | ## v1.0.0 - March 25, 2017 16 | 17 | - Initial version -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true, 5 | "mocha": true, 6 | "es6": true 7 | }, 8 | "parser": "babel-eslint", 9 | "parserOptions": { 10 | "ecmaVersion": 6, 11 | "sourceType": "module", 12 | "ecmaFeatures": { 13 | "forOf": true, 14 | "es6": true, 15 | "experimentalObjectRestSpread": true 16 | } 17 | }, 18 | "rules": { 19 | "comma-dangle": [2, "always-multiline"], 20 | "default-case": 1, 21 | "dot-notation": 1, 22 | "no-cond-assign": 1, 23 | "no-constant-condition": 2, 24 | "no-eval": 2, 25 | "no-extend-native": 2, 26 | "no-fallthrough": 2, 27 | "no-lone-blocks": 1, 28 | "no-loop-func": 1, 29 | "no-redeclare": 1, 30 | "no-unused-vars": 1, 31 | "no-use-before-define": 0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
Also see quill-image-drop-module, 17 | a module that enables copy-paste and drag/drop for Quill.
18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | entry: "./src/ImageResize.js", 5 | output: { 6 | path: __dirname, 7 | library: 'ImageResize', 8 | libraryTarget: 'umd', 9 | filename: "image-resize.min.js" 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.js$/, 15 | include: path.join(__dirname, 'src'), 16 | exclude: /(node_modules|bower_components)/, 17 | use: [{ 18 | loader: 'babel-loader', 19 | options: { 20 | "presets": [["es2015", { "modules": false }]], 21 | "plugins": ["babel-plugin-transform-class-properties"] 22 | } 23 | }] 24 | }, 25 | { 26 | test: /\.svg$/, 27 | use: [{ 28 | loader: 'raw-loader' 29 | }] 30 | } 31 | ] 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | Copyright © 2018 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the “Software”), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. -------------------------------------------------------------------------------- /demo/script.js: -------------------------------------------------------------------------------- 1 | var quill = new Quill('#editor', { 2 | theme: 'snow', 3 | modules: { 4 | toolbar: [ 5 | ['bold', 'italic', 'underline', 'strike', 6 | { 7 | 'script': 'sub', 8 | }, { 9 | 'script': 'super', 10 | }, 11 | { 12 | 'color': [], 13 | }, { 14 | 'background': [], 15 | }, 'code', 16 | ], 17 | [{ 18 | 'font': [], 19 | }, { 20 | 'size': ['small', false, 'large', 'huge'], 21 | }], 22 | 23 | ['link', 'image', 'video', 'formula'], 24 | ['blockquote', 'code-block', { 25 | 'header': 1, 26 | }, 27 | { 28 | 'list': 'ordered', 29 | }, { 30 | 'list': 'bullet', 31 | }, 32 | ], 33 | [{ 34 | 'indent': '-1', 35 | }, { 36 | 'indent': '+1', 37 | }, { 38 | 'direction': 'rtl', 39 | }, { 40 | 'align': [], 41 | }], 42 | ['clean'], 43 | ], 44 | imageResize: {}, 45 | }, 46 | }); 47 | 48 | function convert() { 49 | const delta = quill.getContents(); 50 | console.log(toHtml(delta)); 51 | // return toHtml(delta); 52 | } 53 | 54 | function toHtml(delta){ 55 | const tempCont = document.createElement('div'); 56 | (new Quill(tempCont)).setContents(delta); 57 | return tempCont.getElementsByClassName('ql-editor')[0].innerHTML; 58 | } 59 | 60 | // console.log(convert()); 61 | -------------------------------------------------------------------------------- /src/DefaultOptions.js: -------------------------------------------------------------------------------- 1 | export default { 2 | modules: [ 3 | 'DisplaySize', 4 | 'Toolbar', 5 | 'Resize', 6 | ], 7 | overlayStyles: { 8 | position: 'absolute', 9 | boxSizing: 'border-box', 10 | border: '1px dashed #444', 11 | }, 12 | handleStyles: { 13 | position: 'absolute', 14 | height: '12px', 15 | width: '12px', 16 | backgroundColor: 'white', 17 | border: '1px solid #777', 18 | boxSizing: 'border-box', 19 | opacity: '0.80', 20 | }, 21 | displayStyles: { 22 | position: 'absolute', 23 | font: '12px/1.0 Arial, Helvetica, sans-serif', 24 | padding: '4px 8px', 25 | textAlign: 'center', 26 | backgroundColor: 'white', 27 | color: '#333', 28 | border: '1px solid #777', 29 | boxSizing: 'border-box', 30 | opacity: '0.80', 31 | cursor: 'default', 32 | }, 33 | toolbarStyles: { 34 | position: 'absolute', 35 | top: '-12px', 36 | right: '0', 37 | left: '0', 38 | height: '0', 39 | minWidth: '100px', 40 | font: '12px/1.0 Arial, Helvetica, sans-serif', 41 | textAlign: 'center', 42 | color: '#333', 43 | boxSizing: 'border-box', 44 | cursor: 'default', 45 | }, 46 | toolbarButtonStyles: { 47 | display: 'inline-block', 48 | width: '24px', 49 | height: '24px', 50 | background: 'white', 51 | border: '1px solid #999', 52 | verticalAlign: 'middle', 53 | }, 54 | toolbarButtonSvgStyles: { 55 | fill: '#444', 56 | stroke: '#444', 57 | strokeWidth: '2', 58 | }, 59 | }; 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quill-image-resize", 3 | "version": "3.0.9", 4 | "description": "A module for Quill rich text editor to allow images to be resized.", 5 | "main": "image-resize.min.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "release": "webpack -p --progress --colors", 9 | "dev": "webpack --progress --colors --watch", 10 | "lint": "eslint --ext js,es6 src", 11 | "fixlint": "eslint --fix --ext js,es6 src" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/Etoile984816138/quill-image-resize-module.git" 16 | }, 17 | "keywords": [ 18 | "quill", 19 | "quilljs", 20 | "image", 21 | "resize", 22 | "sizer" 23 | ], 24 | "author": "@kensnyder", 25 | "contributors": [ 26 | { 27 | "name": "Wikia", 28 | "url": "https://github.com/Wikia" 29 | } 30 | ], 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/Etoile984816138/quill-image-resize-module/issues" 34 | }, 35 | "homepage": "https://github.com/Etoile984816138/quill-image-resize-module#readme", 36 | "devDependencies": { 37 | "babel-cli": "^6.24.0", 38 | "babel-eslint": "^7.2.1", 39 | "babel-loader": "^6.4.1", 40 | "babel-plugin-transform-class-properties": "^6.23.0", 41 | "babel-preset-env": "^1.2.2", 42 | "babel-preset-es2015": "^6.24.0", 43 | "eslint": "^3.19.0", 44 | "eslint-config-airbnb": "^14.1.0", 45 | "eslint-plugin-import": "^2.2.0", 46 | "eslint-plugin-jsx-a11y": "^4.0.0", 47 | "eslint-plugin-react": "^6.10.3", 48 | "webpack": "^2.3.3" 49 | }, 50 | "dependencies": { 51 | "lodash": "^4.17.4", 52 | "quill": "^1.2.2", 53 | "raw-loader": "^0.5.1" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/modules/BaseModule.js: -------------------------------------------------------------------------------- 1 | export class BaseModule { 2 | constructor(resizer) { 3 | this.overlay = resizer.overlay; 4 | this.img = resizer.img; 5 | this.options = resizer.options; 6 | this.requestUpdate = resizer.onUpdate; 7 | } 8 | /* 9 | requestUpdate (passed in by the library during construction, above) can be used to let the library know that 10 | you've changed something about the image that would require re-calculating the overlay (and all of its child 11 | elements) 12 | 13 | For example, if you add a margin to the element, you'll want to call this or else all the controls will be 14 | misaligned on-screen. 15 | */ 16 | 17 | /* 18 | onCreate will be called when the element is clicked on 19 | 20 | If the module has any user controls, it should create any containers that it'll need here. 21 | The overlay has absolute positioning, and will be automatically repositioned and resized as needed, so you can 22 | use your own absolute positioning and the 'top', 'right', etc. styles to be positioned relative to the element 23 | on-screen. 24 | */ 25 | onCreate = () => {}; 26 | 27 | /* 28 | onDestroy will be called when the element is de-selected, or when this module otherwise needs to tidy up. 29 | 30 | If you created any DOM elements in onCreate, please remove them from the DOM and destroy them here. 31 | */ 32 | onDestroy = () => {}; 33 | 34 | /* 35 | onUpdate will be called any time that the element is changed (e.g. resized, aligned, etc.) 36 | 37 | This frequently happens during resize dragging, so keep computations light while here to ensure a smooth 38 | user experience. 39 | */ 40 | onUpdate = () => {}; 41 | } 42 | -------------------------------------------------------------------------------- /src/modules/DisplaySize.js: -------------------------------------------------------------------------------- 1 | import { BaseModule } from './BaseModule'; 2 | 3 | export class DisplaySize extends BaseModule { 4 | onCreate = () => { 5 | // Create the container to hold the size display 6 | this.display = document.createElement('div'); 7 | 8 | // Apply styles 9 | Object.assign(this.display.style, this.options.displayStyles); 10 | 11 | // Attach it 12 | this.overlay.appendChild(this.display); 13 | }; 14 | 15 | onDestroy = () => {}; 16 | 17 | onUpdate = () => { 18 | if (!this.display || !this.img) { 19 | return; 20 | } 21 | 22 | const size = this.getCurrentSize(); 23 | this.display.innerHTML = size.join(' × '); 24 | if (size[0] > 120 && size[1] > 30) { 25 | // position on top of image 26 | Object.assign(this.display.style, { 27 | right: '4px', 28 | bottom: '4px', 29 | left: 'auto', 30 | }); 31 | } 32 | else if (this.img.style.float == 'right') { 33 | // position off bottom left 34 | const dispRect = this.display.getBoundingClientRect(); 35 | Object.assign(this.display.style, { 36 | right: 'auto', 37 | bottom: `-${dispRect.height + 4}px`, 38 | left: `-${dispRect.width + 4}px`, 39 | }); 40 | } 41 | else { 42 | // position off bottom right 43 | const dispRect = this.display.getBoundingClientRect(); 44 | Object.assign(this.display.style, { 45 | right: `-${dispRect.width + 4}px`, 46 | bottom: `-${dispRect.height + 4}px`, 47 | left: 'auto', 48 | }); 49 | } 50 | }; 51 | 52 | getCurrentSize = () => [ 53 | this.img.width, 54 | Math.round((this.img.width / this.img.naturalWidth) * this.img.naturalHeight), 55 | ]; 56 | } 57 | -------------------------------------------------------------------------------- /src/modules/Resize.js: -------------------------------------------------------------------------------- 1 | import { BaseModule } from './BaseModule'; 2 | 3 | export class Resize extends BaseModule { 4 | onCreate = () => { 5 | // track resize handles 6 | this.boxes = []; 7 | 8 | // add 4 resize handles 9 | this.addBox('nwse-resize'); // top left 10 | this.addBox('nesw-resize'); // top right 11 | this.addBox('nwse-resize'); // bottom right 12 | this.addBox('nesw-resize'); // bottom left 13 | 14 | this.positionBoxes(); 15 | }; 16 | 17 | onDestroy = () => { 18 | // reset drag handle cursors 19 | this.setCursor(''); 20 | }; 21 | 22 | positionBoxes = () => { 23 | const handleXOffset = `${-parseFloat(this.options.handleStyles.width) / 2}px`; 24 | const handleYOffset = `${-parseFloat(this.options.handleStyles.height) / 2}px`; 25 | 26 | // set the top and left for each drag handle 27 | [ 28 | { left: handleXOffset, top: handleYOffset }, // top left 29 | { right: handleXOffset, top: handleYOffset }, // top right 30 | { right: handleXOffset, bottom: handleYOffset }, // bottom right 31 | { left: handleXOffset, bottom: handleYOffset }, // bottom left 32 | ].forEach((pos, idx) => { 33 | Object.assign(this.boxes[idx].style, pos); 34 | }); 35 | }; 36 | 37 | addBox = (cursor) => { 38 | // create div element for resize handle 39 | const box = document.createElement('div'); 40 | 41 | // Star with the specified styles 42 | Object.assign(box.style, this.options.handleStyles); 43 | box.style.cursor = cursor; 44 | 45 | // Set the width/height to use 'px' 46 | box.style.width = `${this.options.handleStyles.width}px`; 47 | box.style.height = `${this.options.handleStyles.height}px`; 48 | 49 | // listen for mousedown on each box 50 | box.addEventListener('mousedown', this.handleMousedown, false); 51 | // add drag handle to document 52 | this.overlay.appendChild(box); 53 | // keep track of drag handle 54 | this.boxes.push(box); 55 | }; 56 | 57 | handleMousedown = (evt) => { 58 | // note which box 59 | this.dragBox = evt.target; 60 | // note starting mousedown position 61 | this.dragStartX = evt.clientX; 62 | // store the width before the drag 63 | this.preDragWidth = this.img.width || this.img.naturalWidth; 64 | // set the proper cursor everywhere 65 | this.setCursor(this.dragBox.style.cursor); 66 | // listen for movement and mouseup 67 | document.addEventListener('mousemove', this.handleDrag, false); 68 | document.addEventListener('mouseup', this.handleMouseup, false); 69 | }; 70 | 71 | handleMouseup = () => { 72 | // reset cursor everywhere 73 | this.setCursor(''); 74 | // stop listening for movement and mouseup 75 | document.removeEventListener('mousemove', this.handleDrag); 76 | document.removeEventListener('mouseup', this.handleMouseup); 77 | }; 78 | 79 | handleDrag = (evt) => { 80 | if (!this.img) { 81 | // image not set yet 82 | return; 83 | } 84 | // update image size 85 | const deltaX = evt.clientX - this.dragStartX; 86 | if (this.dragBox === this.boxes[0] || this.dragBox === this.boxes[3]) { 87 | // left-side resize handler; dragging right shrinks image 88 | this.img.width = Math.round(this.preDragWidth - deltaX); 89 | } else { 90 | // right-side resize handler; dragging right enlarges image 91 | this.img.width = Math.round(this.preDragWidth + deltaX); 92 | } 93 | this.requestUpdate(); 94 | }; 95 | 96 | setCursor = (value) => { 97 | [ 98 | document.body, 99 | this.img, 100 | ].forEach((el) => { 101 | el.style.cursor = value; // eslint-disable-line no-param-reassign 102 | }); 103 | }; 104 | } 105 | -------------------------------------------------------------------------------- /src/modules/Toolbar.js: -------------------------------------------------------------------------------- 1 | import Quill from "quill"; 2 | import IconAlignLeft from 'quill/assets/icons/align-left.svg'; 3 | import IconAlignCenter from 'quill/assets/icons/align-center.svg'; 4 | import IconAlignRight from 'quill/assets/icons/align-right.svg'; 5 | import { BaseModule } from './BaseModule'; 6 | 7 | const Parchment = Quill.imports.parchment; 8 | const FloatStyle = new Parchment.Attributor.Style('float', 'float'); 9 | const MarginStyle = new Parchment.Attributor.Style('margin', 'margin'); 10 | const DisplayStyle = new Parchment.Attributor.Style('display', 'display'); 11 | 12 | const offsetAttributor = new Parchment.Attributor.Attribute('nameClass', 'class', { 13 | scope: Parchment.Scope.INLINE, 14 | }); 15 | 16 | Quill.register(offsetAttributor); 17 | 18 | export class Toolbar extends BaseModule { 19 | onCreate = () => { 20 | // Setup Toolbar 21 | this.toolbar = document.createElement('div'); 22 | Object.assign(this.toolbar.style, this.options.toolbarStyles); 23 | this.overlay.appendChild(this.toolbar); 24 | 25 | // Setup Buttons 26 | this._defineAlignments(); 27 | this._addToolbarButtons(); 28 | }; 29 | 30 | // The toolbar and its children will be destroyed when the overlay is removed 31 | onDestroy = () => {}; 32 | 33 | // Nothing to update on drag because we are are positioned relative to the overlay 34 | onUpdate = () => {}; 35 | 36 | _defineAlignments = () => { 37 | this.alignments = [ 38 | { 39 | icon: IconAlignLeft, 40 | apply: () => { 41 | DisplayStyle.add(this.img, 'inline'); 42 | FloatStyle.add(this.img, 'left'); 43 | MarginStyle.add(this.img, '0 1em 1em 0'); 44 | this.img.align = 'left'; 45 | }, 46 | isApplied: () => FloatStyle.value(this.img) == 'left', 47 | }, 48 | { 49 | icon: IconAlignCenter, 50 | apply: () => { 51 | DisplayStyle.add(this.img, 'block'); 52 | FloatStyle.remove(this.img); 53 | MarginStyle.add(this.img, 'auto'); 54 | this.img.align = 'center'; 55 | }, 56 | isApplied: () => MarginStyle.value(this.img) == 'auto', 57 | }, 58 | { 59 | icon: IconAlignRight, 60 | apply: () => { 61 | DisplayStyle.add(this.img, 'inline'); 62 | FloatStyle.add(this.img, 'right'); 63 | MarginStyle.add(this.img, '0 0 1em 1em'); 64 | this.img.align = 'right'; 65 | }, 66 | isApplied: () => FloatStyle.value(this.img) == 'right', 67 | }, 68 | ]; 69 | }; 70 | 71 | _addToolbarButtons = () => { 72 | const buttons = []; 73 | this.alignments.forEach((alignment, idx) => { 74 | const button = document.createElement('span'); 75 | buttons.push(button); 76 | button.innerHTML = alignment.icon; 77 | button.addEventListener('click', () => { 78 | // deselect all buttons 79 | buttons.forEach(button => button.style.filter = ''); 80 | if (alignment.isApplied()) { 81 | // If applied, unapply 82 | FloatStyle.remove(this.img); 83 | MarginStyle.remove(this.img); 84 | DisplayStyle.remove(this.img); 85 | }else { 86 | // otherwise, select button and apply 87 | this._selectButton(button); 88 | alignment.apply(); 89 | } 90 | // image may change position; redraw drag handles 91 | this.requestUpdate(); 92 | }); 93 | Object.assign(button.style, this.options.toolbarButtonStyles); 94 | if (idx > 0) { 95 | button.style.borderLeftWidth = '0'; 96 | } 97 | Object.assign(button.children[0].style, this.options.toolbarButtonSvgStyles); 98 | if (alignment.isApplied()) { 99 | // select button if previously applied 100 | this._selectButton(button); 101 | } 102 | this.toolbar.appendChild(button); 103 | }); 104 | }; 105 | 106 | _selectButton = (button) => { 107 | button.style.filter = 'invert(20%)'; 108 | }; 109 | 110 | } 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quill ImageResize Module 2 | 3 | A module for Quill rich text editor to allow images to be resized. 4 | 5 | Also see [quill-image-drop-module](https://github.com/kensnyder/quill-image-drop-module), 6 | a module that enables copy-paste and drag/drop for Quill. 7 | 8 | ## Demo 9 | 10 | [Plunker](https://plnkr.co/edit/gq708AOrSBOWSlHcFslG?p=preview) 11 | 12 | ## Usage 13 | 14 | ### Webpack/ES6 15 | 16 | ```javascript 17 | import Quill from 'quill'; 18 | import { ImageResize } from 'quill-image-resize-module'; 19 | 20 | Quill.register('modules/imageResize', ImageResize); 21 | 22 | const quill = new Quill(editor, { 23 | // ... 24 | modules: { 25 | // ... 26 | imageResize: { 27 | // See optional "config" below 28 | } 29 | } 30 | }); 31 | ``` 32 | 33 | ### Script Tag 34 | 35 | Copy image-resize.min.js into your web root or include from node_modules 36 | 37 | ```html 38 | 39 | ``` 40 | 41 | ```javascript 42 | var quill = new Quill(editor, { 43 | // ... 44 | modules: { 45 | // ... 46 | ImageResize: { 47 | // See optional "config" below 48 | } 49 | } 50 | }); 51 | ``` 52 | 53 | ### Config 54 | 55 | For the default experience, pass an empty object, like so: 56 | ```javascript 57 | var quill = new Quill(editor, { 58 | // ... 59 | modules: { 60 | // ... 61 | ImageResize: {} 62 | } 63 | }); 64 | ``` 65 | 66 | Functionality is broken down into modules, which can be mixed and matched as you like. For example, 67 | the default is to include all modules: 68 | 69 | ```javascript 70 | const quill = new Quill(editor, { 71 | // ... 72 | modules: { 73 | // ... 74 | ImageResize: { 75 | modules: [ 'Resize', 'DisplaySize', 'Toolbar' ] 76 | } 77 | } 78 | }); 79 | ``` 80 | 81 | Each module is described below. 82 | 83 | #### `Resize` - Resize the image 84 | 85 | Adds handles to the image's corners which can be dragged with the mouse to resize the image. 86 | 87 | The look and feel can be controlled with options: 88 | 89 | ```javascript 90 | var quill = new Quill(editor, { 91 | // ... 92 | modules: { 93 | // ... 94 | ImageResize: { 95 | // ... 96 | handleStyles: { 97 | backgroundColor: 'black', 98 | border: 'none', 99 | color: white 100 | // other camelCase styles for size display 101 | } 102 | } 103 | } 104 | }); 105 | ``` 106 | 107 | #### `DisplaySize` - Display pixel size 108 | 109 | Shows the size of the image in pixels near the bottom right of the image. 110 | 111 | The look and feel can be controlled with options: 112 | 113 | ```javascript 114 | var quill = new Quill(editor, { 115 | // ... 116 | modules: { 117 | // ... 118 | ImageResize: { 119 | // ... 120 | displayStyles: { 121 | backgroundColor: 'black', 122 | border: 'none', 123 | color: white 124 | // other camelCase styles for size display 125 | } 126 | } 127 | } 128 | }); 129 | ``` 130 | 131 | #### `Toolbar` - Image alignment tools 132 | 133 | Displays a toolbar below the image, where the user can select an alignment for the image. 134 | 135 | The look and feel can be controlled with options: 136 | 137 | ```javascript 138 | var quill = new Quill(editor, { 139 | // ... 140 | modules: { 141 | // ... 142 | ImageResize: { 143 | // ... 144 | toolbarStyles: { 145 | backgroundColor: 'black', 146 | border: 'none', 147 | color: white 148 | // other camelCase styles for size display 149 | }, 150 | toolbarButtonStyles: { 151 | // ... 152 | }, 153 | toolbarButtonSvgStyles: { 154 | // ... 155 | }, 156 | } 157 | } 158 | }); 159 | ``` 160 | 161 | #### `BaseModule` - Include your own custom module 162 | 163 | You can write your own module by extending the `BaseModule` class, and then including it in 164 | the module setup. 165 | 166 | For example, 167 | 168 | ```javascript 169 | import { Resize, BaseModule } from 'quill-image-resize-module'; 170 | 171 | class MyModule extends BaseModule { 172 | // See src/modules/BaseModule.js for documentation on the various lifecycle callbacks 173 | } 174 | 175 | var quill = new Quill(editor, { 176 | // ... 177 | modules: { 178 | // ... 179 | ImageResize: { 180 | modules: [ MyModule, Resize ], 181 | // ... 182 | } 183 | } 184 | }); 185 | ``` 186 | -------------------------------------------------------------------------------- /src/ImageResize.js: -------------------------------------------------------------------------------- 1 | import Quill from "quill"; 2 | import defaultsDeep from 'lodash/defaultsDeep'; 3 | import DefaultOptions from './DefaultOptions'; 4 | import { DisplaySize } from './modules/DisplaySize'; 5 | import { Toolbar } from './modules/Toolbar'; 6 | import { Resize } from './modules/Resize'; 7 | 8 | const knownModules = { DisplaySize, Toolbar, Resize }; 9 | 10 | /** 11 | * Custom module for quilljs to allow user to resize