building-a-custom-module.mdx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. ---
  2. title: Building a Custom Module
  3. ---
  4. 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.
  5. <Hint>
  6. 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.
  7. </Hint>
  8. ### Counting Words
  9. 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:
  10. 1. Listen for text changes in Quill.
  11. 1. Count the number of words.
  12. 1. Display this value.
  13. Let's jump straight in with a complete example!
  14. <Sandpack
  15. defaultShowPreview
  16. externalResources={[
  17. "{{site.cdn}}/quill.snow.css",
  18. "{{site.cdn}}/quill.js",
  19. ]}
  20. files={{
  21. 'index.html': `
  22. <link href="/index.css" rel="stylesheet">
  23. <div id="editor"></div>
  24. <div id="counter">0</div>
  25. <script src="/index.js"></script>
  26. `,
  27. 'index.css': `
  28. #editor {
  29. border: 1px solid #ccc;
  30. }
  31. #counter {
  32. border: 1px solid #ccc;
  33. border-width: 0px 1px 1px 1px;
  34. color: #aaa;
  35. padding: 5px 15px;
  36. text-align: right;
  37. }
  38. `,
  39. 'index.js': `
  40. function Counter(quill, options) {
  41. const container = document.querySelector('#counter');
  42. quill.on(Quill.events.TEXT_CHANGE, () => {
  43. const text = quill.getText();
  44. // There are a couple issues with counting words
  45. // this way but we'll fix these later
  46. container.innerText = text.split(/\\s+/).length;
  47. });
  48. }
  49. Quill.register('modules/counter', Counter);
  50. // We can now initialize Quill with something like this:
  51. const quill = new Quill('#editor', {
  52. modules: {
  53. counter: true
  54. }
  55. });
  56. `
  57. }}
  58. />
  59. 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.
  60. ### Using Options
  61. 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:
  62. <Sandpack
  63. defaultShowPreview
  64. externalResources={[
  65. "{{site.cdn}}/quill.snow.css",
  66. "{{site.cdn}}/quill.js",
  67. ]}
  68. files={{
  69. 'index.html': `
  70. <link href="/index.css" rel="stylesheet">
  71. <div id="editor"></div>
  72. <div id="counter">0</div>
  73. <script src="/index.js"></script>
  74. `,
  75. 'index.css': `
  76. #editor {
  77. border: 1px solid #ccc;
  78. }
  79. #counter {
  80. border: 1px solid #ccc;
  81. border-width: 0px 1px 1px 1px;
  82. color: #aaa;
  83. padding: 5px 15px;
  84. text-align: right;
  85. }
  86. `,
  87. 'index.js': `
  88. function Counter(quill, options) {
  89. const container = document.querySelector(options.container);
  90. quill.on(Quill.events.TEXT_CHANGE, () => {
  91. const text = quill.getText();
  92. if (options.unit === 'word') {
  93. container.innerText = text.split(/\\s+/).length + ' words';
  94. } else {
  95. container.innerText = text.length + ' characters';
  96. }
  97. });
  98. }
  99. Quill.register('modules/counter', Counter);
  100. // We can now initialize Quill with something like this:
  101. const quill = new Quill('#editor', {
  102. modules: {
  103. counter: {
  104. container: '#counter',
  105. unit: 'word'
  106. }
  107. }
  108. });
  109. `
  110. }}
  111. />
  112. ### Constructors
  113. 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.
  114. <Sandpack
  115. defaultShowPreview
  116. externalResources={[
  117. "{{site.cdn}}/quill.snow.css",
  118. "{{site.cdn}}/quill.js",
  119. ]}
  120. files={{
  121. 'index.html': `
  122. <link href="/index.css" rel="stylesheet">
  123. <div id="editor"></div>
  124. <div id="counter">0</div>
  125. <script src="/index.js"></script>
  126. `,
  127. 'index.css': `
  128. #editor {
  129. border: 1px solid #ccc;
  130. }
  131. #counter {
  132. border: 1px solid #ccc;
  133. border-width: 0px 1px 1px 1px;
  134. color: #aaa;
  135. padding: 5px 15px;
  136. text-align: right;
  137. }
  138. `,
  139. 'index.js': `
  140. class Counter {
  141. constructor(quill, options) {
  142. const container = document.querySelector(options.container);
  143. quill.on(Quill.events.TEXT_CHANGE, () => {
  144. const text = quill.getText();
  145. if (options.unit === 'word') {
  146. container.innerText = text.split(/\\s+/).length + ' words';
  147. } else {
  148. container.innerText = text.length + ' characters';
  149. }
  150. });
  151. }
  152. calculate() {
  153. const text = this.quill.getText();
  154. return this.options.unit === 'word' ?
  155. text.split(/\\s+/).length :
  156. text.length;
  157. }
  158. }
  159. Quill.register('modules/counter', Counter);
  160. // We can now initialize Quill with something like this:
  161. const quill = new Quill('#editor', {
  162. modules: {
  163. counter: {
  164. container: '#counter',
  165. unit: 'word'
  166. }
  167. }
  168. });
  169. `
  170. }}
  171. />
  172. ### Wrapping It All Up
  173. Now let's polish off the module in ES6 and fix a few pesky bugs. That's all there is to it!
  174. <Sandpack
  175. defaultShowPreview
  176. externalResources={[
  177. "{{site.cdn}}/quill.snow.css",
  178. "{{site.cdn}}/quill.js",
  179. ]}
  180. files={{
  181. 'index.html': `
  182. <link href="/index.css" rel="stylesheet">
  183. <div id="editor"></div>
  184. <div id="counter">0</div>
  185. <script src="/index.js"></script>
  186. `,
  187. 'index.css': `
  188. #editor {
  189. border: 1px solid #ccc;
  190. }
  191. #counter {
  192. border: 1px solid #ccc;
  193. border-width: 0px 1px 1px 1px;
  194. color: #aaa;
  195. padding: 5px 15px;
  196. text-align: right;
  197. }
  198. `,
  199. 'index.js': `
  200. class Counter {
  201. constructor(quill, options) {
  202. this.quill = quill;
  203. this.options = options;
  204. this.container = document.querySelector(options.container);
  205. quill.on(Quill.events.TEXT_CHANGE, this.update.bind(this));
  206. }
  207. calculate() {
  208. const text = this.quill.getText();
  209. if (this.options.unit === 'word') {
  210. const trimmed = text.trim();
  211. // Splitting empty text returns a non-empty array
  212. return trimmed.length > 0 ? trimmed.split(/\\s+/).length : 0;
  213. } else {
  214. return text.length;
  215. }
  216. }
  217. update() {
  218. const length = this.calculate();
  219. let label = this.options.unit;
  220. if (length !== 1) {
  221. label += 's';
  222. }
  223. this.container.innerText = \`\${length} \${label}\`;
  224. }
  225. }
  226. Quill.register('modules/counter', Counter);
  227. // We can now initialize Quill with something like this:
  228. const quill = new Quill('#editor', {
  229. modules: {
  230. counter: {
  231. container: '#counter',
  232. unit: 'word'
  233. }
  234. }
  235. });
  236. `
  237. }}
  238. />