123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- ---
- title: Building a Custom Module
- ---
- Quill's core strength as an editor is its rich API and powerful customization capabilities. As you implement functionality on top of Quill's API, it may be convenient to organize this as a module. For the purpose of this guide, we will walk through one way to build a word counter module, a commonly found feature in many word processors.
- <Hint>
- Internally modules are how much of Quill's functionality is organized. You can overwrite these default [modules](/docs/modules/) by implementing your own and registering it with the same name.
- </Hint>
- ### Counting Words
- At its core a word counter simply counts the number of words in the editor and displays this value in some UI. Thus we need to:
- 1. Listen for text changes in Quill.
- 1. Count the number of words.
- 1. Display this value.
- Let's jump straight in with a complete example!
- <Sandpack
- defaultShowPreview
- externalResources={[
- "{{site.cdn}}/quill.snow.css",
- "{{site.cdn}}/quill.js",
- ]}
- files={{
- 'index.html': `
- <link href="/index.css" rel="stylesheet">
- <div id="editor"></div>
- <div id="counter">0</div>
- <script src="/index.js"></script>
- `,
- 'index.css': `
- #editor {
- border: 1px solid #ccc;
- }
- #counter {
- border: 1px solid #ccc;
- border-width: 0px 1px 1px 1px;
- color: #aaa;
- padding: 5px 15px;
- text-align: right;
- }
- `,
- 'index.js': `
- function Counter(quill, options) {
- const container = document.querySelector('#counter');
- quill.on(Quill.events.TEXT_CHANGE, () => {
- const text = quill.getText();
- // There are a couple issues with counting words
- // this way but we'll fix these later
- container.innerText = text.split(/\\s+/).length;
- });
- }
- Quill.register('modules/counter', Counter);
- // We can now initialize Quill with something like this:
- const quill = new Quill('#editor', {
- modules: {
- counter: true
- }
- });
- `
- }}
- />
- That's all it takes to add a custom module to Quill! A function can be [registered](/docs/api/#quillregistermodule/) as a module and it will be passed the corresponding Quill editor object along with any options.
- ### Using Options
- Modules are passed an options object that can be used to fine tune the desired behavior. We can use this to accept a selector for the counter container instead of a hard-coded string. Let's also customize the counter to either count words or characters:
- <Sandpack
- defaultShowPreview
- externalResources={[
- "{{site.cdn}}/quill.snow.css",
- "{{site.cdn}}/quill.js",
- ]}
- files={{
- 'index.html': `
- <link href="/index.css" rel="stylesheet">
- <div id="editor"></div>
- <div id="counter">0</div>
- <script src="/index.js"></script>
- `,
- 'index.css': `
- #editor {
- border: 1px solid #ccc;
- }
- #counter {
- border: 1px solid #ccc;
- border-width: 0px 1px 1px 1px;
- color: #aaa;
- padding: 5px 15px;
- text-align: right;
- }
- `,
- 'index.js': `
- function Counter(quill, options) {
- const container = document.querySelector(options.container);
- quill.on(Quill.events.TEXT_CHANGE, () => {
- const text = quill.getText();
- if (options.unit === 'word') {
- container.innerText = text.split(/\\s+/).length + ' words';
- } else {
- container.innerText = text.length + ' characters';
- }
- });
- }
- Quill.register('modules/counter', Counter);
- // We can now initialize Quill with something like this:
- const quill = new Quill('#editor', {
- modules: {
- counter: {
- container: '#counter',
- unit: 'word'
- }
- }
- });
- `
- }}
- />
- ### Constructors
- Since any function can be registered as a Quill module, we could have implemented our counter as an ES5 constructor or ES6 class. This allows us to access and utilize the module directly.
- <Sandpack
- defaultShowPreview
- externalResources={[
- "{{site.cdn}}/quill.snow.css",
- "{{site.cdn}}/quill.js",
- ]}
- files={{
- 'index.html': `
- <link href="/index.css" rel="stylesheet">
- <div id="editor"></div>
- <div id="counter">0</div>
- <script src="/index.js"></script>
- `,
- 'index.css': `
- #editor {
- border: 1px solid #ccc;
- }
- #counter {
- border: 1px solid #ccc;
- border-width: 0px 1px 1px 1px;
- color: #aaa;
- padding: 5px 15px;
- text-align: right;
- }
- `,
- 'index.js': `
- class Counter {
- constructor(quill, options) {
- const container = document.querySelector(options.container);
- quill.on(Quill.events.TEXT_CHANGE, () => {
- const text = quill.getText();
- if (options.unit === 'word') {
- container.innerText = text.split(/\\s+/).length + ' words';
- } else {
- container.innerText = text.length + ' characters';
- }
- });
- }
- calculate() {
- const text = this.quill.getText();
- return this.options.unit === 'word' ?
- text.split(/\\s+/).length :
- text.length;
- }
- }
- Quill.register('modules/counter', Counter);
- // We can now initialize Quill with something like this:
- const quill = new Quill('#editor', {
- modules: {
- counter: {
- container: '#counter',
- unit: 'word'
- }
- }
- });
- `
- }}
- />
- ### Wrapping It All Up
- Now let's polish off the module in ES6 and fix a few pesky bugs. That's all there is to it!
- <Sandpack
- defaultShowPreview
- externalResources={[
- "{{site.cdn}}/quill.snow.css",
- "{{site.cdn}}/quill.js",
- ]}
- files={{
- 'index.html': `
- <link href="/index.css" rel="stylesheet">
- <div id="editor"></div>
- <div id="counter">0</div>
- <script src="/index.js"></script>
- `,
- 'index.css': `
- #editor {
- border: 1px solid #ccc;
- }
- #counter {
- border: 1px solid #ccc;
- border-width: 0px 1px 1px 1px;
- color: #aaa;
- padding: 5px 15px;
- text-align: right;
- }
- `,
- 'index.js': `
- class Counter {
- constructor(quill, options) {
- this.quill = quill;
- this.options = options;
- this.container = document.querySelector(options.container);
- quill.on(Quill.events.TEXT_CHANGE, this.update.bind(this));
- }
- calculate() {
- const text = this.quill.getText();
- if (this.options.unit === 'word') {
- const trimmed = text.trim();
- // Splitting empty text returns a non-empty array
- return trimmed.length > 0 ? trimmed.split(/\\s+/).length : 0;
- } else {
- return text.length;
- }
- }
- update() {
- const length = this.calculate();
- let label = this.options.unit;
- if (length !== 1) {
- label += 's';
- }
- this.container.innerText = \`\${length} \${label}\`;
- }
- }
- Quill.register('modules/counter', Counter);
- // We can now initialize Quill with something like this:
- const quill = new Quill('#editor', {
- modules: {
- counter: {
- container: '#counter',
- unit: 'word'
- }
- }
- });
- `
- }}
- />
|